OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights
reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 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 15 matching lines...) Expand all Loading... |
26 #include "core/editing/SelectionAdjuster.h" | 26 #include "core/editing/SelectionAdjuster.h" |
27 | 27 |
28 #include "core/editing/EditingUtilities.h" | 28 #include "core/editing/EditingUtilities.h" |
29 | 29 |
30 namespace blink { | 30 namespace blink { |
31 | 31 |
32 namespace { | 32 namespace { |
33 | 33 |
34 Node* enclosingShadowHost(Node* node) | 34 Node* enclosingShadowHost(Node* node) |
35 { | 35 { |
36 for (Node* runner = node; runner; runner = ComposedTreeTraversal::parent(*ru
nner)) { | 36 for (Node* runner = node; runner; runner = FlatTreeTraversal::parent(*runner
)) { |
37 if (isShadowHost(runner)) | 37 if (isShadowHost(runner)) |
38 return runner; | 38 return runner; |
39 } | 39 } |
40 return nullptr; | 40 return nullptr; |
41 } | 41 } |
42 | 42 |
43 bool isEnclosedBy(const PositionInComposedTree& position, const Node& node) | 43 bool isEnclosedBy(const PositionInFlatTree& position, const Node& node) |
44 { | 44 { |
45 ASSERT(position.isNotNull()); | 45 ASSERT(position.isNotNull()); |
46 Node* anchorNode = position.anchorNode(); | 46 Node* anchorNode = position.anchorNode(); |
47 if (anchorNode == node) | 47 if (anchorNode == node) |
48 return !position.isAfterAnchor() && !position.isBeforeAnchor(); | 48 return !position.isAfterAnchor() && !position.isBeforeAnchor(); |
49 | 49 |
50 return ComposedTreeTraversal::isDescendantOf(*anchorNode, node); | 50 return FlatTreeTraversal::isDescendantOf(*anchorNode, node); |
51 } | 51 } |
52 | 52 |
53 bool isSelectionBoundary(const Node& node) | 53 bool isSelectionBoundary(const Node& node) |
54 { | 54 { |
55 return isHTMLTextAreaElement(node) || isHTMLInputElement(node) || isHTMLSele
ctElement(node); | 55 return isHTMLTextAreaElement(node) || isHTMLInputElement(node) || isHTMLSele
ctElement(node); |
56 } | 56 } |
57 | 57 |
58 Node* enclosingShadowHostForStart(const PositionInComposedTree& position) | 58 Node* enclosingShadowHostForStart(const PositionInFlatTree& position) |
59 { | 59 { |
60 Node* node = position.nodeAsRangeFirstNode(); | 60 Node* node = position.nodeAsRangeFirstNode(); |
61 if (!node) | 61 if (!node) |
62 return nullptr; | 62 return nullptr; |
63 Node* shadowHost = enclosingShadowHost(node); | 63 Node* shadowHost = enclosingShadowHost(node); |
64 if (!shadowHost) | 64 if (!shadowHost) |
65 return nullptr; | 65 return nullptr; |
66 if (!isEnclosedBy(position, *shadowHost)) | 66 if (!isEnclosedBy(position, *shadowHost)) |
67 return nullptr; | 67 return nullptr; |
68 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; | 68 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; |
69 } | 69 } |
70 | 70 |
71 Node* enclosingShadowHostForEnd(const PositionInComposedTree& position) | 71 Node* enclosingShadowHostForEnd(const PositionInFlatTree& position) |
72 { | 72 { |
73 Node* node = position.nodeAsRangeLastNode(); | 73 Node* node = position.nodeAsRangeLastNode(); |
74 if (!node) | 74 if (!node) |
75 return nullptr; | 75 return nullptr; |
76 Node* shadowHost = enclosingShadowHost(node); | 76 Node* shadowHost = enclosingShadowHost(node); |
77 if (!shadowHost) | 77 if (!shadowHost) |
78 return nullptr; | 78 return nullptr; |
79 if (!isEnclosedBy(position, *shadowHost)) | 79 if (!isEnclosedBy(position, *shadowHost)) |
80 return nullptr; | 80 return nullptr; |
81 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; | 81 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr; |
82 } | 82 } |
83 | 83 |
84 PositionInComposedTree adjustPositionInComposedTreeForStart(const PositionInComp
osedTree& position, Node* shadowHost) | 84 PositionInFlatTree adjustPositionInFlatTreeForStart(const PositionInFlatTree& po
sition, Node* shadowHost) |
85 { | 85 { |
86 if (isEnclosedBy(position, *shadowHost)) { | 86 if (isEnclosedBy(position, *shadowHost)) { |
87 if (position.isBeforeChildren()) | 87 if (position.isBeforeChildren()) |
88 return PositionInComposedTree::beforeNode(shadowHost); | 88 return PositionInFlatTree::beforeNode(shadowHost); |
89 return PositionInComposedTree::afterNode(shadowHost); | 89 return PositionInFlatTree::afterNode(shadowHost); |
90 } | 90 } |
91 | 91 |
92 // We use |firstChild|'s after instead of beforeAllChildren for backward | 92 // We use |firstChild|'s after instead of beforeAllChildren for backward |
93 // compatibility. The positions are same but the anchors would be different, | 93 // compatibility. The positions are same but the anchors would be different, |
94 // and selection painting uses anchor nodes. | 94 // and selection painting uses anchor nodes. |
95 if (Node* firstChild = ComposedTreeTraversal::firstChild(*shadowHost)) | 95 if (Node* firstChild = FlatTreeTraversal::firstChild(*shadowHost)) |
96 return PositionInComposedTree::beforeNode(firstChild); | 96 return PositionInFlatTree::beforeNode(firstChild); |
97 return PositionInComposedTree(); | 97 return PositionInFlatTree(); |
98 } | 98 } |
99 | 99 |
100 Position adjustPositionForEnd(const Position& currentPosition, Node* startContai
nerNode) | 100 Position adjustPositionForEnd(const Position& currentPosition, Node* startContai
nerNode) |
101 { | 101 { |
102 TreeScope& treeScope = startContainerNode->treeScope(); | 102 TreeScope& treeScope = startContainerNode->treeScope(); |
103 | 103 |
104 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope); | 104 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope); |
105 | 105 |
106 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo
ntainerNode())) { | 106 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo
ntainerNode())) { |
107 if (ancestor->contains(startContainerNode)) | 107 if (ancestor->contains(startContainerNode)) |
108 return positionAfterNode(ancestor); | 108 return positionAfterNode(ancestor); |
109 return positionBeforeNode(ancestor); | 109 return positionBeforeNode(ancestor); |
110 } | 110 } |
111 | 111 |
112 if (Node* lastChild = treeScope.rootNode().lastChild()) | 112 if (Node* lastChild = treeScope.rootNode().lastChild()) |
113 return positionAfterNode(lastChild); | 113 return positionAfterNode(lastChild); |
114 | 114 |
115 return Position(); | 115 return Position(); |
116 } | 116 } |
117 | 117 |
118 PositionInComposedTree adjustPositionInComposedTreeForEnd(const PositionInCompos
edTree& position, Node* shadowHost) | 118 PositionInFlatTree adjustPositionInFlatTreeForEnd(const PositionInFlatTree& posi
tion, Node* shadowHost) |
119 { | 119 { |
120 if (isEnclosedBy(position, *shadowHost)) { | 120 if (isEnclosedBy(position, *shadowHost)) { |
121 if (position.isAfterChildren()) | 121 if (position.isAfterChildren()) |
122 return PositionInComposedTree::afterNode(shadowHost); | 122 return PositionInFlatTree::afterNode(shadowHost); |
123 return PositionInComposedTree::beforeNode(shadowHost); | 123 return PositionInFlatTree::beforeNode(shadowHost); |
124 } | 124 } |
125 | 125 |
126 // We use |lastChild|'s after instead of afterAllChildren for backward | 126 // We use |lastChild|'s after instead of afterAllChildren for backward |
127 // compatibility. The positions are same but the anchors would be different, | 127 // compatibility. The positions are same but the anchors would be different, |
128 // and selection painting uses anchor nodes. | 128 // and selection painting uses anchor nodes. |
129 if (Node* lastChild = ComposedTreeTraversal::lastChild(*shadowHost)) | 129 if (Node* lastChild = FlatTreeTraversal::lastChild(*shadowHost)) |
130 return PositionInComposedTree::afterNode(lastChild); | 130 return PositionInFlatTree::afterNode(lastChild); |
131 return PositionInComposedTree(); | 131 return PositionInFlatTree(); |
132 } | 132 } |
133 | 133 |
134 Position adjustPositionForStart(const Position& currentPosition, Node* endContai
nerNode) | 134 Position adjustPositionForStart(const Position& currentPosition, Node* endContai
nerNode) |
135 { | 135 { |
136 TreeScope& treeScope = endContainerNode->treeScope(); | 136 TreeScope& treeScope = endContainerNode->treeScope(); |
137 | 137 |
138 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope); | 138 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope); |
139 | 139 |
140 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo
ntainerNode())) { | 140 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo
ntainerNode())) { |
141 if (ancestor->contains(endContainerNode)) | 141 if (ancestor->contains(endContainerNode)) |
142 return positionBeforeNode(ancestor); | 142 return positionBeforeNode(ancestor); |
143 return positionAfterNode(ancestor); | 143 return positionAfterNode(ancestor); |
144 } | 144 } |
145 | 145 |
146 if (Node* firstChild = treeScope.rootNode().firstChild()) | 146 if (Node* firstChild = treeScope.rootNode().firstChild()) |
147 return positionBeforeNode(firstChild); | 147 return positionBeforeNode(firstChild); |
148 | 148 |
149 return Position(); | 149 return Position(); |
150 } | 150 } |
151 | 151 |
152 } // namespace | 152 } // namespace |
153 | 153 |
154 // Updates |selectionInComposedTree| to match with |selection|. | 154 // Updates |selectionInFlatTree| to match with |selection|. |
155 void SelectionAdjuster::adjustSelectionInComposedTree(VisibleSelectionInComposed
Tree* selectionInComposedTree, const VisibleSelection& selection) | 155 void SelectionAdjuster::adjustSelectionInFlatTree(VisibleSelectionInFlatTree* se
lectionInFlatTree, const VisibleSelection& selection) |
156 { | 156 { |
157 if (selection.isNone()) { | 157 if (selection.isNone()) { |
158 *selectionInComposedTree = VisibleSelectionInComposedTree(); | 158 *selectionInFlatTree = VisibleSelectionInFlatTree(); |
159 return; | 159 return; |
160 } | 160 } |
161 | 161 |
162 const PositionInComposedTree& base = toPositionInComposedTree(selection.base
()); | 162 const PositionInFlatTree& base = toPositionInFlatTree(selection.base()); |
163 const PositionInComposedTree& extent = toPositionInComposedTree(selection.ex
tent()); | 163 const PositionInFlatTree& extent = toPositionInFlatTree(selection.extent()); |
164 const PositionInComposedTree& position1 = toPositionInComposedTree(selection
.start()); | 164 const PositionInFlatTree& position1 = toPositionInFlatTree(selection.start()
); |
165 const PositionInComposedTree& position2 = toPositionInComposedTree(selection
.end()); | 165 const PositionInFlatTree& position2 = toPositionInFlatTree(selection.end()); |
166 position1.anchorNode()->updateDistribution(); | 166 position1.anchorNode()->updateDistribution(); |
167 position2.anchorNode()->updateDistribution(); | 167 position2.anchorNode()->updateDistribution(); |
168 selectionInComposedTree->m_base = base; | 168 selectionInFlatTree->m_base = base; |
169 selectionInComposedTree->m_extent = extent; | 169 selectionInFlatTree->m_extent = extent; |
170 selectionInComposedTree->m_affinity = selection.m_affinity; | 170 selectionInFlatTree->m_affinity = selection.m_affinity; |
171 selectionInComposedTree->m_isDirectional = selection.m_isDirectional; | 171 selectionInFlatTree->m_isDirectional = selection.m_isDirectional; |
172 selectionInComposedTree->m_granularity = selection.m_granularity; | 172 selectionInFlatTree->m_granularity = selection.m_granularity; |
173 selectionInComposedTree->m_hasTrailingWhitespace = selection.m_hasTrailingWh
itespace; | 173 selectionInFlatTree->m_hasTrailingWhitespace = selection.m_hasTrailingWhites
pace; |
174 selectionInComposedTree->m_baseIsFirst = base.isNull() || base.compareTo(ext
ent) <= 0; | 174 selectionInFlatTree->m_baseIsFirst = base.isNull() || base.compareTo(extent)
<= 0; |
175 if (position1.compareTo(position2) <= 0) { | 175 if (position1.compareTo(position2) <= 0) { |
176 selectionInComposedTree->m_start = position1; | 176 selectionInFlatTree->m_start = position1; |
177 selectionInComposedTree->m_end = position2; | 177 selectionInFlatTree->m_end = position2; |
178 } else { | 178 } else { |
179 selectionInComposedTree->m_start = position2; | 179 selectionInFlatTree->m_start = position2; |
180 selectionInComposedTree->m_end = position1; | 180 selectionInFlatTree->m_end = position1; |
181 } | 181 } |
182 selectionInComposedTree->updateSelectionType(); | 182 selectionInFlatTree->updateSelectionType(); |
183 selectionInComposedTree->didChange(); | 183 selectionInFlatTree->didChange(); |
184 } | 184 } |
185 | 185 |
186 static bool isCrossingShadowBoundaries(const VisibleSelectionInComposedTree& sel
ection) | 186 static bool isCrossingShadowBoundaries(const VisibleSelectionInFlatTree& selecti
on) |
187 { | 187 { |
188 if (!selection.isRange()) | 188 if (!selection.isRange()) |
189 return false; | 189 return false; |
190 TreeScope& treeScope = selection.base().anchorNode()->treeScope(); | 190 TreeScope& treeScope = selection.base().anchorNode()->treeScope(); |
191 return selection.extent().anchorNode()->treeScope() != treeScope | 191 return selection.extent().anchorNode()->treeScope() != treeScope |
192 || selection.start().anchorNode()->treeScope() != treeScope | 192 || selection.start().anchorNode()->treeScope() != treeScope |
193 || selection.end().anchorNode()->treeScope() != treeScope; | 193 || selection.end().anchorNode()->treeScope() != treeScope; |
194 } | 194 } |
195 | 195 |
196 void SelectionAdjuster::adjustSelectionInDOMTree(VisibleSelection* selection, co
nst VisibleSelectionInComposedTree& selectionInComposedTree) | 196 void SelectionAdjuster::adjustSelectionInDOMTree(VisibleSelection* selection, co
nst VisibleSelectionInFlatTree& selectionInFlatTree) |
197 { | 197 { |
198 if (selectionInComposedTree.isNone()) { | 198 if (selectionInFlatTree.isNone()) { |
199 *selection = VisibleSelection(); | 199 *selection = VisibleSelection(); |
200 return; | 200 return; |
201 } | 201 } |
202 | 202 |
203 const Position& base = toPositionInDOMTree(selectionInComposedTree.base()); | 203 const Position& base = toPositionInDOMTree(selectionInFlatTree.base()); |
204 const Position& extent = toPositionInDOMTree(selectionInComposedTree.extent(
)); | 204 const Position& extent = toPositionInDOMTree(selectionInFlatTree.extent()); |
205 | 205 |
206 if (isCrossingShadowBoundaries(selectionInComposedTree)) { | 206 if (isCrossingShadowBoundaries(selectionInFlatTree)) { |
207 *selection = VisibleSelection(base, extent); | 207 *selection = VisibleSelection(base, extent); |
208 return; | 208 return; |
209 } | 209 } |
210 | 210 |
211 const Position& position1 = toPositionInDOMTree(selectionInComposedTree.star
t()); | 211 const Position& position1 = toPositionInDOMTree(selectionInFlatTree.start())
; |
212 const Position& position2 = toPositionInDOMTree(selectionInComposedTree.end(
)); | 212 const Position& position2 = toPositionInDOMTree(selectionInFlatTree.end()); |
213 selection->m_base = base; | 213 selection->m_base = base; |
214 selection->m_extent = extent; | 214 selection->m_extent = extent; |
215 selection->m_affinity = selectionInComposedTree.m_affinity; | 215 selection->m_affinity = selectionInFlatTree.m_affinity; |
216 selection->m_isDirectional = selectionInComposedTree.m_isDirectional; | 216 selection->m_isDirectional = selectionInFlatTree.m_isDirectional; |
217 selection->m_granularity = selectionInComposedTree.m_granularity; | 217 selection->m_granularity = selectionInFlatTree.m_granularity; |
218 selection->m_hasTrailingWhitespace = selectionInComposedTree.m_hasTrailingWh
itespace; | 218 selection->m_hasTrailingWhitespace = selectionInFlatTree.m_hasTrailingWhites
pace; |
219 selection->m_baseIsFirst = base.isNull() || base.compareTo(extent) <= 0; | 219 selection->m_baseIsFirst = base.isNull() || base.compareTo(extent) <= 0; |
220 if (position1.compareTo(position2) <= 0) { | 220 if (position1.compareTo(position2) <= 0) { |
221 selection->m_start = position1; | 221 selection->m_start = position1; |
222 selection->m_end = position2; | 222 selection->m_end = position2; |
223 } else { | 223 } else { |
224 selection->m_start = position2; | 224 selection->m_start = position2; |
225 selection->m_end = position1; | 225 selection->m_end = position1; |
226 } | 226 } |
227 selection->updateSelectionType(); | 227 selection->updateSelectionType(); |
228 selection->didChange(); | 228 selection->didChange(); |
(...skipping 20 matching lines...) Expand all Loading... |
249 } | 249 } |
250 | 250 |
251 const Position& newStart = adjustPositionForStart(selection->start(), select
ion->end().computeContainerNode()); | 251 const Position& newStart = adjustPositionForStart(selection->start(), select
ion->end().computeContainerNode()); |
252 selection->m_extent = newStart; | 252 selection->m_extent = newStart; |
253 selection->m_start = newStart; | 253 selection->m_start = newStart; |
254 } | 254 } |
255 | 255 |
256 // This function is called twice. The first is called when |m_start| and |m_end| | 256 // This function is called twice. The first is called when |m_start| and |m_end| |
257 // or |m_extent| are same, and the second when |m_start| and |m_end| are changed | 257 // or |m_extent| are same, and the second when |m_start| and |m_end| are changed |
258 // after downstream/upstream. | 258 // after downstream/upstream. |
259 void SelectionAdjuster::adjustSelectionToAvoidCrossingShadowBoundaries(VisibleSe
lectionInComposedTree* selection) | 259 void SelectionAdjuster::adjustSelectionToAvoidCrossingShadowBoundaries(VisibleSe
lectionInFlatTree* selection) |
260 { | 260 { |
261 Node* const shadowHostStart = enclosingShadowHostForStart(selection->start()
); | 261 Node* const shadowHostStart = enclosingShadowHostForStart(selection->start()
); |
262 Node* const shadowHostEnd = enclosingShadowHostForEnd(selection->end()); | 262 Node* const shadowHostEnd = enclosingShadowHostForEnd(selection->end()); |
263 if (shadowHostStart == shadowHostEnd) | 263 if (shadowHostStart == shadowHostEnd) |
264 return; | 264 return; |
265 | 265 |
266 if (selection->isBaseFirst()) { | 266 if (selection->isBaseFirst()) { |
267 Node* const shadowHost = shadowHostStart ? shadowHostStart : shadowHostE
nd; | 267 Node* const shadowHost = shadowHostStart ? shadowHostStart : shadowHostE
nd; |
268 const PositionInComposedTree& newEnd = adjustPositionInComposedTreeForEn
d(selection->end(), shadowHost); | 268 const PositionInFlatTree& newEnd = adjustPositionInFlatTreeForEnd(select
ion->end(), shadowHost); |
269 selection->m_extent = newEnd; | 269 selection->m_extent = newEnd; |
270 selection->m_end = newEnd; | 270 selection->m_end = newEnd; |
271 return; | 271 return; |
272 } | 272 } |
273 Node* const shadowHost = shadowHostEnd ? shadowHostEnd : shadowHostStart; | 273 Node* const shadowHost = shadowHostEnd ? shadowHostEnd : shadowHostStart; |
274 const PositionInComposedTree& newStart = adjustPositionInComposedTreeForStar
t(selection->start(), shadowHost); | 274 const PositionInFlatTree& newStart = adjustPositionInFlatTreeForStart(select
ion->start(), shadowHost); |
275 selection->m_extent = newStart; | 275 selection->m_extent = newStart; |
276 selection->m_start = newStart; | 276 selection->m_start = newStart; |
277 } | 277 } |
278 | 278 |
279 } // namespace blink | 279 } // namespace blink |
OLD | NEW |