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 reserv
ed. |
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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 #include "platform/Logging.h" | 59 #include "platform/Logging.h" |
60 #include "platform/RuntimeEnabledFeatures.h" | 60 #include "platform/RuntimeEnabledFeatures.h" |
61 #include "platform/heap/Handle.h" | 61 #include "platform/heap/Handle.h" |
62 #include "platform/text/TextBoundaries.h" | 62 #include "platform/text/TextBoundaries.h" |
63 | 63 |
64 namespace blink { | 64 namespace blink { |
65 | 65 |
66 using namespace HTMLNames; | 66 using namespace HTMLNames; |
67 using namespace WTF::Unicode; | 67 using namespace WTF::Unicode; |
68 | 68 |
| 69 template <typename PositionType> |
| 70 static PositionType canonicalizeCandidate(const PositionType& candidate) |
| 71 { |
| 72 if (candidate.isNull()) |
| 73 return PositionType(); |
| 74 ASSERT(isVisuallyEquivalentCandidate(candidate)); |
| 75 PositionType upstream = mostBackwardCaretPosition(candidate); |
| 76 if (isVisuallyEquivalentCandidate(upstream)) |
| 77 return upstream; |
| 78 return candidate; |
| 79 } |
| 80 |
| 81 template <typename PositionType> |
| 82 static PositionType canonicalPosition(const PositionType& passedPosition) |
| 83 { |
| 84 // Sometimes updating selection positions can be extremely expensive and |
| 85 // occur frequently. Often calling preventDefault on mousedown events can |
| 86 // avoid doing unnecessary text selection work. http://crbug.com/472258. |
| 87 TRACE_EVENT0("blink", "VisiblePosition::canonicalPosition"); |
| 88 |
| 89 // The updateLayout call below can do so much that even the position passed |
| 90 // in to us might get changed as a side effect. Specifically, there are code |
| 91 // paths that pass selection endpoints, and updateLayout can change the |
| 92 // selection. |
| 93 PositionType position = passedPosition; |
| 94 |
| 95 // FIXME (9535): Canonicalizing to the leftmost candidate means that if |
| 96 // we're at a line wrap, we will ask layoutObjects to paint downstream |
| 97 // carets for other layoutObjects. To fix this, we need to either a) add |
| 98 // code to all paintCarets to pass the responsibility off to the appropriate |
| 99 // layoutObject for VisiblePosition's like these, or b) canonicalize to the |
| 100 // rightmost candidate unless the affinity is upstream. |
| 101 if (position.isNull()) |
| 102 return PositionType(); |
| 103 |
| 104 ASSERT(position.document()); |
| 105 position.document()->updateLayoutIgnorePendingStylesheets(); |
| 106 |
| 107 Node* node = position.computeContainerNode(); |
| 108 |
| 109 PositionType candidate = mostBackwardCaretPosition(position); |
| 110 if (isVisuallyEquivalentCandidate(candidate)) |
| 111 return candidate; |
| 112 candidate = mostForwardCaretPosition(position); |
| 113 if (isVisuallyEquivalentCandidate(candidate)) |
| 114 return candidate; |
| 115 |
| 116 // When neither upstream or downstream gets us to a candidate |
| 117 // (upstream/downstream won't leave blocks or enter new ones), we search |
| 118 // forward and backward until we find one. |
| 119 PositionType next = canonicalizeCandidate(nextCandidate(position)); |
| 120 PositionType prev = canonicalizeCandidate(previousCandidate(position)); |
| 121 Node* nextNode = next.anchorNode(); |
| 122 Node* prevNode = prev.anchorNode(); |
| 123 |
| 124 // The new position must be in the same editable element. Enforce that |
| 125 // first. Unless the descent is from a non-editable html element to an |
| 126 // editable body. |
| 127 if (isHTMLHtmlElement(node) && !node->hasEditableStyle() && node->document()
.body() && node->document().body()->hasEditableStyle()) |
| 128 return next.isNotNull() ? next : prev; |
| 129 |
| 130 Element* editingRoot = editableRootForPosition(position); |
| 131 |
| 132 // If the html element is editable, descending into its body will look like |
| 133 // a descent from non-editable to editable content since |
| 134 // |rootEditableElementOf()| always stops at the body. |
| 135 if (isHTMLHtmlElement(editingRoot) || position.anchorNode()->isDocumentNode(
)) |
| 136 return next.isNotNull() ? next : prev; |
| 137 |
| 138 bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev)
== editingRoot; |
| 139 bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next)
== editingRoot; |
| 140 if (prevIsInSameEditableElement && !nextIsInSameEditableElement) |
| 141 return prev; |
| 142 |
| 143 if (nextIsInSameEditableElement && !prevIsInSameEditableElement) |
| 144 return next; |
| 145 |
| 146 if (!nextIsInSameEditableElement && !prevIsInSameEditableElement) |
| 147 return PositionType(); |
| 148 |
| 149 // The new position should be in the same block flow element. Favor that. |
| 150 Element* originalBlock = node ? enclosingBlockFlowElement(*node) : 0; |
| 151 bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) &
& nextNode != originalBlock; |
| 152 bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) &
& prevNode != originalBlock; |
| 153 if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock) |
| 154 return prev; |
| 155 |
| 156 return next; |
| 157 } |
| 158 |
| 159 Position canonicalPositionOf(const Position& position) |
| 160 { |
| 161 return canonicalPosition(position); |
| 162 } |
| 163 |
| 164 PositionInComposedTree canonicalPositionOf(const PositionInComposedTree& positio
n) |
| 165 { |
| 166 return canonicalPosition(position); |
| 167 } |
| 168 |
69 static Node* previousLeafWithSameEditability(Node* node, EditableType editableTy
pe) | 169 static Node* previousLeafWithSameEditability(Node* node, EditableType editableTy
pe) |
70 { | 170 { |
71 bool editable = node->hasEditableStyle(editableType); | 171 bool editable = node->hasEditableStyle(editableType); |
72 node = previousAtomicLeafNode(*node); | 172 node = previousAtomicLeafNode(*node); |
73 while (node) { | 173 while (node) { |
74 if (editable == node->hasEditableStyle(editableType)) | 174 if (editable == node->hasEditableStyle(editableType)) |
75 return node; | 175 return node; |
76 node = previousAtomicLeafNode(*node); | 176 node = previousAtomicLeafNode(*node); |
77 } | 177 } |
78 return 0; | 178 return 0; |
(...skipping 2371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2450 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivale
nt()); | 2550 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivale
nt()); |
2451 case CanSkipOverEditingBoundary: | 2551 case CanSkipOverEditingBoundary: |
2452 return skipToStartOfEditingBoundary(prev, visiblePosition.deepEquivalent
()); | 2552 return skipToStartOfEditingBoundary(prev, visiblePosition.deepEquivalent
()); |
2453 } | 2553 } |
2454 | 2554 |
2455 ASSERT_NOT_REACHED(); | 2555 ASSERT_NOT_REACHED(); |
2456 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivalent()
); | 2556 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivalent()
); |
2457 } | 2557 } |
2458 | 2558 |
2459 } // namespace blink | 2559 } // namespace blink |
OLD | NEW |