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 "Position.h"
28
29 #include "CSSComputedStyleDeclaration.h"
30 #include "CString.h"
31 #include "CharacterNames.h"
32 #include "Logging.h"
33 #include "PositionIterator.h"
34 #include "RenderBlock.h"
35 #include "Text.h"
36 #include "TextIterator.h"
37 #include "VisiblePosition.h"
38 #include "htmlediting.h"
39 #include "visible_units.h"
40 #include <stdio.h>
41
42 namespace WebCore {
43
44 using namespace HTMLNames;
45
nextRenderedEditable(Node * node)46 static Node* nextRenderedEditable(Node* node)
47 {
48 while (1) {
49 node = node->nextEditable();
50 if (!node)
51 return 0;
52 RenderObject* renderer = node->renderer();
53 if (!renderer)
54 continue;
55 if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
56 return node;
57 }
58 return 0;
59 }
60
previousRenderedEditable(Node * node)61 static Node* previousRenderedEditable(Node* node)
62 {
63 while (1) {
64 node = node->previousEditable();
65 if (!node)
66 return 0;
67 RenderObject* renderer = node->renderer();
68 if (!renderer)
69 continue;
70 if ((renderer->isBox() && toRenderBox(renderer)->inlineBoxWrapper()) || (renderer->isText() && toRenderText(renderer)->firstTextBox()))
71 return node;
72 }
73 return 0;
74 }
75
Position(PassRefPtr<Node> anchorNode,int offset)76 Position::Position(PassRefPtr<Node> anchorNode, int offset)
77 : m_anchorNode(anchorNode)
78 , m_offset(offset)
79 , m_anchorType(anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset))
80 , m_isLegacyEditingPosition(true)
81 {
82 }
83
Position(PassRefPtr<Node> anchorNode,AnchorType anchorType)84 Position::Position(PassRefPtr<Node> anchorNode, AnchorType anchorType)
85 : m_anchorNode(anchorNode)
86 , m_offset(0)
87 , m_anchorType(anchorType)
88 , m_isLegacyEditingPosition(false)
89 {
90 ASSERT(anchorType != PositionIsOffsetInAnchor);
91 }
92
Position(PassRefPtr<Node> anchorNode,int offset,AnchorType anchorType)93 Position::Position(PassRefPtr<Node> anchorNode, int offset, AnchorType anchorType)
94 : m_anchorNode(anchorNode)
95 , m_offset(offset)
96 , m_anchorType(anchorType)
97 , m_isLegacyEditingPosition(false)
98 {
99 ASSERT(anchorType == PositionIsOffsetInAnchor);
100 }
101
moveToPosition(PassRefPtr<Node> node,int offset)102 void Position::moveToPosition(PassRefPtr<Node> node, int offset)
103 {
104 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
105 m_anchorNode = node;
106 m_offset = offset;
107 if (m_isLegacyEditingPosition)
108 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
109 }
moveToOffset(int offset)110 void Position::moveToOffset(int offset)
111 {
112 ASSERT(anchorType() == PositionIsOffsetInAnchor || m_isLegacyEditingPosition);
113 m_offset = offset;
114 if (m_isLegacyEditingPosition)
115 m_anchorType = anchorTypeForLegacyEditingPosition(m_anchorNode.get(), m_offset);
116 }
117
containerNode() const118 Node* Position::containerNode() const
119 {
120 if (!m_anchorNode)
121 return 0;
122
123 switch (anchorType()) {
124 case PositionIsOffsetInAnchor:
125 return m_anchorNode.get();
126 case PositionIsBeforeAnchor:
127 case PositionIsAfterAnchor:
128 return m_anchorNode->parentNode();
129 }
130 ASSERT_NOT_REACHED();
131 return 0;
132 }
133
computeOffsetInContainerNode() const134 int Position::computeOffsetInContainerNode() const
135 {
136 if (!m_anchorNode)
137 return 0;
138
139 switch (anchorType()) {
140 case PositionIsOffsetInAnchor:
141 {
142 int maximumValidOffset = m_anchorNode->offsetInCharacters() ? m_anchorNode->maxCharacterOffset() : m_anchorNode->childNodeCount();
143 return std::min(maximumValidOffset, m_offset);
144 }
145 case PositionIsBeforeAnchor:
146 return m_anchorNode->nodeIndex();
147 case PositionIsAfterAnchor:
148 return m_anchorNode->nodeIndex() + 1;
149 }
150 ASSERT_NOT_REACHED();
151 return 0;
152 }
153
computeNodeBeforePosition() const154 Node* Position::computeNodeBeforePosition() const
155 {
156 if (!m_anchorNode)
157 return 0;
158
159 switch (anchorType()) {
160 case PositionIsOffsetInAnchor:
161 return m_anchorNode->childNode(m_offset - 1); // -1 converts to childNode((unsigned)-1) and returns null.
162 case PositionIsBeforeAnchor:
163 return m_anchorNode->previousSibling();
164 case PositionIsAfterAnchor:
165 return m_anchorNode.get();
166 }
167 ASSERT_NOT_REACHED();
168 return 0;
169 }
170
computeNodeAfterPosition() const171 Node* Position::computeNodeAfterPosition() const
172 {
173 if (!m_anchorNode)
174 return 0;
175
176 switch (anchorType()) {
177 case PositionIsOffsetInAnchor:
178 return m_anchorNode->childNode(m_offset);
179 case PositionIsBeforeAnchor:
180 return m_anchorNode.get();
181 case PositionIsAfterAnchor:
182 return m_anchorNode->nextSibling();
183 }
184 ASSERT_NOT_REACHED();
185 return 0;
186 }
187
anchorTypeForLegacyEditingPosition(Node * anchorNode,int offset)188 Position::AnchorType Position::anchorTypeForLegacyEditingPosition(Node* anchorNode, int offset)
189 {
190 if (anchorNode && editingIgnoresContent(anchorNode)) {
191 if (offset == 0)
192 return Position::PositionIsBeforeAnchor;
193 return Position::PositionIsAfterAnchor;
194 }
195 return Position::PositionIsOffsetInAnchor;
196 }
197
198 // FIXME: This method is confusing (does it return anchorNode() or containerNode()?) and should be renamed or removed
element() const199 Element* Position::element() const
200 {
201 Node* n = anchorNode();
202 while (n && !n->isElementNode())
203 n = n->parentNode();
204 return static_cast<Element*>(n);
205 }
206
computedStyle() const207 PassRefPtr<CSSComputedStyleDeclaration> Position::computedStyle() const
208 {
209 Element* elem = element();
210 if (!elem)
211 return 0;
212 return WebCore::computedStyle(elem);
213 }
214
previous(PositionMoveType moveType) const215 Position Position::previous(PositionMoveType moveType) const
216 {
217 Node* n = node();
218 if (!n)
219 return *this;
220
221 int o = m_offset;
222 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
223 ASSERT(o >= 0);
224
225 if (o > 0) {
226 Node* child = n->childNode(o - 1);
227 if (child)
228 return lastDeepEditingPositionForNode(child);
229
230 // There are two reasons child might be 0:
231 // 1) The node is node like a text node that is not an element, and therefore has no children.
232 // Going backward one character at a time is correct.
233 // 2) The old offset was a bogus offset like (<br>, 1), and there is no child.
234 // Going from 1 to 0 is correct.
235 switch (moveType) {
236 case CodePoint:
237 return Position(n, o - 1);
238 case Character:
239 return Position(n, uncheckedPreviousOffset(n, o));
240 case BackwardDeletion:
241 return Position(n, uncheckedPreviousOffsetForBackwardDeletion(n, o));
242 }
243 }
244
245 Node* parent = n->parentNode();
246 if (!parent)
247 return *this;
248
249 return Position(parent, n->nodeIndex());
250 }
251
next(PositionMoveType moveType) const252 Position Position::next(PositionMoveType moveType) const
253 {
254 ASSERT(moveType != BackwardDeletion);
255
256 Node* n = node();
257 if (!n)
258 return *this;
259
260 int o = m_offset;
261 // FIXME: Negative offsets shouldn't be allowed. We should catch this earlier.
262 ASSERT(o >= 0);
263
264 Node* child = n->childNode(o);
265 if (child || (!n->hasChildNodes() && o < lastOffsetForEditing(n))) {
266 if (child)
267 return firstDeepEditingPositionForNode(child);
268
269 // There are two reasons child might be 0:
270 // 1) The node is node like a text node that is not an element, and therefore has no children.
271 // Going forward one character at a time is correct.
272 // 2) The new offset is a bogus offset like (<br>, 1), and there is no child.
273 // Going from 0 to 1 is correct.
274 return Position(n, (moveType == Character) ? uncheckedNextOffset(n, o) : o + 1);
275 }
276
277 Node* parent = n->parentNode();
278 if (!parent)
279 return *this;
280
281 return Position(parent, n->nodeIndex() + 1);
282 }
283
uncheckedPreviousOffset(const Node * n,int current)284 int Position::uncheckedPreviousOffset(const Node* n, int current)
285 {
286 return n->renderer() ? n->renderer()->previousOffset(current) : current - 1;
287 }
288
uncheckedPreviousOffsetForBackwardDeletion(const Node * n,int current)289 int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current)
290 {
291 return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1;
292 }
293
uncheckedNextOffset(const Node * n,int current)294 int Position::uncheckedNextOffset(const Node* n, int current)
295 {
296 return n->renderer() ? n->renderer()->nextOffset(current) : current + 1;
297 }
298
atFirstEditingPositionForNode() const299 bool Position::atFirstEditingPositionForNode() const
300 {
301 if (isNull())
302 return true;
303 return m_offset <= 0;
304 }
305
atLastEditingPositionForNode() const306 bool Position::atLastEditingPositionForNode() const
307 {
308 if (isNull())
309 return true;
310 return m_offset >= lastOffsetForEditing(node());
311 }
312
atStartOfTree() const313 bool Position::atStartOfTree() const
314 {
315 if (isNull())
316 return true;
317 return !node()->parentNode() && m_offset <= 0;
318 }
319
atEndOfTree() const320 bool Position::atEndOfTree() const
321 {
322 if (isNull())
323 return true;
324 return !node()->parentNode() && m_offset >= lastOffsetForEditing(node());
325 }
326
renderedOffset() const327 int Position::renderedOffset() const
328 {
329 if (!node()->isTextNode())
330 return m_offset;
331
332 if (!node()->renderer())
333 return m_offset;
334
335 int result = 0;
336 RenderText *textRenderer = toRenderText(node()->renderer());
337 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
338 int start = box->start();
339 int end = box->start() + box->len();
340 if (m_offset < start)
341 return result;
342 if (m_offset <= end) {
343 result += m_offset - start;
344 return result;
345 }
346 result += box->len();
347 }
348 return result;
349 }
350
351 // return first preceding DOM position rendered at a different location, or "this"
previousCharacterPosition(EAffinity affinity) const352 Position Position::previousCharacterPosition(EAffinity affinity) const
353 {
354 if (isNull())
355 return Position();
356
357 Node *fromRootEditableElement = node()->rootEditableElement();
358
359 bool atStartOfLine = isStartOfLine(VisiblePosition(*this, affinity));
360 bool rendered = isCandidate();
361
362 Position currentPos = *this;
363 while (!currentPos.atStartOfTree()) {
364 currentPos = currentPos.previous();
365
366 if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
367 return *this;
368
369 if (atStartOfLine || !rendered) {
370 if (currentPos.isCandidate())
371 return currentPos;
372 } else if (rendersInDifferentPosition(currentPos))
373 return currentPos;
374 }
375
376 return *this;
377 }
378
379 // return first following position rendered at a different location, or "this"
nextCharacterPosition(EAffinity affinity) const380 Position Position::nextCharacterPosition(EAffinity affinity) const
381 {
382 if (isNull())
383 return Position();
384
385 Node *fromRootEditableElement = node()->rootEditableElement();
386
387 bool atEndOfLine = isEndOfLine(VisiblePosition(*this, affinity));
388 bool rendered = isCandidate();
389
390 Position currentPos = *this;
391 while (!currentPos.atEndOfTree()) {
392 currentPos = currentPos.next();
393
394 if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
395 return *this;
396
397 if (atEndOfLine || !rendered) {
398 if (currentPos.isCandidate())
399 return currentPos;
400 } else if (rendersInDifferentPosition(currentPos))
401 return currentPos;
402 }
403
404 return *this;
405 }
406
407 // Whether or not [node, 0] and [node, lastOffsetForEditing(node)] are their own VisiblePositions.
408 // If true, adjacent candidates are visually distinct.
409 // FIXME: Disregard nodes with renderers that have no height, as we do in isCandidate.
410 // FIXME: Share code with isCandidate, if possible.
endsOfNodeAreVisuallyDistinctPositions(Node * node)411 static bool endsOfNodeAreVisuallyDistinctPositions(Node* node)
412 {
413 if (!node || !node->renderer())
414 return false;
415
416 if (!node->renderer()->isInline())
417 return true;
418
419 // Don't include inline tables.
420 if (node->hasTagName(tableTag))
421 return false;
422
423 // There is a VisiblePosition inside an empty inline-block container.
424 return node->renderer()->isReplaced() && canHaveChildrenForEditing(node) && toRenderBox(node->renderer())->height() != 0 && !node->firstChild();
425 }
426
enclosingVisualBoundary(Node * node)427 static Node* enclosingVisualBoundary(Node* node)
428 {
429 while (node && !endsOfNodeAreVisuallyDistinctPositions(node))
430 node = node->parentNode();
431
432 return node;
433 }
434
435 // upstream() and downstream() want to return positions that are either in a
436 // text node or at just before a non-text node. This method checks for that.
isStreamer(const PositionIterator & pos)437 static bool isStreamer(const PositionIterator& pos)
438 {
439 if (!pos.node())
440 return true;
441
442 if (isAtomicNode(pos.node()))
443 return true;
444
445 return pos.atStartOfNode();
446 }
447
448 // This function and downstream() are used for moving back and forth between visually equivalent candidates.
449 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
450 // that map to the VisiblePosition between 'b' and the space. This function will return the left candidate
451 // and downstream() will return the right one.
452 // Also, upstream() will return [boundary, 0] for any of the positions from [boundary, 0] to the first candidate
453 // in boundary, where endsOfNodeAreVisuallyDistinctPositions(boundary) is true.
upstream() const454 Position Position::upstream() const
455 {
456 Node* startNode = node();
457 if (!startNode)
458 return Position();
459
460 // iterate backward from there, looking for a qualified position
461 Node* boundary = enclosingVisualBoundary(startNode);
462 PositionIterator lastVisible = *this;
463 PositionIterator currentPos = lastVisible;
464 bool startEditable = startNode->isContentEditable();
465 Node* lastNode = startNode;
466 for (; !currentPos.atStart(); currentPos.decrement()) {
467 Node* currentNode = currentPos.node();
468
469 // Don't check for an editability change if we haven't moved to a different node,
470 // to avoid the expense of computing isContentEditable().
471 if (currentNode != lastNode) {
472 // Don't change editability.
473 bool currentEditable = currentNode->isContentEditable();
474 if (startEditable != currentEditable)
475 break;
476 lastNode = currentNode;
477 }
478
479 // If we've moved to a position that is visually disinct, return the last saved position. There
480 // is code below that terminates early if we're *about* to move to a visually distinct position.
481 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
482 return lastVisible;
483
484 // skip position in unrendered or invisible node
485 RenderObject* renderer = currentNode->renderer();
486 if (!renderer || renderer->style()->visibility() != VISIBLE)
487 continue;
488
489 // track last visible streamer position
490 if (isStreamer(currentPos))
491 lastVisible = currentPos;
492
493 // Don't move past a position that is visually distinct. We could rely on code above to terminate and
494 // return lastVisible on the next iteration, but we terminate early to avoid doing a nodeIndex() call.
495 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentPos.atStartOfNode())
496 return lastVisible;
497
498 // Return position after tables and nodes which have content that can be ignored.
499 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
500 if (currentPos.atEndOfNode())
501 return lastDeepEditingPositionForNode(currentNode);
502 continue;
503 }
504
505 // return current position if it is in rendered text
506 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
507 if (currentNode != startNode) {
508 // This assertion fires in layout tests in the case-transform.html test because
509 // of a mix-up between offsets in the text in the DOM tree with text in the
510 // render tree which can have a different length due to case transformation.
511 // Until we resolve that, disable this so we can run the layout tests!
512 //ASSERT(currentOffset >= renderer->caretMaxOffset());
513 return Position(currentNode, renderer->caretMaxOffset());
514 }
515
516 unsigned textOffset = currentPos.offsetInLeafNode();
517 RenderText* textRenderer = toRenderText(renderer);
518 InlineTextBox* lastTextBox = textRenderer->lastTextBox();
519 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
520 if (textOffset <= box->start() + box->len()) {
521 if (textOffset > box->start())
522 return currentPos;
523 continue;
524 }
525
526 if (box == lastTextBox || textOffset != box->start() + box->len() + 1)
527 continue;
528
529 // The text continues on the next line only if the last text box is not on this line and
530 // none of the boxes on this line have a larger start offset.
531
532 bool continuesOnNextLine = true;
533 InlineBox* otherBox = box;
534 while (continuesOnNextLine) {
535 otherBox = otherBox->nextLeafChild();
536 if (!otherBox)
537 break;
538 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
539 continuesOnNextLine = false;
540 }
541
542 otherBox = box;
543 while (continuesOnNextLine) {
544 otherBox = otherBox->prevLeafChild();
545 if (!otherBox)
546 break;
547 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() > textOffset))
548 continuesOnNextLine = false;
549 }
550
551 if (continuesOnNextLine)
552 return currentPos;
553 }
554 }
555 }
556
557 return lastVisible;
558 }
559
560 // This function and upstream() are used for moving back and forth between visually equivalent candidates.
561 // For example, for the text node "foo bar" where whitespace is collapsible, there are two candidates
562 // that map to the VisiblePosition between 'b' and the space. This function will return the right candidate
563 // and upstream() will return the left one.
564 // Also, downstream() will return the last position in the last atomic node in boundary for all of the positions
565 // in boundary after the last candidate, where endsOfNodeAreVisuallyDistinctPositions(boundary).
downstream() const566 Position Position::downstream() const
567 {
568 Node* startNode = node();
569 if (!startNode)
570 return Position();
571
572 // iterate forward from there, looking for a qualified position
573 Node* boundary = enclosingVisualBoundary(startNode);
574 PositionIterator lastVisible = *this;
575 PositionIterator currentPos = lastVisible;
576 bool startEditable = startNode->isContentEditable();
577 Node* lastNode = startNode;
578 for (; !currentPos.atEnd(); currentPos.increment()) {
579 Node* currentNode = currentPos.node();
580
581 // Don't check for an editability change if we haven't moved to a different node,
582 // to avoid the expense of computing isContentEditable().
583 if (currentNode != lastNode) {
584 // Don't change editability.
585 bool currentEditable = currentNode->isContentEditable();
586 if (startEditable != currentEditable)
587 break;
588 lastNode = currentNode;
589 }
590
591 // stop before going above the body, up into the head
592 // return the last visible streamer position
593 if (currentNode->hasTagName(bodyTag) && currentPos.atEndOfNode())
594 break;
595
596 // Do not move to a visually distinct position.
597 if (endsOfNodeAreVisuallyDistinctPositions(currentNode) && currentNode != boundary)
598 return lastVisible;
599 // Do not move past a visually disinct position.
600 // Note: The first position after the last in a node whose ends are visually distinct
601 // positions will be [boundary->parentNode(), originalBlock->nodeIndex() + 1].
602 if (boundary && boundary->parentNode() == currentNode)
603 return lastVisible;
604
605 // skip position in unrendered or invisible node
606 RenderObject* renderer = currentNode->renderer();
607 if (!renderer || renderer->style()->visibility() != VISIBLE)
608 continue;
609
610 // track last visible streamer position
611 if (isStreamer(currentPos))
612 lastVisible = currentPos;
613
614 // Return position before tables and nodes which have content that can be ignored.
615 if (editingIgnoresContent(currentNode) || isTableElement(currentNode)) {
616 if (currentPos.offsetInLeafNode() <= renderer->caretMinOffset())
617 return Position(currentNode, renderer->caretMinOffset());
618 continue;
619 }
620
621 // return current position if it is in rendered text
622 if (renderer->isText() && toRenderText(renderer)->firstTextBox()) {
623 if (currentNode != startNode) {
624 ASSERT(currentPos.atStartOfNode());
625 return Position(currentNode, renderer->caretMinOffset());
626 }
627
628 unsigned textOffset = currentPos.offsetInLeafNode();
629 RenderText* textRenderer = toRenderText(renderer);
630 InlineTextBox* lastTextBox = textRenderer->lastTextBox();
631 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
632 if (textOffset <= box->end()) {
633 if (textOffset >= box->start())
634 return currentPos;
635 continue;
636 }
637
638 if (box == lastTextBox || textOffset != box->start() + box->len())
639 continue;
640
641 // The text continues on the next line only if the last text box is not on this line and
642 // none of the boxes on this line have a larger start offset.
643
644 bool continuesOnNextLine = true;
645 InlineBox* otherBox = box;
646 while (continuesOnNextLine) {
647 otherBox = otherBox->nextLeafChild();
648 if (!otherBox)
649 break;
650 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
651 continuesOnNextLine = false;
652 }
653
654 otherBox = box;
655 while (continuesOnNextLine) {
656 otherBox = otherBox->prevLeafChild();
657 if (!otherBox)
658 break;
659 if (otherBox == lastTextBox || (otherBox->renderer() == textRenderer && static_cast<InlineTextBox*>(otherBox)->start() >= textOffset))
660 continuesOnNextLine = false;
661 }
662
663 if (continuesOnNextLine)
664 return currentPos;
665 }
666 }
667 }
668
669 return lastVisible;
670 }
671
hasRenderedNonAnonymousDescendantsWithHeight(RenderObject * renderer)672 bool Position::hasRenderedNonAnonymousDescendantsWithHeight(RenderObject* renderer)
673 {
674 RenderObject* stop = renderer->nextInPreOrderAfterChildren();
675 for (RenderObject *o = renderer->firstChild(); o && o != stop; o = o->nextInPreOrder())
676 if (o->node()) {
677 if ((o->isText() && toRenderText(o)->linesBoundingBox().height()) ||
678 (o->isBox() && toRenderBox(o)->borderBoundingBox().height()))
679 return true;
680 }
681 return false;
682 }
683
nodeIsUserSelectNone(Node * node)684 bool Position::nodeIsUserSelectNone(Node* node)
685 {
686 return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE;
687 }
688
isCandidate() const689 bool Position::isCandidate() const
690 {
691 if (isNull())
692 return false;
693
694 RenderObject *renderer = node()->renderer();
695 if (!renderer)
696 return false;
697
698 if (renderer->style()->visibility() != VISIBLE)
699 return false;
700
701 if (renderer->isBR())
702 return m_offset == 0 && !nodeIsUserSelectNone(node()->parent());
703
704 if (renderer->isText())
705 return inRenderedText() && !nodeIsUserSelectNone(node());
706
707 if (isTableElement(node()) || editingIgnoresContent(node()))
708 return (atFirstEditingPositionForNode() || atLastEditingPositionForNode()) && !nodeIsUserSelectNone(node()->parent());
709
710 if (!node()->hasTagName(htmlTag) && renderer->isBlockFlow() && !hasRenderedNonAnonymousDescendantsWithHeight(renderer) &&
711 (toRenderBox(renderer)->height() || node()->hasTagName(bodyTag)))
712 return atFirstEditingPositionForNode() && !nodeIsUserSelectNone(node());
713
714 return false;
715 }
716
inRenderedText() const717 bool Position::inRenderedText() const
718 {
719 if (isNull() || !node()->isTextNode())
720 return false;
721
722 RenderObject *renderer = node()->renderer();
723 if (!renderer)
724 return false;
725
726 RenderText *textRenderer = toRenderText(renderer);
727 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
728 if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
729 // The offset we're looking for is before this node
730 // this means the offset must be in content that is
731 // not rendered. Return false.
732 return false;
733 }
734 if (box->containsCaretOffset(m_offset))
735 // Return false for offsets inside composed characters.
736 return m_offset == 0 || m_offset == textRenderer->nextOffset(textRenderer->previousOffset(m_offset));
737 }
738
739 return false;
740 }
741
caretMaxRenderedOffset(const Node * n)742 static unsigned caretMaxRenderedOffset(const Node* n)
743 {
744 RenderObject* r = n->renderer();
745 if (r)
746 return r->caretMaxRenderedOffset();
747
748 if (n->isCharacterDataNode())
749 return static_cast<const CharacterData*>(n)->length();
750 return 1;
751 }
752
isRenderedCharacter() const753 bool Position::isRenderedCharacter() const
754 {
755 if (isNull() || !node()->isTextNode())
756 return false;
757
758 RenderObject* renderer = node()->renderer();
759 if (!renderer)
760 return false;
761
762 RenderText* textRenderer = toRenderText(renderer);
763 for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
764 if (m_offset < static_cast<int>(box->start()) && !textRenderer->containsReversedText()) {
765 // The offset we're looking for is before this node
766 // this means the offset must be in content that is
767 // not rendered. Return false.
768 return false;
769 }
770 if (m_offset >= static_cast<int>(box->start()) && m_offset < static_cast<int>(box->start() + box->len()))
771 return true;
772 }
773
774 return false;
775 }
776
rendersInDifferentPosition(const Position & pos) const777 bool Position::rendersInDifferentPosition(const Position &pos) const
778 {
779 if (isNull() || pos.isNull())
780 return false;
781
782 RenderObject *renderer = node()->renderer();
783 if (!renderer)
784 return false;
785
786 RenderObject *posRenderer = pos.node()->renderer();
787 if (!posRenderer)
788 return false;
789
790 if (renderer->style()->visibility() != VISIBLE ||
791 posRenderer->style()->visibility() != VISIBLE)
792 return false;
793
794 if (node() == pos.node()) {
795 if (node()->hasTagName(brTag))
796 return false;
797
798 if (m_offset == pos.deprecatedEditingOffset())
799 return false;
800
801 if (!node()->isTextNode() && !pos.node()->isTextNode()) {
802 if (m_offset != pos.deprecatedEditingOffset())
803 return true;
804 }
805 }
806
807 if (node()->hasTagName(brTag) && pos.isCandidate())
808 return true;
809
810 if (pos.node()->hasTagName(brTag) && isCandidate())
811 return true;
812
813 if (node()->enclosingBlockFlowElement() != pos.node()->enclosingBlockFlowElement())
814 return true;
815
816 if (node()->isTextNode() && !inRenderedText())
817 return false;
818
819 if (pos.node()->isTextNode() && !pos.inRenderedText())
820 return false;
821
822 int thisRenderedOffset = renderedOffset();
823 int posRenderedOffset = pos.renderedOffset();
824
825 if (renderer == posRenderer && thisRenderedOffset == posRenderedOffset)
826 return false;
827
828 int ignoredCaretOffset;
829 InlineBox* b1;
830 getInlineBoxAndOffset(DOWNSTREAM, b1, ignoredCaretOffset);
831 InlineBox* b2;
832 pos.getInlineBoxAndOffset(DOWNSTREAM, b2, ignoredCaretOffset);
833
834 LOG(Editing, "renderer: %p [%p]\n", renderer, b1);
835 LOG(Editing, "thisRenderedOffset: %d\n", thisRenderedOffset);
836 LOG(Editing, "posRenderer: %p [%p]\n", posRenderer, b2);
837 LOG(Editing, "posRenderedOffset: %d\n", posRenderedOffset);
838 LOG(Editing, "node min/max: %d:%d\n", caretMinOffset(node()), caretMaxRenderedOffset(node()));
839 LOG(Editing, "pos node min/max: %d:%d\n", caretMinOffset(pos.node()), caretMaxRenderedOffset(pos.node()));
840 LOG(Editing, "----------------------------------------------------------------------\n");
841
842 if (!b1 || !b2) {
843 return false;
844 }
845
846 if (b1->root() != b2->root()) {
847 return true;
848 }
849
850 if (nextRenderedEditable(node()) == pos.node() &&
851 thisRenderedOffset == (int)caretMaxRenderedOffset(node()) && posRenderedOffset == 0) {
852 return false;
853 }
854
855 if (previousRenderedEditable(node()) == pos.node() &&
856 thisRenderedOffset == 0 && posRenderedOffset == (int)caretMaxRenderedOffset(pos.node())) {
857 return false;
858 }
859
860 return true;
861 }
862
863 // This assumes that it starts in editable content.
leadingWhitespacePosition(EAffinity affinity,bool considerNonCollapsibleWhitespace) const864 Position Position::leadingWhitespacePosition(EAffinity affinity, bool considerNonCollapsibleWhitespace) const
865 {
866 ASSERT(isEditablePosition(*this));
867 if (isNull())
868 return Position();
869
870 if (upstream().node()->hasTagName(brTag))
871 return Position();
872
873 Position prev = previousCharacterPosition(affinity);
874 if (prev != *this && prev.node()->inSameContainingBlockFlowElement(node()) && prev.node()->isTextNode()) {
875 String string = static_cast<Text *>(prev.node())->data();
876 UChar c = string[prev.deprecatedEditingOffset()];
877 if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
878 if (isEditablePosition(prev))
879 return prev;
880 }
881
882 return Position();
883 }
884
885 // This assumes that it starts in editable content.
trailingWhitespacePosition(EAffinity,bool considerNonCollapsibleWhitespace) const886 Position Position::trailingWhitespacePosition(EAffinity, bool considerNonCollapsibleWhitespace) const
887 {
888 ASSERT(isEditablePosition(*this));
889 if (isNull())
890 return Position();
891
892 VisiblePosition v(*this);
893 UChar c = v.characterAfter();
894 // The space must not be in another paragraph and it must be editable.
895 if (!isEndOfParagraph(v) && v.next(true).isNotNull())
896 if (considerNonCollapsibleWhitespace ? (isSpaceOrNewline(c) || c == noBreakSpace) : isCollapsibleWhitespace(c))
897 return *this;
898
899 return Position();
900 }
901
getInlineBoxAndOffset(EAffinity affinity,InlineBox * & inlineBox,int & caretOffset) const902 void Position::getInlineBoxAndOffset(EAffinity affinity, InlineBox*& inlineBox, int& caretOffset) const
903 {
904 TextDirection primaryDirection = LTR;
905 for (RenderObject* r = node()->renderer(); r; r = r->parent()) {
906 if (r->isBlockFlow()) {
907 primaryDirection = r->style()->direction();
908 break;
909 }
910 }
911 getInlineBoxAndOffset(affinity, primaryDirection, inlineBox, caretOffset);
912 }
913
isNonTextLeafChild(RenderObject * object)914 static bool isNonTextLeafChild(RenderObject* object)
915 {
916 if (object->firstChild())
917 return false;
918 if (object->isText())
919 return false;
920 return true;
921 }
922
searchAheadForBetterMatch(RenderObject * renderer)923 static InlineTextBox* searchAheadForBetterMatch(RenderObject* renderer)
924 {
925 RenderBlock* container = renderer->containingBlock();
926 RenderObject* next = renderer;
927 while ((next = next->nextInPreOrder(container))) {
928 if (next->isRenderBlock())
929 return 0;
930 if (next->isBR())
931 return 0;
932 if (isNonTextLeafChild(next))
933 return 0;
934 if (next->isText()) {
935 InlineTextBox* match = 0;
936 int minOffset = INT_MAX;
937 for (InlineTextBox* box = toRenderText(next)->firstTextBox(); box; box = box->nextTextBox()) {
938 int caretMinOffset = box->caretMinOffset();
939 if (caretMinOffset < minOffset) {
940 match = box;
941 minOffset = caretMinOffset;
942 }
943 }
944 if (match)
945 return match;
946 }
947 }
948 return 0;
949 }
950
getInlineBoxAndOffset(EAffinity affinity,TextDirection primaryDirection,InlineBox * & inlineBox,int & caretOffset) const951 void Position::getInlineBoxAndOffset(EAffinity affinity, TextDirection primaryDirection, InlineBox*& inlineBox, int& caretOffset) const
952 {
953 caretOffset = m_offset;
954 RenderObject* renderer = node()->renderer();
955 if (!renderer->isText()) {
956 inlineBox = renderer->isBox() ? toRenderBox(renderer)->inlineBoxWrapper() : 0;
957 if (!inlineBox || (caretOffset > inlineBox->caretMinOffset() && caretOffset < inlineBox->caretMaxOffset()))
958 return;
959 } else {
960 RenderText* textRenderer = toRenderText(renderer);
961
962 InlineTextBox* box;
963 InlineTextBox* candidate = 0;
964
965 for (box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
966 int caretMinOffset = box->caretMinOffset();
967 int caretMaxOffset = box->caretMaxOffset();
968
969 if (caretOffset < caretMinOffset || caretOffset > caretMaxOffset || (caretOffset == caretMaxOffset && box->isLineBreak()))
970 continue;
971
972 if (caretOffset > caretMinOffset && caretOffset < caretMaxOffset) {
973 inlineBox = box;
974 return;
975 }
976
977 if ((caretOffset == caretMinOffset) ^ (affinity == UPSTREAM))
978 break;
979
980 candidate = box;
981 }
982 if (candidate && !box && affinity == DOWNSTREAM) {
983 box = searchAheadForBetterMatch(textRenderer);
984 if (box)
985 caretOffset = box->caretMinOffset();
986 }
987 inlineBox = box ? box : candidate;
988 }
989
990 if (!inlineBox)
991 return;
992
993 unsigned char level = inlineBox->bidiLevel();
994
995 if (inlineBox->direction() == primaryDirection) {
996 if (caretOffset == inlineBox->caretRightmostOffset()) {
997 InlineBox* nextBox = inlineBox->nextLeafChild();
998 if (!nextBox || nextBox->bidiLevel() >= level)
999 return;
1000
1001 level = nextBox->bidiLevel();
1002 InlineBox* prevBox = inlineBox;
1003 do {
1004 prevBox = prevBox->prevLeafChild();
1005 } while (prevBox && prevBox->bidiLevel() > level);
1006
1007 if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
1008 return;
1009
1010 // For example, abc 123 ^ CBA
1011 while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1012 if (nextBox->bidiLevel() < level)
1013 break;
1014 inlineBox = nextBox;
1015 }
1016 caretOffset = inlineBox->caretRightmostOffset();
1017 } else {
1018 InlineBox* prevBox = inlineBox->prevLeafChild();
1019 if (!prevBox || prevBox->bidiLevel() >= level)
1020 return;
1021
1022 level = prevBox->bidiLevel();
1023 InlineBox* nextBox = inlineBox;
1024 do {
1025 nextBox = nextBox->nextLeafChild();
1026 } while (nextBox && nextBox->bidiLevel() > level);
1027
1028 if (nextBox && nextBox->bidiLevel() == level)
1029 return;
1030
1031 while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1032 if (prevBox->bidiLevel() < level)
1033 break;
1034 inlineBox = prevBox;
1035 }
1036 caretOffset = inlineBox->caretLeftmostOffset();
1037 }
1038 return;
1039 }
1040
1041 if (caretOffset == inlineBox->caretLeftmostOffset()) {
1042 InlineBox* prevBox = inlineBox->prevLeafChild();
1043 if (!prevBox || prevBox->bidiLevel() < level) {
1044 // Left edge of a secondary run. Set to the right edge of the entire run.
1045 while (InlineBox* nextBox = inlineBox->nextLeafChild()) {
1046 if (nextBox->bidiLevel() < level)
1047 break;
1048 inlineBox = nextBox;
1049 }
1050 caretOffset = inlineBox->caretRightmostOffset();
1051 } else if (prevBox->bidiLevel() > level) {
1052 // Right edge of a "tertiary" run. Set to the left edge of that run.
1053 while (InlineBox* tertiaryBox = inlineBox->prevLeafChild()) {
1054 if (tertiaryBox->bidiLevel() <= level)
1055 break;
1056 inlineBox = tertiaryBox;
1057 }
1058 caretOffset = inlineBox->caretLeftmostOffset();
1059 }
1060 } else {
1061 InlineBox* nextBox = inlineBox->nextLeafChild();
1062 if (!nextBox || nextBox->bidiLevel() < level) {
1063 // Right edge of a secondary run. Set to the left edge of the entire run.
1064 while (InlineBox* prevBox = inlineBox->prevLeafChild()) {
1065 if (prevBox->bidiLevel() < level)
1066 break;
1067 inlineBox = prevBox;
1068 }
1069 caretOffset = inlineBox->caretLeftmostOffset();
1070 } else if (nextBox->bidiLevel() > level) {
1071 // Left edge of a "tertiary" run. Set to the right edge of that run.
1072 while (InlineBox* tertiaryBox = inlineBox->nextLeafChild()) {
1073 if (tertiaryBox->bidiLevel() <= level)
1074 break;
1075 inlineBox = tertiaryBox;
1076 }
1077 caretOffset = inlineBox->caretRightmostOffset();
1078 }
1079 }
1080 }
1081
debugPosition(const char * msg) const1082 void Position::debugPosition(const char* msg) const
1083 {
1084 if (isNull())
1085 fprintf(stderr, "Position [%s]: null\n", msg);
1086 else
1087 fprintf(stderr, "Position [%s]: %s [%p] at %d\n", msg, node()->nodeName().utf8().data(), node(), m_offset);
1088 }
1089
1090 #ifndef NDEBUG
1091
formatForDebugger(char * buffer,unsigned length) const1092 void Position::formatForDebugger(char* buffer, unsigned length) const
1093 {
1094 String result;
1095
1096 if (isNull())
1097 result = "<null>";
1098 else {
1099 char s[1024];
1100 result += "offset ";
1101 result += String::number(m_offset);
1102 result += " of ";
1103 node()->formatForDebugger(s, sizeof(s));
1104 result += s;
1105 }
1106
1107 strncpy(buffer, result.utf8().data(), length - 1);
1108 }
1109
showTreeForThis() const1110 void Position::showTreeForThis() const
1111 {
1112 if (node())
1113 node()->showTreeForThis();
1114 }
1115
1116 #endif
1117
startPosition(const Range * r)1118 Position startPosition(const Range* r)
1119 {
1120 return r ? r->startPosition() : Position();
1121 }
1122
endPosition(const Range * r)1123 Position endPosition(const Range* r)
1124 {
1125 return r ? r->endPosition() : Position();
1126 }
1127
1128 // NOTE: first/lastDeepEditingPositionForNode can return "editing positions" (like [img, 0])
1129 // for elements which editing "ignores". the rest of the editing code will treat [img, 0]
1130 // as "the last position before the img"
firstDeepEditingPositionForNode(Node * node)1131 Position firstDeepEditingPositionForNode(Node* node)
1132 {
1133 return Position(node, 0);
1134 }
1135
lastDeepEditingPositionForNode(Node * node)1136 Position lastDeepEditingPositionForNode(Node* node)
1137 {
1138 return Position(node, lastOffsetForEditing(node));
1139 }
1140
1141 } // namespace WebCore
1142
1143 #ifndef NDEBUG
1144
showTree(const WebCore::Position & pos)1145 void showTree(const WebCore::Position& pos)
1146 {
1147 pos.showTreeForThis();
1148 }
1149
showTree(const WebCore::Position * pos)1150 void showTree(const WebCore::Position* pos)
1151 {
1152 if (pos)
1153 pos->showTreeForThis();
1154 }
1155
1156 #endif
1157