2011-02-22 Ryosuke Niwa <rniwa@webkit.org>
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Feb 2011 02:22:33 +0000 (02:22 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Feb 2011 02:22:33 +0000 (02:22 +0000)
        Reviewed by Darin Adler.

        Deploy EditingStyle in removeInlineStyleFromElement and removeCSSStyle
        https://bugs.webkit.org/show_bug.cgi?id=54944

        Deployed EditingStyle in removeInlineStyleFromElement and removeCSSStyle.

        Also extracted EditingStyle::conflictsWithInlineStyleOfElement from ApplyStyleCommand::removeCSSStyle,
        which returns true iff the specified element has inline style that conflicts or matches the editing style.
        It also appends conflicting property IDs to the vector of property IDs if one is specified.

        * editing/ApplyStyleCommand.cpp:
        (WebCore::ApplyStyleCommand::applyBlockStyle): Calls removeCSSStyle.
        (WebCore::ApplyStyleCommand::applyInlineStyle): Calls shouldSplitTextElement.
        (WebCore::ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle): Calls removeInlineStyleFromElement.
        (WebCore::ApplyStyleCommand::removeInlineStyleFromElement): Takes EditingStyle* instead of CSSMutableStyleDeclaration*.
        (WebCore::ApplyStyleCommand::removeCSSStyle): Ditto; extracted the logic to decide properties to remove as
        conflictsWithInlineStyleOfElement.
        (WebCore::ApplyStyleCommand::highestAncestorWithConflictingInlineStyle): Calls shouldRemoveInlineStyleFromElement.
        (WebCore::ApplyStyleCommand::pushDownInlineStyleAroundNode): Calls removeInlineStyleFromElement.
        (WebCore::ApplyStyleCommand::removeInlineStyle): Ditto.
        (WebCore::ApplyStyleCommand::shouldSplitTextElement): Takes EditingStyle* instead of CSSMutableStyleDeclaration*.
        * editing/ApplyStyleCommand.h:
        (WebCore::ApplyStyleCommand::shouldRemoveInlineStyleFromElement): Ditto.
        * editing/EditingStyle.cpp:
        (WebCore::EditingStyle::conflictsWithInlineStyleOfElement): Extracted from ApplyStyleCommand::removeCSSStyle.
        * editing/EditingStyle.h:
        (WebCore::EditingStyle::conflictsWithInlineStyleOfElement): Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@79382 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/editing/ApplyStyleCommand.cpp
Source/WebCore/editing/ApplyStyleCommand.h
Source/WebCore/editing/EditingStyle.cpp
Source/WebCore/editing/EditingStyle.h

index f6a6f8d..6e366b4 100644 (file)
@@ -1,3 +1,34 @@
+2011-02-22  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Reviewed by Darin Adler.
+
+        Deploy EditingStyle in removeInlineStyleFromElement and removeCSSStyle
+        https://bugs.webkit.org/show_bug.cgi?id=54944
+
+        Deployed EditingStyle in removeInlineStyleFromElement and removeCSSStyle.
+
+        Also extracted EditingStyle::conflictsWithInlineStyleOfElement from ApplyStyleCommand::removeCSSStyle,
+        which returns true iff the specified element has inline style that conflicts or matches the editing style.
+        It also appends conflicting property IDs to the vector of property IDs if one is specified.
+
+        * editing/ApplyStyleCommand.cpp:
+        (WebCore::ApplyStyleCommand::applyBlockStyle): Calls removeCSSStyle.
+        (WebCore::ApplyStyleCommand::applyInlineStyle): Calls shouldSplitTextElement.
+        (WebCore::ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle): Calls removeInlineStyleFromElement.
+        (WebCore::ApplyStyleCommand::removeInlineStyleFromElement): Takes EditingStyle* instead of CSSMutableStyleDeclaration*.
+        (WebCore::ApplyStyleCommand::removeCSSStyle): Ditto; extracted the logic to decide properties to remove as
+        conflictsWithInlineStyleOfElement.
+        (WebCore::ApplyStyleCommand::highestAncestorWithConflictingInlineStyle): Calls shouldRemoveInlineStyleFromElement.
+        (WebCore::ApplyStyleCommand::pushDownInlineStyleAroundNode): Calls removeInlineStyleFromElement.
+        (WebCore::ApplyStyleCommand::removeInlineStyle): Ditto.
+        (WebCore::ApplyStyleCommand::shouldSplitTextElement): Takes EditingStyle* instead of CSSMutableStyleDeclaration*.
+        * editing/ApplyStyleCommand.h:
+        (WebCore::ApplyStyleCommand::shouldRemoveInlineStyleFromElement): Ditto.
+        * editing/EditingStyle.cpp:
+        (WebCore::EditingStyle::conflictsWithInlineStyleOfElement): Extracted from ApplyStyleCommand::removeCSSStyle.
+        * editing/EditingStyle.h:
+        (WebCore::EditingStyle::conflictsWithInlineStyleOfElement): Added.
+
 2011-02-22  Chang Shu  <cshu@webkit.org>
 
         Reviewed by Csaba Osztrogon√°c.
index 3e04dda..c79136a 100644 (file)
@@ -601,7 +601,7 @@ void ApplyStyleCommand::applyBlockStyle(EditingStyle *style)
             }
             ASSERT(block->isHTMLElement());
             if (block->isHTMLElement()) {
-                removeCSSStyle(style->style(), toHTMLElement(block.get()));
+                removeCSSStyle(style, toHTMLElement(block.get()));
                 if (!m_removeOnly)
                     addBlockStyle(styleChange, toHTMLElement(block.get()));
             }
@@ -876,7 +876,7 @@ void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
     // split the start node and containing element if the selection starts inside of it
     bool splitStart = isValidCaretPositionInTextNode(start);
     if (splitStart) {
-        if (shouldSplitTextElement(start.deprecatedNode()->parentElement(), style->style()))
+        if (shouldSplitTextElement(start.deprecatedNode()->parentElement(), style))
             splitTextElementAtStart(start, end);
         else
             splitTextAtStart(start, end);
@@ -888,7 +888,7 @@ void ApplyStyleCommand::applyInlineStyle(EditingStyle* style)
     // split the end node and containing element if the selection ends inside of it
     bool splitEnd = isValidCaretPositionInTextNode(end);
     if (splitEnd) {
-        if (shouldSplitTextElement(end.deprecatedNode()->parentElement(), style->style()))
+        if (shouldSplitTextElement(end.deprecatedNode()->parentElement(), style))
             splitTextElementAtEnd(start, end);
         else
             splitTextAtEnd(start, end);
@@ -1117,7 +1117,7 @@ bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(EditingStyle* styl
         RefPtr<Node> previousSibling = node->previousSibling();
         RefPtr<Node> nextSibling = node->nextSibling();
         RefPtr<ContainerNode> parent = node->parentNode();
-        removeInlineStyleFromElement(style->style(), toHTMLElement(node.get()), RemoveAlways);
+        removeInlineStyleFromElement(style, toHTMLElement(node.get()), RemoveAlways);
         if (!node->inDocument()) {
             // FIXME: We might need to update the start and the end of current selection here but need a test.
             if (runStart == node)
@@ -1130,7 +1130,7 @@ bool ApplyStyleCommand::removeStyleFromRunBeforeApplyingStyle(EditingStyle* styl
     return true;
 }
 
-bool ApplyStyleCommand::removeInlineStyleFromElement(CSSMutableStyleDeclaration* style, PassRefPtr<HTMLElement> element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle)
+bool ApplyStyleCommand::removeInlineStyleFromElement(EditingStyle* style, PassRefPtr<HTMLElement> element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle)
 {
     ASSERT(element);
 
@@ -1147,11 +1147,11 @@ bool ApplyStyleCommand::removeInlineStyleFromElement(CSSMutableStyleDeclaration*
         return true;
     }
 
-    if (!style)
+    if (!style->style())
         return false;
 
     bool removed = false;
-    if (removeImplicitlyStyledElement(style, element.get(), mode, extractedStyle))
+    if (removeImplicitlyStyledElement(style->style(), element.get(), mode, extractedStyle))
         removed = true;
 
     if (!element->inDocument())
@@ -1289,50 +1289,37 @@ void ApplyStyleCommand::replaceWithSpanOrRemoveIfWithoutAttributes(HTMLElement*&
     }
 }
 
-bool ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclaration* style, HTMLElement* element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle)
+bool ApplyStyleCommand::removeCSSStyle(EditingStyle* style, HTMLElement* element, InlineStyleRemovalMode mode, CSSMutableStyleDeclaration* extractedStyle)
 {
     ASSERT(style);
     ASSERT(element);
+    
+    if (mode == RemoveNone)
+        return style->conflictsWithInlineStyleOfElement(element);
 
-    CSSMutableStyleDeclaration* decl = element->inlineStyleDecl();
-    if (!decl)
+    Vector<CSSPropertyID> properties;
+    if (!style->conflictsWithInlineStyleOfElement(element, properties))
         return false;
 
-    bool removed = false;
-    CSSMutableStyleDeclaration::const_iterator end = style->end();
-    for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) {
-        CSSPropertyID propertyID = static_cast<CSSPropertyID>(it->id());
-        RefPtr<CSSValue> value = decl->getPropertyCSSValue(propertyID);
-        if (!value || (isTabSpanNode(element) && propertyID == CSSPropertyWhiteSpace))
-            continue;
-
-        removed = true;
-        if (mode == RemoveNone)
-            return true;
-
-        ExceptionCode ec = 0;
-        if (extractedStyle)
-            extractedStyle->setProperty(propertyID, value->cssText(), decl->getPropertyPriority(propertyID), ec);
-        removeCSSProperty(element, propertyID);
-
-        if (propertyID == CSSPropertyUnicodeBidi && !decl->getPropertyValue(CSSPropertyDirection).isEmpty()) {
-            if (extractedStyle)
-                extractedStyle->setProperty(CSSPropertyDirection, decl->getPropertyValue(CSSPropertyDirection), decl->getPropertyPriority(CSSPropertyDirection), ec);
-            removeCSSProperty(element, CSSPropertyDirection);
+    CSSMutableStyleDeclaration* inlineStyle = element->inlineStyleDecl();
+    ASSERT(inlineStyle);
+    for (size_t i = 0; i < properties.size(); i++) {
+        CSSPropertyID id = properties[i];
+        if (extractedStyle) {
+            ExceptionCode ec = 0;
+            extractedStyle->setProperty(id, inlineStyle->getPropertyValue(id), inlineStyle->getPropertyPriority(id), ec);
         }
+        removeCSSProperty(element, id);
     }
 
-    if (mode == RemoveNone)
-        return removed;
-
     // No need to serialize <foo style=""> if we just removed the last css property
-    if (decl->isEmpty())
+    if (inlineStyle->isEmpty())
         removeNodeAttribute(element, styleAttr);
 
     if (isSpanWithoutAttributesOrUnstyleStyleSpan(element))
         removeNodePreservingChildren(element);
 
-    return removed;
+    return true;
 }
 
 HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(EditingStyle* style, Node* node)
@@ -1344,7 +1331,7 @@ HTMLElement* ApplyStyleCommand::highestAncestorWithConflictingInlineStyle(Editin
     Node* unsplittableElement = unsplittableElementForPosition(firstPositionInOrBeforeNode(node));
 
     for (Node *n = node; n; n = n->parentNode()) {
-        if (n->isHTMLElement() && shouldRemoveInlineStyleFromElement(style->style(), toHTMLElement(n)))
+        if (n->isHTMLElement() && shouldRemoveInlineStyleFromElement(style, toHTMLElement(n)))
             result = toHTMLElement(n);
         // Should stop at the editable root (cannot cross editing boundary) and
         // also stop at the unsplittable element to be consistent with other UAs
@@ -1436,7 +1423,7 @@ void ApplyStyleCommand::pushDownInlineStyleAroundNode(EditingStyle* style, Node*
             elementsToPushDown.append(styledElement);
         }
         RefPtr<CSSMutableStyleDeclaration> styleToPushDown = CSSMutableStyleDeclaration::create();
-        removeInlineStyleFromElement(style->style(), toHTMLElement(current), RemoveIfNeeded, styleToPushDown.get());
+        removeInlineStyleFromElement(style, toHTMLElement(current), RemoveIfNeeded, styleToPushDown.get());
 
         // 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.
@@ -1513,7 +1500,7 @@ void ApplyStyleCommand::removeInlineStyle(EditingStyle* style, const Position &s
                 childNode = elem->firstChild();
             }
 
-            removeInlineStyleFromElement(style->style(), elem.get(), RemoveIfNeeded, styleToPushDown.get());
+            removeInlineStyleFromElement(style, elem.get(), RemoveIfNeeded, styleToPushDown.get());
             if (!elem->inDocument()) {
                 if (s.deprecatedNode() == elem) {
                     // Since elem must have been fully selected, and it is at the start
@@ -1622,7 +1609,7 @@ void ApplyStyleCommand::splitTextElementAtEnd(const Position& start, const Posit
     updateStartEnd(newStart, Position(prevNode->parentNode(), prevNode->nodeIndex() + 1, Position::PositionIsOffsetInAnchor));
 }
 
-bool ApplyStyleCommand::shouldSplitTextElement(Element* element, CSSMutableStyleDeclaration* style)
+bool ApplyStyleCommand::shouldSplitTextElement(Element* element, EditingStyle* style)
 {
     if (!element || !element->isHTMLElement())
         return false;
index 07e125c..2aea95e 100644 (file)
@@ -78,11 +78,11 @@ private:
     // style-removal helpers
     bool isStyledInlineElementToRemove(Element*) const;
     bool removeStyleFromRunBeforeApplyingStyle(EditingStyle*, RefPtr<Node>& runStart, RefPtr<Node>& runEnd);
-    bool removeInlineStyleFromElement(CSSMutableStyleDeclaration*, PassRefPtr<HTMLElement>, InlineStyleRemovalMode = RemoveIfNeeded, CSSMutableStyleDeclaration* extractedStyle = 0);
-    inline bool shouldRemoveInlineStyleFromElement(CSSMutableStyleDeclaration* style, HTMLElement* element) {return removeInlineStyleFromElement(style, element, RemoveNone);}
+    bool removeInlineStyleFromElement(EditingStyle*, PassRefPtr<HTMLElement>, InlineStyleRemovalMode = RemoveIfNeeded, CSSMutableStyleDeclaration* extractedStyle = 0);
+    inline bool shouldRemoveInlineStyleFromElement(EditingStyle* style, HTMLElement* element) {return removeInlineStyleFromElement(style, element, RemoveNone);}
     bool removeImplicitlyStyledElement(CSSMutableStyleDeclaration*, HTMLElement*, InlineStyleRemovalMode, CSSMutableStyleDeclaration* extractedStyle);
     void replaceWithSpanOrRemoveIfWithoutAttributes(HTMLElement*&);
-    bool removeCSSStyle(CSSMutableStyleDeclaration*, HTMLElement*, InlineStyleRemovalMode = RemoveIfNeeded, CSSMutableStyleDeclaration* extractedStyle = 0);
+    bool removeCSSStyle(EditingStyle*, HTMLElement*, InlineStyleRemovalMode = RemoveIfNeeded, CSSMutableStyleDeclaration* extractedStyle = 0);
     HTMLElement* highestAncestorWithConflictingInlineStyle(EditingStyle*, Node*);
     void applyInlineStyleToPushDown(Node*, CSSMutableStyleDeclaration*);
     void pushDownInlineStyleAroundNode(EditingStyle*, Node*);
@@ -102,7 +102,7 @@ private:
     void splitTextAtEnd(const Position& start, const Position& end);
     void splitTextElementAtStart(const Position& start, const Position& end);
     void splitTextElementAtEnd(const Position& start, const Position& end);
-    bool shouldSplitTextElement(Element* elem, CSSMutableStyleDeclaration*);
+    bool shouldSplitTextElement(Element*, EditingStyle*);
     bool isValidCaretPositionInTextNode(const Position& position);
     bool mergeStartWithPreviousIfIdentical(const Position& start, const Position& end);
     bool mergeEndWithNextIfIdentical(const Position& start, const Position& end);
index 191234c..507b376 100644 (file)
 #include "CSSMutableStyleDeclaration.h"
 #include "CSSValueKeywords.h"
 #include "Frame.h"
+#include "HTMLNames.h"
 #include "Node.h"
 #include "Position.h"
 #include "RenderStyle.h"
 #include "SelectionController.h"
+#include "StyledElement.h"
+#include "htmlediting.h"
 
 namespace WebCore {
 
@@ -322,6 +325,46 @@ void EditingStyle::collapseTextDecorationProperties()
     m_mutableStyle->removeProperty(CSSPropertyWebkitTextDecorationsInEffect);
 }
 
+bool EditingStyle::conflictsWithInlineStyleOfElement(StyledElement* element, Vector<CSSPropertyID>* conflictingProperties) const
+{
+    ASSERT(element);
+    ASSERT(!conflictingProperties || conflictingProperties->isEmpty());
+
+    CSSMutableStyleDeclaration* inlineStyle = element->inlineStyleDecl();
+    if (!m_mutableStyle || !inlineStyle)
+        return false;
+
+    if (!conflictingProperties) {
+        CSSMutableStyleDeclaration::const_iterator end = m_mutableStyle->end();
+        for (CSSMutableStyleDeclaration::const_iterator it = m_mutableStyle->begin(); it != end; ++it) {
+            CSSPropertyID propertyID = static_cast<CSSPropertyID>(it->id());
+
+            // We don't override whitespace property of a tab span because that would collapse the tab into a space.
+            if (propertyID == CSSPropertyWhiteSpace && isTabSpanNode(element))
+                continue;
+
+            if (inlineStyle->getPropertyCSSValue(propertyID))
+                return true;
+        }
+
+        return false;
+    }
+
+    CSSMutableStyleDeclaration::const_iterator end = m_mutableStyle->end();
+    for (CSSMutableStyleDeclaration::const_iterator it = m_mutableStyle->begin(); it != end; ++it) {
+        CSSPropertyID propertyID = static_cast<CSSPropertyID>(it->id());
+        if ((propertyID == CSSPropertyWhiteSpace && isTabSpanNode(element)) || !inlineStyle->getPropertyCSSValue(propertyID))
+            continue;
+
+        if (propertyID == CSSPropertyUnicodeBidi && inlineStyle->getPropertyCSSValue(CSSPropertyDirection))
+            conflictingProperties->append(CSSPropertyDirection);
+
+        conflictingProperties->append(propertyID);
+    }
+
+    return !conflictingProperties->isEmpty();
+}
+
 void EditingStyle::prepareToApplyAt(const Position& position, ShouldPreserveWritingDirection shouldPreserveWritingDirection)
 {
     if (!m_mutableStyle)
index a1031f7..f6aa6a1 100644 (file)
 #ifndef EditingStyle_h
 #define EditingStyle_h
 
+#include "CSSPropertyNames.h"
 #include "WritingDirection.h"
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
 
 namespace WebCore {
 
@@ -43,6 +45,7 @@ class CSSMutableStyleDeclaration;
 class Node;
 class Position;
 class RenderStyle;
+class StyledElement;
 
 class EditingStyle : public RefCounted<EditingStyle> {
 public:
@@ -87,6 +90,11 @@ public:
     void removeStyleConflictingWithStyleOfNode(Node*);
     void removeNonEditingProperties();
     void collapseTextDecorationProperties();
+    bool conflictsWithInlineStyleOfElement(StyledElement* element) const { return conflictsWithInlineStyleOfElement(element, 0); }
+    bool conflictsWithInlineStyleOfElement(StyledElement* element, Vector<CSSPropertyID>& conflictingProperties) const
+    {
+        return conflictsWithInlineStyleOfElement(element, &conflictingProperties);
+    }
     void prepareToApplyAt(const Position&, ShouldPreserveWritingDirection = DoNotPreserveWritingDirection);
 
     float fontSizeDelta() const { return m_fontSizeDelta; }
@@ -101,6 +109,7 @@ private:
     void removeTextFillAndStrokeColorsIfNeeded(RenderStyle*);
     void replaceFontSizeByKeywordIfPossible(RenderStyle*, CSSComputedStyleDeclaration*);
     void extractFontSizeDelta();
+    bool conflictsWithInlineStyleOfElement(StyledElement*, Vector<CSSPropertyID>* conflictingProperties) const;
 
     RefPtr<CSSMutableStyleDeclaration> m_mutableStyle;
     bool m_shouldUseFixedDefaultFontSize;