2 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "core/editing/htmlediting.h"
29 #include "HTMLElementFactory.h"
30 #include "HTMLNames.h"
31 #include "bindings/v8/ExceptionState.h"
32 #include "bindings/v8/ExceptionStatePlaceholder.h"
33 #include "core/dom/Document.h"
34 #include "core/dom/NodeTraversal.h"
35 #include "core/dom/PositionIterator.h"
36 #include "core/dom/Range.h"
37 #include "core/dom/Text.h"
38 #include "core/dom/shadow/ShadowRoot.h"
39 #include "core/editing/Editor.h"
40 #include "core/editing/HTMLInterchange.h"
41 #include "core/editing/PlainTextRange.h"
42 #include "core/editing/TextIterator.h"
43 #include "core/editing/VisiblePosition.h"
44 #include "core/editing/VisibleSelection.h"
45 #include "core/editing/VisibleUnits.h"
46 #include "core/html/HTMLBRElement.h"
47 #include "core/html/HTMLDivElement.h"
48 #include "core/html/HTMLLIElement.h"
49 #include "core/html/HTMLOListElement.h"
50 #include "core/html/HTMLParagraphElement.h"
51 #include "core/html/HTMLUListElement.h"
52 #include "core/frame/Frame.h"
53 #include "core/rendering/RenderObject.h"
54 #include "wtf/Assertions.h"
55 #include "wtf/StdLibExtras.h"
56 #include "wtf/text/StringBuilder.h"
62 using namespace HTMLNames;
64 // Atomic means that the node has no children, or has children which are ignored for the
65 // purposes of editing.
66 bool isAtomicNode(const Node *node)
68 return node && (!node->hasChildNodes() || editingIgnoresContent(node));
71 // Compare two positions, taking into account the possibility that one or both
72 // could be inside a shadow tree. Only works for non-null values.
73 int comparePositions(const Position& a, const Position& b)
75 TreeScope* commonScope = commonTreeScope(a.containerNode(), b.containerNode());
81 Node* nodeA = commonScope->ancestorInThisScope(a.containerNode());
83 bool hasDescendentA = nodeA != a.containerNode();
84 int offsetA = hasDescendentA ? 0 : a.computeOffsetInContainerNode();
86 Node* nodeB = commonScope->ancestorInThisScope(b.containerNode());
88 bool hasDescendentB = nodeB != b.containerNode();
89 int offsetB = hasDescendentB ? 0 : b.computeOffsetInContainerNode();
95 else if (hasDescendentB)
99 int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB, IGNORE_EXCEPTION);
100 return result ? result : bias;
103 int comparePositions(const PositionWithAffinity& a, const PositionWithAffinity& b)
105 return comparePositions(a.position(), b.position());
108 int comparePositions(const VisiblePosition& a, const VisiblePosition& b)
110 return comparePositions(a.deepEquivalent(), b.deepEquivalent());
113 Node* highestEditableRoot(const Position& position, EditableType editableType)
115 Node* node = position.deprecatedNode();
119 Node* highestRoot = editableRootForPosition(position, editableType);
123 if (highestRoot->hasTagName(bodyTag))
126 node = highestRoot->parentNode();
128 if (node->rendererIsEditable(editableType))
130 if (node->hasTagName(bodyTag))
132 node = node->parentNode();
138 Node* lowestEditableAncestor(Node* node)
141 if (node->rendererIsEditable())
142 return node->rootEditableElement();
143 if (node->hasTagName(bodyTag))
145 node = node->parentNode();
151 bool isEditablePosition(const Position& p, EditableType editableType, EUpdateStyle updateStyle)
153 Node* node = p.deprecatedNode();
156 if (updateStyle == UpdateStyle)
157 node->document().updateLayoutIgnorePendingStylesheets();
159 ASSERT(updateStyle == DoNotUpdateStyle);
161 if (isRenderedTableElement(node))
162 node = node->parentNode();
164 return node->rendererIsEditable(editableType);
167 bool isAtUnsplittableElement(const Position& pos)
169 Node* node = pos.deprecatedNode();
170 return (node == editableRootForPosition(pos) || node == enclosingNodeOfType(pos, &isTableCell));
174 bool isRichlyEditablePosition(const Position& p, EditableType editableType)
176 Node* node = p.deprecatedNode();
180 if (isRenderedTableElement(node))
181 node = node->parentNode();
183 return node->rendererIsRichlyEditable(editableType);
186 Element* editableRootForPosition(const Position& p, EditableType editableType)
188 Node* node = p.containerNode();
192 if (isRenderedTableElement(node))
193 node = node->parentNode();
195 return node->rootEditableElement(editableType);
198 // Finds the enclosing element until which the tree can be split.
199 // When a user hits ENTER, he/she won't expect this element to be split into two.
200 // You may pass it as the second argument of splitTreeToNode.
201 Element* unsplittableElementForPosition(const Position& p)
203 // Since enclosingNodeOfType won't search beyond the highest root editable node,
204 // this code works even if the closest table cell was outside of the root editable node.
205 Element* enclosingCell = toElement(enclosingNodeOfType(p, &isTableCell));
207 return enclosingCell;
209 return editableRootForPosition(p);
212 Position nextCandidate(const Position& position)
214 PositionIterator p = position;
223 Position nextVisuallyDistinctCandidate(const Position& position)
225 Position p = position;
226 Position downstreamStart = p.downstream();
227 while (!p.atEndOfTree()) {
228 p = p.next(Character);
229 if (p.isCandidate() && p.downstream() != downstreamStart)
235 Position previousCandidate(const Position& position)
237 PositionIterator p = position;
238 while (!p.atStart()) {
246 Position previousVisuallyDistinctCandidate(const Position& position)
248 Position p = position;
249 Position downstreamStart = p.downstream();
250 while (!p.atStartOfTree()) {
251 p = p.previous(Character);
252 if (p.isCandidate() && p.downstream() != downstreamStart)
258 VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, Node* highestRoot)
260 // position falls before highestRoot.
261 if (comparePositions(position, firstPositionInNode(highestRoot)) == -1 && highestRoot->rendererIsEditable())
262 return firstPositionInNode(highestRoot);
264 Position p = position;
266 if (position.deprecatedNode()->treeScope() != highestRoot->treeScope()) {
267 Node* shadowAncestor = highestRoot->treeScope().ancestorInThisScope(p.deprecatedNode());
269 return VisiblePosition();
271 p = positionAfterNode(shadowAncestor);
274 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot))
275 p = isAtomicNode(p.deprecatedNode()) ? positionInParentAfterNode(p.deprecatedNode()) : nextVisuallyDistinctCandidate(p);
277 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecatedNode()->isDescendantOf(highestRoot))
278 return VisiblePosition();
280 return VisiblePosition(p);
283 VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, Node* highestRoot)
285 // When position falls after highestRoot, the result is easy to compute.
286 if (comparePositions(position, lastPositionInNode(highestRoot)) == 1)
287 return lastPositionInNode(highestRoot);
289 Position p = position;
291 if (position.deprecatedNode()->treeScope() != highestRoot->treeScope()) {
292 Node* shadowAncestor = highestRoot->treeScope().ancestorInThisScope(p.deprecatedNode());
294 return VisiblePosition();
296 p = firstPositionInOrBeforeNode(shadowAncestor);
299 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot))
300 p = isAtomicNode(p.deprecatedNode()) ? positionInParentBeforeNode(p.deprecatedNode()) : previousVisuallyDistinctCandidate(p);
302 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecatedNode()->isDescendantOf(highestRoot))
303 return VisiblePosition();
305 return VisiblePosition(p);
308 // FIXME: The method name, comment, and code say three different things here!
309 // Whether or not content before and after this node will collapse onto the same line as it.
310 bool isBlock(const Node* node)
312 return node && node->isElementNode() && node->renderer() && !node->renderer()->isInline() && !node->renderer()->isRubyText();
315 bool isInline(const Node* node)
317 return node && node->isElementNode() && node->renderer() && node->renderer()->isInline();
320 // FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlockFlowOrTableElement are used.
321 // FIXME: Pass a position to this function. The enclosing block of [table, x] for example, should be the
322 // block that contains the table and not the table, and this function should be the only one responsible for
323 // knowing about these kinds of special cases.
324 Element* enclosingBlock(Node* node, EditingBoundaryCrossingRule rule)
326 Node* enclosingNode = enclosingNodeOfType(firstPositionInOrBeforeNode(node), isBlock, rule);
327 return toElement(enclosingNode);
330 TextDirection directionOfEnclosingBlock(const Position& position)
332 Node* enclosingBlockNode = enclosingBlock(position.containerNode());
333 if (!enclosingBlockNode)
335 RenderObject* renderer = enclosingBlockNode->renderer();
336 return renderer ? renderer->style()->direction() : LTR;
339 // This method is used to create positions in the DOM. It returns the maximum valid offset
340 // in a node. It returns 1 for some elements even though they do not have children, which
341 // creates technically invalid DOM Positions. Be sure to call parentAnchoredEquivalent
342 // on a Position before using it to create a DOM Range, or an exception will be thrown.
343 int lastOffsetForEditing(const Node* node)
348 if (node->offsetInCharacters())
349 return node->maxCharacterOffset();
351 if (node->hasChildNodes())
352 return node->childNodeCount();
354 // NOTE: This should preempt the childNodeCount for, e.g., select nodes
355 if (editingIgnoresContent(node))
361 String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
363 unsigned length = string.length();
365 StringBuilder rebalancedString;
366 rebalancedString.reserveCapacity(length);
368 bool previousCharacterWasSpace = false;
369 for (size_t i = 0; i < length; i++) {
371 if (!isWhitespace(c)) {
372 rebalancedString.append(c);
373 previousCharacterWasSpace = false;
377 if (previousCharacterWasSpace || (!i && startIsStartOfParagraph) || (i + 1 == length && endIsEndOfParagraph)) {
378 rebalancedString.append(noBreakSpace);
379 previousCharacterWasSpace = false;
381 rebalancedString.append(' ');
382 previousCharacterWasSpace = true;
386 ASSERT(rebalancedString.length() == length);
388 return rebalancedString.toString();
391 bool isTableStructureNode(const Node *node)
393 RenderObject* renderer = node->renderer();
394 return (renderer && (renderer->isTableCell() || renderer->isTableRow() || renderer->isTableSection() || renderer->isRenderTableCol()));
397 const String& nonBreakingSpaceString()
399 DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1));
400 return nonBreakingSpaceString;
403 // FIXME: need to dump this
404 bool isSpecialElement(const Node *n)
409 if (!n->isHTMLElement())
415 RenderObject* renderer = n->renderer();
419 if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
422 if (renderer->style()->isFloating())
428 static Node* firstInSpecialElement(const Position& pos)
430 Node* rootEditableElement = pos.containerNode()->rootEditableElement();
431 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
432 if (isSpecialElement(n)) {
433 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
434 VisiblePosition firstInElement = VisiblePosition(firstPositionInOrBeforeNode(n), DOWNSTREAM);
435 if (isRenderedTable(n) && vPos == firstInElement.next())
437 if (vPos == firstInElement)
443 static Node* lastInSpecialElement(const Position& pos)
445 Node* rootEditableElement = pos.containerNode()->rootEditableElement();
446 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
447 if (isSpecialElement(n)) {
448 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
449 VisiblePosition lastInElement = VisiblePosition(lastPositionInOrAfterNode(n), DOWNSTREAM);
450 if (isRenderedTable(n) && vPos == lastInElement.previous())
452 if (vPos == lastInElement)
458 Position positionBeforeContainingSpecialElement(const Position& pos, Node** containingSpecialElement)
460 Node* n = firstInSpecialElement(pos);
463 Position result = positionInParentBeforeNode(n);
464 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos.deprecatedNode()->rootEditableElement())
466 if (containingSpecialElement)
467 *containingSpecialElement = n;
471 Position positionAfterContainingSpecialElement(const Position& pos, Node **containingSpecialElement)
473 Node* n = lastInSpecialElement(pos);
476 Position result = positionInParentAfterNode(n);
477 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos.deprecatedNode()->rootEditableElement())
479 if (containingSpecialElement)
480 *containingSpecialElement = n;
484 Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition)
486 Position upstream(visiblePosition.deepEquivalent().upstream());
487 if (isRenderedTable(upstream.deprecatedNode()) && upstream.atLastEditingPositionForNode())
488 return upstream.deprecatedNode();
493 Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition)
495 Position downstream(visiblePosition.deepEquivalent().downstream());
496 if (isRenderedTable(downstream.deprecatedNode()) && downstream.atFirstEditingPositionForNode())
497 return downstream.deprecatedNode();
502 // Returns the visible position at the beginning of a node
503 VisiblePosition visiblePositionBeforeNode(Node* node)
506 if (node->childNodeCount())
507 return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
508 ASSERT(node->parentNode());
509 ASSERT(!node->parentNode()->isShadowRoot());
510 return positionInParentBeforeNode(node);
513 // Returns the visible position at the ending of a node
514 VisiblePosition visiblePositionAfterNode(Node* node)
517 if (node->childNodeCount())
518 return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM);
519 ASSERT(node->parentNode());
520 ASSERT(!node->parentNode()->isShadowRoot());
521 return positionInParentAfterNode(node);
524 // Create a range object with two visible positions, start and end.
525 // create(Document*, const Position&, const Position&); will use deprecatedEditingOffset
526 // Use this function instead of create a regular range object (avoiding editing offset).
527 PassRefPtr<Range> createRange(Document& document, const VisiblePosition& start, const VisiblePosition& end, ExceptionState& exceptionState)
529 RefPtr<Range> selectedRange = Range::create(document);
530 selectedRange->setStart(start.deepEquivalent().containerNode(), start.deepEquivalent().computeOffsetInContainerNode(), exceptionState);
531 if (!exceptionState.hadException())
532 selectedRange->setEnd(end.deepEquivalent().containerNode(), end.deepEquivalent().computeOffsetInContainerNode(), exceptionState);
533 return selectedRange.release();
536 bool isListElement(Node *n)
538 return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
541 bool isListItem(const Node *n)
543 return n && n->renderer() && n->renderer()->isListItem();
546 Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
551 Node* root = highestEditableRoot(p);
552 for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
553 if (root && !n->rendererIsEditable())
555 if (n->hasTagName(tagName))
564 Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule)
566 // FIXME: support CanSkipCrossEditingBoundary
567 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
571 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0;
572 for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
573 // Don't return a non-editable node if the input position was editable, since
574 // the callers from editing will no doubt want to perform editing inside the returned node.
575 if (root && !n->rendererIsEditable())
586 Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule, Node* stayWithin)
589 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0;
590 for (Node* n = p.containerNode(); n && n != stayWithin; n = n->parentNode()) {
591 if (root && !n->rendererIsEditable())
602 static bool hasARenderedDescendant(Node* node, Node* excludedNode)
604 for (Node* n = node->firstChild(); n;) {
605 if (n == excludedNode) {
606 n = NodeTraversal::nextSkippingChildren(*n, node);
611 n = NodeTraversal::next(*n, node);
616 Node* highestNodeToRemoveInPruning(Node* node, Node* excludeNode)
618 Node* previousNode = 0;
619 Node* rootEditableElement = node ? node->rootEditableElement() : 0;
620 for (; node; node = node->parentNode()) {
621 if (RenderObject* renderer = node->renderer()) {
622 if (!renderer->canHaveChildren() || hasARenderedDescendant(node, previousNode) || rootEditableElement == node || excludeNode == node)
630 Node* enclosingTableCell(const Position& p)
632 return toElement(enclosingNodeOfType(p, isTableCell));
635 Element* enclosingAnchorElement(const Position& p)
640 Node* node = p.deprecatedNode();
641 while (node && !(node->isElementNode() && node->isLink()))
642 node = node->parentNode();
643 return toElement(node);
646 HTMLElement* enclosingList(Node* node)
651 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node));
653 for (ContainerNode* n = node->parentNode(); n; n = n->parentNode()) {
654 if (n->hasTagName(ulTag) || n->hasTagName(olTag))
655 return toHTMLElement(n);
663 Node* enclosingListChild(Node *node)
667 // Check for a list item element, or for a node whose parent is a list element. Such a node
668 // will appear visually as a list item (but without a list marker)
669 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node));
671 // FIXME: This function is inappropriately named if it starts with node instead of node->parentNode()
672 for (Node* n = node; n && n->parentNode(); n = n->parentNode()) {
673 if (n->hasTagName(liTag) || (isListElement(n->parentNode()) && n != root))
675 if (n == root || isTableCell(n))
682 // FIXME: This method should not need to call isStartOfParagraph/isEndOfParagraph
683 Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
685 // Check that position is on a line by itself inside a list item
686 Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().deprecatedNode());
687 if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
690 VisiblePosition firstInListChild(firstPositionInOrBeforeNode(listChildNode));
691 VisiblePosition lastInListChild(lastPositionInOrAfterNode(listChildNode));
693 if (firstInListChild != visiblePos || lastInListChild != visiblePos)
696 return listChildNode;
699 HTMLElement* outermostEnclosingList(Node* node, Node* rootList)
701 HTMLElement* list = enclosingList(node);
705 while (HTMLElement* nextList = enclosingList(list)) {
706 if (nextList == rootList)
714 bool canMergeLists(Element* firstList, Element* secondList)
716 if (!firstList || !secondList || !firstList->isHTMLElement() || !secondList->isHTMLElement())
719 return firstList->hasTagName(secondList->tagQName()) // make sure the list types match (ol vs. ul)
720 && firstList->rendererIsEditable() && secondList->rendererIsEditable() // both lists are editable
721 && firstList->rootEditableElement() == secondList->rootEditableElement() // don't cross editing boundaries
722 && isVisiblyAdjacent(positionInParentAfterNode(firstList), positionInParentBeforeNode(secondList));
723 // Make sure there is no visible content between this li and the previous list
726 bool isRenderedTableElement(const Node* node)
728 if (!node || !node->isElementNode())
731 return node->renderer() && node->hasTagName(tableTag);
734 bool isRenderedTable(const Node* node)
736 if (!node || !node->isElementNode())
739 RenderObject* renderer = node->renderer();
740 return (renderer && renderer->isTable());
743 bool isTableCell(const Node* node)
745 RenderObject* r = node->renderer();
747 return node->hasTagName(tdTag) || node->hasTagName(thTag);
749 return r->isTableCell();
752 bool isEmptyTableCell(const Node* node)
754 // Returns true IFF the passed in node is one of:
755 // .) a table cell with no children,
756 // .) a table cell with a single BR child, and which has no other child renderers, including :before and :after renderers
757 // .) the BR child of such a table cell
759 // Find rendered node
760 while (node && !node->renderer())
761 node = node->parentNode();
765 // Make sure the rendered node is a table cell or <br>.
766 // If it's a <br>, then the parent node has to be a table cell.
767 RenderObject* renderer = node->renderer();
768 if (renderer->isBR()) {
769 renderer = renderer->parent();
773 if (!renderer->isTableCell())
776 // Check that the table cell contains no child renderers except for perhaps a single <br>.
777 RenderObject* childRenderer = renderer->firstChild();
780 if (!childRenderer->isBR())
782 return !childRenderer->nextSibling();
785 PassRefPtr<HTMLElement> createDefaultParagraphElement(Document& document)
787 switch (document.frame()->editor().defaultParagraphSeparator()) {
788 case EditorParagraphSeparatorIsDiv:
789 return HTMLDivElement::create(document);
790 case EditorParagraphSeparatorIsP:
791 return HTMLParagraphElement::create(document);
794 ASSERT_NOT_REACHED();
798 PassRefPtr<HTMLElement> createBreakElement(Document& document)
800 return HTMLBRElement::create(document);
803 PassRefPtr<HTMLElement> createOrderedListElement(Document& document)
805 return HTMLOListElement::create(document);
808 PassRefPtr<HTMLElement> createUnorderedListElement(Document& document)
810 return HTMLUListElement::create(document);
813 PassRefPtr<HTMLElement> createListItemElement(Document& document)
815 return HTMLLIElement::create(document);
818 PassRefPtr<HTMLElement> createHTMLElement(Document& document, const QualifiedName& name)
820 return createHTMLElement(document, name.localName());
823 PassRefPtr<HTMLElement> createHTMLElement(Document& document, const AtomicString& tagName)
825 return HTMLElementFactory::createHTMLElement(tagName, document, 0, false);
828 bool isTabSpanNode(const Node *node)
830 return node && node->hasTagName(spanTag) && node->isElementNode() && toElement(node)->getAttribute(classAttr) == AppleTabSpanClass;
833 bool isTabSpanTextNode(const Node *node)
835 return node && node->isTextNode() && node->parentNode() && isTabSpanNode(node->parentNode());
838 Node* tabSpanNode(const Node *node)
840 return isTabSpanTextNode(node) ? node->parentNode() : 0;
843 PassRefPtr<Element> createTabSpanElement(Document& document, PassRefPtr<Node> prpTabTextNode)
845 RefPtr<Node> tabTextNode = prpTabTextNode;
847 // Make the span to hold the tab.
848 RefPtr<Element> spanElement = document.createElement(spanTag, false);
849 spanElement->setAttribute(classAttr, AppleTabSpanClass);
850 spanElement->setAttribute(styleAttr, "white-space:pre");
852 // Add tab text to that span.
854 tabTextNode = document.createEditingTextNode("\t");
856 spanElement->appendChild(tabTextNode.release());
858 return spanElement.release();
861 PassRefPtr<Element> createTabSpanElement(Document& document, const String& tabText)
863 return createTabSpanElement(document, document.createTextNode(tabText));
866 PassRefPtr<Element> createTabSpanElement(Document& document)
868 return createTabSpanElement(document, PassRefPtr<Node>());
871 bool isNodeRendered(const Node *node)
876 RenderObject* renderer = node->renderer();
880 return renderer->style()->visibility() == VISIBLE;
883 unsigned numEnclosingMailBlockquotes(const Position& p)
886 for (Node* n = p.deprecatedNode(); n; n = n->parentNode())
887 if (isMailBlockquote(n))
893 void updatePositionForNodeRemoval(Position& position, Node* node)
895 if (position.isNull())
897 switch (position.anchorType()) {
898 case Position::PositionIsBeforeChildren:
899 if (position.containerNode() == node)
900 position = positionInParentBeforeNode(node);
902 case Position::PositionIsAfterChildren:
903 if (position.containerNode() == node)
904 position = positionInParentAfterNode(node);
906 case Position::PositionIsOffsetInAnchor:
907 if (position.containerNode() == node->parentNode() && static_cast<unsigned>(position.offsetInContainerNode()) > node->nodeIndex())
908 position.moveToOffset(position.offsetInContainerNode() - 1);
909 else if (node->containsIncludingShadowDOM(position.containerNode()))
910 position = positionInParentBeforeNode(node);
912 case Position::PositionIsAfterAnchor:
913 if (node->containsIncludingShadowDOM(position.anchorNode()))
914 position = positionInParentAfterNode(node);
916 case Position::PositionIsBeforeAnchor:
917 if (node->containsIncludingShadowDOM(position.anchorNode()))
918 position = positionInParentBeforeNode(node);
923 bool isMailBlockquote(const Node *node)
925 if (!node || !node->hasTagName(blockquoteTag))
928 return toElement(node)->getAttribute("type") == "cite";
931 int caretMinOffset(const Node* n)
933 RenderObject* r = n->renderer();
934 ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
935 return r ? r->caretMinOffset() : 0;
938 // If a node can contain candidates for VisiblePositions, return the offset of the last candidate, otherwise
939 // return the number of children for container nodes and the length for unrendered text nodes.
940 int caretMaxOffset(const Node* n)
942 // For rendered text nodes, return the last position that a caret could occupy.
943 if (n->isTextNode() && n->renderer())
944 return n->renderer()->caretMaxOffset();
945 // For containers return the number of children. For others do the same as above.
946 return lastOffsetForEditing(n);
949 bool lineBreakExistsAtVisiblePosition(const VisiblePosition& visiblePosition)
951 return lineBreakExistsAtPosition(visiblePosition.deepEquivalent().downstream());
954 bool lineBreakExistsAtPosition(const Position& position)
956 if (position.isNull())
959 if (position.anchorNode()->hasTagName(brTag) && position.atFirstEditingPositionForNode())
962 if (!position.anchorNode()->renderer())
965 if (!position.anchorNode()->isTextNode() || !position.anchorNode()->renderer()->style()->preserveNewline())
968 Text* textNode = toText(position.anchorNode());
969 unsigned offset = position.offsetInContainerNode();
970 return offset < textNode->length() && textNode->data()[offset] == '\n';
973 // Modifies selections that have an end point at the edge of a table
974 // that contains the other endpoint so that they don't confuse
975 // code that iterates over selected paragraphs.
976 VisibleSelection selectionForParagraphIteration(const VisibleSelection& original)
978 VisibleSelection newSelection(original);
979 VisiblePosition startOfSelection(newSelection.visibleStart());
980 VisiblePosition endOfSelection(newSelection.visibleEnd());
982 // If the end of the selection to modify is just after a table, and
983 // if the start of the selection is inside that table, then the last paragraph
984 // that we'll want modify is the last one inside the table, not the table itself
985 // (a table is itself a paragraph).
986 if (Node* table = isFirstPositionAfterTable(endOfSelection))
987 if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
988 newSelection = VisibleSelection(startOfSelection, endOfSelection.previous(CannotCrossEditingBoundary));
990 // If the start of the selection to modify is just before a table,
991 // and if the end of the selection is inside that table, then the first paragraph
992 // we'll want to modify is the first one inside the table, not the paragraph
993 // containing the table itself.
994 if (Node* table = isLastPositionBeforeTable(startOfSelection))
995 if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
996 newSelection = VisibleSelection(startOfSelection.next(CannotCrossEditingBoundary), endOfSelection);
1001 // FIXME: indexForVisiblePosition and visiblePositionForIndex use TextIterators to convert between
1002 // VisiblePositions and indices. But TextIterator iteration using TextIteratorEmitsCharactersBetweenAllVisiblePositions
1003 // does not exactly match VisiblePosition iteration, so using them to preserve a selection during an editing
1004 // opertion is unreliable. TextIterator's TextIteratorEmitsCharactersBetweenAllVisiblePositions mode needs to be fixed,
1005 // or these functions need to be changed to iterate using actual VisiblePositions.
1006 // FIXME: Deploy these functions everywhere that TextIterators are used to convert between VisiblePositions and indices.
1007 int indexForVisiblePosition(const VisiblePosition& visiblePosition, RefPtr<ContainerNode>& scope)
1009 if (visiblePosition.isNull())
1012 Position p(visiblePosition.deepEquivalent());
1013 Document& document = *p.document();
1014 ShadowRoot* shadowRoot = p.anchorNode()->containingShadowRoot();
1019 scope = document.documentElement();
1021 RefPtr<Range> range = Range::create(document, firstPositionInNode(scope.get()), p.parentAnchoredEquivalent());
1023 return TextIterator::rangeLength(range.get(), true);
1026 VisiblePosition visiblePositionForIndex(int index, ContainerNode* scope)
1029 return VisiblePosition();
1030 RefPtr<Range> range = PlainTextRange(index).createRangeForSelection(*scope);
1031 // Check for an invalid index. Certain editing operations invalidate indices because
1032 // of problems with TextIteratorEmitsCharactersBetweenAllVisiblePositions.
1034 return VisiblePosition();
1035 return VisiblePosition(range->startPosition());
1038 // Determines whether two positions are visibly next to each other (first then second)
1039 // while ignoring whitespaces and unrendered nodes
1040 bool isVisiblyAdjacent(const Position& first, const Position& second)
1042 return VisiblePosition(first) == VisiblePosition(second.upstream());
1045 // Determines whether a node is inside a range or visibly starts and ends at the boundaries of the range.
1046 // Call this function to determine whether a node is visibly fit inside selectedRange
1047 bool isNodeVisiblyContainedWithin(Node* node, const Range* selectedRange)
1050 ASSERT(selectedRange);
1051 // If the node is inside the range, then it surely is contained within
1052 if (selectedRange->compareNode(node, IGNORE_EXCEPTION) == Range::NODE_INSIDE)
1055 bool startIsVisuallySame = visiblePositionBeforeNode(node) == selectedRange->startPosition();
1056 if (startIsVisuallySame && comparePositions(positionInParentAfterNode(node), selectedRange->endPosition()) < 0)
1059 bool endIsVisuallySame = visiblePositionAfterNode(node) == selectedRange->endPosition();
1060 if (endIsVisuallySame && comparePositions(selectedRange->startPosition(), positionInParentBeforeNode(node)) < 0)
1063 return startIsVisuallySame && endIsVisuallySame;
1066 bool isRenderedAsNonInlineTableImageOrHR(const Node* node)
1070 RenderObject* renderer = node->renderer();
1071 return renderer && ((renderer->isTable() && !renderer->isInline()) || (renderer->isImage() && !renderer->isInline()) || renderer->isHR());
1074 bool areIdenticalElements(const Node* first, const Node* second)
1076 if (!first->isElementNode() || !second->isElementNode())
1079 const Element* firstElement = toElement(first);
1080 const Element* secondElement = toElement(second);
1081 if (!firstElement->hasTagName(secondElement->tagQName()))
1084 return firstElement->hasEquivalentAttributes(secondElement);
1087 bool isNonTableCellHTMLBlockElement(const Node* node)
1089 return node->hasTagName(listingTag)
1090 || node->hasTagName(olTag)
1091 || node->hasTagName(preTag)
1092 || node->hasTagName(tableTag)
1093 || node->hasTagName(ulTag)
1094 || node->hasTagName(xmpTag)
1095 || node->hasTagName(h1Tag)
1096 || node->hasTagName(h2Tag)
1097 || node->hasTagName(h3Tag)
1098 || node->hasTagName(h4Tag)
1099 || node->hasTagName(h5Tag);
1102 Position adjustedSelectionStartForStyleComputation(const VisibleSelection& selection)
1104 // This function is used by range style computations to avoid bugs like:
1105 // <rdar://problem/4017641> REGRESSION (Mail): you can only bold/unbold a selection starting from end of line once
1106 // It is important to skip certain irrelevant content at the start of the selection, so we do not wind up
1107 // with a spurious "mixed" style.
1109 VisiblePosition visiblePosition = selection.start();
1110 if (visiblePosition.isNull())
1113 // if the selection is a caret, just return the position, since the style
1114 // behind us is relevant
1115 if (selection.isCaret())
1116 return visiblePosition.deepEquivalent();
1118 // if the selection starts just before a paragraph break, skip over it
1119 if (isEndOfParagraph(visiblePosition))
1120 return visiblePosition.next().deepEquivalent().downstream();
1122 // otherwise, make sure to be at the start of the first selected node,
1123 // instead of possibly at the end of the last node before the selection
1124 return visiblePosition.deepEquivalent().downstream();
1127 } // namespace WebCore