1/*
2 * Copyright (C) 2004, 2005, 2006, 2009, 2013 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 "Position.h"
28
29#include "CSSComputedStyleDeclaration.h"
30#include "Editing.h"
31#include "HTMLBRElement.h"
32#include "HTMLBodyElement.h"
33#include "HTMLHtmlElement.h"
34#include "HTMLNames.h"
35#include "HTMLParserIdioms.h"
36#include "HTMLTableElement.h"
37#include "InlineElementBox.h"
38#include "InlineIterator.h"
39#include "InlineTextBox.h"
40#include "Logging.h"
41#include "NodeTraversal.h"
42#include "PositionIterator.h"
43#include "RenderBlock.h"
44#include "RenderFlexibleBox.h"
45#include "RenderGrid.h"
46#include "RenderInline.h"
47#include "RenderIterator.h"
48#include "RenderLineBreak.h"
49#include "RenderText.h"
50#include "RuntimeEnabledFeatures.h"
51#include "Text.h"
52#include "TextIterator.h"
53#include "VisiblePosition.h"
54#include "VisibleUnits.h"
55#include <stdio.h>
56#include <wtf/text/CString.h>
57#include <wtf/text/TextStream.h>
58#include <wtf/unicode/CharacterNames.h>
59
60#if ENABLE(TREE_DEBUGGING)
61#include <wtf/text/StringBuilder.h>
62#endif
63
64namespace WebCore {
65
66using namespace HTMLNames;
67
68static bool hasInlineBoxWrapper(RenderObject& renderer)
69{
70 if (is<RenderBox>(renderer) && downcast<RenderBox>(renderer).inlineBoxWrapper())
71 return true;
72 if (is<RenderText>(renderer) && downcast<RenderText>(renderer).firstTextBox())
73 return true;
74 if (is<RenderLineBreak>(renderer) && downcast<RenderLineBreak>(renderer).inlineBoxWrapper())
75 return true;
76 return false;
77}
78
79static Node* nextRenderedEditable(Node* node)
80{
81 while ((node = nextLeafNode(node))) {
82 RenderObject* renderer = node->renderer();
83 if (!renderer || !node->hasEditableStyle())
84 continue;
85 if (hasInlineBoxWrapper(*renderer))
86 return node;
87 }
88 return nullptr;
89}
90
91static Node* previousRenderedEditable(Node* node)
92{
93 while ((node = previousLeafNode(node))) {
94 RenderObject* renderer = node->renderer();
95 if (!renderer || !node->hasEditableStyle())
96 continue;
97 if (hasInlineBoxWrapper(*renderer))
98 return node;
99 }
100 return nullptr;
101}
102
103Position::Position(Node* anchorNode, unsigned offset, LegacyEditingPositionFlag)
104 : m_anchorNode(anchorNode)
105 , m_offset(offset)
106 , m_anchorType(anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset))
107 , m_isLegacyEditingPosition(true)
108{
109 ASSERT(!m_anchorNode || !m_anchorNode->isShadowRoot() || m_anchorNode == containerNode());
110 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
111}
112
113Position::Position(Node* anchorNode, AnchorType anchorType)
114 : m_anchorNode(anchorNode)
115 , m_offset(0)
116 , m_anchorType(anchorType)
117 , m_isLegacyEditingPosition(false)
118{
119 ASSERT(!m_anchorNode || !m_anchorNode->isShadowRoot() || m_anchorNode == containerNode());
120 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
121 ASSERT(anchorType != PositionIsOffsetInAnchor);
122 ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIsAfterChildren)
123 && (is<Text>(*m_anchorNode) || editingIgnoresContent(*m_anchorNode))));
124}
125
126Position::Position(Node* anchorNode, int offset, AnchorType anchorType)
127 : m_anchorNode(anchorNode)
128 , m_offset(offset)
129 , m_anchorType(anchorType)
130 , m_isLegacyEditingPosition(false)
131{
132 ASSERT(!m_anchorNode || !editingIgnoresContent(*m_anchorNode));
133 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
134 ASSERT(anchorType == PositionIsOffsetInAnchor);
135}
136
137Position::Position(Text* textNode, unsigned offset)
138 : m_anchorNode(textNode)
139 , m_offset(offset)
140 , m_anchorType(PositionIsOffsetInAnchor)
141 , m_isLegacyEditingPosition(false)
142{
143 ASSERT(m_anchorNode);
144}
145
146void Position::moveToPosition(Node* node, int offset)
147{
148 ASSERT(!editingIgnoresContent(*node));
149 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
150 m_anchorNode = node;
151 m_offset = offset;
152 if (m_isLegacyEditingPosition)
153 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
154}
155void Position::moveToOffset(int offset)
156{
157 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
158 m_offset = offset;
159 if (m_isLegacyEditingPosition)
160 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
161}
162
163Node* Position::containerNode() const
164{
165 if (!m_anchorNode)
166 return nullptr;
167
168 switch (anchorType()) {
169 case PositionIsBeforeChildren:
170 case PositionIsAfterChildren:
171 case PositionIsOffsetInAnchor:
172 return m_anchorNode.get();
173 case PositionIsBeforeAnchor:
174 case PositionIsAfterAnchor:
175 return m_anchorNode->parentNode();
176 }
177 ASSERT_NOT_REACHED();
178 return nullptr;
179}
180
181Text* Position::containerText() const
182{
183 switch (anchorType()) {
184 case PositionIsOffsetInAnchor:
185 return m_anchorNode && is<Text>(*m_anchorNode) ? downcast<Text>(m_anchorNode.get()) : nullptr;
186 case PositionIsBeforeAnchor:
187 case PositionIsAfterAnchor:
188 return nullptr;
189 case PositionIsBeforeChildren:
190 case PositionIsAfterChildren:
191 ASSERT(!m_anchorNode || !is<Text>(*m_anchorNode));
192 return nullptr;
193 }
194 ASSERT_NOT_REACHED();
195 return nullptr;
196}
197
198int Position::computeOffsetInContainerNode() const
199{
200 if (!m_anchorNode)
201 return 0;
202
203 switch (anchorType()) {
204 case PositionIsBeforeChildren:
205 return 0;
206 case PositionIsAfterChildren:
207 return lastOffsetInNode(m_anchorNode.get());
208 case PositionIsOffsetInAnchor:
209 return minOffsetForNode(m_anchorNode.get(), m_offset);
210 case PositionIsBeforeAnchor:
211 return m_anchorNode->computeNodeIndex();
212 case PositionIsAfterAnchor:
213 return m_anchorNode->computeNodeIndex() + 1;
214 }
215 ASSERT_NOT_REACHED();
216 return 0;
217}
218
219int Position::offsetForPositionAfterAnchor() const
220{
221 ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren);
222 ASSERT(!m_isLegacyEditingPosition);
223 ASSERT(m_anchorNode);
224 return m_anchorNode ? lastOffsetForEditing(*m_anchorNode) : 0;
225}
226
227// Neighbor-anchored positions are invalid DOM positions, so they need to be
228// fixed up before handing them off to the Range object.
229Position Position::parentAnchoredEquivalent() const
230{
231 if (!m_anchorNode)
232 return { };
233
234 // FIXME: This should only be necessary for legacy positions, but is also needed for positions before and after Tables
235 if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType != PositionIsAfterChildren)) {
236 if (m_anchorNode->parentNode() && (editingIgnoresContent(*m_anchorNode) || isRenderedTable(m_anchorNode.get())))
237 return positionInParentBeforeNode(m_anchorNode.get());
238 return Position(m_anchorNode.get(), 0, PositionIsOffsetInAnchor);
239 }
240
241 if (!m_anchorNode->isCharacterDataNode()
242 && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->countChildNodes())
243 && (editingIgnoresContent(*m_anchorNode) || isRenderedTable(m_anchorNode.get()))
244 && containerNode()) {
245 return positionInParentAfterNode(m_anchorNode.get());
246 }
247
248 return { containerNode(), computeOffsetInContainerNode(), PositionIsOffsetInAnchor };
249}
250
251RefPtr<Node> Position::firstNode() const
252{
253 auto container = makeRefPtr(containerNode());
254 if (!container)
255 return nullptr;
256 if (is<CharacterData>(*container))
257 return container;
258 if (auto* node = computeNodeAfterPosition())
259 return node;
260 if (!computeOffsetInContainerNode())
261 return container;
262 return NodeTraversal::nextSkippingChildren(*container);
263}
264
265Node* Position::computeNodeBeforePosition() const
266{
267 if (!m_anchorNode)
268 return nullptr;
269
270 switch (anchorType()) {
271 case PositionIsBeforeChildren:
272 return nullptr;
273 case PositionIsAfterChildren:
274 return m_anchorNode->lastChild();
275 case PositionIsOffsetInAnchor:
276 return m_offset ? m_anchorNode->traverseToChildAt(m_offset - 1) : nullptr;
277 case PositionIsBeforeAnchor:
278 return m_anchorNode->previousSibling();
279 case PositionIsAfterAnchor:
280 return m_anchorNode.get();
281 }
282 ASSERT_NOT_REACHED();
283 return nullptr;
284}
285
286Node* Position::computeNodeAfterPosition() const
287{
288 if (!m_anchorNode)
289 return nullptr;
290
291 switch (anchorType()) {
292 case PositionIsBeforeChildren:
293 return m_anchorNode->firstChild();
294 case PositionIsAfterChildren:
295 return nullptr;
296 case PositionIsOffsetInAnchor:
297 return m_anchorNode->traverseToChildAt(m_offset);
298 case PositionIsBeforeAnchor:
299 return m_anchorNode.get();
300 case PositionIsAfterAnchor:
301 return m_anchorNode->nextSibling();
302 }
303 ASSERT_NOT_REACHED();
304 return nullptr;
305}
306
307Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset)
308{
309 if (anchorNode && editingIgnoresContent(*anchorNode)) {
310 if (offset == 0)
311 return Position::PositionIsBeforeAnchor;
312 return Position::PositionIsAfterAnchor;
313 }
314 return Position::PositionIsOffsetInAnchor;
315}
316
317// FIXME: This method is confusing (does it return anchorNode() or containerNode()?) and should be renamed or removed
318Element* Position::element() const
319{
320 Node* node = anchorNode();
321 while (node && !is<Element>(*node))
322 node = node->parentNode();
323 return downcast<Element>(node);
324}
325
326Position Position::previous(PositionMoveType moveType) const
327{
328 Node* node = deprecatedNode();
329 if (!node)
330 return *this;
331
332 int offset = deprecatedEditingOffset();
333 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
334 ASSERT(offset >= 0);
335
336 if (anchorType() == PositionIsBeforeAnchor) {
337 node = containerNode();
338 if (!node)
339 return *this;
340
341 offset = computeOffsetInContainerNode();
342 }
343
344 if (offset > 0) {
345 if (Node* child = node->traverseToChildAt(offset - 1))
346 return lastPositionInOrAfterNode(child);
347
348 // There are two reasons child might be 0:
349 // 1) The node is node like a text node that is not an element, and therefore has no children.
350 // Going backward one character at a time is correct.
351 // 2) The old offset was a bogus offset like (<br>, 1), and there is no child.
352 // Going from 1 to 0 is correct.
353 switch (moveType) {
354 case CodePoint:
355 return createLegacyEditingPosition(node, offset - 1);
356 case Character:
357 return createLegacyEditingPosition(node, uncheckedPreviousOffset(node, offset));
358 case BackwardDeletion:
359 return createLegacyEditingPosition(node, uncheckedPreviousOffsetForBackwardDeletion(node, offset));
360 }
361 }
362
363 ContainerNode* parent = node->parentNode();
364 if (!parent)
365 return *this;
366
367 if (positionBeforeOrAfterNodeIsCandidate(*node))
368 return positionBeforeNode(node);
369
370 Node* previousSibling = node->previousSibling();
371 if (previousSibling && positionBeforeOrAfterNodeIsCandidate(*previousSibling))
372 return positionAfterNode(previousSibling);
373
374 return createLegacyEditingPosition(parent, node->computeNodeIndex());
375}
376
377Position Position::next(PositionMoveType moveType) const
378{
379 ASSERT(moveType != BackwardDeletion);
380
381 Node* node = deprecatedNode();
382 if (!node)
383 return *this;
384
385 int offset = deprecatedEditingOffset();
386 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
387 ASSERT(offset >= 0);
388
389 if (anchorType() == PositionIsAfterAnchor) {
390 node = containerNode();
391 if (!node)
392 return *this;
393
394 offset = computeOffsetInContainerNode();
395 }
396
397 Node* child = node->traverseToChildAt(offset);
398 if (child || (!node->hasChildNodes() && offset < lastOffsetForEditing(*node))) {
399 if (child)
400 return firstPositionInOrBeforeNode(child);
401
402 // There are two reasons child might be 0:
403 // 1) The node is node like a text node that is not an element, and therefore has no children.
404 // Going forward one character at a time is correct.
405 // 2) The new offset is a bogus offset like (<br>, 1), and there is no child.
406 // Going from 0 to 1 is correct.
407 return createLegacyEditingPosition(node, (moveType == Character) ? uncheckedNextOffset(node, offset) : offset + 1);
408 }
409
410 ContainerNode* parent = node->parentNode();
411 if (!parent)
412 return *this;
413
414 if (isRenderedTable(node) || editingIgnoresContent(*node))
415 return positionAfterNode(node);
416
417 Node* nextSibling = node->nextSibling();
418 if (nextSibling && positionBeforeOrAfterNodeIsCandidate(*nextSibling))
419 return positionBeforeNode(nextSibling);
420
421 return createLegacyEditingPosition(parent, node->computeNodeIndex() + 1);
422}
423
424int Position::uncheckedPreviousOffset(const Node* n, int current)
425{
426 return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
427}
428
429int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current)
430{
431 return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1;
432}
433
434int Position::uncheckedNextOffset(const Node* n, int current)
435{
436 return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
437}
438
439bool Position::atFirstEditingPositionForNode() const
440{
441 if (isNull())
442 return true;
443 // FIXME: Position before anchor shouldn't be considered as at the first editing position for node
444 // since that position resides outside of the node.
445 switch (m_anchorType) {
446 case PositionIsOffsetInAnchor:
447 return m_offset <= 0;
448 case PositionIsBeforeChildren:
449 case PositionIsBeforeAnchor:
450 return true;
451 case PositionIsAfterChildren:
452 case PositionIsAfterAnchor:
453 return !lastOffsetForEditing(*deprecatedNode());
454 }
455 ASSERT_NOT_REACHED();
456 return false;
457}
458
459bool Position::atLastEditingPositionForNode() const
460{
461 if (isNull())
462 return true;
463 // FIXME: Position after anchor shouldn't be considered as at the first editing position for node
464 // since that position resides outside of the node.
465 return m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || m_offset >= lastOffsetForEditing(*deprecatedNode());
466}
467
468// A position is considered at editing boundary if one of the following is true:
469// 1. It is the first position in the node and the next visually equivalent position
470// is non editable.
471// 2. It is the last position in the node and the previous visually equivalent position
472// is non editable.
473// 3. It is an editable position and both the next and previous visually equivalent
474// positions are both non editable.
475bool Position::atEditingBoundary() const
476{
477 Position nextPosition = downstream(CanCrossEditingBoundary);
478 if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.deprecatedNode()->hasEditableStyle())
479 return true;
480
481 Position prevPosition = upstream(CanCrossEditingBoundary);
482 if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->hasEditableStyle())
483 return true;
484
485 return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->hasEditableStyle()
486 && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->hasEditableStyle();
487}
488
489Node* Position::parentEditingBoundary() const
490{
491 if (!m_anchorNode)
492 return nullptr;
493
494 Node* documentElement = m_anchorNode->document().documentElement();
495 if (!documentElement)
496 return nullptr;
497
498 Node* boundary = m_anchorNode.get();
499 while (boundary != documentElement && boundary->nonShadowBoundaryParentNode() && m_anchorNode->hasEditableStyle() == boundary->parentNode()->hasEditableStyle())
500 boundary = boundary->nonShadowBoundaryParentNode();
501
502 return boundary;
503}
504
505
506bool Position::atStartOfTree() const
507{
508 if (isNull())
509 return true;
510
511 Node* container = containerNode();
512 if (container && container->parentNode())
513 return false;
514
515 switch (m_anchorType) {
516 case PositionIsOffsetInAnchor:
517 return m_offset <= 0;
518 case PositionIsBeforeAnchor:
519 return !m_anchorNode->previousSibling();
520 case PositionIsAfterAnchor:
521 return false;
522 case PositionIsBeforeChildren:
523 return true;
524 case PositionIsAfterChildren:
525 return !lastOffsetForEditing(*m_anchorNode);
526 }
527 ASSERT_NOT_REACHED();
528 return false;
529}
530
531bool Position::atEndOfTree() const
532{
533 if (isNull())
534 return true;
535
536 Node* container = containerNode();
537 if (container && container->parentNode())
538 return false;
539
540 switch (m_anchorType) {
541 case PositionIsOffsetInAnchor:
542 return m_offset >= lastOffsetForEditing(*m_anchorNode);
543 case PositionIsBeforeAnchor:
544 return false;
545 case PositionIsAfterAnchor:
546 return !m_anchorNode->nextSibling();
547 case PositionIsBeforeChildren:
548 return !lastOffsetForEditing(*m_anchorNode);
549 case PositionIsAfterChildren:
550 return true;
551 }
552 ASSERT_NOT_REACHED();
553 return false;
554}
555
556// return first preceding DOM position rendered at a different location, or "this"
557Position Position::previousCharacterPosition(EAffinity affinity) const
558{
559 if (isNull())
560 return { };
561
562 Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
563
564 bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
565 bool rendered = isCandidate();
566
567 Position currentPosition = *this;
568 while (!currentPosition.atStartOfTree()) {
569 currentPosition = currentPosition.previous();
570
571 if (currentPosition.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
572 return *this;
573
574 if (atStartOfLine || !rendered) {
575 if (currentPosition.isCandidate())
576 return currentPosition;
577 } else if (rendersInDifferentPosition(currentPosition))
578 return currentPosition;
579 }
580
581 return *this;
582}
583
584// return first following position rendered at a different location, or "this"
585Position Position::nextCharacterPosition(EAffinity affinity) const
586{
587 if (isNull())
588 return { };
589
590 Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
591
592 bool atEndOfLine = isEndOfLine({ *this, affinity });
593 bool rendered = isCandidate();
594
595 Position currentPosition = *this;
596 while (!currentPosition.atEndOfTree()) {
597 currentPosition = currentPosition.next();
598
599 if (currentPosition.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
600 return *this;
601
602 if (atEndOfLine || !rendered) {
603 if (currentPosition.isCandidate())
604 return currentPosition;
605 } else if (rendersInDifferentPosition(currentPosition))
606 return currentPosition;
607 }
608
609 return *this;
610}
611
612// Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
613// If true, adjacent candidates are visually distinct.
614// FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
615// FIXME: Share code with isCandidate, if possible.
616static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
617{
618 if (!node || !node->renderer())
619 return false;
620
621 if (!node->renderer()->isInline())
622 return true;
623
624 // Don't include inline tables.
625 if (is<HTMLTableElement>(*node))
626 return false;
627
628 // There is a VisiblePosition inside an empty inline-block container.
629 return node->renderer()->isReplaced() && canHaveChildrenForEditing(*node) && downcast<RenderBox>(*node->renderer()).height() && !node->firstChild();
630}
631
632static Node* enclosingVisualBoundary(Node* node)
633{
634 while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
635 node = node->parentNode();
636
637 return node;
638}
639
640// upstream() and downstream() want to return positions that are either in a
641// text node or at just before a non-text node. This method checks for that.
642static bool isStreamer(const PositionIterator& pos)
643{
644 if (!pos.node())
645 return true;
646
647 if (isAtomicNode(pos.node()))
648 return true;
649
650 return pos.atStartOfNode();
651}
652
653static void ensureLineBoxesIfNeeded(RenderObject& renderer)
654{
655 if (!is<RenderText>(renderer) && !is<RenderLineBreak>(renderer))
656 return;
657 is<RenderText>(renderer) ? downcast<RenderText>(renderer).ensureLineBoxes() : downcast<RenderLineBreak>(renderer).ensureLineBoxes();
658}
659
660// This function and downstream() are used for moving back and forth between visually equivalent candidates.
661// For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
662// that map to the VisiblePosition between 'b' and the space. This function will return the left candidate
663// and downstream() will return the right one.
664// Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
665// in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
666Position Position::upstream(EditingBoundaryCrossingRule rule) const
667{
668 Node* startNode = deprecatedNode();
669 if (!startNode)
670 return { };
671
672 // iterate backward from there, looking for a qualified position
673 Node* boundary = enclosingVisualBoundary(startNode);
674 // FIXME: PositionIterator should respect Before and After positions.
675 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(*m_anchorNode)) : *this;
676 PositionIterator currentPosition = lastVisible;
677 bool startEditable = startNode->hasEditableStyle();
678 Node* lastNode = startNode;
679 bool boundaryCrossed = false;
680 for (; !currentPosition.atStart(); currentPosition.decrement()) {
681 auto& currentNode = *currentPosition.node();
682
683 // Don't check for an editability change if we haven't moved to a different node,
684 // to avoid the expense of computing hasEditableStyle().
685 if (&currentNode != lastNode) {
686 // Don't change editability.
687 bool currentEditable = currentNode.hasEditableStyle();
688 if (startEditable != currentEditable) {
689 if (rule == CannotCrossEditingBoundary)
690 break;
691 boundaryCrossed = true;
692 }
693 lastNode = &currentNode;
694 }
695
696 // If we've moved to a position that is visually distinct, return the last saved position. There
697 // is code below that terminates early if we're *about* to move to a visually distinct position.
698 if (endsOfNodeAreVisuallyDistinctPositions(&currentNode) && &currentNode != boundary)
699 return lastVisible;
700
701 // skip position in unrendered or invisible node
702 RenderObject* renderer = currentNode.renderer();
703 if (!renderer || renderer->style().visibility() != Visibility::Visible)
704 continue;
705 ensureLineBoxesIfNeeded(*renderer);
706 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
707 lastVisible = currentPosition;
708 break;
709 }
710
711 // track last visible streamer position
712 if (isStreamer(currentPosition))
713 lastVisible = currentPosition;
714
715 // Don't move past a position that is visually distinct. We could rely on code above to terminate and
716 // return lastVisible on the next iteration, but we terminate early to avoid doing a computeNodeIndex() call.
717 if (endsOfNodeAreVisuallyDistinctPositions(&currentNode) && currentPosition.atStartOfNode())
718 return lastVisible;
719
720 // Return position after tables and nodes which have content that can be ignored.
721 if (editingIgnoresContent(currentNode) || isRenderedTable(&currentNode)) {
722 if (currentPosition.atEndOfNode())
723 return positionAfterNode(&currentNode);
724 continue;
725 }
726
727 // return current position if it is in rendered text
728 if (is<RenderText>(*renderer)) {
729 auto& textRenderer = downcast<RenderText>(*renderer);
730 if (!textRenderer.firstTextBox())
731 continue;
732 if (&currentNode != startNode) {
733 // This assertion fires in layout tests in the case-transform.html test because
734 // of a mix-up between offsets in the text in the DOM tree with text in the
735 // render tree which can have a different length due to case transformation.
736 // Until we resolve that, disable this so we can run the layout tests!
737 //ASSERT(currentOffset >= renderer->caretMaxOffset());
738 return createLegacyEditingPosition(&currentNode, renderer->caretMaxOffset());
739 }
740
741 unsigned textOffset = currentPosition.offsetInLeafNode();
742 auto lastTextBox = textRenderer.lastTextBox();
743 for (auto* box = textRenderer.firstTextBox(); box; box = box->nextTextBox()) {
744 if (textOffset <= box->start() + box->len()) {
745 if (textOffset > box->start())
746 return currentPosition;
747 continue;
748 }
749
750 if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
751 continue;
752
753 // The text continues on the next line only if the last text box is not on this line and
754 // none of the boxes on this line have a larger start offset.
755
756 bool continuesOnNextLine = true;
757 InlineBox* otherBox = box;
758 while (continuesOnNextLine) {
759 otherBox = otherBox->nextLeafChild();
760 if (!otherBox)
761 break;
762 if (otherBox == lastTextBox || (&otherBox->renderer() == &textRenderer && downcast<InlineTextBox>(*otherBox).start() > textOffset))
763 continuesOnNextLine = false;
764 }
765
766 otherBox = box;
767 while (continuesOnNextLine) {
768 otherBox = otherBox->prevLeafChild();
769 if (!otherBox)
770 break;
771 if (otherBox == lastTextBox || (&otherBox->renderer() == &textRenderer && downcast<InlineTextBox>(*otherBox).start() > textOffset))
772 continuesOnNextLine = false;
773 }
774
775 if (continuesOnNextLine)
776 return currentPosition;
777 }
778 }
779 }
780
781 return lastVisible;
782}
783
784// This function and upstream() are used for moving back and forth between visually equivalent candidates.
785// For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
786// that map to the VisiblePosition between 'b' and the space. This function will return the right candidate
787// and upstream() will return the left one.
788// Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
789// in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
790// FIXME: This function should never be called when the line box tree is dirty. See https://bugs.webkit.org/show_bug.cgi?id=97264
791Position Position::downstream(EditingBoundaryCrossingRule rule) const
792{
793 Node* startNode = deprecatedNode();
794 if (!startNode)
795 return { };
796
797 // iterate forward from there, looking for a qualified position
798 Node* boundary = enclosingVisualBoundary(startNode);
799 // FIXME: PositionIterator should respect Before and After positions.
800 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(*m_anchorNode)) : *this;
801 PositionIterator currentPosition = lastVisible;
802 bool startEditable = startNode->hasEditableStyle();
803 Node* lastNode = startNode;
804 bool boundaryCrossed = false;
805 for (; !currentPosition.atEnd(); currentPosition.increment()) {
806 auto& currentNode = *currentPosition.node();
807
808 // Don't check for an editability change if we haven't moved to a different node,
809 // to avoid the expense of computing hasEditableStyle().
810 if (&currentNode != lastNode) {
811 // Don't change editability.
812 bool currentEditable = currentNode.hasEditableStyle();
813 if (startEditable != currentEditable) {
814 if (rule == CannotCrossEditingBoundary)
815 break;
816 boundaryCrossed = true;
817 }
818
819 lastNode = &currentNode;
820 }
821
822 // stop before going above the body, up into the head
823 // return the last visible streamer position
824 if (is<HTMLBodyElement>(currentNode) && currentPosition.atEndOfNode())
825 break;
826
827 // Do not move to a visually distinct position.
828 if (endsOfNodeAreVisuallyDistinctPositions(&currentNode) && &currentNode != boundary)
829 return lastVisible;
830 // Do not move past a visually disinct position.
831 // Note: The first position after the last in a node whose ends are visually distinct
832 // positions will be [boundary->parentNode(), originalBlock->computeNodeIndex() + 1].
833 if (boundary && boundary->parentNode() == &currentNode)
834 return lastVisible;
835
836 // skip position in unrendered or invisible node
837 auto* renderer = currentNode.renderer();
838 if (!renderer || renderer->style().visibility() != Visibility::Visible)
839 continue;
840 ensureLineBoxesIfNeeded(*renderer);
841 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
842 lastVisible = currentPosition;
843 break;
844 }
845
846 // track last visible streamer position
847 if (isStreamer(currentPosition))
848 lastVisible = currentPosition;
849
850 // Return position before tables and nodes which have content that can be ignored.
851 if (editingIgnoresContent(currentNode) || isRenderedTable(&currentNode)) {
852 if (currentPosition.atStartOfNode())
853 return positionBeforeNode(&currentNode);
854 continue;
855 }
856
857 // return current position if it is in rendered text
858 if (is<RenderText>(*renderer)) {
859 auto& textRenderer = downcast<RenderText>(*renderer);
860 if (!textRenderer.firstTextBox())
861 continue;
862 if (&currentNode != startNode) {
863 ASSERT(currentPosition.atStartOfNode());
864 return createLegacyEditingPosition(&currentNode, renderer->caretMinOffset());
865 }
866
867 unsigned textOffset = currentPosition.offsetInLeafNode();
868 auto lastTextBox = textRenderer.lastTextBox();
869 for (auto* box = textRenderer.firstTextBox(); box; box = box->nextTextBox()) {
870 if (textOffset <= box->end()) {
871 if (textOffset >= box->start())
872 return currentPosition;
873 continue;
874 }
875
876 if (box == lastTextBox || textOffset != box->start() + box->len())
877 continue;
878
879 // The text continues on the next line only if the last text box is not on this line and
880 // none of the boxes on this line have a larger start offset.
881
882 bool continuesOnNextLine = true;
883 InlineBox* otherBox = box;
884 while (continuesOnNextLine) {
885 otherBox = otherBox->nextLeafChild();
886 if (!otherBox)
887 break;
888 if (otherBox == lastTextBox || (&otherBox->renderer() == &textRenderer && downcast<InlineTextBox>(*otherBox).start() >= textOffset))
889 continuesOnNextLine = false;
890 }
891
892 otherBox = box;
893 while (continuesOnNextLine) {
894 otherBox = otherBox->prevLeafChild();
895 if (!otherBox)
896 break;
897 if (otherBox == lastTextBox || (&otherBox->renderer() == &textRenderer && downcast<InlineTextBox>(*otherBox).start() >= textOffset))
898 continuesOnNextLine = false;
899 }
900
901 if (continuesOnNextLine)
902 return currentPosition;
903 }
904 }
905 }
906
907 return lastVisible;
908}
909
910unsigned Position::positionCountBetweenPositions(const Position& a, const Position& b)
911{
912 if (a.isNull() || b.isNull())
913 return UINT_MAX;
914
915 Position endPos;
916 Position pos;
917 if (a > b) {
918 endPos = a;
919 pos = b;
920 } else if (a < b) {
921 endPos = b;
922 pos = a;
923 } else
924 return 0;
925
926 unsigned posCount = 0;
927 while (!pos.atEndOfTree() && pos != endPos) {
928 pos = pos.next();
929 ++posCount;
930 }
931 return posCount;
932}
933
934static int boundingBoxLogicalHeight(RenderObject *o, const IntRect &rect)
935{
936 return o->style().isHorizontalWritingMode() ? rect.height() : rect.width();
937}
938
939bool Position::hasRenderedNonAnonymousDescendantsWithHeight(const RenderElement& renderer)
940{
941 RenderObject* stop = renderer.nextInPreOrderAfterChildren();
942 for (RenderObject* o = renderer.firstChild(); o && o != stop; o = o->nextInPreOrder()) {
943 if (!o->nonPseudoNode())
944 continue;
945 if (is<RenderText>(*o)) {
946 if (boundingBoxLogicalHeight(o, downcast<RenderText>(*o).linesBoundingBox()))
947 return true;
948 continue;
949 }
950 if (is<RenderLineBreak>(*o)) {
951 if (boundingBoxLogicalHeight(o, downcast<RenderLineBreak>(*o).linesBoundingBox()))
952 return true;
953 continue;
954 }
955 if (is<RenderBox>(*o)) {
956 if (roundToInt(downcast<RenderBox>(*o).logicalHeight()))
957 return true;
958 continue;
959 }
960 if (is<RenderInline>(*o)) {
961 const RenderInline& renderInline = downcast<RenderInline>(*o);
962 if (isEmptyInline(renderInline) && boundingBoxLogicalHeight(o, renderInline.linesBoundingBox()))
963 return true;
964 continue;
965 }
966 }
967 return false;
968}
969
970bool Position::nodeIsUserSelectNone(Node* node)
971{
972 return node && node->renderer() && node->renderer()->style().userSelect() == UserSelect::None;
973}
974
975#if ENABLE(USERSELECT_ALL)
976bool Position::nodeIsUserSelectAll(const Node* node)
977{
978 return node && node->renderer() && node->renderer()->style().userSelect() == UserSelect::All;
979}
980
981Node* Position::rootUserSelectAllForNode(Node* node)
982{
983 if (!node || !nodeIsUserSelectAll(node))
984 return nullptr;
985 Node* parent = node->parentNode();
986 if (!parent)
987 return node;
988
989 Node* candidateRoot = node;
990 while (parent) {
991 if (!parent->renderer()) {
992 parent = parent->parentNode();
993 continue;
994 }
995 if (!nodeIsUserSelectAll(parent))
996 break;
997 candidateRoot = parent;
998 parent = candidateRoot->parentNode();
999 }
1000 return candidateRoot;
1001}
1002#endif
1003
1004bool Position::isCandidate() const
1005{
1006 if (isNull())
1007 return false;
1008
1009 auto* renderer = deprecatedNode()->renderer();
1010 if (!renderer)
1011 return false;
1012
1013 if (renderer->style().visibility() != Visibility::Visible)
1014 return false;
1015
1016 if (renderer->isBR()) {
1017 // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor, but for now we still need to support legacy positions.
1018 return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
1019 }
1020
1021 if (is<RenderText>(*renderer))
1022 return !nodeIsUserSelectNone(deprecatedNode()) && downcast<RenderText>(*renderer).containsCaretOffset(m_offset);
1023
1024 if (positionBeforeOrAfterNodeIsCandidate(*deprecatedNode())) {
1025 return ((atFirstEditingPositionForNode() && m_anchorType == PositionIsBeforeAnchor)
1026 || (atLastEditingPositionForNode() && m_anchorType == PositionIsAfterAnchor))
1027 && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
1028 }
1029
1030 if (is<HTMLHtmlElement>(*m_anchorNode))
1031 return false;
1032
1033 if (is<RenderBlockFlow>(*renderer) || is<RenderGrid>(*renderer) || is<RenderFlexibleBox>(*renderer)) {
1034 RenderBlock& block = downcast<RenderBlock>(*renderer);
1035 if (block.logicalHeight() || is<HTMLBodyElement>(*m_anchorNode) || m_anchorNode->isRootEditableElement()) {
1036 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(block))
1037 return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(deprecatedNode());
1038 return m_anchorNode->hasEditableStyle() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
1039 }
1040 return false;
1041 }
1042
1043 return m_anchorNode->hasEditableStyle() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
1044}
1045
1046bool Position::isRenderedCharacter() const
1047{
1048 if (!is<Text>(deprecatedNode()))
1049 return false;
1050
1051 RenderText* renderer = downcast<Text>(*deprecatedNode()).renderer();
1052 if (!renderer)
1053 return false;
1054
1055 return renderer->containsRenderedCharacterOffset(m_offset);
1056}
1057
1058static bool inSameEnclosingBlockFlowElement(Node* a, Node* b)
1059{
1060 return a && b && deprecatedEnclosingBlockFlowElement(a) == deprecatedEnclosingBlockFlowElement(b);
1061}
1062
1063bool Position::rendersInDifferentPosition(const Position& position) const
1064{
1065 if (isNull() || position.isNull())
1066 return false;
1067
1068 auto* renderer = deprecatedNode()->renderer();
1069 if (!renderer)
1070 return false;
1071
1072 auto* positionRenderer = position.deprecatedNode()->renderer();
1073 if (!positionRenderer)
1074 return false;
1075
1076 if (renderer->style().visibility() != Visibility::Visible || positionRenderer->style().visibility() != Visibility::Visible)
1077 return false;
1078
1079 if (deprecatedNode() == position.deprecatedNode()) {
1080 if (is<HTMLBRElement>(*deprecatedNode()))
1081 return false;
1082
1083 if (m_offset == position.deprecatedEditingOffset())
1084 return false;
1085
1086 if (!is<Text>(*deprecatedNode()) && !is<Text>(*position.deprecatedNode())) {
1087 if (m_offset != position.deprecatedEditingOffset())
1088 return true;
1089 }
1090 }
1091
1092 if (is<HTMLBRElement>(*deprecatedNode()) && position.isCandidate())
1093 return true;
1094
1095 if (is<HTMLBRElement>(*position.deprecatedNode()) && isCandidate())
1096 return true;
1097
1098 if (!inSameEnclosingBlockFlowElement(deprecatedNode(), position.deprecatedNode()))
1099 return true;
1100
1101 if (is<RenderText>(*renderer) && !downcast<RenderText>(*renderer).containsCaretOffset(m_offset))
1102 return false;
1103
1104 if (is<RenderText>(*positionRenderer) && !downcast<RenderText>(*positionRenderer).containsCaretOffset(position.m_offset))
1105 return false;
1106
1107 int thisRenderedOffset = is<RenderText>(*renderer) ? downcast<RenderText>(*renderer).countRenderedCharacterOffsetsUntil(m_offset) : m_offset;
1108 int positionRenderedOffset = is<RenderText>(*positionRenderer) ? downcast<RenderText>(*positionRenderer).countRenderedCharacterOffsetsUntil(position.m_offset) : position.m_offset;
1109
1110 if (renderer == positionRenderer && thisRenderedOffset == positionRenderedOffset)
1111 return false;
1112
1113 int ignoredCaretOffset;
1114 InlineBox* b1;
1115 getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
1116 InlineBox* b2;
1117 position.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
1118
1119 LOG(Editing, "renderer: %p [%p]\n", renderer, b1);
1120 LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset);
1121 LOG(Editing, "posRenderer: %p [%p]\n", positionRenderer, b2);
1122 LOG(Editing, "posRenderedOffset: %d\n", positionRenderedOffset);
1123 LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(*deprecatedNode()), caretMaxOffset(*deprecatedNode()));
1124 LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(*position.deprecatedNode()), caretMaxOffset(*position.deprecatedNode()));
1125 LOG(Editing, "----------------------------------------------------------------------\n");
1126
1127 if (!b1 || !b2) {
1128 return false;
1129 }
1130
1131 if (&b1->root() != &b2->root()) {
1132 return true;
1133 }
1134
1135 if (nextRenderedEditable(deprecatedNode()) == position.deprecatedNode()
1136 && thisRenderedOffset == caretMaxOffset(*deprecatedNode()) && !positionRenderedOffset) {
1137 return false;
1138 }
1139
1140 if (previousRenderedEditable(deprecatedNode()) == position.deprecatedNode()
1141 && !thisRenderedOffset && positionRenderedOffset == caretMaxOffset(*position.deprecatedNode())) {
1142 return false;
1143 }
1144
1145 return true;
1146}
1147
1148// This assumes that it starts in editable content.
1149Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
1150{
1151 ASSERT(isEditablePosition(*this));
1152 if (isNull())
1153 return { };
1154
1155 if (is<HTMLBRElement>(*upstream().deprecatedNode()))
1156 return { };
1157
1158 Position prev = previousCharacterPosition(affinity);
1159 if (prev != *this && inSameEnclosingBlockFlowElement(deprecatedNode(), prev.deprecatedNode()) && is<Text>(*prev.deprecatedNode())) {
1160 UChar c = downcast<Text>(*prev.deprecatedNode()).data()[prev.deprecatedEditingOffset()];
1161 if (considerNonCollapsibleWhitespace ? (isHTMLSpace(c) || c == noBreakSpace) : deprecatedIsCollapsibleWhitespace(c)) {
1162 if (isEditablePosition(prev))
1163 return prev;
1164 }
1165 }
1166
1167 return { };
1168}
1169
1170// This assumes that it starts in editable content.
1171Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace) const
1172{
1173 ASSERT(isEditablePosition(*this));
1174 if (isNull())
1175 return { };
1176
1177 VisiblePosition v(*this);
1178 UChar c = v.characterAfter();
1179 // The space must not be in another paragraph and it must be editable.
1180 if (!isEndOfParagraph(v) && v.next(CannotCrossEditingBoundary).isNotNull())
1181 if (considerNonCollapsibleWhitespace ? (isHTMLSpace(c) || c == noBreakSpace) : deprecatedIsCollapsibleWhitespace(c))
1182 return *this;
1183
1184 return { };
1185}
1186
1187void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
1188{
1189 getInlineBoxAndOffset(affinity, primaryDirection(), inlineBox, caretOffset);
1190}
1191
1192static bool isNonTextLeafChild(RenderObject& object)
1193{
1194 if (is<RenderText>(object))
1195 return false;
1196 return !downcast<RenderElement>(object).firstChild();
1197}
1198
1199static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
1200{
1201 RenderBlock* container = renderer->containingBlock();
1202 RenderObject* next = renderer;
1203 while ((next = next->nextInPreOrder(container))) {
1204 if (is<RenderBlock>(*next))
1205 return nullptr;
1206 if (next->isBR())
1207 return nullptr;
1208 if (isNonTextLeafChild(*next))
1209 return nullptr;
1210 if (is<RenderText>(*next)) {
1211 InlineTextBox* match = nullptr;
1212 int minOffset = INT_MAX;
1213 for (InlineTextBox* box = downcast<RenderText>(*next).firstTextBox(); box; box = box->nextTextBox()) {
1214 int caretMinOffset = box->caretMinOffset();
1215 if (caretMinOffset < minOffset) {
1216 match = box;
1217 minOffset = caretMinOffset;
1218 }
1219 }
1220 if (match)
1221 return match;
1222 }
1223 }
1224 return nullptr;
1225}
1226
1227static Position downstreamIgnoringEditingBoundaries(Position position)
1228{
1229 Position lastPosition;
1230 while (position != lastPosition) {
1231 lastPosition = position;
1232 position = position.downstream(CanCrossEditingBoundary);
1233 }
1234 return position;
1235}
1236
1237static Position upstreamIgnoringEditingBoundaries(Position position)
1238{
1239 Position lastPosition;
1240 while (position != lastPosition) {
1241 lastPosition = position;
1242 position = position.upstream(CanCrossEditingBoundary);
1243 }
1244 return position;
1245}
1246
1247void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
1248{
1249 caretOffset = deprecatedEditingOffset();
1250 RenderObject* renderer = deprecatedNode()->renderer();
1251
1252 if (renderer->isBR()) {
1253 auto& lineBreakRenderer = downcast<RenderLineBreak>(*renderer);
1254 lineBreakRenderer.ensureLineBoxes();
1255 inlineBox = !caretOffset ? lineBreakRenderer.inlineBoxWrapper() : nullptr;
1256 } else if (is<RenderText>(*renderer)) {
1257 auto& textRenderer = downcast<RenderText>(*renderer);
1258 textRenderer.ensureLineBoxes();
1259
1260 InlineTextBox* box;
1261 InlineTextBox* candidate = nullptr;
1262
1263 for (box = textRenderer.firstTextBox(); box; box = box->nextTextBox()) {
1264 int caretMinOffset = box->caretMinOffset();
1265 int caretMaxOffset = box->caretMaxOffset();
1266
1267 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
1268 continue;
1269
1270 if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
1271 inlineBox = box;
1272 return;
1273 }
1274
1275 if (((caretOffset == caretMaxOffset) ^ (affinity == DOWNSTREAM))
1276 || ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM))
1277 || (caretOffset == caretMaxOffset && box->nextLeafChild() && box->nextLeafChild()->isLineBreak()))
1278 break;
1279
1280 candidate = box;
1281 }
1282 if (candidate && candidate == textRenderer.lastTextBox() && affinity == DOWNSTREAM) {
1283 box = searchAheadForBetterMatch(&textRenderer);
1284 if (box)
1285 caretOffset = box->caretMinOffset();
1286 }
1287 inlineBox = box ? box : candidate;
1288 } else {
1289 inlineBox = nullptr;
1290 if (canHaveChildrenForEditing(*deprecatedNode()) && is<RenderBlockFlow>(*renderer) && hasRenderedNonAnonymousDescendantsWithHeight(downcast<RenderBlockFlow>(*renderer))) {
1291 // Try a visually equivalent position with possibly opposite editability. This helps in case |this| is in
1292 // an editable block but surrounded by non-editable positions. It acts to negate the logic at the beginning
1293 // of RenderObject::createVisiblePosition().
1294 Position equivalent = downstreamIgnoringEditingBoundaries(*this);
1295 if (equivalent == *this) {
1296 equivalent = upstreamIgnoringEditingBoundaries(*this);
1297 if (equivalent == *this || downstreamIgnoringEditingBoundaries(equivalent) == *this)
1298 return;
1299 }
1300
1301 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset);
1302 return;
1303 }
1304 if (is<RenderBox>(*renderer)) {
1305 inlineBox = downcast<RenderBox>(*renderer).inlineBoxWrapper();
1306 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
1307 return;
1308 }
1309 }
1310
1311 if (!inlineBox)
1312 return;
1313
1314 unsigned char level = inlineBox->bidiLevel();
1315
1316 if (inlineBox->direction() == primaryDirection) {
1317 if (caretOffset == inlineBox->caretRightmostOffset()) {
1318 InlineBox* nextBox = inlineBox->nextLeafChild();
1319 if (!nextBox || nextBox->bidiLevel() >= level)
1320 return;
1321
1322 level = nextBox->bidiLevel();
1323 InlineBox* prevBox = inlineBox;
1324 do {
1325 prevBox = prevBox->prevLeafChild();
1326 } while (prevBox && prevBox->bidiLevel() > level);
1327
1328 if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
1329 return;
1330
1331 // For example, abc 123 ^ CBA
1332 while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1333 if (nextBox->bidiLevel() < level)
1334 break;
1335 inlineBox = nextBox;
1336 }
1337 caretOffset = inlineBox->caretRightmostOffset();
1338 } else {
1339 InlineBox* prevBox = inlineBox->prevLeafChild();
1340 if (!prevBox || prevBox->bidiLevel() >= level)
1341 return;
1342
1343 level = prevBox->bidiLevel();
1344 InlineBox* nextBox = inlineBox;
1345 do {
1346 nextBox = nextBox->nextLeafChild();
1347 } while (nextBox && nextBox->bidiLevel() > level);
1348
1349 if (nextBox && nextBox->bidiLevel() == level)
1350 return;
1351
1352 while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1353 if (prevBox->bidiLevel() < level)
1354 break;
1355 inlineBox = prevBox;
1356 }
1357 caretOffset = inlineBox->caretLeftmostOffset();
1358 }
1359 return;
1360 }
1361
1362 if (caretOffset == inlineBox->caretLeftmostOffset()) {
1363 InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak();
1364 if (!prevBox || prevBox->bidiLevel() < level) {
1365 // Left edge of a secondary run. Set to the right edge of the entire run.
1366 while (InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1367 if (nextBox->bidiLevel() < level)
1368 break;
1369 inlineBox = nextBox;
1370 }
1371 caretOffset = inlineBox->caretRightmostOffset();
1372 } else if (prevBox->bidiLevel() > level) {
1373 // Right edge of a "tertiary" run. Set to the left edge of that run.
1374 while (InlineBox* tertiaryBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1375 if (tertiaryBox->bidiLevel() <= level)
1376 break;
1377 inlineBox = tertiaryBox;
1378 }
1379 caretOffset = inlineBox->caretLeftmostOffset();
1380 }
1381 } else {
1382 InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak();
1383 if (!nextBox || nextBox->bidiLevel() < level) {
1384 // Right edge of a secondary run. Set to the left edge of the entire run.
1385 while (InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1386 if (prevBox->bidiLevel() < level)
1387 break;
1388 inlineBox = prevBox;
1389 }
1390 caretOffset = inlineBox->caretLeftmostOffset();
1391 } else if (nextBox->bidiLevel() > level) {
1392 // Left edge of a "tertiary" run. Set to the right edge of that run.
1393 while (InlineBox* tertiaryBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1394 if (tertiaryBox->bidiLevel() <= level)
1395 break;
1396 inlineBox = tertiaryBox;
1397 }
1398 caretOffset = inlineBox->caretRightmostOffset();
1399 }
1400 }
1401}
1402
1403TextDirection Position::primaryDirection() const
1404{
1405 if (!m_anchorNode->renderer())
1406 return TextDirection::LTR;
1407 if (auto* blockFlow = lineageOfType<RenderBlockFlow>(*m_anchorNode->renderer()).first())
1408 return blockFlow->style().direction();
1409 return TextDirection::LTR;
1410}
1411
1412#if ENABLE(TREE_DEBUGGING)
1413
1414void Position::debugPosition(const char* msg) const
1415{
1416 if (isNull())
1417 fprintf(stderr, "Position [%s]: null\n", msg);
1418 else
1419 fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, deprecatedNode()->nodeName().utf8().data(), deprecatedNode(), m_offset);
1420}
1421
1422void Position::formatForDebugger(char* buffer, unsigned length) const
1423{
1424 StringBuilder result;
1425
1426 if (isNull())
1427 result.appendLiteral("<null>");
1428 else {
1429 char s[1024];
1430 result.appendLiteral("offset ");
1431 result.appendNumber(m_offset);
1432 result.appendLiteral(" of ");
1433 deprecatedNode()->formatForDebugger(s, sizeof(s));
1434 result.append(s);
1435 }
1436
1437 strncpy(buffer, result.toString().utf8().data(), length - 1);
1438}
1439
1440void Position::showAnchorTypeAndOffset() const
1441{
1442 if (m_isLegacyEditingPosition)
1443 fputs("legacy, ", stderr);
1444 switch (anchorType()) {
1445 case PositionIsOffsetInAnchor:
1446 fputs("offset", stderr);
1447 break;
1448 case PositionIsBeforeChildren:
1449 fputs("beforeChildren", stderr);
1450 break;
1451 case PositionIsAfterChildren:
1452 fputs("afterChildren", stderr);
1453 break;
1454 case PositionIsBeforeAnchor:
1455 fputs("before", stderr);
1456 break;
1457 case PositionIsAfterAnchor:
1458 fputs("after", stderr);
1459 break;
1460 }
1461 fprintf(stderr, ", offset:%d\n", m_offset);
1462}
1463
1464void Position::showTreeForThis() const
1465{
1466 if (anchorNode()) {
1467 anchorNode()->showTreeForThis();
1468 showAnchorTypeAndOffset();
1469 }
1470}
1471
1472#endif
1473
1474bool Position::equals(const Position& other) const
1475{
1476 if (!m_anchorNode)
1477 return !m_anchorNode == !other.m_anchorNode;
1478 if (!other.m_anchorNode)
1479 return false;
1480
1481 switch (anchorType()) {
1482 case PositionIsBeforeChildren:
1483 ASSERT(!is<Text>(*m_anchorNode));
1484 switch (other.anchorType()) {
1485 case PositionIsBeforeChildren:
1486 ASSERT(!is<Text>(*other.m_anchorNode));
1487 return m_anchorNode == other.m_anchorNode;
1488 case PositionIsAfterChildren:
1489 ASSERT(!is<Text>(*other.m_anchorNode));
1490 return m_anchorNode == other.m_anchorNode && !m_anchorNode->hasChildNodes();
1491 case PositionIsOffsetInAnchor:
1492 return m_anchorNode == other.m_anchorNode && !other.m_offset;
1493 case PositionIsBeforeAnchor:
1494 return m_anchorNode->firstChild() == other.m_anchorNode;
1495 case PositionIsAfterAnchor:
1496 return false;
1497 }
1498 break;
1499 case PositionIsAfterChildren:
1500 ASSERT(!is<Text>(*m_anchorNode));
1501 switch (other.anchorType()) {
1502 case PositionIsBeforeChildren:
1503 ASSERT(!is<Text>(*other.m_anchorNode));
1504 return m_anchorNode == other.m_anchorNode && !m_anchorNode->hasChildNodes();
1505 case PositionIsAfterChildren:
1506 ASSERT(!is<Text>(*other.m_anchorNode));
1507 return m_anchorNode == other.m_anchorNode;
1508 case PositionIsOffsetInAnchor:
1509 return m_anchorNode == other.m_anchorNode && m_anchorNode->countChildNodes() == static_cast<unsigned>(m_offset);
1510 case PositionIsBeforeAnchor:
1511 return false;
1512 case PositionIsAfterAnchor:
1513 return m_anchorNode->lastChild() == other.m_anchorNode;
1514 }
1515 break;
1516 case PositionIsOffsetInAnchor:
1517 switch (other.anchorType()) {
1518 case PositionIsBeforeChildren:
1519 ASSERT(!is<Text>(*other.m_anchorNode));
1520 return m_anchorNode == other.m_anchorNode && !m_offset;
1521 case PositionIsAfterChildren:
1522 ASSERT(!is<Text>(*other.m_anchorNode));
1523 return m_anchorNode == other.m_anchorNode && m_offset == static_cast<int>(other.m_anchorNode->countChildNodes());
1524 case PositionIsOffsetInAnchor:
1525 return m_anchorNode == other.m_anchorNode && m_offset == other.m_offset;
1526 case PositionIsBeforeAnchor:
1527 return m_anchorNode->traverseToChildAt(m_offset) == other.m_anchorNode;
1528 case PositionIsAfterAnchor:
1529 return m_offset && m_anchorNode->traverseToChildAt(m_offset - 1) == other.m_anchorNode;
1530 }
1531 break;
1532 case PositionIsBeforeAnchor:
1533 switch (other.anchorType()) {
1534 case PositionIsBeforeChildren:
1535 ASSERT(!is<Text>(*other.m_anchorNode));
1536 return m_anchorNode == other.m_anchorNode->firstChild();
1537 case PositionIsAfterChildren:
1538 ASSERT(!is<Text>(*other.m_anchorNode));
1539 return false;
1540 case PositionIsOffsetInAnchor:
1541 return m_anchorNode == other.m_anchorNode->traverseToChildAt(other.m_offset);
1542 case PositionIsBeforeAnchor:
1543 return m_anchorNode == other.m_anchorNode;
1544 case PositionIsAfterAnchor:
1545 return m_anchorNode->previousSibling() == other.m_anchorNode;
1546 }
1547 break;
1548 case PositionIsAfterAnchor:
1549 switch (other.anchorType()) {
1550 case PositionIsBeforeChildren:
1551 ASSERT(!is<Text>(*other.m_anchorNode));
1552 return false;
1553 case PositionIsAfterChildren:
1554 ASSERT(!is<Text>(*other.m_anchorNode));
1555 return m_anchorNode == other.m_anchorNode->lastChild();
1556 case PositionIsOffsetInAnchor:
1557 return other.m_offset && m_anchorNode == other.m_anchorNode->traverseToChildAt(other.m_offset - 1);
1558 case PositionIsBeforeAnchor:
1559 return m_anchorNode->nextSibling() == other.m_anchorNode;
1560 case PositionIsAfterAnchor:
1561 return m_anchorNode == other.m_anchorNode;
1562 }
1563 break;
1564 }
1565
1566 ASSERT_NOT_REACHED();
1567 return false;
1568}
1569
1570static TextStream& operator<<(TextStream& stream, Position::AnchorType anchorType)
1571{
1572 switch (anchorType) {
1573 case Position::PositionIsOffsetInAnchor:
1574 stream << "offset in anchor";
1575 break;
1576 case Position::PositionIsBeforeAnchor:
1577 stream << "before anchor";
1578 break;
1579 case Position::PositionIsAfterAnchor:
1580 stream << "after anchor";
1581 break;
1582 case Position::PositionIsBeforeChildren:
1583 stream << "before children";
1584 break;
1585 case Position::PositionIsAfterChildren:
1586 stream << "after children";
1587 break;
1588 }
1589 return stream;
1590}
1591
1592TextStream& operator<<(TextStream& stream, const Position& position)
1593{
1594 TextStream::GroupScope scope(stream);
1595 stream << "Position " << &position;
1596
1597 stream.dumpProperty("anchor node", position.anchorNode());
1598 stream.dumpProperty("offset", position.offsetInContainerNode());
1599 stream.dumpProperty("anchor type", position.anchorType());
1600
1601 return stream;
1602}
1603
1604RefPtr<Node> commonShadowIncludingAncestor(const Position& a, const Position& b)
1605{
1606 auto* commonScope = commonTreeScope(a.containerNode(), b.containerNode());
1607 if (!commonScope)
1608 return nullptr;
1609 auto* nodeA = commonScope->ancestorNodeInThisScope(a.containerNode());
1610 ASSERT(nodeA);
1611 auto* nodeB = commonScope->ancestorNodeInThisScope(b.containerNode());
1612 ASSERT(nodeB);
1613 return Range::commonAncestorContainer(nodeA, nodeB);
1614}
1615
1616} // namespace WebCore
1617
1618#if ENABLE(TREE_DEBUGGING)
1619
1620void showTree(const WebCore::Position& pos)
1621{
1622 pos.showTreeForThis();
1623}
1624
1625void showTree(const WebCore::Position* pos)
1626{
1627 if (pos)
1628 pos->showTreeForThis();
1629}
1630
1631#endif
1632