| Index: Source/core/editing/ReplaceSelectionCommand.cpp
|
| diff --git a/Source/core/editing/ReplaceSelectionCommand.cpp b/Source/core/editing/ReplaceSelectionCommand.cpp
|
| index 3980379427ed3f56d5633071b8aca6f6f1b0b343..d4cf82ff5627b03daf140f65e103462bbe104915 100644
|
| --- a/Source/core/editing/ReplaceSelectionCommand.cpp
|
| +++ b/Source/core/editing/ReplaceSelectionCommand.cpp
|
| @@ -53,6 +53,8 @@
|
| #include "core/html/HTMLElement.h"
|
| #include "core/html/HTMLInputElement.h"
|
| #include "core/html/HTMLLIElement.h"
|
| +#include "core/html/HTMLQuoteElement.h"
|
| +#include "core/html/HTMLSelectElement.h"
|
| #include "core/html/HTMLSpanElement.h"
|
| #include "core/rendering/RenderObject.h"
|
| #include "core/rendering/RenderText.h"
|
| @@ -82,13 +84,13 @@ public:
|
| bool hasInterchangeNewlineAtEnd() const { return m_hasInterchangeNewlineAtEnd; }
|
|
|
| void removeNode(PassRefPtrWillBeRawPtr<Node>);
|
| - void removeNodePreservingChildren(PassRefPtrWillBeRawPtr<Node>);
|
| + void removeNodePreservingChildren(PassRefPtrWillBeRawPtr<ContainerNode>);
|
|
|
| private:
|
| - PassRefPtrWillBeRawPtr<Element> insertFragmentForTestRendering(Node* rootEditableNode);
|
| - void removeUnrenderedNodes(Node*);
|
| + PassRefPtrWillBeRawPtr<HTMLElement> insertFragmentForTestRendering(Element* rootEditableElement);
|
| + void removeUnrenderedNodes(ContainerNode*);
|
| void restoreAndRemoveTestRenderingNodesToFragment(Element*);
|
| - void removeInterchangeNodes(Node*);
|
| + void removeInterchangeNodes(ContainerNode*);
|
|
|
| void insertNodeBefore(PassRefPtrWillBeRawPtr<Node>, Node* refNode);
|
|
|
| @@ -98,16 +100,16 @@ private:
|
| bool m_hasInterchangeNewlineAtEnd;
|
| };
|
|
|
| -static bool isInterchangeNewlineNode(const Node *node)
|
| +static bool isInterchangeHTMLBRElement(const Node* node)
|
| {
|
| DEFINE_STATIC_LOCAL(String, interchangeNewlineClassString, (AppleInterchangeNewline));
|
| - if (!isHTMLBRElement(node) || toElement(node)->getAttribute(classAttr) != interchangeNewlineClassString)
|
| + if (!isHTMLBRElement(node) || toHTMLBRElement(node)->getAttribute(classAttr) != interchangeNewlineClassString)
|
| return false;
|
| UseCounter::count(node->document(), UseCounter::EditingAppleInterchangeNewline);
|
| return true;
|
| }
|
|
|
| -static bool isInterchangeConvertedSpaceSpan(const Node *node)
|
| +static bool isHTMLInterchangeConvertedSpaceSpan(const Node* node)
|
| {
|
| DEFINE_STATIC_LOCAL(String, convertedSpaceSpanClassString, (AppleConvertedSpace));
|
| if (!node->isHTMLElement() || toHTMLElement(node)->getAttribute(classAttr) != convertedSpaceSpanClassString)
|
| @@ -126,8 +128,8 @@ static Position positionAvoidingPrecedingNodes(Position pos)
|
| // same. E.g.,
|
| // <div>foo^</div>^
|
| // The two positions above are the same visual position, but we want to stay in the same block.
|
| - Node* enclosingBlockNode = enclosingBlock(pos.containerNode());
|
| - for (Position nextPosition = pos; nextPosition.containerNode() != enclosingBlockNode; pos = nextPosition) {
|
| + Element* enclosingBlockElement = enclosingBlock(pos.containerNode());
|
| + for (Position nextPosition = pos; nextPosition.containerNode() != enclosingBlockElement; pos = nextPosition) {
|
| if (lineBreakExistsAtPosition(pos))
|
| break;
|
|
|
| @@ -135,7 +137,7 @@ static Position positionAvoidingPrecedingNodes(Position pos)
|
| nextPosition = positionInParentAfterNode(*pos.containerNode());
|
|
|
| if (nextPosition == pos
|
| - || enclosingBlock(nextPosition.containerNode()) != enclosingBlockNode
|
| + || enclosingBlock(nextPosition.containerNode()) != enclosingBlockElement
|
| || VisiblePosition(pos) != VisiblePosition(nextPosition))
|
| break;
|
| }
|
| @@ -158,21 +160,21 @@ ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* f
|
| if (!editableRoot)
|
| return;
|
|
|
| - Node* shadowAncestorNode;
|
| + Element* shadowAncestorElement;
|
| if (editableRoot->isInShadowTree())
|
| - shadowAncestorNode = editableRoot->shadowHost();
|
| + shadowAncestorElement = editableRoot->shadowHost();
|
| else
|
| - shadowAncestorNode = editableRoot.get();
|
| + shadowAncestorElement = editableRoot.get();
|
|
|
| - if (!editableRoot->getAttributeEventListener(EventTypeNames::webkitBeforeTextInserted) &&
|
| + if (!editableRoot->getAttributeEventListener(EventTypeNames::webkitBeforeTextInserted)
|
| // FIXME: Remove these checks once textareas and textfields actually register an event handler.
|
| - !(shadowAncestorNode && shadowAncestorNode->renderer() && shadowAncestorNode->renderer()->isTextControl()) &&
|
| - editableRoot->rendererIsRichlyEditable()) {
|
| + && !(shadowAncestorElement && shadowAncestorElement->renderer() && shadowAncestorElement->renderer()->isTextControl())
|
| + && editableRoot->rendererIsRichlyEditable()) {
|
| removeInterchangeNodes(m_fragment.get());
|
| return;
|
| }
|
|
|
| - RefPtrWillBeRawPtr<Element> holder = insertFragmentForTestRendering(editableRoot.get());
|
| + RefPtrWillBeRawPtr<HTMLElement> holder = insertFragmentForTestRendering(editableRoot.get());
|
| if (!holder) {
|
| removeInterchangeNodes(m_fragment.get());
|
| return;
|
| @@ -207,17 +209,17 @@ bool ReplacementFragment::isEmpty() const
|
| return (!m_fragment || !m_fragment->hasChildren()) && !m_hasInterchangeNewlineAtStart && !m_hasInterchangeNewlineAtEnd;
|
| }
|
|
|
| -Node *ReplacementFragment::firstChild() const
|
| +Node* ReplacementFragment::firstChild() const
|
| {
|
| return m_fragment ? m_fragment->firstChild() : 0;
|
| }
|
|
|
| -Node *ReplacementFragment::lastChild() const
|
| +Node* ReplacementFragment::lastChild() const
|
| {
|
| return m_fragment ? m_fragment->lastChild() : 0;
|
| }
|
|
|
| -void ReplacementFragment::removeNodePreservingChildren(PassRefPtrWillBeRawPtr<Node> node)
|
| +void ReplacementFragment::removeNodePreservingChildren(PassRefPtrWillBeRawPtr<ContainerNode> node)
|
| {
|
| if (!node)
|
| return;
|
| @@ -253,10 +255,10 @@ void ReplacementFragment::insertNodeBefore(PassRefPtrWillBeRawPtr<Node> node, No
|
| parent->insertBefore(node, refNode);
|
| }
|
|
|
| -PassRefPtrWillBeRawPtr<Element> ReplacementFragment::insertFragmentForTestRendering(Node* rootEditableElement)
|
| +PassRefPtrWillBeRawPtr<HTMLElement> ReplacementFragment::insertFragmentForTestRendering(Element* rootEditableElement)
|
| {
|
| ASSERT(m_document);
|
| - RefPtrWillBeRawPtr<Element> holder = createDefaultParagraphElement(*m_document.get());
|
| + RefPtrWillBeRawPtr<HTMLElement> holder = createDefaultParagraphElement(*m_document.get());
|
|
|
| holder->appendChild(m_fragment);
|
| rootEditableElement->appendChild(holder.get());
|
| @@ -278,7 +280,7 @@ void ReplacementFragment::restoreAndRemoveTestRenderingNodesToFragment(Element*
|
| removeNode(holder);
|
| }
|
|
|
| -void ReplacementFragment::removeUnrenderedNodes(Node* holder)
|
| +void ReplacementFragment::removeUnrenderedNodes(ContainerNode* holder)
|
| {
|
| WillBeHeapVector<RefPtrWillBeMember<Node> > unrendered;
|
|
|
| @@ -291,7 +293,7 @@ void ReplacementFragment::removeUnrenderedNodes(Node* holder)
|
| removeNode(unrendered[i]);
|
| }
|
|
|
| -void ReplacementFragment::removeInterchangeNodes(Node* container)
|
| +void ReplacementFragment::removeInterchangeNodes(ContainerNode* container)
|
| {
|
| m_hasInterchangeNewlineAtStart = false;
|
| m_hasInterchangeNewlineAtEnd = false;
|
| @@ -300,7 +302,7 @@ void ReplacementFragment::removeInterchangeNodes(Node* container)
|
| // either the first node in the fragment or the first leaf in the fragment.
|
| Node* node = container->firstChild();
|
| while (node) {
|
| - if (isInterchangeNewlineNode(node)) {
|
| + if (isInterchangeHTMLBRElement(node)) {
|
| m_hasInterchangeNewlineAtStart = true;
|
| removeNode(node);
|
| break;
|
| @@ -313,7 +315,7 @@ void ReplacementFragment::removeInterchangeNodes(Node* container)
|
| // either the last node in the fragment or the last leaf in the fragment.
|
| node = container->lastChild();
|
| while (node) {
|
| - if (isInterchangeNewlineNode(node)) {
|
| + if (isInterchangeHTMLBRElement(node)) {
|
| m_hasInterchangeNewlineAtEnd = true;
|
| removeNode(node);
|
| break;
|
| @@ -324,9 +326,10 @@ void ReplacementFragment::removeInterchangeNodes(Node* container)
|
| node = container->firstChild();
|
| while (node) {
|
| RefPtrWillBeRawPtr<Node> next = NodeTraversal::next(*node);
|
| - if (isInterchangeConvertedSpaceSpan(node)) {
|
| - next = NodeTraversal::nextSkippingChildren(*node);
|
| - removeNodePreservingChildren(node);
|
| + if (isHTMLInterchangeConvertedSpaceSpan(node)) {
|
| + HTMLElement& element = toHTMLElement(*node);
|
| + next = NodeTraversal::nextSkippingChildren(element);
|
| + removeNodePreservingChildren(&element);
|
| }
|
| node = next.get();
|
| }
|
| @@ -428,15 +431,18 @@ bool ReplaceSelectionCommand::shouldMergeEnd(bool selectionEndWasEndOfParagraph)
|
| && shouldMerge(endOfInsertedContent, next);
|
| }
|
|
|
| -static bool isMailPasteAsQuotationNode(const Node* node)
|
| +static bool isMailPasteAsQuotationHTMLBlockQuoteElement(const Node* node)
|
| {
|
| - if (!node || !node->hasTagName(blockquoteTag) || toElement(node)->getAttribute(classAttr) != ApplePasteAsQuotation)
|
| + if (!node || !node->isHTMLElement())
|
| + return false;
|
| + const HTMLElement& element = toHTMLElement(*node);
|
| + if (!element.hasTagName(blockquoteTag) || element.getAttribute(classAttr) != ApplePasteAsQuotation)
|
| return false;
|
| UseCounter::count(node->document(), UseCounter::EditingApplePasteAsQuotation);
|
| return true;
|
| }
|
|
|
| -static bool isHeaderElement(const Node* a)
|
| +static bool isHTMLHeaderElement(const Node* a)
|
| {
|
| if (!a || !a->isHTMLElement())
|
| return false;
|
| @@ -450,9 +456,9 @@ static bool isHeaderElement(const Node* a)
|
| || element.hasTagName(h6Tag);
|
| }
|
|
|
| -static bool haveSameTagName(Node* a, Node* b)
|
| +static bool haveSameTagName(Element* a, Element* b)
|
| {
|
| - return a && b && a->isElementNode() && b->isElementNode() && toElement(a)->tagName() == toElement(b)->tagName();
|
| + return a && b && a->tagName() == b->tagName();
|
| }
|
|
|
| bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const VisiblePosition& destination)
|
| @@ -464,11 +470,11 @@ bool ReplaceSelectionCommand::shouldMerge(const VisiblePosition& source, const V
|
| Node* destinationNode = destination.deepEquivalent().deprecatedNode();
|
| Element* sourceBlock = enclosingBlock(sourceNode);
|
| Element* destinationBlock = enclosingBlock(destinationNode);
|
| - return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotationNode)
|
| + return !enclosingNodeOfType(source.deepEquivalent(), &isMailPasteAsQuotationHTMLBlockQuoteElement)
|
| && sourceBlock && (!sourceBlock->hasTagName(blockquoteTag) || isMailHTMLBlockquoteElement(sourceBlock))
|
| && enclosingListChild(sourceBlock) == enclosingListChild(destinationNode)
|
| && enclosingTableCell(source.deepEquivalent()) == enclosingTableCell(destination.deepEquivalent())
|
| - && (!isHeaderElement(sourceBlock) || haveSameTagName(sourceBlock, destinationBlock))
|
| + && (!isHTMLHeaderElement(sourceBlock) || haveSameTagName(sourceBlock, destinationBlock))
|
| // Don't merge to or from a position before or after a block because it would
|
| // be a no-op and cause infinite recursion.
|
| && !isBlock(sourceNode) && !isBlock(destinationNode);
|
| @@ -506,7 +512,7 @@ void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert
|
| EditingStyle::DoNotExtractMatchingStyle)) {
|
| // e.g. <font size="3" style="font-size: 20px;"> is converted to <font style="font-size: 20px;">
|
| for (size_t i = 0; i < attributes.size(); i++)
|
| - removeNodeAttribute(element, attributes[i]);
|
| + removeElementAttribute(htmlElement, attributes[i]);
|
| }
|
| }
|
|
|
| @@ -514,8 +520,10 @@ void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert
|
|
|
| // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region,
|
| // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>.
|
| - Node* blockquoteNode = !context || isMailPasteAsQuotationNode(context) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailHTMLBlockquoteElement, CanCrossEditingBoundary);
|
| - if (blockquoteNode)
|
| + HTMLQuoteElement* blockquoteElement = !context || isMailPasteAsQuotationHTMLBlockQuoteElement(context) ?
|
| + toHTMLQuoteElement(context) :
|
| + toHTMLQuoteElement(enclosingNodeOfType(firstPositionInNode(context), isMailHTMLBlockquoteElement, CanCrossEditingBoundary));
|
| + if (blockquoteElement)
|
| newInlineStyle->removeStyleFromRulesAndContext(element, document().documentElement());
|
|
|
| newInlineStyle->removeStyleFromRulesAndContext(element, context);
|
| @@ -527,7 +535,7 @@ void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert
|
| removeNodePreservingChildren(element);
|
| continue;
|
| }
|
| - removeNodeAttribute(element, styleAttr);
|
| + removeElementAttribute(element, styleAttr);
|
| } else if (newInlineStyle->style()->propertyCount() != inlineStyle->propertyCount()) {
|
| setNodeAttribute(element, styleAttr, AtomicString(newInlineStyle->style()->asText()));
|
| }
|
| @@ -542,11 +550,11 @@ void ReplaceSelectionCommand::removeRedundantStylesAndKeepStyleSpanInline(Insert
|
| }
|
|
|
| if (element->parentNode() && element->parentNode()->rendererIsRichlyEditable())
|
| - removeNodeAttribute(element, contenteditableAttr);
|
| + removeElementAttribute(element, contenteditableAttr);
|
|
|
| // WebKit used to not add display: inline and float: none on copy.
|
| // Keep this code around for backward compatibility
|
| - if (isLegacyAppleStyleSpan(element)) {
|
| + if (isLegacyAppleHTMLSpanElement(element)) {
|
| if (!element->hasChildren()) {
|
| insertedNodes.willRemoveNodePreservingChildren(*element);
|
| removeNodePreservingChildren(element);
|
| @@ -635,38 +643,39 @@ void ReplaceSelectionCommand::makeInsertedContentRoundTrippableWithHTMLTreeBuild
|
| if (!node->isHTMLElement())
|
| continue;
|
|
|
| - if (isProhibitedParagraphChild(toHTMLElement(node)->localName())) {
|
| - if (HTMLElement* paragraphElement = toHTMLElement(enclosingElementWithTag(positionInParentBeforeNode(*node), pTag)))
|
| - moveNodeOutOfAncestor(node, paragraphElement);
|
| + HTMLElement& element = toHTMLElement(*node);
|
| + if (isProhibitedParagraphChild(element.localName())) {
|
| + if (HTMLElement* paragraphElement = toHTMLElement(enclosingElementWithTag(positionInParentBeforeNode(element), pTag)))
|
| + moveElementOutOfAncestor(&element, paragraphElement);
|
| }
|
|
|
| - if (isHeaderElement(node.get())) {
|
| - if (HTMLElement* headerElement = toHTMLElement(highestEnclosingNodeOfType(positionInParentBeforeNode(*node), isHeaderElement)))
|
| - moveNodeOutOfAncestor(node, headerElement);
|
| + if (isHTMLHeaderElement(&element)) {
|
| + if (HTMLElement* headerElement = toHTMLElement(highestEnclosingNodeOfType(positionInParentBeforeNode(element), isHTMLHeaderElement)))
|
| + moveElementOutOfAncestor(&element, headerElement);
|
| }
|
| }
|
| }
|
|
|
| -void ReplaceSelectionCommand::moveNodeOutOfAncestor(PassRefPtrWillBeRawPtr<Node> prpNode, PassRefPtrWillBeRawPtr<ContainerNode> prpAncestor)
|
| +void ReplaceSelectionCommand::moveElementOutOfAncestor(PassRefPtrWillBeRawPtr<Element> prpElement, PassRefPtrWillBeRawPtr<ContainerNode> prpAncestor)
|
| {
|
| - RefPtrWillBeRawPtr<Node> node = prpNode;
|
| - RefPtrWillBeRawPtr<Node> ancestor = prpAncestor;
|
| + RefPtrWillBeRawPtr<Element> element = prpElement;
|
| + RefPtrWillBeRawPtr<ContainerNode> ancestor = prpAncestor;
|
|
|
| if (!ancestor->parentNode()->hasEditableStyle())
|
| return;
|
|
|
| - VisiblePosition positionAtEndOfNode(lastPositionInOrAfterNode(node.get()));
|
| + VisiblePosition positionAtEndOfNode(lastPositionInOrAfterNode(element.get()));
|
| VisiblePosition lastPositionInParagraph(lastPositionInNode(ancestor.get()));
|
| if (positionAtEndOfNode == lastPositionInParagraph) {
|
| - removeNode(node);
|
| + removeNode(element);
|
| if (ancestor->nextSibling())
|
| - insertNodeBefore(node, ancestor->nextSibling());
|
| + insertNodeBefore(element, ancestor->nextSibling());
|
| else
|
| - appendNode(node, ancestor->parentNode());
|
| + appendNode(element, ancestor->parentNode());
|
| } else {
|
| - RefPtrWillBeRawPtr<Node> nodeToSplitTo = splitTreeToNode(node.get(), ancestor.get(), true);
|
| - removeNode(node);
|
| - insertNodeBefore(node, nodeToSplitTo);
|
| + RefPtrWillBeRawPtr<Node> nodeToSplitTo = splitTreeToNode(element.get(), ancestor.get(), true);
|
| + removeNode(element);
|
| + insertNodeBefore(element, nodeToSplitTo);
|
| }
|
| if (!ancestor->hasChildren())
|
| removeNode(ancestor.release());
|
| @@ -701,7 +710,7 @@ void ReplaceSelectionCommand::removeUnrenderedTextNodesAtEnds(InsertedNodes& ins
|
| VisiblePosition ReplaceSelectionCommand::positionAtEndOfInsertedContent() const
|
| {
|
| // FIXME: Why is this hack here? What's special about <select> tags?
|
| - Element* enclosingSelect = enclosingElementWithTag(m_endOfInsertedContent, selectTag);
|
| + HTMLSelectElement* enclosingSelect = toHTMLSelectElement(enclosingElementWithTag(m_endOfInsertedContent, selectTag));
|
| return VisiblePosition(enclosingSelect ? lastPositionInOrAfterNode(enclosingSelect) : m_endOfInsertedContent);
|
| }
|
|
|
| @@ -735,21 +744,21 @@ static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const
|
|
|
| // Handling the case where we are doing Paste as Quotation or pasting into quoted content is more complicated (see handleStyleSpans)
|
| // and doesn't receive the optimization.
|
| - if (isMailPasteAsQuotationNode(topNode) || enclosingNodeOfType(firstPositionInOrBeforeNode(topNode), isMailHTMLBlockquoteElement, CanCrossEditingBoundary))
|
| + if (isMailPasteAsQuotationHTMLBlockQuoteElement(topNode) || enclosingNodeOfType(firstPositionInOrBeforeNode(topNode), isMailHTMLBlockquoteElement, CanCrossEditingBoundary))
|
| return false;
|
|
|
| // Either there are no style spans in the fragment or a WebKit client has added content to the fragment
|
| // before inserting it. Look for and handle style spans after insertion.
|
| - if (!isLegacyAppleStyleSpan(topNode))
|
| + if (!isLegacyAppleHTMLSpanElement(topNode))
|
| return false;
|
|
|
| - Node* wrappingStyleSpan = topNode;
|
| + HTMLSpanElement* wrappingStyleSpan = toHTMLSpanElement(topNode);
|
| RefPtrWillBeRawPtr<EditingStyle> styleAtInsertionPos = EditingStyle::create(insertionPos.parentAnchoredEquivalent());
|
| String styleText = styleAtInsertionPos->style()->asText();
|
|
|
| // FIXME: This string comparison is a naive way of comparing two styles.
|
| // We should be taking the diff and check that the diff is empty.
|
| - if (styleText != toElement(wrappingStyleSpan)->getAttribute(styleAttr))
|
| + if (styleText != wrappingStyleSpan->getAttribute(styleAttr))
|
| return false;
|
|
|
| fragment.removeNodePreservingChildren(wrappingStyleSpan);
|
| @@ -766,13 +775,13 @@ static bool handleStyleSpansBeforeInsertion(ReplacementFragment& fragment, const
|
| // or at copy time.
|
| void ReplaceSelectionCommand::handleStyleSpans(InsertedNodes& insertedNodes)
|
| {
|
| - HTMLElement* wrappingStyleSpan = 0;
|
| + HTMLSpanElement* wrappingStyleSpan = 0;
|
| // The style span that contains the source document's default style should be at
|
| // the top of the fragment, but Mail sometimes adds a wrapper (for Paste As Quotation),
|
| // so search for the top level style span instead of assuming it's at the top.
|
| for (Node* node = insertedNodes.firstNodeInserted(); node; node = NodeTraversal::next(*node)) {
|
| - if (isLegacyAppleStyleSpan(node)) {
|
| - wrappingStyleSpan = toHTMLElement(node);
|
| + if (isLegacyAppleHTMLSpanElement(node)) {
|
| + wrappingStyleSpan = toHTMLSpanElement(node);
|
| break;
|
| }
|
| }
|
| @@ -786,9 +795,11 @@ void ReplaceSelectionCommand::handleStyleSpans(InsertedNodes& insertedNodes)
|
| ContainerNode* context = wrappingStyleSpan->parentNode();
|
|
|
| // If Mail wraps the fragment with a Paste as Quotation blockquote, or if you're pasting into a quoted region,
|
| - // styles from blockquoteNode are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>.
|
| - Node* blockquoteNode = isMailPasteAsQuotationNode(context) ? context : enclosingNodeOfType(firstPositionInNode(context), isMailHTMLBlockquoteElement, CanCrossEditingBoundary);
|
| - if (blockquoteNode)
|
| + // styles from blockquoteElement are allowed to override those from the source document, see <rdar://problem/4930986> and <rdar://problem/5089327>.
|
| + HTMLQuoteElement* blockquoteElement = isMailPasteAsQuotationHTMLBlockQuoteElement(context) ?
|
| + toHTMLQuoteElement(context) :
|
| + toHTMLQuoteElement(enclosingNodeOfType(firstPositionInNode(context), isMailHTMLBlockquoteElement, CanCrossEditingBoundary));
|
| + if (blockquoteElement)
|
| context = document().documentElement();
|
|
|
| // This operation requires that only editing styles to be removed from sourceDocumentStyle.
|
| @@ -868,7 +879,7 @@ static Node* enclosingInline(Node* node)
|
| return node;
|
| }
|
|
|
| -static bool isInlineNodeWithStyle(const Node* node)
|
| +static bool isInlineHTMLElementWithStyle(const Node* node)
|
| {
|
| // We don't want to skip over any block elements.
|
| if (isBlock(node))
|
| @@ -882,25 +893,25 @@ static bool isInlineNodeWithStyle(const Node* node)
|
| const HTMLElement* element = toHTMLElement(node);
|
| const AtomicString& classAttributeValue = element->getAttribute(classAttr);
|
| if (classAttributeValue == AppleTabSpanClass) {
|
| - UseCounter::count(node->document(), UseCounter::EditingAppleTabSpanClass);
|
| + UseCounter::count(element->document(), UseCounter::EditingAppleTabSpanClass);
|
| return true;
|
| }
|
| if (classAttributeValue == AppleConvertedSpace) {
|
| - UseCounter::count(node->document(), UseCounter::EditingAppleConvertedSpace);
|
| + UseCounter::count(element->document(), UseCounter::EditingAppleConvertedSpace);
|
| return true;
|
| }
|
| if (classAttributeValue == ApplePasteAsQuotation) {
|
| - UseCounter::count(node->document(), UseCounter::EditingApplePasteAsQuotation);
|
| + UseCounter::count(element->document(), UseCounter::EditingApplePasteAsQuotation);
|
| return true;
|
| }
|
|
|
| return EditingStyle::elementIsStyledSpanOrHTMLEquivalent(element);
|
| }
|
|
|
| -inline Node* nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(const Position& insertionPos)
|
| +static inline HTMLElement* elementToSplitToAvoidPastingIntoInlineElementsWithStyle(const Position& insertionPos)
|
| {
|
| Element* containingBlock = enclosingBlock(insertionPos.containerNode());
|
| - return highestEnclosingNodeOfType(insertionPos, isInlineNodeWithStyle, CannotCrossEditingBoundary, containingBlock);
|
| + return toHTMLElement(highestEnclosingNodeOfType(insertionPos, isInlineHTMLElementWithStyle, CannotCrossEditingBoundary, containingBlock));
|
| }
|
|
|
| void ReplaceSelectionCommand::doApply()
|
| @@ -934,7 +945,7 @@ void ReplaceSelectionCommand::doApply()
|
| bool selectionEndWasEndOfParagraph = isEndOfParagraph(visibleEnd);
|
| bool selectionStartWasStartOfParagraph = isStartOfParagraph(visibleStart);
|
|
|
| - Node* enclosingBlockOfVisibleStart = enclosingBlock(visibleStart.deepEquivalent().deprecatedNode());
|
| + Element* enclosingBlockOfVisibleStart = enclosingBlock(visibleStart.deepEquivalent().deprecatedNode());
|
|
|
| Position insertionPos = selection.start();
|
| bool startIsInsideMailBlockquote = enclosingNodeOfType(insertionPos, isMailHTMLBlockquoteElement, CanCrossEditingBoundary);
|
| @@ -1011,12 +1022,12 @@ void ReplaceSelectionCommand::doApply()
|
| // NOTE: This would be an incorrect usage of downstream() if downstream() were changed to mean the last position after
|
| // p that maps to the same visible position as p (since in the case where a br is at the end of a block and collapsed
|
| // away, there are positions after the br which map to the same visible position as [br, 0]).
|
| - Node* endBR = isHTMLBRElement(*insertionPos.downstream().deprecatedNode()) ? insertionPos.downstream().deprecatedNode() : 0;
|
| + HTMLBRElement* endBR = isHTMLBRElement(*insertionPos.downstream().deprecatedNode()) ? toHTMLBRElement(insertionPos.downstream().deprecatedNode()) : 0;
|
| VisiblePosition originalVisPosBeforeEndBR;
|
| if (endBR)
|
| originalVisPosBeforeEndBR = VisiblePosition(positionBeforeNode(endBR), DOWNSTREAM).previous();
|
|
|
| - RefPtrWillBeRawPtr<Node> enclosingBlockOfInsertionPos = enclosingBlock(insertionPos.deprecatedNode());
|
| + RefPtrWillBeRawPtr<Element> enclosingBlockOfInsertionPos = enclosingBlock(insertionPos.deprecatedNode());
|
|
|
| // Adjust insertionPos to prevent nesting.
|
| // If the start was in a Mail blockquote, we will have already handled adjusting insertionPos above.
|
| @@ -1065,12 +1076,12 @@ void ReplaceSelectionCommand::doApply()
|
| insertionPos = firstPositionInNode(insertionPos.containerNode());
|
| }
|
|
|
| - if (RefPtrWillBeRawPtr<Node> nodeToSplitTo = nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(insertionPos)) {
|
| - if (insertionPos.containerNode() != nodeToSplitTo->parentNode()) {
|
| + if (RefPtrWillBeRawPtr<HTMLElement> elementToSplitTo = elementToSplitToAvoidPastingIntoInlineElementsWithStyle(insertionPos)) {
|
| + if (insertionPos.containerNode() != elementToSplitTo->parentNode()) {
|
| Node* splitStart = insertionPos.computeNodeAfterPosition();
|
| if (!splitStart)
|
| splitStart = insertionPos.containerNode();
|
| - nodeToSplitTo = splitTreeToNode(splitStart, nodeToSplitTo->parentNode()).get();
|
| + RefPtrWillBeRawPtr<Node> nodeToSplitTo = splitTreeToNode(splitStart, elementToSplitTo->parentNode()).get();
|
| insertionPos = positionInParentBeforeNode(*nodeToSplitTo);
|
| }
|
| }
|
| @@ -1096,8 +1107,8 @@ void ReplaceSelectionCommand::doApply()
|
|
|
| fragment.removeNode(refNode);
|
|
|
| - Node* blockStart = enclosingBlock(insertionPos.deprecatedNode());
|
| - if ((isHTMLListElement(refNode.get()) || (isLegacyAppleStyleSpan(refNode.get()) && isHTMLListElement(refNode->firstChild())))
|
| + Element* blockStart = enclosingBlock(insertionPos.deprecatedNode());
|
| + if ((isHTMLListElement(refNode.get()) || (isLegacyAppleHTMLSpanElement(refNode.get()) && isHTMLListElement(refNode->firstChild())))
|
| && blockStart && blockStart->renderer()->isListItem())
|
| refNode = insertAsListItems(toHTMLElement(refNode), blockStart, insertionPos, insertedNodes);
|
| else {
|
| @@ -1214,10 +1225,10 @@ void ReplaceSelectionCommand::doApply()
|
| if (selectionEndWasEndOfParagraph || !isEndOfParagraph(endOfInsertedContent) || next.isNull()) {
|
| if (!isStartOfParagraph(endOfInsertedContent)) {
|
| setEndingSelection(endOfInsertedContent);
|
| - Node* enclosingNode = enclosingBlock(endOfInsertedContent.deepEquivalent().deprecatedNode());
|
| - if (isListItem(enclosingNode)) {
|
| + Element* enclosingBlockElement = enclosingBlock(endOfInsertedContent.deepEquivalent().deprecatedNode());
|
| + if (isListItem(enclosingBlockElement)) {
|
| RefPtrWillBeRawPtr<HTMLLIElement> newListItem = createListItemElement(document());
|
| - insertNodeAfter(newListItem, enclosingNode);
|
| + insertNodeAfter(newListItem, enclosingBlockElement);
|
| setEndingSelection(VisiblePosition(firstPositionInNode(newListItem.get())));
|
| } else {
|
| // Use a default paragraph element (a plain div) for the empty paragraph, using the last paragraph
|
| @@ -1234,12 +1245,12 @@ void ReplaceSelectionCommand::doApply()
|
| // Select up to the beginning of the next paragraph.
|
| lastPositionToSelect = next.deepEquivalent().downstream();
|
| }
|
| -
|
| - } else
|
| + } else {
|
| mergeEndIfNeeded();
|
| + }
|
|
|
| - if (Node* mailBlockquote = enclosingNodeOfType(positionAtStartOfInsertedContent().deepEquivalent(), isMailPasteAsQuotationNode))
|
| - removeNodeAttribute(toElement(mailBlockquote), classAttr);
|
| + if (HTMLQuoteElement* mailBlockquote = toHTMLQuoteElement(enclosingNodeOfType(positionAtStartOfInsertedContent().deepEquivalent(), isMailPasteAsQuotationHTMLBlockQuoteElement)))
|
| + removeElementAttribute(mailBlockquote, classAttr);
|
|
|
| if (shouldPerformSmartReplace())
|
| addSpacesForSmartReplace();
|
| @@ -1252,7 +1263,7 @@ void ReplaceSelectionCommand::doApply()
|
| completeHTMLReplacement(lastPositionToSelect);
|
| }
|
|
|
| -bool ReplaceSelectionCommand::shouldRemoveEndBR(Node* endBR, const VisiblePosition& originalVisPosBeforeEndBR)
|
| +bool ReplaceSelectionCommand::shouldRemoveEndBR(HTMLBRElement* endBR, const VisiblePosition& originalVisPosBeforeEndBR)
|
| {
|
| if (!endBR || !endBR->inDocument())
|
| return false;
|
| @@ -1277,7 +1288,7 @@ bool ReplaceSelectionCommand::shouldPerformSmartReplace() const
|
| if (!m_smartReplace)
|
| return false;
|
|
|
| - Element* textControl = enclosingTextFormControl(positionAtStartOfInsertedContent().deepEquivalent());
|
| + HTMLTextFormControlElement* textControl = enclosingTextFormControl(positionAtStartOfInsertedContent().deepEquivalent());
|
| if (isHTMLInputElement(textControl) && toHTMLInputElement(textControl)->isPasswordField())
|
| return false; // Disable smart replace for password fields.
|
|
|
| @@ -1310,7 +1321,7 @@ void ReplaceSelectionCommand::addSpacesForSmartReplace()
|
| if (m_endOfInsertedContent.containerNode() == endNode)
|
| m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offsetInContainerNode() + 1);
|
| } else {
|
| - RefPtrWillBeRawPtr<Node> node = document().createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
|
| + RefPtrWillBeRawPtr<Text> node = document().createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
|
| insertNodeAfter(node, endNode);
|
| updateNodesInserted(node.get());
|
| }
|
| @@ -1334,7 +1345,7 @@ void ReplaceSelectionCommand::addSpacesForSmartReplace()
|
| if (m_endOfInsertedContent.containerNode() == startNode && m_endOfInsertedContent.offsetInContainerNode())
|
| m_endOfInsertedContent.moveToOffset(m_endOfInsertedContent.offsetInContainerNode() + 1);
|
| } else {
|
| - RefPtrWillBeRawPtr<Node> node = document().createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
|
| + RefPtrWillBeRawPtr<Text> node = document().createEditingTextNode(collapseWhiteSpace ? nonBreakingSpaceString() : " ");
|
| // Don't updateNodesInserted. Doing so would set m_endOfInsertedContent to be the node containing the leading space,
|
| // but m_endOfInsertedContent is supposed to mark the end of pasted content.
|
| insertNodeBefore(node, startNode);
|
| @@ -1438,7 +1449,7 @@ EditAction ReplaceSelectionCommand::editingAction() const
|
|
|
| // If the user is inserting a list into an existing list, instead of nesting the list,
|
| // we put the list items into the existing list.
|
| -Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtrWillBeRawPtr<HTMLElement> prpListElement, Node* insertionBlock, const Position& insertPos, InsertedNodes& insertedNodes)
|
| +Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtrWillBeRawPtr<HTMLElement> prpListElement, Element* insertionBlock, const Position& insertPos, InsertedNodes& insertedNodes)
|
| {
|
| RefPtrWillBeRawPtr<HTMLElement> listElement = prpListElement;
|
|
|
| @@ -1503,7 +1514,7 @@ bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f
|
| return false;
|
|
|
| // e.g. when "bar" is inserted after "foo" in <div><u>foo</u></div>, "bar" should not be underlined.
|
| - if (nodeToSplitToAvoidPastingIntoInlineNodesWithStyle(endingSelection().start()))
|
| + if (elementToSplitToAvoidPastingIntoInlineElementsWithStyle(endingSelection().start()))
|
| return false;
|
|
|
| RefPtrWillBeRawPtr<Node> nodeAfterInsertionPos = endingSelection().end().downstream().anchorNode();
|
| @@ -1516,7 +1527,7 @@ bool ReplaceSelectionCommand::performTrivialReplace(const ReplacementFragment& f
|
| return false;
|
|
|
| if (nodeAfterInsertionPos && nodeAfterInsertionPos->parentNode() && isHTMLBRElement(*nodeAfterInsertionPos)
|
| - && shouldRemoveEndBR(nodeAfterInsertionPos.get(), VisiblePosition(positionBeforeNode(nodeAfterInsertionPos.get()))))
|
| + && shouldRemoveEndBR(toHTMLBRElement(nodeAfterInsertionPos.get()), VisiblePosition(positionBeforeNode(nodeAfterInsertionPos.get()))))
|
| removeNodeAndPruneAncestors(nodeAfterInsertionPos.get());
|
|
|
| VisibleSelection selectionAfterReplace(m_selectReplacement ? start : end, end);
|
|
|