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