diff options
Diffstat (limited to 'WebCore/editing/ApplyStyleCommand.cpp')
-rw-r--r-- | WebCore/editing/ApplyStyleCommand.cpp | 81 |
1 files changed, 62 insertions, 19 deletions
diff --git a/WebCore/editing/ApplyStyleCommand.cpp b/WebCore/editing/ApplyStyleCommand.cpp index bfbfab8..0a02e7a 100644 --- a/WebCore/editing/ApplyStyleCommand.cpp +++ b/WebCore/editing/ApplyStyleCommand.cpp @@ -90,6 +90,23 @@ public: String fontFace() { return m_applyFontFace; } String fontSize() { return m_applyFontSize; } + bool operator==(const StyleChange& other) + { + return m_cssStyle == other.m_cssStyle + && m_applyBold == other.m_applyBold + && m_applyItalic == other.m_applyItalic + && m_applyUnderline == other.m_applyUnderline + && m_applyLineThrough == other.m_applyLineThrough + && m_applySubscript == other.m_applySubscript + && m_applySuperscript == other.m_applySuperscript + && m_applyFontColor == other.m_applyFontColor + && m_applyFontFace == other.m_applyFontFace + && m_applyFontSize == other.m_applyFontSize; + } + bool operator!=(const StyleChange& other) + { + return !(*this == other); + } private: void init(PassRefPtr<CSSStyleDeclaration>, const Position&); void reconcileTextDecorationProperties(CSSMutableStyleDeclaration*); @@ -1103,14 +1120,17 @@ void ApplyStyleCommand::applyInlineStyleToRange(CSSMutableStyleDeclaration* styl Node* runStart = node; // Find the end of the run. Node* sibling = node->nextSibling(); - while (sibling && sibling != pastEndNode && (!sibling->isElementNode() || sibling->hasTagName(brTag)) && !isBlock(sibling)) { + StyleChange startChange(style, Position(node, 0)); + while (sibling && sibling != pastEndNode && !sibling->contains(pastEndNode) + && (!isBlock(sibling) || sibling->hasTagName(brTag)) + && StyleChange(style, Position(sibling, 0)) == startChange) { node = sibling; sibling = node->nextSibling(); } // Recompute next, since node has changed. - next = node->traverseNextNode(); + next = node->traverseNextSibling(); // Apply the style to the run. - addInlineStyleIfNeeded(style, runStart, node); + addInlineStyleIfNeeded(style, runStart, node, m_removeOnly ? DoNotAddStyledElement : AddStyledElement); } } } @@ -1344,7 +1364,7 @@ HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(CSSMut return result; } -PassRefPtr<CSSMutableStyleDeclaration> ApplyStyleCommand::extractInlineStyleToPushDown(Node* node, const Vector<int>& properties) +PassRefPtr<CSSMutableStyleDeclaration> ApplyStyleCommand::extractInlineStyleToPushDown(Node* node, bool isStyledElement, const Vector<int>& properties) { ASSERT(node); ASSERT(node->isElementNode()); @@ -1353,13 +1373,17 @@ PassRefPtr<CSSMutableStyleDeclaration> ApplyStyleCommand::extractInlineStyleToPu if (!node->isHTMLElement()) return 0; - HTMLElement *element = static_cast<HTMLElement *>(node); + HTMLElement* element = static_cast<HTMLElement*>(node); RefPtr<CSSMutableStyleDeclaration> style = element->inlineStyleDecl(); + if (isStyledElement) { + removeNodePreservingChildren(element); + return style.release(); + } + if (!style) return 0; style = style->copyPropertiesInSet(properties.data(), properties.size()); - for (size_t i = 0; i < properties.size(); i++) { RefPtr<CSSValue> property = style->getPropertyCSSValue(properties[i]); if (property) @@ -1429,7 +1453,10 @@ void ApplyStyleCommand::applyInlineStyleToPushDown(Node* node, CSSMutableStyleDe return; // FIXME: addInlineStyleIfNeeded may override the style of node - addInlineStyleIfNeeded(style, node, node); + // We can't wrap node with the styled element here because new styled element will never be removed if we did. + // If we modified the child pointer in pushDownInlineStyleAroundNode to point to new style element + // then we fall into an infinite loop where we keep removing and adding styled element wrapping node. + addInlineStyleIfNeeded(style, node, node, DoNotAddStyledElement); } void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration* style, Node* targetNode) @@ -1450,14 +1477,33 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration ASSERT(current->isHTMLElement()); ASSERT(current->contains(targetNode)); Node* child = current->firstChild(); - RefPtr<CSSMutableStyleDeclaration> styleToPushDown = extractInlineStyleToPushDown(current, properties); + Node* lastChild = current->lastChild(); + RefPtr<StyledElement> styledElement; + if (current->isStyledElement() && m_styledInlineElement && current->hasTagName(m_styledInlineElement->tagQName())) + styledElement = static_cast<StyledElement*>(current); + RefPtr<CSSMutableStyleDeclaration> styleToPushDown = extractInlineStyleToPushDown(current, styledElement, properties); // The inner loop will go through children on each level + // FIXME: we should aggregate inline child elements together so that we don't wrap each child separately. while (child) { Node* nextChild = child->nextSibling(); + if (child != targetNode && styledElement) { + // If child has children, wrap children of child by a clone of the styled element to avoid infinite loop. + // Otherwise, wrap the child by the styled element, and we won't fall into an infinite loop. + RefPtr<Element> wrapper = styledElement->cloneElementWithoutChildren(); + ExceptionCode ec = 0; + wrapper->removeAttribute(styleAttr, ec); + ASSERT(!ec); + if (child->firstChild()) + surroundNodeRangeWithElement(child->firstChild(), child->lastChild(), wrapper); + else + surroundNodeRangeWithElement(child, child, wrapper); + } + // Apply text decoration to all nodes containing targetNode and their siblings but NOT to targetNode - if (child != targetNode) + // But if we've removed styledElement then go ahead and always apply the style. + if (child != targetNode || styledElement) applyInlineStyleToPushDown(child, styleToPushDown.get()); // We found the next node for the outer loop (contains targetNode) @@ -1465,6 +1511,8 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration if (child == targetNode || child->contains(targetNode)) current = child; + if (child == lastChild || child->contains(lastChild)) + break; child = nextChild; } } @@ -1737,11 +1785,9 @@ void ApplyStyleCommand::surroundNodeRangeWithElement(Node* startNode, Node* endN Node* node = startNode; while (1) { - Node* next = node->traverseNextNode(); - if (node->childNodeCount() == 0 && node->renderer() && node->renderer()->isInline()) { - removeNode(node); - appendNode(node, element); - } + Node* next = node->nextSibling(); + removeNode(node); + appendNode(node, element); if (node == endNode) break; node = next; @@ -1779,11 +1825,8 @@ void ApplyStyleCommand::addBlockStyle(const StyleChange& styleChange, HTMLElemen setNodeAttribute(block, styleAttr, cssText); } -void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style, Node *startNode, Node *endNode) +void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style, Node *startNode, Node *endNode, EAddStyledElement addStyledElement) { - if (m_removeOnly) - return; - StyleChange styleChange(style, Position(startNode, 0)); // Font tags need to go outside of CSS so that CSS font sizes override leagcy font sizes. @@ -1823,7 +1866,7 @@ void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style else if (styleChange.applySuperscript()) surroundNodeRangeWithElement(startNode, endNode, createHTMLElement(document(), supTag)); - if (m_styledInlineElement) + if (m_styledInlineElement && addStyledElement == AddStyledElement) surroundNodeRangeWithElement(startNode, endNode, m_styledInlineElement->cloneElementWithoutChildren()); } |