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