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

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-27T14:51:58 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 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "core/editing/SelectionAdjuster.h"
27
28 #include "core/editing/EditingUtilities.h"
29
30 namespace blink {
31
32 namespace {
33
34 Node* enclosingShadowHost(Node* node)
35 {
36 for (Node* runner = node; runner; runner = ComposedTreeTraversal::parent(*ru nner)) {
37 if (isShadowHost(runner))
38 return runner;
39 }
40 return nullptr;
41 }
42
43 bool isEnclosedBy(const PositionInComposedTree& position, const Node& node)
44 {
45 ASSERT(position.isNotNull());
46 Node* anchorNode = position.anchorNode();
47 if (anchorNode == node)
48 return !position.isAfterAnchor() && !position.isBeforeAnchor();
49
50 return ComposedTreeTraversal::isDescendantOf(*anchorNode, node);
51 }
52
53 bool isSelectionBoundary(const Node& node)
54 {
55 return isHTMLTextAreaElement(node) || isHTMLInputElement(node) || isHTMLSele ctElement(node);
56 }
57
58 Node* enclosingShadowHostForStart(const PositionInComposedTree& position)
59 {
60 Node* node = position.nodeAsRangeFirstNode();
61 if (!node)
62 return nullptr;
63 Node* shadowHost = enclosingShadowHost(node);
64 if (!shadowHost)
65 return nullptr;
66 if (!isEnclosedBy(position, *shadowHost))
67 return nullptr;
68 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr;
69 }
70
71 Node* enclosingShadowHostForEnd(const PositionInComposedTree& position)
72 {
73 Node* node = position.nodeAsRangeLastNode();
74 if (!node)
75 return nullptr;
76 Node* shadowHost = enclosingShadowHost(node);
77 if (!shadowHost)
78 return nullptr;
79 if (!isEnclosedBy(position, *shadowHost))
80 return nullptr;
81 return isSelectionBoundary(*shadowHost) ? shadowHost : nullptr;
82 }
83
84 PositionInComposedTree adjustPositionInComposedTreeForStart(const PositionInComp osedTree& position, Node* shadowHost)
85 {
86 if (isEnclosedBy(position, *shadowHost)) {
87 if (position.isBeforeChildren())
88 return PositionInComposedTree::beforeNode(shadowHost);
89 return PositionInComposedTree::afterNode(shadowHost);
90 }
91
92 // We use |firstChild|'s after instead of beforeAllChildren for backward
93 // compatibility. The positions are same but the anchors would be different,
94 // and selection painting uses anchor nodes.
95 if (Node* firstChild = ComposedTreeTraversal::firstChild(*shadowHost))
96 return PositionInComposedTree::beforeNode(firstChild);
97 return PositionInComposedTree();
98 }
99
100 Position adjustPositionForEnd(const Position& currentPosition, Node* startContai nerNode)
101 {
102 TreeScope& treeScope = startContainerNode->treeScope();
103
104 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope);
105
106 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo ntainerNode())) {
107 if (ancestor->contains(startContainerNode))
108 return positionAfterNode(ancestor);
109 return positionBeforeNode(ancestor);
110 }
111
112 if (Node* lastChild = treeScope.rootNode().lastChild())
113 return positionAfterNode(lastChild);
114
115 return Position();
116 }
117
118 PositionInComposedTree adjustPositionInComposedTreeForEnd(const PositionInCompos edTree& position, Node* shadowHost)
119 {
120 if (isEnclosedBy(position, *shadowHost)) {
121 if (position.isAfterChildren())
122 return PositionInComposedTree::afterNode(shadowHost);
123 return PositionInComposedTree::beforeNode(shadowHost);
124 }
125
126 // We use |lastChild|'s after instead of afterAllChildren for backward
127 // compatibility. The positions are same but the anchors would be different,
128 // and selection painting uses anchor nodes.
129 if (Node* lastChild = ComposedTreeTraversal::lastChild(*shadowHost))
130 return PositionInComposedTree::afterNode(lastChild);
131 return PositionInComposedTree();
132 }
133
134 Position adjustPositionForStart(const Position& currentPosition, Node* endContai nerNode)
135 {
136 TreeScope& treeScope = endContainerNode->treeScope();
137
138 ASSERT(currentPosition.computeContainerNode()->treeScope() != treeScope);
139
140 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.computeCo ntainerNode())) {
141 if (ancestor->contains(endContainerNode))
142 return positionBeforeNode(ancestor);
143 return positionAfterNode(ancestor);
144 }
145
146 if (Node* firstChild = treeScope.rootNode().firstChild())
147 return positionBeforeNode(firstChild);
148
149 return Position();
150 }
151
152 } // namespace
153
154 // Updates |selectionInComposedTree| to match with |selection|.
155 void SelectionAdjuster::adjustSelectionInComposedTree(VisibleSelectionInComposed Tree* selectionInComposedTree, const VisibleSelection& selection)
156 {
157 if (selection.isNone()) {
158 *selectionInComposedTree = VisibleSelectionInComposedTree();
159 return;
160 }
161
162 const PositionInComposedTree& base = toPositionInComposedTree(selection.base ());
163 const PositionInComposedTree& extent = toPositionInComposedTree(selection.ex tent());
164 const PositionInComposedTree& position1 = toPositionInComposedTree(selection .start());
165 const PositionInComposedTree& position2 = toPositionInComposedTree(selection .end());
166 position1.anchorNode()->updateDistribution();
167 position2.anchorNode()->updateDistribution();
168 selectionInComposedTree->m_base = base;
169 selectionInComposedTree->m_extent = extent;
170 selectionInComposedTree->m_affinity = selection.m_affinity;
171 selectionInComposedTree->m_isDirectional = selection.m_isDirectional;
172 selectionInComposedTree->m_baseIsFirst = base.isNull() || base.compareTo(ext ent) <= 0;
173 if (position1.compareTo(position2) <= 0) {
174 selectionInComposedTree->m_start = position1;
175 selectionInComposedTree->m_end = position2;
176 } else {
177 selectionInComposedTree->m_start = position2;
178 selectionInComposedTree->m_end = position1;
179 }
180 selectionInComposedTree->updateSelectionType();
181 }
182
183 static bool isCrossingShadowBoundaries(const VisibleSelectionInComposedTree& sel ection)
184 {
185 if (!selection.isRange())
186 return false;
187 TreeScope& treeScope = selection.base().anchorNode()->treeScope();
188 return selection.extent().anchorNode()->treeScope() != treeScope
189 || selection.start().anchorNode()->treeScope() != treeScope
190 || selection.end().anchorNode()->treeScope() != treeScope;
191 }
192
193 void SelectionAdjuster::adjustSelectionInDOMTree(VisibleSelection* selection, co nst VisibleSelectionInComposedTree& selectionInComposedTree)
194 {
195 if (selectionInComposedTree.isNone()) {
196 *selection = VisibleSelection();
197 return;
198 }
199
200 const Position& base = toPositionInDOMTree(selectionInComposedTree.base());
201 const Position& extent = toPositionInDOMTree(selectionInComposedTree.extent( ));
202
203 if (isCrossingShadowBoundaries(selectionInComposedTree)) {
204 *selection = VisibleSelection(base, extent);
205 return;
206 }
207
208 const Position& position1 = toPositionInDOMTree(selectionInComposedTree.star t());
209 const Position& position2 = toPositionInDOMTree(selectionInComposedTree.end( ));
210 selection->m_base = base;
211 selection->m_extent = extent;
212 selection->m_affinity = selectionInComposedTree.m_affinity;
213 selection->m_isDirectional = selectionInComposedTree.m_isDirectional;
214 selection->m_baseIsFirst = base.isNull() || base.compareTo(extent) <= 0;
215 if (position1.compareTo(position2) <= 0) {
216 selection->m_start = position1;
217 selection->m_end = position2;
218 } else {
219 selection->m_start = position2;
220 selection->m_end = position1;
221 }
222 selection->updateSelectionType();
223 }
224
225 void SelectionAdjuster::adjustSelectionToAvoidCrossingShadowBoundaries(VisibleSe lection* selection)
226 {
227 // Note: |m_selectionType| isn't computed yet.
228 ASSERT(selection->base().isNotNull());
229 ASSERT(selection->extent().isNotNull());
230 ASSERT(selection->start().isNotNull());
231 ASSERT(selection->end().isNotNull());
232
233 // TODO(hajimehoshi): Checking treeScope is wrong when a node is
234 // distributed, but we leave it as it is for backward compatibility.
235 if (selection->start().anchorNode()->treeScope() == selection->end().anchorN ode()->treeScope())
236 return;
237
238 if (selection->isBaseFirst()) {
239 const Position& newEnd = adjustPositionForEnd(selection->end(), selectio n->start().computeContainerNode());
240 selection->m_extent = newEnd;
241 selection->m_end = newEnd;
242 return;
243 }
244
245 const Position& newStart = adjustPositionForStart(selection->start(), select ion->end().computeContainerNode());
246 selection->m_extent = newStart;
247 selection->m_start = newStart;
248 }
249
250 // This function is called twice. The first is called when |m_start| and |m_end|
251 // or |m_extent| are same, and the second when |m_start| and |m_end| are changed
252 // after downstream/upstream.
253 void SelectionAdjuster::adjustSelectionToAvoidCrossingShadowBoundaries(VisibleSe lectionInComposedTree* selection)
254 {
255 Node* const shadowHostStart = enclosingShadowHostForStart(selection->start() );
256 Node* const shadowHostEnd = enclosingShadowHostForEnd(selection->end());
257 if (shadowHostStart == shadowHostEnd)
258 return;
259
260 if (selection->isBaseFirst()) {
261 Node* const shadowHost = shadowHostStart ? shadowHostStart : shadowHostE nd;
262 const PositionInComposedTree& newEnd = adjustPositionInComposedTreeForEn d(selection->end(), shadowHost);
263 selection->m_extent = newEnd;
264 selection->m_end = newEnd;
265 return;
266 }
267 Node* const shadowHost = shadowHostEnd ? shadowHostEnd : shadowHostStart;
268 const PositionInComposedTree& newStart = adjustPositionInComposedTreeForStar t(selection->start(), shadowHost);
269 selection->m_extent = newStart;
270 selection->m_start = newStart;
271 }
272
273 } // 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