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