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"
31 #include "EditingText.h"
34 #include "HTMLBRElement.h"
35 #include "HTMLDivElement.h"
36 #include "HTMLElementFactory.h"
37 #include "HTMLTextFormControlElement.h"
38 #include "HTMLInterchange.h"
39 #include "HTMLLIElement.h"
40 #include "HTMLNames.h"
41 #include "HTMLObjectElement.h"
42 #include "HTMLOListElement.h"
43 #include "HTMLParagraphElement.h"
44 #include "HTMLUListElement.h"
45 #include "PositionIterator.h"
46 #include "RenderObject.h"
48 #include "ShadowRoot.h"
50 #include "TextIterator.h"
51 #include "VisiblePosition.h"
52 #include "VisibleSelection.h"
53 #include "visible_units.h"
54 #include <wtf/Assertions.h>
55 #include <wtf/StdLibExtras.h>
56 #include <wtf/unicode/CharacterNames.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)
100 int result = Range::compareBoundaryPoints(nodeA, offsetA, nodeB, offsetB, ec);
101 return result ? result : bias;
104 int comparePositions(const VisiblePosition& a, const VisiblePosition& b)
106 return comparePositions(a.deepEquivalent(), b.deepEquivalent());
109 Node* highestEditableRoot(const Position& position, EditableType editableType)
111 Node* node = position.deprecatedNode();
115 Node* highestRoot = editableRootForPosition(position, editableType);
121 if (node->rendererIsEditable(editableType))
123 if (node->hasTagName(bodyTag))
125 node = node->parentNode();
131 Node* lowestEditableAncestor(Node* node)
136 Node *lowestRoot = 0;
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 = static_cast<Element*>(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 Node* enclosingBlockNode = enclosingBlock(position.containerNode());
330 if (!enclosingBlockNode)
332 RenderObject* renderer = enclosingBlockNode->renderer();
333 return renderer ? renderer->style()->direction() : LTR;
336 // This method is used to create positions in the DOM. It returns the maximum valid offset
337 // in a node. It returns 1 for some elements even though they do not have children, which
338 // creates technically invalid DOM Positions. Be sure to call parentAnchoredEquivalent
339 // on a Position before using it to create a DOM Range, or an exception will be thrown.
340 int lastOffsetForEditing(const Node* node)
345 if (node->offsetInCharacters())
346 return node->maxCharacterOffset();
348 if (node->hasChildNodes())
349 return node->childNodeCount();
351 // NOTE: This should preempt the childNodeCount for, e.g., select nodes
352 if (editingIgnoresContent(node))
358 String stringWithRebalancedWhitespace(const String& string, bool startIsStartOfParagraph, bool endIsEndOfParagraph)
360 Vector<UChar> rebalancedString;
361 append(rebalancedString, string);
363 bool previousCharacterWasSpace = false;
364 for (size_t i = 0; i < rebalancedString.size(); i++) {
365 if (!isWhitespace(rebalancedString[i])) {
366 previousCharacterWasSpace = false;
370 if (previousCharacterWasSpace || (!i && startIsStartOfParagraph) || (i + 1 == rebalancedString.size() && endIsEndOfParagraph)) {
371 rebalancedString[i] = noBreakSpace;
372 previousCharacterWasSpace = false;
374 rebalancedString[i] = ' ';
375 previousCharacterWasSpace = true;
380 return String::adopt(rebalancedString);
383 bool isTableStructureNode(const Node *node)
385 RenderObject* renderer = node->renderer();
386 return (renderer && (renderer->isTableCell() || renderer->isTableRow() || renderer->isTableSection() || renderer->isRenderTableCol()));
389 const String& nonBreakingSpaceString()
391 DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1));
392 return nonBreakingSpaceString;
395 // FIXME: need to dump this
396 bool isSpecialElement(const Node *n)
401 if (!n->isHTMLElement())
407 RenderObject *renderer = n->renderer();
411 if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
414 if (renderer->style()->isFloating())
417 if (renderer->style()->position() != StaticPosition)
423 static Node* firstInSpecialElement(const Position& pos)
425 Node* rootEditableElement = pos.containerNode()->rootEditableElement();
426 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
427 if (isSpecialElement(n)) {
428 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
429 VisiblePosition firstInElement = VisiblePosition(firstPositionInOrBeforeNode(n), DOWNSTREAM);
430 if (isTableElement(n) && vPos == firstInElement.next())
432 if (vPos == firstInElement)
438 static Node* lastInSpecialElement(const Position& pos)
440 Node* rootEditableElement = pos.containerNode()->rootEditableElement();
441 for (Node* n = pos.deprecatedNode(); n && n->rootEditableElement() == rootEditableElement; n = n->parentNode())
442 if (isSpecialElement(n)) {
443 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM);
444 VisiblePosition lastInElement = VisiblePosition(lastPositionInOrAfterNode(n), DOWNSTREAM);
445 if (isTableElement(n) && vPos == lastInElement.previous())
447 if (vPos == lastInElement)
453 bool isFirstVisiblePositionInSpecialElement(const Position& pos)
455 return firstInSpecialElement(pos);
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 bool isLastVisiblePositionInSpecialElement(const Position& pos)
473 return lastInSpecialElement(pos);
476 Position positionAfterContainingSpecialElement(const Position& pos, Node **containingSpecialElement)
478 Node* n = lastInSpecialElement(pos);
481 Position result = positionInParentAfterNode(n);
482 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos.deprecatedNode()->rootEditableElement())
484 if (containingSpecialElement)
485 *containingSpecialElement = n;
489 Position positionOutsideContainingSpecialElement(const Position &pos, Node **containingSpecialElement)
491 if (isFirstVisiblePositionInSpecialElement(pos))
492 return positionBeforeContainingSpecialElement(pos, containingSpecialElement);
493 if (isLastVisiblePositionInSpecialElement(pos))
494 return positionAfterContainingSpecialElement(pos, containingSpecialElement);
498 Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition)
500 Position upstream(visiblePosition.deepEquivalent().upstream());
501 if (upstream.deprecatedNode() && upstream.deprecatedNode()->renderer() && upstream.deprecatedNode()->renderer()->isTable() && upstream.atLastEditingPositionForNode())
502 return upstream.deprecatedNode();
507 Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition)
509 Position downstream(visiblePosition.deepEquivalent().downstream());
510 if (downstream.deprecatedNode() && downstream.deprecatedNode()->renderer() && downstream.deprecatedNode()->renderer()->isTable() && downstream.atFirstEditingPositionForNode())
511 return downstream.deprecatedNode();
516 // Returns the visible position at the beginning of a node
517 VisiblePosition visiblePositionBeforeNode(Node* node)
520 if (node->childNodeCount())
521 return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM);
522 ASSERT(node->parentNode());
523 ASSERT(!node->parentNode()->isShadowRoot());
524 return positionInParentBeforeNode(node);
527 // Returns the visible position at the ending of a node
528 VisiblePosition visiblePositionAfterNode(Node* node)
531 if (node->childNodeCount())
532 return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM);
533 ASSERT(node->parentNode());
534 ASSERT(!node->parentNode()->isShadowRoot());
535 return positionInParentAfterNode(node);
538 // Create a range object with two visible positions, start and end.
539 // create(PassRefPtr<Document>, const Position&, const Position&); will use deprecatedEditingOffset
540 // Use this function instead of create a regular range object (avoiding editing offset).
541 PassRefPtr<Range> createRange(PassRefPtr<Document> document, const VisiblePosition& start, const VisiblePosition& end, ExceptionCode& ec)
544 RefPtr<Range> selectedRange = Range::create(document);
545 selectedRange->setStart(start.deepEquivalent().containerNode(), start.deepEquivalent().computeOffsetInContainerNode(), ec);
547 selectedRange->setEnd(end.deepEquivalent().containerNode(), end.deepEquivalent().computeOffsetInContainerNode(), ec);
548 return selectedRange.release();
551 // Extend rangeToExtend to include nodes that wraps range and visibly starts and ends inside or at the boudnaries of maximumRange
552 // e.g. if the original range spaned "hello" in <div>hello</div>, then this function extends the range to contain div's around it.
553 // Call this function before copying / moving paragraphs to contain all wrapping nodes.
554 // This function stops extending the range immediately below rootNode; i.e. the extended range can contain a child node of rootNode
555 // but it can never contain rootNode itself.
556 PassRefPtr<Range> extendRangeToWrappingNodes(PassRefPtr<Range> range, const Range* maximumRange, const Node* rootNode)
559 ASSERT(maximumRange);
561 ExceptionCode ec = 0;
562 Node* ancestor = range->commonAncestorContainer(ec);// find the cloeset common ancestor
563 Node* highestNode = 0;
564 // traverse through ancestors as long as they are contained within the range, content-editable, and below rootNode (could be =0).
565 while (ancestor && ancestor->rendererIsEditable() && isNodeVisiblyContainedWithin(ancestor, maximumRange) && ancestor != rootNode) {
566 highestNode = ancestor;
567 ancestor = ancestor->parentNode();
573 // Create new range with the highest editable node contained within the range
574 RefPtr<Range> extendedRange = Range::create(range->ownerDocument());
575 extendedRange->selectNode(highestNode, ec);
576 return extendedRange.release();
579 bool isListElement(Node *n)
581 return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(dlTag)));
584 bool isListItem(Node *n)
586 return n && n->renderer() && n->renderer()->isListItem();
589 Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName)
594 Node* root = highestEditableRoot(p);
595 for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
596 if (root && !n->rendererIsEditable())
598 if (n->hasTagName(tagName))
607 Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule)
609 // FIXME: support CanSkipCrossEditingBoundary
610 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
614 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0;
615 for (Node* n = p.deprecatedNode(); n; n = n->parentNode()) {
616 // Don't return a non-editable node if the input position was editable, since
617 // the callers from editing will no doubt want to perform editing inside the returned node.
618 if (root && !n->rendererIsEditable())
629 Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*), EditingBoundaryCrossingRule rule, Node* stayWithin)
632 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0;
633 for (Node* n = p.containerNode(); n && n != stayWithin; n = n->parentNode()) {
634 if (root && !n->rendererIsEditable())
645 static bool hasARenderedDescendant(Node* node, Node* excludedNode)
647 for (Node* n = node->firstChild(); n;) {
648 if (n == excludedNode) {
649 n = n->traverseNextSibling(node);
654 n = n->traverseNextNode(node);
659 Node* highestNodeToRemoveInPruning(Node* node)
661 Node* previousNode = 0;
662 Node* rootEditableElement = node ? node->rootEditableElement() : 0;
663 for (; node; node = node->parentNode()) {
664 if (RenderObject* renderer = node->renderer()) {
665 if (!renderer->canHaveChildren() || hasARenderedDescendant(node, previousNode) || rootEditableElement == node)
673 Node* enclosingTableCell(const Position& p)
675 return static_cast<Element*>(enclosingNodeOfType(p, isTableCell));
678 Node* enclosingAnchorElement(const Position& p)
683 Node* node = p.deprecatedNode();
684 while (node && !(node->isElementNode() && node->isLink()))
685 node = node->parentNode();
689 HTMLElement* enclosingList(Node* node)
694 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node));
696 for (ContainerNode* n = node->parentNode(); n; n = n->parentNode()) {
697 if (n->hasTagName(ulTag) || n->hasTagName(olTag))
698 return toHTMLElement(n);
706 Node* enclosingListChild(Node *node)
710 // Check for a list item element, or for a node whose parent is a list element. Such a node
711 // will appear visually as a list item (but without a list marker)
712 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node));
714 // FIXME: This function is inappropriately named if it starts with node instead of node->parentNode()
715 for (Node* n = node; n && n->parentNode(); n = n->parentNode()) {
716 if (n->hasTagName(liTag) || (isListElement(n->parentNode()) && n != root))
718 if (n == root || isTableCell(n))
725 static HTMLElement* embeddedSublist(Node* listItem)
727 // Check the DOM so that we'll find collapsed sublists without renderers.
728 for (Node* n = listItem->firstChild(); n; n = n->nextSibling()) {
729 if (isListElement(n))
730 return toHTMLElement(n);
736 static Node* appendedSublist(Node* listItem)
738 // Check the DOM so that we'll find collapsed sublists without renderers.
739 for (Node* n = listItem->nextSibling(); n; n = n->nextSibling()) {
740 if (isListElement(n))
741 return toHTMLElement(n);
742 if (isListItem(listItem))
749 // FIXME: This method should not need to call isStartOfParagraph/isEndOfParagraph
750 Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
752 // Check that position is on a line by itself inside a list item
753 Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().deprecatedNode());
754 if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(visiblePos))
757 VisiblePosition firstInListChild(firstPositionInOrBeforeNode(listChildNode));
758 VisiblePosition lastInListChild(lastPositionInOrAfterNode(listChildNode));
760 if (firstInListChild != visiblePos || lastInListChild != visiblePos)
763 if (embeddedSublist(listChildNode) || appendedSublist(listChildNode))
766 return listChildNode;
769 HTMLElement* outermostEnclosingList(Node* node, Node* rootList)
771 HTMLElement* list = enclosingList(node);
775 while (HTMLElement* nextList = enclosingList(list)) {
776 if (nextList == rootList)
784 bool canMergeLists(Element* firstList, Element* secondList)
786 if (!firstList || !secondList || !firstList->isHTMLElement() || !secondList->isHTMLElement())
789 return firstList->hasTagName(secondList->tagQName())// make sure the list types match (ol vs. ul)
790 && firstList->rendererIsEditable() && secondList->rendererIsEditable() // both lists are editable
791 && firstList->rootEditableElement() == secondList->rootEditableElement()// don't cross editing boundaries
792 && isVisiblyAdjacent(positionInParentAfterNode(firstList), positionInParentBeforeNode(secondList));
793 // Make sure there is no visible content between this li and the previous list
796 Node* highestAncestor(Node* node)
800 while ((node = node->parentNode()))
805 // FIXME: do not require renderer, so that this can be used within fragments, or rename to isRenderedTable()
806 bool isTableElement(Node* n)
808 if (!n || !n->isElementNode())
811 RenderObject* renderer = n->renderer();
812 return (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE));
815 bool isTableCell(const Node* node)
817 RenderObject* r = node->renderer();
819 return node->hasTagName(tdTag) || node->hasTagName(thTag);
821 return r->isTableCell();
824 bool isEmptyTableCell(const Node* node)
826 // Returns true IFF the passed in node is one of:
827 // .) a table cell with no children,
828 // .) a table cell with a single BR child, and which has no other child renderers, including :before and :after renderers
829 // .) the BR child of such a table cell
831 // Find rendered node
832 while (node && !node->renderer())
833 node = node->parentNode();
837 // Make sure the rendered node is a table cell or <br>.
838 // If it's a <br>, then the parent node has to be a table cell.
839 RenderObject* renderer = node->renderer();
840 if (renderer->isBR()) {
841 renderer = renderer->parent();
845 if (!renderer->isTableCell())
848 // Check that the table cell contains no child renderers except for perhaps a single <br>.
849 RenderObject* childRenderer = renderer->firstChild();
852 if (!childRenderer->isBR())
854 return !childRenderer->nextSibling();
857 PassRefPtr<HTMLElement> createDefaultParagraphElement(Document* document)
859 switch (document->frame()->editor()->defaultParagraphSeparator()) {
860 case EditorParagraphSeparatorIsDiv:
861 return HTMLDivElement::create(document);
862 case EditorParagraphSeparatorIsP:
863 return HTMLParagraphElement::create(document);
866 ASSERT_NOT_REACHED();
870 PassRefPtr<HTMLElement> createBreakElement(Document* document)
872 return HTMLBRElement::create(document);
875 PassRefPtr<HTMLElement> createOrderedListElement(Document* document)
877 return HTMLOListElement::create(document);
880 PassRefPtr<HTMLElement> createUnorderedListElement(Document* document)
882 return HTMLUListElement::create(document);
885 PassRefPtr<HTMLElement> createListItemElement(Document* document)
887 return HTMLLIElement::create(document);
890 PassRefPtr<HTMLElement> createHTMLElement(Document* document, const QualifiedName& name)
892 return HTMLElementFactory::createHTMLElement(name, document, 0, false);
895 PassRefPtr<HTMLElement> createHTMLElement(Document* document, const AtomicString& tagName)
897 return createHTMLElement(document, QualifiedName(nullAtom, tagName, xhtmlNamespaceURI));
900 bool isTabSpanNode(const Node *node)
902 return node && node->hasTagName(spanTag) && node->isElementNode() && static_cast<const Element *>(node)->getAttribute(classAttr) == AppleTabSpanClass;
905 bool isTabSpanTextNode(const Node *node)
907 return node && node->isTextNode() && node->parentNode() && isTabSpanNode(node->parentNode());
910 Node *tabSpanNode(const Node *node)
912 return isTabSpanTextNode(node) ? node->parentNode() : 0;
915 Position positionOutsideTabSpan(const Position& pos)
917 Node* node = pos.containerNode();
918 if (isTabSpanTextNode(node))
919 node = tabSpanNode(node);
920 else if (!isTabSpanNode(node))
923 if (node && VisiblePosition(pos) == lastPositionInNode(node))
924 return positionInParentAfterNode(node);
926 return positionInParentBeforeNode(node);
929 PassRefPtr<Element> createTabSpanElement(Document* document, PassRefPtr<Node> prpTabTextNode)
931 RefPtr<Node> tabTextNode = prpTabTextNode;
933 // Make the span to hold the tab.
934 RefPtr<Element> spanElement = document->createElement(spanTag, false);
935 spanElement->setAttribute(classAttr, AppleTabSpanClass);
936 spanElement->setAttribute(styleAttr, "white-space:pre");
938 // Add tab text to that span.
940 tabTextNode = document->createEditingTextNode("\t");
942 ExceptionCode ec = 0;
943 spanElement->appendChild(tabTextNode.release(), ec);
946 return spanElement.release();
949 PassRefPtr<Element> createTabSpanElement(Document* document, const String& tabText)
951 return createTabSpanElement(document, document->createTextNode(tabText));
954 PassRefPtr<Element> createTabSpanElement(Document* document)
956 return createTabSpanElement(document, PassRefPtr<Node>());
959 bool isNodeRendered(const Node *node)
964 RenderObject *renderer = node->renderer();
968 return renderer->style()->visibility() == VISIBLE;
971 unsigned numEnclosingMailBlockquotes(const Position& p)
974 for (Node* n = p.deprecatedNode(); n; n = n->parentNode())
975 if (isMailBlockquote(n))
981 void updatePositionForNodeRemoval(Position& position, Node* node)
983 if (position.isNull())
985 switch (position.anchorType()) {
986 case Position::PositionIsBeforeChildren:
987 if (position.containerNode() == node)
988 position = positionInParentBeforeNode(node);
990 case Position::PositionIsAfterChildren:
991 if (position.containerNode() == node)
992 position = positionInParentAfterNode(node);
994 case Position::PositionIsOffsetInAnchor:
995 if (position.containerNode() == node->parentNode() && static_cast<unsigned>(position.offsetInContainerNode()) > node->nodeIndex())
996 position.moveToOffset(position.offsetInContainerNode() - 1);
997 else if (node->contains(position.containerNode()) || node->contains(position.containerNode()->shadowAncestorNode()))
998 position = positionInParentBeforeNode(node);
1000 case Position::PositionIsAfterAnchor:
1001 if (node->contains(position.anchorNode()) || node->contains(position.anchorNode()->shadowAncestorNode()))
1002 position = positionInParentAfterNode(node);
1004 case Position::PositionIsBeforeAnchor:
1005 if (node->contains(position.anchorNode()) || node->contains(position.anchorNode()->shadowAncestorNode()))
1006 position = positionInParentBeforeNode(node);
1011 bool isMailBlockquote(const Node *node)
1013 if (!node || !node->hasTagName(blockquoteTag))
1016 return static_cast<const Element *>(node)->getAttribute("type") == "cite";
1019 int caretMinOffset(const Node* n)
1021 RenderObject* r = n->renderer();
1022 ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
1023 return r ? r->caretMinOffset() : 0;
1026 // If a node can contain candidates for VisiblePositions, return the offset of the last candidate, otherwise
1027 // return the number of children for container nodes and the length for unrendered text nodes.
1028 int caretMaxOffset(const Node* n)
1030 // For rendered text nodes, return the last position that a caret could occupy.
1031 if (n->isTextNode() && n->renderer())
1032 return n->renderer()->caretMaxOffset();
1033 // For containers return the number of children. For others do the same as above.
1034 return lastOffsetForEditing(n);
1037 bool lineBreakExistsAtVisiblePosition(const VisiblePosition& visiblePosition)
1039 return lineBreakExistsAtPosition(visiblePosition.deepEquivalent().downstream());
1042 bool lineBreakExistsAtPosition(const Position& position)
1044 if (position.isNull())
1047 if (position.anchorNode()->hasTagName(brTag) && position.atFirstEditingPositionForNode())
1050 if (!position.anchorNode()->renderer())
1053 if (!position.anchorNode()->isTextNode() || !position.anchorNode()->renderer()->style()->preserveNewline())
1056 Text* textNode = toText(position.anchorNode());
1057 unsigned offset = position.offsetInContainerNode();
1058 return offset < textNode->length() && textNode->data()[offset] == '\n';
1061 // Modifies selections that have an end point at the edge of a table
1062 // that contains the other endpoint so that they don't confuse
1063 // code that iterates over selected paragraphs.
1064 VisibleSelection selectionForParagraphIteration(const VisibleSelection& original)
1066 VisibleSelection newSelection(original);
1067 VisiblePosition startOfSelection(newSelection.visibleStart());
1068 VisiblePosition endOfSelection(newSelection.visibleEnd());
1070 // If the end of the selection to modify is just after a table, and
1071 // if the start of the selection is inside that table, then the last paragraph
1072 // that we'll want modify is the last one inside the table, not the table itself
1073 // (a table is itself a paragraph).
1074 if (Node* table = isFirstPositionAfterTable(endOfSelection))
1075 if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
1076 newSelection = VisibleSelection(startOfSelection, endOfSelection.previous(CannotCrossEditingBoundary));
1078 // If the start of the selection to modify is just before a table,
1079 // and if the end of the selection is inside that table, then the first paragraph
1080 // we'll want to modify is the first one inside the table, not the paragraph
1081 // containing the table itself.
1082 if (Node* table = isLastPositionBeforeTable(startOfSelection))
1083 if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(table))
1084 newSelection = VisibleSelection(startOfSelection.next(CannotCrossEditingBoundary), endOfSelection);
1086 return newSelection;
1089 // FIXME: indexForVisiblePosition and visiblePositionForIndex use TextIterators to convert between
1090 // VisiblePositions and indices. But TextIterator iteration using TextIteratorEmitsCharactersBetweenAllVisiblePositions
1091 // does not exactly match VisiblePosition iteration, so using them to preserve a selection during an editing
1092 // opertion is unreliable. TextIterator's TextIteratorEmitsCharactersBetweenAllVisiblePositions mode needs to be fixed,
1093 // or these functions need to be changed to iterate using actual VisiblePositions.
1094 // FIXME: Deploy these functions everywhere that TextIterators are used to convert between VisiblePositions and indices.
1096 int indexForVisiblePosition(const VisiblePosition& visiblePosition, RefPtr<ContainerNode>& scope)
1098 if (visiblePosition.isNull())
1101 Position p(visiblePosition.deepEquivalent());
1102 Document* document = p.anchorNode()->document();
1103 ShadowRoot* shadowRoot = p.anchorNode()->shadowRoot();
1108 scope = document->documentElement();
1110 RefPtr<Range> range = Range::create(document, firstPositionInNode(scope.get()), p.parentAnchoredEquivalent());
1112 return TextIterator::rangeLength(range.get(), true);
1115 VisiblePosition visiblePositionForIndex(int index, ContainerNode* scope)
1117 RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(scope, index, 0, true);
1118 // Check for an invalid index. Certain editing operations invalidate indices because
1119 // of problems with TextIteratorEmitsCharactersBetweenAllVisiblePositions.
1121 return VisiblePosition();
1122 return VisiblePosition(range->startPosition());
1125 // Determines whether two positions are visibly next to each other (first then second)
1126 // while ignoring whitespaces and unrendered nodes
1127 bool isVisiblyAdjacent(const Position& first, const Position& second)
1129 return VisiblePosition(first) == VisiblePosition(second.upstream());
1132 // Determines whether a node is inside a range or visibly starts and ends at the boundaries of the range.
1133 // Call this function to determine whether a node is visibly fit inside selectedRange
1134 bool isNodeVisiblyContainedWithin(Node* node, const Range* selectedRange)
1137 ASSERT(selectedRange);
1138 // If the node is inside the range, then it surely is contained within
1139 ExceptionCode ec = 0;
1140 if (selectedRange->compareNode(node, ec) == Range::NODE_INSIDE)
1143 bool startIsVisuallySame = visiblePositionBeforeNode(node) == selectedRange->startPosition();
1144 if (startIsVisuallySame && comparePositions(positionInParentAfterNode(node), selectedRange->endPosition()) < 0)
1147 bool endIsVisuallySame = visiblePositionAfterNode(node) == selectedRange->endPosition();
1148 if (endIsVisuallySame && comparePositions(selectedRange->startPosition(), positionInParentBeforeNode(node)) < 0)
1151 return startIsVisuallySame && endIsVisuallySame;
1154 bool isRenderedAsNonInlineTableImageOrHR(const Node* node)
1158 RenderObject* renderer = node->renderer();
1159 return renderer && ((renderer->isTable() && !renderer->isInline()) || (renderer->isImage() && !renderer->isInline()) || renderer->isHR());
1162 bool areIdenticalElements(const Node* first, const Node* second)
1164 if (!first->isElementNode() || !second->isElementNode())
1167 const Element* firstElement = toElement(first);
1168 const Element* secondElement = toElement(second);
1169 if (!firstElement->hasTagName(secondElement->tagQName()))
1172 return firstElement->hasEquivalentAttributes(secondElement);
1175 bool isNonTableCellHTMLBlockElement(const Node* node)
1177 return node->hasTagName(listingTag)
1178 || node->hasTagName(olTag)
1179 || node->hasTagName(preTag)
1180 || node->hasTagName(tableTag)
1181 || node->hasTagName(ulTag)
1182 || node->hasTagName(xmpTag)
1183 || node->hasTagName(h1Tag)
1184 || node->hasTagName(h2Tag)
1185 || node->hasTagName(h3Tag)
1186 || node->hasTagName(h4Tag)
1187 || node->hasTagName(h5Tag);
1190 PassRefPtr<Range> avoidIntersectionWithNode(const Range* range, Node* node)
1195 Document* document = range->ownerDocument();
1197 Node* startContainer = range->startContainer();
1198 int startOffset = range->startOffset();
1199 Node* endContainer = range->endContainer();
1200 int endOffset = range->endOffset();
1202 if (!startContainer)
1205 ASSERT(endContainer);
1207 if (startContainer == node || startContainer->isDescendantOf(node)) {
1208 ASSERT(node->parentNode());
1209 startContainer = node->parentNode();
1210 startOffset = node->nodeIndex();
1212 if (endContainer == node || endContainer->isDescendantOf(node)) {
1213 ASSERT(node->parentNode());
1214 endContainer = node->parentNode();
1215 endOffset = node->nodeIndex();
1218 return Range::create(document, startContainer, startOffset, endContainer, endOffset);
1221 VisibleSelection avoidIntersectionWithNode(const VisibleSelection& selection, Node* node)
1223 if (selection.isNone())
1224 return VisibleSelection(selection);
1226 VisibleSelection updatedSelection(selection);
1227 Node* base = selection.base().deprecatedNode();
1228 Node* extent = selection.extent().deprecatedNode();
1232 if (base == node || base->isDescendantOf(node)) {
1233 ASSERT(node->parentNode());
1234 updatedSelection.setBase(positionInParentBeforeNode(node));
1237 if (extent == node || extent->isDescendantOf(node)) {
1238 ASSERT(node->parentNode());
1239 updatedSelection.setExtent(positionInParentBeforeNode(node));
1242 return updatedSelection;
1245 Position adjustedSelectionStartForStyleComputation(const VisibleSelection& selection)
1247 // This function is used by range style computations to avoid bugs like:
1248 // <rdar://problem/4017641> REGRESSION (Mail): you can only bold/unbold a selection starting from end of line once
1249 // It is important to skip certain irrelevant content at the start of the selection, so we do not wind up
1250 // with a spurious "mixed" style.
1252 VisiblePosition visiblePosition = selection.start();
1253 if (visiblePosition.isNull())
1256 // if the selection is a caret, just return the position, since the style
1257 // behind us is relevant
1258 if (selection.isCaret())
1259 return visiblePosition.deepEquivalent();
1261 // if the selection starts just before a paragraph break, skip over it
1262 if (isEndOfParagraph(visiblePosition))
1263 return visiblePosition.next().deepEquivalent().downstream();
1265 // otherwise, make sure to be at the start of the first selected node,
1266 // instead of possibly at the end of the last node before the selection
1267 return visiblePosition.deepEquivalent().downstream();
1270 } // namespace WebCore