Reviewed by darin
[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: need to dump this
390 bool isSpecialElement(const Node *n)
391 {
392     if (!n)
393         return false;
394         
395     if (!n->isHTMLElement())
396         return false;
397
398     if (n->isLink())
399         return true;
400
401     if (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag))
402         return true;
403
404     RenderObject *renderer = n->renderer();
405     if (!renderer)
406         return false;
407         
408     if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
409         return true;
410
411     if (renderer->style()->isFloating())
412         return true;
413
414     if (renderer->style()->position() != StaticPosition)
415         return true;
416         
417     return false;
418 }
419
420 // Checks if a string is a valid tag for the FormatBlockCommand function of execCommand. Expects lower case strings.
421 bool validBlockTag(const String& blockTag)
422 {
423     if (blockTag == "address" ||
424         blockTag == "blockquote" ||
425         blockTag == "dd" ||
426         blockTag == "div" ||
427         blockTag == "dl" ||
428         blockTag == "dt" ||
429         blockTag == "h1" ||
430         blockTag == "h2" ||
431         blockTag == "h3" ||
432         blockTag == "h4" ||
433         blockTag == "h5" ||
434         blockTag == "h6" ||
435         blockTag == "p" ||
436         blockTag == "pre")
437         return true;
438     return false;
439 }
440
441 static Node* firstInSpecialElement(const Position& pos)
442 {
443     Node* rootEditableElement = pos.node()->rootEditableElement();
444     for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
445         if (isSpecialElement(n)) {
446             VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
447             VisiblePosition firstInElement = VisiblePosition(n, 0, DOWNSTREAM);
448             if (isTableElement(n) && vPos == firstInElement.next())
449                 return n;
450             if (vPos == firstInElement)
451                 return n;
452         }
453     return 0;
454 }
455
456 static Node* lastInSpecialElement(const Position& pos)
457 {
458     Node* rootEditableElement = pos.node()->rootEditableElement();
459     for (Node* n = pos.node(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
460         if (isSpecialElement(n)) {
461             VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
462             VisiblePosition lastInElement = VisiblePosition(n, n->childNodeCount(), DOWNSTREAM);
463             if (isTableElement(n) && vPos == lastInElement.previous())
464                 return n;
465             if (vPos == lastInElement)
466                 return n;
467         }
468     return 0;
469 }
470
471 bool isFirstVisiblePositionInSpecialElement(const Position& pos)
472 {
473     return firstInSpecialElement(pos);
474 }
475
476 Position positionBeforeContainingSpecialElement(const Position& pos, Node** containingSpecialElement)
477 {
478     Node* n = firstInSpecialElement(pos);
479     ASSERT(n);
480     if (!n)
481         return pos;
482     Position result = positionBeforeNode(n);
483     if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
484         return pos;
485     if (containingSpecialElement)
486         *containingSpecialElement = n;
487     return result;
488 }
489
490 bool isLastVisiblePositionInSpecialElement(const Position& pos)
491 {
492     return lastInSpecialElement(pos);
493 }
494
495 Position positionAfterContainingSpecialElement(const Position& pos, Node **containingSpecialElement)
496 {
497     Node* n = lastInSpecialElement(pos);
498     ASSERT(n);
499     if (!n)
500         return pos;
501     Position result = positionAfterNode(n);
502     if (result.isNull() || result.node()->rootEditableElement() != pos.node()->rootEditableElement())
503         return pos;
504     if (containingSpecialElement)
505         *containingSpecialElement = n;
506     return result;
507 }
508
509 Position positionOutsideContainingSpecialElement(const Position &pos, Node **containingSpecialElement)
510 {
511     if (isFirstVisiblePositionInSpecialElement(pos))
512         return positionBeforeContainingSpecialElement(pos, containingSpecialElement);
513     if (isLastVisiblePositionInSpecialElement(pos))
514         return positionAfterContainingSpecialElement(pos, containingSpecialElement);
515     return pos;
516 }
517
518 Position positionBeforeNode(const Node *node)
519 {
520     return Position(node->parentNode(), node->nodeIndex());
521 }
522
523 Position positionAfterNode(const Node *node)
524 {
525     return Position(node->parentNode(), node->nodeIndex() + 1);
526 }
527
528 bool isListElement(Node *n)
529 {
530     return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
531 }
532
533 Node* enclosingNodeWithTag(Node* node, const QualifiedName& tagName)
534 {
535     if (!node)
536         return 0;
537         
538     Node* root = highestEditableRoot(Position(node, 0));
539     
540     for (Node* n = node->parentNode(); n; n = n->parentNode()) {
541         if (n->hasTagName(tagName))
542             return n;
543         if (n == root)
544             return 0;
545     }
546     
547     return 0;
548 }
549
550 Node* enclosingNodeOfType(Node* node, bool (*nodeIsOfType)(Node*))
551 {
552     if (!node)
553         return 0;
554         
555     Node* root = highestEditableRoot(Position(node, 0));
556     
557     for (Node* n = node->parentNode(); n; n = n->parentNode()) {
558         if ((*nodeIsOfType)(n))
559             return n;
560         if (n == root)
561             return 0;
562     }
563     
564     return 0;
565 }
566
567 Node* enclosingTableCell(Node* node)
568 {
569     if (!node)
570         return 0;
571         
572     for (Node* n = node->parentNode(); n; n = n->parentNode())
573         if (n->renderer() && n->renderer()->isTableCell())
574             return n;
575             
576     return 0;
577 }
578
579 Node* enclosingList(Node* node)
580 {
581     if (!node)
582         return 0;
583         
584     Node* root = highestEditableRoot(Position(node, 0));
585     
586     for (Node* n = node->parentNode(); n; n = n->parentNode()) {
587         if (n->hasTagName(ulTag) || n->hasTagName(olTag))
588             return n;
589         if (n == root)
590             return 0;
591     }
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 = highestEditableRoot(Position(node, 0));
603     
604     // FIXME: This function is inappropriately named if it starts with node instead of node->parentNode()
605     for (Node* n = node; n && n->parentNode(); n = n->parentNode()) {
606         if (n->hasTagName(liTag) || isListElement(n->parentNode()))
607             return n;
608         if (n == root)
609             return 0;
610     }
611     
612     return 0;
613 }
614
615 static Node* embeddedSublist(Node* listItem)
616 {
617     // Check the DOM so that we'll find collapsed sublists without renderers.
618     for (Node* n = listItem->firstChild(); n; n = n->nextSibling()) {
619         if (isListElement(n))
620             return n;
621     }
622     
623     return 0;
624 }
625
626 static Node* appendedSublist(Node* listItem)
627 {
628     // Check the DOM so that we'll find collapsed sublists without renderers.
629     for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) {
630         if (isListElement(n))
631             return n;
632         if (n->renderer() && n->renderer()->isListItem())
633             return 0;
634     }
635     
636     return 0;
637 }
638
639 Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
640 {
641     // Check that position is on a line by itself inside a list item
642     Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().node());
643     if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
644         return 0;
645     
646     if (embeddedSublist(listChildNode) || appendedSublist(listChildNode))
647         return 0;
648         
649     return listChildNode;
650 }
651
652 Node* outermostEnclosingListChild(Node* node)
653 {
654     Node* listNode = 0;
655     Node* nextNode = node;
656     while ((nextNode = enclosingListChild(nextNode)))
657         listNode = nextNode;
658     return listNode;
659 }
660
661 Node* outermostEnclosingList(Node* node)
662 {
663     Node* listNode = 0;
664     Node* nextNode = node;
665     while ((nextNode = enclosingList(nextNode)))
666         listNode = nextNode;
667     return listNode;
668 }
669
670 Node* highestAncestor(Node* node)
671 {
672     ASSERT(node);
673     Node* parent = node;
674     while ((node = node->parentNode()))
675         parent = node;
676     return parent;
677 }
678
679 // FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable()
680 bool isTableElement(Node *n)
681 {
682     RenderObject *renderer = n ? n->renderer() : 0;
683     return (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE));
684 }
685
686 bool isFirstVisiblePositionAfterTableElement(const Position& pos)
687 {
688     return isTableElement(pos.upstream().node());
689 }
690
691 Position positionBeforePrecedingTableElement(const Position& pos)
692 {
693     ASSERT(isFirstVisiblePositionAfterTableElement(pos));
694     Position result = positionBeforeNode(pos.upstream().node());
695     if (result.isNull() || !result.node()->rootEditableElement())
696         return pos;
697     return result;
698 }
699
700 bool isLastVisiblePositionBeforeTableElement(const Position &pos)
701 {
702     return isTableElement(pos.downstream().node());
703 }
704
705 Position positionAfterFollowingTableElement(const Position &pos)
706 {
707     ASSERT(isLastVisiblePositionBeforeTableElement(pos));
708     Position result = positionAfterNode(pos.downstream().node());
709     if (result.isNull() || !result.node()->rootEditableElement())
710         return pos;
711     return result;
712 }
713
714 // This function is necessary because a VisiblePosition is allowed
715 // to be at the start or end of elements where we do not want to
716 // add content directly.  For example, clicking at the end of a hyperlink,
717 // then typing, needs to add the text after the link.  Also, table
718 // offset 0 and table offset childNodeCount are valid VisiblePostions,
719 // but we can not add more content right there... it needs to go before
720 // or after the table.
721 Position positionAvoidingSpecialElementBoundary(const Position &pos, bool avoidAnchor)
722 {
723     if (pos.isNull())
724         return pos;
725         
726     VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
727     Node* enclosingAnchor = enclosingNodeWithTag(pos.node(), aTag);
728     Position result;
729     if (enclosingAnchor) {
730         // If the caret is after an anchor, do insertion inside the anchor unless it's the last 
731         // VisiblePosition in the document, to match TextEdit.
732         if (VisiblePosition(Position(enclosingAnchor, maxDeepOffset(enclosingAnchor))) == vPos && (isEndOfDocument(vPos) || avoidAnchor))
733             result = positionAfterNode(enclosingAnchor);
734         // If the caret is before an anchor, do insertion outside the anchor unless it's the first
735         // VisiblePosition in a paragraph, to match TextEdit.
736         if (VisiblePosition(Position(enclosingAnchor, 0)) == vPos && (!isStartOfParagraph(vPos) || avoidAnchor))
737             result = positionBeforeNode(enclosingAnchor);
738     } else if (isTableElement(pos.node())) {
739         if (VisiblePosition(Position(pos.node(), maxDeepOffset(pos.node()))) == vPos)
740             result = positionAfterNode(pos.node());
741         if (VisiblePosition(Position(pos.node(), 0)) == vPos)
742             result = positionBeforeNode(pos.node());
743     } else
744         return pos;
745         
746     if (result.isNull() || !editableRootForPosition(result))
747         result = pos;
748     
749     return result;
750 }
751
752 PassRefPtr<Element> createDefaultParagraphElement(Document *document)
753 {
754     ExceptionCode ec = 0;
755     RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "div", ec);
756     ASSERT(ec == 0);
757     return element.release();
758 }
759
760 PassRefPtr<Element> createBreakElement(Document *document)
761 {
762     ExceptionCode ec = 0;
763     RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "br", ec);
764     ASSERT(ec == 0);
765     return breakNode.release();
766 }
767
768 PassRefPtr<Element> createOrderedListElement(Document *document)
769 {
770     ExceptionCode ec = 0;
771     RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "ol", ec);
772     ASSERT(ec == 0);
773     return element.release();
774 }
775
776 PassRefPtr<Element> createUnorderedListElement(Document *document)
777 {
778     ExceptionCode ec = 0;
779     RefPtr<Element> element = document->createElementNS(xhtmlNamespaceURI, "ul", ec);
780     ASSERT(ec == 0);
781     return element.release();
782 }
783
784 PassRefPtr<Element> createListItemElement(Document *document)
785 {
786     ExceptionCode ec = 0;
787     RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, "li", ec);
788     ASSERT(ec == 0);
789     return breakNode.release();
790 }
791
792 PassRefPtr<Element> createElement(Document* document, const String& tagName)
793 {
794     ExceptionCode ec = 0;
795     RefPtr<Element> breakNode = document->createElementNS(xhtmlNamespaceURI, tagName, ec);
796     ASSERT(ec == 0);
797     return breakNode.release();
798 }
799
800 bool isTabSpanNode(const Node *node)
801 {
802     return (node && node->isElementNode() && static_cast<const Element *>(node)->getAttribute("class") == AppleTabSpanClass);
803 }
804
805 bool isTabSpanTextNode(const Node *node)
806 {
807     return (node && node->parentNode() && isTabSpanNode(node->parentNode()));
808 }
809
810 Node *tabSpanNode(const Node *node)
811 {
812     return isTabSpanTextNode(node) ? node->parentNode() : 0;
813 }
814
815 Position positionBeforeTabSpan(const Position& pos)
816 {
817     Node *node = pos.node();
818     if (isTabSpanTextNode(node))
819         node = tabSpanNode(node);
820     else if (!isTabSpanNode(node))
821         return pos;
822     
823     return positionBeforeNode(node);
824 }
825
826 PassRefPtr<Element> createTabSpanElement(Document* document, PassRefPtr<Node> tabTextNode)
827 {
828     // make the span to hold the tab
829     ExceptionCode ec = 0;
830     RefPtr<Element> spanElement = document->createElementNS(xhtmlNamespaceURI, "span", ec);
831     assert(ec == 0);
832     spanElement->setAttribute(classAttr, AppleTabSpanClass);
833     spanElement->setAttribute(styleAttr, "white-space:pre");
834
835     // add tab text to that span
836     if (!tabTextNode)
837         tabTextNode = document->createEditingTextNode("\t");
838     spanElement->appendChild(tabTextNode, ec);
839     assert(ec == 0);
840
841     return spanElement.release();
842 }
843
844 PassRefPtr<Element> createTabSpanElement(Document* document, const String& tabText)
845 {
846     return createTabSpanElement(document, document->createTextNode(tabText));
847 }
848
849 PassRefPtr<Element> createTabSpanElement(Document* document)
850 {
851     return createTabSpanElement(document, PassRefPtr<Node>());
852 }
853
854 bool isNodeRendered(const Node *node)
855 {
856     if (!node)
857         return false;
858
859     RenderObject *renderer = node->renderer();
860     if (!renderer)
861         return false;
862
863     return renderer->style()->visibility() == VISIBLE;
864 }
865
866 Node *nearestMailBlockquote(const Node *node)
867 {
868     for (Node *n = const_cast<Node *>(node); n; n = n->parentNode()) {
869         if (isMailBlockquote(n))
870             return n;
871     }
872     return 0;
873 }
874
875 bool isMailBlockquote(const Node *node)
876 {
877     if (!node || !node->isElementNode() && !node->hasTagName(blockquoteTag))
878         return false;
879         
880     return static_cast<const Element *>(node)->getAttribute("type") == "cite";
881 }
882
883 } // namespace WebCore