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#ifndef InspectorStyleSheet_h
26#define InspectorStyleSheet_h
27
28#include "CSSPropertySourceData.h"
29#include "InspectorValues.h"
30#include "PlatformString.h"
31
32#include <wtf/HashMap.h>
33#include <wtf/HashSet.h>
34#include <wtf/PassRefPtr.h>
35#include <wtf/RefPtr.h>
36#include <wtf/Vector.h>
37
38class ParsedStyleSheet;
39
40namespace WebCore {
41
42class CSSRuleList;
43class CSSStyleDeclaration;
44class CSSStyleSheet;
45class Document;
46class Element;
47class InspectorStyleSheet;
48class Node;
49
50#if ENABLE(INSPECTOR)
51
52typedef String ErrorString;
53
54class InspectorCSSId {
55public:
56    InspectorCSSId() { }
57
58    explicit InspectorCSSId(RefPtr<InspectorObject> value)
59    {
60        if (!value->getString("styleSheetId", &m_styleSheetId))
61            return;
62
63        RefPtr<InspectorValue> ordinalValue = value->get("ordinal");
64        if (!ordinalValue || !ordinalValue->asNumber(&m_ordinal))
65            m_styleSheetId = "";
66    }
67
68    InspectorCSSId(const String& styleSheetId, unsigned ordinal)
69        : m_styleSheetId(styleSheetId)
70        , m_ordinal(ordinal)
71    {
72    }
73
74    bool isEmpty() const { return m_styleSheetId.isEmpty(); }
75
76    const String& styleSheetId() const { return m_styleSheetId; }
77    unsigned ordinal() const { return m_ordinal; }
78
79    PassRefPtr<InspectorValue> asInspectorValue() const
80    {
81        if (isEmpty())
82            return InspectorValue::null();
83
84        RefPtr<InspectorObject> result = InspectorObject::create();
85        result->setString("styleSheetId", m_styleSheetId);
86        result->setNumber("ordinal", m_ordinal);
87        return result.release();
88    }
89
90private:
91    String m_styleSheetId;
92    unsigned m_ordinal;
93};
94
95struct InspectorStyleProperty {
96    InspectorStyleProperty()
97    {
98    }
99
100    InspectorStyleProperty(CSSPropertySourceData sourceData, bool hasSource, bool disabled)
101        : sourceData(sourceData)
102        , hasSource(hasSource)
103        , disabled(disabled)
104    {
105    }
106
107    void setRawTextFromStyleDeclaration(const String& styleDeclaration)
108    {
109        unsigned start = sourceData.range.start;
110        unsigned end = sourceData.range.end;
111        ASSERT(start < end);
112        ASSERT(end <= styleDeclaration.length());
113        rawText = styleDeclaration.substring(start, end - start);
114    }
115
116    bool hasRawText() const { return !rawText.isEmpty(); }
117
118    CSSPropertySourceData sourceData;
119    bool hasSource;
120    bool disabled;
121    String rawText;
122};
123
124class InspectorStyle : public RefCounted<InspectorStyle> {
125public:
126    static PassRefPtr<InspectorStyle> create(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet);
127    virtual ~InspectorStyle();
128
129    CSSStyleDeclaration* cssStyle() const { return m_style.get(); }
130    PassRefPtr<InspectorObject> buildObjectForStyle() const;
131    bool hasDisabledProperties() const { return !m_disabledProperties.isEmpty(); }
132    bool setPropertyText(ErrorString*, unsigned index, const String& text, bool overwrite);
133    bool toggleProperty(ErrorString*, unsigned index, bool disable);
134
135private:
136    InspectorStyle(const InspectorCSSId& styleId, PassRefPtr<CSSStyleDeclaration> style, InspectorStyleSheet* parentStyleSheet);
137
138    static unsigned disabledIndexByOrdinal(unsigned ordinal, bool canUseSubsequent, Vector<InspectorStyleProperty>& allProperties);
139
140    bool styleText(String* result) const;
141    bool disableProperty(unsigned indexToDisable, Vector<InspectorStyleProperty>& allProperties);
142    bool enableProperty(unsigned indexToEnable, Vector<InspectorStyleProperty>& allProperties);
143    bool populateAllProperties(Vector<InspectorStyleProperty>* result) const;
144    void populateObjectWithStyleProperties(InspectorObject* result) const;
145    void shiftDisabledProperties(unsigned fromIndex, long offset);
146    bool replacePropertyInStyleText(const InspectorStyleProperty& property, const String& newText);
147    String shorthandValue(const String& shorthandProperty) const;
148    String shorthandPriority(const String& shorthandProperty) const;
149    Vector<String> longhandProperties(const String& shorthandProperty) const;
150
151    InspectorCSSId m_styleId;
152    RefPtr<CSSStyleDeclaration> m_style;
153    InspectorStyleSheet* m_parentStyleSheet;
154    Vector<InspectorStyleProperty> m_disabledProperties;
155};
156
157class InspectorStyleSheet : public RefCounted<InspectorStyleSheet> {
158public:
159    typedef HashMap<CSSStyleDeclaration*, RefPtr<InspectorStyle> > InspectorStyleMap;
160    static PassRefPtr<InspectorStyleSheet> create(const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, const String& origin, const String& documentURL);
161
162    virtual ~InspectorStyleSheet();
163
164    String id() const { return m_id; }
165    String finalURL() const;
166    CSSStyleSheet* pageStyleSheet() const { return m_pageStyleSheet.get(); }
167    void reparseStyleSheet(const String&);
168    bool setText(const String&);
169    bool setRuleSelector(const InspectorCSSId&, const String& selector);
170    CSSStyleRule* addRule(const String& selector);
171    CSSStyleRule* ruleForId(const InspectorCSSId&) const;
172    PassRefPtr<InspectorObject> buildObjectForStyleSheet();
173    PassRefPtr<InspectorObject> buildObjectForStyleSheetInfo();
174    PassRefPtr<InspectorObject> buildObjectForRule(CSSStyleRule*);
175    PassRefPtr<InspectorObject> buildObjectForStyle(CSSStyleDeclaration*);
176    bool setPropertyText(ErrorString*, const InspectorCSSId&, unsigned propertyIndex, const String& text, bool overwrite);
177    bool toggleProperty(ErrorString*, const InspectorCSSId&, unsigned propertyIndex, bool disable);
178
179    virtual bool text(String* result) const;
180    virtual CSSStyleDeclaration* styleForId(const InspectorCSSId&) const;
181
182protected:
183    InspectorStyleSheet(const String& id, PassRefPtr<CSSStyleSheet> pageStyleSheet, const String& origin, const String& documentURL);
184
185    bool canBind() const { return m_origin != "userAgent" && m_origin != "user"; }
186    InspectorCSSId ruleOrStyleId(CSSStyleDeclaration* style) const;
187    virtual Document* ownerDocument() const;
188    virtual RefPtr<CSSRuleSourceData> ruleSourceDataFor(CSSStyleDeclaration* style) const;
189    virtual unsigned ruleIndexByStyle(CSSStyleDeclaration*) const;
190    virtual bool ensureParsedDataReady();
191    virtual PassRefPtr<InspectorStyle> inspectorStyleForId(const InspectorCSSId&);
192    virtual void rememberInspectorStyle(RefPtr<InspectorStyle> inspectorStyle);
193    virtual void forgetInspectorStyle(CSSStyleDeclaration* style);
194
195    // Also accessed by friend class InspectorStyle.
196    virtual bool setStyleText(CSSStyleDeclaration*, const String&);
197
198private:
199    static void fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData, const String& styleSheetText);
200    static void collectFlatRules(PassRefPtr<CSSRuleList>, Vector<CSSStyleRule*>* result);
201    bool ensureText() const;
202    bool ensureSourceData();
203    void ensureFlatRules() const;
204    bool styleSheetTextWithChangedStyle(CSSStyleDeclaration*, const String& newStyleText, String* result);
205    InspectorCSSId ruleId(CSSStyleRule* rule) const;
206    InspectorCSSId styleId(CSSStyleDeclaration* style) const { return ruleOrStyleId(style); }
207    void revalidateStyle(CSSStyleDeclaration*);
208    bool originalStyleSheetText(String* result) const;
209    bool resourceStyleSheetText(String* result) const;
210    bool inlineStyleSheetText(String* result) const;
211    PassRefPtr<InspectorArray> buildArrayForRuleList(CSSRuleList*);
212
213    String m_id;
214    RefPtr<CSSStyleSheet> m_pageStyleSheet;
215    String m_origin;
216    String m_documentURL;
217    bool m_isRevalidating;
218    ParsedStyleSheet* m_parsedStyleSheet;
219    InspectorStyleMap m_inspectorStyles;
220    mutable Vector<CSSStyleRule*> m_flatRules;
221
222    friend class InspectorStyle;
223};
224
225class InspectorStyleSheetForInlineStyle : public InspectorStyleSheet {
226public:
227    static PassRefPtr<InspectorStyleSheetForInlineStyle> create(const String& id, PassRefPtr<Element> element, const String& origin);
228
229    void didModifyElementAttribute();
230    virtual bool text(String* result) const;
231    virtual CSSStyleDeclaration* styleForId(const InspectorCSSId& id) const { ASSERT_UNUSED(id, !id.ordinal()); return inlineStyle(); }
232
233protected:
234    InspectorStyleSheetForInlineStyle(const String& id, PassRefPtr<Element> element, const String& origin);
235
236    virtual Document* ownerDocument() const;
237    virtual RefPtr<CSSRuleSourceData> ruleSourceDataFor(CSSStyleDeclaration* style) const { ASSERT_UNUSED(style, style == inlineStyle()); return m_ruleSourceData; }
238    virtual unsigned ruleIndexByStyle(CSSStyleDeclaration*) const { return 0; }
239    virtual bool ensureParsedDataReady();
240    virtual PassRefPtr<InspectorStyle> inspectorStyleForId(const InspectorCSSId&);
241    virtual void rememberInspectorStyle(RefPtr<InspectorStyle>) { }
242    virtual void forgetInspectorStyle(CSSStyleDeclaration*) { }
243
244    // Also accessed by friend class InspectorStyle.
245    virtual bool setStyleText(CSSStyleDeclaration*, const String&);
246
247private:
248    CSSStyleDeclaration* inlineStyle() const;
249    const String& elementStyleText() const;
250    bool getStyleAttributeRanges(RefPtr<CSSStyleSourceData>* result);
251
252    RefPtr<Element> m_element;
253    RefPtr<CSSRuleSourceData> m_ruleSourceData;
254    RefPtr<InspectorStyle> m_inspectorStyle;
255
256    // Contains "style" attribute value and should always be up-to-date.
257    String m_styleText;
258};
259
260#endif
261
262} // namespace WebCore
263
264#endif // !defined(InspectorStyleSheet_h)
265