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