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