Home | History | Annotate | Download | only in inspector
      1 /*
      2  * Copyright (C) 2010, Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1.  Redistributions of source code must retain the above copyright
      8  *     notice, this list of conditions and the following disclaimer.
      9  * 2.  Redistributions in binary form must reproduce the above copyright
     10  *     notice, this list of conditions and the following disclaimer in the
     11  *     documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 #include "config.h"
     26 #include "core/inspector/InspectorCSSAgent.h"
     27 
     28 #include "CSSPropertyNames.h"
     29 #include "InspectorTypeBuilder.h"
     30 #include "StylePropertyShorthand.h"
     31 #include "bindings/v8/ExceptionState.h"
     32 #include "bindings/v8/ExceptionStatePlaceholder.h"
     33 #include "core/css/CSSComputedStyleDeclaration.h"
     34 #include "core/css/CSSImportRule.h"
     35 #include "core/css/CSSMediaRule.h"
     36 #include "core/css/CSSParser.h"
     37 #include "core/css/CSSRule.h"
     38 #include "core/css/CSSRuleList.h"
     39 #include "core/css/CSSStyleRule.h"
     40 #include "core/css/CSSStyleSheet.h"
     41 #include "core/css/MediaList.h"
     42 #include "core/css/StylePropertySet.h"
     43 #include "core/css/StyleRule.h"
     44 #include "core/css/StyleSheet.h"
     45 #include "core/css/StyleSheetContents.h"
     46 #include "core/css/StyleSheetList.h"
     47 #include "core/css/resolver/StyleResolver.h"
     48 #include "core/dom/NamedFlow.h"
     49 #include "core/dom/NamedFlowCollection.h"
     50 #include "core/dom/Node.h"
     51 #include "core/dom/NodeList.h"
     52 #include "core/html/HTMLHeadElement.h"
     53 #include "core/inspector/InspectorDOMAgent.h"
     54 #include "core/inspector/InspectorHistory.h"
     55 #include "core/inspector/InspectorPageAgent.h"
     56 #include "core/inspector/InspectorState.h"
     57 #include "core/inspector/InstrumentingAgents.h"
     58 #include "core/loader/DocumentLoader.h"
     59 #include "core/page/ContentSecurityPolicy.h"
     60 #include "core/platform/JSONValues.h"
     61 #include "core/rendering/RenderRegion.h"
     62 #include "wtf/CurrentTime.h"
     63 #include "wtf/HashSet.h"
     64 #include "wtf/Vector.h"
     65 #include "wtf/text/CString.h"
     66 #include "wtf/text/StringConcatenate.h"
     67 
     68 namespace CSSAgentState {
     69 static const char cssAgentEnabled[] = "cssAgentEnabled";
     70 }
     71 
     72 namespace WebCore {
     73 
     74 enum ForcePseudoClassFlags {
     75     PseudoNone = 0,
     76     PseudoHover = 1 << 0,
     77     PseudoFocus = 1 << 1,
     78     PseudoActive = 1 << 2,
     79     PseudoVisited = 1 << 3
     80 };
     81 
     82 class StyleSheetAppender {
     83 public:
     84     StyleSheetAppender(CSSStyleSheetToInspectorStyleSheet& cssStyleSheetToInspectorStyleSheet, Vector<CSSStyleSheet*>& result)
     85         : m_cssStyleSheetToInspectorStyleSheet(cssStyleSheetToInspectorStyleSheet)
     86         , m_result(result) { }
     87 
     88     void run(CSSStyleSheet* styleSheet)
     89     {
     90         RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
     91         // Avoid creating m_childRuleCSSOMWrappers in the stylesheet if it is in the process of re-parsing.
     92         // Otherwise m_childRuleCSSOMWrappers size will be initialized only for a part of rules, resulting in an ASSERT failure in CSSStyleSheet::item().
     93         // Instead, wait for the RuleMutationScope destruction and handle the complete CSSStyleSheet.
     94         if (inspectorStyleSheet && inspectorStyleSheet->isReparsing())
     95             return;
     96         m_result.append(styleSheet);
     97         for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
     98             CSSRule* rule = styleSheet->item(i);
     99             if (rule->type() == CSSRule::IMPORT_RULE) {
    100                 CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet();
    101                 if (importedStyleSheet)
    102                     run(importedStyleSheet);
    103             }
    104         }
    105     }
    106 
    107 private:
    108     CSSStyleSheetToInspectorStyleSheet& m_cssStyleSheetToInspectorStyleSheet;
    109     Vector<CSSStyleSheet*>& m_result;
    110 };
    111 
    112 static unsigned computePseudoClassMask(JSONArray* pseudoClassArray)
    113 {
    114     DEFINE_STATIC_LOCAL(String, active, ("active"));
    115     DEFINE_STATIC_LOCAL(String, hover, ("hover"));
    116     DEFINE_STATIC_LOCAL(String, focus, ("focus"));
    117     DEFINE_STATIC_LOCAL(String, visited, ("visited"));
    118     if (!pseudoClassArray || !pseudoClassArray->length())
    119         return PseudoNone;
    120 
    121     unsigned result = PseudoNone;
    122     for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
    123         RefPtr<JSONValue> pseudoClassValue = pseudoClassArray->get(i);
    124         String pseudoClass;
    125         bool success = pseudoClassValue->asString(&pseudoClass);
    126         if (!success)
    127             continue;
    128         if (pseudoClass == active)
    129             result |= PseudoActive;
    130         else if (pseudoClass == hover)
    131             result |= PseudoHover;
    132         else if (pseudoClass == focus)
    133             result |= PseudoFocus;
    134         else if (pseudoClass == visited)
    135             result |= PseudoVisited;
    136     }
    137 
    138     return result;
    139 }
    140 
    141 class UpdateRegionLayoutTask {
    142 public:
    143     UpdateRegionLayoutTask(InspectorCSSAgent*);
    144     void scheduleFor(NamedFlow*, int documentNodeId);
    145     void unschedule(NamedFlow*);
    146     void reset();
    147     void onTimer(Timer<UpdateRegionLayoutTask>*);
    148 
    149 private:
    150     InspectorCSSAgent* m_cssAgent;
    151     Timer<UpdateRegionLayoutTask> m_timer;
    152     HashMap<NamedFlow*, int> m_namedFlows;
    153 };
    154 
    155 UpdateRegionLayoutTask::UpdateRegionLayoutTask(InspectorCSSAgent* cssAgent)
    156     : m_cssAgent(cssAgent)
    157     , m_timer(this, &UpdateRegionLayoutTask::onTimer)
    158 {
    159 }
    160 
    161 void UpdateRegionLayoutTask::scheduleFor(NamedFlow* namedFlow, int documentNodeId)
    162 {
    163     m_namedFlows.add(namedFlow, documentNodeId);
    164 
    165     if (!m_timer.isActive())
    166         m_timer.startOneShot(0);
    167 }
    168 
    169 void UpdateRegionLayoutTask::unschedule(NamedFlow* namedFlow)
    170 {
    171     m_namedFlows.remove(namedFlow);
    172 }
    173 
    174 void UpdateRegionLayoutTask::reset()
    175 {
    176     m_timer.stop();
    177     m_namedFlows.clear();
    178 }
    179 
    180 void UpdateRegionLayoutTask::onTimer(Timer<UpdateRegionLayoutTask>*)
    181 {
    182     // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed.
    183     Vector<std::pair<NamedFlow*, int> > namedFlows;
    184 
    185     for (HashMap<NamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it)
    186         namedFlows.append(std::make_pair(it->key, it->value));
    187 
    188     for (unsigned i = 0, size = namedFlows.size(); i < size; ++i) {
    189         NamedFlow* namedFlow = namedFlows.at(i).first;
    190         int documentNodeId = namedFlows.at(i).second;
    191 
    192         if (m_namedFlows.contains(namedFlow)) {
    193             m_cssAgent->regionLayoutUpdated(namedFlow, documentNodeId);
    194             m_namedFlows.remove(namedFlow);
    195         }
    196     }
    197 
    198     if (!m_namedFlows.isEmpty() && !m_timer.isActive())
    199         m_timer.startOneShot(0);
    200 }
    201 
    202 class ChangeRegionOversetTask {
    203 public:
    204     ChangeRegionOversetTask(InspectorCSSAgent*);
    205     void scheduleFor(NamedFlow*, int documentNodeId);
    206     void unschedule(NamedFlow*);
    207     void reset();
    208     void onTimer(Timer<ChangeRegionOversetTask>*);
    209 
    210 private:
    211     InspectorCSSAgent* m_cssAgent;
    212     Timer<ChangeRegionOversetTask> m_timer;
    213     HashMap<NamedFlow*, int> m_namedFlows;
    214 };
    215 
    216 ChangeRegionOversetTask::ChangeRegionOversetTask(InspectorCSSAgent* cssAgent)
    217     : m_cssAgent(cssAgent)
    218     , m_timer(this, &ChangeRegionOversetTask::onTimer)
    219 {
    220 }
    221 
    222 void ChangeRegionOversetTask::scheduleFor(NamedFlow* namedFlow, int documentNodeId)
    223 {
    224     m_namedFlows.add(namedFlow, documentNodeId);
    225 
    226     if (!m_timer.isActive())
    227         m_timer.startOneShot(0);
    228 }
    229 
    230 void ChangeRegionOversetTask::unschedule(NamedFlow* namedFlow)
    231 {
    232     m_namedFlows.remove(namedFlow);
    233 }
    234 
    235 void ChangeRegionOversetTask::reset()
    236 {
    237     m_timer.stop();
    238     m_namedFlows.clear();
    239 }
    240 
    241 void ChangeRegionOversetTask::onTimer(Timer<ChangeRegionOversetTask>*)
    242 {
    243     // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed.
    244     for (HashMap<NamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it)
    245         m_cssAgent->regionOversetChanged(it->key, it->value);
    246 
    247     m_namedFlows.clear();
    248 }
    249 
    250 class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
    251     WTF_MAKE_NONCOPYABLE(StyleSheetAction);
    252 public:
    253     StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
    254         : InspectorHistory::Action(name)
    255         , m_styleSheet(styleSheet)
    256     {
    257     }
    258 
    259 protected:
    260     RefPtr<InspectorStyleSheet> m_styleSheet;
    261 };
    262 
    263 class InspectorCSSAgent::SetStyleSheetTextAction : public InspectorCSSAgent::StyleSheetAction {
    264     WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
    265 public:
    266     SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
    267         : InspectorCSSAgent::StyleSheetAction("SetStyleSheetText", styleSheet)
    268         , m_text(text)
    269     {
    270     }
    271 
    272     virtual bool perform(ExceptionState& es)
    273     {
    274         if (!m_styleSheet->getText(&m_oldText))
    275             return false;
    276         return redo(es);
    277     }
    278 
    279     virtual bool undo(ExceptionState& es)
    280     {
    281         if (m_styleSheet->setText(m_oldText, es)) {
    282             m_styleSheet->reparseStyleSheet(m_oldText);
    283             return true;
    284         }
    285         return false;
    286     }
    287 
    288     virtual bool redo(ExceptionState& es)
    289     {
    290         if (m_styleSheet->setText(m_text, es)) {
    291             m_styleSheet->reparseStyleSheet(m_text);
    292             return true;
    293         }
    294         return false;
    295     }
    296 
    297     virtual String mergeId()
    298     {
    299         return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
    300     }
    301 
    302     virtual void merge(PassOwnPtr<Action> action)
    303     {
    304         ASSERT(action->mergeId() == mergeId());
    305 
    306         SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get());
    307         m_text = other->m_text;
    308     }
    309 
    310 private:
    311     String m_text;
    312     String m_oldText;
    313 };
    314 
    315 class InspectorCSSAgent::SetStyleTextAction : public InspectorCSSAgent::StyleSheetAction {
    316     WTF_MAKE_NONCOPYABLE(SetStyleTextAction);
    317 public:
    318     SetStyleTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& text)
    319         : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
    320         , m_cssId(cssId)
    321         , m_text(text)
    322     {
    323     }
    324 
    325     virtual String toString()
    326     {
    327         return mergeId() + ": " + m_oldText + " -> " + m_text;
    328     }
    329 
    330     virtual bool perform(ExceptionState& es)
    331     {
    332         return redo(es);
    333     }
    334 
    335     virtual bool undo(ExceptionState& es)
    336     {
    337         String placeholder;
    338         return m_styleSheet->setStyleText(m_cssId, m_oldText, &placeholder, es);
    339     }
    340 
    341     virtual bool redo(ExceptionState& es)
    342     {
    343         return m_styleSheet->setStyleText(m_cssId, m_text, &m_oldText, es);
    344     }
    345 
    346     virtual String mergeId()
    347     {
    348         return String::format("SetStyleText %s:%u", m_cssId.styleSheetId().utf8().data(), m_cssId.ordinal());
    349     }
    350 
    351     virtual void merge(PassOwnPtr<Action> action)
    352     {
    353         ASSERT(action->mergeId() == mergeId());
    354 
    355         SetStyleTextAction* other = static_cast<SetStyleTextAction*>(action.get());
    356         m_text = other->m_text;
    357     }
    358 
    359 private:
    360     InspectorCSSId m_cssId;
    361     String m_text;
    362     String m_oldText;
    363 };
    364 
    365 class InspectorCSSAgent::SetPropertyTextAction : public InspectorCSSAgent::StyleSheetAction {
    366     WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
    367 public:
    368     SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
    369         : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
    370         , m_cssId(cssId)
    371         , m_propertyIndex(propertyIndex)
    372         , m_text(text)
    373         , m_overwrite(overwrite)
    374     {
    375     }
    376 
    377     virtual String toString()
    378     {
    379         return mergeId() + ": " + m_oldText + " -> " + m_text;
    380     }
    381 
    382     virtual bool perform(ExceptionState& es)
    383     {
    384         return redo(es);
    385     }
    386 
    387     virtual bool undo(ExceptionState& es)
    388     {
    389         String placeholder;
    390         return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, es);
    391     }
    392 
    393     virtual bool redo(ExceptionState& es)
    394     {
    395         String oldText;
    396         bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, es);
    397         m_oldText = oldText.stripWhiteSpace();
    398         // FIXME: remove this once the model handles this case.
    399         if (!m_oldText.endsWith(';'))
    400             m_oldText.append(';');
    401         return result;
    402     }
    403 
    404     virtual String mergeId()
    405     {
    406         return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false");
    407     }
    408 
    409     virtual void merge(PassOwnPtr<Action> action)
    410     {
    411         ASSERT(action->mergeId() == mergeId());
    412 
    413         SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
    414         m_text = other->m_text;
    415     }
    416 
    417 private:
    418     InspectorCSSId m_cssId;
    419     unsigned m_propertyIndex;
    420     String m_text;
    421     String m_oldText;
    422     bool m_overwrite;
    423 };
    424 
    425 class InspectorCSSAgent::TogglePropertyAction : public InspectorCSSAgent::StyleSheetAction {
    426     WTF_MAKE_NONCOPYABLE(TogglePropertyAction);
    427 public:
    428     TogglePropertyAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, bool disable)
    429         : InspectorCSSAgent::StyleSheetAction("ToggleProperty", styleSheet)
    430         , m_cssId(cssId)
    431         , m_propertyIndex(propertyIndex)
    432         , m_disable(disable)
    433     {
    434     }
    435 
    436     virtual bool perform(ExceptionState& es)
    437     {
    438         return redo(es);
    439     }
    440 
    441     virtual bool undo(ExceptionState& es)
    442     {
    443         return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, !m_disable, es);
    444     }
    445 
    446     virtual bool redo(ExceptionState& es)
    447     {
    448         return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, m_disable, es);
    449     }
    450 
    451 private:
    452     InspectorCSSId m_cssId;
    453     unsigned m_propertyIndex;
    454     bool m_disable;
    455 };
    456 
    457 class InspectorCSSAgent::SetRuleSelectorAction : public InspectorCSSAgent::StyleSheetAction {
    458     WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
    459 public:
    460     SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
    461         : InspectorCSSAgent::StyleSheetAction("SetRuleSelector", styleSheet)
    462         , m_cssId(cssId)
    463         , m_selector(selector)
    464     {
    465     }
    466 
    467     virtual bool perform(ExceptionState& es)
    468     {
    469         m_oldSelector = m_styleSheet->ruleSelector(m_cssId, es);
    470         if (es.hadException())
    471             return false;
    472         return redo(es);
    473     }
    474 
    475     virtual bool undo(ExceptionState& es)
    476     {
    477         return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, es);
    478     }
    479 
    480     virtual bool redo(ExceptionState& es)
    481     {
    482         return m_styleSheet->setRuleSelector(m_cssId, m_selector, es);
    483     }
    484 
    485 private:
    486     InspectorCSSId m_cssId;
    487     String m_selector;
    488     String m_oldSelector;
    489 };
    490 
    491 class InspectorCSSAgent::AddRuleAction : public InspectorCSSAgent::StyleSheetAction {
    492     WTF_MAKE_NONCOPYABLE(AddRuleAction);
    493 public:
    494     AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
    495         : InspectorCSSAgent::StyleSheetAction("AddRule", styleSheet)
    496         , m_selector(selector)
    497     {
    498     }
    499 
    500     virtual bool perform(ExceptionState& es)
    501     {
    502         return redo(es);
    503     }
    504 
    505     virtual bool undo(ExceptionState& es)
    506     {
    507         return m_styleSheet->deleteRule(m_newId, es);
    508     }
    509 
    510     virtual bool redo(ExceptionState& es)
    511     {
    512         CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, es);
    513         if (es.hadException())
    514             return false;
    515         m_newId = m_styleSheet->ruleId(cssStyleRule);
    516         return true;
    517     }
    518 
    519     InspectorCSSId newRuleId() { return m_newId; }
    520 
    521 private:
    522     InspectorCSSId m_newId;
    523     String m_selector;
    524     String m_oldSelector;
    525 };
    526 
    527 // static
    528 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
    529 {
    530     if (!rule || rule->type() != CSSRule::STYLE_RULE)
    531         return 0;
    532     return static_cast<CSSStyleRule*>(rule);
    533 }
    534 
    535 template <typename CharType, size_t bufferLength>
    536 static size_t vendorPrefixLowerCase(const CharType* string, size_t stringLength, char (&buffer)[bufferLength])
    537 {
    538     static const char lowerCaseOffset = 'a' - 'A';
    539 
    540     if (string[0] != '-')
    541         return 0;
    542 
    543     for (size_t i = 0; i < stringLength - 1; i++) {
    544         CharType c = string[i + 1];
    545         if (c == '-')
    546             return i;
    547         if (i == bufferLength)
    548             break;
    549         if (c < 'A' || c > 'z')
    550             break;
    551         if (c >= 'a')
    552             buffer[i] = c;
    553         else if (c <= 'Z')
    554             buffer[i] = c + lowerCaseOffset;
    555         else
    556             break;
    557     }
    558     return 0;
    559 }
    560 
    561 template <size_t patternLength>
    562 static bool equals(const char* prefix, size_t prefixLength, const char (&pattern)[patternLength])
    563 {
    564     if (prefixLength != patternLength - 1)
    565         return false;
    566     for (size_t i = 0; i < patternLength - 1; i++) {
    567         if (prefix[i] != pattern[i])
    568             return false;
    569     }
    570     return true;
    571 }
    572 
    573 static bool hasNonWebkitVendorSpecificPrefix(const CSSParserString& string)
    574 {
    575     // Known prefixes: http://wiki.csswg.org/spec/vendor-prefixes
    576     const size_t stringLength = string.length();
    577     if (stringLength < 4)
    578         return false;
    579 
    580     char buffer[6];
    581     size_t prefixLength = string.is8Bit() ?
    582         vendorPrefixLowerCase(string.characters8(), stringLength, buffer) :
    583         vendorPrefixLowerCase(string.characters16(), stringLength, buffer);
    584 
    585     if (!prefixLength || prefixLength == stringLength - 2)
    586         return false;
    587 
    588     switch (buffer[0]) {
    589     case 'a':
    590         return (prefixLength == 2 && buffer[1] == 'h') || equals(buffer + 1, prefixLength - 1, "tsc");
    591     case 'e':
    592         return equals(buffer + 1, prefixLength - 1, "pub");
    593     case 'h':
    594         return prefixLength == 2 && buffer[1] == 'p';
    595     case 'i':
    596         return equals(buffer + 1, prefixLength - 1, "books");
    597     case 'k':
    598         return equals(buffer + 1, prefixLength - 1, "html");
    599     case 'm':
    600         if (prefixLength == 2)
    601             return buffer[1] == 's';
    602         if (prefixLength == 3)
    603             return (buffer[1] == 'o' && buffer[2] == 'z') || (buffer[1] == 's' || buffer[2] == 'o');
    604         break;
    605     case 'o':
    606         return prefixLength == 1;
    607     case 'p':
    608         return equals(buffer + 1, prefixLength - 1, "rince");
    609     case 'r':
    610         return (prefixLength == 2 && buffer[1] == 'o') || equals(buffer + 1, prefixLength - 1, "im");
    611     case 't':
    612         return prefixLength == 2 && buffer[1] == 'c';
    613     case 'w':
    614         return (prefixLength == 3 && buffer[1] == 'a' && buffer[2] == 'p') || equals(buffer + 1, prefixLength - 1, "easy");
    615     case 'x':
    616         return prefixLength == 2 && buffer[1] == 'v';
    617     }
    618     return false;
    619 }
    620 
    621 static bool isValidPropertyName(const CSSParserString& content)
    622 {
    623     if (content.equalIgnoringCase("animation")
    624         || content.equalIgnoringCase("font-size-adjust")
    625         || content.equalIgnoringCase("transform")
    626         || content.equalIgnoringCase("user-select")
    627         || content.equalIgnoringCase("-webkit-flex-pack")
    628         || content.equalIgnoringCase("-webkit-text-size-adjust"))
    629         return true;
    630 
    631     return false;
    632 }
    633 
    634 // static
    635 bool InspectorCSSAgent::cssErrorFilter(const CSSParserString& content, int propertyId, int errorType)
    636 {
    637     const size_t contentLength = content.length();
    638 
    639     switch (errorType) {
    640     case CSSParser::PropertyDeclarationError:
    641         // Ignore errors like "*property: value". This trick is used for IE7: http://stackoverflow.com/questions/4563651/what-does-an-asterisk-do-in-a-css-property-name
    642         if (contentLength && content[0] == '*')
    643             return false;
    644 
    645         // The "filter" property is commonly used instead of "opacity" for IE9.
    646         if (propertyId == CSSPropertyFilter)
    647             return false;
    648 
    649         break;
    650 
    651     case CSSParser::InvalidPropertyValueError:
    652         // The "filter" property is commonly used instead of "opacity" for IE9.
    653         if (propertyId == CSSPropertyFilter)
    654             return false;
    655 
    656         // Value might be a vendor-specific function.
    657         if (hasNonWebkitVendorSpecificPrefix(content))
    658             return false;
    659 
    660         // IE-only "cursor: hand".
    661         if (propertyId == CSSPropertyCursor && content.equalIgnoringCase("hand"))
    662             return false;
    663 
    664         // Ignore properties like "property: value \9" (common IE hack) or "property: value \0" (IE 8 hack).
    665         if (contentLength > 2 && content[contentLength - 2] == '\\' && (content[contentLength - 1] == '9' || content[contentLength - 1] == '0'))
    666             return false;
    667 
    668         if (contentLength > 3) {
    669 
    670             // property: value\0/;
    671             if (content[contentLength - 3] == '\\' && content[contentLength - 2] == '0' && content[contentLength - 1] == '/')
    672                 return false;
    673 
    674             // property: value !ie;
    675             if (content[contentLength - 3] == '!' && content[contentLength - 2] == 'i' && content[contentLength - 1] == 'e')
    676                 return false;
    677         }
    678 
    679         // Popular value prefixes valid in other browsers.
    680         if (content.startsWithIgnoringCase("linear-gradient"))
    681             return false;
    682         if (content.startsWithIgnoringCase("-webkit-flexbox"))
    683             return false;
    684         if (propertyId == CSSPropertyUnicodeBidi && content.startsWithIgnoringCase("isolate"))
    685             return false;
    686 
    687         break;
    688 
    689     case CSSParser::InvalidPropertyError:
    690         if (hasNonWebkitVendorSpecificPrefix(content))
    691             return false;
    692 
    693         // Another hack to make IE-only property.
    694         if (contentLength && content[0] == '_')
    695             return false;
    696 
    697         // IE-only set of properties.
    698         if (content.startsWithIgnoringCase("scrollbar-"))
    699             return false;
    700 
    701         if (isValidPropertyName(content))
    702             return false;
    703 
    704         break;
    705 
    706     case CSSParser::InvalidRuleError:
    707         // Block error reporting for @-rules for now to avoid noise.
    708         if (contentLength > 4 && content[0] == '@')
    709             return false;
    710         return true;
    711 
    712     case CSSParser::InvalidSelectorPseudoError:
    713         if (hasNonWebkitVendorSpecificPrefix(content))
    714             return false;
    715     }
    716     return true;
    717 }
    718 
    719 InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorDOMAgent* domAgent, InspectorPageAgent* pageAgent)
    720     : InspectorBaseAgent<InspectorCSSAgent>("CSS", instrumentingAgents, state)
    721     , m_frontend(0)
    722     , m_domAgent(domAgent)
    723     , m_pageAgent(pageAgent)
    724     , m_lastStyleSheetId(1)
    725     , m_creatingViaInspectorStyleSheet(false)
    726     , m_isSettingStyleSheetText(false)
    727 {
    728     m_domAgent->setDOMListener(this);
    729 }
    730 
    731 InspectorCSSAgent::~InspectorCSSAgent()
    732 {
    733     ASSERT(!m_domAgent);
    734     reset();
    735 }
    736 
    737 void InspectorCSSAgent::setFrontend(InspectorFrontend* frontend)
    738 {
    739     ASSERT(!m_frontend);
    740     m_frontend = frontend->css();
    741 }
    742 
    743 void InspectorCSSAgent::clearFrontend()
    744 {
    745     ASSERT(m_frontend);
    746     m_frontend = 0;
    747     resetNonPersistentData();
    748 }
    749 
    750 void InspectorCSSAgent::discardAgent()
    751 {
    752     m_domAgent->setDOMListener(0);
    753     m_domAgent = 0;
    754 }
    755 
    756 void InspectorCSSAgent::restore()
    757 {
    758     if (m_state->getBoolean(CSSAgentState::cssAgentEnabled)) {
    759         ErrorString error;
    760         enable(&error);
    761     }
    762 }
    763 
    764 void InspectorCSSAgent::reset()
    765 {
    766     m_idToInspectorStyleSheet.clear();
    767     m_cssStyleSheetToInspectorStyleSheet.clear();
    768     m_nodeToInspectorStyleSheet.clear();
    769     m_documentToInspectorStyleSheet.clear();
    770     resetNonPersistentData();
    771 }
    772 
    773 void InspectorCSSAgent::resetNonPersistentData()
    774 {
    775     m_namedFlowCollectionsRequested.clear();
    776     if (m_updateRegionLayoutTask)
    777         m_updateRegionLayoutTask->reset();
    778     if (m_changeRegionOversetTask)
    779         m_changeRegionOversetTask->reset();
    780     resetPseudoStates();
    781 }
    782 
    783 void InspectorCSSAgent::enable(ErrorString*)
    784 {
    785     m_state->setBoolean(CSSAgentState::cssAgentEnabled, true);
    786     m_instrumentingAgents->setInspectorCSSAgent(this);
    787 
    788     if (!m_frontend)
    789         return;
    790     Vector<InspectorStyleSheet*> styleSheets;
    791     collectAllStyleSheets(styleSheets);
    792     for (size_t i = 0; i < styleSheets.size(); ++i)
    793         m_frontend->styleSheetAdded(styleSheets.at(i)->buildObjectForStyleSheetInfo());
    794 }
    795 
    796 void InspectorCSSAgent::disable(ErrorString*)
    797 {
    798     m_instrumentingAgents->setInspectorCSSAgent(0);
    799     m_state->setBoolean(CSSAgentState::cssAgentEnabled, false);
    800 }
    801 
    802 void InspectorCSSAgent::didCommitLoad(Frame* frame, DocumentLoader* loader)
    803 {
    804     if (loader->frame() != frame->page()->mainFrame())
    805         return;
    806 
    807     reset();
    808 }
    809 
    810 void InspectorCSSAgent::mediaQueryResultChanged()
    811 {
    812     if (m_frontend)
    813         m_frontend->mediaQueryResultChanged();
    814 }
    815 
    816 void InspectorCSSAgent::didCreateNamedFlow(Document* document, NamedFlow* namedFlow)
    817 {
    818     int documentNodeId = documentNodeWithRequestedFlowsId(document);
    819     if (!documentNodeId)
    820         return;
    821 
    822     ErrorString errorString;
    823     m_frontend->namedFlowCreated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
    824 }
    825 
    826 void InspectorCSSAgent::willRemoveNamedFlow(Document* document, NamedFlow* namedFlow)
    827 {
    828     int documentNodeId = documentNodeWithRequestedFlowsId(document);
    829     if (!documentNodeId)
    830         return;
    831 
    832     if (m_updateRegionLayoutTask)
    833         m_updateRegionLayoutTask->unschedule(namedFlow);
    834 
    835     m_frontend->namedFlowRemoved(documentNodeId, namedFlow->name().string());
    836 }
    837 
    838 void InspectorCSSAgent::didUpdateRegionLayout(Document* document, NamedFlow* namedFlow)
    839 {
    840     int documentNodeId = documentNodeWithRequestedFlowsId(document);
    841     if (!documentNodeId)
    842         return;
    843 
    844     if (!m_updateRegionLayoutTask)
    845         m_updateRegionLayoutTask = adoptPtr(new UpdateRegionLayoutTask(this));
    846     m_updateRegionLayoutTask->scheduleFor(namedFlow, documentNodeId);
    847 }
    848 
    849 void InspectorCSSAgent::regionLayoutUpdated(NamedFlow* namedFlow, int documentNodeId)
    850 {
    851     if (namedFlow->flowState() == NamedFlow::FlowStateNull)
    852         return;
    853 
    854     ErrorString errorString;
    855     RefPtr<NamedFlow> protector(namedFlow);
    856 
    857     m_frontend->regionLayoutUpdated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
    858 }
    859 
    860 void InspectorCSSAgent::didChangeRegionOverset(Document* document, NamedFlow* namedFlow)
    861 {
    862     int documentNodeId = documentNodeWithRequestedFlowsId(document);
    863     if (!documentNodeId)
    864         return;
    865 
    866     if (!m_changeRegionOversetTask)
    867         m_changeRegionOversetTask = adoptPtr(new ChangeRegionOversetTask(this));
    868     m_changeRegionOversetTask->scheduleFor(namedFlow, documentNodeId);
    869 }
    870 
    871 void InspectorCSSAgent::regionOversetChanged(NamedFlow* namedFlow, int documentNodeId)
    872 {
    873     if (namedFlow->flowState() == NamedFlow::FlowStateNull)
    874         return;
    875 
    876     ErrorString errorString;
    877     RefPtr<NamedFlow> protector(namedFlow);
    878 
    879     m_frontend->regionOversetChanged(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
    880 }
    881 
    882 void InspectorCSSAgent::activeStyleSheetsUpdated(Document* document, const StyleSheetVector& newSheets)
    883 {
    884     if (m_isSettingStyleSheetText)
    885         return;
    886     HashSet<CSSStyleSheet*> removedSheets;
    887     for (CSSStyleSheetToInspectorStyleSheet::iterator it = m_cssStyleSheetToInspectorStyleSheet.begin(); it != m_cssStyleSheetToInspectorStyleSheet.end(); ++it) {
    888         if (it->value->canBind() && (!it->key->ownerDocument() || it->key->ownerDocument() == document))
    889             removedSheets.add(it->key);
    890     }
    891 
    892     Vector<CSSStyleSheet*> newSheetsVector;
    893     for (size_t i = 0, size = newSheets.size(); i < size; ++i) {
    894         StyleSheet* newSheet = newSheets.at(i).get();
    895         if (newSheet->isCSSStyleSheet()) {
    896             StyleSheetAppender appender(m_cssStyleSheetToInspectorStyleSheet, newSheetsVector);
    897             appender.run(static_cast<CSSStyleSheet*>(newSheet));
    898         }
    899     }
    900 
    901     HashSet<CSSStyleSheet*> addedSheets;
    902     for (size_t i = 0; i < newSheetsVector.size(); ++i) {
    903         CSSStyleSheet* newCSSSheet = newSheetsVector.at(i);
    904         if (removedSheets.contains(newCSSSheet))
    905             removedSheets.remove(newCSSSheet);
    906         else
    907             addedSheets.add(newCSSSheet);
    908     }
    909 
    910     for (HashSet<CSSStyleSheet*>::iterator it = removedSheets.begin(); it != removedSheets.end(); ++it) {
    911         RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(*it);
    912         ASSERT(inspectorStyleSheet);
    913         if (m_idToInspectorStyleSheet.contains(inspectorStyleSheet->id())) {
    914             String id = unbindStyleSheet(inspectorStyleSheet.get());
    915             if (m_frontend)
    916                 m_frontend->styleSheetRemoved(id);
    917         }
    918     }
    919 
    920     for (HashSet<CSSStyleSheet*>::iterator it = addedSheets.begin(); it != addedSheets.end(); ++it) {
    921         if (!m_cssStyleSheetToInspectorStyleSheet.contains(*it)) {
    922             InspectorStyleSheet* newStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(*it));
    923             if (m_frontend)
    924                 m_frontend->styleSheetAdded(newStyleSheet->buildObjectForStyleSheetInfo());
    925         }
    926     }
    927 }
    928 
    929 void InspectorCSSAgent::frameDetachedFromParent(Frame* frame)
    930 {
    931     Document* document = frame->document();
    932     if (!document)
    933         return;
    934     StyleSheetVector newSheets;
    935     activeStyleSheetsUpdated(document, newSheets);
    936 }
    937 
    938 bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType)
    939 {
    940     if (m_nodeIdToForcedPseudoState.isEmpty())
    941         return false;
    942 
    943     int nodeId = m_domAgent->boundNodeId(element);
    944     if (!nodeId)
    945         return false;
    946 
    947     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
    948     if (it == m_nodeIdToForcedPseudoState.end())
    949         return false;
    950 
    951     unsigned forcedPseudoState = it->value;
    952     switch (pseudoType) {
    953     case CSSSelector::PseudoActive:
    954         return forcedPseudoState & PseudoActive;
    955     case CSSSelector::PseudoFocus:
    956         return forcedPseudoState & PseudoFocus;
    957     case CSSSelector::PseudoHover:
    958         return forcedPseudoState & PseudoHover;
    959     case CSSSelector::PseudoVisited:
    960         return forcedPseudoState & PseudoVisited;
    961     default:
    962         return false;
    963     }
    964 }
    965 
    966 void InspectorCSSAgent::getMatchedStylesForNode(ErrorString* errorString, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> >& matchedCSSRules, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> >& pseudoIdMatches, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> >& inheritedEntries)
    967 {
    968     Element* element = elementForId(errorString, nodeId);
    969     if (!element)
    970         return;
    971 
    972     // Matched rules.
    973     StyleResolver* styleResolver = element->ownerDocument()->styleResolver();
    974     RefPtr<CSSRuleList> matchedRules = styleResolver->styleRulesForElement(element, StyleResolver::AllCSSRules);
    975     matchedCSSRules = buildArrayForMatchedRuleList(matchedRules.get(), styleResolver, element);
    976 
    977     // Pseudo elements.
    978     if (!includePseudo || *includePseudo) {
    979         RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> > pseudoElements = TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches>::create();
    980         for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
    981             RefPtr<CSSRuleList> matchedRules = styleResolver->pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
    982             if (matchedRules && matchedRules->length()) {
    983                 RefPtr<TypeBuilder::CSS::PseudoIdMatches> matches = TypeBuilder::CSS::PseudoIdMatches::create()
    984                     .setPseudoId(static_cast<int>(pseudoId))
    985                     .setMatches(buildArrayForMatchedRuleList(matchedRules.get(), styleResolver, element));
    986                 pseudoElements->addItem(matches.release());
    987             }
    988         }
    989 
    990         pseudoIdMatches = pseudoElements.release();
    991     }
    992 
    993     // Inherited styles.
    994     if (!includeInherited || *includeInherited) {
    995         RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> > entries = TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry>::create();
    996         Element* parentElement = element->parentElement();
    997         while (parentElement) {
    998             StyleResolver* parentStyleResolver = parentElement->ownerDocument()->styleResolver();
    999             RefPtr<CSSRuleList> parentMatchedRules = parentStyleResolver->styleRulesForElement(parentElement, StyleResolver::AllCSSRules);
   1000             RefPtr<TypeBuilder::CSS::InheritedStyleEntry> entry = TypeBuilder::CSS::InheritedStyleEntry::create()
   1001                 .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules.get(), styleResolver, parentElement));
   1002             if (parentElement->style() && parentElement->style()->length()) {
   1003                 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
   1004                 if (styleSheet)
   1005                     entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
   1006             }
   1007 
   1008             entries->addItem(entry.release());
   1009             parentElement = parentElement->parentElement();
   1010         }
   1011 
   1012         inheritedEntries = entries.release();
   1013     }
   1014 }
   1015 
   1016 void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<TypeBuilder::CSS::CSSStyle>& attributesStyle)
   1017 {
   1018     Element* element = elementForId(errorString, nodeId);
   1019     if (!element)
   1020         return;
   1021 
   1022     InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
   1023     if (!styleSheet)
   1024         return;
   1025 
   1026     inlineStyle = styleSheet->buildObjectForStyle(element->style());
   1027     RefPtr<TypeBuilder::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
   1028     attributesStyle = attributes ? attributes.release() : 0;
   1029 }
   1030 
   1031 void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> >& style)
   1032 {
   1033     Element* element = elementForId(errorString, nodeId);
   1034     if (!element)
   1035         return;
   1036 
   1037     RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(element, true);
   1038     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
   1039     style = inspectorStyle->buildArrayForComputedStyle();
   1040 }
   1041 
   1042 void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader> >& styleInfos)
   1043 {
   1044     styleInfos = TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>::create();
   1045     Vector<InspectorStyleSheet*> styleSheets;
   1046     collectAllStyleSheets(styleSheets);
   1047     for (size_t i = 0; i < styleSheets.size(); ++i)
   1048         styleInfos->addItem(styleSheets.at(i)->buildObjectForStyleSheetInfo());
   1049 }
   1050 
   1051 void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<TypeBuilder::CSS::CSSStyleSheetBody>& styleSheetObject)
   1052 {
   1053     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
   1054     if (!inspectorStyleSheet)
   1055         return;
   1056 
   1057     Document* doc = inspectorStyleSheet->pageStyleSheet() ? inspectorStyleSheet->pageStyleSheet()->ownerDocument() : 0;
   1058     if (!doc || !doc->styleResolver())
   1059         return;
   1060 
   1061     RefPtr<TypeBuilder::CSS::CSSStyleSheetBody> result = TypeBuilder::CSS::CSSStyleSheetBody::create()
   1062         .setStyleSheetId(styleSheetId)
   1063         .setRules(buildArrayForRuleList(inspectorStyleSheet->pageStyleSheet()->rules().get(), doc->styleResolver()));
   1064 
   1065     bool success = inspectorStyleSheet->fillObjectForStyleSheet(result);
   1066     if (success)
   1067         styleSheetObject = result;
   1068 }
   1069 
   1070 void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
   1071 {
   1072     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
   1073     if (!inspectorStyleSheet)
   1074         return;
   1075 
   1076     inspectorStyleSheet->getText(result);
   1077 }
   1078 
   1079 void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
   1080 {
   1081     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
   1082     if (!inspectorStyleSheet)
   1083         return;
   1084 
   1085     TrackExceptionState es;
   1086     m_domAgent->history()->perform(adoptPtr(new SetStyleSheetTextAction(inspectorStyleSheet, text)), es);
   1087     *errorString = InspectorDOMAgent::toErrorString(es);
   1088 }
   1089 
   1090 void InspectorCSSAgent::setStyleText(ErrorString* errorString, const RefPtr<JSONObject>& fullStyleId, const String& text, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
   1091 {
   1092     InspectorCSSId compoundId(fullStyleId);
   1093     ASSERT(!compoundId.isEmpty());
   1094 
   1095     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
   1096     if (!inspectorStyleSheet)
   1097         return;
   1098 
   1099     TrackExceptionState es;
   1100     m_domAgent->history()->perform(adoptPtr(new SetStyleTextAction(inspectorStyleSheet, compoundId, text)), es);
   1101     if (!es.hadException())
   1102         result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
   1103     *errorString = InspectorDOMAgent::toErrorString(es);
   1104 }
   1105 
   1106 void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<JSONObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
   1107 {
   1108     InspectorCSSId compoundId(fullStyleId);
   1109     ASSERT(!compoundId.isEmpty());
   1110 
   1111     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
   1112     if (!inspectorStyleSheet)
   1113         return;
   1114 
   1115     TrackExceptionState es;
   1116     bool success = m_domAgent->history()->perform(adoptPtr(new SetPropertyTextAction(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite)), es);
   1117     if (success)
   1118         result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
   1119     *errorString = InspectorDOMAgent::toErrorString(es);
   1120 }
   1121 
   1122 void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<JSONObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
   1123 {
   1124     InspectorCSSId compoundId(fullStyleId);
   1125     ASSERT(!compoundId.isEmpty());
   1126 
   1127     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
   1128     if (!inspectorStyleSheet)
   1129         return;
   1130 
   1131     TrackExceptionState es;
   1132     bool success = m_domAgent->history()->perform(adoptPtr(new TogglePropertyAction(inspectorStyleSheet, compoundId, propertyIndex, disable)), es);
   1133     if (success)
   1134         result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
   1135     *errorString = InspectorDOMAgent::toErrorString(es);
   1136 }
   1137 
   1138 void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<JSONObject>& fullRuleId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
   1139 {
   1140     InspectorCSSId compoundId(fullRuleId);
   1141     ASSERT(!compoundId.isEmpty());
   1142 
   1143     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
   1144     if (!inspectorStyleSheet)
   1145         return;
   1146 
   1147     TrackExceptionState es;
   1148     bool success = m_domAgent->history()->perform(adoptPtr(new SetRuleSelectorAction(inspectorStyleSheet, compoundId, selector)), es);
   1149 
   1150     if (success) {
   1151         CSSStyleRule* rule = inspectorStyleSheet->ruleForId(compoundId);
   1152         result = inspectorStyleSheet->buildObjectForRule(rule, buildMediaListChain(rule));
   1153     }
   1154     *errorString = InspectorDOMAgent::toErrorString(es);
   1155 }
   1156 
   1157 void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
   1158 {
   1159     Node* node = m_domAgent->assertNode(errorString, contextNodeId);
   1160     if (!node)
   1161         return;
   1162 
   1163     InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
   1164     if (!inspectorStyleSheet) {
   1165         *errorString = "No target stylesheet found";
   1166         return;
   1167     }
   1168 
   1169     TrackExceptionState es;
   1170     OwnPtr<AddRuleAction> action = adoptPtr(new AddRuleAction(inspectorStyleSheet, selector));
   1171     AddRuleAction* rawAction = action.get();
   1172     bool success = m_domAgent->history()->perform(action.release(), es);
   1173     if (!success) {
   1174         *errorString = InspectorDOMAgent::toErrorString(es);
   1175         return;
   1176     }
   1177 
   1178     InspectorCSSId ruleId = rawAction->newRuleId();
   1179     CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
   1180     result = inspectorStyleSheet->buildObjectForRule(rule, buildMediaListChain(rule));
   1181 }
   1182 
   1183 void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> >& cssProperties)
   1184 {
   1185     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> > properties = TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo>::create();
   1186     for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
   1187         CSSPropertyID id = convertToCSSPropertyID(i);
   1188         RefPtr<TypeBuilder::CSS::CSSPropertyInfo> property = TypeBuilder::CSS::CSSPropertyInfo::create()
   1189             .setName(getPropertyNameString(id));
   1190 
   1191         const StylePropertyShorthand& shorthand = shorthandForProperty(id);
   1192         if (!shorthand.length()) {
   1193             properties->addItem(property.release());
   1194             continue;
   1195         }
   1196         RefPtr<TypeBuilder::Array<String> > longhands = TypeBuilder::Array<String>::create();
   1197         for (unsigned j = 0; j < shorthand.length(); ++j) {
   1198             CSSPropertyID longhandID = shorthand.properties()[j];
   1199             longhands->addItem(getPropertyNameString(longhandID));
   1200         }
   1201         property->setLonghands(longhands);
   1202         properties->addItem(property.release());
   1203     }
   1204     cssProperties = properties.release();
   1205 }
   1206 
   1207 void InspectorCSSAgent::forcePseudoState(ErrorString* errorString, int nodeId, const RefPtr<JSONArray>& forcedPseudoClasses)
   1208 {
   1209     Element* element = m_domAgent->assertElement(errorString, nodeId);
   1210     if (!element)
   1211         return;
   1212 
   1213     unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses.get());
   1214     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
   1215     unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value;
   1216     bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState;
   1217     if (!needStyleRecalc)
   1218         return;
   1219 
   1220     if (forcedPseudoState)
   1221         m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
   1222     else
   1223         m_nodeIdToForcedPseudoState.remove(nodeId);
   1224     element->ownerDocument()->setNeedsStyleRecalc();
   1225 }
   1226 
   1227 void InspectorCSSAgent::getNamedFlowCollection(ErrorString* errorString, int documentNodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> >& result)
   1228 {
   1229     Document* document = m_domAgent->assertDocument(errorString, documentNodeId);
   1230     if (!document)
   1231         return;
   1232 
   1233     m_namedFlowCollectionsRequested.add(documentNodeId);
   1234 
   1235     Vector<RefPtr<NamedFlow> > namedFlowsVector = document->namedFlows()->namedFlows();
   1236     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> > namedFlows = TypeBuilder::Array<TypeBuilder::CSS::NamedFlow>::create();
   1237 
   1238     for (Vector<RefPtr<NamedFlow> >::iterator it = namedFlowsVector.begin(); it != namedFlowsVector.end(); ++it)
   1239         namedFlows->addItem(buildObjectForNamedFlow(errorString, it->get(), documentNodeId));
   1240 
   1241     result = namedFlows.release();
   1242 }
   1243 
   1244 PassRefPtr<TypeBuilder::CSS::CSSMedia> InspectorCSSAgent::buildMediaObject(const MediaList* media, MediaListSource mediaListSource, const String& sourceURL, CSSStyleSheet* parentStyleSheet)
   1245 {
   1246     // Make certain compilers happy by initializing |source| up-front.
   1247     TypeBuilder::CSS::CSSMedia::Source::Enum source = TypeBuilder::CSS::CSSMedia::Source::InlineSheet;
   1248     switch (mediaListSource) {
   1249     case MediaListSourceMediaRule:
   1250         source = TypeBuilder::CSS::CSSMedia::Source::MediaRule;
   1251         break;
   1252     case MediaListSourceImportRule:
   1253         source = TypeBuilder::CSS::CSSMedia::Source::ImportRule;
   1254         break;
   1255     case MediaListSourceLinkedSheet:
   1256         source = TypeBuilder::CSS::CSSMedia::Source::LinkedSheet;
   1257         break;
   1258     case MediaListSourceInlineSheet:
   1259         source = TypeBuilder::CSS::CSSMedia::Source::InlineSheet;
   1260         break;
   1261     }
   1262 
   1263     RefPtr<TypeBuilder::CSS::CSSMedia> mediaObject = TypeBuilder::CSS::CSSMedia::create()
   1264         .setText(media->mediaText())
   1265         .setSource(source);
   1266 
   1267     if (parentStyleSheet && mediaListSource != MediaListSourceLinkedSheet) {
   1268         if (InspectorStyleSheet* inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(parentStyleSheet))
   1269             mediaObject->setParentStyleSheetId(inspectorStyleSheet->id());
   1270     }
   1271     if (!sourceURL.isEmpty()) {
   1272         mediaObject->setSourceURL(sourceURL);
   1273 
   1274         CSSRule* parentRule = media->parentRule();
   1275         if (!parentRule)
   1276             return mediaObject.release();
   1277         InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(parentRule->parentStyleSheet());
   1278         RefPtr<TypeBuilder::CSS::SourceRange> mediaRange = inspectorStyleSheet->ruleHeaderSourceRange(parentRule);
   1279         if (mediaRange)
   1280             mediaObject->setRange(mediaRange);
   1281     }
   1282     return mediaObject.release();
   1283 }
   1284 
   1285 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSMedia> > InspectorCSSAgent::buildMediaListChain(CSSRule* rule)
   1286 {
   1287     if (!rule)
   1288         return 0;
   1289     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSMedia> > mediaArray = TypeBuilder::Array<TypeBuilder::CSS::CSSMedia>::create();
   1290     bool hasItems = false;
   1291     MediaList* mediaList;
   1292     CSSRule* parentRule = rule;
   1293     String sourceURL;
   1294     while (parentRule) {
   1295         CSSStyleSheet* parentStyleSheet = 0;
   1296         bool isMediaRule = true;
   1297         if (parentRule->type() == CSSRule::MEDIA_RULE) {
   1298             CSSMediaRule* mediaRule = static_cast<CSSMediaRule*>(parentRule);
   1299             mediaList = mediaRule->media();
   1300             parentStyleSheet = mediaRule->parentStyleSheet();
   1301         } else if (parentRule->type() == CSSRule::IMPORT_RULE) {
   1302             CSSImportRule* importRule = static_cast<CSSImportRule*>(parentRule);
   1303             mediaList = importRule->media();
   1304             parentStyleSheet = importRule->parentStyleSheet();
   1305             isMediaRule = false;
   1306         } else {
   1307             mediaList = 0;
   1308         }
   1309 
   1310         if (parentStyleSheet) {
   1311             sourceURL = parentStyleSheet->contents()->baseURL();
   1312             if (sourceURL.isEmpty())
   1313                 sourceURL = InspectorDOMAgent::documentURLString(parentStyleSheet->ownerDocument());
   1314         } else {
   1315             sourceURL = "";
   1316         }
   1317 
   1318         if (mediaList && mediaList->length()) {
   1319             mediaArray->addItem(buildMediaObject(mediaList, isMediaRule ? MediaListSourceMediaRule : MediaListSourceImportRule, sourceURL, parentStyleSheet));
   1320             hasItems = true;
   1321         }
   1322 
   1323         if (parentRule->parentRule()) {
   1324             parentRule = parentRule->parentRule();
   1325         } else {
   1326             CSSStyleSheet* styleSheet = parentRule->parentStyleSheet();
   1327             while (styleSheet) {
   1328                 mediaList = styleSheet->media();
   1329                 if (mediaList && mediaList->length()) {
   1330                     Document* doc = styleSheet->ownerDocument();
   1331                     if (doc)
   1332                         sourceURL = doc->url();
   1333                     else if (!styleSheet->contents()->baseURL().isEmpty())
   1334                         sourceURL = styleSheet->contents()->baseURL();
   1335                     else
   1336                         sourceURL = "";
   1337                     mediaArray->addItem(buildMediaObject(mediaList, styleSheet->ownerNode() ? MediaListSourceLinkedSheet : MediaListSourceInlineSheet, sourceURL, styleSheet));
   1338                     hasItems = true;
   1339                 }
   1340                 parentRule = styleSheet->ownerRule();
   1341                 if (parentRule)
   1342                     break;
   1343                 styleSheet = styleSheet->parentStyleSheet();
   1344             }
   1345         }
   1346     }
   1347     return hasItems ? mediaArray : 0;
   1348 }
   1349 
   1350 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
   1351 {
   1352     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
   1353     if (it != m_nodeToInspectorStyleSheet.end())
   1354         return it->value.get();
   1355 
   1356     CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
   1357     if (!style)
   1358         return 0;
   1359 
   1360     String newStyleSheetId = String::number(m_lastStyleSheetId++);
   1361     RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_pageAgent, newStyleSheetId, element, TypeBuilder::CSS::StyleSheetOrigin::Regular, this);
   1362     m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
   1363     m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
   1364     return inspectorStyleSheet.get();
   1365 }
   1366 
   1367 Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
   1368 {
   1369     Node* node = m_domAgent->nodeForId(nodeId);
   1370     if (!node) {
   1371         *errorString = "No node with given id found";
   1372         return 0;
   1373     }
   1374     if (!node->isElementNode()) {
   1375         *errorString = "Not an element node";
   1376         return 0;
   1377     }
   1378     return toElement(node);
   1379 }
   1380 
   1381 int InspectorCSSAgent::documentNodeWithRequestedFlowsId(Document* document)
   1382 {
   1383     int documentNodeId = m_domAgent->boundNodeId(document);
   1384     if (!documentNodeId || !m_namedFlowCollectionsRequested.contains(documentNodeId))
   1385         return 0;
   1386 
   1387     return documentNodeId;
   1388 }
   1389 
   1390 void InspectorCSSAgent::collectAllStyleSheets(Vector<InspectorStyleSheet*>& result)
   1391 {
   1392     Vector<Document*> documents = m_domAgent->documents();
   1393     for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
   1394         StyleSheetList* list = (*it)->styleSheets();
   1395         for (unsigned i = 0; i < list->length(); ++i) {
   1396             StyleSheet* styleSheet = list->item(i);
   1397             if (styleSheet->isCSSStyleSheet())
   1398                 collectStyleSheets(static_cast<CSSStyleSheet*>(styleSheet), result);
   1399         }
   1400     }
   1401 }
   1402 
   1403 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Vector<InspectorStyleSheet*>& result)
   1404 {
   1405     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
   1406     result.append(inspectorStyleSheet);
   1407     for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
   1408         CSSRule* rule = styleSheet->item(i);
   1409         if (rule->type() == CSSRule::IMPORT_RULE) {
   1410             CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet();
   1411             if (importedStyleSheet)
   1412                 collectStyleSheets(importedStyleSheet, result);
   1413         }
   1414     }
   1415 }
   1416 
   1417 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
   1418 {
   1419     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
   1420     if (!inspectorStyleSheet) {
   1421         String id = String::number(m_lastStyleSheetId++);
   1422         Document* document = styleSheet->ownerDocument();
   1423         inspectorStyleSheet = InspectorStyleSheet::create(m_pageAgent, id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
   1424         m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
   1425         m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
   1426         if (m_creatingViaInspectorStyleSheet)
   1427             m_documentToInspectorStyleSheet.add(document, inspectorStyleSheet);
   1428     }
   1429     return inspectorStyleSheet.get();
   1430 }
   1431 
   1432 String InspectorCSSAgent::unbindStyleSheet(InspectorStyleSheet* inspectorStyleSheet)
   1433 {
   1434     String id = inspectorStyleSheet->id();
   1435     m_idToInspectorStyleSheet.remove(id);
   1436     if (inspectorStyleSheet->pageStyleSheet())
   1437         m_cssStyleSheetToInspectorStyleSheet.remove(inspectorStyleSheet->pageStyleSheet());
   1438     return id;
   1439 }
   1440 
   1441 InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
   1442 {
   1443     if (!document) {
   1444         ASSERT(!createIfAbsent);
   1445         return 0;
   1446     }
   1447 
   1448     if (!document->isHTMLDocument() && !document->isSVGDocument())
   1449         return 0;
   1450 
   1451     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
   1452     if (inspectorStyleSheet || !createIfAbsent)
   1453         return inspectorStyleSheet.get();
   1454 
   1455     TrackExceptionState es;
   1456     RefPtr<Element> styleElement = document->createElement("style", es);
   1457     if (!es.hadException())
   1458         styleElement->setAttribute("type", "text/css", es);
   1459     if (!es.hadException()) {
   1460         ContainerNode* targetNode;
   1461         // HEAD is absent in ImageDocuments, for example.
   1462         if (document->head())
   1463             targetNode = document->head();
   1464         else if (document->body())
   1465             targetNode = document->body();
   1466         else
   1467             return 0;
   1468 
   1469         InlineStyleOverrideScope overrideScope(document);
   1470         m_creatingViaInspectorStyleSheet = true;
   1471         targetNode->appendChild(styleElement, es, AttachLazily);
   1472         // At this point the added stylesheet will get bound through the updateActiveStyleSheets() invocation.
   1473         // We just need to pick the respective InspectorStyleSheet from m_documentToInspectorStyleSheet.
   1474         m_creatingViaInspectorStyleSheet = false;
   1475     }
   1476     if (es.hadException())
   1477         return 0;
   1478 
   1479     return m_documentToInspectorStyleSheet.get(document);
   1480 }
   1481 
   1482 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
   1483 {
   1484     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
   1485     if (it == m_idToInspectorStyleSheet.end()) {
   1486         *errorString = "No style sheet with given id found";
   1487         return 0;
   1488     }
   1489     return it->value.get();
   1490 }
   1491 
   1492 TypeBuilder::CSS::StyleSheetOrigin::Enum InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
   1493 {
   1494     if (m_creatingViaInspectorStyleSheet)
   1495         return TypeBuilder::CSS::StyleSheetOrigin::Inspector;
   1496 
   1497     TypeBuilder::CSS::StyleSheetOrigin::Enum origin = TypeBuilder::CSS::StyleSheetOrigin::Regular;
   1498     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
   1499         origin = TypeBuilder::CSS::StyleSheetOrigin::User_agent;
   1500     else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
   1501         origin = TypeBuilder::CSS::StyleSheetOrigin::User;
   1502     else {
   1503         InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
   1504         if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
   1505             origin = TypeBuilder::CSS::StyleSheetOrigin::Inspector;
   1506     }
   1507     return origin;
   1508 }
   1509 
   1510 PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule, StyleResolver* styleResolver)
   1511 {
   1512     if (!rule)
   1513         return 0;
   1514 
   1515     // CSSRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
   1516     // Since the inspector wants to walk the parent chain, we construct the full wrappers here.
   1517     // FIXME: This could be factored better. StyleResolver::styleRulesForElement should return a StyleRule vector, not a CSSRuleList.
   1518     if (!rule->parentStyleSheet()) {
   1519         rule = styleResolver->inspectorCSSOMWrappers().getWrapperForRuleInSheets(rule->styleRule(), styleResolver->document()->styleSheetCollection());
   1520         if (!rule)
   1521             return 0;
   1522     }
   1523     return bindStyleSheet(rule->parentStyleSheet())->buildObjectForRule(rule, buildMediaListChain(rule));
   1524 }
   1525 
   1526 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList, StyleResolver* styleResolver)
   1527 {
   1528     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSRule>::create();
   1529     if (!ruleList)
   1530         return result.release();
   1531 
   1532     RefPtr<CSSRuleList> refRuleList = ruleList;
   1533     CSSRuleVector rules;
   1534     InspectorStyleSheet::collectFlatRules(refRuleList, &rules);
   1535 
   1536     for (unsigned i = 0, size = rules.size(); i < size; ++i) {
   1537         CSSStyleRule* styleRule = asCSSStyleRule(rules.at(i).get());
   1538         if (!styleRule)
   1539             continue;
   1540         result->addItem(buildObjectForRule(styleRule, styleResolver));
   1541     }
   1542 
   1543     return result.release();
   1544 }
   1545 
   1546 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > InspectorCSSAgent::buildArrayForMatchedRuleList(CSSRuleList* ruleList, StyleResolver* styleResolver, Element* element)
   1547 {
   1548     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > result = TypeBuilder::Array<TypeBuilder::CSS::RuleMatch>::create();
   1549     if (!ruleList)
   1550         return result.release();
   1551 
   1552     for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
   1553         CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
   1554         RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule, styleResolver);
   1555         if (!ruleObject)
   1556             continue;
   1557         RefPtr<TypeBuilder::Array<int> > matchingSelectors = TypeBuilder::Array<int>::create();
   1558         const CSSSelectorList& selectorList = rule->styleRule()->selectorList();
   1559         long index = 0;
   1560         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
   1561             bool matched = element->webkitMatchesSelector(selector->selectorText(), IGNORE_EXCEPTION);
   1562             if (matched)
   1563                 matchingSelectors->addItem(index);
   1564             ++index;
   1565         }
   1566         RefPtr<TypeBuilder::CSS::RuleMatch> match = TypeBuilder::CSS::RuleMatch::create()
   1567             .setRule(ruleObject)
   1568             .setMatchingSelectors(matchingSelectors);
   1569         result->addItem(match);
   1570     }
   1571 
   1572     return result;
   1573 }
   1574 
   1575 PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
   1576 {
   1577     if (!element->isStyledElement())
   1578         return 0;
   1579 
   1580     // FIXME: Ugliness below.
   1581     StylePropertySet* attributeStyle = const_cast<StylePropertySet*>(element->presentationAttributeStyle());
   1582     if (!attributeStyle)
   1583         return 0;
   1584 
   1585     ASSERT(attributeStyle->isMutable());
   1586     MutableStylePropertySet* mutableAttributeStyle = static_cast<MutableStylePropertySet*>(attributeStyle);
   1587 
   1588     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), 0);
   1589     return inspectorStyle->buildObjectForStyle();
   1590 }
   1591 
   1592 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > InspectorCSSAgent::buildArrayForRegions(ErrorString* errorString, PassRefPtr<NodeList> regionList, int documentNodeId)
   1593 {
   1594     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > regions = TypeBuilder::Array<TypeBuilder::CSS::Region>::create();
   1595 
   1596     for (unsigned i = 0; i < regionList->length(); ++i) {
   1597         TypeBuilder::CSS::Region::RegionOverset::Enum regionOverset;
   1598 
   1599         switch (toElement(regionList->item(i))->renderRegion()->regionOversetState()) {
   1600         case RegionFit:
   1601             regionOverset = TypeBuilder::CSS::Region::RegionOverset::Fit;
   1602             break;
   1603         case RegionEmpty:
   1604             regionOverset = TypeBuilder::CSS::Region::RegionOverset::Empty;
   1605             break;
   1606         case RegionOverset:
   1607             regionOverset = TypeBuilder::CSS::Region::RegionOverset::Overset;
   1608             break;
   1609         case RegionUndefined:
   1610             continue;
   1611         default:
   1612             ASSERT_NOT_REACHED();
   1613             continue;
   1614         }
   1615 
   1616         RefPtr<TypeBuilder::CSS::Region> region = TypeBuilder::CSS::Region::create()
   1617             .setRegionOverset(regionOverset)
   1618             // documentNodeId was previously asserted
   1619             .setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i)));
   1620 
   1621         regions->addItem(region);
   1622     }
   1623 
   1624     return regions.release();
   1625 }
   1626 
   1627 PassRefPtr<TypeBuilder::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString* errorString, NamedFlow* webkitNamedFlow, int documentNodeId)
   1628 {
   1629     RefPtr<NodeList> contentList = webkitNamedFlow->getContent();
   1630     RefPtr<TypeBuilder::Array<int> > content = TypeBuilder::Array<int>::create();
   1631 
   1632     for (unsigned i = 0; i < contentList->length(); ++i) {
   1633         // documentNodeId was previously asserted
   1634         content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i)));
   1635     }
   1636 
   1637     RefPtr<TypeBuilder::CSS::NamedFlow> namedFlow = TypeBuilder::CSS::NamedFlow::create()
   1638         .setDocumentNodeId(documentNodeId)
   1639         .setName(webkitNamedFlow->name().string())
   1640         .setOverset(webkitNamedFlow->overset())
   1641         .setContent(content)
   1642         .setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId));
   1643 
   1644     return namedFlow.release();
   1645 }
   1646 
   1647 void InspectorCSSAgent::didRemoveDocument(Document* document)
   1648 {
   1649     if (document)
   1650         m_documentToInspectorStyleSheet.remove(document);
   1651 }
   1652 
   1653 void InspectorCSSAgent::didRemoveDOMNode(Node* node)
   1654 {
   1655     if (!node)
   1656         return;
   1657 
   1658     int nodeId = m_domAgent->boundNodeId(node);
   1659     if (nodeId)
   1660         m_nodeIdToForcedPseudoState.remove(nodeId);
   1661 
   1662     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
   1663     if (it == m_nodeToInspectorStyleSheet.end())
   1664         return;
   1665 
   1666     m_idToInspectorStyleSheet.remove(it->value->id());
   1667     m_nodeToInspectorStyleSheet.remove(node);
   1668 }
   1669 
   1670 void InspectorCSSAgent::didModifyDOMAttr(Element* element)
   1671 {
   1672     if (!element)
   1673         return;
   1674 
   1675     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
   1676     if (it == m_nodeToInspectorStyleSheet.end())
   1677         return;
   1678 
   1679     it->value->didModifyElementAttribute();
   1680 }
   1681 
   1682 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
   1683 {
   1684     if (m_frontend)
   1685         m_frontend->styleSheetChanged(styleSheet->id());
   1686 }
   1687 
   1688 void InspectorCSSAgent::willReparseStyleSheet()
   1689 {
   1690     ASSERT(!m_isSettingStyleSheetText);
   1691     m_isSettingStyleSheetText = true;
   1692 }
   1693 
   1694 void InspectorCSSAgent::didReparseStyleSheet()
   1695 {
   1696     ASSERT(m_isSettingStyleSheetText);
   1697     m_isSettingStyleSheetText = false;
   1698 }
   1699 
   1700 void InspectorCSSAgent::resetPseudoStates()
   1701 {
   1702     HashSet<Document*> documentsToChange;
   1703     for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) {
   1704         Element* element = toElement(m_domAgent->nodeForId(it->key));
   1705         if (element && element->ownerDocument())
   1706             documentsToChange.add(element->ownerDocument());
   1707     }
   1708 
   1709     m_nodeIdToForcedPseudoState.clear();
   1710     for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
   1711         (*it)->setNeedsStyleRecalc();
   1712 }
   1713 
   1714 } // namespace WebCore
   1715 
   1716