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