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
27#if ENABLE(INSPECTOR)
28
29#include "InspectorCSSAgent.h"
30
31#include "CSSComputedStyleDeclaration.h"
32#include "CSSImportRule.h"
33#include "CSSPropertyNames.h"
34#include "CSSPropertySourceData.h"
35#include "CSSRule.h"
36#include "CSSRuleList.h"
37#include "CSSStyleRule.h"
38#include "CSSStyleSheet.h"
39#include "ContentSecurityPolicy.h"
40#include "DOMWindow.h"
41#include "ExceptionCodePlaceholder.h"
42#include "HTMLHeadElement.h"
43#include "HTMLStyleElement.h"
44#include "InspectorDOMAgent.h"
45#include "InspectorHistory.h"
46#include "InspectorWebTypeBuilders.h"
47#include "InstrumentingAgents.h"
48#include "NamedFlowCollection.h"
49#include "Node.h"
50#include "NodeList.h"
51#include "RenderNamedFlowFragment.h"
52#include "SVGStyleElement.h"
53#include "StyleProperties.h"
54#include "StylePropertyShorthand.h"
55#include "StyleResolver.h"
56#include "StyleRule.h"
57#include "StyleSheetList.h"
58#include "WebKitNamedFlow.h"
59#include <inspector/InspectorValues.h>
60#include <wtf/CurrentTime.h>
61#include <wtf/HashSet.h>
62#include <wtf/Ref.h>
63#include <wtf/Vector.h>
64#include <wtf/text/CString.h>
65#include <wtf/text/StringConcatenate.h>
66
67using namespace Inspector;
68
69namespace WebCore {
70
71enum ForcePseudoClassFlags {
72    PseudoClassNone = 0,
73    PseudoClassHover = 1 << 0,
74    PseudoClassFocus = 1 << 1,
75    PseudoClassActive = 1 << 2,
76    PseudoClassVisited = 1 << 3
77};
78
79static unsigned computePseudoClassMask(InspectorArray* pseudoClassArray)
80{
81    DEPRECATED_DEFINE_STATIC_LOCAL(String, active, (ASCIILiteral("active")));
82    DEPRECATED_DEFINE_STATIC_LOCAL(String, hover, (ASCIILiteral("hover")));
83    DEPRECATED_DEFINE_STATIC_LOCAL(String, focus, (ASCIILiteral("focus")));
84    DEPRECATED_DEFINE_STATIC_LOCAL(String, visited, (ASCIILiteral("visited")));
85    if (!pseudoClassArray || !pseudoClassArray->length())
86        return PseudoClassNone;
87
88    unsigned result = PseudoClassNone;
89    for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
90        RefPtr<InspectorValue> pseudoClassValue = pseudoClassArray->get(i);
91        String pseudoClass;
92        bool success = pseudoClassValue->asString(&pseudoClass);
93        if (!success)
94            continue;
95        if (pseudoClass == active)
96            result |= PseudoClassActive;
97        else if (pseudoClass == hover)
98            result |= PseudoClassHover;
99        else if (pseudoClass == focus)
100            result |= PseudoClassFocus;
101        else if (pseudoClass == visited)
102            result |= PseudoClassVisited;
103    }
104
105    return result;
106}
107
108class ChangeRegionOversetTask {
109public:
110    ChangeRegionOversetTask(InspectorCSSAgent*);
111    void scheduleFor(WebKitNamedFlow*, int documentNodeId);
112    void unschedule(WebKitNamedFlow*);
113    void reset();
114    void timerFired(Timer<ChangeRegionOversetTask>&);
115
116private:
117    InspectorCSSAgent* m_cssAgent;
118    Timer<ChangeRegionOversetTask> m_timer;
119    HashMap<WebKitNamedFlow*, int> m_namedFlows;
120};
121
122ChangeRegionOversetTask::ChangeRegionOversetTask(InspectorCSSAgent* cssAgent)
123    : m_cssAgent(cssAgent)
124    , m_timer(this, &ChangeRegionOversetTask::timerFired)
125{
126}
127
128void ChangeRegionOversetTask::scheduleFor(WebKitNamedFlow* namedFlow, int documentNodeId)
129{
130    m_namedFlows.add(namedFlow, documentNodeId);
131
132    if (!m_timer.isActive())
133        m_timer.startOneShot(0);
134}
135
136void ChangeRegionOversetTask::unschedule(WebKitNamedFlow* namedFlow)
137{
138    m_namedFlows.remove(namedFlow);
139}
140
141void ChangeRegionOversetTask::reset()
142{
143    m_timer.stop();
144    m_namedFlows.clear();
145}
146
147void ChangeRegionOversetTask::timerFired(Timer<ChangeRegionOversetTask>&)
148{
149    // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed.
150    for (HashMap<WebKitNamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it)
151        m_cssAgent->regionOversetChanged(it->key, it->value);
152
153    m_namedFlows.clear();
154}
155
156class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
157    WTF_MAKE_NONCOPYABLE(StyleSheetAction);
158public:
159    StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
160        : InspectorHistory::Action(name)
161        , m_styleSheet(styleSheet)
162    {
163    }
164
165protected:
166    RefPtr<InspectorStyleSheet> m_styleSheet;
167};
168
169class InspectorCSSAgent::SetStyleSheetTextAction final : public InspectorCSSAgent::StyleSheetAction {
170    WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
171public:
172    SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
173        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetStyleSheetText"), styleSheet)
174        , m_text(text)
175    {
176    }
177
178    virtual bool perform(ExceptionCode& ec) override
179    {
180        if (!m_styleSheet->getText(&m_oldText))
181            return false;
182        return redo(ec);
183    }
184
185    virtual bool undo(ExceptionCode& ec) override
186    {
187        if (m_styleSheet->setText(m_oldText, ec)) {
188            m_styleSheet->reparseStyleSheet(m_oldText);
189            return true;
190        }
191        return false;
192    }
193
194    virtual bool redo(ExceptionCode& ec) override
195    {
196        if (m_styleSheet->setText(m_text, ec)) {
197            m_styleSheet->reparseStyleSheet(m_text);
198            return true;
199        }
200        return false;
201    }
202
203    virtual String mergeId() override
204    {
205        return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
206    }
207
208    virtual void merge(std::unique_ptr<Action> action) override
209    {
210        ASSERT(action->mergeId() == mergeId());
211
212        SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get());
213        m_text = other->m_text;
214    }
215
216private:
217    String m_text;
218    String m_oldText;
219};
220
221class InspectorCSSAgent::SetStyleTextAction final : public InspectorCSSAgent::StyleSheetAction {
222    WTF_MAKE_NONCOPYABLE(SetStyleTextAction);
223public:
224    SetStyleTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& text)
225        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetStyleText"), styleSheet)
226        , m_cssId(cssId)
227        , m_text(text)
228    {
229    }
230
231    virtual bool perform(ExceptionCode& ec) override
232    {
233        return redo(ec);
234    }
235
236    virtual bool undo(ExceptionCode& ec) override
237    {
238        return m_styleSheet->setStyleText(m_cssId, m_oldText, nullptr, ec);
239    }
240
241    virtual bool redo(ExceptionCode& ec) override
242    {
243        return m_styleSheet->setStyleText(m_cssId, m_text, &m_oldText, ec);
244    }
245
246    virtual String mergeId() override
247    {
248        ASSERT(m_styleSheet->id() == m_cssId.styleSheetId());
249        return String::format("SetStyleText %s:%u", m_styleSheet->id().utf8().data(), m_cssId.ordinal());
250    }
251
252    virtual void merge(std::unique_ptr<Action> action) override
253    {
254        ASSERT(action->mergeId() == mergeId());
255
256        SetStyleTextAction* other = static_cast<SetStyleTextAction*>(action.get());
257        m_text = other->m_text;
258    }
259
260private:
261    InspectorCSSId m_cssId;
262    String m_text;
263    String m_oldText;
264};
265
266class InspectorCSSAgent::SetPropertyTextAction final : public InspectorCSSAgent::StyleSheetAction {
267    WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
268public:
269    SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
270        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetPropertyText"), styleSheet)
271        , m_cssId(cssId)
272        , m_propertyIndex(propertyIndex)
273        , m_text(text)
274        , m_overwrite(overwrite)
275    {
276    }
277
278    virtual String toString() override
279    {
280        return mergeId() + ": " + m_oldText + " -> " + m_text;
281    }
282
283    virtual bool perform(ExceptionCode& ec) override
284    {
285        return redo(ec);
286    }
287
288    virtual bool undo(ExceptionCode& ec) override
289    {
290        String placeholder;
291        return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, ec);
292    }
293
294    virtual bool redo(ExceptionCode& ec) override
295    {
296        String oldText;
297        bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, ec);
298        m_oldText = oldText.stripWhiteSpace();
299        // FIXME: remove this once the model handles this case.
300        if (!m_oldText.endsWith(';'))
301            m_oldText.append(';');
302
303        return result;
304    }
305
306    virtual String mergeId() override
307    {
308        return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false");
309    }
310
311    virtual void merge(std::unique_ptr<Action> action) override
312    {
313        ASSERT(action->mergeId() == mergeId());
314
315        SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
316        m_text = other->m_text;
317    }
318
319private:
320    InspectorCSSId m_cssId;
321    unsigned m_propertyIndex;
322    String m_text;
323    String m_oldText;
324    bool m_overwrite;
325};
326
327class InspectorCSSAgent::TogglePropertyAction final : public InspectorCSSAgent::StyleSheetAction {
328    WTF_MAKE_NONCOPYABLE(TogglePropertyAction);
329public:
330    TogglePropertyAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, bool disable)
331        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("ToggleProperty"), styleSheet)
332        , m_cssId(cssId)
333        , m_propertyIndex(propertyIndex)
334        , m_disable(disable)
335    {
336    }
337
338    virtual bool perform(ExceptionCode& ec) override
339    {
340        return redo(ec);
341    }
342
343    virtual bool undo(ExceptionCode& ec) override
344    {
345        return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, !m_disable, ec);
346    }
347
348    virtual bool redo(ExceptionCode& ec) override
349    {
350        return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, m_disable, ec);
351    }
352
353private:
354    InspectorCSSId m_cssId;
355    unsigned m_propertyIndex;
356    bool m_disable;
357};
358
359class InspectorCSSAgent::SetRuleSelectorAction final : public InspectorCSSAgent::StyleSheetAction {
360    WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
361public:
362    SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
363        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetRuleSelector"), styleSheet)
364        , m_cssId(cssId)
365        , m_selector(selector)
366    {
367    }
368
369    virtual bool perform(ExceptionCode& ec) override
370    {
371        m_oldSelector = m_styleSheet->ruleSelector(m_cssId, ec);
372        if (ec)
373            return false;
374        return redo(ec);
375    }
376
377    virtual bool undo(ExceptionCode& ec) override
378    {
379        return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, ec);
380    }
381
382    virtual bool redo(ExceptionCode& ec) override
383    {
384        return m_styleSheet->setRuleSelector(m_cssId, m_selector, ec);
385    }
386
387private:
388    InspectorCSSId m_cssId;
389    String m_selector;
390    String m_oldSelector;
391};
392
393class InspectorCSSAgent::AddRuleAction final : public InspectorCSSAgent::StyleSheetAction {
394    WTF_MAKE_NONCOPYABLE(AddRuleAction);
395public:
396    AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
397        : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("AddRule"), styleSheet)
398        , m_selector(selector)
399    {
400    }
401
402    virtual bool perform(ExceptionCode& ec) override
403    {
404        return redo(ec);
405    }
406
407    virtual bool undo(ExceptionCode& ec) override
408    {
409        return m_styleSheet->deleteRule(m_newId, ec);
410    }
411
412    virtual bool redo(ExceptionCode& ec) override
413    {
414        CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, ec);
415        if (ec)
416            return false;
417        m_newId = m_styleSheet->ruleId(cssStyleRule);
418        return true;
419    }
420
421    InspectorCSSId newRuleId() { return m_newId; }
422
423private:
424    InspectorCSSId m_newId;
425    String m_selector;
426    String m_oldSelector;
427};
428
429// static
430CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
431{
432    if (rule->type() != CSSRule::STYLE_RULE)
433        return nullptr;
434    return static_cast<CSSStyleRule*>(rule);
435}
436
437InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorDOMAgent* domAgent)
438    : InspectorAgentBase(ASCIILiteral("CSS"), instrumentingAgents)
439    , m_domAgent(domAgent)
440    , m_lastStyleSheetId(1)
441{
442    m_domAgent->setDOMListener(this);
443}
444
445InspectorCSSAgent::~InspectorCSSAgent()
446{
447    ASSERT(!m_domAgent);
448    reset();
449}
450
451void InspectorCSSAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
452{
453    m_frontendDispatcher = std::make_unique<InspectorCSSFrontendDispatcher>(frontendChannel);
454    m_backendDispatcher = InspectorCSSBackendDispatcher::create(backendDispatcher, this);
455}
456
457void InspectorCSSAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
458{
459    m_frontendDispatcher = nullptr;
460    m_backendDispatcher.clear();
461
462    resetNonPersistentData();
463}
464
465void InspectorCSSAgent::discardAgent()
466{
467    m_domAgent->setDOMListener(nullptr);
468    m_domAgent = nullptr;
469}
470
471void InspectorCSSAgent::reset()
472{
473    m_idToInspectorStyleSheet.clear();
474    m_cssStyleSheetToInspectorStyleSheet.clear();
475    m_nodeToInspectorStyleSheet.clear();
476    m_documentToInspectorStyleSheet.clear();
477    resetNonPersistentData();
478}
479
480void InspectorCSSAgent::resetNonPersistentData()
481{
482    m_namedFlowCollectionsRequested.clear();
483    if (m_changeRegionOversetTask)
484        m_changeRegionOversetTask->reset();
485    resetPseudoStates();
486}
487
488void InspectorCSSAgent::enable(ErrorString*)
489{
490    m_instrumentingAgents->setInspectorCSSAgent(this);
491}
492
493void InspectorCSSAgent::disable(ErrorString*)
494{
495    m_instrumentingAgents->setInspectorCSSAgent(nullptr);
496}
497
498void InspectorCSSAgent::mediaQueryResultChanged()
499{
500    if (m_frontendDispatcher)
501        m_frontendDispatcher->mediaQueryResultChanged();
502}
503
504void InspectorCSSAgent::didCreateNamedFlow(Document* document, WebKitNamedFlow* namedFlow)
505{
506    int documentNodeId = documentNodeWithRequestedFlowsId(document);
507    if (!documentNodeId)
508        return;
509
510    ErrorString errorString;
511    m_frontendDispatcher->namedFlowCreated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
512}
513
514void InspectorCSSAgent::willRemoveNamedFlow(Document* document, WebKitNamedFlow* namedFlow)
515{
516    int documentNodeId = documentNodeWithRequestedFlowsId(document);
517    if (!documentNodeId)
518        return;
519
520    if (m_changeRegionOversetTask)
521        m_changeRegionOversetTask->unschedule(namedFlow);
522
523    m_frontendDispatcher->namedFlowRemoved(documentNodeId, namedFlow->name().string());
524}
525
526void InspectorCSSAgent::didChangeRegionOverset(Document* document, WebKitNamedFlow* namedFlow)
527{
528    int documentNodeId = documentNodeWithRequestedFlowsId(document);
529    if (!documentNodeId)
530        return;
531
532    if (!m_changeRegionOversetTask)
533        m_changeRegionOversetTask = std::make_unique<ChangeRegionOversetTask>(this);
534    m_changeRegionOversetTask->scheduleFor(namedFlow, documentNodeId);
535}
536
537void InspectorCSSAgent::regionOversetChanged(WebKitNamedFlow* namedFlow, int documentNodeId)
538{
539    if (namedFlow->flowState() == WebKitNamedFlow::FlowStateNull)
540        return;
541
542    ErrorString errorString;
543    Ref<WebKitNamedFlow> protect(*namedFlow);
544
545    m_frontendDispatcher->regionOversetChanged(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
546}
547
548void InspectorCSSAgent::didRegisterNamedFlowContentElement(Document* document, WebKitNamedFlow* namedFlow, Node* contentElement, Node* nextContentElement)
549{
550    int documentNodeId = documentNodeWithRequestedFlowsId(document);
551    if (!documentNodeId)
552        return;
553
554    ErrorString errorString;
555    int contentElementNodeId = m_domAgent->pushNodeToFrontend(&errorString, documentNodeId, contentElement);
556    int nextContentElementNodeId = nextContentElement ? m_domAgent->pushNodeToFrontend(&errorString, documentNodeId, nextContentElement) : 0;
557    m_frontendDispatcher->registeredNamedFlowContentElement(documentNodeId, namedFlow->name().string(), contentElementNodeId, nextContentElementNodeId);
558}
559
560void InspectorCSSAgent::didUnregisterNamedFlowContentElement(Document* document, WebKitNamedFlow* namedFlow, Node* contentElement)
561{
562    int documentNodeId = documentNodeWithRequestedFlowsId(document);
563    if (!documentNodeId)
564        return;
565
566    ErrorString errorString;
567    int contentElementNodeId = m_domAgent->pushNodeToFrontend(&errorString, documentNodeId, contentElement);
568    if (!contentElementNodeId) {
569        // We've already notified that the DOM node was removed from the DOM, so there's no need to send another event.
570        return;
571    }
572    m_frontendDispatcher->unregisteredNamedFlowContentElement(documentNodeId, namedFlow->name().string(), contentElementNodeId);
573}
574
575bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoClassType pseudoClassType)
576{
577    if (m_nodeIdToForcedPseudoState.isEmpty())
578        return false;
579
580    int nodeId = m_domAgent->boundNodeId(element);
581    if (!nodeId)
582        return false;
583
584    NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
585    if (it == m_nodeIdToForcedPseudoState.end())
586        return false;
587
588    unsigned forcedPseudoState = it->value;
589    switch (pseudoClassType) {
590    case CSSSelector::PseudoClassActive:
591        return forcedPseudoState & PseudoClassActive;
592    case CSSSelector::PseudoClassFocus:
593        return forcedPseudoState & PseudoClassFocus;
594    case CSSSelector::PseudoClassHover:
595        return forcedPseudoState & PseudoClassHover;
596    case CSSSelector::PseudoClassVisited:
597        return forcedPseudoState & PseudoClassVisited;
598    default:
599        return false;
600    }
601}
602
603void InspectorCSSAgent::getMatchedStylesForNode(ErrorString* errorString, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::RuleMatch>>& matchedCSSRules, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::PseudoIdMatches>>& pseudoIdMatches, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::InheritedStyleEntry>>& inheritedEntries)
604{
605    Element* element = elementForId(errorString, nodeId);
606    if (!element)
607        return;
608
609    // Matched rules.
610    StyleResolver& styleResolver = element->document().ensureStyleResolver();
611    auto matchedRules = styleResolver.styleRulesForElement(element, StyleResolver::AllCSSRules);
612    matchedCSSRules = buildArrayForMatchedRuleList(matchedRules, styleResolver, element);
613
614    // Pseudo elements.
615    if (!includePseudo || *includePseudo) {
616        RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::PseudoIdMatches>> pseudoElements = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::PseudoIdMatches>::create();
617        for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
618            auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
619            if (!matchedRules.isEmpty()) {
620                RefPtr<Inspector::TypeBuilder::CSS::PseudoIdMatches> matches = Inspector::TypeBuilder::CSS::PseudoIdMatches::create()
621                    .setPseudoId(static_cast<int>(pseudoId))
622                    .setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, element));
623                pseudoElements->addItem(matches.release());
624            }
625        }
626
627        pseudoIdMatches = pseudoElements.release();
628    }
629
630    // Inherited styles.
631    if (!includeInherited || *includeInherited) {
632        RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::InheritedStyleEntry>> entries = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::InheritedStyleEntry>::create();
633        Element* parentElement = element->parentElement();
634        while (parentElement) {
635            StyleResolver& parentStyleResolver = parentElement->document().ensureStyleResolver();
636            auto parentMatchedRules = parentStyleResolver.styleRulesForElement(parentElement, StyleResolver::AllCSSRules);
637            RefPtr<Inspector::TypeBuilder::CSS::InheritedStyleEntry> entry = Inspector::TypeBuilder::CSS::InheritedStyleEntry::create()
638                .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules, styleResolver, parentElement));
639            if (parentElement->style() && parentElement->style()->length()) {
640                InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
641                if (styleSheet)
642                    entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
643            }
644
645            entries->addItem(entry.release());
646            parentElement = parentElement->parentElement();
647        }
648
649        inheritedEntries = entries.release();
650    }
651}
652
653void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<Inspector::TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<Inspector::TypeBuilder::CSS::CSSStyle>& attributesStyle)
654{
655    Element* element = elementForId(errorString, nodeId);
656    if (!element)
657        return;
658
659    InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
660    if (!styleSheet)
661        return;
662
663    inlineStyle = styleSheet->buildObjectForStyle(element->style());
664    RefPtr<Inspector::TypeBuilder::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
665    attributesStyle = attributes ? attributes.release() : nullptr;
666}
667
668void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSComputedStyleProperty>>& style)
669{
670    Element* element = elementForId(errorString, nodeId);
671    if (!element)
672        return;
673
674    RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(element, true);
675    RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, nullptr);
676    style = inspectorStyle->buildArrayForComputedStyle();
677}
678
679void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSStyleSheetHeader>>& styleInfos)
680{
681    styleInfos = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSStyleSheetHeader>::create();
682    Vector<Document*> documents = m_domAgent->documents();
683    for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
684        StyleSheetList* list = (*it)->styleSheets();
685        for (unsigned i = 0; i < list->length(); ++i) {
686            StyleSheet* styleSheet = list->item(i);
687            if (styleSheet->isCSSStyleSheet())
688                collectStyleSheets(static_cast<CSSStyleSheet*>(styleSheet), styleInfos.get());
689        }
690    }
691}
692
693void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<Inspector::TypeBuilder::CSS::CSSStyleSheetBody>& styleSheetObject)
694{
695    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
696    if (!inspectorStyleSheet)
697        return;
698
699    styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
700}
701
702void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
703{
704    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
705    if (!inspectorStyleSheet)
706        return;
707
708    inspectorStyleSheet->getText(result);
709}
710
711void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
712{
713    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
714    if (!inspectorStyleSheet)
715        return;
716
717    ExceptionCode ec = 0;
718    m_domAgent->history()->perform(std::make_unique<SetStyleSheetTextAction>(inspectorStyleSheet, text), ec);
719    *errorString = InspectorDOMAgent::toErrorString(ec);
720}
721
722void InspectorCSSAgent::setStyleText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, const String& text, RefPtr<Inspector::TypeBuilder::CSS::CSSStyle>& result)
723{
724    InspectorCSSId compoundId(fullStyleId);
725    ASSERT(!compoundId.isEmpty());
726
727    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
728    if (!inspectorStyleSheet)
729        return;
730
731    ExceptionCode ec = 0;
732    bool success = m_domAgent->history()->perform(std::make_unique<SetStyleTextAction>(inspectorStyleSheet, compoundId, text), ec);
733    if (success)
734        result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
735    *errorString = InspectorDOMAgent::toErrorString(ec);
736}
737
738void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<Inspector::TypeBuilder::CSS::CSSStyle>& result)
739{
740    InspectorCSSId compoundId(fullStyleId);
741    ASSERT(!compoundId.isEmpty());
742
743    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
744    if (!inspectorStyleSheet)
745        return;
746
747    ExceptionCode ec = 0;
748    bool success = m_domAgent->history()->perform(std::make_unique<SetPropertyTextAction>(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite), ec);
749    if (success)
750        result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
751    *errorString = InspectorDOMAgent::toErrorString(ec);
752}
753
754void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<Inspector::TypeBuilder::CSS::CSSStyle>& result)
755{
756    InspectorCSSId compoundId(fullStyleId);
757    ASSERT(!compoundId.isEmpty());
758
759    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
760    if (!inspectorStyleSheet)
761        return;
762
763    ExceptionCode ec = 0;
764    bool success = m_domAgent->history()->perform(std::make_unique<TogglePropertyAction>(inspectorStyleSheet, compoundId, propertyIndex, disable), ec);
765    if (success)
766        result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
767    *errorString = InspectorDOMAgent::toErrorString(ec);
768}
769
770void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<Inspector::TypeBuilder::CSS::CSSRule>& result)
771{
772    InspectorCSSId compoundId(fullRuleId);
773    ASSERT(!compoundId.isEmpty());
774
775    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
776    if (!inspectorStyleSheet)
777        return;
778
779    ExceptionCode ec = 0;
780    bool success = m_domAgent->history()->perform(std::make_unique<SetRuleSelectorAction>(inspectorStyleSheet, compoundId, selector), ec);
781
782    if (success)
783        result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
784    *errorString = InspectorDOMAgent::toErrorString(ec);
785}
786
787void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<Inspector::TypeBuilder::CSS::CSSRule>& result)
788{
789    Node* node = m_domAgent->assertNode(errorString, contextNodeId);
790    if (!node)
791        return;
792
793    InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(&node->document(), true);
794    if (!inspectorStyleSheet) {
795        *errorString = "No target stylesheet found";
796        return;
797    }
798
799    ExceptionCode ec = 0;
800    auto action = std::make_unique<AddRuleAction>(inspectorStyleSheet, selector);
801    AddRuleAction* rawAction = action.get();
802    bool success = m_domAgent->history()->perform(WTF::move(action), ec);
803    if (!success) {
804        *errorString = InspectorDOMAgent::toErrorString(ec);
805        return;
806    }
807
808    InspectorCSSId ruleId = rawAction->newRuleId();
809    CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
810    result = inspectorStyleSheet->buildObjectForRule(rule);
811}
812
813void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSPropertyInfo>>& cssProperties)
814{
815    RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSPropertyInfo>> properties = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSPropertyInfo>::create();
816    for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
817        CSSPropertyID id = convertToCSSPropertyID(i);
818        RefPtr<Inspector::TypeBuilder::CSS::CSSPropertyInfo> property = Inspector::TypeBuilder::CSS::CSSPropertyInfo::create()
819            .setName(getPropertyNameString(id));
820
821        const StylePropertyShorthand& shorthand = shorthandForProperty(id);
822        if (!shorthand.length()) {
823            properties->addItem(property.release());
824            continue;
825        }
826        RefPtr<Inspector::TypeBuilder::Array<String>> longhands = Inspector::TypeBuilder::Array<String>::create();
827        for (unsigned j = 0; j < shorthand.length(); ++j) {
828            CSSPropertyID longhandID = shorthand.properties()[j];
829            longhands->addItem(getPropertyNameString(longhandID));
830        }
831        property->setLonghands(longhands);
832        properties->addItem(property.release());
833    }
834    cssProperties = properties.release();
835}
836
837void InspectorCSSAgent::forcePseudoState(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>& forcedPseudoClasses)
838{
839    Element* element = m_domAgent->assertElement(errorString, nodeId);
840    if (!element)
841        return;
842
843    unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses.get());
844    NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
845    unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value;
846    bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState;
847    if (!needStyleRecalc)
848        return;
849
850    if (forcedPseudoState)
851        m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
852    else
853        m_nodeIdToForcedPseudoState.remove(nodeId);
854    element->document().styleResolverChanged(RecalcStyleImmediately);
855}
856
857void InspectorCSSAgent::getNamedFlowCollection(ErrorString* errorString, int documentNodeId, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::NamedFlow>>& result)
858{
859    Document* document = m_domAgent->assertDocument(errorString, documentNodeId);
860    if (!document)
861        return;
862
863    m_namedFlowCollectionsRequested.add(documentNodeId);
864
865    Vector<RefPtr<WebKitNamedFlow>> namedFlowsVector = document->namedFlows()->namedFlows();
866    RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::NamedFlow>> namedFlows = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::NamedFlow>::create();
867
868    for (Vector<RefPtr<WebKitNamedFlow>>::iterator it = namedFlowsVector.begin(); it != namedFlowsVector.end(); ++it)
869        namedFlows->addItem(buildObjectForNamedFlow(errorString, it->get(), documentNodeId));
870
871    result = namedFlows.release();
872}
873
874InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
875{
876    NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
877    if (it == m_nodeToInspectorStyleSheet.end()) {
878        CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : nullptr;
879        if (!style)
880            return nullptr;
881
882        String newStyleSheetId = String::number(m_lastStyleSheetId++);
883        RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_domAgent->pageAgent(), newStyleSheetId, element, Inspector::TypeBuilder::CSS::StyleSheetOrigin::Regular, this);
884        m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
885        m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
886        return inspectorStyleSheet.get();
887    }
888
889    return it->value.get();
890}
891
892Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
893{
894    Node* node = m_domAgent->nodeForId(nodeId);
895    if (!node) {
896        *errorString = "No node with given id found";
897        return nullptr;
898    }
899    if (!node->isElementNode()) {
900        *errorString = "Not an element node";
901        return nullptr;
902    }
903    return toElement(node);
904}
905
906int InspectorCSSAgent::documentNodeWithRequestedFlowsId(Document* document)
907{
908    int documentNodeId = m_domAgent->boundNodeId(document);
909    if (!documentNodeId || !m_namedFlowCollectionsRequested.contains(documentNodeId))
910        return 0;
911
912    return documentNodeId;
913}
914
915void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSStyleSheetHeader>* result)
916{
917    InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
918    result->addItem(inspectorStyleSheet->buildObjectForStyleSheetInfo());
919    for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
920        CSSRule* rule = styleSheet->item(i);
921        if (rule->type() == CSSRule::IMPORT_RULE) {
922            CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet();
923            if (importedStyleSheet)
924                collectStyleSheets(importedStyleSheet, result);
925        }
926    }
927}
928
929InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
930{
931    RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
932    if (!inspectorStyleSheet) {
933        String id = String::number(m_lastStyleSheetId++);
934        Document* document = styleSheet->ownerDocument();
935        inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
936        m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
937        m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
938    }
939    return inspectorStyleSheet.get();
940}
941
942InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
943{
944    if (!document) {
945        ASSERT(!createIfAbsent);
946        return nullptr;
947    }
948
949    if (!document->isHTMLDocument() && !document->isSVGDocument())
950        return nullptr;
951
952    RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
953    if (inspectorStyleSheet || !createIfAbsent)
954        return inspectorStyleSheet.get();
955
956    ExceptionCode ec = 0;
957    RefPtr<Element> styleElement = document->createElement("style", ec);
958    if (!ec)
959        styleElement->setAttribute("type", "text/css", ec);
960    if (!ec) {
961        ContainerNode* targetNode;
962        // HEAD is absent in ImageDocuments, for example.
963        if (document->head())
964            targetNode = document->head();
965        else if (document->body())
966            targetNode = document->body();
967        else
968            return nullptr;
969
970        InlineStyleOverrideScope overrideScope(document);
971        targetNode->appendChild(styleElement, ec);
972    }
973    if (ec)
974        return nullptr;
975
976    CSSStyleSheet* cssStyleSheet = nullptr;
977    if (styleElement->isHTMLElement())
978        cssStyleSheet = toHTMLStyleElement(styleElement.get())->sheet();
979    else if (styleElement->isSVGElement())
980        cssStyleSheet = toSVGStyleElement(styleElement.get())->sheet();
981
982    if (!cssStyleSheet)
983        return nullptr;
984
985    String id = String::number(m_lastStyleSheetId++);
986    inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, cssStyleSheet, Inspector::TypeBuilder::CSS::StyleSheetOrigin::Inspector, InspectorDOMAgent::documentURLString(document), this);
987    m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
988    m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
989    m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
990    return inspectorStyleSheet.get();
991}
992
993InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
994{
995    IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
996    if (it == m_idToInspectorStyleSheet.end()) {
997        *errorString = "No style sheet with given id found";
998        return nullptr;
999    }
1000    return it->value.get();
1001}
1002
1003Inspector::TypeBuilder::CSS::StyleSheetOrigin::Enum InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
1004{
1005    Inspector::TypeBuilder::CSS::StyleSheetOrigin::Enum origin = Inspector::TypeBuilder::CSS::StyleSheetOrigin::Regular;
1006    if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
1007        origin = Inspector::TypeBuilder::CSS::StyleSheetOrigin::UserAgent;
1008    else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
1009        origin = Inspector::TypeBuilder::CSS::StyleSheetOrigin::User;
1010    else {
1011        InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
1012        if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
1013            origin = Inspector::TypeBuilder::CSS::StyleSheetOrigin::Inspector;
1014    }
1015    return origin;
1016}
1017
1018PassRefPtr<Inspector::TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(StyleRule* styleRule, StyleResolver& styleResolver)
1019{
1020    if (!styleRule)
1021        return nullptr;
1022
1023    // StyleRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
1024    // Since the inspector wants to walk the parent chain, we construct the full wrappers here.
1025    CSSStyleRule* cssomWrapper = styleResolver.inspectorCSSOMWrappers().getWrapperForRuleInSheets(styleRule, styleResolver.document().styleSheetCollection());
1026    if (!cssomWrapper)
1027        return nullptr;
1028    InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssomWrapper->parentStyleSheet());
1029    return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(cssomWrapper) : nullptr;
1030}
1031
1032PassRefPtr<Inspector::TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule)
1033{
1034    if (!rule)
1035        return nullptr;
1036
1037    ASSERT(rule->parentStyleSheet());
1038    InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(rule->parentStyleSheet());
1039    return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(rule) : nullptr;
1040}
1041
1042PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSRule>> InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
1043{
1044    RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSRule>> result = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::CSSRule>::create();
1045    if (!ruleList)
1046        return result.release();
1047
1048    for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
1049        CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
1050        RefPtr<Inspector::TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule);
1051        if (!ruleObject)
1052            continue;
1053        result->addItem(ruleObject);
1054    }
1055    return result.release();
1056}
1057
1058PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::RuleMatch>> InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>& matchedRules, StyleResolver& styleResolver, Element* element)
1059{
1060    RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::RuleMatch>> result = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::RuleMatch>::create();
1061
1062    for (unsigned i = 0; i < matchedRules.size(); ++i) {
1063        if (!matchedRules[i]->isStyleRule())
1064            continue;
1065        StyleRule* matchedStyleRule = static_cast<StyleRule*>(matchedRules[i].get());
1066        RefPtr<Inspector::TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(matchedStyleRule, styleResolver);
1067        if (!ruleObject)
1068            continue;
1069        RefPtr<Inspector::TypeBuilder::Array<int>> matchingSelectors = Inspector::TypeBuilder::Array<int>::create();
1070        const CSSSelectorList& selectorList = matchedStyleRule->selectorList();
1071        long index = 0;
1072        for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
1073            bool matched = element->matches(selector->selectorText(), IGNORE_EXCEPTION);
1074            if (matched)
1075                matchingSelectors->addItem(index);
1076            ++index;
1077        }
1078        RefPtr<Inspector::TypeBuilder::CSS::RuleMatch> match = Inspector::TypeBuilder::CSS::RuleMatch::create()
1079            .setRule(ruleObject)
1080            .setMatchingSelectors(matchingSelectors);
1081        result->addItem(match);
1082    }
1083
1084    return result.release();
1085}
1086
1087PassRefPtr<Inspector::TypeBuilder::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
1088{
1089    if (!element->isStyledElement())
1090        return nullptr;
1091
1092    // FIXME: Ugliness below.
1093    StyleProperties* attributeStyle = const_cast<StyleProperties*>(toStyledElement(element)->presentationAttributeStyle());
1094    if (!attributeStyle)
1095        return nullptr;
1096
1097    ASSERT_WITH_SECURITY_IMPLICATION(attributeStyle->isMutable());
1098    MutableStyleProperties* mutableAttributeStyle = static_cast<MutableStyleProperties*>(attributeStyle);
1099
1100    RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), nullptr);
1101    return inspectorStyle->buildObjectForStyle();
1102}
1103
1104PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::Region>> InspectorCSSAgent::buildArrayForRegions(ErrorString* errorString, PassRefPtr<NodeList> regionList, int documentNodeId)
1105{
1106    RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::Region>> regions = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::CSS::Region>::create();
1107
1108    for (unsigned i = 0; i < regionList->length(); ++i) {
1109        Inspector::TypeBuilder::CSS::Region::RegionOverset::Enum regionOverset;
1110
1111        switch (toElement(regionList->item(i))->regionOversetState()) {
1112        case RegionFit:
1113            regionOverset = Inspector::TypeBuilder::CSS::Region::RegionOverset::Fit;
1114            break;
1115        case RegionEmpty:
1116            regionOverset = Inspector::TypeBuilder::CSS::Region::RegionOverset::Empty;
1117            break;
1118        case RegionOverset:
1119            regionOverset = Inspector::TypeBuilder::CSS::Region::RegionOverset::Overset;
1120            break;
1121        case RegionUndefined:
1122            continue;
1123        default:
1124            ASSERT_NOT_REACHED();
1125            continue;
1126        }
1127
1128        RefPtr<Inspector::TypeBuilder::CSS::Region> region = Inspector::TypeBuilder::CSS::Region::create()
1129            .setRegionOverset(regionOverset)
1130            // documentNodeId was previously asserted
1131            .setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i)));
1132
1133        regions->addItem(region);
1134    }
1135
1136    return regions.release();
1137}
1138
1139PassRefPtr<Inspector::TypeBuilder::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString* errorString, WebKitNamedFlow* webkitNamedFlow, int documentNodeId)
1140{
1141    RefPtr<NodeList> contentList = webkitNamedFlow->getContent();
1142    RefPtr<Inspector::TypeBuilder::Array<int>> content = Inspector::TypeBuilder::Array<int>::create();
1143
1144    for (unsigned i = 0; i < contentList->length(); ++i) {
1145        // documentNodeId was previously asserted
1146        content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i)));
1147    }
1148
1149    RefPtr<Inspector::TypeBuilder::CSS::NamedFlow> namedFlow = Inspector::TypeBuilder::CSS::NamedFlow::create()
1150        .setDocumentNodeId(documentNodeId)
1151        .setName(webkitNamedFlow->name().string())
1152        .setOverset(webkitNamedFlow->overset())
1153        .setContent(content)
1154        .setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId));
1155
1156    return namedFlow.release();
1157}
1158
1159void InspectorCSSAgent::didRemoveDocument(Document* document)
1160{
1161    if (document)
1162        m_documentToInspectorStyleSheet.remove(document);
1163}
1164
1165void InspectorCSSAgent::didRemoveDOMNode(Node* node)
1166{
1167    if (!node)
1168        return;
1169
1170    int nodeId = m_domAgent->boundNodeId(node);
1171    if (nodeId)
1172        m_nodeIdToForcedPseudoState.remove(nodeId);
1173
1174    NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
1175    if (it == m_nodeToInspectorStyleSheet.end())
1176        return;
1177
1178    m_idToInspectorStyleSheet.remove(it->value->id());
1179    m_nodeToInspectorStyleSheet.remove(node);
1180}
1181
1182void InspectorCSSAgent::didModifyDOMAttr(Element* element)
1183{
1184    if (!element)
1185        return;
1186
1187    NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1188    if (it == m_nodeToInspectorStyleSheet.end())
1189        return;
1190
1191    it->value->didModifyElementAttribute();
1192}
1193
1194void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1195{
1196    if (m_frontendDispatcher)
1197        m_frontendDispatcher->styleSheetChanged(styleSheet->id());
1198}
1199
1200void InspectorCSSAgent::resetPseudoStates()
1201{
1202    HashSet<Document*> documentsToChange;
1203    for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) {
1204        if (Element* element = toElement(m_domAgent->nodeForId(it->key)))
1205            documentsToChange.add(&element->document());
1206    }
1207
1208    m_nodeIdToForcedPseudoState.clear();
1209    for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
1210        (*it)->styleResolverChanged(RecalcStyleImmediately);
1211}
1212
1213} // namespace WebCore
1214
1215#endif // ENABLE(INSPECTOR)
1216