summaryrefslogtreecommitdiffstats
path: root/WebCore/editing/ApplyStyleCommand.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/editing/ApplyStyleCommand.cpp')
-rw-r--r--WebCore/editing/ApplyStyleCommand.cpp81
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());
}