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 "htmlediting.h"
29 #include "AXObjectCache.h"
32 #include "ExceptionCodePlaceholder.h"
34 #include "HTMLBRElement.h"
35 #include "HTMLDivElement.h"
36 #include "HTMLElementFactory.h"
37 #include "HTMLInterchange.h"
38 #include "HTMLLIElement.h"
39 #include "HTMLNames.h"
40 #include "HTMLOListElement.h"
41 #include "HTMLObjectElement.h"
42 #include "HTMLParagraphElement.h"
43 #include "HTMLTableElement.h"
44 #include "HTMLTextFormControlElement.h"
45 #include "HTMLUListElement.h"
46 #include "NodeTraversal.h"
47 #include "PositionIterator.h"
49 #include "RenderElement.h"
50 #include "ShadowRoot.h"
52 #include "TextIterator.h"
53 #include "VisiblePosition.h"
54 #include "VisibleSelection.h"
55 #include "VisibleUnits.h"
56 #include <wtf/Assertions.h>
57 #include <wtf/StdLibExtras.h>
58 #include <wtf/unicode/CharacterNames.h>
64 using namespace HTMLNames;
66 // Atomic means that the node has no children, or has children which are ignored for the
67 // purposes of editing.
68 bool isAtomicNode(const Node *node)
70 return node && (!node->hasChildNodes() || editingIgnoresContent(node));
73 // Compare two positions, taking into account the possibility that one or both
74 // could be inside a shadow tree. Only works for non-null values.
75 int comparePositions(const Position& a, const Position& b)
77 TreeScope* commonScope = commonTreeScope(a.containerNode(), b.containerNode());
83 Node* nodeA = commonScope->ancestorInThisScope(a.containerNode());
85 bool hasDescendentA = nodeA != a.containerNode();
86 int offsetA = hasDescendentA ? 0 : a.computeOffsetInContainerNode();
88 Node* nodeB = commonScope->ancestorInThisScope(b.containerNode());
90 bool hasDescendentB = nodeB != b.containerNode();
91 int offsetB = hasDescendentB ? 0 : b.computeOffsetInContainerNode();
97 else if (hasDescendentB)
101 int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB, IGNORE_EXCEPTION);
102 return result ? result : bias;
105 int comparePositions(const VisiblePosition& a, const VisiblePosition& b)
107 return comparePositions(a.deepEquivalent(), b.deepEquivalent());
110 Node* highestEditableRoot(const Position& position, EditableType editableType)
112 Node* node = position.deprecatedNode();
116 Node* highestEditableRoot = editableRootForPosition(position, editableType);
117 if (!highestEditableRoot)
120 node = highestEditableRoot;
121 while (!node->hasTagName(bodyTag)) {
122 node = node->parentNode();
125 if (node->rendererIsEditable(editableType))
126 highestEditableRoot = node;
129 return highestEditableRoot;
132 Node* lowestEditableAncestor(Node* node)
138 if (node->rendererIsEditable())
139 return node->rootEditableElement();
140 if (node->hasTagName(bodyTag))
142 node = node->parentNode();
148 bool isEditablePosition(const Position& p, EditableType editableType, EUpdateStyle updateStyle)
150 Node* node = p.deprecatedNode();
153 if (updateStyle == UpdateStyle)
154 node->document().updateLayoutIgnorePendingStylesheets();
156 ASSERT(updateStyle == DoNotUpdateStyle);
158 if (node->renderer() && node->renderer()->isTable())
159 node = node->parentNode();
161 return node->rendererIsEditable(editableType);
164 bool isAtUnsplittableElement(const Position& pos)
166 Node* node = pos.deprecatedNode();
167 return (node == editableRootForPosition(pos) || node == enclosingNodeOfType(pos, &isTableCell));
171 bool isRichlyEditablePosition(const Position& p, EditableType editableType)
173 Node* node = p.deprecatedNode();
177 if (node->renderer() && node->renderer()->isTable())
178 node = node->parentNode();
180 return node->rendererIsRichlyEditable(editableType);
183 Element* editableRootForPosition(const Position& p, EditableType editableType)
185 Node* node = p.containerNode();
189 if (node->renderer() && node->renderer()->isTable())
190 node = node->parentNode();
192 return node->rootEditableElement(editableType);
195 // Finds the enclosing element until which the tree can be split.
196 // When a user hits ENTER, he/she won't expect this element to be split into two.
197 // You may pass it as the second argument of splitTreeToNode.
198 Element* unsplittableElementForPosition(const Position& p)
200 // Since enclosingNodeOfType won't search beyond the highest root editable node,
201 // this code works even if the closest table cell was outside of the root editable node.
202 Element* enclosingCell = toElement(enclosingNodeOfType(p, &isTableCell));
204 return enclosingCell;
206 return editableRootForPosition(p);
209 Position nextCandidate(const Position& position)
211 PositionIterator p = position;
220 Position nextVisuallyDistinctCandidate(const Position& position)
222 Position p = position;
223 Position downstreamStart = p.downstream();
224 while (!p.atEndOfTree()) {
225 p = p.next(Character);
226 if (p.isCandidate() && p.downstream() != downstreamStart)
232 Position previousCandidate(const Position& position)
234 PositionIterator p = position;
235 while (!p.atStart()) {
243 Position previousVisuallyDistinctCandidate(const Position& position)
245 Position p = position;
246 Position downstreamStart = p.downstream();
247 while (!p.atStartOfTree()) {
248 p = p.previous(Character);
249 if (p.isCandidate() && p.downstream() != downstreamStart)
255 VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& position, Node* highestRoot)
257 // position falls before highestRoot.
258 if (comparePositions(position, firstPositionInNode(highestRoot)) == -1 && highestRoot->rendererIsEditable())
259 return firstPositionInNode(highestRoot);
261 Position p = position;
263 if (&position.deprecatedNode()->treeScope() != &highestRoot->treeScope()) {
264 Node* shadowAncestor = highestRoot->treeScope().ancestorInThisScope(p.deprecatedNode());
266 return VisiblePosition();
268 p = positionAfterNode(shadowAncestor);
271 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot))
272 p = isAtomicNode(p.deprecatedNode()) ? positionInParentAfterNode(p.deprecatedNode()) : nextVisuallyDistinctCandidate(p);
274 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecatedNode()->isDescendantOf(highestRoot))
275 return VisiblePosition();
277 return VisiblePosition(p);
280 VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& position, Node* highestRoot)
282 // When position falls after highestRoot, the result is easy to compute.
283 if (comparePositions(position, lastPositionInNode(highestRoot)) == 1)
284 return lastPositionInNode(highestRoot);
286 Position p = position;
288 if (&position.deprecatedNode()->treeScope() != &highestRoot->treeScope()) {
289 Node* shadowAncestor = highestRoot->treeScope().ancestorInThisScope(p.deprecatedNode());
291 return VisiblePosition();
293 p = firstPositionInOrBeforeNode(shadowAncestor);
296 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->isDescendantOf(highestRoot))
297 p = isAtomicNode(p.deprecatedNode()) ? positionInParentBeforeNode(p.deprecatedNode()) : previousVisuallyDistinctCandidate(p);
299 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecatedNode()->isDescendantOf(highestRoot))
300 return VisiblePosition();
302 return VisiblePosition(p);
305 // FIXME: The method name, comment, and code say three different things here!
306 // Whether or not content before and after this node will collapse onto the same line as it.
307 bool isBlock(const Node* node)
309 return node && node->renderer() && !node->renderer()->isInline() && !node->renderer()->isRubyText();
312 bool isInline(const Node* node)
314 return node && node->renderer() && node->renderer()->isInline();
317 // FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlockFlowOrTableElement are used.
318 // FIXME: Pass a position to this function. The enclosing block of [table, x] for example, should be the
319 // block that contains the table and not the table, and this function should be the only one responsible for
320 // knowing about these kinds of special cases.
321 Element* enclosingBlock(Node* node, EditingBoundaryCrossingRule rule)
323 Node* enclosingNode = enclosingNodeOfType(firstPositionInOrBeforeNode(node), isBlock, rule);
324 return enclosingNode && enclosingNode->isElementNode() ? toElement(enclosingNode) : 0;
327 TextDirection directionOfEnclosingBlock(const Position& position)
329 auto block = enclosingBlock(position.containerNode());
332 auto renderer = block->renderer();
335 return renderer->style()->direction();
338 // This method is used to create positions in the DOM. It returns the maximum valid offset
339 // in a node. It returns 1 for some elements even though they do not have children, which
340 // creates technically invalid DOM Positions. Be sure to call parentAnchoredEquivalent
341 // on a Position before using it to create a DOM Range, or an exception will be thrown.
342 int lastOffsetForEditing(const Node* node)
347 if (node->offsetInCharacters())
348 return node->maxCharacterOffset();
350 if (node->hasChildNodes())
351 return node->childNodeCount();
353 // NOTE: This should preempt the childNodeCount for, e.g., select nodes
354 if (editingIgnoresContent(node))
360 String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
362 Vector<UChar> rebalancedString;
363 append(rebalancedString, string);
365 bool previousCharacterWasSpace = false;
366 for (size_t i = 0; i < rebalancedString.size(); i++) {
367 if (!isWhitespace(rebalancedString[i])) {
368 previousCharacterWasSpace = false;
372 if (previousCharacterWasSpace || (!i && startIsStartOfParagraph) || (i + 1 == rebalancedString.size() && endIsEndOfParagraph)) {
373 rebalancedString[i] = noBreakSpace;
374 previousCharacterWasSpace = false;
376 rebalancedString[i] = ' ';
377 previousCharacterWasSpace = true;
382 return String::adopt(rebalancedString);
385 bool isTableStructureNode(const Node *node)
387 RenderObject* renderer = node->renderer();
388 return (renderer && (renderer->isTableCell() || renderer->isTableRow() || renderer->isTableSection() || renderer->isRenderTableCol()));
391 const String& nonBreakingSpaceString()
393 DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1));
394 return nonBreakingSpaceString;
397 // FIXME: need to dump this
398 bool isSpecialElement(const Node *n)
403 if (!n->isHTMLElement())
409 RenderObject* renderer = n->renderer();
413 if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
416 if (renderer->style()->isFloating())
419 if (renderer->style()->position() != StaticPosition)
425 static Node* firstInSpecialElement(const Position& pos)
427 Node* rootEditableElement = pos.containerNode()->rootEditableElement();
428 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
429 if (isSpecialElement(n)) {
430 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
431 VisiblePosition firstInElement = VisiblePosition(firstPositionInOrBeforeNode(n), DOWNSTREAM);
432 if (isTableElement(n) && vPos == firstInElement.next())
434 if (vPos == firstInElement)
440 static Node* lastInSpecialElement(const Position& pos)
442 Node* rootEditableElement = pos.containerNode()->rootEditableElement();
443 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
444 if (isSpecialElement(n)) {
445 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
446 VisiblePosition lastInElement = VisiblePosition(lastPositionInOrAfterNode(n), DOWNSTREAM);
447 if (isTableElement(n) && vPos == lastInElement.previous())
449 if (vPos == lastInElement)
455 bool isFirstVisiblePositionInSpecialElement(const Position& pos)
457 return firstInSpecialElement(pos);
460 Position positionBeforeContainingSpecialElement(const Position& pos, Node** containingSpecialElement)
462 Node* n = firstInSpecialElement(pos);
465 Position result = positionInParentBeforeNode(n);
466 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos.deprecatedNode()->rootEditableElement())
468 if (containingSpecialElement)
469 *containingSpecialElement = n;
473 bool isLastVisiblePositionInSpecialElement(const Position& pos)
475 return lastInSpecialElement(pos);
478 Position positionAfterContainingSpecialElement(const Position& pos, Node **containingSpecialElement)
480 Node* n = lastInSpecialElement(pos);
483 Position result = positionInParentAfterNode(n);
484 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos.deprecatedNode()->rootEditableElement())
486 if (containingSpecialElement)
487 *containingSpecialElement = n;
491 Position positionOutsideContainingSpecialElement(const Position &pos, Node **containingSpecialElement)
493 if (isFirstVisiblePositionInSpecialElement(pos))
494 return positionBeforeContainingSpecialElement(pos, containingSpecialElement);
495 if (isLastVisiblePositionInSpecialElement(pos))
496 return positionAfterContainingSpecialElement(pos, containingSpecialElement);
500 Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition)
502 Position upstream(visiblePosition.deepEquivalent().upstream());
503 if (upstream.deprecatedNode() && upstream.deprecatedNode()->renderer() && upstream.deprecatedNode()->renderer()->isTable() && upstream.atLastEditingPositionForNode())
504 return upstream.deprecatedNode();
509 Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition)
511 Position downstream(visiblePosition.deepEquivalent().downstream());
512 if (downstream.deprecatedNode() && downstream.deprecatedNode()->renderer() && downstream.deprecatedNode()->renderer()->isTable() && downstream.atFirstEditingPositionForNode())
513 return downstream.deprecatedNode();
518 // Returns the visible position at the beginning of a node
519 VisiblePosition visiblePositionBeforeNode(Node* node)
522 if (node->childNodeCount())
523 return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
524 ASSERT(node->parentNode());
525 ASSERT(!node->parentNode()->isShadowRoot());
526 return positionInParentBeforeNode(node);
529 // Returns the visible position at the ending of a node
530 VisiblePosition visiblePositionAfterNode(Node* node)
533 if (node->childNodeCount())
534 return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM);
535 ASSERT(node->parentNode());
536 ASSERT(!node->parentNode()->isShadowRoot());
537 return positionInParentAfterNode(node);
540 bool isListElement(Node *n)
542 return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
545 bool isListItem(const Node *n)
547 return n && n->renderer() && n->renderer()->isListItem();
550 Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
555 Node* root = highestEditableRoot(p);
556 for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
557 if (root && !n->rendererIsEditable())
559 if (n->hasTagName(tagName))
568 Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule)
570 // FIXME: support CanSkipCrossEditingBoundary
571 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
575 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0;
576 for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
577 // Don't return a non-editable node if the input position was editable, since
578 // the callers from editing will no doubt want to perform editing inside the returned node.
579 if (root && !n->rendererIsEditable())
590 Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule, Node* stayWithin)
593 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0;
594 for (Node* n = p.containerNode(); n && n != stayWithin; n = n->parentNode()) {
595 if (root && !n->rendererIsEditable())
606 static bool hasARenderedDescendant(Node* node, Node* excludedNode)
608 for (Node* n = node->firstChild(); n;) {
609 if (n == excludedNode) {
610 n = NodeTraversal::nextSkippingChildren(n, node);
615 n = NodeTraversal::next(n, node);
620 Node* highestNodeToRemoveInPruning(Node* node)
622 Node* previousNode = 0;
623 Node* rootEditableElement = node ? node->rootEditableElement() : 0;
624 for (; node; node = node->parentNode()) {
625 if (RenderObject* renderer = node->renderer()) {
626 if (!renderer->canHaveChildren() || hasARenderedDescendant(node, previousNode) || rootEditableElement == node)
634 Node* enclosingTableCell(const Position& p)
636 return toElement(enclosingNodeOfType(p, isTableCell));
639 Element* enclosingAnchorElement(const Position& p)
644 for (Node* node = p.deprecatedNode(); node; node = node->parentNode()) {
645 if (node->isElementNode() && node->isLink())
646 return toElement(node);
651 HTMLElement* enclosingList(Node* node)
656 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node));
658 for (ContainerNode* n = node->parentNode(); n; n = n->parentNode()) {
659 if (n->hasTagName(ulTag) || n->hasTagName(olTag))
660 return toHTMLElement(n);
668 Node* enclosingListChild(Node *node)
672 // Check for a list item element, or for a node whose parent is a list element. Such a node
673 // will appear visually as a list item (but without a list marker)
674 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node));
676 // FIXME: This function is inappropriately named if it starts with node instead of node->parentNode()
677 for (Node* n = node; n && n->parentNode(); n = n->parentNode()) {
678 if (n->hasTagName(liTag) || (isListElement(n->parentNode()) && n != root))
680 if (n == root || isTableCell(n))
687 static HTMLElement* embeddedSublist(Node* listItem)
689 // Check the DOM so that we'll find collapsed sublists without renderers.
690 for (Node* n = listItem->firstChild(); n; n = n->nextSibling()) {
691 if (isListElement(n))
692 return toHTMLElement(n);
698 static Node* appendedSublist(Node* listItem)
700 // Check the DOM so that we'll find collapsed sublists without renderers.
701 for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) {
702 if (isListElement(n))
703 return toHTMLElement(n);
704 if (isListItem(listItem))
711 // FIXME: This method should not need to call isStartOfParagraph/isEndOfParagraph
712 Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
714 // Check that position is on a line by itself inside a list item
715 Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().deprecatedNode());
716 if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
719 VisiblePosition firstInListChild(firstPositionInOrBeforeNode(listChildNode));
720 VisiblePosition lastInListChild(lastPositionInOrAfterNode(listChildNode));
722 if (firstInListChild != visiblePos || lastInListChild != visiblePos)
725 if (embeddedSublist(listChildNode) || appendedSublist(listChildNode))
728 return listChildNode;
731 HTMLElement* outermostEnclosingList(Node* node, Node* rootList)
733 HTMLElement* list = enclosingList(node);
737 while (HTMLElement* nextList = enclosingList(list)) {
738 if (nextList == rootList)
746 bool canMergeLists(Element* firstList, Element* secondList)
748 if (!firstList || !secondList || !firstList->isHTMLElement() || !secondList->isHTMLElement())
751 return firstList->hasTagName(secondList->tagQName()) // make sure the list types match (ol vs. ul)
752 && firstList->rendererIsEditable() && secondList->rendererIsEditable() // both lists are editable
753 && firstList->rootEditableElement() == secondList->rootEditableElement() // don't cross editing boundaries
754 && isVisiblyAdjacent(positionInParentAfterNode(firstList), positionInParentBeforeNode(secondList));
755 // Make sure there is no visible content between this li and the previous list
758 Node* highestAncestor(Node* node)
762 while ((node = node->parentNode()))
767 static Node* previousNodeConsideringAtomicNodes(const Node* node)
769 if (node->previousSibling()) {
770 Node* n = node->previousSibling();
771 while (!isAtomicNode(n) && n->lastChild())
775 if (node->parentNode())
776 return node->parentNode();
780 static Node* nextNodeConsideringAtomicNodes(const Node* node)
782 if (!isAtomicNode(node) && node->firstChild())
783 return node->firstChild();
784 if (node->nextSibling())
785 return node->nextSibling();
786 const Node* n = node;
787 while (n && !n->nextSibling())
790 return n->nextSibling();
794 Node* previousLeafNode(const Node* node)
796 Node* n = previousNodeConsideringAtomicNodes(node);
800 n = previousNodeConsideringAtomicNodes(n);
805 Node* nextLeafNode(const Node* node)
807 Node* n = nextNodeConsideringAtomicNodes(node);
811 n = nextNodeConsideringAtomicNodes(n);
816 // FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable()
817 bool isTableElement(Node* n)
819 if (!n || !n->isElementNode())
822 RenderObject* renderer = n->renderer();
823 return (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE));
826 bool isTableCell(const Node* node)
828 RenderObject* r = node->renderer();
830 return node->hasTagName(tdTag) || node->hasTagName(thTag);
832 return r->isTableCell();
835 bool isEmptyTableCell(const Node* node)
837 // Returns true IFF the passed in node is one of:
838 // .) a table cell with no children,
839 // .) a table cell with a single BR child, and which has no other child renderers, including :before and :after renderers
840 // .) the BR child of such a table cell
842 // Find rendered node
843 while (node && !node->renderer())
844 node = node->parentNode();
848 // Make sure the rendered node is a table cell or <br>.
849 // If it's a <br>, then the parent node has to be a table cell.
850 RenderObject* renderer = node->renderer();
851 if (renderer->isBR()) {
852 renderer = renderer->parent();
856 if (!renderer->isTableCell())
859 // Check that the table cell contains no child renderers except for perhaps a single <br>.
860 RenderObject* childRenderer = toRenderElement(renderer)->firstChild();
863 if (!childRenderer->isBR())
865 return !childRenderer->nextSibling();
868 PassRefPtr<HTMLElement> createDefaultParagraphElement(Document& document)
870 switch (document.frame()->editor().defaultParagraphSeparator()) {
871 case EditorParagraphSeparatorIsDiv:
872 return HTMLDivElement::create(document);
873 case EditorParagraphSeparatorIsP:
874 return HTMLParagraphElement::create(document);
877 ASSERT_NOT_REACHED();
881 PassRefPtr<HTMLElement> createBreakElement(Document& document)
883 return HTMLBRElement::create(document);
886 PassRefPtr<HTMLElement> createOrderedListElement(Document& document)
888 return HTMLOListElement::create(document);
891 PassRefPtr<HTMLElement> createUnorderedListElement(Document& document)
893 return HTMLUListElement::create(document);
896 PassRefPtr<HTMLElement> createListItemElement(Document& document)
898 return HTMLLIElement::create(document);
901 PassRefPtr<HTMLElement> createHTMLElement(Document& document, const QualifiedName& name)
903 return HTMLElementFactory::createElement(name, document);
906 PassRefPtr<HTMLElement> createHTMLElement(Document& document, const AtomicString& tagName)
908 return createHTMLElement(document, QualifiedName(nullAtom, tagName, xhtmlNamespaceURI));
911 bool isTabSpanNode(const Node *node)
913 return node && node->hasTagName(spanTag) && node->isElementNode() && static_cast<const Element *>(node)->getAttribute(classAttr) == AppleTabSpanClass;
916 bool isTabSpanTextNode(const Node *node)
918 return node && node->isTextNode() && node->parentNode() && isTabSpanNode(node->parentNode());
921 Node* tabSpanNode(const Node *node)
923 return isTabSpanTextNode(node) ? node->parentNode() : 0;
926 Position positionOutsideTabSpan(const Position& pos)
928 Node* node = pos.containerNode();
929 if (isTabSpanTextNode(node))
930 node = tabSpanNode(node);
931 else if (!isTabSpanNode(node))
934 if (node && VisiblePosition(pos) == lastPositionInNode(node))
935 return positionInParentAfterNode(node);
937 return positionInParentBeforeNode(node);
940 PassRefPtr<Element> createTabSpanElement(Document& document, PassRefPtr<Node> prpTabTextNode)
942 RefPtr<Node> tabTextNode = prpTabTextNode;
944 // Make the span to hold the tab.
945 RefPtr<Element> spanElement = document.createElement(spanTag, false);
946 spanElement->setAttribute(classAttr, AppleTabSpanClass);
947 spanElement->setAttribute(styleAttr, "white-space:pre");
949 // Add tab text to that span.
951 tabTextNode = document.createEditingTextNode("\t");
953 spanElement->appendChild(tabTextNode.release(), ASSERT_NO_EXCEPTION);
955 return spanElement.release();
958 PassRefPtr<Element> createTabSpanElement(Document& document, const String& tabText)
960 return createTabSpanElement(document, document.createTextNode(tabText));
963 PassRefPtr<Element> createTabSpanElement(Document& document)
965 return createTabSpanElement(document, PassRefPtr<Node>());
968 bool isNodeRendered(const Node* node)
973 RenderObject* renderer = node->renderer();
977 return renderer->style()->visibility() == VISIBLE;
980 unsigned numEnclosingMailBlockquotes(const Position& p)
983 for (Node* n = p.deprecatedNode(); n; n = n->parentNode())
984 if (isMailBlockquote(n))
990 void updatePositionForNodeRemoval(Position& position, Node* node)
992 if (position.isNull())
994 switch (position.anchorType()) {
995 case Position::PositionIsBeforeChildren:
996 if (position.containerNode() == node)
997 position = positionInParentBeforeNode(node);
999 case Position::PositionIsAfterChildren:
1000 if (position.containerNode() == node)
1001 position = positionInParentAfterNode(node);
1003 case Position::PositionIsOffsetInAnchor:
1004 if (position.containerNode() == node->parentNode() && static_cast<unsigned>(position.offsetInContainerNode()) > node->nodeIndex())
1005 position.moveToOffset(position.offsetInContainerNode() - 1);
1006 else if (node->containsIncludingShadowDOM(position.containerNode()))
1007 position = positionInParentBeforeNode(node);
1009 case Position::PositionIsAfterAnchor:
1010 if (node->containsIncludingShadowDOM(position.anchorNode()))
1011 position = positionInParentAfterNode(node);
1013 case Position::PositionIsBeforeAnchor:
1014 if (node->containsIncludingShadowDOM(position.anchorNode()))
1015 position = positionInParentBeforeNode(node);
1020 bool isMailBlockquote(const Node *node)
1022 if (!node || !node->hasTagName(blockquoteTag))
1025 return static_cast<const Element *>(node)->getAttribute("type") == "cite";
1028 int caretMinOffset(const Node* n)
1030 RenderObject* r = n->renderer();
1031 ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
1032 return r ? r->caretMinOffset() : 0;
1035 // If a node can contain candidates for VisiblePositions, return the offset of the last candidate, otherwise
1036 // return the number of children for container nodes and the length for unrendered text nodes.
1037 int caretMaxOffset(const Node* n)
1039 // For rendered text nodes, return the last position that a caret could occupy.
1040 if (n->isTextNode() && n->renderer())
1041 return n->renderer()->caretMaxOffset();
1042 // For containers return the number of children. For others do the same as above.
1043 return lastOffsetForEditing(n);
1046 bool lineBreakExistsAtVisiblePosition(const VisiblePosition& visiblePosition)
1048 return lineBreakExistsAtPosition(visiblePosition.deepEquivalent().downstream());
1051 bool lineBreakExistsAtPosition(const Position& position)
1053 if (position.isNull())
1056 if (position.anchorNode()->hasTagName(brTag) && position.atFirstEditingPositionForNode())
1059 if (!position.anchorNode()->renderer())
1062 if (!position.anchorNode()->isTextNode() || !position.anchorNode()->renderer()->style()->preserveNewline())
1065 Text* textNode = toText(position.anchorNode());
1066 unsigned offset = position.offsetInContainerNode();
1067 return offset < textNode->length() && textNode->data()[offset] == '\n';
1070 // Modifies selections that have an end point at the edge of a table
1071 // that contains the other endpoint so that they don't confuse
1072 // code that iterates over selected paragraphs.
1073 VisibleSelection selectionForParagraphIteration(const VisibleSelection& original)
1075 VisibleSelection newSelection(original);
1076 VisiblePosition startOfSelection(newSelection.visibleStart());
1077 VisiblePosition endOfSelection(newSelection.visibleEnd());
1079 // If the end of the selection to modify is just after a table, and
1080 // if the start of the selection is inside that table, then the last paragraph
1081 // that we'll want modify is the last one inside the table, not the table itself
1082 // (a table is itself a paragraph).
1083 if (Node* table = isFirstPositionAfterTable(endOfSelection))
1084 if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
1085 newSelection = VisibleSelection(startOfSelection, endOfSelection.previous(CannotCrossEditingBoundary));
1087 // If the start of the selection to modify is just before a table,
1088 // and if the end of the selection is inside that table, then the first paragraph
1089 // we'll want to modify is the first one inside the table, not the paragraph
1090 // containing the table itself.
1091 if (Node* table = isLastPositionBeforeTable(startOfSelection))
1092 if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
1093 newSelection = VisibleSelection(startOfSelection.next(CannotCrossEditingBoundary), endOfSelection);
1095 return newSelection;
1098 // FIXME: indexForVisiblePosition and visiblePositionForIndex use TextIterators to convert between
1099 // VisiblePositions and indices. But TextIterator iteration using TextIteratorEmitsCharactersBetweenAllVisiblePositions
1100 // does not exactly match VisiblePosition iteration, so using them to preserve a selection during an editing
1101 // opertion is unreliable. TextIterator's TextIteratorEmitsCharactersBetweenAllVisiblePositions mode needs to be fixed,
1102 // or these functions need to be changed to iterate using actual VisiblePositions.
1103 // FIXME: Deploy these functions everywhere that TextIterators are used to convert between VisiblePositions and indices.
1104 int indexForVisiblePosition(const VisiblePosition& visiblePosition, RefPtr<ContainerNode>& scope)
1106 if (visiblePosition.isNull())
1109 Position p(visiblePosition.deepEquivalent());
1110 Document& document = p.anchorNode()->document();
1111 ShadowRoot* shadowRoot = p.anchorNode()->containingShadowRoot();
1116 scope = document.documentElement();
1118 RefPtr<Range> range = Range::create(document, firstPositionInNode(scope.get()), p.parentAnchoredEquivalent());
1119 return TextIterator::rangeLength(range.get(), true);
1122 // FIXME: Merge these two functions.
1123 int indexForVisiblePosition(Node* node, const VisiblePosition& visiblePosition, bool forSelectionPreservation)
1126 RefPtr<Range> range = Range::create(node->document(), firstPositionInNode(node), visiblePosition.deepEquivalent().parentAnchoredEquivalent());
1127 return TextIterator::rangeLength(range.get(), forSelectionPreservation);
1130 VisiblePosition visiblePositionForIndex(int index, ContainerNode* scope)
1132 RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(scope, index, 0, true);
1133 // Check for an invalid index. Certain editing operations invalidate indices because
1134 // of problems with TextIteratorEmitsCharactersBetweenAllVisiblePositions.
1136 return VisiblePosition();
1137 return VisiblePosition(range->startPosition());
1140 VisiblePosition visiblePositionForIndexUsingCharacterIterator(Node* node, int index)
1144 return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
1146 RefPtr<Range> range = Range::create(node->document());
1147 range->selectNodeContents(node, IGNORE_EXCEPTION);
1148 CharacterIterator it(range.get());
1149 it.advance(index - 1);
1151 return VisiblePosition(Position(it.range()->endContainer(), it.range()->endOffset(), Position::PositionIsOffsetInAnchor), UPSTREAM);
1154 // Determines whether two positions are visibly next to each other (first then second)
1155 // while ignoring whitespaces and unrendered nodes
1156 bool isVisiblyAdjacent(const Position& first, const Position& second)
1158 return VisiblePosition(first) == VisiblePosition(second.upstream());
1161 // Determines whether a node is inside a range or visibly starts and ends at the boundaries of the range.
1162 // Call this function to determine whether a node is visibly fit inside selectedRange
1163 bool isNodeVisiblyContainedWithin(Node* node, const Range* selectedRange)
1166 ASSERT(selectedRange);
1167 // If the node is inside the range, then it surely is contained within
1168 if (selectedRange->compareNode(node, IGNORE_EXCEPTION) == Range::NODE_INSIDE)
1171 bool startIsVisuallySame = visiblePositionBeforeNode(node) == selectedRange->startPosition();
1172 if (startIsVisuallySame && comparePositions(positionInParentAfterNode(node), selectedRange->endPosition()) < 0)
1175 bool endIsVisuallySame = visiblePositionAfterNode(node) == selectedRange->endPosition();
1176 if (endIsVisuallySame && comparePositions(selectedRange->startPosition(), positionInParentBeforeNode(node)) < 0)
1179 return startIsVisuallySame && endIsVisuallySame;
1182 bool isRenderedAsNonInlineTableImageOrHR(const Node* node)
1186 RenderObject* renderer = node->renderer();
1187 return renderer && ((renderer->isTable() && !renderer->isInline()) || (renderer->isImage() && !renderer->isInline()) || renderer->isHR());
1190 bool areIdenticalElements(const Node* first, const Node* second)
1192 if (!first->isElementNode() || !second->isElementNode())
1195 const Element* firstElement = toElement(first);
1196 const Element* secondElement = toElement(second);
1197 if (!firstElement->hasTagName(secondElement->tagQName()))
1200 return firstElement->hasEquivalentAttributes(secondElement);
1203 bool isNonTableCellHTMLBlockElement(const Node* node)
1205 if (!node->isElementNode())
1208 const Element* element = toElement(node);
1209 return element->hasTagName(listingTag)
1210 || element->hasTagName(olTag)
1211 || element->hasTagName(preTag)
1212 || isHTMLTableElement(element)
1213 || element->hasTagName(ulTag)
1214 || element->hasTagName(xmpTag)
1215 || element->hasTagName(h1Tag)
1216 || element->hasTagName(h2Tag)
1217 || element->hasTagName(h3Tag)
1218 || element->hasTagName(h4Tag)
1219 || element->hasTagName(h5Tag);
1222 Position adjustedSelectionStartForStyleComputation(const VisibleSelection& selection)
1224 // This function is used by range style computations to avoid bugs like:
1225 // <rdar://problem/4017641> REGRESSION (Mail): you can only bold/unbold a selection starting from end of line once
1226 // It is important to skip certain irrelevant content at the start of the selection, so we do not wind up
1227 // with a spurious "mixed" style.
1229 VisiblePosition visiblePosition = selection.start();
1230 if (visiblePosition.isNull())
1233 // if the selection is a caret, just return the position, since the style
1234 // behind us is relevant
1235 if (selection.isCaret())
1236 return visiblePosition.deepEquivalent();
1238 // if the selection starts just before a paragraph break, skip over it
1239 if (isEndOfParagraph(visiblePosition))
1240 return visiblePosition.next().deepEquivalent().downstream();
1242 // otherwise, make sure to be at the start of the first selected node,
1243 // instead of possibly at the end of the last node before the selection
1244 return visiblePosition.deepEquivalent().downstream();
1247 // FIXME: Should this be deprecated like deprecatedEnclosingBlockFlowElement is?
1248 bool isBlockFlowElement(const Node* node)
1250 if (!node->isElementNode())
1252 RenderObject* renderer = node->renderer();
1253 return renderer && renderer->isRenderBlockFlow();
1256 Element* deprecatedEnclosingBlockFlowElement(Node* node)
1260 if (isBlockFlowElement(node))
1261 return toElement(node);
1262 while ((node = node->parentNode())) {
1263 if (isBlockFlowElement(node) || node->hasTagName(bodyTag))
1264 return toElement(node);
1269 } // namespace WebCore