1 | /* |
2 | * Copyright (C) 2010, Google Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
15 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
16 | * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
17 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
18 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
19 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
21 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
22 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
23 | */ |
24 | |
25 | #pragma once |
26 | |
27 | #include "CSSPropertySourceData.h" |
28 | #include "CSSStyleDeclaration.h" |
29 | #include <JavaScriptCore/InspectorProtocolObjects.h> |
30 | #include <wtf/HashMap.h> |
31 | #include <wtf/JSONValues.h> |
32 | #include <wtf/Vector.h> |
33 | |
34 | class ParsedStyleSheet; |
35 | |
36 | namespace WebCore { |
37 | |
38 | class CSSRuleList; |
39 | class CSSSelector; |
40 | class CSSStyleDeclaration; |
41 | class CSSStyleRule; |
42 | class CSSStyleSheet; |
43 | class Document; |
44 | class Element; |
45 | class InspectorPageAgent; |
46 | class InspectorStyleSheet; |
47 | |
48 | typedef String ErrorString; |
49 | |
50 | class InspectorCSSId { |
51 | public: |
52 | InspectorCSSId() = default; |
53 | |
54 | explicit InspectorCSSId(const JSON::Object& value) |
55 | { |
56 | if (!value.getString("styleSheetId"_s , m_styleSheetId)) |
57 | return; |
58 | |
59 | if (!value.getInteger("ordinal"_s , m_ordinal)) |
60 | m_styleSheetId = String(); |
61 | } |
62 | |
63 | InspectorCSSId(const String& styleSheetId, unsigned ordinal) |
64 | : m_styleSheetId(styleSheetId) |
65 | , m_ordinal(ordinal) |
66 | { |
67 | } |
68 | |
69 | bool isEmpty() const { return m_styleSheetId.isEmpty(); } |
70 | |
71 | const String& styleSheetId() const { return m_styleSheetId; } |
72 | unsigned ordinal() const { return m_ordinal; } |
73 | |
74 | // ID type is either Inspector::Protocol::CSS::CSSStyleId or Inspector::Protocol::CSS::CSSRuleId. |
75 | template<typename ID> |
76 | RefPtr<ID> asProtocolValue() const |
77 | { |
78 | if (isEmpty()) |
79 | return nullptr; |
80 | |
81 | return ID::create() |
82 | .setStyleSheetId(m_styleSheetId) |
83 | .setOrdinal(m_ordinal) |
84 | .release(); |
85 | } |
86 | |
87 | private: |
88 | String m_styleSheetId; |
89 | unsigned m_ordinal = {0}; |
90 | }; |
91 | |
92 | struct InspectorStyleProperty { |
93 | InspectorStyleProperty() |
94 | : hasSource(false) |
95 | , disabled(false) |
96 | { |
97 | } |
98 | |
99 | InspectorStyleProperty(CSSPropertySourceData sourceData, bool hasSource, bool disabled) |
100 | : sourceData(sourceData) |
101 | , hasSource(hasSource) |
102 | , disabled(disabled) |
103 | { |
104 | } |
105 | |
106 | void setRawTextFromStyleDeclaration(const String& styleDeclaration) |
107 | { |
108 | unsigned start = sourceData.range.start; |
109 | unsigned end = sourceData.range.end; |
110 | ASSERT_WITH_SECURITY_IMPLICATION(start < end); |
111 | ASSERT(end <= styleDeclaration.length()); |
112 | rawText = styleDeclaration.substring(start, end - start); |
113 | } |
114 | |
115 | bool hasRawText() const { return !rawText.isEmpty(); } |
116 | |
117 | CSSPropertySourceData sourceData; |
118 | bool hasSource; |
119 | bool disabled; |
120 | String rawText; |
121 | }; |
122 | |
123 | class InspectorStyle final : public RefCounted<InspectorStyle> { |
124 | public: |
125 | static Ref<InspectorStyle> create(const InspectorCSSId& styleId, Ref<CSSStyleDeclaration>&&, InspectorStyleSheet* parentStyleSheet); |
126 | ~InspectorStyle(); |
127 | |
128 | CSSStyleDeclaration& cssStyle() const { return m_style.get(); } |
129 | RefPtr<Inspector::Protocol::CSS::CSSStyle> buildObjectForStyle() const; |
130 | Ref<JSON::ArrayOf<Inspector::Protocol::CSS::CSSComputedStyleProperty>> buildArrayForComputedStyle() const; |
131 | |
132 | ExceptionOr<String> text() const; |
133 | ExceptionOr<void> setText(const String&); |
134 | |
135 | private: |
136 | InspectorStyle(const InspectorCSSId& styleId, Ref<CSSStyleDeclaration>&&, InspectorStyleSheet* parentStyleSheet); |
137 | |
138 | void populateAllProperties(Vector<InspectorStyleProperty>* result) const; |
139 | Ref<Inspector::Protocol::CSS::CSSStyle> styleWithProperties() const; |
140 | RefPtr<CSSRuleSourceData> () const; |
141 | String shorthandValue(const String& shorthandProperty) const; |
142 | String shorthandPriority(const String& shorthandProperty) const; |
143 | Vector<String> longhandProperties(const String& shorthandProperty) const; |
144 | |
145 | InspectorCSSId m_styleId; |
146 | Ref<CSSStyleDeclaration> m_style; |
147 | InspectorStyleSheet* m_parentStyleSheet; |
148 | }; |
149 | |
150 | class InspectorStyleSheet : public RefCounted<InspectorStyleSheet> { |
151 | public: |
152 | class Listener { |
153 | public: |
154 | Listener() = default; |
155 | virtual ~Listener() = default; |
156 | virtual void styleSheetChanged(InspectorStyleSheet*) = 0; |
157 | }; |
158 | |
159 | typedef HashMap<CSSStyleDeclaration*, RefPtr<InspectorStyle>> InspectorStyleMap; |
160 | static Ref<InspectorStyleSheet> create(InspectorPageAgent*, const String& id, RefPtr<CSSStyleSheet>&& pageStyleSheet, Inspector::Protocol::CSS::StyleSheetOrigin, const String& documentURL, Listener*); |
161 | static String styleSheetURL(CSSStyleSheet* pageStyleSheet); |
162 | |
163 | virtual ~InspectorStyleSheet(); |
164 | |
165 | String id() const { return m_id; } |
166 | String finalURL() const; |
167 | CSSStyleSheet* pageStyleSheet() const { return m_pageStyleSheet.get(); } |
168 | void reparseStyleSheet(const String&); |
169 | ExceptionOr<void> setText(const String&); |
170 | ExceptionOr<String> ruleSelector(const InspectorCSSId&); |
171 | ExceptionOr<void> setRuleSelector(const InspectorCSSId&, const String& selector); |
172 | ExceptionOr<CSSStyleRule*> addRule(const String& selector); |
173 | ExceptionOr<void> deleteRule(const InspectorCSSId&); |
174 | CSSStyleRule* ruleForId(const InspectorCSSId&) const; |
175 | RefPtr<Inspector::Protocol::CSS::CSSStyleSheetBody> buildObjectForStyleSheet(); |
176 | RefPtr<Inspector::Protocol::CSS::CSSStyleSheetHeader> buildObjectForStyleSheetInfo(); |
177 | RefPtr<Inspector::Protocol::CSS::CSSRule> buildObjectForRule(CSSStyleRule*, Element*); |
178 | RefPtr<Inspector::Protocol::CSS::CSSStyle> buildObjectForStyle(CSSStyleDeclaration*); |
179 | ExceptionOr<void> setStyleText(const InspectorCSSId&, const String& text, String* oldText); |
180 | |
181 | virtual ExceptionOr<String> text() const; |
182 | virtual CSSStyleDeclaration* styleForId(const InspectorCSSId&) const; |
183 | void fireStyleSheetChanged(); |
184 | |
185 | InspectorCSSId ruleId(CSSStyleRule*) const; |
186 | InspectorCSSId styleId(CSSStyleDeclaration* style) const { return ruleOrStyleId(style); } |
187 | |
188 | protected: |
189 | InspectorStyleSheet(InspectorPageAgent*, const String& id, RefPtr<CSSStyleSheet>&& pageStyleSheet, Inspector::Protocol::CSS::StyleSheetOrigin, const String& documentURL, Listener*); |
190 | |
191 | bool canBind() const { return m_origin != Inspector::Protocol::CSS::StyleSheetOrigin::UserAgent && m_origin != Inspector::Protocol::CSS::StyleSheetOrigin::User; } |
192 | InspectorCSSId ruleOrStyleId(CSSStyleDeclaration*) const; |
193 | virtual Document* ownerDocument() const; |
194 | virtual RefPtr<CSSRuleSourceData> ruleSourceDataFor(CSSStyleDeclaration*) const; |
195 | virtual unsigned ruleIndexByStyle(CSSStyleDeclaration*) const; |
196 | virtual bool ensureParsedDataReady(); |
197 | virtual RefPtr<InspectorStyle> inspectorStyleForId(const InspectorCSSId&); |
198 | |
199 | // Also accessed by friend class InspectorStyle. |
200 | virtual ExceptionOr<void> setStyleText(CSSStyleDeclaration*, const String&); |
201 | virtual Vector<size_t> lineEndings() const; |
202 | |
203 | private: |
204 | typedef Vector<RefPtr<CSSStyleRule>> CSSStyleRuleVector; |
205 | friend class InspectorStyle; |
206 | |
207 | static void collectFlatRules(RefPtr<CSSRuleList>&&, CSSStyleRuleVector* result); |
208 | bool styleSheetMutated() const; |
209 | bool ensureText() const; |
210 | bool ensureSourceData(); |
211 | void ensureFlatRules() const; |
212 | bool styleSheetTextWithChangedStyle(CSSStyleDeclaration*, const String& newStyleText, String* result); |
213 | bool originalStyleSheetText(String* result) const; |
214 | bool resourceStyleSheetText(String* result) const; |
215 | bool inlineStyleSheetText(String* result) const; |
216 | Ref<JSON::ArrayOf<Inspector::Protocol::CSS::CSSRule>> buildArrayForRuleList(CSSRuleList*); |
217 | Ref<Inspector::Protocol::CSS::CSSSelector> buildObjectForSelector(const CSSSelector*, Element*); |
218 | Ref<Inspector::Protocol::CSS::SelectorList> buildObjectForSelectorList(CSSStyleRule*, Element*, int& endingLine); |
219 | |
220 | InspectorPageAgent* m_pageAgent; |
221 | String m_id; |
222 | RefPtr<CSSStyleSheet> m_pageStyleSheet; |
223 | Inspector::Protocol::CSS::StyleSheetOrigin m_origin; |
224 | String m_documentURL; |
225 | ParsedStyleSheet* m_parsedStyleSheet; |
226 | mutable CSSStyleRuleVector m_flatRules; |
227 | Listener* m_listener; |
228 | }; |
229 | |
230 | class InspectorStyleSheetForInlineStyle final : public InspectorStyleSheet { |
231 | public: |
232 | static Ref<InspectorStyleSheetForInlineStyle> create(InspectorPageAgent*, const String& id, Ref<StyledElement>&&, Inspector::Protocol::CSS::StyleSheetOrigin, Listener*); |
233 | |
234 | void didModifyElementAttribute(); |
235 | ExceptionOr<String> text() const final; |
236 | CSSStyleDeclaration* styleForId(const InspectorCSSId& id) const final { ASSERT_UNUSED(id, !id.ordinal()); return &inlineStyle(); } |
237 | |
238 | protected: |
239 | InspectorStyleSheetForInlineStyle(InspectorPageAgent*, const String& id, Ref<StyledElement>&&, Inspector::Protocol::CSS::StyleSheetOrigin, Listener*); |
240 | |
241 | Document* ownerDocument() const final; |
242 | RefPtr<CSSRuleSourceData> ruleSourceDataFor(CSSStyleDeclaration* style) const final { ASSERT_UNUSED(style, style == &inlineStyle()); return m_ruleSourceData; } |
243 | unsigned ruleIndexByStyle(CSSStyleDeclaration*) const final { return 0; } |
244 | bool ensureParsedDataReady() final; |
245 | RefPtr<InspectorStyle> inspectorStyleForId(const InspectorCSSId&) final; |
246 | |
247 | // Also accessed by friend class InspectorStyle. |
248 | ExceptionOr<void> setStyleText(CSSStyleDeclaration*, const String&) final; |
249 | Vector<size_t> lineEndings() const final; |
250 | |
251 | private: |
252 | CSSStyleDeclaration& inlineStyle() const; |
253 | const String& elementStyleText() const; |
254 | Ref<CSSRuleSourceData> ruleSourceData() const; |
255 | |
256 | Ref<StyledElement> m_element; |
257 | RefPtr<CSSRuleSourceData> m_ruleSourceData; |
258 | RefPtr<InspectorStyle> m_inspectorStyle; |
259 | |
260 | // Contains "style" attribute value. |
261 | mutable String m_styleText; |
262 | mutable bool m_isStyleTextValid; |
263 | }; |
264 | |
265 | } // namespace WebCore |
266 | |