6eecd5d30b6880828c2838a528754493677aa3c9
[WebKit-https.git] / Source / WebCore / inspector / InspectorCSSAgent.cpp
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 "InspectorWebProtocolTypes.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
67 using namespace Inspector;
68
69 namespace WebCore {
70
71 enum ForcePseudoClassFlags {
72     PseudoClassNone = 0,
73     PseudoClassHover = 1 << 0,
74     PseudoClassFocus = 1 << 1,
75     PseudoClassActive = 1 << 2,
76     PseudoClassVisited = 1 << 3
77 };
78
79 static 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
108 class ChangeRegionOversetTask {
109 public:
110     ChangeRegionOversetTask(InspectorCSSAgent*);
111     void scheduleFor(WebKitNamedFlow*, int documentNodeId);
112     void unschedule(WebKitNamedFlow*);
113     void reset();
114     void timerFired(Timer<ChangeRegionOversetTask>&);
115
116 private:
117     InspectorCSSAgent* m_cssAgent;
118     Timer<ChangeRegionOversetTask> m_timer;
119     HashMap<WebKitNamedFlow*, int> m_namedFlows;
120 };
121
122 ChangeRegionOversetTask::ChangeRegionOversetTask(InspectorCSSAgent* cssAgent)
123     : m_cssAgent(cssAgent)
124     , m_timer(this, &ChangeRegionOversetTask::timerFired)
125 {
126 }
127
128 void 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
136 void ChangeRegionOversetTask::unschedule(WebKitNamedFlow* namedFlow)
137 {
138     m_namedFlows.remove(namedFlow);
139 }
140
141 void ChangeRegionOversetTask::reset()
142 {
143     m_timer.stop();
144     m_namedFlows.clear();
145 }
146
147 void 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
156 class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
157     WTF_MAKE_NONCOPYABLE(StyleSheetAction);
158 public:
159     StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
160         : InspectorHistory::Action(name)
161         , m_styleSheet(styleSheet)
162     {
163     }
164
165 protected:
166     RefPtr<InspectorStyleSheet> m_styleSheet;
167 };
168
169 class InspectorCSSAgent::SetStyleSheetTextAction final : public InspectorCSSAgent::StyleSheetAction {
170     WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
171 public:
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
216 private:
217     String m_text;
218     String m_oldText;
219 };
220
221 class InspectorCSSAgent::SetStyleTextAction final : public InspectorCSSAgent::StyleSheetAction {
222     WTF_MAKE_NONCOPYABLE(SetStyleTextAction);
223 public:
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
260 private:
261     InspectorCSSId m_cssId;
262     String m_text;
263     String m_oldText;
264 };
265
266 class InspectorCSSAgent::SetPropertyTextAction final : public InspectorCSSAgent::StyleSheetAction {
267     WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
268 public:
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
319 private:
320     InspectorCSSId m_cssId;
321     unsigned m_propertyIndex;
322     String m_text;
323     String m_oldText;
324     bool m_overwrite;
325 };
326
327 class InspectorCSSAgent::TogglePropertyAction final : public InspectorCSSAgent::StyleSheetAction {
328     WTF_MAKE_NONCOPYABLE(TogglePropertyAction);
329 public:
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
353 private:
354     InspectorCSSId m_cssId;
355     unsigned m_propertyIndex;
356     bool m_disable;
357 };
358
359 class InspectorCSSAgent::SetRuleSelectorAction final : public InspectorCSSAgent::StyleSheetAction {
360     WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
361 public:
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
387 private:
388     InspectorCSSId m_cssId;
389     String m_selector;
390     String m_oldSelector;
391 };
392
393 class InspectorCSSAgent::AddRuleAction final : public InspectorCSSAgent::StyleSheetAction {
394     WTF_MAKE_NONCOPYABLE(AddRuleAction);
395 public:
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
423 private:
424     InspectorCSSId m_newId;
425     String m_selector;
426     String m_oldSelector;
427 };
428
429 // static
430 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
431 {
432     if (rule->type() != CSSRule::STYLE_RULE)
433         return nullptr;
434     return toCSSStyleRule(rule);
435 }
436
437 InspectorCSSAgent::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
445 InspectorCSSAgent::~InspectorCSSAgent()
446 {
447     ASSERT(!m_domAgent);
448     reset();
449 }
450
451 void 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
457 void InspectorCSSAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
458 {
459     m_frontendDispatcher = nullptr;
460     m_backendDispatcher.clear();
461
462     resetNonPersistentData();
463 }
464
465 void InspectorCSSAgent::discardAgent()
466 {
467     m_domAgent->setDOMListener(nullptr);
468     m_domAgent = nullptr;
469 }
470
471 void InspectorCSSAgent::reset()
472 {
473     m_idToInspectorStyleSheet.clear();
474     m_cssStyleSheetToInspectorStyleSheet.clear();
475     m_nodeToInspectorStyleSheet.clear();
476     m_documentToInspectorStyleSheet.clear();
477     resetNonPersistentData();
478 }
479
480 void InspectorCSSAgent::resetNonPersistentData()
481 {
482     m_namedFlowCollectionsRequested.clear();
483     if (m_changeRegionOversetTask)
484         m_changeRegionOversetTask->reset();
485     resetPseudoStates();
486 }
487
488 void InspectorCSSAgent::enable(ErrorString&)
489 {
490     m_instrumentingAgents->setInspectorCSSAgent(this);
491 }
492
493 void InspectorCSSAgent::disable(ErrorString&)
494 {
495     m_instrumentingAgents->setInspectorCSSAgent(nullptr);
496 }
497
498 void InspectorCSSAgent::mediaQueryResultChanged()
499 {
500     if (m_frontendDispatcher)
501         m_frontendDispatcher->mediaQueryResultChanged();
502 }
503
504 void InspectorCSSAgent::didCreateNamedFlow(Document* document, WebKitNamedFlow* namedFlow)
505 {
506     int documentNodeId = documentNodeWithRequestedFlowsId(document);
507     if (!documentNodeId)
508         return;
509
510     ErrorString unused;
511     m_frontendDispatcher->namedFlowCreated(buildObjectForNamedFlow(unused, namedFlow, documentNodeId));
512 }
513
514 void 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
526 void 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
537 void InspectorCSSAgent::regionOversetChanged(WebKitNamedFlow* namedFlow, int documentNodeId)
538 {
539     if (namedFlow->flowState() == WebKitNamedFlow::FlowStateNull)
540         return;
541
542     ErrorString unused;
543     Ref<WebKitNamedFlow> protect(*namedFlow);
544
545     m_frontendDispatcher->regionOversetChanged(buildObjectForNamedFlow(unused, namedFlow, documentNodeId));
546 }
547
548 void InspectorCSSAgent::didRegisterNamedFlowContentElement(Document* document, WebKitNamedFlow* namedFlow, Node* contentElement, Node* nextContentElement)
549 {
550     int documentNodeId = documentNodeWithRequestedFlowsId(document);
551     if (!documentNodeId)
552         return;
553
554     ErrorString unused;
555     int contentElementNodeId = m_domAgent->pushNodeToFrontend(unused, documentNodeId, contentElement);
556     int nextContentElementNodeId = nextContentElement ? m_domAgent->pushNodeToFrontend(unused, documentNodeId, nextContentElement) : 0;
557     m_frontendDispatcher->registeredNamedFlowContentElement(documentNodeId, namedFlow->name().string(), contentElementNodeId, nextContentElementNodeId);
558 }
559
560 void InspectorCSSAgent::didUnregisterNamedFlowContentElement(Document* document, WebKitNamedFlow* namedFlow, Node* contentElement)
561 {
562     int documentNodeId = documentNodeWithRequestedFlowsId(document);
563     if (!documentNodeId)
564         return;
565
566     ErrorString unused;
567     int contentElementNodeId = m_domAgent->pushNodeToFrontend(unused, 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
575 bool 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
603 void InspectorCSSAgent::getMatchedStylesForNode(ErrorString& errorString, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>>& matchedCSSRules, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::PseudoIdMatches>>& pseudoIdMatches, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::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::Protocol::Array<Inspector::Protocol::CSS::PseudoIdMatches>> pseudoElements = Inspector::Protocol::Array<Inspector::Protocol::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::Protocol::CSS::PseudoIdMatches> matches = Inspector::Protocol::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::Protocol::Array<Inspector::Protocol::CSS::InheritedStyleEntry>> entries = Inspector::Protocol::Array<Inspector::Protocol::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::Protocol::CSS::InheritedStyleEntry> entry = Inspector::Protocol::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
653 void InspectorCSSAgent::getInlineStylesForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::CSS::CSSStyle>& inlineStyle, RefPtr<Inspector::Protocol::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::Protocol::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
665     attributesStyle = attributes ? attributes.release() : nullptr;
666 }
667
668 void InspectorCSSAgent::getComputedStyleForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::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
679 void InspectorCSSAgent::getAllStyleSheets(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSStyleSheetHeader>>& styleInfos)
680 {
681     styleInfos = Inspector::Protocol::Array<Inspector::Protocol::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(&toCSSStyleSheet(styleSheet), styleInfos.get());
689         }
690     }
691 }
692
693 void InspectorCSSAgent::getStyleSheet(ErrorString& errorString, const String& styleSheetId, RefPtr<Inspector::Protocol::CSS::CSSStyleSheetBody>& styleSheetObject)
694 {
695     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
696     if (!inspectorStyleSheet)
697         return;
698
699     styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
700 }
701
702 void 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
711 void 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
722 void InspectorCSSAgent::setStyleText(ErrorString& errorString, const RefPtr<InspectorObject>& fullStyleId, const String& text, RefPtr<Inspector::Protocol::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
738 void InspectorCSSAgent::setPropertyText(ErrorString& errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<Inspector::Protocol::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
754 void InspectorCSSAgent::toggleProperty(ErrorString& errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<Inspector::Protocol::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
770 void InspectorCSSAgent::setRuleSelector(ErrorString& errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<Inspector::Protocol::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
787 void InspectorCSSAgent::addRule(ErrorString& errorString, const int contextNodeId, const String& selector, RefPtr<Inspector::Protocol::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 = ASCIILiteral("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
813 void InspectorCSSAgent::getSupportedCSSProperties(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSPropertyInfo>>& cssProperties)
814 {
815     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSPropertyInfo>> properties = Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSPropertyInfo>::create();
816     for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
817         CSSPropertyID id = convertToCSSPropertyID(i);
818         RefPtr<Inspector::Protocol::CSS::CSSPropertyInfo> property = Inspector::Protocol::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::Protocol::Array<String>> longhands = Inspector::Protocol::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
837 void 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
857 void InspectorCSSAgent::getNamedFlowCollection(ErrorString& errorString, int documentNodeId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::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::Protocol::Array<Inspector::Protocol::CSS::NamedFlow>> namedFlows = Inspector::Protocol::Array<Inspector::Protocol::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
874 InspectorStyleSheetForInlineStyle* 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::Protocol::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
892 Element* InspectorCSSAgent::elementForId(ErrorString& errorString, int nodeId)
893 {
894     Node* node = m_domAgent->nodeForId(nodeId);
895     if (!node) {
896         errorString = ASCIILiteral("No node with given id found");
897         return nullptr;
898     }
899     if (!is<Element>(*node)) {
900         errorString = ASCIILiteral("Not an element node");
901         return nullptr;
902     }
903     return downcast<Element>(node);
904 }
905
906 int 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
915 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSStyleSheetHeader>* result)
916 {
917     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(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 = toCSSImportRule(rule)->styleSheet();
923             if (importedStyleSheet)
924                 collectStyleSheets(importedStyleSheet, result);
925         }
926     }
927 }
928
929 InspectorStyleSheet* 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
942 InspectorStyleSheet* 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 = downcast<HTMLStyleElement>(*styleElement).sheet();
979     else if (styleElement->isSVGElement())
980         cssStyleSheet = downcast<SVGStyleElement>(*styleElement).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::Protocol::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
993 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString& errorString, const String& styleSheetId)
994 {
995     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
996     if (it == m_idToInspectorStyleSheet.end()) {
997         errorString = ASCIILiteral("No style sheet with given id found");
998         return nullptr;
999     }
1000     return it->value.get();
1001 }
1002
1003 Inspector::Protocol::CSS::StyleSheetOrigin InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
1004 {
1005     Inspector::Protocol::CSS::StyleSheetOrigin origin = Inspector::Protocol::CSS::StyleSheetOrigin::Regular;
1006     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
1007         origin = Inspector::Protocol::CSS::StyleSheetOrigin::UserAgent;
1008     else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
1009         origin = Inspector::Protocol::CSS::StyleSheetOrigin::User;
1010     else {
1011         InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
1012         if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
1013             origin = Inspector::Protocol::CSS::StyleSheetOrigin::Inspector;
1014     }
1015     return origin;
1016 }
1017
1018 PassRefPtr<Inspector::Protocol::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
1032 PassRefPtr<Inspector::Protocol::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
1042 PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSRule>> InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
1043 {
1044     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSRule>> result = Inspector::Protocol::Array<Inspector::Protocol::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::Protocol::CSS::CSSRule> ruleObject = buildObjectForRule(rule);
1051         if (!ruleObject)
1052             continue;
1053         result->addItem(ruleObject);
1054     }
1055     return result.release();
1056 }
1057
1058 PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>& matchedRules, StyleResolver& styleResolver, Element* element)
1059 {
1060     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> result = Inspector::Protocol::Array<Inspector::Protocol::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::Protocol::CSS::CSSRule> ruleObject = buildObjectForRule(matchedStyleRule, styleResolver);
1067         if (!ruleObject)
1068             continue;
1069         RefPtr<Inspector::Protocol::Array<int>> matchingSelectors = Inspector::Protocol::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::Protocol::CSS::RuleMatch> match = Inspector::Protocol::CSS::RuleMatch::create()
1079             .setRule(ruleObject)
1080             .setMatchingSelectors(matchingSelectors);
1081         result->addItem(match);
1082     }
1083
1084     return result.release();
1085 }
1086
1087 PassRefPtr<Inspector::Protocol::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
1088 {
1089     ASSERT(element);
1090     if (!is<StyledElement>(*element))
1091         return nullptr;
1092
1093     // FIXME: Ugliness below.
1094     StyleProperties* attributeStyle = const_cast<StyleProperties*>(downcast<StyledElement>(element)->presentationAttributeStyle());
1095     if (!attributeStyle)
1096         return nullptr;
1097
1098     ASSERT_WITH_SECURITY_IMPLICATION(attributeStyle->isMutable());
1099     MutableStyleProperties* mutableAttributeStyle = static_cast<MutableStyleProperties*>(attributeStyle);
1100
1101     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), nullptr);
1102     return inspectorStyle->buildObjectForStyle();
1103 }
1104
1105 PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>> InspectorCSSAgent::buildArrayForRegions(ErrorString& errorString, PassRefPtr<NodeList> regionList, int documentNodeId)
1106 {
1107     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>> regions = Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>::create();
1108
1109     for (unsigned i = 0; i < regionList->length(); ++i) {
1110         Inspector::Protocol::CSS::Region::RegionOverset regionOverset;
1111
1112         switch (downcast<Element>(regionList->item(i))->regionOversetState()) {
1113         case RegionFit:
1114             regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Fit;
1115             break;
1116         case RegionEmpty:
1117             regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Empty;
1118             break;
1119         case RegionOverset:
1120             regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Overset;
1121             break;
1122         case RegionUndefined:
1123             continue;
1124         default:
1125             ASSERT_NOT_REACHED();
1126             continue;
1127         }
1128
1129         RefPtr<Inspector::Protocol::CSS::Region> region = Inspector::Protocol::CSS::Region::create()
1130             .setRegionOverset(regionOverset)
1131             // documentNodeId was previously asserted
1132             .setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i)));
1133
1134         regions->addItem(region);
1135     }
1136
1137     return regions.release();
1138 }
1139
1140 PassRefPtr<Inspector::Protocol::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString& errorString, WebKitNamedFlow* webkitNamedFlow, int documentNodeId)
1141 {
1142     RefPtr<NodeList> contentList = webkitNamedFlow->getContent();
1143     RefPtr<Inspector::Protocol::Array<int>> content = Inspector::Protocol::Array<int>::create();
1144
1145     for (unsigned i = 0; i < contentList->length(); ++i) {
1146         // documentNodeId was previously asserted
1147         content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i)));
1148     }
1149
1150     RefPtr<Inspector::Protocol::CSS::NamedFlow> namedFlow = Inspector::Protocol::CSS::NamedFlow::create()
1151         .setDocumentNodeId(documentNodeId)
1152         .setName(webkitNamedFlow->name().string())
1153         .setOverset(webkitNamedFlow->overset())
1154         .setContent(content)
1155         .setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId));
1156
1157     return namedFlow.release();
1158 }
1159
1160 void InspectorCSSAgent::didRemoveDocument(Document* document)
1161 {
1162     if (document)
1163         m_documentToInspectorStyleSheet.remove(document);
1164 }
1165
1166 void InspectorCSSAgent::didRemoveDOMNode(Node* node)
1167 {
1168     if (!node)
1169         return;
1170
1171     int nodeId = m_domAgent->boundNodeId(node);
1172     if (nodeId)
1173         m_nodeIdToForcedPseudoState.remove(nodeId);
1174
1175     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
1176     if (it == m_nodeToInspectorStyleSheet.end())
1177         return;
1178
1179     m_idToInspectorStyleSheet.remove(it->value->id());
1180     m_nodeToInspectorStyleSheet.remove(node);
1181 }
1182
1183 void InspectorCSSAgent::didModifyDOMAttr(Element* element)
1184 {
1185     if (!element)
1186         return;
1187
1188     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1189     if (it == m_nodeToInspectorStyleSheet.end())
1190         return;
1191
1192     it->value->didModifyElementAttribute();
1193 }
1194
1195 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1196 {
1197     if (m_frontendDispatcher)
1198         m_frontendDispatcher->styleSheetChanged(styleSheet->id());
1199 }
1200
1201 void InspectorCSSAgent::resetPseudoStates()
1202 {
1203     HashSet<Document*> documentsToChange;
1204     for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) {
1205         if (Element* element = downcast<Element>(m_domAgent->nodeForId(it->key)))
1206             documentsToChange.add(&element->document());
1207     }
1208
1209     m_nodeIdToForcedPseudoState.clear();
1210     for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
1211         (*it)->styleResolverChanged(RecalcStyleImmediately);
1212 }
1213
1214 } // namespace WebCore
1215
1216 #endif // ENABLE(INSPECTOR)