1/*
2 * Copyright (C) 2010 Google Inc. All rights reserved.
3 * Copyright (C) 2015-2016 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#pragma once
27
28#include "CSSSelector.h"
29#include "ContentSecurityPolicy.h"
30#include "InspectorStyleSheet.h"
31#include "InspectorWebAgentBase.h"
32#include "SecurityContext.h"
33#include <JavaScriptCore/InspectorBackendDispatchers.h>
34#include <wtf/HashMap.h>
35#include <wtf/HashSet.h>
36#include <wtf/JSONValues.h>
37#include <wtf/RefPtr.h>
38#include <wtf/text/WTFString.h>
39
40namespace Inspector {
41class CSSFrontendDispatcher;
42}
43
44namespace WebCore {
45
46class CSSRule;
47class CSSStyleRule;
48class CSSStyleSheet;
49class Document;
50class Element;
51class Node;
52class NodeList;
53class StyleResolver;
54class StyleRule;
55
56class InspectorCSSAgent final
57 : public InspectorAgentBase
58 , public Inspector::CSSBackendDispatcherHandler
59 , public InspectorStyleSheet::Listener {
60 WTF_MAKE_NONCOPYABLE(InspectorCSSAgent);
61 WTF_MAKE_FAST_ALLOCATED;
62public:
63 class InlineStyleOverrideScope {
64 public:
65 InlineStyleOverrideScope(SecurityContext& context)
66 : m_contentSecurityPolicy(context.contentSecurityPolicy())
67 {
68 m_contentSecurityPolicy->setOverrideAllowInlineStyle(true);
69 }
70
71 ~InlineStyleOverrideScope()
72 {
73 m_contentSecurityPolicy->setOverrideAllowInlineStyle(false);
74 }
75
76 private:
77 ContentSecurityPolicy* m_contentSecurityPolicy;
78 };
79
80 InspectorCSSAgent(WebAgentContext&);
81 virtual ~InspectorCSSAgent() = default;
82
83 static CSSStyleRule* asCSSStyleRule(CSSRule&);
84
85 void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override;
86 void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override;
87 void reset();
88
89 // InspectorInstrumentation
90 void documentDetached(Document&);
91 void mediaQueryResultChanged();
92 void activeStyleSheetsUpdated(Document&);
93 bool forcePseudoState(const Element&, CSSSelector::PseudoClassType);
94
95 // CSSBackendDispatcherHandler
96 void enable(ErrorString&) override;
97 void disable(ErrorString&) override;
98 void getComputedStyleForNode(ErrorString&, int nodeId, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSComputedStyleProperty>>&) override;
99 void getInlineStylesForNode(ErrorString&, int nodeId, RefPtr<Inspector::Protocol::CSS::CSSStyle>& inlineStyle, RefPtr<Inspector::Protocol::CSS::CSSStyle>& attributes) override;
100 void getMatchedStylesForNode(ErrorString&, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::RuleMatch>>& matchedCSSRules, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::PseudoIdMatches>>&, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::InheritedStyleEntry>>& inheritedEntries) override;
101 void getAllStyleSheets(ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSStyleSheetHeader>>& styleSheetInfos) override;
102 void getStyleSheet(ErrorString&, const String& styleSheetId, RefPtr<Inspector::Protocol::CSS::CSSStyleSheetBody>& result) override;
103 void getStyleSheetText(ErrorString&, const String& styleSheetId, String* result) override;
104 void setStyleSheetText(ErrorString&, const String& styleSheetId, const String& text) override;
105 void setStyleText(ErrorString&, const JSON::Object& styleId, const String& text, RefPtr<Inspector::Protocol::CSS::CSSStyle>& result) override;
106 void setRuleSelector(ErrorString&, const JSON::Object& ruleId, const String& selector, RefPtr<Inspector::Protocol::CSS::CSSRule>& result) override;
107 void createStyleSheet(ErrorString&, const String& frameId, String* styleSheetId) override;
108 void addRule(ErrorString&, const String& styleSheetId, const String& selector, RefPtr<Inspector::Protocol::CSS::CSSRule>& result) override;
109 void getSupportedCSSProperties(ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSPropertyInfo>>& result) override;
110 void getSupportedSystemFontFamilyNames(ErrorString&, RefPtr<JSON::ArrayOf<String>>& result) override;
111 void forcePseudoState(ErrorString&, int nodeId, const JSON::Array& forcedPseudoClasses) override;
112
113 // InspectorDOMAgent hooks
114 void didRemoveDOMNode(Node&, int nodeId);
115 void didModifyDOMAttr(Element&);
116
117private:
118 class StyleSheetAction;
119 class SetStyleSheetTextAction;
120 class SetStyleTextAction;
121 class SetRuleSelectorAction;
122 class AddRuleAction;
123
124 typedef HashMap<String, RefPtr<InspectorStyleSheet>> IdToInspectorStyleSheet;
125 typedef HashMap<CSSStyleSheet*, RefPtr<InspectorStyleSheet>> CSSStyleSheetToInspectorStyleSheet;
126 typedef HashMap<RefPtr<Document>, Vector<RefPtr<InspectorStyleSheet>>> DocumentToViaInspectorStyleSheet; // "via inspector" stylesheets
127 typedef HashMap<int, unsigned> NodeIdToForcedPseudoState;
128
129 InspectorStyleSheetForInlineStyle& asInspectorStyleSheet(StyledElement&);
130 Element* elementForId(ErrorString&, int nodeId);
131
132 void collectAllStyleSheets(Vector<InspectorStyleSheet*>&);
133 void collectAllDocumentStyleSheets(Document&, Vector<CSSStyleSheet*>&);
134 void collectStyleSheets(CSSStyleSheet*, Vector<CSSStyleSheet*>&);
135 void setActiveStyleSheetsForDocument(Document&, Vector<CSSStyleSheet*>& activeStyleSheets);
136
137 String unbindStyleSheet(InspectorStyleSheet*);
138 InspectorStyleSheet* bindStyleSheet(CSSStyleSheet*);
139 InspectorStyleSheet* assertStyleSheetForId(ErrorString&, const String&);
140 InspectorStyleSheet* createInspectorStyleSheetForDocument(Document&);
141 Inspector::Protocol::CSS::StyleSheetOrigin detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument);
142
143 RefPtr<Inspector::Protocol::CSS::CSSRule> buildObjectForRule(StyleRule*, StyleResolver&, Element&);
144 RefPtr<Inspector::Protocol::CSS::CSSRule> buildObjectForRule(CSSStyleRule*);
145 RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::RuleMatch>> buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>&, StyleResolver&, Element&, PseudoId);
146 RefPtr<Inspector::Protocol::CSS::CSSStyle> buildObjectForAttributesStyle(StyledElement&);
147
148 // InspectorCSSAgent::Listener implementation
149 void styleSheetChanged(InspectorStyleSheet*) override;
150
151 void resetPseudoStates();
152
153 std::unique_ptr<Inspector::CSSFrontendDispatcher> m_frontendDispatcher;
154 RefPtr<Inspector::CSSBackendDispatcher> m_backendDispatcher;
155
156 IdToInspectorStyleSheet m_idToInspectorStyleSheet;
157 CSSStyleSheetToInspectorStyleSheet m_cssStyleSheetToInspectorStyleSheet;
158 HashMap<Node*, Ref<InspectorStyleSheetForInlineStyle>> m_nodeToInspectorStyleSheet; // bogus "stylesheets" with elements' inline styles
159 DocumentToViaInspectorStyleSheet m_documentToInspectorStyleSheet;
160 HashMap<Document*, HashSet<CSSStyleSheet*>> m_documentToKnownCSSStyleSheets;
161 NodeIdToForcedPseudoState m_nodeIdToForcedPseudoState;
162 HashSet<Document*> m_documentsWithForcedPseudoStates;
163
164 int m_lastStyleSheetId { 1 };
165 bool m_creatingViaInspectorStyleSheet { false };
166};
167
168} // namespace WebCore
169