Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: third_party/WebKit/Source/core/editing/SelectionAdjuster.cpp

Issue 1640623002: Move SelectionAdjust to its own file (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 2016-01-27T13:38:54 Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
tkent 2016/01/27 05:12:48 Please use the copyright headers of SelectionEdito
yosin_UTC9 2016/01/27 05:58:22 Done
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/editing/SelectionAdjuster.h"
6
7 #include "core/editing/EditingUtilities.h"
8
9 namespace blink {
10
11 namespace {
12
13 Node* enclosingShadowHost(Node* node)
14 {
15 for (Node* runner = node; runner; runner = ComposedTreeTraversal::parent(*ru nner)) {
16 if (isShadowHost(runner))
17 return runner;
18 }
19 return nullptr;
20 }
21
22 bool isEnclosedBy(const PositionInComposedTree& position, const Node& node)
23 {
24 ASSERT(position.isNotNull());
25 Node* anchorNode = position.anchorNode();
26 if (anchorNode == node)
27 return !position.isAfterAnchor() && !position.isBeforeAnchor();
28
29 return ComposedTreeTraversal::isDescendantOf(*anchorNode, node);
30 }
31
32 bool isSelectionBoundary(const Node& node)
33 {
34 return isHTMLTextAreaElement(node) || isHTMLInputElement(node) || isHTMLSele ctElement(node);
35 }
36
37 Node* enclosingShadowHostForStart(const PositionInComposedTree& position)
38 {
39 Node* node = position.nodeAsRangeFirstNode();
40 if (!node)
41 return nullptr;
42 Node* shadowHost = enclosingShadowHost(node);
43 if (!shadowHost)
44 return nullptr;
45 if (!isEnclosedBy(position, *shadowHost))
46 return nullptr;
47 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr;
48 }
49
50 Node* enclosingShadowHostForEnd(const PositionInComposedTree& position)
51 {
52 Node* node = position.nodeAsRangeLastNode();
53 if (!node)
54 return nullptr;
55 Node* shadowHost = enclosingShadowHost(node);
56 if (!shadowHost)
57 return nullptr;
58 if (!isEnclosedBy(position, *shadowHost))
59 return nullptr;
60 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr;
61 }
62
63 PositionInComposedTree adjustPositionInComposedTreeForStart(const PositionInComp osedTree& position, Node* shadowHost)
64 {
65 if (isEnclosedBy(position, *shadowHost)) {
66 if (position.isBeforeChildren())
67 return PositionInComposedTree::beforeNode(shadowHost);
68 return PositionInComposedTree::afterNode(shadowHost);
69 }
70
71 // We use |firstChild|'s after instead of beforeAllChildren for backward
72 // compatibility. The positions are same but the anchors would be different,
73 // and selection painting uses anchor nodes.
74 if (Node* firstChild = ComposedTreeTraversal::firstChild(*shadowHost))
75 return PositionInComposedTree::beforeNode(firstChild);
76 return PositionInComposedTree();
77 }
78
79 Position adjustPositionForEnd(const Position& currentPosition, Node* startContai nerNode)
80 {
81 TreeScope& treeScope = startContainerNode->treeScope();
82
83 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope);
84
85 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo ntainerNode())) {
86 if (ancestor->contains(startContainerNode))
87 return positionAfterNode(ancestor);
88 return positionBeforeNode(ancestor);
89 }
90
91 if (Node* lastChild = treeScope.rootNode().lastChild())
92 return positionAfterNode(lastChild);
93
94 return Position();
95 }
96
97 PositionInComposedTree adjustPositionInComposedTreeForEnd(const PositionInCompos edTree& position, Node* shadowHost)
98 {
99 if (isEnclosedBy(position, *shadowHost)) {
100 if (position.isAfterChildren())
101 return PositionInComposedTree::afterNode(shadowHost);
102 return PositionInComposedTree::beforeNode(shadowHost);
103 }
104
105 // We use |lastChild|'s after instead of afterAllChildren for backward
106 // compatibility. The positions are same but the anchors would be different,
107 // and selection painting uses anchor nodes.
108 if (Node* lastChild = ComposedTreeTraversal::lastChild(*shadowHost))
109 return PositionInComposedTree::afterNode(lastChild);
110 return PositionInComposedTree();
111 }
112
113 Position adjustPositionForStart(const Position& currentPosition, Node* endContai nerNode)
114 {
115 TreeScope& treeScope = endContainerNode->treeScope();
116
117 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope);
118
119 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo ntainerNode())) {
120 if (ancestor->contains(endContainerNode))
121 return positionBeforeNode(ancestor);
122 return positionAfterNode(ancestor);
123 }
124
125 if (Node* firstChild = treeScope.rootNode().firstChild())
126 return positionBeforeNode(firstChild);
127
128 return Position();
129 }
130
131 } // namespace
132
133 // Updates |selectionInComposedTree| to match with |selection|.
134 void SelectionAdjuster::adjustSelectionInComposedTree(VisibleSelectionInComposed Tree* selectionInComposedTree, const VisibleSelection& selection)
135 {
136 if (selection.isNone()) {
137 *selectionInComposedTree = VisibleSelectionInComposedTree();
138 return;
139 }
140
141 const PositionInComposedTree& base = toPositionInComposedTree(selection.base ());
142 const PositionInComposedTree& extent = toPositionInComposedTree(selection.ex tent());
143 const PositionInComposedTree& position1 = toPositionInComposedTree(selection .start());
144 const PositionInComposedTree& position2 = toPositionInComposedTree(selection .end());
145 position1.anchorNode()->updateDistribution();
146 position2.anchorNode()->updateDistribution();
147 selectionInComposedTree->m_base = base;
148 selectionInComposedTree->m_extent = extent;
149 selectionInComposedTree->m_affinity = selection.m_affinity;
150 selectionInComposedTree->m_isDirectional = selection.m_isDirectional;
151 selectionInComposedTree->m_baseIsFirst = base.isNull() || base.compareTo(ext ent) <= 0;
152 if (position1.compareTo(position2) <= 0) {
153 selectionInComposedTree->m_start = position1;
154 selectionInComposedTree->m_end = position2;
155 } else {
156 selectionInComposedTree->m_start = position2;
157 selectionInComposedTree->m_end = position1;
158 }
159 selectionInComposedTree->updateSelectionType();
160 }
161
162 static bool isCrossingShadowBoundaries(const VisibleSelectionInComposedTree& sel ection)
163 {
164 if (!selection.isRange())
165 return false;
166 TreeScope& treeScope = selection.base().anchorNode()->treeScope();
167 return selection.extent().anchorNode()->treeScope() != treeScope
168 || selection.start().anchorNode()->treeScope() != treeScope
169 || selection.end().anchorNode()->treeScope() != treeScope;
170 }
171
172 void SelectionAdjuster::adjustSelectionInDOMTree(VisibleSelection* selection, co nst VisibleSelectionInComposedTree& selectionInComposedTree)
173 {
174 if (selectionInComposedTree.isNone()) {
175 *selection = VisibleSelection();
176 return;
177 }
178
179 const Position& base = toPositionInDOMTree(selectionInComposedTree.base());
180 const Position& extent = toPositionInDOMTree(selectionInComposedTree.extent( ));
181
182 if (isCrossingShadowBoundaries(selectionInComposedTree)) {
183 *selection = VisibleSelection(base, extent);
184 return;
185 }
186
187 const Position& position1 = toPositionInDOMTree(selectionInComposedTree.star t());
188 const Position& position2 = toPositionInDOMTree(selectionInComposedTree.end( ));
189 selection->m_base = base;
190 selection->m_extent = extent;
191 selection->m_affinity = selectionInComposedTree.m_affinity;
192 selection->m_isDirectional = selectionInComposedTree.m_isDirectional;
193 selection->m_baseIsFirst = base.isNull() || base.compareTo(extent) <= 0;
194 if (position1.compareTo(position2) <= 0) {
195 selection->m_start = position1;
196 selection->m_end = position2;
197 } else {
198 selection->m_start = position2;
199 selection->m_end = position1;
200 }
201 selection->updateSelectionType();
202 }
203
204 void SelectionAdjuster::adjustSelectionToAvoidCrossingShadowBoundaries(VisibleSe lection* selection)
205 {
206 // Note: |m_selectionType| isn't computed yet.
207 ASSERT(selection->base().isNotNull());
208 ASSERT(selection->extent().isNotNull());
209 ASSERT(selection->start().isNotNull());
210 ASSERT(selection->end().isNotNull());
211
212 // TODO(hajimehoshi): Checking treeScope is wrong when a node is
213 // distributed, but we leave it as it is for backward compatibility.
214 if (selection->start().anchorNode()->treeScope() == selection->end().anchorN ode()->treeScope())
215 return;
216
217 if (selection->isBaseFirst()) {
218 const Position& newEnd = adjustPositionForEnd(selection->end(), selectio n->start().computeContainerNode());
219 selection->m_extent = newEnd;
220 selection->m_end = newEnd;
221 return;
222 }
223
224 const Position& newStart = adjustPositionForStart(selection->start(), select ion->end().computeContainerNode());
225 selection->m_extent = newStart;
226 selection->m_start = newStart;
227 }
228
229 // This function is called twice. The first is called when |m_start| and |m_end|
230 // or |m_extent| are same, and the second when |m_start| and |m_end| are changed
231 // after downstream/upstream.
232 void SelectionAdjuster::adjustSelectionToAvoidCrossingShadowBoundaries(VisibleSe lectionInComposedTree* selection)
233 {
234 Node* const shadowHostStart = enclosingShadowHostForStart(selection->start() );
235 Node* const shadowHostEnd = enclosingShadowHostForEnd(selection->end());
236 if (shadowHostStart == shadowHostEnd)
237 return;
238
239 if (selection->isBaseFirst()) {
240 Node* const shadowHost = shadowHostStart ? shadowHostStart : shadowHostE nd;
241 const PositionInComposedTree& newEnd = adjustPositionInComposedTreeForEn d(selection->end(), shadowHost);
242 selection->m_extent = newEnd;
243 selection->m_end = newEnd;
244 return;
245 }
246 Node* const shadowHost = shadowHostEnd ? shadowHostEnd : shadowHostStart;
247 const PositionInComposedTree& newStart = adjustPositionInComposedTreeForStar t(selection->start(), shadowHost);
248 selection->m_extent = newStart;
249 selection->m_start = newStart;
250 }
251
252 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/SelectionAdjuster.h ('k') | third_party/WebKit/Source/core/editing/SelectionEditor.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698