summaryrefslogtreecommitdiffstats
path: root/WebCore/editing/ApplyStyleCommand.cpp
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2010-11-04 12:00:17 -0700
committerJohn Reck <jreck@google.com>2010-11-09 11:35:04 -0800
commite14391e94c850b8bd03680c23b38978db68687a8 (patch)
tree3fed87e6620fecaf3edc7259ae58a11662bedcb2 /WebCore/editing/ApplyStyleCommand.cpp
parent1bd705833a68f07850cf7e204b26f8d328d16951 (diff)
downloadexternal_webkit-e14391e94c850b8bd03680c23b38978db68687a8.zip
external_webkit-e14391e94c850b8bd03680c23b38978db68687a8.tar.gz
external_webkit-e14391e94c850b8bd03680c23b38978db68687a8.tar.bz2
Merge Webkit at r70949: Initial merge by git.
Change-Id: I77b8645c083b5d0da8dba73ed01d4014aab9848e
Diffstat (limited to 'WebCore/editing/ApplyStyleCommand.cpp')
-rw-r--r--WebCore/editing/ApplyStyleCommand.cpp75
1 files changed, 54 insertions, 21 deletions
diff --git a/WebCore/editing/ApplyStyleCommand.cpp b/WebCore/editing/ApplyStyleCommand.cpp
index 3f60a8b..8862da7 100644
--- a/WebCore/editing/ApplyStyleCommand.cpp
+++ b/WebCore/editing/ApplyStyleCommand.cpp
@@ -538,6 +538,7 @@ ApplyStyleCommand::ApplyStyleCommand(Document* document, CSSStyleDeclaration* st
, m_useEndingSelection(true)
, m_styledInlineElement(0)
, m_removeOnly(false)
+ , m_isInlineElementToRemoveFunction(0)
{
}
@@ -551,6 +552,7 @@ ApplyStyleCommand::ApplyStyleCommand(Document* document, CSSStyleDeclaration* st
, m_useEndingSelection(false)
, m_styledInlineElement(0)
, m_removeOnly(false)
+ , m_isInlineElementToRemoveFunction(0)
{
}
@@ -564,6 +566,21 @@ ApplyStyleCommand::ApplyStyleCommand(PassRefPtr<Element> element, bool removeOnl
, m_useEndingSelection(true)
, m_styledInlineElement(element)
, m_removeOnly(removeOnly)
+ , m_isInlineElementToRemoveFunction(0)
+{
+}
+
+ApplyStyleCommand::ApplyStyleCommand(Document* document, CSSStyleDeclaration* style, IsInlineElementToRemoveFunction isInlineElementToRemoveFunction, EditAction editingAction)
+ : CompositeEditCommand(document)
+ , m_style(style->makeMutable())
+ , m_editingAction(editingAction)
+ , m_propertyLevel(PropertyDefault)
+ , m_start(endingSelection().start().downstream())
+ , m_end(endingSelection().end().upstream())
+ , m_useEndingSelection(true)
+ , m_styledInlineElement(0)
+ , m_removeOnly(true)
+ , m_isInlineElementToRemoveFunction(isInlineElementToRemoveFunction)
{
}
@@ -605,7 +622,7 @@ void ApplyStyleCommand::doApply()
applyBlockStyle(blockStyle.get());
// apply any remaining styles to the inline elements
// NOTE: hopefully, this string comparison is the same as checking for a non-null diff
- if (blockStyle->length() < m_style->length() || m_styledInlineElement) {
+ if (blockStyle->length() < m_style->length() || m_styledInlineElement || m_isInlineElementToRemoveFunction) {
RefPtr<CSSMutableStyleDeclaration> inlineStyle = m_style->copy();
applyRelativeFontStyleChange(inlineStyle.get());
blockStyle->diff(inlineStyle.get());
@@ -664,9 +681,11 @@ void ApplyStyleCommand::applyBlockStyle(CSSMutableStyleDeclaration *style)
StyleChange styleChange(style, paragraphStart.deepEquivalent());
if (styleChange.cssStyle().length() || m_removeOnly) {
RefPtr<Node> block = enclosingBlock(paragraphStart.deepEquivalent().node());
- RefPtr<Node> newBlock = moveParagraphContentsToNewBlockIfNecessary(paragraphStart.deepEquivalent());
- if (newBlock)
- block = newBlock;
+ if (!m_removeOnly) {
+ RefPtr<Node> newBlock = moveParagraphContentsToNewBlockIfNecessary(paragraphStart.deepEquivalent());
+ if (newBlock)
+ block = newBlock;
+ }
ASSERT(block->isHTMLElement());
if (block->isHTMLElement()) {
removeCSSStyle(style, static_cast<HTMLElement*>(block.get()));
@@ -1104,8 +1123,10 @@ void ApplyStyleCommand::fixRangeAndApplyInlineStyle(CSSMutableStyleDeclaration*
// to generate <font color="blue" size="4">hello</font> instead of <font color="blue"><font size="4">hello</font></font>
RefPtr<Range> range = Range::create(startNode->document(), start, end);
Element* editableRoot = startNode->rootEditableElement();
- while (editableRoot && startNode->parentNode() != editableRoot && isNodeVisiblyContainedWithin(startNode->parentNode(), range.get()))
- startNode = startNode->parentNode();
+ if (startNode != editableRoot) {
+ while (editableRoot && startNode->parentNode() != editableRoot && isNodeVisiblyContainedWithin(startNode->parentNode(), range.get()))
+ startNode = startNode->parentNode();
+ }
applyInlineStyleToNodeRange(style, startNode, pastEndNode);
}
@@ -1126,6 +1147,9 @@ static bool containsNonEditableRegion(Node* node)
void ApplyStyleCommand::applyInlineStyleToNodeRange(CSSMutableStyleDeclaration* style, Node* node, Node* pastEndNode)
{
+ if (m_removeOnly)
+ return;
+
for (Node* next; node && node != pastEndNode; node = next) {
next = node->traverseNextNode();
@@ -1171,10 +1195,16 @@ void ApplyStyleCommand::applyInlineStyleToNodeRange(CSSMutableStyleDeclaration*
if (!removeStyleFromRunBeforeApplyingStyle(style, node, runEnd))
continue;
- addInlineStyleIfNeeded(style, node, runEnd, m_removeOnly ? DoNotAddStyledElement : AddStyledElement);
+ addInlineStyleIfNeeded(style, node, runEnd, AddStyledElement);
}
}
+bool ApplyStyleCommand::isStyledInlineElementToRemove(Element* element) const
+{
+ return (m_styledInlineElement && element->hasTagName(m_styledInlineElement->tagQName()))
+ || (m_isInlineElementToRemoveFunction && m_isInlineElementToRemoveFunction(element));
+}
+
bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(CSSMutableStyleDeclaration* style, Node*& runStart, Node*& runEnd)
{
ASSERT(runStart && runEnd && runStart->parentNode() == runEnd->parentNode());
@@ -1183,6 +1213,7 @@ bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(CSSMutableStyleDec
for (Node* node = runStart; node && node != pastEndNode; node = node->traverseNextNode()) {
if (node->childNodeCount())
continue;
+ // We don't consider m_isInlineElementToRemoveFunction here because we never apply style when m_isInlineElementToRemoveFunction is specified
if (getPropertiesNotIn(style, computedStyle(node).get())->length()
|| (m_styledInlineElement && !enclosingNodeWithTag(positionBeforeNode(node), m_styledInlineElement->tagQName()))) {
needToApplyStyle = true;
@@ -1222,7 +1253,7 @@ bool ApplyStyleCommand::removeInlineStyleFromElement(CSSMutableStyleDeclaration*
if (!element->parentNode() || !element->parentNode()->isContentEditable())
return false;
- if (m_styledInlineElement && element->hasTagName(m_styledInlineElement->tagQName())) {
+ if (isStyledInlineElementToRemove(element)) {
if (mode == RemoveNone)
return true;
ASSERT(extractedStyle);
@@ -1331,7 +1362,7 @@ bool ApplyStyleCommand::removeImplicitlyStyledElement(CSSMutableStyleDeclaration
continue; // If CSS value is primitive, then skip if they are equal.
}
- if (extractedStyle)
+ if (extractedStyle && mapValue)
extractedStyle->setProperty(equivalent.propertyID, mapValue->cssText());
if (mode == RemoveNone)
@@ -1504,6 +1535,9 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration
// The outer loop is traversing the tree vertically from highestAncestor to targetNode
Node* current = highestAncestor;
+ // Along the way, styled elements that contain targetNode are removed and accumulated into elementsToPushDown.
+ // Each child of the removed element, exclusing ancestors of targetNode, is then wrapped by clones of elements in elementsToPushDown.
+ Vector<RefPtr<Element> > elementsToPushDown;
while (current != targetNode) {
ASSERT(current);
ASSERT(current->isHTMLElement());
@@ -1511,8 +1545,10 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration
Node* child = current->firstChild();
Node* lastChild = current->lastChild();
RefPtr<StyledElement> styledElement;
- if (current->isStyledElement() && m_styledInlineElement && current->hasTagName(m_styledInlineElement->tagQName()))
+ if (current->isStyledElement() && isStyledInlineElementToRemove(static_cast<Element*>(current))) {
styledElement = static_cast<StyledElement*>(current);
+ elementsToPushDown.append(styledElement);
+ }
RefPtr<CSSMutableStyleDeclaration> styleToPushDown = CSSMutableStyleDeclaration::create();
removeInlineStyleFromElement(style, static_cast<HTMLElement*>(current), RemoveIfNeeded, styleToPushDown.get());
@@ -1521,17 +1557,14 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(CSSMutableStyleDeclaration
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
+ if (!child->contains(targetNode) && elementsToPushDown.size()) {
+ for (size_t i = 0; i < elementsToPushDown.size(); i++) {
+ RefPtr<Element> wrapper = elementsToPushDown[i]->cloneElementWithoutChildren();
+ ExceptionCode ec = 0;
+ wrapper->removeAttribute(styleAttr, ec);
+ ASSERT(!ec);
surroundNodeRangeWithElement(child, child, wrapper);
+ }
}
// Apply text decoration to all nodes containing targetNode and their siblings but NOT to targetNode
@@ -1594,7 +1627,7 @@ void ApplyStyleCommand::removeInlineStyle(PassRefPtr<CSSMutableStyleDeclaration>
RefPtr<Node> next = elem->traverseNextNode();
RefPtr<CSSMutableStyleDeclaration> styleToPushDown;
PassRefPtr<Node> childNode = 0;
- if (m_styledInlineElement && elem->hasTagName(m_styledInlineElement->tagQName())) {
+ if (isStyledInlineElementToRemove(elem.get())) {
styleToPushDown = CSSMutableStyleDeclaration::create();
childNode = elem->firstChild();
}