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