| 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 |