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