efac6df845256cb79b2bee171ede50980d28ee40
[WebKit-https.git] / WebCore / editing / htmlediting.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006 Apple Computer, 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 "HTMLElement.h"
32 #include "HTMLInterchange.h"
33 #include "HTMLNames.h"
34 #include "RenderObject.h"
35 #include "RegularExpression.h"
36 #include "Range.h"
37 #include "Text.h"
38 #include "VisiblePosition.h"
39 #include "visible_units.h"
40
41 using namespace std;
42
43 namespace WebCore {
44
45 using namespace HTMLNames;
46
47 // Atomic means that the node has no children, or has children which are ignored for the
48 // purposes of editing.
49 bool isAtomicNode(const Node *node)
50 {
51     return node && (!node->hasChildNodes() || editingIgnoresContent(node));
52 }
53
54 bool editingIgnoresContent(const Node *node)
55 {
56     if (!node || !node->isHTMLElement())
57         return false;
58     
59     // There doesn't seem to be a way to find out if a a node is a pop up box by looking at its renderer.
60     if (node->hasTagName(selectTag))
61         return true;
62     
63     if (node->renderer())
64         return node->renderer()->isWidget() || node->renderer()->isImage() || node->renderer()->isHR() || node->renderer()->isTextArea() || node->renderer()->isTextField();
65
66     return node->hasTagName(appletTag) ||
67            node->hasTagName(embedTag) ||
68            node->hasTagName(iframeTag) ||
69            node->hasTagName(imgTag) ||
70            node->hasTagName(hrTag) ||
71            static_cast<const HTMLElement *>(node)->isGenericFormElement();
72 }
73
74 // Some nodes, like brs, will technically accept children, but we don't want that to happen while editing. 
75 bool canHaveChildrenForEditing(const Node* node)
76 {
77     return !node->hasTagName(hrTag) &&
78            !node->hasTagName(brTag) &&
79            !node->hasTagName(imgTag) &&
80            !node->hasTagName(buttonTag) &&
81            !node->hasTagName(objectTag) &&
82            !node->hasTagName(iframeTag) &&
83            !node->isTextNode();
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.
88 int comparePositions(const Position& a, const Position& b)
89 {
90     Node* nodeA = a.node();
91     ASSERT(nodeA);
92     Node* nodeB = b.node();
93     ASSERT(nodeB);
94     int offsetA = a.offset();
95     int offsetB = b.offset();
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     int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB);
119     return result ? result : bias;
120 }
121
122 Node* highestEditableRoot(const Position& position)
123 {
124     Node* node = position.node();
125     if (!node)
126         return 0;
127         
128     Node* highestRoot = editableRootForPosition(position);
129     if (!highestRoot)
130         return 0;
131     
132     node = highestRoot;
133     while (node) {
134         if (node->isContentEditable())
135             highestRoot = node;
136         if (node->hasTagName(bodyTag))
137             break;
138         node = node->parentNode();
139     }
140     
141     return highestRoot;
142 }
143
144 Node* lowestEditableAncestor(Node* node)
145 {
146     if (!node)
147         return 0;
148     
149     Node *lowestRoot = 0;
150     while (node) {
151         if (node->isContentEditable())
152             return node->rootEditableElement();
153         if (node->hasTagName(bodyTag))
154             break;
155         node = node->parentNode();
156     }
157     
158     return lowestRoot;
159 }
160
161 bool isEditablePosition(const Position& p)
162 {
163     Node* node = p.node();
164     if (!node)
165         return false;
166         
167     if (node->renderer() && node->renderer()->isTable())
168         node = node->parentNode();
169     
170     return node->isContentEditable();
171 }
172
173 bool isRichlyEditablePosition(const Position& p)
174 {
175     Node* node = p.node();
176     if (!node)
177         return false;
178         
179     if (node->renderer() && node->renderer()->isTable())
180         node = node->parentNode();
181     
182     return node->isContentRichlyEditable();
183 }
184
185 Element* editableRootForPosition(const Position& p)
186 {
187     Node* node = p.node();
188     if (!node)
189         return 0;
190         
191     if (node->renderer() && node->renderer()->isTable())
192         node = node->parentNode();
193     
194     return node->rootEditableElement();
195 }
196
197 Position nextCandidate(const Position& position)
198 {
199     Position p = position;
200     while (!p.atEnd()) {
201         p = p.next(UsingComposedCharacters);
202         if (p.inRenderedContent())
203             return p;
204     }
205     return Position();
206 }
207
208 Position nextVisuallyDistinctCandidate(const Position& position)
209 {
210     Position p = position;
211     Position downstreamStart = p.downstream();
212     while (!p.atEnd()) {
213         p = p.next(UsingComposedCharacters);
214         if (p.inRenderedContent() && p.downstream() != downstreamStart)
215             return p;
216     }
217     return Position();
218 }
219
220 Position previousCandidate(const Position& position)
221 {
222     Position p = position;
223     while (!p.atStart()) {
224         p = p.previous(UsingComposedCharacters);
225         if (p.inRenderedContent())
226             return p;
227     }
228     return Position();
229 }
230
231 Position previousVisuallyDistinctCandidate(const Position& position)
232 {
233     Position p = position;
234     Position downstreamStart = p.downstream();
235     while (!p.atStart()) {
236         p = p.previous(UsingComposedCharacters);
237         if (p.inRenderedContent() && p.downstream() != downstreamStart)
238             return p;
239     }
240     return Position();
241 }
242
243 VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, Node* highestRoot)
244 {
245     if (comparePositions(position, Position(highestRoot, 0)) == -1)
246         return VisiblePosition(Position(highestRoot, 0));
247
248     Position p = nextVisuallyDistinctCandidate(position);
249     while (p.isNotNull() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
250         p = isAtomicNode(p.node()) ? positionAfterNode(p.node()) : nextVisuallyDistinctCandidate(p);
251
252     return VisiblePosition(p);
253 }
254
255 VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, Node* highestRoot)
256 {
257     if (comparePositions(position, Position(highestRoot, maxDeepOffset(highestRoot))) == 1)
258         return VisiblePosition(Position(highestRoot, maxDeepOffset(highestRoot)));
259     
260     Position p = previousVisuallyDistinctCandidate(position);
261     while (p.isNotNull() && !isEditablePosition(p) && p.node()->isDescendantOf(highestRoot))
262         p = isAtomicNode(p.node()) ? positionBeforeNode(p.node()) : previousVisuallyDistinctCandidate(p);
263
264     return VisiblePosition(p);
265 }
266
267 // Whether or not content before and after this node will collapse onto the same line as it.
268 bool isBlock(Node* node)
269 {
270     return node && node->renderer() && !node->renderer()->isInline();
271 }
272
273 // FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlockFlowOrTableElement are used.
274 // FIXME: Pass a position to this function.  The enclosing block of [table, x] for example, should be the 
275 // block that contains the table and not the table, and this function should be the only one responsible for 
276 // knowing about these kinds of special cases.
277 Node* enclosingBlock(Node* node)
278 {
279     if (isBlock(node))
280         return node;
281         
282     while (1) {
283         node = node->parentNode();
284         if (!node)
285             break;
286         if (isBlock(node))
287             return node;
288     }
289     return 0;
290 }
291
292 Position rangeCompliantEquivalent(const Position& pos)
293 {
294     if (pos.isNull())
295         return Position();
296
297     Node *node = pos.node();
298     
299     if (pos.offset() <= 0) {
300         if (node->parentNode() && (node->hasTagName(brTag) || editingIgnoresContent(node)))
301             return positionBeforeNode(node);
302         return Position(node, 0);
303     }
304     
305     if (node->offsetInCharacters())
306         return Position(node, min(node->maxOffset(), pos.offset()));
307     
308     int maxCompliantOffset = node->childNodeCount();
309     if (pos.offset() > maxCompliantOffset) {
310         if (node->parentNode())
311             return positionAfterNode(node);
312         
313         // there is no other option at this point than to
314         // use the highest allowed position in the node
315         return Position(node, maxCompliantOffset);
316     } 
317
318     // Editing should never generate positions like this.
319     if ((pos.offset() < maxCompliantOffset) && editingIgnoresContent(node)) {
320         ASSERT_NOT_REACHED();
321         return node->parentNode() ? positionBeforeNode(node) : Position(node, 0);
322     }
323     
324     return Position(pos);
325 }
326
327 Position rangeCompliantEquivalent(const VisiblePosition& vpos)
328 {
329     return rangeCompliantEquivalent(vpos.deepEquivalent());
330 }
331
332 // This method is used to create positions in the DOM. It returns the maximum valid offset
333 // in a node.  It returns 1 for some elements even though they do not have children, which
334 // creates technically invalid DOM Positions.  Be sure to call rangeCompliantEquivalent
335 // on a Position before using it to create a DOM Range, or an exception will be thrown.
336 int maxDeepOffset(const Node *node)
337 {
338     if (node->offsetInCharacters())
339         return node->maxOffset();
340         
341     if (node->hasChildNodes())
342         return node->childNodeCount();
343     
344     // NOTE: This should preempt the childNodeCount for, e.g., select nodes
345     if (node->hasTagName(brTag) || editingIgnoresContent(node))
346         return 1;
347
348     return 0;
349 }
350
351 void rebalanceWhitespaceInTextNode(Node *node, unsigned int start, unsigned int length)
352 {
353     ASSERT(node->isTextNode());
354     Text *textNode = static_cast<Text *>(node);
355     String text = textNode->data();
356     ASSERT(length <= text.length() && start + length <= text.length());
357     
358     String substring = text.substring(start, length);
359
360     // FIXME: We rebalance with all nbsps, for simplicity (we don't need crazy sequences while editing
361     // because all editable regions will have -webkit-nbsp-mode: space.  We should produce sequences of 
362     // regular spaces and nbsps that are better for interchange when we serialize (10636).
363     substring.replace(' ', NON_BREAKING_SPACE);
364     substring.replace('\t', NON_BREAKING_SPACE);
365     substring.replace('\n', NON_BREAKING_SPACE);
366     
367     ExceptionCode ec = 0;
368     textNode->deleteData(start, length, ec);
369     ASSERT(!ec);
370     textNode->insertData(start, String(substring), ec);
371     ASSERT(!ec);
372 }
373
374 bool isTableStructureNode(const Node *node)
375 {
376     RenderObject *r = node->renderer();
377     return (r && (r->isTableCell() || r->isTableRow() || r->isTableSection() || r->isTableCol()));
378 }
379
380 const String& nonBreakingSpaceString()
381 {
382     static String nonBreakingSpaceString = DeprecatedString(DeprecatedChar(NON_BREAKING_SPACE));
383     return nonBreakingSpaceString;
384 }
385
386 // FIXME: Why use this instead of maxDeepOffset?
387 static int maxRangeOffset(Node *n)
388 {
389     if (n->offsetInCharacters())
390         return n->maxOffset();
391
392     if (n->isElementNode())
393         return n->childNodeCount();
394
395     return 1;
396 }
397
398 // FIXME: need to dump this
399 bool isSpecialElement(const Node *n)
400 {
401     if (!n)
402         return false;
403         
404     if (!n->isHTMLElement())
405         return false;
406
407     if (n->isLink())
408         return true;
409
410     if (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag))
411         return true;
412
413     RenderObject *renderer = n->renderer();
414     if (!renderer)
415         return false;
416         
417     if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
418         return true;
419
420     if (renderer->style()->isFloating())
421         return true;
422
423     if (renderer->style()->position() != StaticPosition)
424         return true;
425         
426     return false;
427 }
428
429 // Checks if a string is a valid tag for the FormatBlockCommand function of execCommand. Expects lower case strings.
430 bool validBlockTag(const String& blockTag)
431 {
432     if (blockTag == "address" ||
433         blockTag == "blockquote" ||
434         blockTag == "dd" ||
435         blockTag == "div" ||
436         blockTag == "dl" ||
437         blockTag == "dt" ||
438         blockTag == "h1" ||
439         blockTag == "h2" ||
440         blockTag == "h3" ||
441         blockTag == "h4" ||
442         blockTag == "h5" ||
443         blockTag == "h6" ||
444         blockTag == "p" ||
445         blockTag == "pre")
446         return true;
447     return false;
448 }
449
450 static Node* firstInSpecialElement(const Position& pos)
451 {
452     Node* rootEditableElement = pos.node()->rootEditableElement();
453     for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
454         if (isSpecialElement(n)) {
455             VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
456             VisiblePosition firstInElement = VisiblePosition(n, 0, DOWNSTREAM);
457             if (isTableElement(n) && vPos == firstInElement.next())
458                 return n;
459             if (vPos == firstInElement)
460                 return n;
461         }
462     return 0;
463 }
464
465 static Node* lastInSpecialElement(const Position& pos)
466 {
467     Node* rootEditableElement = pos.node()->rootEditableElement();
468     for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
469         if (isSpecialElement(n)) {
470             VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
471             VisiblePosition lastInElement = VisiblePosition(n, n->childNodeCount(), DOWNSTREAM);
472             if (isTableElement(n) && vPos == lastInElement.previous())
473                 return n;
474             if (vPos == lastInElement)
475                 return n;
476         }
477     return 0;
478 }
479
480 bool isFirstVisiblePositionInSpecialElement(const Position& pos)
481 {
482     return firstInSpecialElement(pos);
483 }
484
485 Position positionBeforeContainingSpecialElement(const Position& pos, Node** containingSpecialElement)
486 {
487     Node* n = firstInSpecialElement(pos);
488     ASSERT(n);
489     if (!n)
490         return pos;
491     Position result = positionBeforeNode(n);
492     if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
493         return pos;
494     if (containingSpecialElement)
495         *containingSpecialElement = n;
496     return result;
497 }
498
499 bool isLastVisiblePositionInSpecialElement(const Position& pos)
500 {
501     return lastInSpecialElement(pos);
502 }
503
504 Position positionAfterContainingSpecialElement(const Position& pos, Node **containingSpecialElement)
505 {
506     Node* n = lastInSpecialElement(pos);
507     ASSERT(n);
508     if (!n)
509         return pos;
510     Position result = positionAfterNode(n);
511     if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
512         return pos;
513     if (containingSpecialElement)
514         *containingSpecialElement = n;
515     return result;
516 }
517
518 Position positionOutsideContainingSpecialElement(const Position &pos, Node **containingSpecialElement)
519 {
520     if (isFirstVisiblePositionInSpecialElement(pos))
521         return positionBeforeContainingSpecialElement(pos, containingSpecialElement);
522     if (isLastVisiblePositionInSpecialElement(pos))
523         return positionAfterContainingSpecialElement(pos, containingSpecialElement);
524     return pos;
525 }
526
527 Position positionBeforeNode(const Node *node)
528 {
529     return Position(node->parentNode(), node->nodeIndex());
530 }
531
532 Position positionAfterNode(const Node *node)
533 {
534     return Position(node->parentNode(), node->nodeIndex() + 1);
535 }
536
537 bool isListElement(Node *n)
538 {
539     return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
540 }
541
542 Node* enclosingNodeWithTag(Node* node, const QualifiedName& tagName)
543 {
544     if (!node)
545         return 0;
546     Node* root = (node->inDocument()) ? node->rootEditableElement() : highestAncestor(node);
547     ASSERT(root);
548     for (Node* n = node->parentNode(); n && (n == root || n->isDescendantOf(root)); n = n->parentNode())
549         if (n->hasTagName(tagName))
550             return n;
551             
552     return 0;
553 }
554
555 Node* enclosingNodeOfType(Node* node, bool (*nodeIsOfType)(Node*))
556 {
557     if (!node)
558         return 0;
559         
560     Node* root = highestEditableRoot(Position(node, 0));
561     if (!root)
562         root = highestAncestor(node);
563         
564     for (Node* n = node->parentNode(); n && (n == root || n->isDescendantOf(root)); n = n->parentNode())
565         if ((*nodeIsOfType)(n))
566             return n;
567             
568     return 0;
569 }
570
571 Node* enclosingTableCell(Node* node)
572 {
573     if (!node)
574         return 0;
575         
576     for (Node* n = node->parentNode(); n; n = n->parentNode())
577         if (n->renderer() && n->renderer()->isTableCell())
578             return n;
579             
580     return 0;
581 }
582
583 Node* enclosingList(Node* node)
584 {
585     if (!node)
586         return 0;
587     Node* root = (node->inDocument()) ? node->rootEditableElement() : highestAncestor(node);
588     ASSERT(root);
589     for (Node* n = node->parentNode(); n && (n == root || n->isDescendantOf(root)); n = n->parentNode())
590         if (n->hasTagName(ulTag) || n->hasTagName(olTag))
591             return n;
592             
593     return 0;
594 }
595
596 Node* enclosingListChild (Node *node)
597 {
598     if (!node)
599         return 0;
600     // Check for a list item element, or for a node whose parent is a list element.  Such a node
601     // will appear visually as a list item (but without a list marker)
602     Node* root = (node->inDocument()) ? node->rootEditableElement() : highestAncestor(node);
603     ASSERT(root);
604     for (Node *n = node; n && n->parentNode() && (n == root || n->isDescendantOf(root)); n = n->parentNode()) {
605         if (n->hasTagName(liTag) || isListElement(n->parentNode()))
606             return n;
607     }
608     
609     return 0;
610 }
611
612 static Node* embeddedSublist(Node* listItem)
613 {
614     // Check the DOM so that we'll find collapsed sublists without renderers.
615     for (Node* n = listItem->firstChild(); n; n = n->nextSibling()) {
616         if (isListElement(n))
617             return n;
618     }
619     
620     return 0;
621 }
622
623 static Node* appendedSublist(Node* listItem)
624 {
625     // Check the DOM so that we'll find collapsed sublists without renderers.
626     for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) {
627         if (isListElement(n))
628             return n;
629         if (n->renderer() && n->renderer()->isListItem())
630             return 0;
631     }
632     
633     return 0;
634 }
635
636 Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
637 {
638     // Check that position is on a line by itself inside a list item
639     Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().node());
640     if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
641         return 0;
642     
643     if (embeddedSublist(listChildNode) || appendedSublist(listChildNode))
644         return 0;
645         
646     return listChildNode;
647 }
648
649 Node* outermostEnclosingListChild(Node* node)
650 {
651     Node* listNode = 0;
652     Node* nextNode = node;
653     while ((nextNode = enclosingListChild(nextNode)))
654         listNode = nextNode;
655     return listNode;
656 }
657
658 Node* outermostEnclosingList(Node* node)
659 {
660     Node* listNode = 0;
661     Node* nextNode = node;
662     while ((nextNode = enclosingList(nextNode)))
663         listNode = nextNode;
664     return listNode;
665 }
666
667 Node* highestAncestor(Node* node)
668 {
669     ASSERT(node);
670     Node* parent = node;
671     while ((node = node->parentNode()))
672         parent = node;
673     return parent;
674 }
675
676 // FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable()
677 bool isTableElement(Node *n)
678 {
679     RenderObject *renderer = n ? n->renderer() : 0;
680     return (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE));
681 }
682
683 bool isFirstVisiblePositionAfterTableElement(const Position& pos)
684 {
685     return isTableElement(pos.upstream().node());
686 }
687
688 Position positionBeforePrecedingTableElement(const Position& pos)
689 {
690     ASSERT(isFirstVisiblePositionAfterTableElement(pos));
691     Position result = positionBeforeNode(pos.upstream().node());
692     if (result.isNull() || !result.node()->rootEditableElement())
693         return pos;
694     return result;
695 }
696
697 bool isLastVisiblePositionBeforeTableElement(const Position &pos)
698 {
699     return isTableElement(pos.downstream().node());
700 }
701
702 Position positionAfterFollowingTableElement(const Position &pos)
703 {
704     ASSERT(isLastVisiblePositionBeforeTableElement(pos));
705     Position result = positionAfterNode(pos.downstream().node());
706     if (result.isNull() || !result.node()->rootEditableElement())
707         return pos;
708     return result;
709 }
710
711 // This function is necessary because a VisiblePosition is allowed
712 // to be at the start or end of elements where we do not want to
713 // add content directly.  For example, clicking at the end of a hyperlink,
714 // then typing, needs to add the text after the link.  Also, table
715 // offset 0 and table offset childNodeCount are valid VisiblePostions,
716 // but we can not add more content right there... it needs to go before
717 // or after the table.
718 // FIXME: Consider editable/non-editable boundaries?
719 Position positionAvoidingSpecialElementBoundary(const Position &pos)
720 {
721     Node *compNode = pos.node();
722     if (!compNode)
723         return pos;
724     
725     if (compNode->parentNode() && compNode->parentNode()->isLink())
726         compNode = compNode->parentNode();
727     else if (!isTableElement(compNode))
728         return pos;
729     
730     // FIXME: rangePos isn't being used to create DOM Ranges, so why does it need to be range compliant?
731     Position rangePos = rangeCompliantEquivalent(VisiblePosition(pos, DOWNSTREAM));
732     VisiblePosition vPos = VisiblePosition(rangePos, DOWNSTREAM);
733
734     Position result;
735     if (VisiblePosition(compNode, maxRangeOffset(compNode), DOWNSTREAM) == vPos)
736         result = positionAfterNode(compNode);
737     else if (VisiblePosition(compNode, 0, DOWNSTREAM) == vPos)
738         result = positionBeforeNode(compNode);
739     else
740         return pos;
741         
742     if (result.isNull() || !result.node()->rootEditableElement())
743         result = pos;
744     
745     return result;
746 }
747
748 PassRefPtr<Element> createDefaultParagraphElement(Document *document)
749 {
750     ExceptionCode ec = 0;
751     RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "div", ec);
752     ASSERT(ec == 0);
753     return element.release();
754 }
755
756 PassRefPtr<Element> createBreakElement(Document *document)
757 {
758     ExceptionCode ec = 0;
759     RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "br", ec);
760     ASSERT(ec == 0);
761     return breakNode.release();
762 }
763
764 PassRefPtr<Element> createOrderedListElement(Document *document)
765 {
766     ExceptionCode ec = 0;
767     RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "ol", ec);
768     ASSERT(ec == 0);
769     return element.release();
770 }
771
772 PassRefPtr<Element> createUnorderedListElement(Document *document)
773 {
774     ExceptionCode ec = 0;
775     RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "ul", ec);
776     ASSERT(ec == 0);
777     return element.release();
778 }
779
780 PassRefPtr<Element> createListItemElement(Document *document)
781 {
782     ExceptionCode ec = 0;
783     RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "li", ec);
784     ASSERT(ec == 0);
785     return breakNode.release();
786 }
787
788 PassRefPtr<Element> createElement(Document* document, const String& tagName)
789 {
790     ExceptionCode ec = 0;
791     RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, tagName, ec);
792     ASSERT(ec == 0);
793     return breakNode.release();
794 }
795
796 bool isTabSpanNode(const Node *node)
797 {
798     return (node && node->isElementNode() && static_cast<const Element *>(node)->getAttribute("class") == AppleTabSpanClass);
799 }
800
801 bool isTabSpanTextNode(const Node *node)
802 {
803     return (node && node->parentNode() && isTabSpanNode(node->parentNode()));
804 }
805
806 Node *tabSpanNode(const Node *node)
807 {
808     return isTabSpanTextNode(node) ? node->parentNode() : 0;
809 }
810
811 Position positionBeforeTabSpan(const Position& pos)
812 {
813     Node *node = pos.node();
814     if (isTabSpanTextNode(node))
815         node = tabSpanNode(node);
816     else if (!isTabSpanNode(node))
817         return pos;
818     
819     return positionBeforeNode(node);
820 }
821
822 PassRefPtr<Element> createTabSpanElement(Document* document, PassRefPtr<Node> tabTextNode)
823 {
824     // make the span to hold the tab
825     ExceptionCode ec = 0;
826     RefPtr<Element> spanElement = document->createElementNS(xhtmlNamespaceURI, "span", ec);
827     assert(ec == 0);
828     spanElement->setAttribute(classAttr, AppleTabSpanClass);
829     spanElement->setAttribute(styleAttr, "white-space:pre");
830
831     // add tab text to that span
832     if (!tabTextNode)
833         tabTextNode = document->createEditingTextNode("\t");
834     spanElement->appendChild(tabTextNode, ec);
835     assert(ec == 0);
836
837     return spanElement.release();
838 }
839
840 PassRefPtr<Element> createTabSpanElement(Document* document, const String& tabText)
841 {
842     return createTabSpanElement(document, document->createTextNode(tabText));
843 }
844
845 PassRefPtr<Element> createTabSpanElement(Document* document)
846 {
847     return createTabSpanElement(document, PassRefPtr<Node>());
848 }
849
850 bool isNodeRendered(const Node *node)
851 {
852     if (!node)
853         return false;
854
855     RenderObject *renderer = node->renderer();
856     if (!renderer)
857         return false;
858
859     return renderer->style()->visibility() == VISIBLE;
860 }
861
862 Node *nearestMailBlockquote(const Node *node)
863 {
864     for (Node *n = const_cast<Node *>(node); n; n = n->parentNode()) {
865         if (isMailBlockquote(n))
866             return n;
867     }
868     return 0;
869 }
870
871 bool isMailBlockquote(const Node *node)
872 {
873     if (!node || !node->isElementNode() && !node->hasTagName(blockquoteTag))
874         return false;
875         
876     return static_cast<const Element *>(node)->getAttribute("type") == "cite";
877 }
878
879 } // namespace WebCore