Remove WebCore/ForwardingHeaders directory
[WebKit-https.git] / Source / WebCore / inspector / agents / InspectorCSSAgent.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "InspectorCSSAgent.h"
28
29 #include "CSSComputedStyleDeclaration.h"
30 #include "CSSImportRule.h"
31 #include "CSSPropertyNames.h"
32 #include "CSSPropertySourceData.h"
33 #include "CSSRule.h"
34 #include "CSSRuleList.h"
35 #include "CSSStyleRule.h"
36 #include "CSSStyleSheet.h"
37 #include "ContentSecurityPolicy.h"
38 #include "DOMWindow.h"
39 #include "FontCache.h"
40 #include "Frame.h"
41 #include "HTMLHeadElement.h"
42 #include "HTMLStyleElement.h"
43 #include "InspectorHistory.h"
44 #include "InspectorPageAgent.h"
45 #include "InstrumentingAgents.h"
46 #include "Node.h"
47 #include "NodeList.h"
48 #include "PseudoElement.h"
49 #include "SVGStyleElement.h"
50 #include "SelectorChecker.h"
51 #include "ShadowRoot.h"
52 #include "StyleProperties.h"
53 #include "StylePropertyShorthand.h"
54 #include "StyleResolver.h"
55 #include "StyleRule.h"
56 #include "StyleScope.h"
57 #include "StyleSheetList.h"
58 #include <JavaScriptCore/InspectorProtocolObjects.h>
59 #include <wtf/Ref.h>
60 #include <wtf/Vector.h>
61 #include <wtf/text/CString.h>
62 #include <wtf/text/StringConcatenate.h>
63
64
65 namespace WebCore {
66
67 using namespace Inspector;
68
69 enum ForcePseudoClassFlags {
70     PseudoClassNone = 0,
71     PseudoClassHover = 1 << 0,
72     PseudoClassFocus = 1 << 1,
73     PseudoClassActive = 1 << 2,
74     PseudoClassVisited = 1 << 3
75 };
76
77 static unsigned computePseudoClassMask(const JSON::Array& pseudoClassArray)
78 {
79     static NeverDestroyed<String> active(MAKE_STATIC_STRING_IMPL("active"));
80     static NeverDestroyed<String> hover(MAKE_STATIC_STRING_IMPL("hover"));
81     static NeverDestroyed<String> focus(MAKE_STATIC_STRING_IMPL("focus"));
82     static NeverDestroyed<String> visited(MAKE_STATIC_STRING_IMPL("visited"));
83     if (!pseudoClassArray.length())
84         return PseudoClassNone;
85
86     unsigned result = PseudoClassNone;
87     for (auto& pseudoClassValue : pseudoClassArray) {
88         String pseudoClass;
89         bool success = pseudoClassValue->asString(pseudoClass);
90         if (!success)
91             continue;
92         if (pseudoClass == active)
93             result |= PseudoClassActive;
94         else if (pseudoClass == hover)
95             result |= PseudoClassHover;
96         else if (pseudoClass == focus)
97             result |= PseudoClassFocus;
98         else if (pseudoClass == visited)
99             result |= PseudoClassVisited;
100     }
101
102     return result;
103 }
104
105 class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
106     WTF_MAKE_NONCOPYABLE(StyleSheetAction);
107 public:
108     StyleSheetAction(InspectorStyleSheet* styleSheet)
109         : InspectorHistory::Action()
110         , m_styleSheet(styleSheet)
111     {
112     }
113
114 protected:
115     RefPtr<InspectorStyleSheet> m_styleSheet;
116 };
117
118 class InspectorCSSAgent::SetStyleSheetTextAction final : public InspectorCSSAgent::StyleSheetAction {
119     WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
120 public:
121     SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
122         : InspectorCSSAgent::StyleSheetAction(styleSheet)
123         , m_text(text)
124     {
125     }
126
127 private:
128     ExceptionOr<void> perform() final
129     {
130         auto result = m_styleSheet->text();
131         if (result.hasException())
132             return result.releaseException();
133         m_oldText = result.releaseReturnValue();
134         return redo();
135     }
136
137     ExceptionOr<void> undo() final
138     {
139         auto result = m_styleSheet->setText(m_oldText);
140         if (result.hasException())
141             return result.releaseException();
142         m_styleSheet->reparseStyleSheet(m_oldText);
143         return { };
144     }
145
146     ExceptionOr<void> redo() final
147     {
148         auto result = m_styleSheet->setText(m_text);
149         if (result.hasException())
150             return result.releaseException();
151         m_styleSheet->reparseStyleSheet(m_text);
152         return { };
153     }
154
155     String mergeId() final
156     {
157         return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
158     }
159
160     void merge(std::unique_ptr<Action> action) override
161     {
162         ASSERT(action->mergeId() == mergeId());
163         m_text = static_cast<SetStyleSheetTextAction&>(*action).m_text;
164     }
165
166     String m_text;
167     String m_oldText;
168 };
169
170 class InspectorCSSAgent::SetStyleTextAction final : public InspectorCSSAgent::StyleSheetAction {
171     WTF_MAKE_NONCOPYABLE(SetStyleTextAction);
172 public:
173     SetStyleTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& text)
174         : InspectorCSSAgent::StyleSheetAction(styleSheet)
175         , m_cssId(cssId)
176         , m_text(text)
177     {
178     }
179
180     ExceptionOr<void> perform() override
181     {
182         return redo();
183     }
184
185     ExceptionOr<void> undo() override
186     {
187         return m_styleSheet->setStyleText(m_cssId, m_oldText, nullptr);
188     }
189
190     ExceptionOr<void> redo() override
191     {
192         return m_styleSheet->setStyleText(m_cssId, m_text, &m_oldText);
193     }
194
195     String mergeId() override
196     {
197         ASSERT(m_styleSheet->id() == m_cssId.styleSheetId());
198         return String::format("SetStyleText %s:%u", m_styleSheet->id().utf8().data(), m_cssId.ordinal());
199     }
200
201     void merge(std::unique_ptr<Action> action) override
202     {
203         ASSERT(action->mergeId() == mergeId());
204
205         SetStyleTextAction* other = static_cast<SetStyleTextAction*>(action.get());
206         m_text = other->m_text;
207     }
208
209 private:
210     InspectorCSSId m_cssId;
211     String m_text;
212     String m_oldText;
213 };
214
215 class InspectorCSSAgent::SetRuleSelectorAction final : public InspectorCSSAgent::StyleSheetAction {
216     WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
217 public:
218     SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
219         : InspectorCSSAgent::StyleSheetAction(styleSheet)
220         , m_cssId(cssId)
221         , m_selector(selector)
222     {
223     }
224
225 private:
226     ExceptionOr<void> perform() final
227     {
228         auto result = m_styleSheet->ruleSelector(m_cssId);
229         if (result.hasException())
230             return result.releaseException();
231         m_oldSelector = result.releaseReturnValue();
232         return redo();
233     }
234
235     ExceptionOr<void> undo() final
236     {
237         return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector);
238     }
239
240     ExceptionOr<void> redo() final
241     {
242         return m_styleSheet->setRuleSelector(m_cssId, m_selector);
243     }
244
245     InspectorCSSId m_cssId;
246     String m_selector;
247     String m_oldSelector;
248 };
249
250 class InspectorCSSAgent::AddRuleAction final : public InspectorCSSAgent::StyleSheetAction {
251     WTF_MAKE_NONCOPYABLE(AddRuleAction);
252 public:
253     AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
254         : InspectorCSSAgent::StyleSheetAction(styleSheet)
255         , m_selector(selector)
256     {
257     }
258
259     InspectorCSSId newRuleId() const { return m_newId; }
260
261 private:
262     ExceptionOr<void> perform() final
263     {
264         return redo();
265     }
266
267     ExceptionOr<void> undo() final
268     {
269         return m_styleSheet->deleteRule(m_newId);
270     }
271
272     ExceptionOr<void> redo() final
273     {
274         auto result = m_styleSheet->addRule(m_selector);
275         if (result.hasException())
276             return result.releaseException();
277         m_newId = m_styleSheet->ruleId(result.releaseReturnValue());
278         return { };
279     }
280
281     InspectorCSSId m_newId;
282     String m_selector;
283     String m_oldSelector;
284 };
285
286 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule& rule)
287 {
288     if (!is<CSSStyleRule>(rule))
289         return nullptr;
290     return downcast<CSSStyleRule>(&rule);
291 }
292
293 InspectorCSSAgent::InspectorCSSAgent(WebAgentContext& context, InspectorDOMAgent* domAgent)
294     : InspectorAgentBase(ASCIILiteral("CSS"), context)
295     , m_frontendDispatcher(std::make_unique<CSSFrontendDispatcher>(context.frontendRouter))
296     , m_backendDispatcher(CSSBackendDispatcher::create(context.backendDispatcher, this))
297     , m_domAgent(domAgent)
298 {
299     m_domAgent->setDOMListener(this);
300 }
301
302 InspectorCSSAgent::~InspectorCSSAgent()
303 {
304     ASSERT(!m_domAgent);
305     reset();
306 }
307
308 void InspectorCSSAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
309 {
310 }
311
312 void InspectorCSSAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
313 {
314     resetNonPersistentData();
315
316     String unused;
317     disable(unused);
318 }
319
320 void InspectorCSSAgent::discardAgent()
321 {
322     m_domAgent->setDOMListener(nullptr);
323     m_domAgent = nullptr;
324 }
325
326 void InspectorCSSAgent::reset()
327 {
328     // FIXME: Should we be resetting on main frame navigations?
329     m_idToInspectorStyleSheet.clear();
330     m_cssStyleSheetToInspectorStyleSheet.clear();
331     m_nodeToInspectorStyleSheet.clear();
332     m_documentToInspectorStyleSheet.clear();
333     m_documentToKnownCSSStyleSheets.clear();
334     resetNonPersistentData();
335 }
336
337 void InspectorCSSAgent::resetNonPersistentData()
338 {
339     resetPseudoStates();
340 }
341
342 void InspectorCSSAgent::enable(ErrorString&)
343 {
344     m_instrumentingAgents.setInspectorCSSAgent(this);
345
346     for (auto* document : m_domAgent->documents())
347         activeStyleSheetsUpdated(*document);
348 }
349
350 void InspectorCSSAgent::disable(ErrorString&)
351 {
352     m_instrumentingAgents.setInspectorCSSAgent(nullptr);
353 }
354
355 void InspectorCSSAgent::documentDetached(Document& document)
356 {
357     Vector<CSSStyleSheet*> emptyList;
358     setActiveStyleSheetsForDocument(document, emptyList);
359
360     m_documentToKnownCSSStyleSheets.remove(&document);
361     m_documentToInspectorStyleSheet.remove(&document);
362     m_documentsWithForcedPseudoStates.remove(&document);
363 }
364
365 void InspectorCSSAgent::mediaQueryResultChanged()
366 {
367     m_frontendDispatcher->mediaQueryResultChanged();
368 }
369
370 void InspectorCSSAgent::activeStyleSheetsUpdated(Document& document)
371 {
372     Vector<CSSStyleSheet*> cssStyleSheets;
373     collectAllDocumentStyleSheets(document, cssStyleSheets);
374
375     setActiveStyleSheetsForDocument(document, cssStyleSheets);
376 }
377
378 void InspectorCSSAgent::setActiveStyleSheetsForDocument(Document& document, Vector<CSSStyleSheet*>& activeStyleSheets)
379 {
380     HashSet<CSSStyleSheet*>& previouslyKnownActiveStyleSheets = m_documentToKnownCSSStyleSheets.add(&document, HashSet<CSSStyleSheet*>()).iterator->value;
381
382     HashSet<CSSStyleSheet*> removedStyleSheets(previouslyKnownActiveStyleSheets);
383     Vector<CSSStyleSheet*> addedStyleSheets;
384     for (auto& activeStyleSheet : activeStyleSheets) {
385         if (removedStyleSheets.contains(activeStyleSheet))
386             removedStyleSheets.remove(activeStyleSheet);
387         else
388             addedStyleSheets.append(activeStyleSheet);
389     }
390
391     for (auto* cssStyleSheet : removedStyleSheets) {
392         previouslyKnownActiveStyleSheets.remove(cssStyleSheet);
393         RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(cssStyleSheet);
394         if (m_idToInspectorStyleSheet.contains(inspectorStyleSheet->id())) {
395             String id = unbindStyleSheet(inspectorStyleSheet.get());
396             m_frontendDispatcher->styleSheetRemoved(id);
397         }
398     }
399
400     for (auto* cssStyleSheet : addedStyleSheets) {
401         previouslyKnownActiveStyleSheets.add(cssStyleSheet);
402         if (!m_cssStyleSheetToInspectorStyleSheet.contains(cssStyleSheet)) {
403             InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssStyleSheet);
404             m_frontendDispatcher->styleSheetAdded(inspectorStyleSheet->buildObjectForStyleSheetInfo());
405         }
406     }
407 }
408
409 bool InspectorCSSAgent::forcePseudoState(const Element& element, CSSSelector::PseudoClassType pseudoClassType)
410 {
411     if (m_nodeIdToForcedPseudoState.isEmpty())
412         return false;
413
414     int nodeId = m_domAgent->boundNodeId(&element);
415     if (!nodeId)
416         return false;
417
418     unsigned forcedPseudoState = m_nodeIdToForcedPseudoState.get(nodeId);
419     switch (pseudoClassType) {
420     case CSSSelector::PseudoClassActive:
421         return forcedPseudoState & PseudoClassActive;
422     case CSSSelector::PseudoClassFocus:
423         return forcedPseudoState & PseudoClassFocus;
424     case CSSSelector::PseudoClassHover:
425         return forcedPseudoState & PseudoClassHover;
426     case CSSSelector::PseudoClassVisited:
427         return forcedPseudoState & PseudoClassVisited;
428     default:
429         return false;
430     }
431 }
432
433 void InspectorCSSAgent::getMatchedStylesForNode(ErrorString& errorString, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::RuleMatch>>& matchedCSSRules, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::PseudoIdMatches>>& pseudoIdMatches, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::InheritedStyleEntry>>& inheritedEntries)
434 {
435     Element* element = elementForId(errorString, nodeId);
436     if (!element)
437         return;
438
439     Element* originalElement = element;
440     PseudoId elementPseudoId = element->pseudoId();
441     if (elementPseudoId) {
442         element = downcast<PseudoElement>(*element).hostElement();
443         if (!element) {
444             errorString = ASCIILiteral("Pseudo element has no parent");
445             return;
446         }
447     }
448
449     // Matched rules.
450     StyleResolver& styleResolver = element->styleResolver();
451     auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, elementPseudoId, StyleResolver::AllCSSRules);
452     matchedCSSRules = buildArrayForMatchedRuleList(matchedRules, styleResolver, *element, elementPseudoId);
453
454     if (!originalElement->isPseudoElement()) {
455         // Pseudo elements.
456         if (!includePseudo || *includePseudo) {
457             auto pseudoElements = JSON::ArrayOf<Inspector::Protocol::CSS::PseudoIdMatches>::create();
458             for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
459                 auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
460                 if (!matchedRules.isEmpty()) {
461                     auto matches = Inspector::Protocol::CSS::PseudoIdMatches::create()
462                         .setPseudoId(static_cast<int>(pseudoId))
463                         .setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, *element, pseudoId))
464                         .release();
465                     pseudoElements->addItem(WTFMove(matches));
466                 }
467             }
468
469             pseudoIdMatches = WTFMove(pseudoElements);
470         }
471
472         // Inherited styles.
473         if (!includeInherited || *includeInherited) {
474             auto entries = JSON::ArrayOf<Inspector::Protocol::CSS::InheritedStyleEntry>::create();
475             Element* parentElement = element->parentElement();
476             while (parentElement) {
477                 StyleResolver& parentStyleResolver = parentElement->styleResolver();
478                 auto parentMatchedRules = parentStyleResolver.styleRulesForElement(parentElement, StyleResolver::AllCSSRules);
479                 auto entry = Inspector::Protocol::CSS::InheritedStyleEntry::create()
480                     .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules, styleResolver, *parentElement, NOPSEUDO))
481                     .release();
482                 if (is<StyledElement>(*parentElement) && downcast<StyledElement>(*parentElement).cssomStyle().length()) {
483                     auto& styleSheet = asInspectorStyleSheet(downcast<StyledElement>(*parentElement));
484                     entry->setInlineStyle(styleSheet.buildObjectForStyle(styleSheet.styleForId(InspectorCSSId(styleSheet.id(), 0))));
485                 }
486
487                 entries->addItem(WTFMove(entry));
488                 parentElement = parentElement->parentElement();
489             }
490
491             inheritedEntries = WTFMove(entries);
492         }
493     }
494 }
495
496 void InspectorCSSAgent::getInlineStylesForNode(ErrorString& errorString, int nodeId, RefPtr<Inspector::Protocol::CSS::CSSStyle>& inlineStyle, RefPtr<Inspector::Protocol::CSS::CSSStyle>& attributesStyle)
497 {
498     auto* element = elementForId(errorString, nodeId);
499     if (!is<StyledElement>(element))
500         return;
501
502     auto& styledElement = downcast<StyledElement>(*element);
503     auto& styleSheet = asInspectorStyleSheet(styledElement);
504     inlineStyle = styleSheet.buildObjectForStyle(&styledElement.cssomStyle());
505     if (auto attributes = buildObjectForAttributesStyle(styledElement))
506         attributesStyle = WTFMove(attributes);
507     else
508         attributesStyle = nullptr;
509 }
510
511 void InspectorCSSAgent::getComputedStyleForNode(ErrorString& errorString, int nodeId, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSComputedStyleProperty>>& style)
512 {
513     auto* element = elementForId(errorString, nodeId);
514     if (!element)
515         return;
516
517     auto computedStyleInfo = CSSComputedStyleDeclaration::create(*element, true);
518     auto inspectorStyle = InspectorStyle::create(InspectorCSSId(), WTFMove(computedStyleInfo), nullptr);
519     style = inspectorStyle->buildArrayForComputedStyle();
520 }
521
522 void InspectorCSSAgent::getAllStyleSheets(ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSStyleSheetHeader>>& styleInfos)
523 {
524     styleInfos = JSON::ArrayOf<Inspector::Protocol::CSS::CSSStyleSheetHeader>::create();
525
526     Vector<InspectorStyleSheet*> inspectorStyleSheets;
527     collectAllStyleSheets(inspectorStyleSheets);
528     for (auto* inspectorStyleSheet : inspectorStyleSheets)
529         styleInfos->addItem(inspectorStyleSheet->buildObjectForStyleSheetInfo());
530 }
531
532 void InspectorCSSAgent::collectAllStyleSheets(Vector<InspectorStyleSheet*>& result)
533 {
534     Vector<CSSStyleSheet*> cssStyleSheets;
535     for (auto* document : m_domAgent->documents())
536         collectAllDocumentStyleSheets(*document, cssStyleSheets);
537
538     for (auto* cssStyleSheet : cssStyleSheets)
539         result.append(bindStyleSheet(cssStyleSheet));
540 }
541
542 void InspectorCSSAgent::collectAllDocumentStyleSheets(Document& document, Vector<CSSStyleSheet*>& result)
543 {
544     auto cssStyleSheets = document.styleScope().activeStyleSheetsForInspector();
545     for (auto& cssStyleSheet : cssStyleSheets)
546         collectStyleSheets(cssStyleSheet.get(), result);
547 }
548
549 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Vector<CSSStyleSheet*>& result)
550 {
551     result.append(styleSheet);
552
553     for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
554         CSSRule* rule = styleSheet->item(i);
555         if (is<CSSImportRule>(*rule)) {
556             if (CSSStyleSheet* importedStyleSheet = downcast<CSSImportRule>(*rule).styleSheet())
557                 collectStyleSheets(importedStyleSheet, result);
558         }
559     }
560 }
561
562 void InspectorCSSAgent::getStyleSheet(ErrorString& errorString, const String& styleSheetId, RefPtr<Inspector::Protocol::CSS::CSSStyleSheetBody>& styleSheetObject)
563 {
564     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
565     if (!inspectorStyleSheet)
566         return;
567
568     styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
569 }
570
571 void InspectorCSSAgent::getStyleSheetText(ErrorString& errorString, const String& styleSheetId, String* result)
572 {
573     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
574     if (!inspectorStyleSheet)
575         return;
576
577     auto text = inspectorStyleSheet->text();
578     if (!text.hasException())
579         *result = text.releaseReturnValue();
580 }
581
582 void InspectorCSSAgent::setStyleSheetText(ErrorString& errorString, const String& styleSheetId, const String& text)
583 {
584     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
585     if (!inspectorStyleSheet)
586         return;
587
588     auto result = m_domAgent->history()->perform(std::make_unique<SetStyleSheetTextAction>(inspectorStyleSheet, text));
589     if (result.hasException())
590         errorString = InspectorDOMAgent::toErrorString(result.releaseException());
591 }
592
593 void InspectorCSSAgent::setStyleText(ErrorString& errorString, const JSON::Object& fullStyleId, const String& text, RefPtr<Inspector::Protocol::CSS::CSSStyle>& result)
594 {
595     InspectorCSSId compoundId(fullStyleId);
596     ASSERT(!compoundId.isEmpty());
597
598     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
599     if (!inspectorStyleSheet)
600         return;
601
602     auto performResult = m_domAgent->history()->perform(std::make_unique<SetStyleTextAction>(inspectorStyleSheet, compoundId, text));
603     if (performResult.hasException()) {
604         errorString = InspectorDOMAgent::toErrorString(performResult.releaseException());
605         return;
606     }
607
608     result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
609 }
610
611 void InspectorCSSAgent::setRuleSelector(ErrorString& errorString, const JSON::Object& fullRuleId, const String& selector, RefPtr<Inspector::Protocol::CSS::CSSRule>& result)
612 {
613     InspectorCSSId compoundId(fullRuleId);
614     ASSERT(!compoundId.isEmpty());
615
616     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
617     if (!inspectorStyleSheet)
618         return;
619
620     auto performResult = m_domAgent->history()->perform(std::make_unique<SetRuleSelectorAction>(inspectorStyleSheet, compoundId, selector));
621     if (performResult.hasException()) {
622         errorString = InspectorDOMAgent::toErrorString(performResult.releaseException());
623         return;
624     }
625
626     result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId), nullptr);
627 }
628
629 void InspectorCSSAgent::createStyleSheet(ErrorString& errorString, const String& frameId, String* styleSheetId)
630 {
631     Frame* frame = m_domAgent->pageAgent()->frameForId(frameId);
632     if (!frame) {
633         errorString = ASCIILiteral("No frame for given id found");
634         return;
635     }
636
637     Document* document = frame->document();
638     if (!document) {
639         errorString = ASCIILiteral("No document for frame");
640         return;
641     }
642
643     InspectorStyleSheet* inspectorStyleSheet = createInspectorStyleSheetForDocument(*document);
644     if (!inspectorStyleSheet) {
645         errorString = ASCIILiteral("Could not create stylesheet for the frame.");
646         return;
647     }
648
649     *styleSheetId = inspectorStyleSheet->id();
650 }
651
652 InspectorStyleSheet* InspectorCSSAgent::createInspectorStyleSheetForDocument(Document& document)
653 {
654     if (!document.isHTMLDocument() && !document.isSVGDocument())
655         return nullptr;
656
657     auto styleElement = HTMLStyleElement::create(document);
658     styleElement->setAttributeWithoutSynchronization(HTMLNames::typeAttr, AtomicString("text/css", AtomicString::ConstructFromLiteral));
659
660     ContainerNode* targetNode;
661     // HEAD is absent in ImageDocuments, for example.
662     if (auto* head = document.head())
663         targetNode = head;
664     else if (auto* body = document.bodyOrFrameset())
665         targetNode = body;
666     else
667         return nullptr;
668
669     // Inserting this <style> into the document will trigger activeStyleSheetsUpdated
670     // and we will create an InspectorStyleSheet for this <style>'s CSSStyleSheet.
671     // Set this flag, so when we create it, we put it into the via inspector map.
672     m_creatingViaInspectorStyleSheet = true;
673     InlineStyleOverrideScope overrideScope(document);
674     auto appendResult = targetNode->appendChild(styleElement);
675     document.styleScope().flushPendingUpdate();
676     m_creatingViaInspectorStyleSheet = false;
677     if (appendResult.hasException())
678         return nullptr;
679
680     auto iterator = m_documentToInspectorStyleSheet.find(&document);
681     ASSERT(iterator != m_documentToInspectorStyleSheet.end());
682     if (iterator == m_documentToInspectorStyleSheet.end())
683         return nullptr;
684
685     auto& inspectorStyleSheetsForDocument = iterator->value;
686     ASSERT(!inspectorStyleSheetsForDocument.isEmpty());
687     if (inspectorStyleSheetsForDocument.isEmpty())
688         return nullptr;
689
690     return inspectorStyleSheetsForDocument.last().get();
691 }
692
693 void InspectorCSSAgent::addRule(ErrorString& errorString, const String& styleSheetId, const String& selector, RefPtr<Inspector::Protocol::CSS::CSSRule>& result)
694 {
695     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
696     if (!inspectorStyleSheet) {
697         errorString = ASCIILiteral("No target stylesheet found");
698         return;
699     }
700
701     auto action = std::make_unique<AddRuleAction>(inspectorStyleSheet, selector);
702     auto& rawAction = *action;
703     auto performResult = m_domAgent->history()->perform(WTFMove(action));
704     if (performResult.hasException()) {
705         errorString = InspectorDOMAgent::toErrorString(performResult.releaseException());
706         return;
707     }
708
709     InspectorCSSId ruleId = rawAction.newRuleId();
710     CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
711     result = inspectorStyleSheet->buildObjectForRule(rule, nullptr);
712 }
713
714 void InspectorCSSAgent::getSupportedCSSProperties(ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSPropertyInfo>>& cssProperties)
715 {
716     auto properties = JSON::ArrayOf<Inspector::Protocol::CSS::CSSPropertyInfo>::create();
717     for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
718         CSSPropertyID id = convertToCSSPropertyID(i);
719         if (isInternalCSSProperty(id))
720             continue;
721
722         auto property = Inspector::Protocol::CSS::CSSPropertyInfo::create()
723             .setName(getPropertyNameString(id))
724             .release();
725
726         const StylePropertyShorthand& shorthand = shorthandForProperty(id);
727         if (!shorthand.length()) {
728             properties->addItem(WTFMove(property));
729             continue;
730         }
731         auto longhands = JSON::ArrayOf<String>::create();
732         for (unsigned j = 0; j < shorthand.length(); ++j) {
733             CSSPropertyID longhandID = shorthand.properties()[j];
734             longhands->addItem(getPropertyNameString(longhandID));
735         }
736         property->setLonghands(WTFMove(longhands));
737         properties->addItem(WTFMove(property));
738     }
739     cssProperties = WTFMove(properties);
740 }
741
742 void InspectorCSSAgent::getSupportedSystemFontFamilyNames(ErrorString&, RefPtr<JSON::ArrayOf<String>>& fontFamilyNames)
743 {
744     auto families = JSON::ArrayOf<String>::create();
745
746     Vector<String> systemFontFamilies = FontCache::singleton().systemFontFamilies();
747     for (const auto& familyName : systemFontFamilies)
748         families->addItem(familyName);
749
750     fontFamilyNames = WTFMove(families);
751 }
752
753 void InspectorCSSAgent::forcePseudoState(ErrorString& errorString, int nodeId, const JSON::Array& forcedPseudoClasses)
754 {
755     Element* element = m_domAgent->assertElement(errorString, nodeId);
756     if (!element)
757         return;
758
759     // Return early if the forced pseudo state was already set correctly.
760     unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses);
761     if (forcedPseudoState) {
762         auto iterator = m_nodeIdToForcedPseudoState.add(nodeId, 0).iterator;
763         if (forcedPseudoState == iterator->value)
764             return;
765         iterator->value = forcedPseudoState;
766         m_documentsWithForcedPseudoStates.add(&element->document());
767     } else {
768         if (!m_nodeIdToForcedPseudoState.remove(nodeId))
769             return;
770         if (m_nodeIdToForcedPseudoState.isEmpty())
771             m_documentsWithForcedPseudoStates.clear();
772     }
773
774     element->document().styleScope().didChangeStyleSheetEnvironment();
775 }
776
777 InspectorStyleSheetForInlineStyle& InspectorCSSAgent::asInspectorStyleSheet(StyledElement& element)
778 {
779     return m_nodeToInspectorStyleSheet.ensure(&element, [this, &element] {
780         String newStyleSheetId = String::number(m_lastStyleSheetId++);
781         auto inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_domAgent->pageAgent(), newStyleSheetId, element, Inspector::Protocol::CSS::StyleSheetOrigin::Regular, this);
782         m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet.copyRef());
783         return inspectorStyleSheet;
784     }).iterator->value;
785 }
786
787 Element* InspectorCSSAgent::elementForId(ErrorString& errorString, int nodeId)
788 {
789     Node* node = m_domAgent->nodeForId(nodeId);
790     if (!node) {
791         errorString = ASCIILiteral("No node with given id found");
792         return nullptr;
793     }
794     if (!is<Element>(*node)) {
795         errorString = ASCIILiteral("Not an element node");
796         return nullptr;
797     }
798     return downcast<Element>(node);
799 }
800
801 String InspectorCSSAgent::unbindStyleSheet(InspectorStyleSheet* inspectorStyleSheet)
802 {
803     String id = inspectorStyleSheet->id();
804     m_idToInspectorStyleSheet.remove(id);
805     if (inspectorStyleSheet->pageStyleSheet())
806         m_cssStyleSheetToInspectorStyleSheet.remove(inspectorStyleSheet->pageStyleSheet());
807     return id;
808 }
809
810 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
811 {
812     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
813     if (!inspectorStyleSheet) {
814         String id = String::number(m_lastStyleSheetId++);
815         Document* document = styleSheet->ownerDocument();
816         inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
817         m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
818         m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
819         if (m_creatingViaInspectorStyleSheet) {
820             auto& inspectorStyleSheetsForDocument = m_documentToInspectorStyleSheet.add(document, Vector<RefPtr<InspectorStyleSheet>>()).iterator->value;
821             inspectorStyleSheetsForDocument.append(inspectorStyleSheet);
822         }
823     }
824     return inspectorStyleSheet.get();
825 }
826
827 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString& errorString, const String& styleSheetId)
828 {
829     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
830     if (it == m_idToInspectorStyleSheet.end()) {
831         errorString = ASCIILiteral("No stylesheet with given id found");
832         return nullptr;
833     }
834     return it->value.get();
835 }
836
837 Inspector::Protocol::CSS::StyleSheetOrigin InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
838 {
839     if (m_creatingViaInspectorStyleSheet)
840         return Inspector::Protocol::CSS::StyleSheetOrigin::Inspector;
841
842     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
843         return Inspector::Protocol::CSS::StyleSheetOrigin::UserAgent;
844
845     if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
846         return Inspector::Protocol::CSS::StyleSheetOrigin::User;
847
848     auto iterator = m_documentToInspectorStyleSheet.find(ownerDocument);
849     if (iterator != m_documentToInspectorStyleSheet.end()) {
850         for (auto& inspectorStyleSheet : iterator->value) {
851             if (pageStyleSheet == inspectorStyleSheet->pageStyleSheet())
852                 return Inspector::Protocol::CSS::StyleSheetOrigin::Inspector;
853         }
854     }
855
856     return Inspector::Protocol::CSS::StyleSheetOrigin::Regular;
857 }
858
859 RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(StyleRule* styleRule, StyleResolver& styleResolver, Element& element)
860 {
861     if (!styleRule)
862         return nullptr;
863
864     // StyleRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
865     // Since the inspector wants to walk the parent chain, we construct the full wrappers here.
866     styleResolver.inspectorCSSOMWrappers().collectDocumentWrappers(styleResolver.document().extensionStyleSheets());
867     styleResolver.inspectorCSSOMWrappers().collectScopeWrappers(Style::Scope::forNode(element));
868
869     // Possiblity of :host styles if this element has a shadow root.
870     if (ShadowRoot* shadowRoot = element.shadowRoot())
871         styleResolver.inspectorCSSOMWrappers().collectScopeWrappers(shadowRoot->styleScope());
872
873     CSSStyleRule* cssomWrapper = styleResolver.inspectorCSSOMWrappers().getWrapperForRuleInSheets(styleRule);
874     if (!cssomWrapper)
875         return nullptr;
876
877     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssomWrapper->parentStyleSheet());
878     return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(cssomWrapper, &element) : nullptr;
879 }
880
881 RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule)
882 {
883     if (!rule)
884         return nullptr;
885
886     ASSERT(rule->parentStyleSheet());
887     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(rule->parentStyleSheet());
888     return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(rule, nullptr) : nullptr;
889 }
890
891 RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::RuleMatch>> InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>& matchedRules, StyleResolver& styleResolver, Element& element, PseudoId pseudoId)
892 {
893     auto result = JSON::ArrayOf<Inspector::Protocol::CSS::RuleMatch>::create();
894
895     SelectorChecker::CheckingContext context(SelectorChecker::Mode::CollectingRules);
896     context.pseudoId = pseudoId ? pseudoId : element.pseudoId();
897     SelectorChecker selectorChecker(element.document());
898
899     for (auto& matchedRule : matchedRules) {
900         RefPtr<Inspector::Protocol::CSS::CSSRule> ruleObject = buildObjectForRule(matchedRule.get(), styleResolver, element);
901         if (!ruleObject)
902             continue;
903
904         auto matchingSelectors = JSON::ArrayOf<int>::create();
905         const CSSSelectorList& selectorList = matchedRule->selectorList();
906         int index = 0;
907         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
908             unsigned ignoredSpecificity;
909             bool matched = selectorChecker.match(*selector, element, context, ignoredSpecificity);
910             if (matched)
911                 matchingSelectors->addItem(index);
912             ++index;
913         }
914
915         auto match = Inspector::Protocol::CSS::RuleMatch::create()
916             .setRule(WTFMove(ruleObject))
917             .setMatchingSelectors(WTFMove(matchingSelectors))
918             .release();
919         result->addItem(WTFMove(match));
920     }
921
922     return WTFMove(result);
923 }
924
925 RefPtr<Inspector::Protocol::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(StyledElement& element)
926 {
927     // FIXME: Ugliness below.
928     auto* attributeStyle = const_cast<StyleProperties*>(element.presentationAttributeStyle());
929     if (!attributeStyle)
930         return nullptr;
931
932     auto& mutableAttributeStyle = downcast<MutableStyleProperties>(*attributeStyle);
933     auto inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle.ensureCSSStyleDeclaration(), nullptr);
934     return inspectorStyle->buildObjectForStyle();
935 }
936
937 void InspectorCSSAgent::didRemoveDOMNode(Node& node, int nodeId)
938 {
939     m_nodeIdToForcedPseudoState.remove(nodeId);
940
941     auto sheet = m_nodeToInspectorStyleSheet.take(&node);
942     if (!sheet)
943         return;
944     m_idToInspectorStyleSheet.remove(sheet.value()->id());
945 }
946
947 void InspectorCSSAgent::didModifyDOMAttr(Element& element)
948 {
949     auto sheet = m_nodeToInspectorStyleSheet.get(&element);
950     if (!sheet)
951         return;
952     sheet->didModifyElementAttribute();
953 }
954
955 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
956 {
957     m_frontendDispatcher->styleSheetChanged(styleSheet->id());
958 }
959
960 void InspectorCSSAgent::resetPseudoStates()
961 {
962     for (auto& document : m_documentsWithForcedPseudoStates)
963         document->styleScope().didChangeStyleSheetEnvironment();
964
965     m_nodeIdToForcedPseudoState.clear();
966     m_documentsWithForcedPseudoStates.clear();
967 }
968
969 } // namespace WebCore