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