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