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