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