1 /*
2 * Copyright (C) 2004, 2005, 2006 Apple Computer, 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 "config.h"
27 #include "core/editing/VisibleSelection.h"
28
29 #include "bindings/core/v8/ExceptionState.h"
30 #include "core/dom/Document.h"
31 #include "core/dom/Element.h"
32 #include "core/dom/Range.h"
33 #include "core/editing/TextIterator.h"
34 #include "core/editing/VisibleUnits.h"
35 #include "core/editing/htmlediting.h"
36 #include "core/rendering/RenderObject.h"
37 #include "platform/geometry/LayoutPoint.h"
38 #include "wtf/Assertions.h"
39 #include "wtf/text/CString.h"
40 #include "wtf/text/StringBuilder.h"
41 #include "wtf/unicode/CharacterNames.h"
42
43 #ifndef NDEBUG
44 #include <stdio.h>
45 #endif
46
47 namespace blink {
48
VisibleSelection()49 VisibleSelection::VisibleSelection()
50 : m_affinity(DOWNSTREAM)
51 , m_changeObserver(nullptr)
52 , m_selectionType(NoSelection)
53 , m_baseIsFirst(true)
54 , m_isDirectional(false)
55 {
56 }
57
VisibleSelection(const Position & pos,EAffinity affinity,bool isDirectional)58 VisibleSelection::VisibleSelection(const Position& pos, EAffinity affinity, bool isDirectional)
59 : m_base(pos)
60 , m_extent(pos)
61 , m_affinity(affinity)
62 , m_changeObserver(nullptr)
63 , m_isDirectional(isDirectional)
64 {
65 validate();
66 }
67
VisibleSelection(const Position & base,const Position & extent,EAffinity affinity,bool isDirectional)68 VisibleSelection::VisibleSelection(const Position& base, const Position& extent, EAffinity affinity, bool isDirectional)
69 : m_base(base)
70 , m_extent(extent)
71 , m_affinity(affinity)
72 , m_changeObserver(nullptr)
73 , m_isDirectional(isDirectional)
74 {
75 validate();
76 }
77
VisibleSelection(const VisiblePosition & pos,bool isDirectional)78 VisibleSelection::VisibleSelection(const VisiblePosition& pos, bool isDirectional)
79 : m_base(pos.deepEquivalent())
80 , m_extent(pos.deepEquivalent())
81 , m_affinity(pos.affinity())
82 , m_changeObserver(nullptr)
83 , m_isDirectional(isDirectional)
84 {
85 validate();
86 }
87
VisibleSelection(const VisiblePosition & base,const VisiblePosition & extent,bool isDirectional)88 VisibleSelection::VisibleSelection(const VisiblePosition& base, const VisiblePosition& extent, bool isDirectional)
89 : m_base(base.deepEquivalent())
90 , m_extent(extent.deepEquivalent())
91 , m_affinity(base.affinity())
92 , m_changeObserver(nullptr)
93 , m_isDirectional(isDirectional)
94 {
95 validate();
96 }
97
VisibleSelection(const Range * range,EAffinity affinity,bool isDirectional)98 VisibleSelection::VisibleSelection(const Range* range, EAffinity affinity, bool isDirectional)
99 : m_base(range->startPosition())
100 , m_extent(range->endPosition())
101 , m_affinity(affinity)
102 , m_changeObserver(nullptr)
103 , m_isDirectional(isDirectional)
104 {
105 validate();
106 }
107
VisibleSelection(const VisibleSelection & other)108 VisibleSelection::VisibleSelection(const VisibleSelection& other)
109 : m_base(other.m_base)
110 , m_extent(other.m_extent)
111 , m_start(other.m_start)
112 , m_end(other.m_end)
113 , m_affinity(other.m_affinity)
114 , m_changeObserver(nullptr) // Observer is associated with only one VisibleSelection, so this should not be copied.
115 , m_selectionType(other.m_selectionType)
116 , m_baseIsFirst(other.m_baseIsFirst)
117 , m_isDirectional(other.m_isDirectional)
118 {
119 }
120
operator =(const VisibleSelection & other)121 VisibleSelection& VisibleSelection::operator=(const VisibleSelection& other)
122 {
123 didChange();
124
125 m_base = other.m_base;
126 m_extent = other.m_extent;
127 m_start = other.m_start;
128 m_end = other.m_end;
129 m_affinity = other.m_affinity;
130 m_changeObserver = nullptr;
131 m_selectionType = other.m_selectionType;
132 m_baseIsFirst = other.m_baseIsFirst;
133 m_isDirectional = other.m_isDirectional;
134 return *this;
135 }
136
~VisibleSelection()137 VisibleSelection::~VisibleSelection()
138 {
139 #if !ENABLE(OILPAN)
140 didChange();
141 #endif
142 }
143
selectionFromContentsOfNode(Node * node)144 VisibleSelection VisibleSelection::selectionFromContentsOfNode(Node* node)
145 {
146 ASSERT(!editingIgnoresContent(node));
147 return VisibleSelection(firstPositionInNode(node), lastPositionInNode(node), DOWNSTREAM);
148 }
149
setBase(const Position & position)150 void VisibleSelection::setBase(const Position& position)
151 {
152 Position oldBase = m_base;
153 m_base = position;
154 validate();
155 if (m_base != oldBase)
156 didChange();
157 }
158
setBase(const VisiblePosition & visiblePosition)159 void VisibleSelection::setBase(const VisiblePosition& visiblePosition)
160 {
161 Position oldBase = m_base;
162 m_base = visiblePosition.deepEquivalent();
163 validate();
164 if (m_base != oldBase)
165 didChange();
166 }
167
setExtent(const Position & position)168 void VisibleSelection::setExtent(const Position& position)
169 {
170 Position oldExtent = m_extent;
171 m_extent = position;
172 validate();
173 if (m_extent != oldExtent)
174 didChange();
175 }
176
setExtent(const VisiblePosition & visiblePosition)177 void VisibleSelection::setExtent(const VisiblePosition& visiblePosition)
178 {
179 Position oldExtent = m_extent;
180 m_extent = visiblePosition.deepEquivalent();
181 validate();
182 if (m_extent != oldExtent)
183 didChange();
184 }
185
firstRange() const186 PassRefPtrWillBeRawPtr<Range> VisibleSelection::firstRange() const
187 {
188 if (isNone())
189 return nullptr;
190 Position start = m_start.parentAnchoredEquivalent();
191 Position end = m_end.parentAnchoredEquivalent();
192 return Range::create(*start.document(), start, end);
193 }
194
intersectsNode(Node * node) const195 bool VisibleSelection::intersectsNode(Node* node) const
196 {
197 if (isNone())
198 return false;
199 Position start = m_start.parentAnchoredEquivalent();
200 Position end = m_end.parentAnchoredEquivalent();
201 TrackExceptionState exceptionState;
202 return Range::intersectsNode(node, start, end, exceptionState) && !exceptionState.hadException();
203 }
204
toNormalizedRange() const205 PassRefPtrWillBeRawPtr<Range> VisibleSelection::toNormalizedRange() const
206 {
207 Position start, end;
208 if (toNormalizedPositions(start, end))
209 return Range::create(*start.document(), start, end);
210 return nullptr;
211 }
212
toNormalizedPositions(Position & start,Position & end) const213 bool VisibleSelection::toNormalizedPositions(Position& start, Position& end) const
214 {
215 if (isNone())
216 return false;
217
218 // Make sure we have an updated layout since this function is called
219 // in the course of running edit commands which modify the DOM.
220 // Failing to call this can result in equivalentXXXPosition calls returning
221 // incorrect results.
222 m_start.document()->updateLayout();
223
224 // Check again, because updating layout can clear the selection.
225 if (isNone())
226 return false;
227
228 if (isCaret()) {
229 // If the selection is a caret, move the range start upstream. This helps us match
230 // the conventions of text editors tested, which make style determinations based
231 // on the character before the caret, if any.
232 start = m_start.upstream().parentAnchoredEquivalent();
233 end = start;
234 } else {
235 // If the selection is a range, select the minimum range that encompasses the selection.
236 // Again, this is to match the conventions of text editors tested, which make style
237 // determinations based on the first character of the selection.
238 // For instance, this operation helps to make sure that the "X" selected below is the
239 // only thing selected. The range should not be allowed to "leak" out to the end of the
240 // previous text node, or to the beginning of the next text node, each of which has a
241 // different style.
242 //
243 // On a treasure map, <b>X</b> marks the spot.
244 // ^ selected
245 //
246 ASSERT(isRange());
247 start = m_start.downstream();
248 end = m_end.upstream();
249 if (comparePositions(start, end) > 0) {
250 // Make sure the start is before the end.
251 // The end can wind up before the start if collapsed whitespace is the only thing selected.
252 Position tmp = start;
253 start = end;
254 end = tmp;
255 }
256 start = start.parentAnchoredEquivalent();
257 end = end.parentAnchoredEquivalent();
258 }
259
260 if (!start.containerNode() || !end.containerNode())
261 return false;
262
263 return true;
264 }
265
expandUsingGranularity(TextGranularity granularity)266 bool VisibleSelection::expandUsingGranularity(TextGranularity granularity)
267 {
268 if (isNone())
269 return false;
270
271 // FIXME: Do we need to check all of them?
272 Position oldBase = m_base;
273 Position oldExtent = m_extent;
274 Position oldStart = m_start;
275 Position oldEnd = m_end;
276 validate(granularity);
277 if (m_base != oldBase || m_extent != oldExtent || m_start != oldStart || m_end != oldEnd)
278 didChange();
279 return true;
280 }
281
makeSearchRange(const Position & pos)282 static PassRefPtrWillBeRawPtr<Range> makeSearchRange(const Position& pos)
283 {
284 Node* node = pos.deprecatedNode();
285 if (!node)
286 return nullptr;
287 Document& document = node->document();
288 if (!document.documentElement())
289 return nullptr;
290 Element* boundary = enclosingBlockFlowElement(*node);
291 if (!boundary)
292 return nullptr;
293
294 RefPtrWillBeRawPtr<Range> searchRange(Range::create(document));
295 TrackExceptionState exceptionState;
296
297 Position start(pos.parentAnchoredEquivalent());
298 searchRange->selectNodeContents(boundary, exceptionState);
299 searchRange->setStart(start.containerNode(), start.offsetInContainerNode(), exceptionState);
300
301 ASSERT(!exceptionState.hadException());
302 if (exceptionState.hadException())
303 return nullptr;
304
305 return searchRange.release();
306 }
307
appendTrailingWhitespace()308 void VisibleSelection::appendTrailingWhitespace()
309 {
310 RefPtrWillBeRawPtr<Range> searchRange = makeSearchRange(m_end);
311 if (!searchRange)
312 return;
313
314 CharacterIterator charIt(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
315 bool changed = false;
316
317 for (; charIt.length(); charIt.advance(1)) {
318 UChar c = charIt.characterAt(0);
319 if ((!isSpaceOrNewline(c) && c != noBreakSpace) || c == '\n')
320 break;
321 m_end = charIt.endPosition();
322 changed = true;
323 }
324 if (changed)
325 didChange();
326 }
327
setBaseAndExtentToDeepEquivalents()328 void VisibleSelection::setBaseAndExtentToDeepEquivalents()
329 {
330 // Move the selection to rendered positions, if possible.
331 bool baseAndExtentEqual = m_base == m_extent;
332 if (m_base.isNotNull()) {
333 m_base = VisiblePosition(m_base, m_affinity).deepEquivalent();
334 if (baseAndExtentEqual)
335 m_extent = m_base;
336 }
337 if (m_extent.isNotNull() && !baseAndExtentEqual)
338 m_extent = VisiblePosition(m_extent, m_affinity).deepEquivalent();
339
340 // Make sure we do not have a dangling base or extent.
341 if (m_base.isNull() && m_extent.isNull())
342 m_baseIsFirst = true;
343 else if (m_base.isNull()) {
344 m_base = m_extent;
345 m_baseIsFirst = true;
346 } else if (m_extent.isNull()) {
347 m_extent = m_base;
348 m_baseIsFirst = true;
349 } else
350 m_baseIsFirst = comparePositions(m_base, m_extent) <= 0;
351 }
352
setStartAndEndFromBaseAndExtentRespectingGranularity(TextGranularity granularity)353 void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(TextGranularity granularity)
354 {
355 if (m_baseIsFirst) {
356 m_start = m_base;
357 m_end = m_extent;
358 } else {
359 m_start = m_extent;
360 m_end = m_base;
361 }
362
363 switch (granularity) {
364 case CharacterGranularity:
365 // Don't do any expansion.
366 break;
367 case WordGranularity: {
368 // General case: Select the word the caret is positioned inside of, or at the start of (RightWordIfOnBoundary).
369 // Edge case: If the caret is after the last word in a soft-wrapped line or the last word in
370 // the document, select that last word (LeftWordIfOnBoundary).
371 // Edge case: If the caret is after the last word in a paragraph, select from the the end of the
372 // last word to the line break (also RightWordIfOnBoundary);
373 VisiblePosition start = VisiblePosition(m_start, m_affinity);
374 VisiblePosition originalEnd(m_end, m_affinity);
375 EWordSide side = RightWordIfOnBoundary;
376 if (isEndOfEditableOrNonEditableContent(start) || (isEndOfLine(start) && !isStartOfLine(start) && !isEndOfParagraph(start)))
377 side = LeftWordIfOnBoundary;
378 m_start = startOfWord(start, side).deepEquivalent();
379 side = RightWordIfOnBoundary;
380 if (isEndOfEditableOrNonEditableContent(originalEnd) || (isEndOfLine(originalEnd) && !isStartOfLine(originalEnd) && !isEndOfParagraph(originalEnd)))
381 side = LeftWordIfOnBoundary;
382
383 VisiblePosition wordEnd(endOfWord(originalEnd, side));
384 VisiblePosition end(wordEnd);
385
386 if (isEndOfParagraph(originalEnd) && !isEmptyTableCell(m_start.deprecatedNode())) {
387 // Select the paragraph break (the space from the end of a paragraph to the start of
388 // the next one) to match TextEdit.
389 end = wordEnd.next();
390
391 if (Element* table = isFirstPositionAfterTable(end)) {
392 // The paragraph break after the last paragraph in the last cell of a block table ends
393 // at the start of the paragraph after the table.
394 if (isBlock(table))
395 end = end.next(CannotCrossEditingBoundary);
396 else
397 end = wordEnd;
398 }
399
400 if (end.isNull())
401 end = wordEnd;
402
403 }
404
405 m_end = end.deepEquivalent();
406 break;
407 }
408 case SentenceGranularity: {
409 m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
410 m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
411 break;
412 }
413 case LineGranularity: {
414 m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
415 VisiblePosition end = endOfLine(VisiblePosition(m_end, m_affinity));
416 // If the end of this line is at the end of a paragraph, include the space
417 // after the end of the line in the selection.
418 if (isEndOfParagraph(end)) {
419 VisiblePosition next = end.next();
420 if (next.isNotNull())
421 end = next;
422 }
423 m_end = end.deepEquivalent();
424 break;
425 }
426 case LineBoundary:
427 m_start = startOfLine(VisiblePosition(m_start, m_affinity)).deepEquivalent();
428 m_end = endOfLine(VisiblePosition(m_end, m_affinity)).deepEquivalent();
429 break;
430 case ParagraphGranularity: {
431 VisiblePosition pos(m_start, m_affinity);
432 if (isStartOfLine(pos) && isEndOfEditableOrNonEditableContent(pos))
433 pos = pos.previous();
434 m_start = startOfParagraph(pos).deepEquivalent();
435 VisiblePosition visibleParagraphEnd = endOfParagraph(VisiblePosition(m_end, m_affinity));
436
437 // Include the "paragraph break" (the space from the end of this paragraph to the start
438 // of the next one) in the selection.
439 VisiblePosition end(visibleParagraphEnd.next());
440
441 if (Element* table = isFirstPositionAfterTable(end)) {
442 // The paragraph break after the last paragraph in the last cell of a block table ends
443 // at the start of the paragraph after the table, not at the position just after the table.
444 if (isBlock(table))
445 end = end.next(CannotCrossEditingBoundary);
446 // There is no parargraph break after the last paragraph in the last cell of an inline table.
447 else
448 end = visibleParagraphEnd;
449 }
450
451 if (end.isNull())
452 end = visibleParagraphEnd;
453
454 m_end = end.deepEquivalent();
455 break;
456 }
457 case DocumentBoundary:
458 m_start = startOfDocument(VisiblePosition(m_start, m_affinity)).deepEquivalent();
459 m_end = endOfDocument(VisiblePosition(m_end, m_affinity)).deepEquivalent();
460 break;
461 case ParagraphBoundary:
462 m_start = startOfParagraph(VisiblePosition(m_start, m_affinity)).deepEquivalent();
463 m_end = endOfParagraph(VisiblePosition(m_end, m_affinity)).deepEquivalent();
464 break;
465 case SentenceBoundary:
466 m_start = startOfSentence(VisiblePosition(m_start, m_affinity)).deepEquivalent();
467 m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
468 break;
469 }
470
471 // Make sure we do not have a dangling start or end.
472 if (m_start.isNull())
473 m_start = m_end;
474 if (m_end.isNull())
475 m_end = m_start;
476 }
477
updateSelectionType()478 void VisibleSelection::updateSelectionType()
479 {
480 if (m_start.isNull()) {
481 ASSERT(m_end.isNull());
482 m_selectionType = NoSelection;
483 } else if (m_start == m_end || m_start.upstream() == m_end.upstream()) {
484 m_selectionType = CaretSelection;
485 } else
486 m_selectionType = RangeSelection;
487
488 // Affinity only makes sense for a caret
489 if (m_selectionType != CaretSelection)
490 m_affinity = DOWNSTREAM;
491 }
492
validate(TextGranularity granularity)493 void VisibleSelection::validate(TextGranularity granularity)
494 {
495 setBaseAndExtentToDeepEquivalents();
496 setStartAndEndFromBaseAndExtentRespectingGranularity(granularity);
497 adjustSelectionToAvoidCrossingShadowBoundaries();
498 adjustSelectionToAvoidCrossingEditingBoundaries();
499 updateSelectionType();
500
501 if (selectionType() == RangeSelection) {
502 // "Constrain" the selection to be the smallest equivalent range of nodes.
503 // This is a somewhat arbitrary choice, but experience shows that it is
504 // useful to make to make the selection "canonical" (if only for
505 // purposes of comparing selections). This is an ideal point of the code
506 // to do this operation, since all selection changes that result in a RANGE
507 // come through here before anyone uses it.
508 // FIXME: Canonicalizing is good, but haven't we already done it (when we
509 // set these two positions to VisiblePosition deepEquivalent()s above)?
510 m_start = m_start.downstream();
511 m_end = m_end.upstream();
512
513 // FIXME: Position::downstream() or Position::upStream() might violate editing boundaries
514 // if an anchor node has a Shadow DOM. So we adjust selection to avoid crossing editing
515 // boundaries again. See https://bugs.webkit.org/show_bug.cgi?id=87463
516 adjustSelectionToAvoidCrossingEditingBoundaries();
517 }
518 }
519
520 // FIXME: This function breaks the invariant of this class.
521 // But because we use VisibleSelection to store values in editing commands for use when
522 // undoing the command, we need to be able to create a selection that while currently
523 // invalid, will be valid once the changes are undone. This is a design problem.
524 // To fix it we either need to change the invariants of VisibleSelection or create a new
525 // class for editing to use that can manipulate selections that are not currently valid.
setWithoutValidation(const Position & base,const Position & extent)526 void VisibleSelection::setWithoutValidation(const Position& base, const Position& extent)
527 {
528 ASSERT(!base.isNull());
529 ASSERT(!extent.isNull());
530 ASSERT(m_affinity == DOWNSTREAM);
531 m_base = base;
532 m_extent = extent;
533 m_baseIsFirst = comparePositions(base, extent) <= 0;
534 if (m_baseIsFirst) {
535 m_start = base;
536 m_end = extent;
537 } else {
538 m_start = extent;
539 m_end = base;
540 }
541 m_selectionType = base == extent ? CaretSelection : RangeSelection;
542 didChange();
543 }
544
adjustPositionForEnd(const Position & currentPosition,Node * startContainerNode)545 static Position adjustPositionForEnd(const Position& currentPosition, Node* startContainerNode)
546 {
547 TreeScope& treeScope = startContainerNode->treeScope();
548
549 ASSERT(currentPosition.containerNode()->treeScope() != treeScope);
550
551 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.containerNode())) {
552 if (ancestor->contains(startContainerNode))
553 return positionAfterNode(ancestor);
554 return positionBeforeNode(ancestor);
555 }
556
557 if (Node* lastChild = treeScope.rootNode().lastChild())
558 return positionAfterNode(lastChild);
559
560 return Position();
561 }
562
adjustPositionForStart(const Position & currentPosition,Node * endContainerNode)563 static Position adjustPositionForStart(const Position& currentPosition, Node* endContainerNode)
564 {
565 TreeScope& treeScope = endContainerNode->treeScope();
566
567 ASSERT(currentPosition.containerNode()->treeScope() != treeScope);
568
569 if (Node* ancestor = treeScope.ancestorInThisScope(currentPosition.containerNode())) {
570 if (ancestor->contains(endContainerNode))
571 return positionBeforeNode(ancestor);
572 return positionAfterNode(ancestor);
573 }
574
575 if (Node* firstChild = treeScope.rootNode().firstChild())
576 return positionBeforeNode(firstChild);
577
578 return Position();
579 }
580
adjustSelectionToAvoidCrossingShadowBoundaries()581 void VisibleSelection::adjustSelectionToAvoidCrossingShadowBoundaries()
582 {
583 if (m_base.isNull() || m_start.isNull() || m_end.isNull())
584 return;
585
586 if (m_start.anchorNode()->treeScope() == m_end.anchorNode()->treeScope())
587 return;
588
589 if (m_baseIsFirst) {
590 m_extent = adjustPositionForEnd(m_end, m_start.containerNode());
591 m_end = m_extent;
592 } else {
593 m_extent = adjustPositionForStart(m_start, m_end.containerNode());
594 m_start = m_extent;
595 }
596
597 ASSERT(m_start.anchorNode()->treeScope() == m_end.anchorNode()->treeScope());
598 }
599
adjustSelectionToAvoidCrossingEditingBoundaries()600 void VisibleSelection::adjustSelectionToAvoidCrossingEditingBoundaries()
601 {
602 if (m_base.isNull() || m_start.isNull() || m_end.isNull())
603 return;
604
605 ContainerNode* baseRoot = highestEditableRoot(m_base);
606 ContainerNode* startRoot = highestEditableRoot(m_start);
607 ContainerNode* endRoot = highestEditableRoot(m_end);
608
609 Element* baseEditableAncestor = lowestEditableAncestor(m_base.containerNode());
610
611 // The base, start and end are all in the same region. No adjustment necessary.
612 if (baseRoot == startRoot && baseRoot == endRoot)
613 return;
614
615 // The selection is based in editable content.
616 if (baseRoot) {
617 // If the start is outside the base's editable root, cap it at the start of that root.
618 // If the start is in non-editable content that is inside the base's editable root, put it
619 // at the first editable position after start inside the base's editable root.
620 if (startRoot != baseRoot) {
621 VisiblePosition first = firstEditableVisiblePositionAfterPositionInRoot(m_start, baseRoot);
622 m_start = first.deepEquivalent();
623 if (m_start.isNull()) {
624 ASSERT_NOT_REACHED();
625 m_start = m_end;
626 }
627 }
628 // If the end is outside the base's editable root, cap it at the end of that root.
629 // If the end is in non-editable content that is inside the base's root, put it
630 // at the last editable position before the end inside the base's root.
631 if (endRoot != baseRoot) {
632 VisiblePosition last = lastEditableVisiblePositionBeforePositionInRoot(m_end, baseRoot);
633 m_end = last.deepEquivalent();
634 if (m_end.isNull())
635 m_end = m_start;
636 }
637 // The selection is based in non-editable content.
638 } else {
639 // FIXME: Non-editable pieces inside editable content should be atomic, in the same way that editable
640 // pieces in non-editable content are atomic.
641
642 // The selection ends in editable content or non-editable content inside a different editable ancestor,
643 // move backward until non-editable content inside the same lowest editable ancestor is reached.
644 Element* endEditableAncestor = lowestEditableAncestor(m_end.containerNode());
645 if (endRoot || endEditableAncestor != baseEditableAncestor) {
646
647 Position p = previousVisuallyDistinctCandidate(m_end);
648 Element* shadowAncestor = endRoot ? endRoot->shadowHost() : 0;
649 if (p.isNull() && shadowAncestor)
650 p = positionAfterNode(shadowAncestor);
651 while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) {
652 Element* root = editableRootForPosition(p);
653 shadowAncestor = root ? root->shadowHost() : 0;
654 p = isAtomicNode(p.containerNode()) ? positionInParentBeforeNode(*p.containerNode()) : previousVisuallyDistinctCandidate(p);
655 if (p.isNull() && shadowAncestor)
656 p = positionAfterNode(shadowAncestor);
657 }
658 VisiblePosition previous(p);
659
660 if (previous.isNull()) {
661 // The selection crosses an Editing boundary. This is a
662 // programmer error in the editing code. Happy debugging!
663 ASSERT_NOT_REACHED();
664 m_base = Position();
665 m_extent = Position();
666 validate();
667 return;
668 }
669 m_end = previous.deepEquivalent();
670 }
671
672 // The selection starts in editable content or non-editable content inside a different editable ancestor,
673 // move forward until non-editable content inside the same lowest editable ancestor is reached.
674 Element* startEditableAncestor = lowestEditableAncestor(m_start.containerNode());
675 if (startRoot || startEditableAncestor != baseEditableAncestor) {
676 Position p = nextVisuallyDistinctCandidate(m_start);
677 Element* shadowAncestor = startRoot ? startRoot->shadowHost() : 0;
678 if (p.isNull() && shadowAncestor)
679 p = positionBeforeNode(shadowAncestor);
680 while (p.isNotNull() && !(lowestEditableAncestor(p.containerNode()) == baseEditableAncestor && !isEditablePosition(p))) {
681 Element* root = editableRootForPosition(p);
682 shadowAncestor = root ? root->shadowHost() : 0;
683 p = isAtomicNode(p.containerNode()) ? positionInParentAfterNode(*p.containerNode()) : nextVisuallyDistinctCandidate(p);
684 if (p.isNull() && shadowAncestor)
685 p = positionBeforeNode(shadowAncestor);
686 }
687 VisiblePosition next(p);
688
689 if (next.isNull()) {
690 // The selection crosses an Editing boundary. This is a
691 // programmer error in the editing code. Happy debugging!
692 ASSERT_NOT_REACHED();
693 m_base = Position();
694 m_extent = Position();
695 validate();
696 return;
697 }
698 m_start = next.deepEquivalent();
699 }
700 }
701
702 // Correct the extent if necessary.
703 if (baseEditableAncestor != lowestEditableAncestor(m_extent.containerNode()))
704 m_extent = m_baseIsFirst ? m_end : m_start;
705 }
706
visiblePositionRespectingEditingBoundary(const LayoutPoint & localPoint,Node * targetNode) const707 VisiblePosition VisibleSelection::visiblePositionRespectingEditingBoundary(const LayoutPoint& localPoint, Node* targetNode) const
708 {
709 if (!targetNode->renderer())
710 return VisiblePosition();
711
712 LayoutPoint selectionEndPoint = localPoint;
713 Element* editableElement = rootEditableElement();
714
715 if (editableElement && !editableElement->contains(targetNode)) {
716 if (!editableElement->renderer())
717 return VisiblePosition();
718
719 FloatPoint absolutePoint = targetNode->renderer()->localToAbsolute(FloatPoint(selectionEndPoint));
720 selectionEndPoint = roundedLayoutPoint(editableElement->renderer()->absoluteToLocal(absolutePoint));
721 targetNode = editableElement;
722 }
723
724 return VisiblePosition(targetNode->renderer()->positionForPoint(selectionEndPoint));
725 }
726
727
isContentEditable() const728 bool VisibleSelection::isContentEditable() const
729 {
730 return isEditablePosition(start());
731 }
732
hasEditableStyle() const733 bool VisibleSelection::hasEditableStyle() const
734 {
735 return isEditablePosition(start(), ContentIsEditable, DoNotUpdateStyle);
736 }
737
isContentRichlyEditable() const738 bool VisibleSelection::isContentRichlyEditable() const
739 {
740 return isRichlyEditablePosition(start());
741 }
742
rootEditableElement() const743 Element* VisibleSelection::rootEditableElement() const
744 {
745 return editableRootForPosition(start());
746 }
747
nonBoundaryShadowTreeRootNode() const748 Node* VisibleSelection::nonBoundaryShadowTreeRootNode() const
749 {
750 return start().deprecatedNode() ? start().deprecatedNode()->nonBoundaryShadowTreeRootNode() : 0;
751 }
752
ChangeObserver()753 VisibleSelection::ChangeObserver::ChangeObserver()
754 {
755 }
756
~ChangeObserver()757 VisibleSelection::ChangeObserver::~ChangeObserver()
758 {
759 }
760
setChangeObserver(ChangeObserver & observer)761 void VisibleSelection::setChangeObserver(ChangeObserver& observer)
762 {
763 ASSERT(!m_changeObserver);
764 m_changeObserver = &observer;
765 }
766
clearChangeObserver()767 void VisibleSelection::clearChangeObserver()
768 {
769 ASSERT(m_changeObserver);
770 m_changeObserver = nullptr;
771 }
772
didChange()773 void VisibleSelection::didChange()
774 {
775 if (m_changeObserver)
776 m_changeObserver->didChangeVisibleSelection();
777 }
778
trace(Visitor * visitor)779 void VisibleSelection::trace(Visitor* visitor)
780 {
781 visitor->trace(m_base);
782 visitor->trace(m_extent);
783 visitor->trace(m_start);
784 visitor->trace(m_end);
785 visitor->trace(m_changeObserver);
786 }
787
isValidPosition(const Position & position)788 static bool isValidPosition(const Position& position)
789 {
790 if (!position.inDocument())
791 return false;
792
793 if (position.anchorType() != Position::PositionIsOffsetInAnchor)
794 return true;
795
796 if (position.offsetInContainerNode() < 0)
797 return false;
798
799 const unsigned offset = static_cast<unsigned>(position.offsetInContainerNode());
800 const unsigned nodeLength = position.anchorNode()->lengthOfContents();
801 return offset <= nodeLength;
802 }
803
validatePositionsIfNeeded()804 void VisibleSelection::validatePositionsIfNeeded()
805 {
806 if (!isValidPosition(m_base) || !isValidPosition(m_extent) || !isValidPosition(m_start) || !isValidPosition(m_end))
807 validate();
808 }
809
810 #ifndef NDEBUG
811
debugPosition() const812 void VisibleSelection::debugPosition() const
813 {
814 fprintf(stderr, "VisibleSelection ===============\n");
815
816 if (!m_start.anchorNode())
817 fputs("pos: null", stderr);
818 else if (m_start == m_end) {
819 fprintf(stderr, "pos: %s ", m_start.anchorNode()->nodeName().utf8().data());
820 m_start.showAnchorTypeAndOffset();
821 } else {
822 fprintf(stderr, "start: %s ", m_start.anchorNode()->nodeName().utf8().data());
823 m_start.showAnchorTypeAndOffset();
824 fprintf(stderr, "end: %s ", m_end.anchorNode()->nodeName().utf8().data());
825 m_end.showAnchorTypeAndOffset();
826 }
827
828 fprintf(stderr, "================================\n");
829 }
830
formatForDebugger(char * buffer,unsigned length) const831 void VisibleSelection::formatForDebugger(char* buffer, unsigned length) const
832 {
833 StringBuilder result;
834 String s;
835
836 if (isNone()) {
837 result.appendLiteral("<none>");
838 } else {
839 const int FormatBufferSize = 1024;
840 char s[FormatBufferSize];
841 result.appendLiteral("from ");
842 start().formatForDebugger(s, FormatBufferSize);
843 result.append(s);
844 result.appendLiteral(" to ");
845 end().formatForDebugger(s, FormatBufferSize);
846 result.append(s);
847 }
848
849 strncpy(buffer, result.toString().utf8().data(), length - 1);
850 }
851
showTreeForThis() const852 void VisibleSelection::showTreeForThis() const
853 {
854 if (start().anchorNode()) {
855 start().anchorNode()->showTreeAndMark(start().anchorNode(), "S", end().anchorNode(), "E");
856 fputs("start: ", stderr);
857 start().showAnchorTypeAndOffset();
858 fputs("end: ", stderr);
859 end().showAnchorTypeAndOffset();
860 }
861 }
862
863 #endif
864
865 } // namespace blink
866
867 #ifndef NDEBUG
868
showTree(const blink::VisibleSelection & sel)869 void showTree(const blink::VisibleSelection& sel)
870 {
871 sel.showTreeForThis();
872 }
873
showTree(const blink::VisibleSelection * sel)874 void showTree(const blink::VisibleSelection* sel)
875 {
876 if (sel)
877 sel->showTreeForThis();
878 }
879
880 #endif
881