2010-10-22  Alexander Pavlov  <apavlov@chromium.org>

        Reviewed by Pavel Feldman.

        Web Inspector: Implement property toggling in InspectorCSSAgent

        This change implements enablement/disablement and setting of style properties.
        Disabled properties are persisted in the (top-level) scope of InspectorStyleSheet.
        https://bugs.webkit.org/show_bug.cgi?id=47339

        Drive-by: fixes for the Web Inspector Protocol format.

        * inspector/InspectorCSSAgent.cpp:
        (WebCore::InspectorCSSAgent::getComputedStyleForNode2):
        (WebCore::InspectorCSSAgent::getInheritedStylesForNode2):
        (WebCore::InspectorCSSAgent::setPropertyText2):
        (WebCore::InspectorCSSAgent::toggleProperty2):
        (WebCore::InspectorCSSAgent::setRuleSelector2):
        (WebCore::InspectorCSSAgent::buildObjectForAttributeStyles):
        * inspector/InspectorCSSAgent.h:
        * inspector/InspectorStyleSheet.cpp:
        (WebCore::InspectorStyle::buildObjectForStyle):
        (WebCore::InspectorStyle::setPropertyText):
        (WebCore::InspectorStyle::toggleProperty):
        (WebCore::InspectorStyle::disabledIndexByOrdinal):
        (WebCore::InspectorStyle::styleText):
        (WebCore::InspectorStyle::disableProperty):
        (WebCore::InspectorStyle::enableProperty):
        (WebCore::InspectorStyle::populateAllProperties):
        (WebCore::InspectorStyle::populateObjectWithStyleProperties):
        (WebCore::InspectorStyle::shiftDisabledProperties):
        (WebCore::InspectorStyle::replacePropertyInStyleText):
        (WebCore::InspectorStyle::shorthandValue):
        (WebCore::InspectorStyle::shorthandPriority):
        (WebCore::InspectorStyle::longhandProperties):
        (WebCore::InspectorStyleSheet::setText):
        (WebCore::InspectorStyleSheet::setRuleSelector):
        (WebCore::InspectorStyleSheet::addRule):
        (WebCore::InspectorStyleSheet::ruleForId):
        (WebCore::InspectorStyleSheet::buildObjectForStyleSheet):
        (WebCore::InspectorStyleSheet::buildObjectForRule):
        (WebCore::InspectorStyleSheet::buildObjectForStyle):
        (WebCore::InspectorStyleSheet::setPropertyText):
        (WebCore::InspectorStyleSheet::toggleProperty):
        (WebCore::InspectorStyleSheet::styleForId):
        (WebCore::InspectorStyleSheet::inspectorStyleForId):
        (WebCore::InspectorStyleSheet::rememberInspectorStyle):
        (WebCore::InspectorStyleSheet::forgetInspectorStyle):
        (WebCore::InspectorStyleSheet::ruleOrStyleId):
        (WebCore::InspectorStyleSheet::ensureText):
        (WebCore::InspectorStyleSheet::setStyleText):
        (WebCore::InspectorStyleSheet::styleSheetTextWithChangedStyle):
        (WebCore::InspectorStyleSheet::ruleId):
        (WebCore::InspectorStyleSheet::revalidateStyle):
        (WebCore::InspectorStyleSheet::originalStyleSheetText):
        (WebCore::InspectorStyleSheet::resourceStyleSheetText):
        (WebCore::InspectorStyleSheetForInlineStyle::InspectorStyleSheetForInlineStyle):
        (WebCore::InspectorStyleSheetForInlineStyle::setStyleText):
        (WebCore::InspectorStyleSheetForInlineStyle::inspectorStyleForId):
        * inspector/InspectorStyleSheet.h:
        (WebCore::InspectorCSSId::createFromParts):
        (WebCore::InspectorCSSId::InspectorCSSId):
        (WebCore::InspectorCSSId::styleSheetId):
        (WebCore::InspectorCSSId::ordinal):
        (WebCore::InspectorCSSId::isEmpty):
        (WebCore::InspectorCSSId::asString):
        (WebCore::InspectorStyleProperty::InspectorStyleProperty):
        (WebCore::InspectorStyle::create):
        (WebCore::InspectorStyle::InspectorStyle):
        (WebCore::InspectorStyle::cssStyle):
        (WebCore::InspectorStyle::hasDisabledProperties):
        (WebCore::InspectorStyleSheet::styleId):
        (WebCore::InspectorStyleSheetForInlineStyle::styleForId):
        (WebCore::InspectorStyleSheetForInlineStyle::ruleSourceDataFor):
        (WebCore::InspectorStyleSheetForInlineStyle::rememberInspectorStyle):
        (WebCore::InspectorStyleSheetForInlineStyle::forgetInspectorStyle):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@70306 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/inspector/InspectorCSSAgent.cpp b/WebCore/inspector/InspectorCSSAgent.cpp
index e0fab85..d1f7412 100644
--- a/WebCore/inspector/InspectorCSSAgent.cpp
+++ b/WebCore/inspector/InspectorCSSAgent.cpp
@@ -49,7 +49,8 @@
 #include <wtf/Vector.h>
 #include <wtf/text/CString.h>
 
-
+// Currently implemented model:
+//
 // cssProperty = {
 //    name          : <string>,
 //    value         : <string>,
@@ -62,85 +63,57 @@
 //    endOffset     : <number>, // Optional - property text end offset in enclosing style declaration. Absent for computed styles and such.
 // }
 //
+// name + value + priority : present when the property is enabled
+// text                    : present when the property is disabled
+//
+// For disabled properties, startOffset === endOffset === insertion point for the property.
+//
 // status:
 // "disabled" == property disabled by user
 // "active" == property participates in the computed style calculation
 // "inactive" == property does no participate in the computed style calculation (i.e. overridden by a subsequent property with the same name)
 // "style" == property is active and originates from the WebCore CSSStyleDeclaration rather than CSS source code (e.g. implicit longhand properties)
 //
-//
 // cssStyle = {
-//    styleId         : <number>, // Optional
-//    styleSheetId    : <number>, // Parent: -1 for inline styles (<foo style="..">)
-//    cssProperties   : [
+//    styleId            : <string>, // Optional
+//    cssProperties      : [
 //                          #cssProperty,
 //                          ...
 //                          #cssProperty
-//                    ],
-//    shorthandValues : {
+//                         ],
+//    shorthandValues    : {
 //                          shorthandName1 : shorthandValue1,
 //                          shorthandName2 : shorthandValue2
-//                      },
-//    cssText         : <string>, // declaration text
-//    properties      : { } // ???
+//                         },
+//    cssText            : <string>, // Optional - declaration text
+//    properties         : { width, height }
 // }
 //
-// // TODO:
-// // - convert disabledProperties to enabled flag.
-// // - convert width, height to properties
-//
 // cssRule = {
-//    ruleId       : <number>,
-//    selectorText : <string>
-//    sourceURL    : <string>
-//    sourceLine   : <string>
-//    styleSheetId : <number> // also found in style
-//    origin       : <string> // "" || "user-agent" || "user" || "inspector"
+//    ruleId       : <string>, // Optional
+//    selectorText : <string>,
+//    sourceURL    : <string>,
+//    sourceLine   : <string>,
+//    origin       : <string>, // "" || "user-agent" || "user" || "inspector"
 //    style        : #cssStyle
 // }
 //
-// // TODO:
-// // - fix origin
-// // - add sourceURL
-// // - fix parentStyleSheetId
-//
 // cssStyleSheet = {
 //    styleSheetId   : <number>
-//    href           : <string>
+//    sourceURL      : <string>
 //    title          : <string>
 //    disabled       : <boolean>
-//    documentNodeId : <number>
 //    rules          : [
 //                         #cssRule,
 //                         ...
 //                         #cssRule
 //                     ]
+//    text           : <string> // Optional - whenever the text is available for a text-based stylesheet
 // }
 
 namespace WebCore {
 
 // static
-PassRefPtr<InspectorObject> InspectorCSSAgent::buildObjectForStyle(CSSStyleDeclaration* style, const String& fullStyleId, CSSStyleSourceData* sourceData)
-{
-    RefPtr<InspectorObject> result = InspectorObject::create();
-    if (!fullStyleId.isEmpty())
-        result->setString("id", fullStyleId);
-
-    result->setString("width", style->getPropertyValue("width"));
-    result->setString("height", style->getPropertyValue("height"));
-    Vector<CSSPropertySourceData>* propertyData = 0;
-
-    if (sourceData) {
-        result->setNumber("startOffset", sourceData->styleBodyRange.start);
-        result->setNumber("endOffset", sourceData->styleBodyRange.end);
-        propertyData = &sourceData->propertyData;
-    }
-    populateObjectWithStyleProperties(style, result.get(), propertyData);
-
-    return result.release();
-}
-
-// static
 CSSStyleSheet* InspectorCSSAgent::parentStyleSheet(StyleBase* styleBase)
 {
     if (!styleBase)
@@ -164,7 +137,6 @@
     return static_cast<CSSStyleRule*>(rule);
 }
 
-
 InspectorCSSAgent::InspectorCSSAgent(InspectorDOMAgent* domAgent, InspectorFrontend* frontend)
     : m_domAgent(domAgent)
     , m_frontend(frontend)
@@ -246,7 +218,10 @@
     if (!defaultView)
         return;
 
-    *style = buildObjectForStyle(defaultView->getComputedStyle(element, "").get(), "");
+    RefPtr<CSSStyleDeclaration> computedStyle = defaultView->getComputedStyle(element, "");
+    Vector<InspectorStyleProperty> properties;
+    RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyle.get(), 0);
+    *style = inspectorStyle->buildObjectForStyle();
 }
 
 void InspectorCSSAgent::getInheritedStylesForNode2(long nodeId, RefPtr<InspectorArray>* style)
@@ -263,7 +238,7 @@
         if (parentElement->style() && parentElement->style()->length()) {
             InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
             if (styleSheet)
-                parentStyle->setObject("inlineStyle", styleSheet->buildObjectForStyle(styleSheet->styleForId("0")));
+                parentStyle->setObject("inlineStyle", styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId::createFromParts(styleSheet->id(), "0"))));
         }
 
         CSSStyleSelector* parentSelector = parentElement->ownerDocument()->styleSelector();
@@ -308,43 +283,48 @@
     inspectorStyleSheet->setText(text);
 }
 
-void InspectorCSSAgent::setStyleText2(const String& fullStyleId, const String& text, RefPtr<InspectorValue>* result)
+void InspectorCSSAgent::setPropertyText2(const String& fullStyleId, long propertyIndex, const String& text, bool overwrite, RefPtr<InspectorValue>* result)
 {
-    Vector<String> idParts;
-    fullStyleId.split(':', idParts);
-    ASSERT(idParts.size() == 2);
+    InspectorCSSId compoundId(fullStyleId);
+    ASSERT(!compoundId.isEmpty());
 
-    InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(idParts.at(0));
+    InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(compoundId.styleSheetId());
     if (!inspectorStyleSheet)
         return;
 
-    if (!inspectorStyleSheet->setStyleText(idParts.at(1), text))
-        return;
-
-    *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(idParts.at(1)));
+    bool success = inspectorStyleSheet->setPropertyText(compoundId, propertyIndex, text, overwrite);
+    if (success)
+        *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
 }
 
-void InspectorCSSAgent::toggleProperty2(const String&, long, bool)
+void InspectorCSSAgent::toggleProperty2(const String& fullStyleId, long propertyIndex, bool disable, RefPtr<InspectorValue>* result)
 {
-    // FIXME(apavlov): implement
+    InspectorCSSId compoundId(fullStyleId);
+    ASSERT(!compoundId.isEmpty());
+
+    InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(compoundId.styleSheetId());
+    if (!inspectorStyleSheet)
+        return;
+
+    bool success = inspectorStyleSheet->toggleProperty(compoundId, propertyIndex, disable);
+    if (success)
+        *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
 }
 
 void InspectorCSSAgent::setRuleSelector2(const String& fullRuleId, const String& selector, RefPtr<InspectorValue>* result)
 {
-    Vector<String> idParts;
-    fullRuleId.split(':', idParts);
-    ASSERT(idParts.size() == 2);
+    InspectorCSSId compoundId(fullRuleId);
+    ASSERT(!compoundId.isEmpty());
 
-    InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(idParts.at(0));
+    InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(compoundId.styleSheetId());
     if (!inspectorStyleSheet)
         return;
 
-    const String& ruleId = idParts.at(1);
-    bool success = inspectorStyleSheet->setRuleSelector(ruleId, selector);
+    bool success = inspectorStyleSheet->setRuleSelector(compoundId, selector);
     if (!success)
         return;
 
-    *result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(ruleId));
+    *result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
 }
 
 void InspectorCSSAgent::addRule2(const long contextNodeId, const String& selector, RefPtr<InspectorValue>* result)
@@ -379,130 +359,6 @@
     return static_cast<Element*>(node);
 }
 
-// static
-void InspectorCSSAgent::populateObjectWithStyleProperties(CSSStyleDeclaration* style, InspectorObject* result, Vector<CSSPropertySourceData>* propertyData)
-{
-    RefPtr<InspectorArray> properties = InspectorArray::create();
-    RefPtr<InspectorObject> shorthandValues = InspectorObject::create();
-    HashMap<String, RefPtr<InspectorObject> > propertyNameToPreviousActiveProperty;
-    HashSet<String> foundShorthands;
-    HashSet<String> sourcePropertyNames;
-    if (propertyData) {
-        for (Vector<CSSPropertySourceData>::const_iterator it = propertyData->begin(); it != propertyData->end(); ++it) {
-            const CSSPropertySourceData& propertyEntry = *it;
-            RefPtr<InspectorObject> property = InspectorObject::create();
-            properties->pushObject(property);
-            const String& name = propertyEntry.name;
-            sourcePropertyNames.add(name);
-            property->setString("name", name);
-            property->setString("value", propertyEntry.value);
-            property->setString("priority", propertyEntry.important ? "important" : "");
-            property->setString("status", "active");
-            property->setBoolean("parsedOk", propertyEntry.parsedOk);
-            property->setNumber("startOffset", propertyEntry.range.start);
-            property->setNumber("endOffset", propertyEntry.range.end);
-            if (propertyEntry.parsedOk) {
-                property->setBoolean("implicit", false);
-                String shorthand = style->getPropertyShorthand(name);
-                property->setString("shorthandName", shorthand);
-                if (!shorthand.isEmpty() && !foundShorthands.contains(shorthand)) {
-                    foundShorthands.add(shorthand);
-                    shorthandValues->setString(shorthand, shorthandValue(style, shorthand));
-                }
-            } else {
-                property->setBoolean("implicit", false);
-                property->setString("shorthandName", "");
-            }
-            HashMap<String, RefPtr<InspectorObject> >::iterator activeIt = propertyNameToPreviousActiveProperty.find(name);
-            if (activeIt != propertyNameToPreviousActiveProperty.end()) {
-                activeIt->second->setString("status", "inactive");
-                activeIt->second->setString("shorthandName", "");
-            }
-            propertyNameToPreviousActiveProperty.set(name, property);
-        }
-    }
-
-    for (int i = 0, size = style->length(); i < size; ++i) {
-        String name = style->item(i);
-        if (sourcePropertyNames.contains(name))
-            continue;
-
-        sourcePropertyNames.add(name);
-        RefPtr<InspectorObject> property = InspectorObject::create();
-        properties->pushObject(property);
-        property->setString("name", name);
-        property->setString("value", style->getPropertyValue(name));
-        property->setString("priority", style->getPropertyPriority("name"));
-        property->setBoolean("implicit", style->isPropertyImplicit(name));
-        property->setBoolean("parsedOk", true);
-        property->setString("status", "style");
-        String shorthand = style->getPropertyShorthand(name);
-        property->setString("shorthandName", shorthand);
-        if (!shorthand.isEmpty() && !foundShorthands.contains(shorthand)) {
-            foundShorthands.add(shorthand);
-            shorthandValues->setString(shorthand, shorthandValue(style, shorthand));
-        }
-    }
-
-    result->setArray("properties", properties);
-    result->setObject("shorthandValues", shorthandValues);
-}
-
-// static
-String InspectorCSSAgent::shorthandValue(CSSStyleDeclaration* style, const String& shorthandProperty)
-{
-    String value = style->getPropertyValue(shorthandProperty);
-    if (value.isEmpty()) {
-        for (unsigned i = 0; i < style->length(); ++i) {
-            String individualProperty = style->item(i);
-            if (style->getPropertyShorthand(individualProperty) != shorthandProperty)
-                continue;
-            if (style->isPropertyImplicit(individualProperty))
-                continue;
-            String individualValue = style->getPropertyValue(individualProperty);
-            if (individualValue == "initial")
-                continue;
-            if (value.length())
-                value.append(" ");
-            value.append(individualValue);
-        }
-    }
-    return value;
-}
-
-// static
-String InspectorCSSAgent::shorthandPriority(CSSStyleDeclaration* style, const String& shorthandProperty)
-{
-    String priority = style->getPropertyPriority(shorthandProperty);
-    if (priority.isEmpty()) {
-        for (unsigned i = 0; i < style->length(); ++i) {
-            String individualProperty = style->item(i);
-            if (style->getPropertyShorthand(individualProperty) != shorthandProperty)
-                continue;
-            priority = style->getPropertyPriority(individualProperty);
-            break;
-        }
-    }
-    return priority;
-}
-
-
-// static
-Vector<String> InspectorCSSAgent::longhandProperties(CSSStyleDeclaration* style, const String& shorthandProperty)
-{
-    Vector<String> properties;
-    HashSet<String> foundProperties;
-    for (unsigned i = 0; i < style->length(); ++i) {
-        String individualProperty = style->item(i);
-        if (foundProperties.contains(individualProperty) || style->getPropertyShorthand(individualProperty) != shorthandProperty)
-            continue;
-
-        foundProperties.add(individualProperty);
-        properties.append(individualProperty);
-    }
-    return properties;
-}
-
 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
 {
     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
@@ -622,7 +478,8 @@
         Attribute* attribute = attributes->attributeItem(i);
         if (attribute->style()) {
             String attributeName = attribute->localName();
-            styleAttributes->setObject(attributeName.utf8().data(), buildObjectForStyle(attribute->style(), ""));
+            RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), attribute->style(), 0);
+            styleAttributes->setObject(attributeName.utf8().data(), inspectorStyle->buildObjectForStyle());
         }
     }