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