| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights |
| 3 * reserved. |
| 3 * | 4 * |
| 4 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 6 * are met: | 7 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 11 * notice, this list of conditions and the following disclaimer in the |
| 11 * documentation and/or other materials provided with the distribution. | 12 * documentation and/or other materials provided with the distribution. |
| 12 * | 13 * |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 409 : m_rootInlineBox(0) {} | 410 : m_rootInlineBox(0) {} |
| 410 | 411 |
| 411 const InlineTextBox* CachedLogicallyOrderedLeafBoxes::previousTextBox( | 412 const InlineTextBox* CachedLogicallyOrderedLeafBoxes::previousTextBox( |
| 412 const RootInlineBox* root, | 413 const RootInlineBox* root, |
| 413 const InlineTextBox* box) { | 414 const InlineTextBox* box) { |
| 414 if (!root) | 415 if (!root) |
| 415 return 0; | 416 return 0; |
| 416 | 417 |
| 417 collectBoxes(root); | 418 collectBoxes(root); |
| 418 | 419 |
| 419 // If box is null, root is box's previous RootInlineBox, and previousBox is th
e last logical box in root. | 420 // If box is null, root is box's previous RootInlineBox, and previousBox is |
| 421 // the last logical box in root. |
| 420 int boxIndex = m_leafBoxes.size() - 1; | 422 int boxIndex = m_leafBoxes.size() - 1; |
| 421 if (box) | 423 if (box) |
| 422 boxIndex = boxIndexInLeaves(box) - 1; | 424 boxIndex = boxIndexInLeaves(box) - 1; |
| 423 | 425 |
| 424 for (int i = boxIndex; i >= 0; --i) { | 426 for (int i = boxIndex; i >= 0; --i) { |
| 425 if (m_leafBoxes[i]->isInlineTextBox()) | 427 if (m_leafBoxes[i]->isInlineTextBox()) |
| 426 return toInlineTextBox(m_leafBoxes[i]); | 428 return toInlineTextBox(m_leafBoxes[i]); |
| 427 } | 429 } |
| 428 | 430 |
| 429 return 0; | 431 return 0; |
| 430 } | 432 } |
| 431 | 433 |
| 432 const InlineTextBox* CachedLogicallyOrderedLeafBoxes::nextTextBox( | 434 const InlineTextBox* CachedLogicallyOrderedLeafBoxes::nextTextBox( |
| 433 const RootInlineBox* root, | 435 const RootInlineBox* root, |
| 434 const InlineTextBox* box) { | 436 const InlineTextBox* box) { |
| 435 if (!root) | 437 if (!root) |
| 436 return 0; | 438 return 0; |
| 437 | 439 |
| 438 collectBoxes(root); | 440 collectBoxes(root); |
| 439 | 441 |
| 440 // If box is null, root is box's next RootInlineBox, and nextBox is the first
logical box in root. | 442 // If box is null, root is box's next RootInlineBox, and nextBox is the first |
| 441 // Otherwise, root is box's RootInlineBox, and nextBox is the next logical box
in the same line. | 443 // logical box in root. Otherwise, root is box's RootInlineBox, and nextBox is |
| 444 // the next logical box in the same line. |
| 442 size_t nextBoxIndex = 0; | 445 size_t nextBoxIndex = 0; |
| 443 if (box) | 446 if (box) |
| 444 nextBoxIndex = boxIndexInLeaves(box) + 1; | 447 nextBoxIndex = boxIndexInLeaves(box) + 1; |
| 445 | 448 |
| 446 for (size_t i = nextBoxIndex; i < m_leafBoxes.size(); ++i) { | 449 for (size_t i = nextBoxIndex; i < m_leafBoxes.size(); ++i) { |
| 447 if (m_leafBoxes[i]->isInlineTextBox()) | 450 if (m_leafBoxes[i]->isInlineTextBox()) |
| 448 return toInlineTextBox(m_leafBoxes[i]); | 451 return toInlineTextBox(m_leafBoxes[i]); |
| 449 } | 452 } |
| 450 | 453 |
| 451 return 0; | 454 return 0; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 617 } | 620 } |
| 618 | 621 |
| 619 static bool isLogicalStartOfWord(TextBreakIterator* iter, | 622 static bool isLogicalStartOfWord(TextBreakIterator* iter, |
| 620 int position, | 623 int position, |
| 621 bool hardLineBreak) { | 624 bool hardLineBreak) { |
| 622 bool boundary = hardLineBreak ? true : iter->isBoundary(position); | 625 bool boundary = hardLineBreak ? true : iter->isBoundary(position); |
| 623 if (!boundary) | 626 if (!boundary) |
| 624 return false; | 627 return false; |
| 625 | 628 |
| 626 iter->following(position); | 629 iter->following(position); |
| 627 // isWordTextBreak returns true after moving across a word and false after mov
ing across a punctuation/space. | 630 // isWordTextBreak returns true after moving across a word and false after |
| 631 // moving across a punctuation/space. |
| 628 return isWordTextBreak(iter); | 632 return isWordTextBreak(iter); |
| 629 } | 633 } |
| 630 | 634 |
| 631 static bool islogicalEndOfWord(TextBreakIterator* iter, | 635 static bool islogicalEndOfWord(TextBreakIterator* iter, |
| 632 int position, | 636 int position, |
| 633 bool hardLineBreak) { | 637 bool hardLineBreak) { |
| 634 bool boundary = iter->isBoundary(position); | 638 bool boundary = iter->isBoundary(position); |
| 635 return (hardLineBreak || boundary) && isWordTextBreak(iter); | 639 return (hardLineBreak || boundary) && isWordTextBreak(iter); |
| 636 } | 640 } |
| 637 | 641 |
| (...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1177 return PositionWithAffinityTemplate<Strategy>(); | 1181 return PositionWithAffinityTemplate<Strategy>(); |
| 1178 } | 1182 } |
| 1179 | 1183 |
| 1180 Node* startNode; | 1184 Node* startNode; |
| 1181 InlineBox* startBox; | 1185 InlineBox* startBox; |
| 1182 if (mode == UseLogicalOrdering) { | 1186 if (mode == UseLogicalOrdering) { |
| 1183 startNode = rootBox->getLogicalStartBoxWithNode(startBox); | 1187 startNode = rootBox->getLogicalStartBoxWithNode(startBox); |
| 1184 if (!startNode) | 1188 if (!startNode) |
| 1185 return PositionWithAffinityTemplate<Strategy>(); | 1189 return PositionWithAffinityTemplate<Strategy>(); |
| 1186 } else { | 1190 } else { |
| 1187 // Generated content (e.g. list markers and CSS :before and :after pseudoele
ments) have no corresponding DOM element, | 1191 // Generated content (e.g. list markers and CSS :before and :after |
| 1188 // and so cannot be represented by a VisiblePosition. Use whatever follows i
nstead. | 1192 // pseudoelements) have no corresponding DOM element, and so cannot be |
| 1193 // represented by a VisiblePosition. Use whatever follows instead. |
| 1189 startBox = rootBox->firstLeafChild(); | 1194 startBox = rootBox->firstLeafChild(); |
| 1190 while (true) { | 1195 while (true) { |
| 1191 if (!startBox) | 1196 if (!startBox) |
| 1192 return PositionWithAffinityTemplate<Strategy>(); | 1197 return PositionWithAffinityTemplate<Strategy>(); |
| 1193 | 1198 |
| 1194 startNode = startBox->getLineLayoutItem().nonPseudoNode(); | 1199 startNode = startBox->getLineLayoutItem().nonPseudoNode(); |
| 1195 if (startNode) | 1200 if (startNode) |
| 1196 break; | 1201 break; |
| 1197 | 1202 |
| 1198 startBox = startBox->nextLeafChild(); | 1203 startBox = startBox->nextLeafChild(); |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1567 absoluteLineDirectionPointToLocalPointInBlock(root, lineDirectionPoint); | 1572 absoluteLineDirectionPointToLocalPointInBlock(root, lineDirectionPoint); |
| 1568 LineLayoutItem lineLayoutItem = | 1573 LineLayoutItem lineLayoutItem = |
| 1569 root->closestLeafChildForPoint(pointInLine, isEditablePosition(p)) | 1574 root->closestLeafChildForPoint(pointInLine, isEditablePosition(p)) |
| 1570 ->getLineLayoutItem(); | 1575 ->getLineLayoutItem(); |
| 1571 Node* node = lineLayoutItem.node(); | 1576 Node* node = lineLayoutItem.node(); |
| 1572 if (node && editingIgnoresContent(node)) | 1577 if (node && editingIgnoresContent(node)) |
| 1573 return VisiblePosition::inParentBeforeNode(*node); | 1578 return VisiblePosition::inParentBeforeNode(*node); |
| 1574 return createVisiblePosition(lineLayoutItem.positionForPoint(pointInLine)); | 1579 return createVisiblePosition(lineLayoutItem.positionForPoint(pointInLine)); |
| 1575 } | 1580 } |
| 1576 | 1581 |
| 1577 // Could not find a previous line. This means we must already be on the first
line. | 1582 // Could not find a previous line. This means we must already be on the first |
| 1578 // Move to the start of the content in this block, which effectively moves us | 1583 // line. Move to the start of the content in this block, which effectively |
| 1579 // to the start of the line we're on. | 1584 // moves us to the start of the line we're on. |
| 1580 Element* rootElement = hasEditableStyle(*node, editableType) | 1585 Element* rootElement = hasEditableStyle(*node, editableType) |
| 1581 ? rootEditableElement(*node, editableType) | 1586 ? rootEditableElement(*node, editableType) |
| 1582 : node->document().documentElement(); | 1587 : node->document().documentElement(); |
| 1583 if (!rootElement) | 1588 if (!rootElement) |
| 1584 return VisiblePosition(); | 1589 return VisiblePosition(); |
| 1585 return VisiblePosition::firstPositionInNode(rootElement); | 1590 return VisiblePosition::firstPositionInNode(rootElement); |
| 1586 } | 1591 } |
| 1587 | 1592 |
| 1588 VisiblePosition nextLinePosition(const VisiblePosition& visiblePosition, | 1593 VisiblePosition nextLinePosition(const VisiblePosition& visiblePosition, |
| 1589 LayoutUnit lineDirectionPoint, | 1594 LayoutUnit lineDirectionPoint, |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1700 VisiblePositionInFlatTree endOfSentence(const VisiblePositionInFlatTree& c) { | 1705 VisiblePositionInFlatTree endOfSentence(const VisiblePositionInFlatTree& c) { |
| 1701 return endOfSentenceAlgorithm<EditingInFlatTreeStrategy>(c); | 1706 return endOfSentenceAlgorithm<EditingInFlatTreeStrategy>(c); |
| 1702 } | 1707 } |
| 1703 | 1708 |
| 1704 static unsigned previousSentencePositionBoundary( | 1709 static unsigned previousSentencePositionBoundary( |
| 1705 const UChar* characters, | 1710 const UChar* characters, |
| 1706 unsigned length, | 1711 unsigned length, |
| 1707 unsigned, | 1712 unsigned, |
| 1708 BoundarySearchContextAvailability, | 1713 BoundarySearchContextAvailability, |
| 1709 bool&) { | 1714 bool&) { |
| 1710 // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's n
ot right. | 1715 // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's |
| 1716 // not right. |
| 1711 TextBreakIterator* iterator = sentenceBreakIterator(characters, length); | 1717 TextBreakIterator* iterator = sentenceBreakIterator(characters, length); |
| 1712 // FIXME: The following function can return -1; we don't handle that. | 1718 // FIXME: The following function can return -1; we don't handle that. |
| 1713 return iterator->preceding(length); | 1719 return iterator->preceding(length); |
| 1714 } | 1720 } |
| 1715 | 1721 |
| 1716 VisiblePosition previousSentencePosition(const VisiblePosition& c) { | 1722 VisiblePosition previousSentencePosition(const VisiblePosition& c) { |
| 1717 DCHECK(c.isValid()) << c; | 1723 DCHECK(c.isValid()) << c; |
| 1718 VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary); | 1724 VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary); |
| 1719 return honorEditingBoundaryAtOrBefore(prev, c.deepEquivalent()); | 1725 return honorEditingBoundaryAtOrBefore(prev, c.deepEquivalent()); |
| 1720 } | 1726 } |
| 1721 | 1727 |
| 1722 static unsigned nextSentencePositionBoundary(const UChar* characters, | 1728 static unsigned nextSentencePositionBoundary(const UChar* characters, |
| 1723 unsigned length, | 1729 unsigned length, |
| 1724 unsigned, | 1730 unsigned, |
| 1725 BoundarySearchContextAvailability, | 1731 BoundarySearchContextAvailability, |
| 1726 bool&) { | 1732 bool&) { |
| 1727 // FIXME: This is identical to endSentenceBoundary. This isn't right, it needs
to | 1733 // FIXME: This is identical to endSentenceBoundary. This isn't right, it needs |
| 1728 // move to the equivlant position in the following sentence. | 1734 // to move to the equivlant position in the following sentence. |
| 1729 TextBreakIterator* iterator = sentenceBreakIterator(characters, length); | 1735 TextBreakIterator* iterator = sentenceBreakIterator(characters, length); |
| 1730 return iterator->following(0); | 1736 return iterator->following(0); |
| 1731 } | 1737 } |
| 1732 | 1738 |
| 1733 VisiblePosition nextSentencePosition(const VisiblePosition& c) { | 1739 VisiblePosition nextSentencePosition(const VisiblePosition& c) { |
| 1734 DCHECK(c.isValid()) << c; | 1740 DCHECK(c.isValid()) << c; |
| 1735 VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary); | 1741 VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary); |
| 1736 return honorEditingBoundaryAtOrAfter(next, c.deepEquivalent()); | 1742 return honorEditingBoundaryAtOrAfter(next, c.deepEquivalent()); |
| 1737 } | 1743 } |
| 1738 | 1744 |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1918 } | 1924 } |
| 1919 const ComputedStyle& style = layoutObject->styleRef(); | 1925 const ComputedStyle& style = layoutObject->styleRef(); |
| 1920 if (style.visibility() != EVisibility::Visible) { | 1926 if (style.visibility() != EVisibility::Visible) { |
| 1921 nextNodeItreator = Strategy::next(*nextNodeItreator, startBlock); | 1927 nextNodeItreator = Strategy::next(*nextNodeItreator, startBlock); |
| 1922 continue; | 1928 continue; |
| 1923 } | 1929 } |
| 1924 | 1930 |
| 1925 if (layoutObject->isBR() || isEnclosingBlock(nextNodeItreator)) | 1931 if (layoutObject->isBR() || isEnclosingBlock(nextNodeItreator)) |
| 1926 break; | 1932 break; |
| 1927 | 1933 |
| 1928 // FIXME: We avoid returning a position where the layoutObject can't accept
the caret. | 1934 // FIXME: We avoid returning a position where the layoutObject can't accept |
| 1935 // the caret. |
| 1929 if (layoutObject->isText() && | 1936 if (layoutObject->isText() && |
| 1930 toLayoutText(layoutObject)->resolvedTextLength()) { | 1937 toLayoutText(layoutObject)->resolvedTextLength()) { |
| 1931 SECURITY_DCHECK(nextNodeItreator->isTextNode()); | 1938 SECURITY_DCHECK(nextNodeItreator->isTextNode()); |
| 1932 LayoutText* const text = toLayoutText(layoutObject); | 1939 LayoutText* const text = toLayoutText(layoutObject); |
| 1933 if (style.preserveNewline()) { | 1940 if (style.preserveNewline()) { |
| 1934 const int length = toLayoutText(layoutObject)->textLength(); | 1941 const int length = toLayoutText(layoutObject)->textLength(); |
| 1935 for (int i = (nextNodeItreator == startNode ? candidateOffset : 0); | 1942 for (int i = (nextNodeItreator == startNode ? candidateOffset : 0); |
| 1936 i < length; ++i) { | 1943 i < length; ++i) { |
| 1937 if ((*text)[i] == '\n') | 1944 if ((*text)[i] == '\n') |
| 1938 return PositionTemplate<Strategy>(toText(nextNodeItreator), | 1945 return PositionTemplate<Strategy>(toText(nextNodeItreator), |
| (...skipping 964 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2903 ? PositionTemplate<Strategy>::editingPositionOf( | 2910 ? PositionTemplate<Strategy>::editingPositionOf( |
| 2904 position.anchorNode(), | 2911 position.anchorNode(), |
| 2905 Strategy::caretMaxOffset(*position.anchorNode())) | 2912 Strategy::caretMaxOffset(*position.anchorNode())) |
| 2906 : position); | 2913 : position); |
| 2907 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible; | 2914 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible; |
| 2908 bool startEditable = hasEditableStyle(*startNode); | 2915 bool startEditable = hasEditableStyle(*startNode); |
| 2909 Node* lastNode = startNode; | 2916 Node* lastNode = startNode; |
| 2910 bool boundaryCrossed = false; | 2917 bool boundaryCrossed = false; |
| 2911 for (; !currentPos.atStart(); currentPos.decrement()) { | 2918 for (; !currentPos.atStart(); currentPos.decrement()) { |
| 2912 Node* currentNode = currentPos.node(); | 2919 Node* currentNode = currentPos.node(); |
| 2913 // Don't check for an editability change if we haven't moved to a different
node, | 2920 // Don't check for an editability change if we haven't moved to a different |
| 2914 // to avoid the expense of computing hasEditableStyle(). | 2921 // node, to avoid the expense of computing hasEditableStyle(). |
| 2915 if (currentNode != lastNode) { | 2922 if (currentNode != lastNode) { |
| 2916 // Don't change editability. | 2923 // Don't change editability. |
| 2917 bool currentEditable = hasEditableStyle(*currentNode); | 2924 bool currentEditable = hasEditableStyle(*currentNode); |
| 2918 if (startEditable != currentEditable) { | 2925 if (startEditable != currentEditable) { |
| 2919 if (rule == CannotCrossEditingBoundary) | 2926 if (rule == CannotCrossEditingBoundary) |
| 2920 break; | 2927 break; |
| 2921 boundaryCrossed = true; | 2928 boundaryCrossed = true; |
| 2922 } | 2929 } |
| 2923 lastNode = currentNode; | 2930 lastNode = currentNode; |
| 2924 } | 2931 } |
| 2925 | 2932 |
| 2926 // If we've moved to a position that is visually distinct, return the last s
aved position. There | 2933 // If we've moved to a position that is visually distinct, return the last |
| 2927 // is code below that terminates early if we're *about* to move to a visuall
y distinct position. | 2934 // saved position. There is code below that terminates early if we're |
| 2935 // *about* to move to a visually distinct position. |
| 2928 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && | 2936 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && |
| 2929 currentNode != boundary) | 2937 currentNode != boundary) |
| 2930 return lastVisible.deprecatedComputePosition(); | 2938 return lastVisible.deprecatedComputePosition(); |
| 2931 | 2939 |
| 2932 // skip position in non-laid out or invisible node | 2940 // skip position in non-laid out or invisible node |
| 2933 LayoutObject* layoutObject = | 2941 LayoutObject* layoutObject = |
| 2934 associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode()); | 2942 associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode()); |
| 2935 if (!layoutObject || | 2943 if (!layoutObject || |
| 2936 layoutObject->style()->visibility() != EVisibility::Visible) | 2944 layoutObject->style()->visibility() != EVisibility::Visible) |
| 2937 continue; | 2945 continue; |
| 2938 | 2946 |
| 2939 if (rule == CanCrossEditingBoundary && boundaryCrossed) { | 2947 if (rule == CanCrossEditingBoundary && boundaryCrossed) { |
| 2940 lastVisible = currentPos; | 2948 lastVisible = currentPos; |
| 2941 break; | 2949 break; |
| 2942 } | 2950 } |
| 2943 | 2951 |
| 2944 // track last visible streamer position | 2952 // track last visible streamer position |
| 2945 if (isStreamer<Strategy>(currentPos)) | 2953 if (isStreamer<Strategy>(currentPos)) |
| 2946 lastVisible = currentPos; | 2954 lastVisible = currentPos; |
| 2947 | 2955 |
| 2948 // Don't move past a position that is visually distinct. We could rely on c
ode above to terminate and | 2956 // Don't move past a position that is visually distinct. We could rely on |
| 2949 // return lastVisible on the next iteration, but we terminate early to avoid
doing a nodeIndex() call. | 2957 // code above to terminate and return lastVisible on the next iteration, but |
| 2958 // we terminate early to avoid doing a nodeIndex() call. |
| 2950 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && | 2959 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && |
| 2951 currentPos.atStartOfNode()) | 2960 currentPos.atStartOfNode()) |
| 2952 return lastVisible.deprecatedComputePosition(); | 2961 return lastVisible.deprecatedComputePosition(); |
| 2953 | 2962 |
| 2954 // Return position after tables and nodes which have content that can be ign
ored. | 2963 // Return position after tables and nodes which have content that can be |
| 2964 // ignored. |
| 2955 if (Strategy::editingIgnoresContent(currentNode) || | 2965 if (Strategy::editingIgnoresContent(currentNode) || |
| 2956 isDisplayInsideTable(currentNode)) { | 2966 isDisplayInsideTable(currentNode)) { |
| 2957 if (currentPos.atEndOfNode()) | 2967 if (currentPos.atEndOfNode()) |
| 2958 return PositionTemplate<Strategy>::afterNode(currentNode); | 2968 return PositionTemplate<Strategy>::afterNode(currentNode); |
| 2959 continue; | 2969 continue; |
| 2960 } | 2970 } |
| 2961 | 2971 |
| 2962 // return current position if it is in laid out text | 2972 // return current position if it is in laid out text |
| 2963 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox()) { | 2973 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox()) { |
| 2964 LayoutText* const textLayoutObject = toLayoutText(layoutObject); | 2974 LayoutText* const textLayoutObject = toLayoutText(layoutObject); |
| 2965 const unsigned textStartOffset = textLayoutObject->textStartOffset(); | 2975 const unsigned textStartOffset = textLayoutObject->textStartOffset(); |
| 2966 if (currentNode != startNode) { | 2976 if (currentNode != startNode) { |
| 2967 // This assertion fires in layout tests in the case-transform.html test
because | 2977 // This assertion fires in layout tests in the case-transform.html test |
| 2968 // of a mix-up between offsets in the text in the DOM tree with text in
the | 2978 // because of a mix-up between offsets in the text in the DOM tree with |
| 2969 // layout tree which can have a different length due to case transformat
ion. | 2979 // text in the layout tree which can have a different length due to case |
| 2980 // transformation. |
| 2970 // Until we resolve that, disable this so we can run the layout tests! | 2981 // Until we resolve that, disable this so we can run the layout tests! |
| 2971 // DCHECK_GE(currentOffset, layoutObject->caretMaxOffset()); | 2982 // DCHECK_GE(currentOffset, layoutObject->caretMaxOffset()); |
| 2972 return PositionTemplate<Strategy>( | 2983 return PositionTemplate<Strategy>( |
| 2973 currentNode, layoutObject->caretMaxOffset() + textStartOffset); | 2984 currentNode, layoutObject->caretMaxOffset() + textStartOffset); |
| 2974 } | 2985 } |
| 2975 | 2986 |
| 2976 // Map offset in DOM node to offset in InlineBox. | 2987 // Map offset in DOM node to offset in InlineBox. |
| 2977 DCHECK_GE(currentPos.offsetInLeafNode(), | 2988 DCHECK_GE(currentPos.offsetInLeafNode(), |
| 2978 static_cast<int>(textStartOffset)); | 2989 static_cast<int>(textStartOffset)); |
| 2979 const unsigned textOffset = | 2990 const unsigned textOffset = |
| (...skipping 21 matching lines...) Expand all Loading... |
| 3001 } | 3012 } |
| 3002 if (textOffset <= box->start() + box->len()) { | 3013 if (textOffset <= box->start() + box->len()) { |
| 3003 if (textOffset > box->start()) | 3014 if (textOffset > box->start()) |
| 3004 return currentPos.computePosition(); | 3015 return currentPos.computePosition(); |
| 3005 continue; | 3016 continue; |
| 3006 } | 3017 } |
| 3007 | 3018 |
| 3008 if (box == lastTextBox || textOffset != box->start() + box->len() + 1) | 3019 if (box == lastTextBox || textOffset != box->start() + box->len() + 1) |
| 3009 continue; | 3020 continue; |
| 3010 | 3021 |
| 3011 // The text continues on the next line only if the last text box is not
on this line and | 3022 // The text continues on the next line only if the last text box is not |
| 3012 // none of the boxes on this line have a larger start offset. | 3023 // on this line and none of the boxes on this line have a larger start |
| 3024 // offset. |
| 3013 | 3025 |
| 3014 bool continuesOnNextLine = true; | 3026 bool continuesOnNextLine = true; |
| 3015 InlineBox* otherBox = box; | 3027 InlineBox* otherBox = box; |
| 3016 while (continuesOnNextLine) { | 3028 while (continuesOnNextLine) { |
| 3017 otherBox = otherBox->nextLeafChild(); | 3029 otherBox = otherBox->nextLeafChild(); |
| 3018 if (!otherBox) | 3030 if (!otherBox) |
| 3019 break; | 3031 break; |
| 3020 if (otherBox == lastTextBox || | 3032 if (otherBox == lastTextBox || |
| 3021 (LineLayoutAPIShim::layoutObjectFrom( | 3033 (LineLayoutAPIShim::layoutObjectFrom( |
| 3022 otherBox->getLineLayoutItem()) == textLayoutObject && | 3034 otherBox->getLineLayoutItem()) == textLayoutObject && |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3072 ? PositionTemplate<Strategy>::editingPositionOf( | 3084 ? PositionTemplate<Strategy>::editingPositionOf( |
| 3073 position.anchorNode(), | 3085 position.anchorNode(), |
| 3074 Strategy::caretMaxOffset(*position.anchorNode())) | 3086 Strategy::caretMaxOffset(*position.anchorNode())) |
| 3075 : position); | 3087 : position); |
| 3076 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible; | 3088 PositionIteratorAlgorithm<Strategy> currentPos = lastVisible; |
| 3077 bool startEditable = hasEditableStyle(*startNode); | 3089 bool startEditable = hasEditableStyle(*startNode); |
| 3078 Node* lastNode = startNode; | 3090 Node* lastNode = startNode; |
| 3079 bool boundaryCrossed = false; | 3091 bool boundaryCrossed = false; |
| 3080 for (; !currentPos.atEnd(); currentPos.increment()) { | 3092 for (; !currentPos.atEnd(); currentPos.increment()) { |
| 3081 Node* currentNode = currentPos.node(); | 3093 Node* currentNode = currentPos.node(); |
| 3082 // Don't check for an editability change if we haven't moved to a different
node, | 3094 // Don't check for an editability change if we haven't moved to a different |
| 3083 // to avoid the expense of computing hasEditableStyle(). | 3095 // node, to avoid the expense of computing hasEditableStyle(). |
| 3084 if (currentNode != lastNode) { | 3096 if (currentNode != lastNode) { |
| 3085 // Don't change editability. | 3097 // Don't change editability. |
| 3086 bool currentEditable = hasEditableStyle(*currentNode); | 3098 bool currentEditable = hasEditableStyle(*currentNode); |
| 3087 if (startEditable != currentEditable) { | 3099 if (startEditable != currentEditable) { |
| 3088 if (rule == CannotCrossEditingBoundary) | 3100 if (rule == CannotCrossEditingBoundary) |
| 3089 break; | 3101 break; |
| 3090 boundaryCrossed = true; | 3102 boundaryCrossed = true; |
| 3091 } | 3103 } |
| 3092 | 3104 |
| 3093 lastNode = currentNode; | 3105 lastNode = currentNode; |
| 3094 } | 3106 } |
| 3095 | 3107 |
| 3096 // stop before going above the body, up into the head | 3108 // stop before going above the body, up into the head |
| 3097 // return the last visible streamer position | 3109 // return the last visible streamer position |
| 3098 if (isHTMLBodyElement(*currentNode) && currentPos.atEndOfNode()) | 3110 if (isHTMLBodyElement(*currentNode) && currentPos.atEndOfNode()) |
| 3099 break; | 3111 break; |
| 3100 | 3112 |
| 3101 // Do not move to a visually distinct position. | 3113 // Do not move to a visually distinct position. |
| 3102 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && | 3114 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && |
| 3103 currentNode != boundary) | 3115 currentNode != boundary) |
| 3104 return lastVisible.deprecatedComputePosition(); | 3116 return lastVisible.deprecatedComputePosition(); |
| 3105 // Do not move past a visually disinct position. | 3117 // Do not move past a visually disinct position. |
| 3106 // Note: The first position after the last in a node whose ends are visually
distinct | 3118 // Note: The first position after the last in a node whose ends are visually |
| 3107 // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1
]. | 3119 // distinct positions will be [boundary->parentNode(), |
| 3120 // originalBlock->nodeIndex() + 1]. |
| 3108 if (boundary && Strategy::parent(*boundary) == currentNode) | 3121 if (boundary && Strategy::parent(*boundary) == currentNode) |
| 3109 return lastVisible.deprecatedComputePosition(); | 3122 return lastVisible.deprecatedComputePosition(); |
| 3110 | 3123 |
| 3111 // skip position in non-laid out or invisible node | 3124 // skip position in non-laid out or invisible node |
| 3112 LayoutObject* layoutObject = | 3125 LayoutObject* layoutObject = |
| 3113 associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode()); | 3126 associatedLayoutObjectOf(*currentNode, currentPos.offsetInLeafNode()); |
| 3114 if (!layoutObject || | 3127 if (!layoutObject || |
| 3115 layoutObject->style()->visibility() != EVisibility::Visible) | 3128 layoutObject->style()->visibility() != EVisibility::Visible) |
| 3116 continue; | 3129 continue; |
| 3117 | 3130 |
| 3118 if (rule == CanCrossEditingBoundary && boundaryCrossed) { | 3131 if (rule == CanCrossEditingBoundary && boundaryCrossed) { |
| 3119 lastVisible = currentPos; | 3132 lastVisible = currentPos; |
| 3120 break; | 3133 break; |
| 3121 } | 3134 } |
| 3122 | 3135 |
| 3123 // track last visible streamer position | 3136 // track last visible streamer position |
| 3124 if (isStreamer<Strategy>(currentPos)) | 3137 if (isStreamer<Strategy>(currentPos)) |
| 3125 lastVisible = currentPos; | 3138 lastVisible = currentPos; |
| 3126 | 3139 |
| 3127 // Return position before tables and nodes which have content that can be ig
nored. | 3140 // Return position before tables and nodes which have content that can be |
| 3141 // ignored. |
| 3128 if (Strategy::editingIgnoresContent(currentNode) || | 3142 if (Strategy::editingIgnoresContent(currentNode) || |
| 3129 isDisplayInsideTable(currentNode)) { | 3143 isDisplayInsideTable(currentNode)) { |
| 3130 if (currentPos.offsetInLeafNode() <= layoutObject->caretMinOffset()) | 3144 if (currentPos.offsetInLeafNode() <= layoutObject->caretMinOffset()) |
| 3131 return PositionTemplate<Strategy>::editingPositionOf( | 3145 return PositionTemplate<Strategy>::editingPositionOf( |
| 3132 currentNode, layoutObject->caretMinOffset()); | 3146 currentNode, layoutObject->caretMinOffset()); |
| 3133 continue; | 3147 continue; |
| 3134 } | 3148 } |
| 3135 | 3149 |
| 3136 // return current position if it is in laid out text | 3150 // return current position if it is in laid out text |
| 3137 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox()) { | 3151 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox()) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3153 box = box->nextTextBox()) { | 3167 box = box->nextTextBox()) { |
| 3154 if (textOffset <= box->end()) { | 3168 if (textOffset <= box->end()) { |
| 3155 if (textOffset >= box->start()) | 3169 if (textOffset >= box->start()) |
| 3156 return currentPos.computePosition(); | 3170 return currentPos.computePosition(); |
| 3157 continue; | 3171 continue; |
| 3158 } | 3172 } |
| 3159 | 3173 |
| 3160 if (box == lastTextBox || textOffset != box->start() + box->len()) | 3174 if (box == lastTextBox || textOffset != box->start() + box->len()) |
| 3161 continue; | 3175 continue; |
| 3162 | 3176 |
| 3163 // The text continues on the next line only if the last text box is not
on this line and | 3177 // The text continues on the next line only if the last text box is not |
| 3164 // none of the boxes on this line have a larger start offset. | 3178 // on this line and none of the boxes on this line have a larger start |
| 3179 // offset. |
| 3165 | 3180 |
| 3166 bool continuesOnNextLine = true; | 3181 bool continuesOnNextLine = true; |
| 3167 InlineBox* otherBox = box; | 3182 InlineBox* otherBox = box; |
| 3168 while (continuesOnNextLine) { | 3183 while (continuesOnNextLine) { |
| 3169 otherBox = otherBox->nextLeafChild(); | 3184 otherBox = otherBox->nextLeafChild(); |
| 3170 if (!otherBox) | 3185 if (!otherBox) |
| 3171 break; | 3186 break; |
| 3172 if (otherBox == lastTextBox || | 3187 if (otherBox == lastTextBox || |
| 3173 (LineLayoutAPIShim::layoutObjectFrom( | 3188 (LineLayoutAPIShim::layoutObjectFrom( |
| 3174 otherBox->getLineLayoutItem()) == textLayoutObject && | 3189 otherBox->getLineLayoutItem()) == textLayoutObject && |
| (...skipping 591 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3766 | 3781 |
| 3767 if (box->bidiLevel() > level) { | 3782 if (box->bidiLevel() > level) { |
| 3768 do { | 3783 do { |
| 3769 nextBox = nextBox->nextLeafChild(); | 3784 nextBox = nextBox->nextLeafChild(); |
| 3770 } while (nextBox && nextBox->bidiLevel() > level); | 3785 } while (nextBox && nextBox->bidiLevel() > level); |
| 3771 | 3786 |
| 3772 if (!nextBox || nextBox->bidiLevel() < level) | 3787 if (!nextBox || nextBox->bidiLevel() < level) |
| 3773 continue; | 3788 continue; |
| 3774 } | 3789 } |
| 3775 } else { | 3790 } else { |
| 3776 // Trailing edge of a secondary run. Set to the leading edge of the enti
re run. | 3791 // Trailing edge of a secondary run. Set to the leading edge of the |
| 3792 // entire run. |
| 3777 while (true) { | 3793 while (true) { |
| 3778 while (InlineBox* prevBox = box->prevLeafChild()) { | 3794 while (InlineBox* prevBox = box->prevLeafChild()) { |
| 3779 if (prevBox->bidiLevel() < level) | 3795 if (prevBox->bidiLevel() < level) |
| 3780 break; | 3796 break; |
| 3781 box = prevBox; | 3797 box = prevBox; |
| 3782 } | 3798 } |
| 3783 if (box->bidiLevel() == level) | 3799 if (box->bidiLevel() == level) |
| 3784 break; | 3800 break; |
| 3785 level = box->bidiLevel(); | 3801 level = box->bidiLevel(); |
| 3786 while (InlineBox* nextBox = box->nextLeafChild()) { | 3802 while (InlineBox* nextBox = box->nextLeafChild()) { |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3994 if (visiblePosition.isNull()) | 4010 if (visiblePosition.isNull()) |
| 3995 return VisiblePositionInFlatTree(); | 4011 return VisiblePositionInFlatTree(); |
| 3996 visiblePosition.deepEquivalent() | 4012 visiblePosition.deepEquivalent() |
| 3997 .document() | 4013 .document() |
| 3998 ->updateStyleAndLayoutIgnorePendingStylesheets(); | 4014 ->updateStyleAndLayoutIgnorePendingStylesheets(); |
| 3999 return previousPositionOfAlgorithm<EditingInFlatTreeStrategy>( | 4015 return previousPositionOfAlgorithm<EditingInFlatTreeStrategy>( |
| 4000 visiblePosition.deepEquivalent(), rule); | 4016 visiblePosition.deepEquivalent(), rule); |
| 4001 } | 4017 } |
| 4002 | 4018 |
| 4003 } // namespace blink | 4019 } // namespace blink |
| OLD | NEW |