OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2009 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 { | 593 { |
594 return inRenderedTextAlgorithm<EditingStrategy>(position); | 594 return inRenderedTextAlgorithm<EditingStrategy>(position); |
595 } | 595 } |
596 | 596 |
597 bool inRenderedText(const PositionInComposedTree& position) | 597 bool inRenderedText(const PositionInComposedTree& position) |
598 { | 598 { |
599 return inRenderedTextAlgorithm<EditingInComposedTreeStrategy>(position); | 599 return inRenderedTextAlgorithm<EditingInComposedTreeStrategy>(position); |
600 } | 600 } |
601 | 601 |
602 template <typename Strategy> | 602 template <typename Strategy> |
603 static InlineBoxPosition computeInlineBoxPositionAlgorithm(const PositionAlgorit
hm<Strategy>& position, TextAffinity affinity) | |
604 { | |
605 return computeInlineBoxPositionAlgorithm<Strategy>(position, affinity, prima
ryDirectionOf(*position.anchorNode())); | |
606 } | |
607 | |
608 InlineBoxPosition computeInlineBoxPosition(const Position& position, TextAffinit
y affinity) | |
609 { | |
610 return computeInlineBoxPositionAlgorithm<EditingStrategy>(position, affinity
); | |
611 } | |
612 | |
613 InlineBoxPosition computeInlineBoxPosition(const PositionInComposedTree& positio
n, TextAffinity affinity) | |
614 { | |
615 return computeInlineBoxPositionAlgorithm<EditingInComposedTreeStrategy>(posi
tion, affinity); | |
616 } | |
617 | |
618 static bool isNonTextLeafChild(LayoutObject* object) | |
619 { | |
620 if (object->slowFirstChild()) | |
621 return false; | |
622 if (object->isText()) | |
623 return false; | |
624 return true; | |
625 } | |
626 | |
627 static InlineTextBox* searchAheadForBetterMatch(LayoutObject* layoutObject) | |
628 { | |
629 LayoutBlock* container = layoutObject->containingBlock(); | |
630 for (LayoutObject* next = layoutObject->nextInPreOrder(container); next; nex
t = next->nextInPreOrder(container)) { | |
631 if (next->isLayoutBlock()) | |
632 return 0; | |
633 if (next->isBR()) | |
634 return 0; | |
635 if (isNonTextLeafChild(next)) | |
636 return 0; | |
637 if (next->isText()) { | |
638 InlineTextBox* match = 0; | |
639 int minOffset = INT_MAX; | |
640 for (InlineTextBox* box = toLayoutText(next)->firstTextBox(); box; b
ox = box->nextTextBox()) { | |
641 int caretMinOffset = box->caretMinOffset(); | |
642 if (caretMinOffset < minOffset) { | |
643 match = box; | |
644 minOffset = caretMinOffset; | |
645 } | |
646 } | |
647 if (match) | |
648 return match; | |
649 } | |
650 } | |
651 return 0; | |
652 } | |
653 | |
654 template <typename Strategy> | |
655 PositionAlgorithm<Strategy> downstreamIgnoringEditingBoundaries(PositionAlgorith
m<Strategy> position) | |
656 { | |
657 PositionAlgorithm<Strategy> lastPosition; | |
658 while (position != lastPosition) { | |
659 lastPosition = position; | |
660 position = position.downstream(CanCrossEditingBoundary); | |
661 } | |
662 return position; | |
663 } | |
664 | |
665 template <typename Strategy> | |
666 PositionAlgorithm<Strategy> upstreamIgnoringEditingBoundaries(PositionAlgorithm<
Strategy> position) | |
667 { | |
668 PositionAlgorithm<Strategy> lastPosition; | |
669 while (position != lastPosition) { | |
670 lastPosition = position; | |
671 position = position.upstream(CanCrossEditingBoundary); | |
672 } | |
673 return position; | |
674 } | |
675 | |
676 template <typename Strategy> | |
677 static InlineBoxPosition computeInlineBoxPositionAlgorithm(const PositionAlgorit
hm<Strategy>& position, TextAffinity affinity, TextDirection primaryDirection) | |
678 { | |
679 InlineBox* inlineBox = nullptr; | |
680 int caretOffset = position.computeEditingOffset(); | |
681 Node* const anchorNode = position.anchorNode(); | |
682 LayoutObject* layoutObject = anchorNode->isShadowRoot() ? toShadowRoot(ancho
rNode)->host()->layoutObject() : anchorNode->layoutObject(); | |
683 | |
684 if (!layoutObject->isText()) { | |
685 inlineBox = 0; | |
686 if (canHaveChildrenForEditing(anchorNode) && layoutObject->isLayoutBlock
Flow() && hasRenderedNonAnonymousDescendantsWithHeight(layoutObject)) { | |
687 // Try a visually equivalent position with possibly opposite | |
688 // editability. This helps in case |this| is in an editable block | |
689 // but surrounded by non-editable positions. It acts to negate the | |
690 // logic at the beginning of LayoutObject::createVisiblePosition(). | |
691 PositionAlgorithm<Strategy> equivalent = downstreamIgnoringEditingBo
undaries(position); | |
692 if (equivalent == position) { | |
693 equivalent = upstreamIgnoringEditingBoundaries(position); | |
694 if (equivalent == position || downstreamIgnoringEditingBoundarie
s(equivalent) == position) | |
695 return InlineBoxPosition(inlineBox, caretOffset); | |
696 } | |
697 | |
698 return computeInlineBoxPosition(equivalent, TextAffinity::Upstream,
primaryDirection); | |
699 } | |
700 if (layoutObject->isBox()) { | |
701 inlineBox = toLayoutBox(layoutObject)->inlineBoxWrapper(); | |
702 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && care
tOffset < inlineBox->caretMaxOffset())) | |
703 return InlineBoxPosition(inlineBox, caretOffset); | |
704 } | |
705 } else { | |
706 LayoutText* textLayoutObject = toLayoutText(layoutObject); | |
707 | |
708 InlineTextBox* box; | |
709 InlineTextBox* candidate = 0; | |
710 | |
711 for (box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox
()) { | |
712 int caretMinOffset = box->caretMinOffset(); | |
713 int caretMaxOffset = box->caretMaxOffset(); | |
714 | |
715 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset ||
(caretOffset == caretMaxOffset && box->isLineBreak())) | |
716 continue; | |
717 | |
718 if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) | |
719 return InlineBoxPosition(box, caretOffset); | |
720 | |
721 if (((caretOffset == caretMaxOffset) ^ (affinity == TextAffinity::Do
wnstream)) | |
722 || ((caretOffset == caretMinOffset) ^ (affinity == TextAffinity:
:Upstream)) | |
723 || (caretOffset == caretMaxOffset && box->nextLeafChild() && box
->nextLeafChild()->isLineBreak())) | |
724 break; | |
725 | |
726 candidate = box; | |
727 } | |
728 if (candidate && candidate == textLayoutObject->lastTextBox() && affinit
y == TextAffinity::Downstream) { | |
729 box = searchAheadForBetterMatch(textLayoutObject); | |
730 if (box) | |
731 caretOffset = box->caretMinOffset(); | |
732 } | |
733 inlineBox = box ? box : candidate; | |
734 } | |
735 | |
736 if (!inlineBox) | |
737 return InlineBoxPosition(inlineBox, caretOffset); | |
738 | |
739 unsigned char level = inlineBox->bidiLevel(); | |
740 | |
741 if (inlineBox->direction() == primaryDirection) { | |
742 if (caretOffset == inlineBox->caretRightmostOffset()) { | |
743 InlineBox* nextBox = inlineBox->nextLeafChild(); | |
744 if (!nextBox || nextBox->bidiLevel() >= level) | |
745 return InlineBoxPosition(inlineBox, caretOffset); | |
746 | |
747 level = nextBox->bidiLevel(); | |
748 InlineBox* prevBox = inlineBox; | |
749 do { | |
750 prevBox = prevBox->prevLeafChild(); | |
751 } while (prevBox && prevBox->bidiLevel() > level); | |
752 | |
753 // For example, abc FED 123 ^ CBA | |
754 if (prevBox && prevBox->bidiLevel() == level) | |
755 return InlineBoxPosition(inlineBox, caretOffset); | |
756 | |
757 // For example, abc 123 ^ CBA | |
758 while (InlineBox* nextBox = inlineBox->nextLeafChild()) { | |
759 if (nextBox->bidiLevel() < level) | |
760 break; | |
761 inlineBox = nextBox; | |
762 } | |
763 return InlineBoxPosition(inlineBox, inlineBox->caretRightmostOffset(
)); | |
764 } | |
765 | |
766 InlineBox* prevBox = inlineBox->prevLeafChild(); | |
767 if (!prevBox || prevBox->bidiLevel() >= level) | |
768 return InlineBoxPosition(inlineBox, caretOffset); | |
769 | |
770 level = prevBox->bidiLevel(); | |
771 InlineBox* nextBox = inlineBox; | |
772 do { | |
773 nextBox = nextBox->nextLeafChild(); | |
774 } while (nextBox && nextBox->bidiLevel() > level); | |
775 | |
776 if (nextBox && nextBox->bidiLevel() == level) | |
777 return InlineBoxPosition(inlineBox, caretOffset); | |
778 | |
779 while (InlineBox* prevBox = inlineBox->prevLeafChild()) { | |
780 if (prevBox->bidiLevel() < level) | |
781 break; | |
782 inlineBox = prevBox; | |
783 } | |
784 return InlineBoxPosition(inlineBox, inlineBox->caretLeftmostOffset()); | |
785 } | |
786 | |
787 if (caretOffset == inlineBox->caretLeftmostOffset()) { | |
788 InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak(); | |
789 if (!prevBox || prevBox->bidiLevel() < level) { | |
790 // Left edge of a secondary run. Set to the right edge of the entire | |
791 // run. | |
792 while (InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBrea
k()) { | |
793 if (nextBox->bidiLevel() < level) | |
794 break; | |
795 inlineBox = nextBox; | |
796 } | |
797 return InlineBoxPosition(inlineBox, inlineBox->caretRightmostOffset(
)); | |
798 } | |
799 | |
800 if (prevBox->bidiLevel() > level) { | |
801 // Right edge of a "tertiary" run. Set to the left edge of that run. | |
802 while (InlineBox* tertiaryBox = inlineBox->prevLeafChildIgnoringLine
Break()) { | |
803 if (tertiaryBox->bidiLevel() <= level) | |
804 break; | |
805 inlineBox = tertiaryBox; | |
806 } | |
807 return InlineBoxPosition(inlineBox, inlineBox->caretLeftmostOffset()
); | |
808 } | |
809 return InlineBoxPosition(inlineBox, caretOffset); | |
810 } | |
811 | |
812 if (layoutObject && layoutObject->style()->unicodeBidi() == Plaintext) { | |
813 if (inlineBox->bidiLevel() < level) | |
814 return InlineBoxPosition(inlineBox, inlineBox->caretLeftmostOffset()
); | |
815 return InlineBoxPosition(inlineBox, inlineBox->caretRightmostOffset()); | |
816 } | |
817 | |
818 InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak(); | |
819 if (!nextBox || nextBox->bidiLevel() < level) { | |
820 // Right edge of a secondary run. Set to the left edge of the entire | |
821 // run. | |
822 while (InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak())
{ | |
823 if (prevBox->bidiLevel() < level) | |
824 break; | |
825 inlineBox = prevBox; | |
826 } | |
827 return InlineBoxPosition(inlineBox, inlineBox->caretLeftmostOffset()); | |
828 } | |
829 | |
830 if (nextBox->bidiLevel() <= level) | |
831 return InlineBoxPosition(inlineBox, caretOffset); | |
832 | |
833 // Left edge of a "tertiary" run. Set to the right edge of that run. | |
834 while (InlineBox* tertiaryBox = inlineBox->nextLeafChildIgnoringLineBreak())
{ | |
835 if (tertiaryBox->bidiLevel() <= level) | |
836 break; | |
837 inlineBox = tertiaryBox; | |
838 } | |
839 return InlineBoxPosition(inlineBox, inlineBox->caretRightmostOffset()); | |
840 } | |
841 | |
842 InlineBoxPosition computeInlineBoxPosition(const Position& position, TextAffinit
y affinity, TextDirection primaryDirection) | |
843 { | |
844 return computeInlineBoxPositionAlgorithm<EditingStrategy>(position, affinity
, primaryDirection); | |
845 } | |
846 | |
847 InlineBoxPosition computeInlineBoxPosition(const PositionInComposedTree& positio
n, TextAffinity affinity, TextDirection primaryDirection) | |
848 { | |
849 return computeInlineBoxPositionAlgorithm<EditingInComposedTreeStrategy>(posi
tion, affinity, primaryDirection); | |
850 } | |
851 | |
852 template <typename Strategy> | |
853 void PositionAlgorithm<Strategy>::debugPosition(const char* msg) const | 603 void PositionAlgorithm<Strategy>::debugPosition(const char* msg) const |
854 { | 604 { |
855 static const char* const anchorTypes[] = { | 605 static const char* const anchorTypes[] = { |
856 "OffsetInAnchor", | 606 "OffsetInAnchor", |
857 "BeforeAnchor", | 607 "BeforeAnchor", |
858 "AfterAnchor", | 608 "AfterAnchor", |
859 "BeforeChildren", | 609 "BeforeChildren", |
860 "AfterChildren", | 610 "AfterChildren", |
861 "Invalid", | 611 "Invalid", |
862 }; | 612 }; |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 | 775 |
1026 void showTree(const blink::Position* pos) | 776 void showTree(const blink::Position* pos) |
1027 { | 777 { |
1028 if (pos) | 778 if (pos) |
1029 pos->showTreeForThis(); | 779 pos->showTreeForThis(); |
1030 else | 780 else |
1031 fprintf(stderr, "Cannot showTree for (nil)\n"); | 781 fprintf(stderr, "Cannot showTree for (nil)\n"); |
1032 } | 782 } |
1033 | 783 |
1034 #endif | 784 #endif |
OLD | NEW |