2010-07-12 Ilya Tikhonovsky <loislo@chromium.org>
[WebKit-https.git] / WebCore / inspector / InspectorCSSStore.cpp
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  *
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  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "InspectorCSSStore.h"
31
32 #if ENABLE(INSPECTOR)
33
34 #include "CSSMutableStyleDeclaration.h"
35 #include "CSSParser.h"
36 #include "CSSRuleList.h"
37 #include "CSSStyleDeclaration.h"
38 #include "CSSStyleRule.h"
39 #include "CSSStyleSheet.h"
40 #include "HTMLHeadElement.h"
41 #include "InspectorController.h"
42 #include "InspectorResource.h"
43 #include "PlatformString.h"
44 #include "RemoteInspectorFrontend.h"
45 #include "StyleSheetList.h"
46
47 namespace WebCore {
48
49 InspectorCSSStore::InspectorCSSStore(InspectorController* inspectorController)
50     : m_inspectorController(inspectorController)
51     , m_lastStyleId(1)
52     , m_lastStyleSheetId(1)
53     , m_lastRuleId(1)
54 {
55 }
56
57 InspectorCSSStore::~InspectorCSSStore()
58 {
59 }
60
61 void InspectorCSSStore::reset()
62 {
63     m_styleToId.clear();
64     m_idToStyle.clear();
65     m_ruleToId.clear();
66     m_idToRule.clear();
67     deleteAllValues(m_styleSheetToOffsets);
68     m_styleSheetToOffsets.clear();
69     m_styleSheetToId.clear();
70     m_idToStyleSheet.clear();
71     m_idToDisabledStyle.clear();
72     m_documentNodeToInspectorStyleSheetMap.clear();
73
74     m_lastStyleId = 1;
75     m_lastStyleSheetId = 1;
76     m_lastRuleId = 1;
77 }
78
79 void InspectorCSSStore::removeDocument(Document* doc)
80 {
81     m_documentNodeToInspectorStyleSheetMap.remove(doc);
82 }
83
84 CSSStyleSheet* InspectorCSSStore::inspectorStyleSheet(Document* ownerDocument, bool createIfAbsent, long callId)
85 {
86     DocumentToStyleSheetMap::iterator it = m_documentNodeToInspectorStyleSheetMap.find(ownerDocument);
87     if (it != m_documentNodeToInspectorStyleSheetMap.end())
88         return it->second.get();
89     if (!createIfAbsent)
90         return 0;
91     ExceptionCode ec = 0;
92     RefPtr<Element> styleElement = ownerDocument->createElement("style", ec);
93     if (!ec)
94         styleElement->setAttribute("type", "text/css", ec);
95     if (!ec)
96         ownerDocument->head()->appendChild(styleElement, ec);
97     if (ec) {
98         m_inspectorController->remoteInspectorFrontend()->didAddRule(callId, InspectorValue::null(), false);
99         return 0;
100     }
101     StyleSheetList* styleSheets = ownerDocument->styleSheets();
102     StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1);
103     if (!styleSheet->isCSSStyleSheet()) {
104         m_inspectorController->remoteInspectorFrontend()->didAddRule(callId, InspectorValue::null(), false);
105         return 0;
106     }
107     CSSStyleSheet* inspectorStyleSheet = static_cast<CSSStyleSheet*>(styleSheet);
108     m_documentNodeToInspectorStyleSheetMap.set(ownerDocument, inspectorStyleSheet);
109     return inspectorStyleSheet;
110 }
111
112 HashMap<long, SourceRange> InspectorCSSStore::getRuleRangesForStyleSheet(CSSStyleSheet* styleSheet)
113 {
114     if (!styleSheet)
115         return HashMap<long, SourceRange>();
116     RefPtr<CSSRuleList> originalRuleList = CSSRuleList::create(styleSheet, false);
117     StyleSheetToOffsetsMap::iterator it = m_styleSheetToOffsets.find(styleSheet);
118     HashMap<long, SourceRange> result;
119     Vector<SourceRange>* offsetVector = 0;
120     if (it == m_styleSheetToOffsets.end()) {
121         InspectorResource* resource = m_inspectorController->resourceForURL(styleSheet->finalURL().string());
122         if (resource) {
123             offsetVector = new Vector<SourceRange>;
124             RefPtr<CSSStyleSheet> newStyleSheet = CSSStyleSheet::create(styleSheet->ownerNode());
125             CSSParser p;
126             CSSParser::StyleRuleRanges ruleRangeMap;
127             p.parseSheet(newStyleSheet.get(), resource->sourceString(), 0, &ruleRangeMap);
128             for (unsigned i = 0, length = newStyleSheet->length(); i < length; ++i) {
129                 CSSStyleRule* rule = asCSSStyleRule(newStyleSheet->item(i));
130                 if (!rule)
131                     continue;
132                 HashMap<CSSStyleRule*, std::pair<unsigned, unsigned> >::iterator it = ruleRangeMap.find(rule);
133                 if (it != ruleRangeMap.end())
134                     offsetVector->append(it->second);
135             }
136             m_styleSheetToOffsets.set(styleSheet, offsetVector);
137         }
138     } else
139         offsetVector = it->second;
140     if (!offsetVector)
141         return HashMap<long, SourceRange>();
142     unsigned ruleIndex = 0;
143     for (unsigned i = 0, length = styleSheet->length(); i < length; ++i) {
144         ASSERT(ruleIndex < offsetVector->size());
145         CSSStyleRule* rule = asCSSStyleRule(styleSheet->item(i));
146         if (!rule)
147             continue;
148         result.set(bindRule(rule), offsetVector->at(ruleIndex));
149         ruleIndex++;
150     }
151     return result;
152 }
153
154 CSSStyleRule* InspectorCSSStore::asCSSStyleRule(StyleBase* styleBase)
155 {
156     if (!styleBase->isStyleRule())
157         return 0;
158     CSSRule* rule = static_cast<CSSRule*>(styleBase);
159     if (rule->type() != CSSRule::STYLE_RULE)
160         return 0;
161     return static_cast<CSSStyleRule*>(rule);
162 }
163
164 DisabledStyleDeclaration* InspectorCSSStore::disabledStyleForId(long styleId, bool createIfAbsent)
165 {
166     IdToDisabledStyleMap::iterator it = m_idToDisabledStyle.find(styleId);
167     if (it == m_idToDisabledStyle.end() && createIfAbsent)
168         it = m_idToDisabledStyle.set(styleId, DisabledStyleDeclaration()).first;
169     return it == m_idToDisabledStyle.end() ? 0 : &(it->second);
170 }
171
172 CSSStyleDeclaration* InspectorCSSStore::styleForId(long styleId)
173 {
174     IdToStyleMap::iterator it = m_idToStyle.find(styleId);
175     return it == m_idToStyle.end() ? 0 : it->second.get();
176 }
177
178 CSSStyleSheet* InspectorCSSStore::styleSheetForId(long styleSheetId)
179 {
180     IdToStyleSheetMap::iterator it = m_idToStyleSheet.find(styleSheetId);
181     return it == m_idToStyleSheet.end() ? 0 : it->second.get();
182 }
183
184 CSSStyleRule* InspectorCSSStore::ruleForId(long ruleId)
185 {
186     IdToRuleMap::iterator it = m_idToRule.find(ruleId);
187     return it == m_idToRule.end() ? 0 : it->second.get();
188 }
189
190 long InspectorCSSStore::bindStyle(CSSStyleDeclaration* style)
191 {
192     long id = m_styleToId.get(style);
193     if (!id) {
194         id = m_lastStyleId++;
195         m_idToStyle.set(id, style);
196         m_styleToId.set(style, id);
197     }
198     return id;
199 }
200
201 long InspectorCSSStore::bindStyleSheet(CSSStyleSheet* styleSheet)
202 {
203     long id = m_styleSheetToId.get(styleSheet);
204     if (!id) {
205         id = m_lastStyleSheetId++;
206         m_idToStyleSheet.set(id, styleSheet);
207         m_styleSheetToId.set(styleSheet, id);
208     }
209     return id;
210 }
211
212 long InspectorCSSStore::bindRule(CSSStyleRule* rule)
213 {
214     long id = m_ruleToId.get(rule);
215     if (!id) {
216         id = m_lastRuleId++;
217         m_idToRule.set(id, rule);
218         m_ruleToId.set(rule, id);
219     }
220     return id;
221 }
222
223 } // namespace WebCore
224
225 #endif // ENABLE(INSPECTOR)