3d54221c5dc893cdd9571dc3f3b1fe687bb08633
[WebKit-https.git] / Source / WebCore / inspector / InspectorCSSAgent.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2015 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(ASCIILiteral("active"));
81     static NeverDestroyed<String> hover(ASCIILiteral("hover"));
82     static NeverDestroyed<String> focus(ASCIILiteral("focus"));
83     static NeverDestroyed<String> visited(ASCIILiteral("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);
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 }
414
415 void InspectorCSSAgent::mediaQueryResultChanged()
416 {
417     m_frontendDispatcher->mediaQueryResultChanged();
418 }
419
420 void InspectorCSSAgent::activeStyleSheetsUpdated(Document& document)
421 {
422     Vector<CSSStyleSheet*> cssStyleSheets;
423     collectAllDocumentStyleSheets(document, cssStyleSheets);
424
425     setActiveStyleSheetsForDocument(document, cssStyleSheets);
426 }
427
428 void InspectorCSSAgent::setActiveStyleSheetsForDocument(Document& document, Vector<CSSStyleSheet*>& activeStyleSheets)
429 {
430     HashSet<CSSStyleSheet*>& previouslyKnownActiveStyleSheets = m_documentToKnownCSSStyleSheets.add(&document, HashSet<CSSStyleSheet*>()).iterator->value;
431
432     HashSet<CSSStyleSheet*> removedStyleSheets(previouslyKnownActiveStyleSheets);
433     Vector<CSSStyleSheet*> addedStyleSheets;
434     for (auto& activeStyleSheet : activeStyleSheets) {
435         if (removedStyleSheets.contains(activeStyleSheet))
436             removedStyleSheets.remove(activeStyleSheet);
437         else
438             addedStyleSheets.append(activeStyleSheet);
439     }
440
441     for (auto* cssStyleSheet : removedStyleSheets) {
442         previouslyKnownActiveStyleSheets.remove(cssStyleSheet);
443         RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(cssStyleSheet);
444         if (m_idToInspectorStyleSheet.contains(inspectorStyleSheet->id())) {
445             String id = unbindStyleSheet(inspectorStyleSheet.get());
446             m_frontendDispatcher->styleSheetRemoved(id);
447         }
448     }
449
450     for (auto* cssStyleSheet : addedStyleSheets) {
451         previouslyKnownActiveStyleSheets.add(cssStyleSheet);
452         if (!m_cssStyleSheetToInspectorStyleSheet.contains(cssStyleSheet)) {
453             InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssStyleSheet);
454             m_frontendDispatcher->styleSheetAdded(inspectorStyleSheet->buildObjectForStyleSheetInfo());
455         }
456     }
457 }
458
459 void InspectorCSSAgent::didCreateNamedFlow(Document& document, WebKitNamedFlow& namedFlow)
460 {
461     int documentNodeId = documentNodeWithRequestedFlowsId(&document);
462     if (!documentNodeId)
463         return;
464
465     ErrorString unused;
466     m_frontendDispatcher->namedFlowCreated(buildObjectForNamedFlow(unused, &namedFlow, documentNodeId));
467 }
468
469 void InspectorCSSAgent::willRemoveNamedFlow(Document& document, WebKitNamedFlow& namedFlow)
470 {
471     int documentNodeId = documentNodeWithRequestedFlowsId(&document);
472     if (!documentNodeId)
473         return;
474
475     if (m_changeRegionOversetTask)
476         m_changeRegionOversetTask->unschedule(&namedFlow);
477
478     m_frontendDispatcher->namedFlowRemoved(documentNodeId, namedFlow.name().string());
479 }
480
481 void InspectorCSSAgent::didChangeRegionOverset(Document& document, WebKitNamedFlow& namedFlow)
482 {
483     int documentNodeId = documentNodeWithRequestedFlowsId(&document);
484     if (!documentNodeId)
485         return;
486
487     if (!m_changeRegionOversetTask)
488         m_changeRegionOversetTask = std::make_unique<ChangeRegionOversetTask>(this);
489     m_changeRegionOversetTask->scheduleFor(&namedFlow, documentNodeId);
490 }
491
492 void InspectorCSSAgent::regionOversetChanged(WebKitNamedFlow* namedFlow, int documentNodeId)
493 {
494     if (namedFlow->flowState() == WebKitNamedFlow::FlowStateNull)
495         return;
496
497     ErrorString unused;
498     Ref<WebKitNamedFlow> protect(*namedFlow);
499
500     m_frontendDispatcher->regionOversetChanged(buildObjectForNamedFlow(unused, namedFlow, documentNodeId));
501 }
502
503 void InspectorCSSAgent::didRegisterNamedFlowContentElement(Document& document, WebKitNamedFlow& namedFlow, Node& contentElement, Node* nextContentElement)
504 {
505     int documentNodeId = documentNodeWithRequestedFlowsId(&document);
506     if (!documentNodeId)
507         return;
508
509     ErrorString unused;
510     int contentElementNodeId = m_domAgent->pushNodeToFrontend(unused, documentNodeId, &contentElement);
511     int nextContentElementNodeId = nextContentElement ? m_domAgent->pushNodeToFrontend(unused, documentNodeId, nextContentElement) : 0;
512     m_frontendDispatcher->registeredNamedFlowContentElement(documentNodeId, namedFlow.name().string(), contentElementNodeId, nextContentElementNodeId);
513 }
514
515 void InspectorCSSAgent::didUnregisterNamedFlowContentElement(Document& document, WebKitNamedFlow& namedFlow, Node& contentElement)
516 {
517     int documentNodeId = documentNodeWithRequestedFlowsId(&document);
518     if (!documentNodeId)
519         return;
520
521     ErrorString unused;
522     int contentElementNodeId = m_domAgent->pushNodeToFrontend(unused, documentNodeId, &contentElement);
523     if (!contentElementNodeId) {
524         // We've already notified that the DOM node was removed from the DOM, so there's no need to send another event.
525         return;
526     }
527     m_frontendDispatcher->unregisteredNamedFlowContentElement(documentNodeId, namedFlow.name().string(), contentElementNodeId);
528 }
529
530 bool InspectorCSSAgent::forcePseudoState(const Element& element, CSSSelector::PseudoClassType pseudoClassType)
531 {
532     if (m_nodeIdToForcedPseudoState.isEmpty())
533         return false;
534
535     int nodeId = m_domAgent->boundNodeId(&element);
536     if (!nodeId)
537         return false;
538
539     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
540     if (it == m_nodeIdToForcedPseudoState.end())
541         return false;
542
543     unsigned forcedPseudoState = it->value;
544     switch (pseudoClassType) {
545     case CSSSelector::PseudoClassActive:
546         return forcedPseudoState & PseudoClassActive;
547     case CSSSelector::PseudoClassFocus:
548         return forcedPseudoState & PseudoClassFocus;
549     case CSSSelector::PseudoClassHover:
550         return forcedPseudoState & PseudoClassHover;
551     case CSSSelector::PseudoClassVisited:
552         return forcedPseudoState & PseudoClassVisited;
553     default:
554         return false;
555     }
556 }
557
558 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)
559 {
560     Element* element = elementForId(errorString, nodeId);
561     if (!element)
562         return;
563
564     Element* originalElement = element;
565     PseudoId elementPseudoId = element->pseudoId();
566     if (elementPseudoId) {
567         element = downcast<PseudoElement>(*element).hostElement();
568         if (!element) {
569             errorString = ASCIILiteral("Pseudo element has no parent");
570             return;
571         }
572     }
573
574     // Matched rules.
575     StyleResolver& styleResolver = element->styleResolver();
576     auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, elementPseudoId, StyleResolver::AllCSSRules);
577     matchedCSSRules = buildArrayForMatchedRuleList(matchedRules, styleResolver, *element, elementPseudoId);
578
579     if (!originalElement->isPseudoElement()) {
580         // Pseudo elements.
581         if (!includePseudo || *includePseudo) {
582             auto pseudoElements = Inspector::Protocol::Array<Inspector::Protocol::CSS::PseudoIdMatches>::create();
583             for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
584                 auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
585                 if (!matchedRules.isEmpty()) {
586                     auto matches = Inspector::Protocol::CSS::PseudoIdMatches::create()
587                         .setPseudoId(static_cast<int>(pseudoId))
588                         .setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, *element, pseudoId))
589                         .release();
590                     pseudoElements->addItem(WTFMove(matches));
591                 }
592             }
593
594             pseudoIdMatches = WTFMove(pseudoElements);
595         }
596
597         // Inherited styles.
598         if (!includeInherited || *includeInherited) {
599             auto entries = Inspector::Protocol::Array<Inspector::Protocol::CSS::InheritedStyleEntry>::create();
600             Element* parentElement = element->parentElement();
601             while (parentElement) {
602                 StyleResolver& parentStyleResolver = parentElement->styleResolver();
603                 auto parentMatchedRules = parentStyleResolver.styleRulesForElement(parentElement, StyleResolver::AllCSSRules);
604                 auto entry = Inspector::Protocol::CSS::InheritedStyleEntry::create()
605                     .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules, styleResolver, *parentElement, NOPSEUDO))
606                     .release();
607                 if (parentElement->cssomStyle() && parentElement->cssomStyle()->length()) {
608                     if (InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement))
609                         entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
610                 }
611
612                 entries->addItem(WTFMove(entry));
613                 parentElement = parentElement->parentElement();
614             }
615
616             inheritedEntries = WTFMove(entries);
617         }
618     }
619 }
620
621 void InspectorCSSAgent::getInlineStylesForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::CSS::CSSStyle>& inlineStyle, RefPtr<Inspector::Protocol::CSS::CSSStyle>& attributesStyle)
622 {
623     Element* element = elementForId(errorString, nodeId);
624     if (!element)
625         return;
626
627     InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
628     if (!styleSheet)
629         return;
630
631     inlineStyle = styleSheet->buildObjectForStyle(element->cssomStyle());
632     if (auto attributes = buildObjectForAttributesStyle(element))
633         attributesStyle = WTFMove(attributes);
634     else
635         attributesStyle = nullptr;
636 }
637
638 void InspectorCSSAgent::getComputedStyleForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSComputedStyleProperty>>& style)
639 {
640     Element* element = elementForId(errorString, nodeId);
641     if (!element)
642         return;
643
644     RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(*element, true);
645     Ref<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, nullptr);
646     style = inspectorStyle->buildArrayForComputedStyle();
647 }
648
649 void InspectorCSSAgent::getAllStyleSheets(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSStyleSheetHeader>>& styleInfos)
650 {
651     styleInfos = Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSStyleSheetHeader>::create();
652
653     Vector<InspectorStyleSheet*> inspectorStyleSheets;
654     collectAllStyleSheets(inspectorStyleSheets);
655     for (auto* inspectorStyleSheet : inspectorStyleSheets)
656         styleInfos->addItem(inspectorStyleSheet->buildObjectForStyleSheetInfo());
657 }
658
659 void InspectorCSSAgent::collectAllStyleSheets(Vector<InspectorStyleSheet*>& result)
660 {
661     Vector<CSSStyleSheet*> cssStyleSheets;
662     for (auto* document : m_domAgent->documents())
663         collectAllDocumentStyleSheets(*document, cssStyleSheets);
664
665     for (auto* cssStyleSheet : cssStyleSheets)
666         result.append(bindStyleSheet(cssStyleSheet));
667 }
668
669 void InspectorCSSAgent::collectAllDocumentStyleSheets(Document& document, Vector<CSSStyleSheet*>& result)
670 {
671     auto cssStyleSheets = document.styleScope().activeStyleSheetsForInspector();
672     for (auto& cssStyleSheet : cssStyleSheets)
673         collectStyleSheets(cssStyleSheet.get(), result);
674 }
675
676 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Vector<CSSStyleSheet*>& result)
677 {
678     result.append(styleSheet);
679
680     for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
681         CSSRule* rule = styleSheet->item(i);
682         if (is<CSSImportRule>(*rule)) {
683             if (CSSStyleSheet* importedStyleSheet = downcast<CSSImportRule>(*rule).styleSheet())
684                 collectStyleSheets(importedStyleSheet, result);
685         }
686     }
687 }
688
689 void InspectorCSSAgent::getStyleSheet(ErrorString& errorString, const String& styleSheetId, RefPtr<Inspector::Protocol::CSS::CSSStyleSheetBody>& styleSheetObject)
690 {
691     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
692     if (!inspectorStyleSheet)
693         return;
694
695     styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
696 }
697
698 void InspectorCSSAgent::getStyleSheetText(ErrorString& errorString, const String& styleSheetId, String* result)
699 {
700     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
701     if (!inspectorStyleSheet)
702         return;
703
704     auto text = inspectorStyleSheet->text();
705     if (!text.hasException())
706         *result = text.releaseReturnValue();
707 }
708
709 void InspectorCSSAgent::setStyleSheetText(ErrorString& errorString, const String& styleSheetId, const String& text)
710 {
711     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
712     if (!inspectorStyleSheet)
713         return;
714
715     auto result = m_domAgent->history()->perform(std::make_unique<SetStyleSheetTextAction>(inspectorStyleSheet, text));
716     if (result.hasException())
717         errorString = InspectorDOMAgent::toErrorString(result.releaseException());
718 }
719
720 void InspectorCSSAgent::setStyleText(ErrorString& errorString, const InspectorObject& fullStyleId, const String& text, RefPtr<Inspector::Protocol::CSS::CSSStyle>& result)
721 {
722     InspectorCSSId compoundId(fullStyleId);
723     ASSERT(!compoundId.isEmpty());
724
725     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
726     if (!inspectorStyleSheet)
727         return;
728
729     auto performResult = m_domAgent->history()->perform(std::make_unique<SetStyleTextAction>(inspectorStyleSheet, compoundId, text));
730     if (performResult.hasException()) {
731         errorString = InspectorDOMAgent::toErrorString(performResult.releaseException());
732         return;
733     }
734
735     result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
736 }
737
738 void InspectorCSSAgent::setRuleSelector(ErrorString& errorString, const InspectorObject& fullRuleId, const String& selector, RefPtr<Inspector::Protocol::CSS::CSSRule>& result)
739 {
740     InspectorCSSId compoundId(fullRuleId);
741     ASSERT(!compoundId.isEmpty());
742
743     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
744     if (!inspectorStyleSheet)
745         return;
746
747     auto performResult = m_domAgent->history()->perform(std::make_unique<SetRuleSelectorAction>(inspectorStyleSheet, compoundId, selector));
748     if (performResult.hasException()) {
749         errorString = InspectorDOMAgent::toErrorString(performResult.releaseException());
750         return;
751     }
752
753     result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId), nullptr);
754 }
755
756 void InspectorCSSAgent::createStyleSheet(ErrorString& errorString, const String& frameId, String* styleSheetId)
757 {
758     Frame* frame = m_domAgent->pageAgent()->frameForId(frameId);
759     if (!frame) {
760         errorString = ASCIILiteral("No frame for given id found");
761         return;
762     }
763
764     Document* document = frame->document();
765     if (!document) {
766         errorString = ASCIILiteral("No document for frame");
767         return;
768     }
769
770     InspectorStyleSheet* inspectorStyleSheet = createInspectorStyleSheetForDocument(*document);
771     if (!inspectorStyleSheet) {
772         errorString = ASCIILiteral("Could not create stylesheet for the frame.");
773         return;
774     }
775
776     *styleSheetId = inspectorStyleSheet->id();
777 }
778
779 InspectorStyleSheet* InspectorCSSAgent::createInspectorStyleSheetForDocument(Document& document)
780 {
781     if (!document.isHTMLDocument() && !document.isSVGDocument())
782         return nullptr;
783
784     auto styleElement = HTMLStyleElement::create(document);
785     styleElement->setAttributeWithoutSynchronization(HTMLNames::typeAttr, AtomicString("text/css", AtomicString::ConstructFromLiteral));
786
787     ContainerNode* targetNode;
788     // HEAD is absent in ImageDocuments, for example.
789     if (auto* head = document.head())
790         targetNode = head;
791     else if (auto* body = document.bodyOrFrameset())
792         targetNode = body;
793     else
794         return nullptr;
795
796     // Inserting this <style> into the document will trigger activeStyleSheetsUpdated
797     // and we will create an InspectorStyleSheet for this <style>'s CSSStyleSheet.
798     // Set this flag, so when we create it, we put it into the via inspector map.
799     m_creatingViaInspectorStyleSheet = true;
800     InlineStyleOverrideScope overrideScope(document);
801     auto appendResult = targetNode->appendChild(styleElement);
802     document.styleScope().flushPendingUpdate();
803     m_creatingViaInspectorStyleSheet = false;
804     if (appendResult.hasException())
805         return nullptr;
806
807     auto iterator = m_documentToInspectorStyleSheet.find(&document);
808     ASSERT(iterator != m_documentToInspectorStyleSheet.end());
809     if (iterator == m_documentToInspectorStyleSheet.end())
810         return nullptr;
811
812     auto& inspectorStyleSheetsForDocument = iterator->value;
813     ASSERT(!inspectorStyleSheetsForDocument.isEmpty());
814     if (inspectorStyleSheetsForDocument.isEmpty())
815         return nullptr;
816
817     return inspectorStyleSheetsForDocument.last().get();
818 }
819
820 void InspectorCSSAgent::addRule(ErrorString& errorString, const String& styleSheetId, const String& selector, RefPtr<Inspector::Protocol::CSS::CSSRule>& result)
821 {
822     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
823     if (!inspectorStyleSheet) {
824         errorString = ASCIILiteral("No target stylesheet found");
825         return;
826     }
827
828     auto action = std::make_unique<AddRuleAction>(inspectorStyleSheet, selector);
829     auto& rawAction = *action;
830     auto performResult = m_domAgent->history()->perform(WTFMove(action));
831     if (performResult.hasException()) {
832         errorString = InspectorDOMAgent::toErrorString(performResult.releaseException());
833         return;
834     }
835
836     InspectorCSSId ruleId = rawAction.newRuleId();
837     CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
838     result = inspectorStyleSheet->buildObjectForRule(rule, nullptr);
839 }
840
841 void InspectorCSSAgent::getSupportedCSSProperties(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSPropertyInfo>>& cssProperties)
842 {
843     auto properties = Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSPropertyInfo>::create();
844     for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
845         CSSPropertyID id = convertToCSSPropertyID(i);
846         auto property = Inspector::Protocol::CSS::CSSPropertyInfo::create()
847             .setName(getPropertyNameString(id))
848             .release();
849
850         const StylePropertyShorthand& shorthand = shorthandForProperty(id);
851         if (!shorthand.length()) {
852             properties->addItem(WTFMove(property));
853             continue;
854         }
855         auto longhands = Inspector::Protocol::Array<String>::create();
856         for (unsigned j = 0; j < shorthand.length(); ++j) {
857             CSSPropertyID longhandID = shorthand.properties()[j];
858             longhands->addItem(getPropertyNameString(longhandID));
859         }
860         property->setLonghands(WTFMove(longhands));
861         properties->addItem(WTFMove(property));
862     }
863     cssProperties = WTFMove(properties);
864 }
865
866 void InspectorCSSAgent::getSupportedSystemFontFamilyNames(ErrorString&, RefPtr<Inspector::Protocol::Array<String>>& fontFamilyNames)
867 {
868     auto families = Inspector::Protocol::Array<String>::create();
869
870     Vector<String> systemFontFamilies = FontCache::singleton().systemFontFamilies();
871     for (const auto& familyName : systemFontFamilies)
872         families->addItem(familyName);
873
874     fontFamilyNames = WTFMove(families);
875 }
876
877 void InspectorCSSAgent::forcePseudoState(ErrorString& errorString, int nodeId, const InspectorArray& forcedPseudoClasses)
878 {
879     Element* element = m_domAgent->assertElement(errorString, nodeId);
880     if (!element)
881         return;
882
883     unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses);
884     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
885     unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value;
886     bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState;
887     if (!needStyleRecalc)
888         return;
889
890     if (forcedPseudoState)
891         m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
892     else
893         m_nodeIdToForcedPseudoState.remove(nodeId);
894     element->document().styleScope().didChangeStyleSheetEnvironment();
895 }
896
897 void InspectorCSSAgent::getNamedFlowCollection(ErrorString& errorString, int documentNodeId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::NamedFlow>>& result)
898 {
899     Document* document = m_domAgent->assertDocument(errorString, documentNodeId);
900     if (!document)
901         return;
902
903     m_namedFlowCollectionsRequested.add(documentNodeId);
904
905     Vector<RefPtr<WebKitNamedFlow>> namedFlowsVector = document->namedFlows().namedFlows();
906     auto namedFlows = Inspector::Protocol::Array<Inspector::Protocol::CSS::NamedFlow>::create();
907
908     for (auto& namedFlow : namedFlowsVector)
909         namedFlows->addItem(buildObjectForNamedFlow(errorString, namedFlow.get(), documentNodeId));
910
911     result = WTFMove(namedFlows);
912 }
913
914 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
915 {
916     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
917     if (it == m_nodeToInspectorStyleSheet.end()) {
918         CSSStyleDeclaration* style = element->cssomStyle();
919         if (!style)
920             return nullptr;
921
922         String newStyleSheetId = String::number(m_lastStyleSheetId++);
923         RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_domAgent->pageAgent(), newStyleSheetId, element, Inspector::Protocol::CSS::StyleSheetOrigin::Regular, this);
924         m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
925         m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
926         return inspectorStyleSheet.get();
927     }
928
929     return it->value.get();
930 }
931
932 Element* InspectorCSSAgent::elementForId(ErrorString& errorString, int nodeId)
933 {
934     Node* node = m_domAgent->nodeForId(nodeId);
935     if (!node) {
936         errorString = ASCIILiteral("No node with given id found");
937         return nullptr;
938     }
939     if (!is<Element>(*node)) {
940         errorString = ASCIILiteral("Not an element node");
941         return nullptr;
942     }
943     return downcast<Element>(node);
944 }
945
946 int InspectorCSSAgent::documentNodeWithRequestedFlowsId(Document* document)
947 {
948     int documentNodeId = m_domAgent->boundNodeId(document);
949     if (!documentNodeId || !m_namedFlowCollectionsRequested.contains(documentNodeId))
950         return 0;
951
952     return documentNodeId;
953 }
954
955 String InspectorCSSAgent::unbindStyleSheet(InspectorStyleSheet* inspectorStyleSheet)
956 {
957     String id = inspectorStyleSheet->id();
958     m_idToInspectorStyleSheet.remove(id);
959     if (inspectorStyleSheet->pageStyleSheet())
960         m_cssStyleSheetToInspectorStyleSheet.remove(inspectorStyleSheet->pageStyleSheet());
961     return id;
962 }
963
964 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
965 {
966     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
967     if (!inspectorStyleSheet) {
968         String id = String::number(m_lastStyleSheetId++);
969         Document* document = styleSheet->ownerDocument();
970         inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
971         m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
972         m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
973         if (m_creatingViaInspectorStyleSheet) {
974             auto& inspectorStyleSheetsForDocument = m_documentToInspectorStyleSheet.add(document, Vector<RefPtr<InspectorStyleSheet>>()).iterator->value;
975             inspectorStyleSheetsForDocument.append(inspectorStyleSheet);
976         }
977     }
978     return inspectorStyleSheet.get();
979 }
980
981 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString& errorString, const String& styleSheetId)
982 {
983     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
984     if (it == m_idToInspectorStyleSheet.end()) {
985         errorString = ASCIILiteral("No stylesheet with given id found");
986         return nullptr;
987     }
988     return it->value.get();
989 }
990
991 Inspector::Protocol::CSS::StyleSheetOrigin InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
992 {
993     if (m_creatingViaInspectorStyleSheet)
994         return Inspector::Protocol::CSS::StyleSheetOrigin::Inspector;
995
996     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
997         return Inspector::Protocol::CSS::StyleSheetOrigin::UserAgent;
998
999     if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
1000         return Inspector::Protocol::CSS::StyleSheetOrigin::User;
1001
1002     auto iterator = m_documentToInspectorStyleSheet.find(ownerDocument);
1003     if (iterator != m_documentToInspectorStyleSheet.end()) {
1004         for (auto& inspectorStyleSheet : iterator->value) {
1005             if (pageStyleSheet == inspectorStyleSheet->pageStyleSheet())
1006                 return Inspector::Protocol::CSS::StyleSheetOrigin::Inspector;
1007         }
1008     }
1009
1010     return Inspector::Protocol::CSS::StyleSheetOrigin::Regular;
1011 }
1012
1013 RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(StyleRule* styleRule, StyleResolver& styleResolver, Element& element)
1014 {
1015     if (!styleRule)
1016         return nullptr;
1017
1018     // StyleRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
1019     // Since the inspector wants to walk the parent chain, we construct the full wrappers here.
1020     styleResolver.inspectorCSSOMWrappers().collectDocumentWrappers(styleResolver.document().extensionStyleSheets());
1021     styleResolver.inspectorCSSOMWrappers().collectScopeWrappers(Style::Scope::forNode(element));
1022
1023     // Possiblity of :host styles if this element has a shadow root.
1024     if (ShadowRoot* shadowRoot = element.shadowRoot())
1025         styleResolver.inspectorCSSOMWrappers().collectScopeWrappers(shadowRoot->styleScope());
1026
1027     CSSStyleRule* cssomWrapper = styleResolver.inspectorCSSOMWrappers().getWrapperForRuleInSheets(styleRule);
1028     if (!cssomWrapper)
1029         return nullptr;
1030
1031     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssomWrapper->parentStyleSheet());
1032     return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(cssomWrapper, &element) : nullptr;
1033 }
1034
1035 RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule)
1036 {
1037     if (!rule)
1038         return nullptr;
1039
1040     ASSERT(rule->parentStyleSheet());
1041     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(rule->parentStyleSheet());
1042     return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(rule, nullptr) : nullptr;
1043 }
1044
1045 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>& matchedRules, StyleResolver& styleResolver, Element& element, PseudoId psuedoId)
1046 {
1047     auto result = Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>::create();
1048
1049     SelectorChecker::CheckingContext context(SelectorChecker::Mode::CollectingRules);
1050     context.pseudoId = psuedoId ? psuedoId : element.pseudoId();
1051     SelectorChecker selectorChecker(element.document());
1052
1053     for (auto& matchedRule : matchedRules) {
1054         RefPtr<Inspector::Protocol::CSS::CSSRule> ruleObject = buildObjectForRule(matchedRule.get(), styleResolver, element);
1055         if (!ruleObject)
1056             continue;
1057
1058         auto matchingSelectors = Inspector::Protocol::Array<int>::create();
1059         const CSSSelectorList& selectorList = matchedRule->selectorList();
1060         int index = 0;
1061         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
1062             unsigned ignoredSpecificity;
1063             bool matched = selectorChecker.match(*selector, element, context, ignoredSpecificity);
1064             if (matched)
1065                 matchingSelectors->addItem(index);
1066             ++index;
1067         }
1068
1069         auto match = Inspector::Protocol::CSS::RuleMatch::create()
1070             .setRule(WTFMove(ruleObject))
1071             .setMatchingSelectors(WTFMove(matchingSelectors))
1072             .release();
1073         result->addItem(WTFMove(match));
1074     }
1075
1076     return WTFMove(result);
1077 }
1078
1079 RefPtr<Inspector::Protocol::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
1080 {
1081     ASSERT(element);
1082     if (!is<StyledElement>(*element))
1083         return nullptr;
1084
1085     // FIXME: Ugliness below.
1086     StyleProperties* attributeStyle = const_cast<StyleProperties*>(downcast<StyledElement>(element)->presentationAttributeStyle());
1087     if (!attributeStyle)
1088         return nullptr;
1089
1090     ASSERT_WITH_SECURITY_IMPLICATION(attributeStyle->isMutable());
1091     MutableStyleProperties* mutableAttributeStyle = static_cast<MutableStyleProperties*>(attributeStyle);
1092
1093     Ref<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), nullptr);
1094     return inspectorStyle->buildObjectForStyle();
1095 }
1096
1097 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>> InspectorCSSAgent::buildArrayForRegions(ErrorString& errorString, RefPtr<NodeList>&& regionList, int documentNodeId)
1098 {
1099     auto regions = Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>::create();
1100
1101     for (unsigned i = 0; i < regionList->length(); ++i) {
1102         Inspector::Protocol::CSS::Region::RegionOverset regionOverset;
1103
1104         switch (downcast<Element>(regionList->item(i))->regionOversetState()) {
1105         case RegionFit:
1106             regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Fit;
1107             break;
1108         case RegionEmpty:
1109             regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Empty;
1110             break;
1111         case RegionOverset:
1112             regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Overset;
1113             break;
1114         case RegionUndefined:
1115             continue;
1116         default:
1117             ASSERT_NOT_REACHED();
1118             continue;
1119         }
1120
1121         auto region = Inspector::Protocol::CSS::Region::create()
1122             .setRegionOverset(regionOverset)
1123             // documentNodeId was previously asserted
1124             .setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i)))
1125             .release();
1126
1127         regions->addItem(WTFMove(region));
1128     }
1129
1130     return WTFMove(regions);
1131 }
1132
1133 RefPtr<Inspector::Protocol::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString& errorString, WebKitNamedFlow* webkitNamedFlow, int documentNodeId)
1134 {
1135     RefPtr<NodeList> contentList = webkitNamedFlow->getContent();
1136     auto content = Inspector::Protocol::Array<int>::create();
1137
1138     for (unsigned i = 0; i < contentList->length(); ++i) {
1139         // documentNodeId was previously asserted
1140         content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i)));
1141     }
1142
1143     return Inspector::Protocol::CSS::NamedFlow::create()
1144         .setDocumentNodeId(documentNodeId)
1145         .setName(webkitNamedFlow->name().string())
1146         .setOverset(webkitNamedFlow->overset())
1147         .setContent(WTFMove(content))
1148         .setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId))
1149         .release();
1150 }
1151
1152 void InspectorCSSAgent::didRemoveDocument(Document* document)
1153 {
1154     if (document)
1155         m_documentToInspectorStyleSheet.remove(document);
1156 }
1157
1158 void InspectorCSSAgent::didRemoveDOMNode(Node* node)
1159 {
1160     if (!node)
1161         return;
1162
1163     int nodeId = m_domAgent->boundNodeId(node);
1164     if (nodeId)
1165         m_nodeIdToForcedPseudoState.remove(nodeId);
1166
1167     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
1168     if (it == m_nodeToInspectorStyleSheet.end())
1169         return;
1170
1171     m_idToInspectorStyleSheet.remove(it->value->id());
1172     m_nodeToInspectorStyleSheet.remove(node);
1173 }
1174
1175 void InspectorCSSAgent::didModifyDOMAttr(Element* element)
1176 {
1177     if (!element)
1178         return;
1179
1180     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1181     if (it == m_nodeToInspectorStyleSheet.end())
1182         return;
1183
1184     it->value->didModifyElementAttribute();
1185 }
1186
1187 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1188 {
1189     m_frontendDispatcher->styleSheetChanged(styleSheet->id());
1190 }
1191
1192 void InspectorCSSAgent::resetPseudoStates()
1193 {
1194     HashSet<Document*> documentsToChange;
1195     for (auto& nodeId : m_nodeIdToForcedPseudoState) {
1196         if (Element* element = downcast<Element>(m_domAgent->nodeForId(nodeId.key)))
1197             documentsToChange.add(&element->document());
1198     }
1199
1200     m_nodeIdToForcedPseudoState.clear();
1201     for (auto& document : documentsToChange)
1202         document->styleScope().didChangeStyleSheetEnvironment();
1203 }
1204
1205 } // namespace WebCore