bool isPlainTextMarkup(Node* node) { DCHECK(node); if (!isHTMLDivElement(*node)) return false; HTMLDivElement& element = toHTMLDivElement(*node); if (!element.hasAttributes()) return false; if (element.hasOneChild()) return element.firstChild()->isTextNode() || element.firstChild()->hasChildren(); return element.hasChildCount(2) && isTabHTMLSpanElementTextNode(element.firstChild()->firstChild()) && element.lastChild()->isTextNode(); }
Position InsertTextCommand::positionInsideTextNode(const Position& p) { Position pos = p; if (isTabHTMLSpanElementTextNode(pos.anchorNode())) { RefPtrWillBeRawPtr<Text> textNode = document().createEditingTextNode(""); insertNodeAtTabSpanPosition(textNode.get(), pos); return firstPositionInNode(textNode.get()); } // Prepare for text input by looking at the specified position. // It may be necessary to insert a text node to receive characters. if (!pos.containerNode()->isTextNode()) { RefPtrWillBeRawPtr<Text> textNode = document().createEditingTextNode(""); insertNodeAt(textNode.get(), pos); return firstPositionInNode(textNode.get()); } return pos; }
Position InsertTextCommand::insertTab(const Position& pos) { Position insertPos = VisiblePosition(pos, DOWNSTREAM).deepEquivalent(); if (insertPos.isNull()) return pos; Node* node = insertPos.containerNode(); unsigned offset = node->isTextNode() ? insertPos.offsetInContainerNode() : 0; // keep tabs coalesced in tab span if (isTabHTMLSpanElementTextNode(node)) { RefPtrWillBeRawPtr<Text> textNode = toText(node); insertTextIntoNode(textNode, offset, "\t"); return Position(textNode.release(), offset + 1); } // create new tab span RefPtrWillBeRawPtr<HTMLSpanElement> spanElement = createTabSpanElement(document()); // place it if (!node->isTextNode()) { insertNodeAt(spanElement.get(), insertPos); } else { RefPtrWillBeRawPtr<Text> textNode = toText(node); if (offset >= textNode->length()) insertNodeAfter(spanElement, textNode.release()); else { // split node to make room for the span // NOTE: splitTextNode uses textNode for the // second node in the split, so we need to // insert the span before it. if (offset > 0) splitTextNode(textNode, offset); insertNodeBefore(spanElement, textNode.release()); } } // return the position following the new tab return lastPositionInNode(spanElement.get()); }
static HTMLElement* highestAncestorToWrapMarkup( const PositionTemplate<Strategy>& startPosition, const PositionTemplate<Strategy>& endPosition, EAnnotateForInterchange shouldAnnotate, Node* constrainingAncestor) { Node* firstNode = startPosition.nodeAsRangeFirstNode(); // For compatibility reason, we use container node of start and end // positions rather than first node and last node in selection. Node* commonAncestor = Strategy::commonAncestor(*startPosition.computeContainerNode(), *endPosition.computeContainerNode()); DCHECK(commonAncestor); HTMLElement* specialCommonAncestor = nullptr; if (shouldAnnotate == AnnotateForInterchange) { // Include ancestors that aren't completely inside the range but are // required to retain the structure and appearance of the copied markup. specialCommonAncestor = ancestorToRetainStructureAndAppearance(commonAncestor); if (Node* parentListNode = enclosingNodeOfType( firstPositionInOrBeforeNode(firstNode), isListItem)) { EphemeralRangeTemplate<Strategy> markupRange = EphemeralRangeTemplate<Strategy>(startPosition, endPosition); EphemeralRangeTemplate<Strategy> nodeRange = normalizeRange( EphemeralRangeTemplate<Strategy>::rangeOfContents(*parentListNode)); if (nodeRange == markupRange) { ContainerNode* ancestor = parentListNode->parentNode(); while (ancestor && !isHTMLListElement(ancestor)) ancestor = ancestor->parentNode(); specialCommonAncestor = toHTMLElement(ancestor); } } // Retain the Mail quote level by including all ancestor mail block quotes. if (HTMLQuoteElement* highestMailBlockquote = toHTMLQuoteElement(highestEnclosingNodeOfType( firstPositionInOrBeforeNode(firstNode), isMailHTMLBlockquoteElement, CanCrossEditingBoundary))) specialCommonAncestor = highestMailBlockquote; } Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor; if (checkAncestor->layoutObject()) { HTMLElement* newSpecialCommonAncestor = toHTMLElement(highestEnclosingNodeOfType( Position::firstPositionInNode(checkAncestor), &isPresentationalHTMLElement, CanCrossEditingBoundary, constrainingAncestor)); if (newSpecialCommonAncestor) specialCommonAncestor = newSpecialCommonAncestor; } // If a single tab is selected, commonAncestor will be a text node inside a // tab span. If two or more tabs are selected, commonAncestor will be the tab // span. In either case, if there is a specialCommonAncestor already, it will // necessarily be above any tab span that needs to be included. if (!specialCommonAncestor && isTabHTMLSpanElementTextNode(commonAncestor)) specialCommonAncestor = toHTMLSpanElement(Strategy::parent(*commonAncestor)); if (!specialCommonAncestor && isTabHTMLSpanElement(commonAncestor)) specialCommonAncestor = toHTMLSpanElement(commonAncestor); if (HTMLAnchorElement* enclosingAnchor = toHTMLAnchorElement(enclosingElementWithTag( Position::firstPositionInNode(specialCommonAncestor ? specialCommonAncestor : commonAncestor), aTag))) specialCommonAncestor = enclosingAnchor; return specialCommonAncestor; }