Web Inspector: forced pseudo classes aren't cleared from inspected page when Inspecto...
[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     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         auto property = Inspector::Protocol::CSS::CSSPropertyInfo::create()
849             .setName(getPropertyNameString(id))
850             .release();
851
852         const StylePropertyShorthand& shorthand = shorthandForProperty(id);
853         if (!shorthand.length()) {
854             properties->addItem(WTFMove(property));
855             continue;
856         }
857         auto longhands = Inspector::Protocol::Array<String>::create();
858         for (unsigned j = 0; j < shorthand.length(); ++j) {
859             CSSPropertyID longhandID = shorthand.properties()[j];
860             longhands->addItem(getPropertyNameString(longhandID));
861         }
862         property->setLonghands(WTFMove(longhands));
863         properties->addItem(WTFMove(property));
864     }
865     cssProperties = WTFMove(properties);
866 }
867
868 void InspectorCSSAgent::getSupportedSystemFontFamilyNames(ErrorString&, RefPtr<Inspector::Protocol::Array<String>>& fontFamilyNames)
869 {
870     auto families = Inspector::Protocol::Array<String>::create();
871
872     Vector<String> systemFontFamilies = FontCache::singleton().systemFontFamilies();
873     for (const auto& familyName : systemFontFamilies)
874         families->addItem(familyName);
875
876     fontFamilyNames = WTFMove(families);
877 }
878
879 void InspectorCSSAgent::forcePseudoState(ErrorString& errorString, int nodeId, const InspectorArray& forcedPseudoClasses)
880 {
881     Element* element = m_domAgent->assertElement(errorString, nodeId);
882     if (!element)
883         return;
884
885     auto it = m_nodeIdToForcedPseudoState.find(nodeId);
886     unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses);
887     unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value;
888     if (forcedPseudoState == currentForcedPseudoState)
889         return;
890
891     if (forcedPseudoState) {
892         m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
893         m_documentsWithForcedPseudoStates.add(&element->document());
894     } else {
895         m_nodeIdToForcedPseudoState.remove(nodeId);
896         if (m_nodeIdToForcedPseudoState.isEmpty())
897             m_documentsWithForcedPseudoStates.clear();
898     }
899
900     element->document().styleScope().didChangeStyleSheetEnvironment();
901 }
902
903 void InspectorCSSAgent::getNamedFlowCollection(ErrorString& errorString, int documentNodeId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::NamedFlow>>& result)
904 {
905     Document* document = m_domAgent->assertDocument(errorString, documentNodeId);
906     if (!document)
907         return;
908
909     m_namedFlowCollectionsRequested.add(documentNodeId);
910
911     Vector<RefPtr<WebKitNamedFlow>> namedFlowsVector = document->namedFlows().namedFlows();
912     auto namedFlows = Inspector::Protocol::Array<Inspector::Protocol::CSS::NamedFlow>::create();
913
914     for (auto& namedFlow : namedFlowsVector)
915         namedFlows->addItem(buildObjectForNamedFlow(errorString, namedFlow.get(), documentNodeId));
916
917     result = WTFMove(namedFlows);
918 }
919
920 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
921 {
922     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
923     if (it == m_nodeToInspectorStyleSheet.end()) {
924         CSSStyleDeclaration* style = element->cssomStyle();
925         if (!style)
926             return nullptr;
927
928         String newStyleSheetId = String::number(m_lastStyleSheetId++);
929         RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_domAgent->pageAgent(), newStyleSheetId, element, Inspector::Protocol::CSS::StyleSheetOrigin::Regular, this);
930         m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
931         m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
932         return inspectorStyleSheet.get();
933     }
934
935     return it->value.get();
936 }
937
938 Element* InspectorCSSAgent::elementForId(ErrorString& errorString, int nodeId)
939 {
940     Node* node = m_domAgent->nodeForId(nodeId);
941     if (!node) {
942         errorString = ASCIILiteral("No node with given id found");
943         return nullptr;
944     }
945     if (!is<Element>(*node)) {
946         errorString = ASCIILiteral("Not an element node");
947         return nullptr;
948     }
949     return downcast<Element>(node);
950 }
951
952 int InspectorCSSAgent::documentNodeWithRequestedFlowsId(Document* document)
953 {
954     int documentNodeId = m_domAgent->boundNodeId(document);
955     if (!documentNodeId || !m_namedFlowCollectionsRequested.contains(documentNodeId))
956         return 0;
957
958     return documentNodeId;
959 }
960
961 String InspectorCSSAgent::unbindStyleSheet(InspectorStyleSheet* inspectorStyleSheet)
962 {
963     String id = inspectorStyleSheet->id();
964     m_idToInspectorStyleSheet.remove(id);
965     if (inspectorStyleSheet->pageStyleSheet())
966         m_cssStyleSheetToInspectorStyleSheet.remove(inspectorStyleSheet->pageStyleSheet());
967     return id;
968 }
969
970 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
971 {
972     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
973     if (!inspectorStyleSheet) {
974         String id = String::number(m_lastStyleSheetId++);
975         Document* document = styleSheet->ownerDocument();
976         inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
977         m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
978         m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
979         if (m_creatingViaInspectorStyleSheet) {
980             auto& inspectorStyleSheetsForDocument = m_documentToInspectorStyleSheet.add(document, Vector<RefPtr<InspectorStyleSheet>>()).iterator->value;
981             inspectorStyleSheetsForDocument.append(inspectorStyleSheet);
982         }
983     }
984     return inspectorStyleSheet.get();
985 }
986
987 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString& errorString, const String& styleSheetId)
988 {
989     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
990     if (it == m_idToInspectorStyleSheet.end()) {
991         errorString = ASCIILiteral("No stylesheet with given id found");
992         return nullptr;
993     }
994     return it->value.get();
995 }
996
997 Inspector::Protocol::CSS::StyleSheetOrigin InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
998 {
999     if (m_creatingViaInspectorStyleSheet)
1000         return Inspector::Protocol::CSS::StyleSheetOrigin::Inspector;
1001
1002     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
1003         return Inspector::Protocol::CSS::StyleSheetOrigin::UserAgent;
1004
1005     if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
1006         return Inspector::Protocol::CSS::StyleSheetOrigin::User;
1007
1008     auto iterator = m_documentToInspectorStyleSheet.find(ownerDocument);
1009     if (iterator != m_documentToInspectorStyleSheet.end()) {
1010         for (auto& inspectorStyleSheet : iterator->value) {
1011             if (pageStyleSheet == inspectorStyleSheet->pageStyleSheet())
1012                 return Inspector::Protocol::CSS::StyleSheetOrigin::Inspector;
1013         }
1014     }
1015
1016     return Inspector::Protocol::CSS::StyleSheetOrigin::Regular;
1017 }
1018
1019 RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(StyleRule* styleRule, StyleResolver& styleResolver, Element& element)
1020 {
1021     if (!styleRule)
1022         return nullptr;
1023
1024     // StyleRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
1025     // Since the inspector wants to walk the parent chain, we construct the full wrappers here.
1026     styleResolver.inspectorCSSOMWrappers().collectDocumentWrappers(styleResolver.document().extensionStyleSheets());
1027     styleResolver.inspectorCSSOMWrappers().collectScopeWrappers(Style::Scope::forNode(element));
1028
1029     // Possiblity of :host styles if this element has a shadow root.
1030     if (ShadowRoot* shadowRoot = element.shadowRoot())
1031         styleResolver.inspectorCSSOMWrappers().collectScopeWrappers(shadowRoot->styleScope());
1032
1033     CSSStyleRule* cssomWrapper = styleResolver.inspectorCSSOMWrappers().getWrapperForRuleInSheets(styleRule);
1034     if (!cssomWrapper)
1035         return nullptr;
1036
1037     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssomWrapper->parentStyleSheet());
1038     return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(cssomWrapper, &element) : nullptr;
1039 }
1040
1041 RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule)
1042 {
1043     if (!rule)
1044         return nullptr;
1045
1046     ASSERT(rule->parentStyleSheet());
1047     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(rule->parentStyleSheet());
1048     return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(rule, nullptr) : nullptr;
1049 }
1050
1051 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>& matchedRules, StyleResolver& styleResolver, Element& element, PseudoId pseudoId)
1052 {
1053     auto result = Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>::create();
1054
1055     SelectorChecker::CheckingContext context(SelectorChecker::Mode::CollectingRules);
1056     context.pseudoId = pseudoId ? pseudoId : element.pseudoId();
1057     SelectorChecker selectorChecker(element.document());
1058
1059     for (auto& matchedRule : matchedRules) {
1060         RefPtr<Inspector::Protocol::CSS::CSSRule> ruleObject = buildObjectForRule(matchedRule.get(), styleResolver, element);
1061         if (!ruleObject)
1062             continue;
1063
1064         auto matchingSelectors = Inspector::Protocol::Array<int>::create();
1065         const CSSSelectorList& selectorList = matchedRule->selectorList();
1066         int index = 0;
1067         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
1068             unsigned ignoredSpecificity;
1069             bool matched = selectorChecker.match(*selector, element, context, ignoredSpecificity);
1070             if (matched)
1071                 matchingSelectors->addItem(index);
1072             ++index;
1073         }
1074
1075         auto match = Inspector::Protocol::CSS::RuleMatch::create()
1076             .setRule(WTFMove(ruleObject))
1077             .setMatchingSelectors(WTFMove(matchingSelectors))
1078             .release();
1079         result->addItem(WTFMove(match));
1080     }
1081
1082     return WTFMove(result);
1083 }
1084
1085 RefPtr<Inspector::Protocol::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
1086 {
1087     ASSERT(element);
1088     if (!is<StyledElement>(*element))
1089         return nullptr;
1090
1091     // FIXME: Ugliness below.
1092     StyleProperties* attributeStyle = const_cast<StyleProperties*>(downcast<StyledElement>(element)->presentationAttributeStyle());
1093     if (!attributeStyle)
1094         return nullptr;
1095
1096     ASSERT_WITH_SECURITY_IMPLICATION(attributeStyle->isMutable());
1097     MutableStyleProperties* mutableAttributeStyle = static_cast<MutableStyleProperties*>(attributeStyle);
1098
1099     Ref<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), nullptr);
1100     return inspectorStyle->buildObjectForStyle();
1101 }
1102
1103 RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>> InspectorCSSAgent::buildArrayForRegions(ErrorString& errorString, RefPtr<NodeList>&& regionList, int documentNodeId)
1104 {
1105     auto regions = Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>::create();
1106
1107     for (unsigned i = 0; i < regionList->length(); ++i) {
1108         Inspector::Protocol::CSS::Region::RegionOverset regionOverset;
1109
1110         switch (downcast<Element>(regionList->item(i))->regionOversetState()) {
1111         case RegionFit:
1112             regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Fit;
1113             break;
1114         case RegionEmpty:
1115             regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Empty;
1116             break;
1117         case RegionOverset:
1118             regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Overset;
1119             break;
1120         case RegionUndefined:
1121             continue;
1122         default:
1123             ASSERT_NOT_REACHED();
1124             continue;
1125         }
1126
1127         auto region = Inspector::Protocol::CSS::Region::create()
1128             .setRegionOverset(regionOverset)
1129             // documentNodeId was previously asserted
1130             .setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i)))
1131             .release();
1132
1133         regions->addItem(WTFMove(region));
1134     }
1135
1136     return WTFMove(regions);
1137 }
1138
1139 RefPtr<Inspector::Protocol::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString& errorString, WebKitNamedFlow* webkitNamedFlow, int documentNodeId)
1140 {
1141     RefPtr<NodeList> contentList = webkitNamedFlow->getContent();
1142     auto content = Inspector::Protocol::Array<int>::create();
1143
1144     for (unsigned i = 0; i < contentList->length(); ++i) {
1145         // documentNodeId was previously asserted
1146         content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i)));
1147     }
1148
1149     return Inspector::Protocol::CSS::NamedFlow::create()
1150         .setDocumentNodeId(documentNodeId)
1151         .setName(webkitNamedFlow->name().string())
1152         .setOverset(webkitNamedFlow->overset())
1153         .setContent(WTFMove(content))
1154         .setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId))
1155         .release();
1156 }
1157
1158 void InspectorCSSAgent::didRemoveDOMNode(Node& node, int nodeId)
1159 {
1160     m_nodeIdToForcedPseudoState.remove(nodeId);
1161
1162     auto it = m_nodeToInspectorStyleSheet.find(&node);
1163     if (it == m_nodeToInspectorStyleSheet.end())
1164         return;
1165
1166     m_idToInspectorStyleSheet.remove(it->value->id());
1167     m_nodeToInspectorStyleSheet.remove(&node);
1168 }
1169
1170 void InspectorCSSAgent::didModifyDOMAttr(Element& element)
1171 {
1172     auto it = m_nodeToInspectorStyleSheet.find(&element);
1173     if (it == m_nodeToInspectorStyleSheet.end())
1174         return;
1175
1176     it->value->didModifyElementAttribute();
1177 }
1178
1179 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1180 {
1181     m_frontendDispatcher->styleSheetChanged(styleSheet->id());
1182 }
1183
1184 void InspectorCSSAgent::resetPseudoStates()
1185 {
1186     for (auto& document : m_documentsWithForcedPseudoStates)
1187         document->styleScope().didChangeStyleSheetEnvironment();
1188
1189     m_nodeIdToForcedPseudoState.clear();
1190     m_documentsWithForcedPseudoStates.clear();
1191 }
1192
1193 } // namespace WebCore