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 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 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 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 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 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 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 } 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 118 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 134 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 151 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 168 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 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 196 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 204 PassRefPtr<CSSComputedStyleDeclaration> Position::computedStyle() const 205 { 206 Element* elem = element(); 207 if (!elem) 208 return 0; 209 return WebCore::computedStyle(elem); 210 } 211 212 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 249 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 281 int Position::uncheckedPreviousOffset(const Node* n, int current) 282 { 283 return n->renderer() ? n->renderer()->previousOffset(current) : current - 1; 284 } 285 286 int Position::uncheckedPreviousOffsetForBackwardDeletion(const Node* n, int current) 287 { 288 return n->renderer() ? n->renderer()->previousOffsetForBackwardDeletion(current) : current - 1; 289 } 290 291 int Position::uncheckedNextOffset(const Node* n, int current) 292 { 293 return n->renderer() ? n->renderer()->nextOffset(current) : current + 1; 294 } 295 296 bool Position::atFirstEditingPositionForNode() const 297 { 298 if (isNull()) 299 return true; 300 return m_offset <= 0; 301 } 302 303 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. 317 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 331 bool Position::atStartOfTree() const 332 { 333 if (isNull()) 334 return true; 335 return !node()->parentNode() && m_offset <= 0; 336 } 337 338 bool Position::atEndOfTree() const 339 { 340 if (isNull()) 341 return true; 342 return !node()->parentNode() && m_offset >= lastOffsetForEditing(node()); 343 } 344 345 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" 370 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" 398 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. 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 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. 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. 472 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). 593 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 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 721 bool Position::nodeIsUserSelectNone(Node* node) 722 { 723 return node && node->renderer() && node->renderer()->style()->userSelect() == SELECT_NONE; 724 } 725 726 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 762 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 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 798 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 822 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. 909 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. 931 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 947 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 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 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 996 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 1149 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 1159 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 1177 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 1193 void showTree(const WebCore::Position& pos) 1194 { 1195 pos.showTreeForThis(); 1196 } 1197 1198 void showTree(const WebCore::Position* pos) 1199 { 1200 if (pos) 1201 pos->showTreeForThis(); 1202 } 1203 1204 #endif 1205