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