1 /*
2 * Copyright (C) 2004, 2005, 2006, 2009 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 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/dom/Position.h"
28
29 #include "core/HTMLNames.h"
30 #include "core/css/CSSComputedStyleDeclaration.h"
31 #include "core/dom/PositionIterator.h"
32 #include "core/dom/Text.h"
33 #include "core/editing/TextIterator.h"
34 #include "core/editing/VisiblePosition.h"
35 #include "core/editing/VisibleUnits.h"
36 #include "core/editing/htmlediting.h"
37 #include "core/frame/LocalFrame.h"
38 #include "core/frame/Settings.h"
39 #include "core/html/HTMLTableElement.h"
40 #include "core/rendering/InlineIterator.h"
41 #include "core/rendering/InlineTextBox.h"
42 #include "core/rendering/RenderBlock.h"
43 #include "core/rendering/RenderInline.h"
44 #include "core/rendering/RenderText.h"
45 #include "platform/Logging.h"
46 #include "wtf/text/CString.h"
47 #include "wtf/unicode/CharacterNames.h"
48 #include <stdio.h>
49
50 namespace WebCore {
51
52 using namespace HTMLNames;
53
nextRenderedEditable(Node * node)54 static Node* nextRenderedEditable(Node* node)
55 {
56 while ((node = node->nextLeafNode())) {
57 RenderObject* renderer = node->renderer();
58 if (!renderer)
59 continue;
60 if (!node->rendererIsEditable())
61 continue;
62 if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
63 return node;
64 }
65 return 0;
66 }
67
previousRenderedEditable(Node * node)68 static Node* previousRenderedEditable(Node* node)
69 {
70 while ((node = node->previousLeafNode())) {
71 RenderObject* renderer = node->renderer();
72 if (!renderer)
73 continue;
74 if (!node->rendererIsEditable())
75 continue;
76 if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
77 return node;
78 }
79 return 0;
80 }
81
Position(PassRefPtrWillBeRawPtr<Node> anchorNode,LegacyEditingOffset offset)82 Position::Position(PassRefPtrWillBeRawPtr<Node> anchorNode, LegacyEditingOffset offset)
83 : m_anchorNode(anchorNode)
84 , m_offset(offset.value())
85 , m_anchorType(anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset))
86 , m_isLegacyEditingPosition(true)
87 {
88 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
89 }
90
Position(PassRefPtrWillBeRawPtr<Node> anchorNode,AnchorType anchorType)91 Position::Position(PassRefPtrWillBeRawPtr<Node> anchorNode, AnchorType anchorType)
92 : m_anchorNode(anchorNode)
93 , m_offset(0)
94 , m_anchorType(anchorType)
95 , m_isLegacyEditingPosition(false)
96 {
97 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
98
99 ASSERT(anchorType != PositionIsOffsetInAnchor);
100 ASSERT(!((anchorType == PositionIsBeforeChildren || anchorType == PositionIsAfterChildren)
101 && (m_anchorNode->isTextNode() || editingIgnoresContent(m_anchorNode.get()))));
102 }
103
Position(PassRefPtrWillBeRawPtr<Node> anchorNode,int offset,AnchorType anchorType)104 Position::Position(PassRefPtrWillBeRawPtr<Node> anchorNode, int offset, AnchorType anchorType)
105 : m_anchorNode(anchorNode)
106 , m_offset(offset)
107 , m_anchorType(anchorType)
108 , m_isLegacyEditingPosition(false)
109 {
110 ASSERT(!m_anchorNode || !m_anchorNode->isPseudoElement());
111
112 ASSERT(anchorType == PositionIsOffsetInAnchor);
113 }
114
Position(PassRefPtrWillBeRawPtr<Text> textNode,unsigned offset)115 Position::Position(PassRefPtrWillBeRawPtr<Text> textNode, unsigned offset)
116 : m_anchorNode(textNode)
117 , m_offset(static_cast<int>(offset))
118 , m_anchorType(PositionIsOffsetInAnchor)
119 , m_isLegacyEditingPosition(false)
120 {
121 ASSERT(m_anchorNode);
122 }
123
moveToPosition(PassRefPtrWillBeRawPtr<Node> node,int offset)124 void Position::moveToPosition(PassRefPtrWillBeRawPtr<Node> node, int offset)
125 {
126 ASSERT(!editingIgnoresContent(node.get()));
127 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
128 m_anchorNode = node;
129 m_offset = offset;
130 if (m_isLegacyEditingPosition)
131 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
132 }
moveToOffset(int offset)133 void Position::moveToOffset(int offset)
134 {
135 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
136 m_offset = offset;
137 if (m_isLegacyEditingPosition)
138 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
139 }
140
containerNode() const141 Node* Position::containerNode() const
142 {
143 if (!m_anchorNode)
144 return 0;
145
146 switch (anchorType()) {
147 case PositionIsBeforeChildren:
148 case PositionIsAfterChildren:
149 case PositionIsOffsetInAnchor:
150 return m_anchorNode.get();
151 case PositionIsBeforeAnchor:
152 case PositionIsAfterAnchor:
153 return m_anchorNode->parentNode();
154 }
155 ASSERT_NOT_REACHED();
156 return 0;
157 }
158
containerText() const159 Text* Position::containerText() const
160 {
161 switch (anchorType()) {
162 case PositionIsOffsetInAnchor:
163 return m_anchorNode && m_anchorNode->isTextNode() ? toText(m_anchorNode) : 0;
164 case PositionIsBeforeAnchor:
165 case PositionIsAfterAnchor:
166 return 0;
167 case PositionIsBeforeChildren:
168 case PositionIsAfterChildren:
169 ASSERT(!m_anchorNode || !m_anchorNode->isTextNode());
170 return 0;
171 }
172 ASSERT_NOT_REACHED();
173 return 0;
174 }
175
computeOffsetInContainerNode() const176 int Position::computeOffsetInContainerNode() const
177 {
178 if (!m_anchorNode)
179 return 0;
180
181 switch (anchorType()) {
182 case PositionIsBeforeChildren:
183 return 0;
184 case PositionIsAfterChildren:
185 return lastOffsetInNode(m_anchorNode.get());
186 case PositionIsOffsetInAnchor:
187 return minOffsetForNode(m_anchorNode.get(), m_offset);
188 case PositionIsBeforeAnchor:
189 return m_anchorNode->nodeIndex();
190 case PositionIsAfterAnchor:
191 return m_anchorNode->nodeIndex() + 1;
192 }
193 ASSERT_NOT_REACHED();
194 return 0;
195 }
196
offsetForPositionAfterAnchor() const197 int Position::offsetForPositionAfterAnchor() const
198 {
199 ASSERT(m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren);
200 ASSERT(!m_isLegacyEditingPosition);
201 return lastOffsetForEditing(m_anchorNode.get());
202 }
203
204 // Neighbor-anchored positions are invalid DOM positions, so they need to be
205 // fixed up before handing them off to the Range object.
parentAnchoredEquivalent() const206 Position Position::parentAnchoredEquivalent() const
207 {
208 if (!m_anchorNode)
209 return Position();
210
211 // FIXME: This should only be necessary for legacy positions, but is also needed for positions before and after Tables
212 if (m_offset <= 0 && (m_anchorType != PositionIsAfterAnchor && m_anchorType != PositionIsAfterChildren)) {
213 if (m_anchorNode->parentNode() && (editingIgnoresContent(m_anchorNode.get()) || isRenderedTableElement(m_anchorNode.get())))
214 return positionInParentBeforeNode(*m_anchorNode);
215 return Position(m_anchorNode.get(), 0, PositionIsOffsetInAnchor);
216 }
217 if (!m_anchorNode->offsetInCharacters()
218 && (m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || static_cast<unsigned>(m_offset) == m_anchorNode->countChildren())
219 && (editingIgnoresContent(m_anchorNode.get()) || isRenderedTableElement(m_anchorNode.get()))
220 && containerNode()) {
221 return positionInParentAfterNode(*m_anchorNode);
222 }
223
224 return Position(containerNode(), computeOffsetInContainerNode(), PositionIsOffsetInAnchor);
225 }
226
computeNodeBeforePosition() const227 Node* Position::computeNodeBeforePosition() const
228 {
229 if (!m_anchorNode)
230 return 0;
231 switch (anchorType()) {
232 case PositionIsBeforeChildren:
233 return 0;
234 case PositionIsAfterChildren:
235 return m_anchorNode->lastChild();
236 case PositionIsOffsetInAnchor:
237 return m_anchorNode->traverseToChildAt(m_offset - 1); // -1 converts to traverseToChildAt((unsigned)-1) and returns null.
238 case PositionIsBeforeAnchor:
239 return m_anchorNode->previousSibling();
240 case PositionIsAfterAnchor:
241 return m_anchorNode.get();
242 }
243 ASSERT_NOT_REACHED();
244 return 0;
245 }
246
computeNodeAfterPosition() const247 Node* Position::computeNodeAfterPosition() const
248 {
249 if (!m_anchorNode)
250 return 0;
251
252 switch (anchorType()) {
253 case PositionIsBeforeChildren:
254 return m_anchorNode->firstChild();
255 case PositionIsAfterChildren:
256 return 0;
257 case PositionIsOffsetInAnchor:
258 return m_anchorNode->traverseToChildAt(m_offset);
259 case PositionIsBeforeAnchor:
260 return m_anchorNode.get();
261 case PositionIsAfterAnchor:
262 return m_anchorNode->nextSibling();
263 }
264 ASSERT_NOT_REACHED();
265 return 0;
266 }
267
anchorTypeForLegacyEditingPosition(Node * anchorNode,int offset)268 Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset)
269 {
270 if (anchorNode && editingIgnoresContent(anchorNode)) {
271 if (offset == 0)
272 return Position::PositionIsBeforeAnchor;
273 return Position::PositionIsAfterAnchor;
274 }
275 return Position::PositionIsOffsetInAnchor;
276 }
277
278 // FIXME: This method is confusing (does it return anchorNode() or containerNode()?) and should be renamed or removed
element() const279 Element* Position::element() const
280 {
281 Node* n = anchorNode();
282 while (n && !n->isElementNode())
283 n = n->parentNode();
284 return toElement(n);
285 }
286
computedStyle() const287 PassRefPtrWillBeRawPtr<CSSComputedStyleDeclaration> Position::computedStyle() const
288 {
289 Element* elem = element();
290 if (!elem)
291 return nullptr;
292 return CSSComputedStyleDeclaration::create(elem);
293 }
294
previous(PositionMoveType moveType) const295 Position Position::previous(PositionMoveType moveType) const
296 {
297 Node* node = deprecatedNode();
298 if (!node)
299 return *this;
300
301 int offset = deprecatedEditingOffset();
302 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
303 ASSERT(offset >= 0);
304
305 if (offset > 0) {
306 if (Node* child = node->traverseToChildAt(offset - 1))
307 return lastPositionInOrAfterNode(child);
308
309 // There are two reasons child might be 0:
310 // 1) The node is node like a text node that is not an element, and therefore has no children.
311 // Going backward one character at a time is correct.
312 // 2) The old offset was a bogus offset like (<br>, 1), and there is no child.
313 // Going from 1 to 0 is correct.
314 switch (moveType) {
315 case CodePoint:
316 return createLegacyEditingPosition(node, offset - 1);
317 case Character:
318 return createLegacyEditingPosition(node, uncheckedPreviousOffset(node, offset));
319 case BackwardDeletion:
320 return createLegacyEditingPosition(node, uncheckedPreviousOffsetForBackwardDeletion(node, offset));
321 }
322 }
323
324 if (ContainerNode* parent = node->parentNode())
325 return createLegacyEditingPosition(parent, node->nodeIndex());
326 return *this;
327 }
328
next(PositionMoveType moveType) const329 Position Position::next(PositionMoveType moveType) const
330 {
331 ASSERT(moveType != BackwardDeletion);
332
333 Node* node = deprecatedNode();
334 if (!node)
335 return *this;
336
337 int offset = deprecatedEditingOffset();
338 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
339 ASSERT(offset >= 0);
340
341 if (Node* child = node->traverseToChildAt(offset))
342 return firstPositionInOrBeforeNode(child);
343
344 if (!node->hasChildren() && offset < lastOffsetForEditing(node)) {
345 // There are two reasons child might be 0:
346 // 1) The node is node like a text node that is not an element, and therefore has no children.
347 // Going forward one character at a time is correct.
348 // 2) The new offset is a bogus offset like (<br>, 1), and there is no child.
349 // Going from 0 to 1 is correct.
350 return createLegacyEditingPosition(node, (moveType == Character) ? uncheckedNextOffset(node, offset) : offset + 1);
351 }
352
353 if (ContainerNode* parent = node->parentNode())
354 return createLegacyEditingPosition(parent, node->nodeIndex() + 1);
355 return *this;
356 }
357
uncheckedPreviousOffset(const Node * n,int current)358 int Position::uncheckedPreviousOffset(const Node* n, int current)
359 {
360 return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
361 }
362
uncheckedPreviousOffsetForBackwardDeletion(const Node * n,int current)363 int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current)
364 {
365 return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1;
366 }
367
uncheckedNextOffset(const Node * n,int current)368 int Position::uncheckedNextOffset(const Node* n, int current)
369 {
370 return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
371 }
372
atFirstEditingPositionForNode() const373 bool Position::atFirstEditingPositionForNode() const
374 {
375 if (isNull())
376 return true;
377 // FIXME: Position before anchor shouldn't be considered as at the first editing position for node
378 // since that position resides outside of the node.
379 switch (m_anchorType) {
380 case PositionIsOffsetInAnchor:
381 return m_offset <= 0;
382 case PositionIsBeforeChildren:
383 case PositionIsBeforeAnchor:
384 return true;
385 case PositionIsAfterChildren:
386 case PositionIsAfterAnchor:
387 return !lastOffsetForEditing(deprecatedNode());
388 }
389 ASSERT_NOT_REACHED();
390 return false;
391 }
392
atLastEditingPositionForNode() const393 bool Position::atLastEditingPositionForNode() const
394 {
395 if (isNull())
396 return true;
397 // FIXME: Position after anchor shouldn't be considered as at the first editing position for node
398 // since that position resides outside of the node.
399 return m_anchorType == PositionIsAfterAnchor || m_anchorType == PositionIsAfterChildren || m_offset >= lastOffsetForEditing(deprecatedNode());
400 }
401
402 // A position is considered at editing boundary if one of the following is true:
403 // 1. It is the first position in the node and the next visually equivalent position
404 // is non editable.
405 // 2. It is the last position in the node and the previous visually equivalent position
406 // is non editable.
407 // 3. It is an editable position and both the next and previous visually equivalent
408 // positions are both non editable.
atEditingBoundary() const409 bool Position::atEditingBoundary() const
410 {
411 Position nextPosition = downstream(CanCrossEditingBoundary);
412 if (atFirstEditingPositionForNode() && nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable())
413 return true;
414
415 Position prevPosition = upstream(CanCrossEditingBoundary);
416 if (atLastEditingPositionForNode() && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable())
417 return true;
418
419 return nextPosition.isNotNull() && !nextPosition.deprecatedNode()->rendererIsEditable()
420 && prevPosition.isNotNull() && !prevPosition.deprecatedNode()->rendererIsEditable();
421 }
422
parentEditingBoundary() const423 Node* Position::parentEditingBoundary() const
424 {
425 if (!m_anchorNode)
426 return 0;
427
428 Node* documentElement = m_anchorNode->document().documentElement();
429 if (!documentElement)
430 return 0;
431
432 Node* boundary = m_anchorNode.get();
433 while (boundary != documentElement && boundary->nonShadowBoundaryParentNode() && m_anchorNode->rendererIsEditable() == boundary->parentNode()->rendererIsEditable())
434 boundary = boundary->nonShadowBoundaryParentNode();
435
436 return boundary;
437 }
438
439
atStartOfTree() const440 bool Position::atStartOfTree() const
441 {
442 if (isNull())
443 return true;
444 return !deprecatedNode()->parentNode() && m_offset <= 0;
445 }
446
atEndOfTree() const447 bool Position::atEndOfTree() const
448 {
449 if (isNull())
450 return true;
451 return !deprecatedNode()->parentNode() && m_offset >= lastOffsetForEditing(deprecatedNode());
452 }
453
renderedOffset() const454 int Position::renderedOffset() const
455 {
456 if (!deprecatedNode()->isTextNode())
457 return m_offset;
458
459 if (!deprecatedNode()->renderer())
460 return m_offset;
461
462 int result = 0;
463 RenderText* textRenderer = toRenderText(deprecatedNode()->renderer());
464 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
465 int start = box->start();
466 int end = box->start() + box->len();
467 if (m_offset < start)
468 return result;
469 if (m_offset <= end) {
470 result += m_offset - start;
471 return result;
472 }
473 result += box->len();
474 }
475 return result;
476 }
477
478 // return first preceding DOM position rendered at a different location, or "this"
previousCharacterPosition(EAffinity affinity) const479 Position Position::previousCharacterPosition(EAffinity affinity) const
480 {
481 if (isNull())
482 return Position();
483
484 Node* fromRootEditableElement = deprecatedNode()->rootEditableElement();
485
486 bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
487 bool rendered = isCandidate();
488
489 Position currentPos = *this;
490 while (!currentPos.atStartOfTree()) {
491 currentPos = currentPos.previous();
492
493 if (currentPos.deprecatedNode()->rootEditableElement() != fromRootEditableElement)
494 return *this;
495
496 if (atStartOfLine || !rendered) {
497 if (currentPos.isCandidate())
498 return currentPos;
499 } else if (rendersInDifferentPosition(currentPos))
500 return currentPos;
501 }
502
503 return *this;
504 }
505
506 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
507 // If true, adjacent candidates are visually distinct.
508 // FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
509 // FIXME: Share code with isCandidate, if possible.
endsOfNodeAreVisuallyDistinctPositions(Node * node)510 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
511 {
512 if (!node || !node->renderer())
513 return false;
514
515 if (!node->renderer()->isInline())
516 return true;
517
518 // Don't include inline tables.
519 if (isHTMLTableElement(*node))
520 return false;
521
522 // A Marquee elements are moving so we should assume their ends are always
523 // visibily distinct.
524 if (isHTMLMarqueeElement(*node))
525 return true;
526
527 // There is a VisiblePosition inside an empty inline-block container.
528 return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) && toRenderBox(node->renderer())->height() != 0 && !node->firstChild();
529 }
530
enclosingVisualBoundary(Node * node)531 static Node* enclosingVisualBoundary(Node* node)
532 {
533 while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
534 node = node->parentNode();
535
536 return node;
537 }
538
539 // upstream() and downstream() want to return positions that are either in a
540 // text node or at just before a non-text node. This method checks for that.
isStreamer(const PositionIterator & pos)541 static bool isStreamer(const PositionIterator& pos)
542 {
543 if (!pos.node())
544 return true;
545
546 if (isAtomicNode(pos.node()))
547 return true;
548
549 return pos.atStartOfNode();
550 }
551
552 // This function and downstream() are used for moving back and forth between visually equivalent candidates.
553 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
554 // that map to the VisiblePosition between 'b' and the space. This function will return the left candidate
555 // and downstream() will return the right one.
556 // Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
557 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
upstream(EditingBoundaryCrossingRule rule) const558 Position Position::upstream(EditingBoundaryCrossingRule rule) const
559 {
560 Node* startNode = deprecatedNode();
561 if (!startNode)
562 return Position();
563
564 // iterate backward from there, looking for a qualified position
565 Node* boundary = enclosingVisualBoundary(startNode);
566 // FIXME: PositionIterator should respect Before and After positions.
567 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
568 PositionIterator currentPos = lastVisible;
569 bool startEditable = startNode->rendererIsEditable();
570 Node* lastNode = startNode;
571 bool boundaryCrossed = false;
572 for (; !currentPos.atStart(); currentPos.decrement()) {
573 Node* currentNode = currentPos.node();
574
575 // Don't check for an editability change if we haven't moved to a different node,
576 // to avoid the expense of computing rendererIsEditable().
577 if (currentNode != lastNode) {
578 // Don't change editability.
579 bool currentEditable = currentNode->rendererIsEditable();
580 if (startEditable != currentEditable) {
581 if (rule == CannotCrossEditingBoundary)
582 break;
583 boundaryCrossed = true;
584 }
585 lastNode = currentNode;
586 }
587
588 // If we've moved to a position that is visually distinct, return the last saved position. There
589 // is code below that terminates early if we're *about* to move to a visually distinct position.
590 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
591 return lastVisible;
592
593 // skip position in unrendered or invisible node
594 RenderObject* renderer = currentNode->renderer();
595 if (!renderer || renderer->style()->visibility() != VISIBLE)
596 continue;
597
598 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
599 lastVisible = currentPos;
600 break;
601 }
602
603 // track last visible streamer position
604 if (isStreamer(currentPos))
605 lastVisible = currentPos;
606
607 // Don't move past a position that is visually distinct. We could rely on code above to terminate and
608 // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
609 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.atStartOfNode())
610 return lastVisible;
611
612 // Return position after tables and nodes which have content that can be ignored.
613 if (editingIgnoresContent(currentNode) || isRenderedTableElement(currentNode)) {
614 if (currentPos.atEndOfNode())
615 return positionAfterNode(currentNode);
616 continue;
617 }
618
619 // return current position if it is in rendered text
620 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
621 if (currentNode != startNode) {
622 // This assertion fires in layout tests in the case-transform.html test because
623 // of a mix-up between offsets in the text in the DOM tree with text in the
624 // render tree which can have a different length due to case transformation.
625 // Until we resolve that, disable this so we can run the layout tests!
626 //ASSERT(currentOffset >= renderer->caretMaxOffset());
627 return createLegacyEditingPosition(currentNode, renderer->caretMaxOffset());
628 }
629
630 unsigned textOffset = currentPos.offsetInLeafNode();
631 RenderText* textRenderer = toRenderText(renderer);
632 InlineTextBox* lastTextBox = textRenderer->lastTextBox();
633 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
634 if (textOffset <= box->start() + box->len()) {
635 if (textOffset > box->start())
636 return currentPos;
637 continue;
638 }
639
640 if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
641 continue;
642
643 // The text continues on the next line only if the last text box is not on this line and
644 // none of the boxes on this line have a larger start offset.
645
646 bool continuesOnNextLine = true;
647 InlineBox* otherBox = box;
648 while (continuesOnNextLine) {
649 otherBox = otherBox->nextLeafChild();
650 if (!otherBox)
651 break;
652 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() > textOffset))
653 continuesOnNextLine = false;
654 }
655
656 otherBox = box;
657 while (continuesOnNextLine) {
658 otherBox = otherBox->prevLeafChild();
659 if (!otherBox)
660 break;
661 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() > textOffset))
662 continuesOnNextLine = false;
663 }
664
665 if (continuesOnNextLine)
666 return currentPos;
667 }
668 }
669 }
670
671 return lastVisible;
672 }
673
674 // This function and upstream() are used for moving back and forth between visually equivalent candidates.
675 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
676 // that map to the VisiblePosition between 'b' and the space. This function will return the right candidate
677 // and upstream() will return the left one.
678 // Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
679 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
680 // FIXME: This function should never be called when the line box tree is dirty. See https://bugs.webkit.org/show_bug.cgi?id=97264
downstream(EditingBoundaryCrossingRule rule) const681 Position Position::downstream(EditingBoundaryCrossingRule rule) const
682 {
683 Node* startNode = deprecatedNode();
684 if (!startNode)
685 return Position();
686
687 // iterate forward from there, looking for a qualified position
688 Node* boundary = enclosingVisualBoundary(startNode);
689 // FIXME: PositionIterator should respect Before and After positions.
690 PositionIterator lastVisible = m_anchorType == PositionIsAfterAnchor ? createLegacyEditingPosition(m_anchorNode.get(), caretMaxOffset(m_anchorNode.get())) : *this;
691 PositionIterator currentPos = lastVisible;
692 bool startEditable = startNode->rendererIsEditable();
693 Node* lastNode = startNode;
694 bool boundaryCrossed = false;
695 for (; !currentPos.atEnd(); currentPos.increment()) {
696 Node* currentNode = currentPos.node();
697
698 // Don't check for an editability change if we haven't moved to a different node,
699 // to avoid the expense of computing rendererIsEditable().
700 if (currentNode != lastNode) {
701 // Don't change editability.
702 bool currentEditable = currentNode->rendererIsEditable();
703 if (startEditable != currentEditable) {
704 if (rule == CannotCrossEditingBoundary)
705 break;
706 boundaryCrossed = true;
707 }
708
709 lastNode = currentNode;
710 }
711
712 // stop before going above the body, up into the head
713 // return the last visible streamer position
714 if (isHTMLBodyElement(*currentNode) && currentPos.atEndOfNode())
715 break;
716
717 // Do not move to a visually distinct position.
718 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
719 return lastVisible;
720 // Do not move past a visually disinct position.
721 // Note: The first position after the last in a node whose ends are visually distinct
722 // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
723 if (boundary && boundary->parentNode() == currentNode)
724 return lastVisible;
725
726 // skip position in unrendered or invisible node
727 RenderObject* renderer = currentNode->renderer();
728 if (!renderer || renderer->style()->visibility() != VISIBLE)
729 continue;
730
731 if (rule == CanCrossEditingBoundary && boundaryCrossed) {
732 lastVisible = currentPos;
733 break;
734 }
735
736 // track last visible streamer position
737 if (isStreamer(currentPos))
738 lastVisible = currentPos;
739
740 // Return position before tables and nodes which have content that can be ignored.
741 if (editingIgnoresContent(currentNode) || isRenderedTableElement(currentNode)) {
742 if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
743 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
744 continue;
745 }
746
747 // return current position if it is in rendered text
748 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
749 if (currentNode != startNode) {
750 ASSERT(currentPos.atStartOfNode());
751 return createLegacyEditingPosition(currentNode, renderer->caretMinOffset());
752 }
753
754 unsigned textOffset = currentPos.offsetInLeafNode();
755 RenderText* textRenderer = toRenderText(renderer);
756 InlineTextBox* lastTextBox = textRenderer->lastTextBox();
757 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
758 if (textOffset <= box->end()) {
759 if (textOffset >= box->start())
760 return currentPos;
761 continue;
762 }
763
764 if (box == lastTextBox || textOffset != box->start() + box->len())
765 continue;
766
767 // The text continues on the next line only if the last text box is not on this line and
768 // none of the boxes on this line have a larger start offset.
769
770 bool continuesOnNextLine = true;
771 InlineBox* otherBox = box;
772 while (continuesOnNextLine) {
773 otherBox = otherBox->nextLeafChild();
774 if (!otherBox)
775 break;
776 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() >= textOffset))
777 continuesOnNextLine = false;
778 }
779
780 otherBox = box;
781 while (continuesOnNextLine) {
782 otherBox = otherBox->prevLeafChild();
783 if (!otherBox)
784 break;
785 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && toInlineTextBox(otherBox)->start() >= textOffset))
786 continuesOnNextLine = false;
787 }
788
789 if (continuesOnNextLine)
790 return currentPos;
791 }
792 }
793 }
794
795 return lastVisible;
796 }
797
boundingBoxLogicalHeight(RenderObject * o,const IntRect & rect)798 static int boundingBoxLogicalHeight(RenderObject *o, const IntRect &rect)
799 {
800 return o->style()->isHorizontalWritingMode() ? rect.height() : rect.width();
801 }
802
hasRenderedNonAnonymousDescendantsWithHeight(RenderObject * renderer)803 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
804 {
805 RenderObject* stop = renderer->nextInPreOrderAfterChildren();
806 for (RenderObject *o = renderer->slowFirstChild(); o && o != stop; o = o->nextInPreOrder())
807 if (o->nonPseudoNode()) {
808 if ((o->isText() && boundingBoxLogicalHeight(o, toRenderText(o)->linesBoundingBox()))
809 || (o->isBox() && toRenderBox(o)->pixelSnappedLogicalHeight())
810 || (o->isRenderInline() && isEmptyInline(o) && boundingBoxLogicalHeight(o, toRenderInline(o)->linesBoundingBox())))
811 return true;
812 }
813 return false;
814 }
815
nodeIsUserSelectNone(Node * node)816 bool Position::nodeIsUserSelectNone(Node* node)
817 {
818 return node && node->renderer() && !node->renderer()->isSelectable();
819 }
820
nodeIsUserSelectAll(const Node * node)821 bool Position::nodeIsUserSelectAll(const Node* node)
822 {
823 return RuntimeEnabledFeatures::userSelectAllEnabled() && node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_ALL;
824 }
825
rootUserSelectAllForNode(Node * node)826 Node* Position::rootUserSelectAllForNode(Node* node)
827 {
828 if (!node || !nodeIsUserSelectAll(node))
829 return 0;
830 Node* parent = node->parentNode();
831 if (!parent)
832 return node;
833
834 Node* candidateRoot = node;
835 while (parent) {
836 if (!parent->renderer()) {
837 parent = parent->parentNode();
838 continue;
839 }
840 if (!nodeIsUserSelectAll(parent))
841 break;
842 candidateRoot = parent;
843 parent = candidateRoot->parentNode();
844 }
845 return candidateRoot;
846 }
847
isCandidate() const848 bool Position::isCandidate() const
849 {
850 if (isNull())
851 return false;
852
853 RenderObject* renderer = deprecatedNode()->renderer();
854 if (!renderer)
855 return false;
856
857 if (renderer->style()->visibility() != VISIBLE)
858 return false;
859
860 if (renderer->isBR())
861 // FIXME: The condition should be m_anchorType == PositionIsBeforeAnchor, but for now we still need to support legacy positions.
862 return !m_offset && m_anchorType != PositionIsAfterAnchor && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
863
864 if (renderer->isText())
865 return !nodeIsUserSelectNone(deprecatedNode()) && inRenderedText();
866
867 if (renderer->isSVG()) {
868 // We don't consider SVG elements are contenteditable except for
869 // associated renderer returns isText() true, e.g. RenderSVGInlineText.
870 return false;
871 }
872
873 if (isRenderedTableElement(deprecatedNode()) || editingIgnoresContent(deprecatedNode()))
874 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(deprecatedNode()->parentNode());
875
876 if (isHTMLHtmlElement(*m_anchorNode))
877 return false;
878
879 if (renderer->isRenderBlockFlow()) {
880 if (toRenderBlock(renderer)->logicalHeight() || isHTMLBodyElement(*m_anchorNode)) {
881 if (!Position::hasRenderedNonAnonymousDescendantsWithHeight(renderer))
882 return atFirstEditingPositionForNode() && !Position::nodeIsUserSelectNone(deprecatedNode());
883 return m_anchorNode->rendererIsEditable() && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
884 }
885 } else {
886 LocalFrame* frame = m_anchorNode->document().frame();
887 bool caretBrowsing = frame->settings() && frame->settings()->caretBrowsingEnabled();
888 return (caretBrowsing || m_anchorNode->rendererIsEditable()) && !Position::nodeIsUserSelectNone(deprecatedNode()) && atEditingBoundary();
889 }
890
891 return false;
892 }
893
inRenderedText() const894 bool Position::inRenderedText() const
895 {
896 if (isNull() || !deprecatedNode()->isTextNode())
897 return false;
898
899 RenderObject* renderer = deprecatedNode()->renderer();
900 if (!renderer)
901 return false;
902
903 RenderText *textRenderer = toRenderText(renderer);
904 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
905 if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
906 // The offset we're looking for is before this node
907 // this means the offset must be in content that is
908 // not rendered. Return false.
909 return false;
910 }
911 if (box->containsCaretOffset(m_offset))
912 // Return false for offsets inside composed characters.
913 return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
914 }
915
916 return false;
917 }
918
isRenderedCharacter() const919 bool Position::isRenderedCharacter() const
920 {
921 if (isNull() || !deprecatedNode()->isTextNode())
922 return false;
923
924 RenderObject* renderer = deprecatedNode()->renderer();
925 if (!renderer)
926 return false;
927
928 RenderText* textRenderer = toRenderText(renderer);
929 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
930 if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
931 // The offset we're looking for is before this node
932 // this means the offset must be in content that is
933 // not rendered. Return false.
934 return false;
935 }
936 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(box->start() + box->len()))
937 return true;
938 }
939
940 return false;
941 }
942
rendersInDifferentPosition(const Position & pos) const943 bool Position::rendersInDifferentPosition(const Position &pos) const
944 {
945 if (isNull() || pos.isNull())
946 return false;
947
948 RenderObject* renderer = deprecatedNode()->renderer();
949 if (!renderer)
950 return false;
951
952 RenderObject* posRenderer = pos.deprecatedNode()->renderer();
953 if (!posRenderer)
954 return false;
955
956 if (renderer->style()->visibility() != VISIBLE ||
957 posRenderer->style()->visibility() != VISIBLE)
958 return false;
959
960 if (deprecatedNode() == pos.deprecatedNode()) {
961 if (isHTMLBRElement(*deprecatedNode()))
962 return false;
963
964 if (m_offset == pos.deprecatedEditingOffset())
965 return false;
966
967 if (!deprecatedNode()->isTextNode() && !pos.deprecatedNode()->isTextNode()) {
968 if (m_offset != pos.deprecatedEditingOffset())
969 return true;
970 }
971 }
972
973 if (isHTMLBRElement(*deprecatedNode()) && pos.isCandidate())
974 return true;
975
976 if (isHTMLBRElement(*pos.deprecatedNode()) && isCandidate())
977 return true;
978
979 if (deprecatedNode()->enclosingBlockFlowElement() != pos.deprecatedNode()->enclosingBlockFlowElement())
980 return true;
981
982 if (deprecatedNode()->isTextNode() && !inRenderedText())
983 return false;
984
985 if (pos.deprecatedNode()->isTextNode() && !pos.inRenderedText())
986 return false;
987
988 int thisRenderedOffset = renderedOffset();
989 int posRenderedOffset = pos.renderedOffset();
990
991 if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
992 return false;
993
994 int ignoredCaretOffset;
995 InlineBox* b1;
996 getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
997 InlineBox* b2;
998 pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
999
1000 WTF_LOG(Editing, "renderer: %p [%p]\n", renderer, b1);
1001 WTF_LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset);
1002 WTF_LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, b2);
1003 WTF_LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset);
1004 WTF_LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(deprecatedNode()), caretMaxOffset(deprecatedNode()));
1005 WTF_LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.deprecatedNode()), caretMaxOffset(pos.deprecatedNode()));
1006 WTF_LOG(Editing, "----------------------------------------------------------------------\n");
1007
1008 if (!b1 || !b2) {
1009 return false;
1010 }
1011
1012 if (b1->root() != b2->root()) {
1013 return true;
1014 }
1015
1016 if (nextRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
1017 && thisRenderedOffset == caretMaxOffset(deprecatedNode()) && !posRenderedOffset) {
1018 return false;
1019 }
1020
1021 if (previousRenderedEditable(deprecatedNode()) == pos.deprecatedNode()
1022 && !thisRenderedOffset && posRenderedOffset == caretMaxOffset(pos.deprecatedNode())) {
1023 return false;
1024 }
1025
1026 return true;
1027 }
1028
1029 // This assumes that it starts in editable content.
leadingWhitespacePosition(EAffinity affinity,bool considerNonCollapsibleWhitespace) const1030 Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
1031 {
1032 ASSERT(isEditablePosition(*this, ContentIsEditable, DoNotUpdateStyle));
1033 if (isNull())
1034 return Position();
1035
1036 if (isHTMLBRElement(*upstream().deprecatedNode()))
1037 return Position();
1038
1039 Position prev = previousCharacterPosition(affinity);
1040 if (prev != *this && prev.deprecatedNode()->inSameContainingBlockFlowElement(deprecatedNode()) && prev.deprecatedNode()->isTextNode()) {
1041 String string = toText(prev.deprecatedNode())->data();
1042 UChar c = string[prev.deprecatedEditingOffset()];
1043 if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
1044 if (isEditablePosition(prev))
1045 return prev;
1046 }
1047
1048 return Position();
1049 }
1050
1051 // This assumes that it starts in editable content.
trailingWhitespacePosition(EAffinity,bool considerNonCollapsibleWhitespace) const1052 Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace) const
1053 {
1054 ASSERT(isEditablePosition(*this, ContentIsEditable, DoNotUpdateStyle));
1055 if (isNull())
1056 return Position();
1057
1058 VisiblePosition v(*this);
1059 UChar c = v.characterAfter();
1060 // The space must not be in another paragraph and it must be editable.
1061 if (!isEndOfParagraph(v) && v.next(CannotCrossEditingBoundary).isNotNull())
1062 if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
1063 return *this;
1064
1065 return Position();
1066 }
1067
getInlineBoxAndOffset(EAffinity affinity,InlineBox * & inlineBox,int & caretOffset) const1068 void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
1069 {
1070 getInlineBoxAndOffset(affinity, primaryDirection(), inlineBox, caretOffset);
1071 }
1072
isNonTextLeafChild(RenderObject * object)1073 static bool isNonTextLeafChild(RenderObject* object)
1074 {
1075 if (object->slowFirstChild())
1076 return false;
1077 if (object->isText())
1078 return false;
1079 return true;
1080 }
1081
searchAheadForBetterMatch(RenderObject * renderer)1082 static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
1083 {
1084 RenderBlock* container = renderer->containingBlock();
1085 RenderObject* next = renderer;
1086 while ((next = next->nextInPreOrder(container))) {
1087 if (next->isRenderBlock())
1088 return 0;
1089 if (next->isBR())
1090 return 0;
1091 if (isNonTextLeafChild(next))
1092 return 0;
1093 if (next->isText()) {
1094 InlineTextBox* match = 0;
1095 int minOffset = INT_MAX;
1096 for (InlineTextBox* box = toRenderText(next)->firstTextBox(); box; box = box->nextTextBox()) {
1097 int caretMinOffset = box->caretMinOffset();
1098 if (caretMinOffset < minOffset) {
1099 match = box;
1100 minOffset = caretMinOffset;
1101 }
1102 }
1103 if (match)
1104 return match;
1105 }
1106 }
1107 return 0;
1108 }
1109
downstreamIgnoringEditingBoundaries(Position position)1110 static Position downstreamIgnoringEditingBoundaries(Position position)
1111 {
1112 Position lastPosition;
1113 while (position != lastPosition) {
1114 lastPosition = position;
1115 position = position.downstream(CanCrossEditingBoundary);
1116 }
1117 return position;
1118 }
1119
upstreamIgnoringEditingBoundaries(Position position)1120 static Position upstreamIgnoringEditingBoundaries(Position position)
1121 {
1122 Position lastPosition;
1123 while (position != lastPosition) {
1124 lastPosition = position;
1125 position = position.upstream(CanCrossEditingBoundary);
1126 }
1127 return position;
1128 }
1129
getInlineBoxAndOffset(EAffinity affinity,TextDirection primaryDirection,InlineBox * & inlineBox,int & caretOffset) const1130 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
1131 {
1132 caretOffset = deprecatedEditingOffset();
1133 RenderObject* renderer = deprecatedNode()->renderer();
1134
1135 if (!renderer->isText()) {
1136 inlineBox = 0;
1137 if (canHaveChildrenForEditing(deprecatedNode()) && renderer->isRenderBlockFlow() && hasRenderedNonAnonymousDescendantsWithHeight(renderer)) {
1138 // Try a visually equivalent position with possibly opposite editability. This helps in case |this| is in
1139 // an editable block but surrounded by non-editable positions. It acts to negate the logic at the beginning
1140 // of RenderObject::createVisiblePosition().
1141 Position equivalent = downstreamIgnoringEditingBoundaries(*this);
1142 if (equivalent == *this) {
1143 equivalent = upstreamIgnoringEditingBoundaries(*this);
1144 if (equivalent == *this || downstreamIgnoringEditingBoundaries(equivalent) == *this)
1145 return;
1146 }
1147
1148 equivalent.getInlineBoxAndOffset(UPSTREAM, primaryDirection, inlineBox, caretOffset);
1149 return;
1150 }
1151 if (renderer->isBox()) {
1152 inlineBox = toRenderBox(renderer)->inlineBoxWrapper();
1153 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
1154 return;
1155 }
1156 } else {
1157 RenderText* textRenderer = toRenderText(renderer);
1158
1159 InlineTextBox* box;
1160 InlineTextBox* candidate = 0;
1161
1162 for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
1163 int caretMinOffset = box->caretMinOffset();
1164 int caretMaxOffset = box->caretMaxOffset();
1165
1166 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
1167 continue;
1168
1169 if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
1170 inlineBox = box;
1171 return;
1172 }
1173
1174 if (((caretOffset == caretMaxOffset) ^ (affinity == DOWNSTREAM))
1175 || ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM))
1176 || (caretOffset == caretMaxOffset && box->nextLeafChild() && box->nextLeafChild()->isLineBreak()))
1177 break;
1178
1179 candidate = box;
1180 }
1181 if (candidate && candidate == textRenderer->lastTextBox() && affinity == DOWNSTREAM) {
1182 box = searchAheadForBetterMatch(textRenderer);
1183 if (box)
1184 caretOffset = box->caretMinOffset();
1185 }
1186 inlineBox = box ? box : candidate;
1187 }
1188
1189 if (!inlineBox)
1190 return;
1191
1192 unsigned char level = inlineBox->bidiLevel();
1193
1194 if (inlineBox->direction() == primaryDirection) {
1195 if (caretOffset == inlineBox->caretRightmostOffset()) {
1196 InlineBox* nextBox = inlineBox->nextLeafChild();
1197 if (!nextBox || nextBox->bidiLevel() >= level)
1198 return;
1199
1200 level = nextBox->bidiLevel();
1201 InlineBox* prevBox = inlineBox;
1202 do {
1203 prevBox = prevBox->prevLeafChild();
1204 } while (prevBox && prevBox->bidiLevel() > level);
1205
1206 if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
1207 return;
1208
1209 // For example, abc 123 ^ CBA
1210 while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1211 if (nextBox->bidiLevel() < level)
1212 break;
1213 inlineBox = nextBox;
1214 }
1215 caretOffset = inlineBox->caretRightmostOffset();
1216 } else {
1217 InlineBox* prevBox = inlineBox->prevLeafChild();
1218 if (!prevBox || prevBox->bidiLevel() >= level)
1219 return;
1220
1221 level = prevBox->bidiLevel();
1222 InlineBox* nextBox = inlineBox;
1223 do {
1224 nextBox = nextBox->nextLeafChild();
1225 } while (nextBox && nextBox->bidiLevel() > level);
1226
1227 if (nextBox && nextBox->bidiLevel() == level)
1228 return;
1229
1230 while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1231 if (prevBox->bidiLevel() < level)
1232 break;
1233 inlineBox = prevBox;
1234 }
1235 caretOffset = inlineBox->caretLeftmostOffset();
1236 }
1237 return;
1238 }
1239
1240 if (caretOffset == inlineBox->caretLeftmostOffset()) {
1241 InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak();
1242 if (!prevBox || prevBox->bidiLevel() < level) {
1243 // Left edge of a secondary run. Set to the right edge of the entire run.
1244 while (InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1245 if (nextBox->bidiLevel() < level)
1246 break;
1247 inlineBox = nextBox;
1248 }
1249 caretOffset = inlineBox->caretRightmostOffset();
1250 } else if (prevBox->bidiLevel() > level) {
1251 // Right edge of a "tertiary" run. Set to the left edge of that run.
1252 while (InlineBox* tertiaryBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1253 if (tertiaryBox->bidiLevel() <= level)
1254 break;
1255 inlineBox = tertiaryBox;
1256 }
1257 caretOffset = inlineBox->caretLeftmostOffset();
1258 }
1259 } else {
1260 InlineBox* nextBox = inlineBox->nextLeafChildIgnoringLineBreak();
1261 if (!nextBox || nextBox->bidiLevel() < level) {
1262 // Right edge of a secondary run. Set to the left edge of the entire run.
1263 while (InlineBox* prevBox = inlineBox->prevLeafChildIgnoringLineBreak()) {
1264 if (prevBox->bidiLevel() < level)
1265 break;
1266 inlineBox = prevBox;
1267 }
1268 if (m_anchorNode->selfOrAncestorHasDirAutoAttribute())
1269 caretOffset = inlineBox->bidiLevel() < level ? inlineBox->caretLeftmostOffset() : inlineBox->caretRightmostOffset();
1270 else
1271 caretOffset = inlineBox->caretLeftmostOffset();
1272 } else if (nextBox->bidiLevel() > level) {
1273 // Left edge of a "tertiary" run. Set to the right edge of that run.
1274 while (InlineBox* tertiaryBox = inlineBox->nextLeafChildIgnoringLineBreak()) {
1275 if (tertiaryBox->bidiLevel() <= level)
1276 break;
1277 inlineBox = tertiaryBox;
1278 }
1279 caretOffset = inlineBox->caretRightmostOffset();
1280 }
1281 }
1282 }
1283
primaryDirection() const1284 TextDirection Position::primaryDirection() const
1285 {
1286 TextDirection primaryDirection = LTR;
1287 for (const RenderObject* r = m_anchorNode->renderer(); r; r = r->parent()) {
1288 if (r->isRenderBlockFlow()) {
1289 primaryDirection = r->style()->direction();
1290 break;
1291 }
1292 }
1293
1294 return primaryDirection;
1295 }
1296
trace(Visitor * visitor)1297 void Position::trace(Visitor* visitor)
1298 {
1299 visitor->trace(m_anchorNode);
1300 }
1301
debugPosition(const char * msg) const1302 void Position::debugPosition(const char* msg) const
1303 {
1304 if (isNull())
1305 fprintf(stderr, "Position [%s]: null\n", msg);
1306 else
1307 fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, deprecatedNode()->nodeName().utf8().data(), deprecatedNode(), m_offset);
1308 }
1309
1310 #ifndef NDEBUG
1311
formatForDebugger(char * buffer,unsigned length) const1312 void Position::formatForDebugger(char* buffer, unsigned length) const
1313 {
1314 StringBuilder result;
1315
1316 if (isNull())
1317 result.appendLiteral("<null>");
1318 else {
1319 char s[1024];
1320 result.appendLiteral("offset ");
1321 result.appendNumber(m_offset);
1322 result.appendLiteral(" of ");
1323 deprecatedNode()->formatForDebugger(s, sizeof(s));
1324 result.append(s);
1325 }
1326
1327 strncpy(buffer, result.toString().utf8().data(), length - 1);
1328 }
1329
showAnchorTypeAndOffset() const1330 void Position::showAnchorTypeAndOffset() const
1331 {
1332 if (m_isLegacyEditingPosition)
1333 fputs("legacy, ", stderr);
1334 switch (anchorType()) {
1335 case PositionIsOffsetInAnchor:
1336 fputs("offset", stderr);
1337 break;
1338 case PositionIsBeforeChildren:
1339 fputs("beforeChildren", stderr);
1340 break;
1341 case PositionIsAfterChildren:
1342 fputs("afterChildren", stderr);
1343 break;
1344 case PositionIsBeforeAnchor:
1345 fputs("before", stderr);
1346 break;
1347 case PositionIsAfterAnchor:
1348 fputs("after", stderr);
1349 break;
1350 }
1351 fprintf(stderr, ", offset:%d\n", m_offset);
1352 }
1353
showTreeForThis() const1354 void Position::showTreeForThis() const
1355 {
1356 if (anchorNode()) {
1357 anchorNode()->showTreeForThis();
1358 showAnchorTypeAndOffset();
1359 }
1360 }
1361
1362 #endif
1363
1364
1365
1366 } // namespace WebCore
1367
1368 #ifndef NDEBUG
1369
showTree(const WebCore::Position & pos)1370 void showTree(const WebCore::Position& pos)
1371 {
1372 pos.showTreeForThis();
1373 }
1374
showTree(const WebCore::Position * pos)1375 void showTree(const WebCore::Position* pos)
1376 {
1377 if (pos)
1378 pos->showTreeForThis();
1379 }
1380
1381 #endif
1382