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

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

Issue 2701363002: Move code for SelectionEditor in FrameSelection.cpp to SelectionEditor.cpp (Closed)
Patch Set: 2017-02-20T16:41:49 Rebase Created 3 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
« no previous file with comments | « third_party/WebKit/Source/core/editing/FrameSelection.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved. 2 * Copyright (C) 2004, 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 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 171
172 void SelectionEditor::contextDestroyed(Document*) { 172 void SelectionEditor::contextDestroyed(Document*) {
173 dispose(); 173 dispose();
174 m_styleVersion = static_cast<uint64_t>(-1); 174 m_styleVersion = static_cast<uint64_t>(-1);
175 m_selection = SelectionInDOMTree(); 175 m_selection = SelectionInDOMTree();
176 m_cachedVisibleSelectionInDOMTree = VisibleSelection(); 176 m_cachedVisibleSelectionInDOMTree = VisibleSelection();
177 m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree(); 177 m_cachedVisibleSelectionInFlatTree = VisibleSelectionInFlatTree();
178 m_cacheIsDirty = false; 178 m_cacheIsDirty = false;
179 } 179 }
180 180
181 static Position computePositionForChildrenRemoval(const Position& position,
182 ContainerNode& container) {
183 Node* node = position.computeContainerNode();
184 if (container.containsIncludingHostElements(*node))
185 return Position::firstPositionInNode(&container);
186 return position;
187 }
188
189 void SelectionEditor::nodeChildrenWillBeRemoved(ContainerNode& container) {
190 if (m_selection.isNone())
191 return;
192 const Position oldBase = m_selection.m_base;
193 const Position oldExtent = m_selection.m_extent;
194 const Position& newBase =
195 computePositionForChildrenRemoval(oldBase, container);
196 const Position& newExtent =
197 computePositionForChildrenRemoval(oldExtent, container);
198 if (newBase == oldBase && newExtent == oldExtent)
199 return;
200 m_selection = SelectionInDOMTree::Builder()
201 .setBaseAndExtent(newBase, newExtent)
202 .build();
203 markCacheDirty();
204 }
205
206 static Position computePositionForNodeRemoval(const Position& position,
207 Node& nodeToBeRemoved) {
208 Position result = position;
209 // TODO(yosin): We should rename |updatePositionForNodeRemoval()|
210 // to |computePositionForNodeRemoval()| to avoid using output parameter.
211 updatePositionForNodeRemoval(result, nodeToBeRemoved);
212 return result;
213 }
214
215 void SelectionEditor::nodeWillBeRemoved(Node& nodeToBeRemoved) {
216 if (m_selection.isNone())
217 return;
218 const Position oldBase = m_selection.m_base;
219 const Position oldExtent = m_selection.m_extent;
220 const Position& newBase =
221 computePositionForNodeRemoval(oldBase, nodeToBeRemoved);
222 const Position& newExtent =
223 computePositionForNodeRemoval(oldExtent, nodeToBeRemoved);
224 if (newBase == oldBase && newExtent == oldExtent)
225 return;
226 m_selection = SelectionInDOMTree::Builder()
227 .setBaseAndExtent(newBase, newExtent)
228 .build();
229 markCacheDirty();
230 }
231
232 static Position updatePositionAfterAdoptingTextReplacement(
233 const Position& position,
234 CharacterData* node,
235 unsigned offset,
236 unsigned oldLength,
237 unsigned newLength) {
238 if (position.anchorNode() != node)
239 return position;
240
241 if (position.isBeforeAnchor()) {
242 return updatePositionAfterAdoptingTextReplacement(
243 Position(node, 0), node, offset, oldLength, newLength);
244 }
245 if (position.isAfterAnchor()) {
246 return updatePositionAfterAdoptingTextReplacement(
247 Position(node, oldLength), node, offset, oldLength, newLength);
248 }
249
250 // See:
251 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range- Mutation
252 DCHECK_GE(position.offsetInContainerNode(), 0);
253 unsigned positionOffset =
254 static_cast<unsigned>(position.offsetInContainerNode());
255 // Replacing text can be viewed as a deletion followed by insertion.
256 if (positionOffset >= offset && positionOffset <= offset + oldLength)
257 positionOffset = offset;
258
259 // Adjust the offset if the position is after the end of the deleted contents
260 // (positionOffset > offset + oldLength) to avoid having a stale offset.
261 if (positionOffset > offset + oldLength)
262 positionOffset = positionOffset - oldLength + newLength;
263
264 // Due to case folding
265 // (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt), LayoutText
266 // length may be different from Text length. A correct implementation would
267 // translate the LayoutText offset to a Text offset; this is just a safety
268 // precaution to avoid offset values that run off the end of the Text.
269 if (positionOffset > node->length())
270 positionOffset = node->length();
271
272 return Position(node, positionOffset);
273 }
274
275 void SelectionEditor::didUpdateCharacterData(CharacterData* node,
276 unsigned offset,
277 unsigned oldLength,
278 unsigned newLength) {
279 // The fragment check is a performance optimization. See
280 // http://trac.webkit.org/changeset/30062.
281 if (m_selection.isNone() || !node || !node->isConnected()) {
282 didFinishDOMMutation();
283 return;
284 }
285 const Position& newBase = updatePositionAfterAdoptingTextReplacement(
286 m_selection.m_base, node, offset, oldLength, newLength);
287 const Position& newExtent = updatePositionAfterAdoptingTextReplacement(
288 m_selection.m_extent, node, offset, oldLength, newLength);
289 didFinishTextChange(newBase, newExtent);
290 }
291
292 // TODO(yosin): We should introduce |Position(const Text&, int)| to avoid
293 // |const_cast<Text*>|.
294 static Position updatePostionAfterAdoptingTextNodesMerged(
295 const Position& position,
296 const Text& mergedNode,
297 const NodeWithIndex& nodeToBeRemovedWithIndex,
298 unsigned oldLength) {
299 Node* const anchorNode = position.anchorNode();
300 const Node& nodeToBeRemoved = nodeToBeRemovedWithIndex.node();
301 switch (position.anchorType()) {
302 case PositionAnchorType::BeforeChildren:
303 case PositionAnchorType::AfterChildren:
304 return position;
305 case PositionAnchorType::BeforeAnchor:
306 if (anchorNode == nodeToBeRemoved)
307 return Position(const_cast<Text*>(&mergedNode), mergedNode.length());
308 return position;
309 case PositionAnchorType::AfterAnchor:
310 if (anchorNode == nodeToBeRemoved)
311 return Position(const_cast<Text*>(&mergedNode), mergedNode.length());
312 if (anchorNode == mergedNode)
313 return Position(const_cast<Text*>(&mergedNode), oldLength);
314 return position;
315 case PositionAnchorType::OffsetInAnchor: {
316 const int offset = position.offsetInContainerNode();
317 if (anchorNode == nodeToBeRemoved)
318 return Position(const_cast<Text*>(&mergedNode), oldLength + offset);
319 if (anchorNode == nodeToBeRemoved.parentNode() &&
320 offset == nodeToBeRemovedWithIndex.index()) {
321 return Position(const_cast<Text*>(&mergedNode), oldLength);
322 }
323 return position;
324 }
325 }
326 NOTREACHED() << position;
327 return position;
328 }
329
330 void SelectionEditor::didMergeTextNodes(
331 const Text& mergedNode,
332 const NodeWithIndex& nodeToBeRemovedWithIndex,
333 unsigned oldLength) {
334 if (m_selection.isNone()) {
335 didFinishDOMMutation();
336 return;
337 }
338 const Position& newBase = updatePostionAfterAdoptingTextNodesMerged(
339 m_selection.m_base, mergedNode, nodeToBeRemovedWithIndex, oldLength);
340 const Position& newExtent = updatePostionAfterAdoptingTextNodesMerged(
341 m_selection.m_extent, mergedNode, nodeToBeRemovedWithIndex, oldLength);
342 didFinishTextChange(newBase, newExtent);
343 }
344
345 static Position updatePostionAfterAdoptingTextNodeSplit(
346 const Position& position,
347 const Text& oldNode) {
348 if (!position.anchorNode() || position.anchorNode() != &oldNode ||
349 !position.isOffsetInAnchor())
350 return position;
351 // See:
352 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range- Mutation
353 DCHECK_GE(position.offsetInContainerNode(), 0);
354 unsigned positionOffset =
355 static_cast<unsigned>(position.offsetInContainerNode());
356 unsigned oldLength = oldNode.length();
357 if (positionOffset <= oldLength)
358 return position;
359 return Position(toText(oldNode.nextSibling()), positionOffset - oldLength);
360 }
361
362 void SelectionEditor::didSplitTextNode(const Text& oldNode) {
363 if (m_selection.isNone() || !oldNode.isConnected()) {
364 didFinishDOMMutation();
365 return;
366 }
367 const Position& newBase =
368 updatePostionAfterAdoptingTextNodeSplit(m_selection.m_base, oldNode);
369 const Position& newExtent =
370 updatePostionAfterAdoptingTextNodeSplit(m_selection.m_extent, oldNode);
371 didFinishTextChange(newBase, newExtent);
372 }
373
181 void SelectionEditor::resetLogicalRange() { 374 void SelectionEditor::resetLogicalRange() {
182 // Non-collapsed ranges are not allowed to start at the end of a line that 375 // Non-collapsed ranges are not allowed to start at the end of a line that
183 // is wrapped, they start at the beginning of the next line instead 376 // is wrapped, they start at the beginning of the next line instead
184 if (!m_logicalRange) 377 if (!m_logicalRange)
185 return; 378 return;
186 m_logicalRange->dispose(); 379 m_logicalRange->dispose();
187 m_logicalRange = nullptr; 380 m_logicalRange = nullptr;
188 } 381 }
189 382
190 void SelectionEditor::setLogicalRange(Range* range) { 383 void SelectionEditor::setLogicalRange(Range* range) {
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 visitor->trace(m_frame); 446 visitor->trace(m_frame);
254 visitor->trace(m_selection); 447 visitor->trace(m_selection);
255 visitor->trace(m_cachedVisibleSelectionInDOMTree); 448 visitor->trace(m_cachedVisibleSelectionInDOMTree);
256 visitor->trace(m_cachedVisibleSelectionInFlatTree); 449 visitor->trace(m_cachedVisibleSelectionInFlatTree);
257 visitor->trace(m_logicalRange); 450 visitor->trace(m_logicalRange);
258 visitor->trace(m_cachedRange); 451 visitor->trace(m_cachedRange);
259 SynchronousMutationObserver::trace(visitor); 452 SynchronousMutationObserver::trace(visitor);
260 } 453 }
261 454
262 } // namespace blink 455 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/FrameSelection.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698