1 /* 2 * Copyright (C) 2004, 2005, 2006, 2007 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 "htmlediting.h" 28 29 #include "Document.h" 30 #include "EditingText.h" 31 #include "HTMLBRElement.h" 32 #include "HTMLDivElement.h" 33 #include "HTMLElementFactory.h" 34 #include "HTMLInterchange.h" 35 #include "HTMLLIElement.h" 36 #include "HTMLNames.h" 37 #include "HTMLObjectElement.h" 38 #include "HTMLOListElement.h" 39 #include "HTMLUListElement.h" 40 #include "PositionIterator.h" 41 #include "RenderObject.h" 42 #include "Range.h" 43 #include "VisibleSelection.h" 44 #include "Text.h" 45 #include "TextIterator.h" 46 #include "VisiblePosition.h" 47 #include "visible_units.h" 48 #include <wtf/StdLibExtras.h> 49 #include <wtf/unicode/CharacterNames.h> 50 51 #if ENABLE(WML) 52 #include "WMLNames.h" 53 #endif 54 55 using namespace std; 56 57 namespace WebCore { 58 59 using namespace HTMLNames; 60 61 // Atomic means that the node has no children, or has children which are ignored for the 62 // purposes of editing. 63 bool isAtomicNode(const Node *node) 64 { 65 return node && (!node->hasChildNodes() || editingIgnoresContent(node)); 66 } 67 68 // Returns true for nodes that either have no content, or have content that is ignored (skipped 69 // over) while editing. There are no VisiblePositions inside these nodes. 70 bool editingIgnoresContent(const Node* node) 71 { 72 return !canHaveChildrenForEditing(node) && !node->isTextNode(); 73 } 74 75 bool canHaveChildrenForEditing(const Node* node) 76 { 77 return !node->isTextNode() 78 && !node->hasTagName(brTag) 79 && !node->hasTagName(imgTag) 80 && !node->hasTagName(inputTag) 81 && !node->hasTagName(textareaTag) 82 && (!node->hasTagName(objectTag) || static_cast<const HTMLObjectElement*>(node)->useFallbackContent()) 83 && !node->hasTagName(iframeTag) 84 && !node->hasTagName(embedTag) 85 && !node->hasTagName(appletTag) 86 && !node->hasTagName(selectTag) 87 #if ENABLE(WML) 88 && !node->hasTagName(WMLNames::doTag) 89 #endif 90 && ((!node->hasTagName(hrTag) && !node->hasTagName(datagridTag)) || node->hasChildNodes()); 91 } 92 93 // Compare two positions, taking into account the possibility that one or both 94 // could be inside a shadow tree. Only works for non-null values. 95 int comparePositions(const Position& a, const Position& b) 96 { 97 Node* nodeA = a.deprecatedNode(); 98 ASSERT(nodeA); 99 Node* nodeB = b.deprecatedNode(); 100 ASSERT(nodeB); 101 int offsetA = a.deprecatedEditingOffset(); 102 int offsetB = b.deprecatedEditingOffset(); 103 104 Node* shadowAncestorA = nodeA->shadowAncestorNode(); 105 if (shadowAncestorA == nodeA) 106 shadowAncestorA = 0; 107 Node* shadowAncestorB = nodeB->shadowAncestorNode(); 108 if (shadowAncestorB == nodeB) 109 shadowAncestorB = 0; 110 111 int bias = 0; 112 if (shadowAncestorA != shadowAncestorB) { 113 if (shadowAncestorA) { 114 nodeA = shadowAncestorA; 115 offsetA = 0; 116 bias = 1; 117 } 118 if (shadowAncestorB) { 119 nodeB = shadowAncestorB; 120 offsetB = 0; 121 bias = -1; 122 } 123 } 124 125 ExceptionCode ec; 126 int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB, ec); 127 return result ? result : bias; 128 } 129 130 int comparePositions(const VisiblePosition& a, const VisiblePosition& b) 131 { 132 return comparePositions(a.deepEquivalent(), b.deepEquivalent()); 133 } 134 135 Node* highestEditableRoot(const Position& position) 136 { 137 Node* node = position.deprecatedNode(); 138 if (!node) 139 return 0; 140 141 Node* highestRoot = editableRootForPosition(position); 142 if (!highestRoot) 143 return 0; 144 145 node = highestRoot; 146 while (node) { 147 if (node->rendererIsEditable()) 148 highestRoot = node; 149 if (node->hasTagName(bodyTag)) 150 break; 151 node = node->parentNode(); 152 } 153 154 return highestRoot; 155 } 156 157 Node* lowestEditableAncestor(Node* node) 158 { 159 if (!node) 160 return 0; 161 162 Node *lowestRoot = 0; 163 while (node) { 164 if (node->rendererIsEditable()) 165 return node->rootEditableElement(); 166 if (node->hasTagName(bodyTag)) 167 break; 168 node = node->parentNode(); 169 } 170 171 return lowestRoot; 172 } 173 174 bool isEditablePosition(const Position& p) 175 { 176 Node* node = p.deprecatedNode(); 177 if (!node) 178 return false; 179 180 if (node->renderer() && node->renderer()->isTable()) 181 node = node->parentNode(); 182 183 return node->rendererIsEditable(); 184 } 185 186 bool isAtUnsplittableElement(const Position& pos) 187 { 188 Node* node = pos.deprecatedNode(); 189 return (node == editableRootForPosition(pos) || node == enclosingNodeOfType(pos, &isTableCell)); 190 } 191 192 193 bool isRichlyEditablePosition(const Position& p) 194 { 195 Node* node = p.deprecatedNode(); 196 if (!node) 197 return false; 198 199 if (node->renderer() && node->renderer()->isTable()) 200 node = node->parentNode(); 201 202 return node->rendererIsRichlyEditable(); 203 } 204 205 Element* editableRootForPosition(const Position& p) 206 { 207 Node* node = p.deprecatedNode(); 208 if (!node) 209 return 0; 210 211 if (node->renderer() && node->renderer()->isTable()) 212 node = node->parentNode(); 213 214 return node->rootEditableElement(); 215 } 216 217 // Finds the enclosing element until which the tree can be split. 218 // When a user hits ENTER, he/she won't expect this element to be split into two. 219 // You may pass it as the second argument of splitTreeToNode. 220 Element* unsplittableElementForPosition(const Position& p) 221 { 222 // Since enclosingNodeOfType won't search beyond the highest root editable node, 223 // this code works even if the closest table cell was outside of the root editable node. 224 Element* enclosingCell = static_cast<Element*>(enclosingNodeOfType(p, &isTableCell)); 225 if (enclosingCell) 226 return enclosingCell; 227 228 return editableRootForPosition(p); 229 } 230 231 Position nextCandidate(const Position& position) 232 { 233 PositionIterator p = position; 234 while (!p.atEnd()) { 235 p.increment(); 236 if (p.isCandidate()) 237 return p; 238 } 239 return Position(); 240 } 241 242 Position nextVisuallyDistinctCandidate(const Position& position) 243 { 244 Position p = position; 245 Position downstreamStart = p.downstream(); 246 while (!p.atEndOfTree()) { 247 p = p.next(Character); 248 if (p.isCandidate() && p.downstream() != downstreamStart) 249 return p; 250 } 251 return Position(); 252 } 253 254 Position previousCandidate(const Position& position) 255 { 256 PositionIterator p = position; 257 while (!p.atStart()) { 258 p.decrement(); 259 if (p.isCandidate()) 260 return p; 261 } 262 return Position(); 263 } 264 265 Position previousVisuallyDistinctCandidate(const Position& position) 266 { 267 Position p = position; 268 Position downstreamStart = p.downstream(); 269 while (!p.atStartOfTree()) { 270 p = p.previous(Character); 271 if (p.isCandidate() && p.downstream() != downstreamStart) 272 return p; 273 } 274 return Position(); 275 } 276 277 VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, Node* highestRoot) 278 { 279 // position falls before highestRoot. 280 if (comparePositions(position, firstPositionInNode(highestRoot)) == -1 && highestRoot->rendererIsEditable()) 281 return firstPositionInNode(highestRoot); 282 283 Position p = position; 284 285 if (Node* shadowAncestor = p.deprecatedNode()->shadowAncestorNode()) 286 if (shadowAncestor != p.deprecatedNode()) 287 p = positionAfterNode(shadowAncestor); 288 289 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot)) 290 p = isAtomicNode(p.deprecatedNode()) ? positionInParentAfterNode(p.deprecatedNode()) : nextVisuallyDistinctCandidate(p); 291 292 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecatedNode()->isDescendantOf(highestRoot)) 293 return VisiblePosition(); 294 295 return VisiblePosition(p); 296 } 297 298 VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, Node* highestRoot) 299 { 300 // When position falls after highestRoot, the result is easy to compute. 301 if (comparePositions(position, lastPositionInNode(highestRoot)) == 1) 302 return lastPositionInNode(highestRoot); 303 304 Position p = position; 305 306 if (Node* shadowAncestor = p.deprecatedNode()->shadowAncestorNode()) { 307 if (shadowAncestor != p.deprecatedNode()) 308 p = firstPositionInOrBeforeNode(shadowAncestor); 309 } 310 311 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot)) 312 p = isAtomicNode(p.deprecatedNode()) ? positionInParentBeforeNode(p.deprecatedNode()) : previousVisuallyDistinctCandidate(p); 313 314 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecatedNode()->isDescendantOf(highestRoot)) 315 return VisiblePosition(); 316 317 return VisiblePosition(p); 318 } 319 320 // FIXME: The method name, comment, and code say three different things here! 321 // Whether or not content before and after this node will collapse onto the same line as it. 322 bool isBlock(const Node* node) 323 { 324 return node && node->renderer() && !node->renderer()->isInline(); 325 } 326 327 // FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlockFlowOrTableElement are used. 328 // FIXME: Pass a position to this function. The enclosing block of [table, x] for example, should be the 329 // block that contains the table and not the table, and this function should be the only one responsible for 330 // knowing about these kinds of special cases. 331 Node* enclosingBlock(Node* node, EditingBoundaryCrossingRule rule) 332 { 333 return static_cast<Element*>(enclosingNodeOfType(firstPositionInOrBeforeNode(node), isBlock, rule)); 334 } 335 336 TextDirection directionOfEnclosingBlock(const Position& position) 337 { 338 Node* enclosingBlockNode = enclosingBlock(position.containerNode()); 339 if (!enclosingBlockNode) 340 return LTR; 341 RenderObject* renderer = enclosingBlockNode->renderer(); 342 return renderer ? renderer->style()->direction() : LTR; 343 } 344 345 // This method is used to create positions in the DOM. It returns the maximum valid offset 346 // in a node. It returns 1 for some elements even though they do not have children, which 347 // creates technically invalid DOM Positions. Be sure to call parentAnchoredEquivalent 348 // on a Position before using it to create a DOM Range, or an exception will be thrown. 349 int lastOffsetForEditing(const Node* node) 350 { 351 ASSERT(node); 352 if (!node) 353 return 0; 354 if (node->offsetInCharacters()) 355 return node->maxCharacterOffset(); 356 357 if (node->hasChildNodes()) 358 return node->childNodeCount(); 359 360 // NOTE: This should preempt the childNodeCount for, e.g., select nodes 361 if (editingIgnoresContent(node)) 362 return 1; 363 364 return 0; 365 } 366 367 String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph) 368 { 369 Vector<UChar> rebalancedString; 370 append(rebalancedString, string); 371 372 bool previousCharacterWasSpace = false; 373 for (size_t i = 0; i < rebalancedString.size(); i++) { 374 if (!isWhitespace(rebalancedString[i])) { 375 previousCharacterWasSpace = false; 376 continue; 377 } 378 379 if (previousCharacterWasSpace || (!i && startIsStartOfParagraph) || (i + 1 == rebalancedString.size() && endIsEndOfParagraph)) { 380 rebalancedString[i] = noBreakSpace; 381 previousCharacterWasSpace = false; 382 } else { 383 rebalancedString[i] = ' '; 384 previousCharacterWasSpace = true; 385 } 386 387 } 388 389 return String::adopt(rebalancedString); 390 } 391 392 bool isTableStructureNode(const Node *node) 393 { 394 RenderObject *r = node->renderer(); 395 return (r && (r->isTableCell() || r->isTableRow() || r->isTableSection() || r->isTableCol())); 396 } 397 398 const String& nonBreakingSpaceString() 399 { 400 DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1)); 401 return nonBreakingSpaceString; 402 } 403 404 // FIXME: need to dump this 405 bool isSpecialElement(const Node *n) 406 { 407 if (!n) 408 return false; 409 410 if (!n->isHTMLElement()) 411 return false; 412 413 if (n->isLink()) 414 return true; 415 416 RenderObject *renderer = n->renderer(); 417 if (!renderer) 418 return false; 419 420 if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE) 421 return true; 422 423 if (renderer->style()->isFloating()) 424 return true; 425 426 if (renderer->style()->position() != StaticPosition) 427 return true; 428 429 return false; 430 } 431 432 static Node* firstInSpecialElement(const Position& pos) 433 { 434 // FIXME: This begins at pos.deprecatedNode(), which doesn't necessarily contain pos (suppose pos was [img, 0]). See <rdar://problem/5027702>. 435 Node* rootEditableElement = pos.deprecatedNode()->rootEditableElement(); 436 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode()) 437 if (isSpecialElement(n)) { 438 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); 439 VisiblePosition firstInElement = VisiblePosition(firstPositionInOrBeforeNode(n), DOWNSTREAM); 440 if (isTableElement(n) && vPos == firstInElement.next()) 441 return n; 442 if (vPos == firstInElement) 443 return n; 444 } 445 return 0; 446 } 447 448 static Node* lastInSpecialElement(const Position& pos) 449 { 450 // FIXME: This begins at pos.deprecatedNode(), which doesn't necessarily contain pos (suppose pos was [img, 0]). See <rdar://problem/5027702>. 451 Node* rootEditableElement = pos.deprecatedNode()->rootEditableElement(); 452 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode()) 453 if (isSpecialElement(n)) { 454 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); 455 VisiblePosition lastInElement = VisiblePosition(Position(n, n->childNodeCount(), Position::PositionIsOffsetInAnchor), DOWNSTREAM); 456 if (isTableElement(n) && vPos == lastInElement.previous()) 457 return n; 458 if (vPos == lastInElement) 459 return n; 460 } 461 return 0; 462 } 463 464 bool isFirstVisiblePositionInSpecialElement(const Position& pos) 465 { 466 return firstInSpecialElement(pos); 467 } 468 469 Position positionBeforeContainingSpecialElement(const Position& pos, Node** containingSpecialElement) 470 { 471 Node* n = firstInSpecialElement(pos); 472 if (!n) 473 return pos; 474 Position result = positionInParentBeforeNode(n); 475 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos.deprecatedNode()->rootEditableElement()) 476 return pos; 477 if (containingSpecialElement) 478 *containingSpecialElement = n; 479 return result; 480 } 481 482 bool isLastVisiblePositionInSpecialElement(const Position& pos) 483 { 484 return lastInSpecialElement(pos); 485 } 486 487 Position positionAfterContainingSpecialElement(const Position& pos, Node **containingSpecialElement) 488 { 489 Node* n = lastInSpecialElement(pos); 490 if (!n) 491 return pos; 492 Position result = positionInParentAfterNode(n); 493 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos.deprecatedNode()->rootEditableElement()) 494 return pos; 495 if (containingSpecialElement) 496 *containingSpecialElement = n; 497 return result; 498 } 499 500 Position positionOutsideContainingSpecialElement(const Position &pos, Node **containingSpecialElement) 501 { 502 if (isFirstVisiblePositionInSpecialElement(pos)) 503 return positionBeforeContainingSpecialElement(pos, containingSpecialElement); 504 if (isLastVisiblePositionInSpecialElement(pos)) 505 return positionAfterContainingSpecialElement(pos, containingSpecialElement); 506 return pos; 507 } 508 509 Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition) 510 { 511 Position upstream(visiblePosition.deepEquivalent().upstream()); 512 if (upstream.deprecatedNode() && upstream.deprecatedNode()->renderer() && upstream.deprecatedNode()->renderer()->isTable() && upstream.atLastEditingPositionForNode()) 513 return upstream.deprecatedNode(); 514 515 return 0; 516 } 517 518 Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition) 519 { 520 Position downstream(visiblePosition.deepEquivalent().downstream()); 521 if (downstream.deprecatedNode() && downstream.deprecatedNode()->renderer() && downstream.deprecatedNode()->renderer()->isTable() && downstream.atFirstEditingPositionForNode()) 522 return downstream.deprecatedNode(); 523 524 return 0; 525 } 526 527 // Returns the visible position at the beginning of a node 528 VisiblePosition visiblePositionBeforeNode(Node* node) 529 { 530 ASSERT(node); 531 if (node->childNodeCount()) 532 return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM); 533 ASSERT(node->parentNode()); 534 return positionInParentBeforeNode(node); 535 } 536 537 // Returns the visible position at the ending of a node 538 VisiblePosition visiblePositionAfterNode(Node* node) 539 { 540 ASSERT(node); 541 if (node->childNodeCount()) 542 return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM); 543 ASSERT(node->parentNode()); 544 return positionInParentAfterNode(node); 545 } 546 547 // Create a range object with two visible positions, start and end. 548 // create(PassRefPtr<Document>, const Position&, const Position&); will use deprecatedEditingOffset 549 // Use this function instead of create a regular range object (avoiding editing offset). 550 PassRefPtr<Range> createRange(PassRefPtr<Document> document, const VisiblePosition& start, const VisiblePosition& end, ExceptionCode& ec) 551 { 552 ec = 0; 553 RefPtr<Range> selectedRange = Range::create(document); 554 selectedRange->setStart(start.deepEquivalent().containerNode(), start.deepEquivalent().computeOffsetInContainerNode(), ec); 555 if (!ec) 556 selectedRange->setEnd(end.deepEquivalent().containerNode(), end.deepEquivalent().computeOffsetInContainerNode(), ec); 557 return selectedRange.release(); 558 } 559 560 // Extend rangeToExtend to include nodes that wraps range and visibly starts and ends inside or at the boudnaries of maximumRange 561 // e.g. if the original range spaned "hello" in <div>hello</div>, then this function extends the range to contain div's around it. 562 // Call this function before copying / moving paragraphs to contain all wrapping nodes. 563 // This function stops extending the range immediately below rootNode; i.e. the extended range can contain a child node of rootNode 564 // but it can never contain rootNode itself. 565 PassRefPtr<Range> extendRangeToWrappingNodes(PassRefPtr<Range> range, const Range* maximumRange, const Node* rootNode) 566 { 567 ASSERT(range); 568 ASSERT(maximumRange); 569 570 ExceptionCode ec = 0; 571 Node* ancestor = range->commonAncestorContainer(ec);// find the cloeset common ancestor 572 Node* highestNode = 0; 573 // traverse through ancestors as long as they are contained within the range, content-editable, and below rootNode (could be =0). 574 while (ancestor && ancestor->rendererIsEditable() && isNodeVisiblyContainedWithin(ancestor, maximumRange) && ancestor != rootNode) { 575 highestNode = ancestor; 576 ancestor = ancestor->parentNode(); 577 } 578 579 if (!highestNode) 580 return range; 581 582 // Create new range with the highest editable node contained within the range 583 RefPtr<Range> extendedRange = Range::create(range->ownerDocument()); 584 extendedRange->selectNode(highestNode, ec); 585 return extendedRange.release(); 586 } 587 588 bool isListElement(Node *n) 589 { 590 return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag))); 591 } 592 593 bool isListItem(Node *n) 594 { 595 return n && n->renderer() && n->renderer()->isListItem(); 596 } 597 598 Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName) 599 { 600 if (p.isNull()) 601 return 0; 602 603 Node* root = highestEditableRoot(p); 604 for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) { 605 if (root && !n->rendererIsEditable()) 606 continue; 607 if (n->hasTagName(tagName)) 608 return n; 609 if (n == root) 610 return 0; 611 } 612 613 return 0; 614 } 615 616 Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule) 617 { 618 // FIXME: support CanSkipCrossEditingBoundary 619 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary); 620 if (p.isNull()) 621 return 0; 622 623 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0; 624 for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) { 625 // Don't return a non-editable node if the input position was editable, since 626 // the callers from editing will no doubt want to perform editing inside the returned node. 627 if (root && !n->rendererIsEditable()) 628 continue; 629 if (nodeIsOfType(n)) 630 return n; 631 if (n == root) 632 return 0; 633 } 634 635 return 0; 636 } 637 638 Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule) 639 { 640 Node* highest = 0; 641 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0; 642 for (Node* n = p.containerNode(); n; n = n->parentNode()) { 643 if (root && !n->rendererIsEditable()) 644 continue; 645 if (nodeIsOfType(n)) 646 highest = n; 647 if (n == root) 648 break; 649 } 650 651 return highest; 652 } 653 654 Node* enclosingTableCell(const Position& p) 655 { 656 return static_cast<Element*>(enclosingNodeOfType(p, isTableCell)); 657 } 658 659 Node* enclosingAnchorElement(const Position& p) 660 { 661 if (p.isNull()) 662 return 0; 663 664 Node* node = p.deprecatedNode(); 665 while (node && !(node->isElementNode() && node->isLink())) 666 node = node->parentNode(); 667 return node; 668 } 669 670 HTMLElement* enclosingList(Node* node) 671 { 672 if (!node) 673 return 0; 674 675 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node)); 676 677 for (ContainerNode* n = node->parentNode(); n; n = n->parentNode()) { 678 if (n->hasTagName(ulTag) || n->hasTagName(olTag)) 679 return toHTMLElement(n); 680 if (n == root) 681 return 0; 682 } 683 684 return 0; 685 } 686 687 Node* enclosingListChild(Node *node) 688 { 689 if (!node) 690 return 0; 691 // Check for a list item element, or for a node whose parent is a list element. Such a node 692 // will appear visually as a list item (but without a list marker) 693 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node)); 694 695 // FIXME: This function is inappropriately named if it starts with node instead of node->parentNode() 696 for (Node* n = node; n && n->parentNode(); n = n->parentNode()) { 697 if (n->hasTagName(liTag) || isListElement(n->parentNode())) 698 return n; 699 if (n == root || isTableCell(n)) 700 return 0; 701 } 702 703 return 0; 704 } 705 706 static HTMLElement* embeddedSublist(Node* listItem) 707 { 708 // Check the DOM so that we'll find collapsed sublists without renderers. 709 for (Node* n = listItem->firstChild(); n; n = n->nextSibling()) { 710 if (isListElement(n)) 711 return toHTMLElement(n); 712 } 713 714 return 0; 715 } 716 717 static Node* appendedSublist(Node* listItem) 718 { 719 // Check the DOM so that we'll find collapsed sublists without renderers. 720 for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) { 721 if (isListElement(n)) 722 return toHTMLElement(n); 723 if (isListItem(listItem)) 724 return 0; 725 } 726 727 return 0; 728 } 729 730 // FIXME: This method should not need to call isStartOfParagraph/isEndOfParagraph 731 Node* enclosingEmptyListItem(const VisiblePosition& visiblePos) 732 { 733 // Check that position is on a line by itself inside a list item 734 Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().deprecatedNode()); 735 if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos)) 736 return 0; 737 738 VisiblePosition firstInListChild(firstPositionInOrBeforeNode(listChildNode)); 739 VisiblePosition lastInListChild(lastPositionInOrAfterNode(listChildNode)); 740 741 if (firstInListChild != visiblePos || lastInListChild != visiblePos) 742 return 0; 743 744 if (embeddedSublist(listChildNode) || appendedSublist(listChildNode)) 745 return 0; 746 747 return listChildNode; 748 } 749 750 HTMLElement* outermostEnclosingList(Node* node, Node* rootList) 751 { 752 HTMLElement* list = enclosingList(node); 753 if (!list) 754 return 0; 755 756 while (HTMLElement* nextList = enclosingList(list)) { 757 if (nextList == rootList) 758 break; 759 list = nextList; 760 } 761 762 return list; 763 } 764 765 bool canMergeLists(Element* firstList, Element* secondList) 766 { 767 if (!firstList || !secondList || !firstList->isHTMLElement() || !secondList->isHTMLElement()) 768 return false; 769 770 return firstList->hasTagName(secondList->tagQName())// make sure the list types match (ol vs. ul) 771 && firstList->rendererIsEditable() && secondList->rendererIsEditable() // both lists are editable 772 && firstList->rootEditableElement() == secondList->rootEditableElement()// don't cross editing boundaries 773 && isVisiblyAdjacent(positionInParentAfterNode(firstList), positionInParentBeforeNode(secondList)); 774 // Make sure there is no visible content between this li and the previous list 775 } 776 777 Node* highestAncestor(Node* node) 778 { 779 ASSERT(node); 780 Node* parent = node; 781 while ((node = node->parentNode())) 782 parent = node; 783 return parent; 784 } 785 786 // FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable() 787 bool isTableElement(Node* n) 788 { 789 if (!n || !n->isElementNode()) 790 return false; 791 792 RenderObject* renderer = n->renderer(); 793 return (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)); 794 } 795 796 bool isTableCell(const Node* node) 797 { 798 RenderObject* r = node->renderer(); 799 if (!r) 800 return node->hasTagName(tdTag) || node->hasTagName(thTag); 801 802 return r->isTableCell(); 803 } 804 805 bool isEmptyTableCell(const Node* node) 806 { 807 // Returns true IFF the passed in node is one of: 808 // .) a table cell with no children, 809 // .) a table cell with a single BR child, and which has no other child renderers, including :before and :after renderers 810 // .) the BR child of such a table cell 811 812 // Find rendered node 813 while (node && !node->renderer()) 814 node = node->parentNode(); 815 if (!node) 816 return false; 817 818 // Make sure the rendered node is a table cell or <br>. 819 // If it's a <br>, then the parent node has to be a table cell. 820 RenderObject* renderer = node->renderer(); 821 if (renderer->isBR()) { 822 renderer = renderer->parent(); 823 if (!renderer) 824 return false; 825 } 826 if (!renderer->isTableCell()) 827 return false; 828 829 // Check that the table cell contains no child renderers except for perhaps a single <br>. 830 RenderObject* childRenderer = renderer->firstChild(); 831 if (!childRenderer) 832 return true; 833 if (!childRenderer->isBR()) 834 return false; 835 return !childRenderer->nextSibling(); 836 } 837 838 PassRefPtr<HTMLElement> createDefaultParagraphElement(Document* document) 839 { 840 return HTMLDivElement::create(document); 841 } 842 843 PassRefPtr<HTMLElement> createBreakElement(Document* document) 844 { 845 return HTMLBRElement::create(document); 846 } 847 848 PassRefPtr<HTMLElement> createOrderedListElement(Document* document) 849 { 850 return HTMLOListElement::create(document); 851 } 852 853 PassRefPtr<HTMLElement> createUnorderedListElement(Document* document) 854 { 855 return HTMLUListElement::create(document); 856 } 857 858 PassRefPtr<HTMLElement> createListItemElement(Document* document) 859 { 860 return HTMLLIElement::create(document); 861 } 862 863 PassRefPtr<HTMLElement> createHTMLElement(Document* document, const QualifiedName& name) 864 { 865 return HTMLElementFactory::createHTMLElement(name, document, 0, false); 866 } 867 868 PassRefPtr<HTMLElement> createHTMLElement(Document* document, const AtomicString& tagName) 869 { 870 return createHTMLElement(document, QualifiedName(nullAtom, tagName, xhtmlNamespaceURI)); 871 } 872 873 bool isTabSpanNode(const Node *node) 874 { 875 return node && node->hasTagName(spanTag) && node->isElementNode() && static_cast<const Element *>(node)->getAttribute(classAttr) == AppleTabSpanClass; 876 } 877 878 bool isTabSpanTextNode(const Node *node) 879 { 880 return node && node->isTextNode() && node->parentNode() && isTabSpanNode(node->parentNode()); 881 } 882 883 Node *tabSpanNode(const Node *node) 884 { 885 return isTabSpanTextNode(node) ? node->parentNode() : 0; 886 } 887 888 bool isNodeInTextFormControl(Node* node) 889 { 890 if (!node) 891 return false; 892 Node* ancestor = node->shadowAncestorNode(); 893 if (ancestor == node) 894 return false; 895 return ancestor->isElementNode() && static_cast<Element*>(ancestor)->isTextFormControl(); 896 } 897 898 Position positionOutsideTabSpan(const Position& pos) 899 { 900 Node* node = pos.containerNode(); 901 if (isTabSpanTextNode(node)) 902 node = tabSpanNode(node); 903 else if (!isTabSpanNode(node)) 904 return pos; 905 906 if (node && VisiblePosition(pos) == lastPositionInNode(node)) 907 return positionInParentAfterNode(node); 908 909 return positionInParentBeforeNode(node); 910 } 911 912 PassRefPtr<Element> createTabSpanElement(Document* document, PassRefPtr<Node> tabTextNode) 913 { 914 // Make the span to hold the tab. 915 RefPtr<Element> spanElement = document->createElement(spanTag, false); 916 spanElement->setAttribute(classAttr, AppleTabSpanClass); 917 spanElement->setAttribute(styleAttr, "white-space:pre"); 918 919 // Add tab text to that span. 920 if (!tabTextNode) 921 tabTextNode = document->createEditingTextNode("\t"); 922 923 ExceptionCode ec = 0; 924 spanElement->appendChild(tabTextNode, ec); 925 ASSERT(ec == 0); 926 927 return spanElement.release(); 928 } 929 930 PassRefPtr<Element> createTabSpanElement(Document* document, const String& tabText) 931 { 932 return createTabSpanElement(document, document->createTextNode(tabText)); 933 } 934 935 PassRefPtr<Element> createTabSpanElement(Document* document) 936 { 937 return createTabSpanElement(document, PassRefPtr<Node>()); 938 } 939 940 bool isNodeRendered(const Node *node) 941 { 942 if (!node) 943 return false; 944 945 RenderObject *renderer = node->renderer(); 946 if (!renderer) 947 return false; 948 949 return renderer->style()->visibility() == VISIBLE; 950 } 951 952 unsigned numEnclosingMailBlockquotes(const Position& p) 953 { 954 unsigned num = 0; 955 for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) 956 if (isMailBlockquote(n)) 957 num++; 958 959 return num; 960 } 961 962 bool isMailBlockquote(const Node *node) 963 { 964 if (!node || !node->hasTagName(blockquoteTag)) 965 return false; 966 967 return static_cast<const Element *>(node)->getAttribute("type") == "cite"; 968 } 969 970 int caretMinOffset(const Node* n) 971 { 972 RenderObject* r = n->renderer(); 973 ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now. 974 return r ? r->caretMinOffset() : 0; 975 } 976 977 // If a node can contain candidates for VisiblePositions, return the offset of the last candidate, otherwise 978 // return the number of children for container nodes and the length for unrendered text nodes. 979 int caretMaxOffset(const Node* n) 980 { 981 // For rendered text nodes, return the last position that a caret could occupy. 982 if (n->isTextNode() && n->renderer()) 983 return n->renderer()->caretMaxOffset(); 984 // For containers return the number of children. For others do the same as above. 985 return lastOffsetForEditing(n); 986 } 987 988 bool lineBreakExistsAtVisiblePosition(const VisiblePosition& visiblePosition) 989 { 990 return lineBreakExistsAtPosition(visiblePosition.deepEquivalent().downstream()); 991 } 992 993 bool lineBreakExistsAtPosition(const Position& position) 994 { 995 if (position.isNull()) 996 return false; 997 998 if (position.anchorNode()->hasTagName(brTag) && position.atFirstEditingPositionForNode()) 999 return true; 1000 1001 if (!position.anchorNode()->renderer()) 1002 return false; 1003 1004 if (!position.anchorNode()->isTextNode() || !position.anchorNode()->renderer()->style()->preserveNewline()) 1005 return false; 1006 1007 Text* textNode = static_cast<Text*>(position.anchorNode()); 1008 unsigned offset = position.offsetInContainerNode(); 1009 return offset < textNode->length() && textNode->data()[offset] == '\n'; 1010 } 1011 1012 // Modifies selections that have an end point at the edge of a table 1013 // that contains the other endpoint so that they don't confuse 1014 // code that iterates over selected paragraphs. 1015 VisibleSelection selectionForParagraphIteration(const VisibleSelection& original) 1016 { 1017 VisibleSelection newSelection(original); 1018 VisiblePosition startOfSelection(newSelection.visibleStart()); 1019 VisiblePosition endOfSelection(newSelection.visibleEnd()); 1020 1021 // If the end of the selection to modify is just after a table, and 1022 // if the start of the selection is inside that table, then the last paragraph 1023 // that we'll want modify is the last one inside the table, not the table itself 1024 // (a table is itself a paragraph). 1025 if (Node* table = isFirstPositionAfterTable(endOfSelection)) 1026 if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table)) 1027 newSelection = VisibleSelection(startOfSelection, endOfSelection.previous(CannotCrossEditingBoundary)); 1028 1029 // If the start of the selection to modify is just before a table, 1030 // and if the end of the selection is inside that table, then the first paragraph 1031 // we'll want to modify is the first one inside the table, not the paragraph 1032 // containing the table itself. 1033 if (Node* table = isLastPositionBeforeTable(startOfSelection)) 1034 if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table)) 1035 newSelection = VisibleSelection(startOfSelection.next(CannotCrossEditingBoundary), endOfSelection); 1036 1037 return newSelection; 1038 } 1039 1040 1041 int indexForVisiblePosition(const VisiblePosition& visiblePosition) 1042 { 1043 if (visiblePosition.isNull()) 1044 return 0; 1045 Position p(visiblePosition.deepEquivalent()); 1046 RefPtr<Range> range = Range::create(p.anchorNode()->document(), firstPositionInNode(p.anchorNode()->document()->documentElement()), 1047 p.parentAnchoredEquivalent()); 1048 return TextIterator::rangeLength(range.get(), true); 1049 } 1050 1051 // Determines whether two positions are visibly next to each other (first then second) 1052 // while ignoring whitespaces and unrendered nodes 1053 bool isVisiblyAdjacent(const Position& first, const Position& second) 1054 { 1055 return VisiblePosition(first) == VisiblePosition(second.upstream()); 1056 } 1057 1058 // Determines whether a node is inside a range or visibly starts and ends at the boundaries of the range. 1059 // Call this function to determine whether a node is visibly fit inside selectedRange 1060 bool isNodeVisiblyContainedWithin(Node* node, const Range* selectedRange) 1061 { 1062 ASSERT(node); 1063 ASSERT(selectedRange); 1064 // If the node is inside the range, then it surely is contained within 1065 ExceptionCode ec = 0; 1066 if (selectedRange->compareNode(node, ec) == Range::NODE_INSIDE) 1067 return true; 1068 1069 bool startIsVisuallySame = visiblePositionBeforeNode(node) == selectedRange->startPosition(); 1070 if (startIsVisuallySame && comparePositions(positionInParentAfterNode(node), selectedRange->endPosition()) < 0) 1071 return true; 1072 1073 bool endIsVisuallySame = visiblePositionAfterNode(node) == selectedRange->endPosition(); 1074 if (endIsVisuallySame && comparePositions(selectedRange->startPosition(), positionInParentBeforeNode(node)) < 0) 1075 return true; 1076 1077 return startIsVisuallySame && endIsVisuallySame; 1078 } 1079 1080 bool isRenderedAsNonInlineTableImageOrHR(const Node* node) 1081 { 1082 if (!node) 1083 return false; 1084 RenderObject* renderer = node->renderer(); 1085 return renderer && ((renderer->isTable() && !renderer->isInline()) || (renderer->isImage() && !renderer->isInline()) || renderer->isHR()); 1086 } 1087 1088 PassRefPtr<Range> avoidIntersectionWithNode(const Range* range, Node* node) 1089 { 1090 if (!range) 1091 return 0; 1092 1093 Document* document = range->ownerDocument(); 1094 1095 Node* startContainer = range->startContainer(); 1096 int startOffset = range->startOffset(); 1097 Node* endContainer = range->endContainer(); 1098 int endOffset = range->endOffset(); 1099 1100 if (!startContainer) 1101 return 0; 1102 1103 ASSERT(endContainer); 1104 1105 if (startContainer == node || startContainer->isDescendantOf(node)) { 1106 ASSERT(node->parentNode()); 1107 startContainer = node->parentNode(); 1108 startOffset = node->nodeIndex(); 1109 } 1110 if (endContainer == node || endContainer->isDescendantOf(node)) { 1111 ASSERT(node->parentNode()); 1112 endContainer = node->parentNode(); 1113 endOffset = node->nodeIndex(); 1114 } 1115 1116 return Range::create(document, startContainer, startOffset, endContainer, endOffset); 1117 } 1118 1119 VisibleSelection avoidIntersectionWithNode(const VisibleSelection& selection, Node* node) 1120 { 1121 if (selection.isNone()) 1122 return VisibleSelection(selection); 1123 1124 VisibleSelection updatedSelection(selection); 1125 Node* base = selection.base().deprecatedNode(); 1126 Node* extent = selection.extent().deprecatedNode(); 1127 ASSERT(base); 1128 ASSERT(extent); 1129 1130 if (base == node || base->isDescendantOf(node)) { 1131 ASSERT(node->parentNode()); 1132 updatedSelection.setBase(positionInParentBeforeNode(node)); 1133 } 1134 1135 if (extent == node || extent->isDescendantOf(node)) { 1136 ASSERT(node->parentNode()); 1137 updatedSelection.setExtent(positionInParentBeforeNode(node)); 1138 } 1139 1140 return updatedSelection; 1141 } 1142 1143 } // namespace WebCore 1144