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