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