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