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 |