blob: f0f965de3cb1bd411c03a19dd6261f8b805effc5 [file] [log] [blame]
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001/*
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#include "config.h"
26#include "InspectorCSSAgent.h"
27
28#if ENABLE(INSPECTOR)
29
30#include "CSSComputedStyleDeclaration.h"
apavlov@chromium.orgbe789cf2011-05-18 13:32:07 +000031#include "CSSImportRule.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000032#include "CSSPropertyNames.h"
33#include "CSSPropertySourceData.h"
34#include "CSSRule.h"
35#include "CSSRuleList.h"
36#include "CSSStyleRule.h"
37#include "CSSStyleSelector.h"
38#include "CSSStyleSheet.h"
apavlov@chromium.org31442e82012-03-05 10:44:40 +000039#include "ContentSecurityPolicy.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000040#include "DOMWindow.h"
41#include "HTMLHeadElement.h"
42#include "InspectorDOMAgent.h"
pfeldman@chromium.org94451152012-02-07 17:00:32 +000043#include "InspectorHistory.h"
apavlov@chromium.orgad517d02011-12-15 09:23:19 +000044#include "InspectorState.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000045#include "InspectorValues.h"
yurys@chromium.org29626f82011-03-04 15:15:45 +000046#include "InstrumentingAgents.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000047#include "Node.h"
pfeldman@chromium.org840f3482011-02-11 15:23:26 +000048#include "NodeList.h"
antti@apple.comf6601802012-02-03 22:41:09 +000049#include "StylePropertySet.h"
antti@apple.com8be9b562012-02-28 17:44:18 +000050#include "StyleRule.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000051#include "StyleSheetList.h"
52
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000053#include <wtf/CurrentTime.h>
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000054#include <wtf/HashSet.h>
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000055#include <wtf/Vector.h>
56#include <wtf/text/CString.h>
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000057#include <wtf/text/StringConcatenate.h>
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000058
apavlov@chromium.orgad517d02011-12-15 09:23:19 +000059namespace CSSAgentState {
60static const char cssAgentEnabled[] = "cssAgentEnabled";
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000061static const char isSelectorProfiling[] = "isSelectorProfiling";
apavlov@chromium.orgad517d02011-12-15 09:23:19 +000062}
63
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000064namespace WebCore {
65
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +000066enum ForcePseudoClassFlags {
67 PseudoNone = 0,
68 PseudoHover = 1 << 0,
69 PseudoFocus = 1 << 1,
70 PseudoActive = 1 << 2,
71 PseudoVisited = 1 << 3
72};
73
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000074struct RuleMatchData {
75 String selector;
76 String url;
77 unsigned lineNumber;
78 double startTime;
79};
80
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000081struct RuleMatchingStats {
82 RuleMatchingStats()
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000083 : lineNumber(0), totalTime(0.0), hits(0), matches(0)
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000084 {
85 }
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000086 RuleMatchingStats(const RuleMatchData& data, double totalTime, unsigned hits, unsigned matches)
87 : selector(data.selector), url(data.url), lineNumber(data.lineNumber), totalTime(totalTime), hits(hits), matches(matches)
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000088 {
89 }
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000090
91 String selector;
92 String url;
93 unsigned lineNumber;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000094 double totalTime;
95 unsigned hits;
96 unsigned matches;
97};
98
99class SelectorProfile {
100public:
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000101 SelectorProfile()
102 : m_totalMatchingTimeMs(0.0)
103 {
104 }
105 virtual ~SelectorProfile()
106 {
107 }
108
109 double totalMatchingTimeMs() const { return m_totalMatchingTimeMs; }
110
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000111 String makeKey();
112 void startSelector(const CSSStyleRule*);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000113 void commitSelector(bool);
114 void commitSelectorTime();
115 PassRefPtr<InspectorObject> toInspectorObject() const;
116
117private:
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000118
119 // Key is "selector?url:line".
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000120 typedef HashMap<String, RuleMatchingStats> RuleMatchingStatsMap;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000121
122 double m_totalMatchingTimeMs;
123 RuleMatchingStatsMap m_ruleMatchingStats;
124 RuleMatchData m_currentMatchData;
125};
126
127
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000128static unsigned computePseudoClassMask(InspectorArray* pseudoClassArray)
129{
130 DEFINE_STATIC_LOCAL(String, active, ("active"));
131 DEFINE_STATIC_LOCAL(String, hover, ("hover"));
132 DEFINE_STATIC_LOCAL(String, focus, ("focus"));
133 DEFINE_STATIC_LOCAL(String, visited, ("visited"));
134 if (!pseudoClassArray || !pseudoClassArray->length())
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000135 return PseudoNone;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000136
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000137 unsigned result = PseudoNone;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000138 for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
139 RefPtr<InspectorValue> pseudoClassValue = pseudoClassArray->get(i);
140 String pseudoClass;
141 bool success = pseudoClassValue->asString(&pseudoClass);
142 if (!success)
143 continue;
144 if (pseudoClass == active)
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000145 result |= PseudoActive;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000146 else if (pseudoClass == hover)
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000147 result |= PseudoHover;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000148 else if (pseudoClass == focus)
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000149 result |= PseudoFocus;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000150 else if (pseudoClass == visited)
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000151 result |= PseudoVisited;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000152 }
153
154 return result;
155}
156
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000157inline String SelectorProfile::makeKey()
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000158{
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000159 return makeString(m_currentMatchData.selector, "?", m_currentMatchData.url, ":", String::number(m_currentMatchData.lineNumber));
160}
161
162inline void SelectorProfile::startSelector(const CSSStyleRule* rule)
163{
164 m_currentMatchData.selector = rule->selectorText();
165 CSSStyleSheet* styleSheet = rule->parentStyleSheet();
166 String url = emptyString();
167 if (styleSheet) {
168 url = InspectorStyleSheet::styleSheetURL(styleSheet);
169 if (url.isEmpty())
170 url = InspectorDOMAgent::documentURLString(styleSheet->findDocument());
171 }
172 m_currentMatchData.url = url;
antti@apple.com972c0822012-02-28 09:38:51 +0000173 m_currentMatchData.lineNumber = rule->styleRule()->sourceLine();
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000174 m_currentMatchData.startTime = WTF::currentTimeMS();
175}
176
177inline void SelectorProfile::commitSelector(bool matched)
178{
179 double matchTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTime;
180 m_totalMatchingTimeMs += matchTimeMs;
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000181
182 pair<RuleMatchingStatsMap::iterator, bool> result = m_ruleMatchingStats.add(makeKey(), RuleMatchingStats(m_currentMatchData, matchTimeMs, 1, matched ? 1 : 0));
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000183 if (!result.second) {
184 result.first->second.totalTime += matchTimeMs;
185 result.first->second.hits += 1;
186 if (matched)
187 result.first->second.matches += 1;
188 }
189}
190
191inline void SelectorProfile::commitSelectorTime()
192{
193 double processingTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTime;
194 m_totalMatchingTimeMs += processingTimeMs;
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000195
196 RuleMatchingStatsMap::iterator it = m_ruleMatchingStats.find(makeKey());
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000197 if (it == m_ruleMatchingStats.end())
198 return;
199
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000200 it->second.totalTime += processingTimeMs;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000201}
202
203PassRefPtr<InspectorObject> SelectorProfile::toInspectorObject() const
204{
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000205 RefPtr<InspectorArray> selectorProfileData = InspectorArray::create();
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000206 for (RuleMatchingStatsMap::const_iterator it = m_ruleMatchingStats.begin(); it != m_ruleMatchingStats.end(); ++it) {
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000207 RefPtr<TypeBuilder::CSS::SelectorProfileEntry> entry = TypeBuilder::CSS::SelectorProfileEntry::create()
208 .setSelector(it->second.selector)
209 .setUrl(it->second.url)
210 .setLineNumber(it->second.lineNumber)
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000211 .setTime(it->second.totalTime)
212 .setHitCount(it->second.hits)
213 .setMatchCount(it->second.matches);
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000214 selectorProfileData->pushObject(entry.release());
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000215 }
216
217 RefPtr<TypeBuilder::CSS::SelectorProfile> result = TypeBuilder::CSS::SelectorProfile::create()
218 .setTotalTime(totalMatchingTimeMs())
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000219 .setData(selectorProfileData);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000220 return result.release();
221}
222
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000223class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
224 WTF_MAKE_NONCOPYABLE(StyleSheetAction);
225public:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000226 StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000227 : InspectorHistory::Action(name)
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000228 , m_styleSheet(styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000229 {
230 }
231
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000232protected:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000233 RefPtr<InspectorStyleSheet> m_styleSheet;
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000234};
235
236class InspectorCSSAgent::SetStyleSheetTextAction : public InspectorCSSAgent::StyleSheetAction {
237 WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
238public:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000239 SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
240 : InspectorCSSAgent::StyleSheetAction("SetStyleSheetText", styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000241 , m_text(text)
242 {
243 }
244
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000245 virtual bool perform(ExceptionCode& ec)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000246 {
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000247 if (!m_styleSheet->getText(&m_oldText))
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000248 return false;
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000249 return redo(ec);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000250 }
251
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000252 virtual bool undo(ExceptionCode&)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000253 {
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000254 if (m_styleSheet->setText(m_oldText)) {
255 m_styleSheet->reparseStyleSheet(m_oldText);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000256 return true;
257 }
258 return false;
259 }
260
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000261 virtual bool redo(ExceptionCode&)
262 {
263 if (m_styleSheet->setText(m_text)) {
264 m_styleSheet->reparseStyleSheet(m_text);
265 return true;
266 }
267 return false;
268 }
269
pfeldman@chromium.orga1a70a42012-02-14 08:50:19 +0000270 virtual String mergeId()
271 {
272 return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
273 }
274
275 virtual void merge(PassOwnPtr<Action> action)
276 {
277 ASSERT(action->mergeId() == mergeId());
278
279 SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get());
280 m_text = other->m_text;
281 }
282
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000283private:
284 String m_text;
285 String m_oldText;
286};
287
288class InspectorCSSAgent::SetPropertyTextAction : public InspectorCSSAgent::StyleSheetAction {
289 WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
290public:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000291 SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
292 : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000293 , m_cssId(cssId)
294 , m_propertyIndex(propertyIndex)
295 , m_text(text)
296 , m_overwrite(overwrite)
297 {
298 }
299
300 virtual String toString()
301 {
302 return mergeId() + ": " + m_oldText + " -> " + m_text;
303 }
304
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000305 virtual bool perform(ExceptionCode& ec)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000306 {
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000307 return redo(ec);
308 }
309
310 virtual bool undo(ExceptionCode& ec)
311 {
312 String placeholder;
313 return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, ec);
314 }
315
316 virtual bool redo(ExceptionCode& ec)
317 {
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000318 String oldText;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000319 bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, ec);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000320 m_oldText = oldText.stripWhiteSpace();
321 // FIXME: remove this once the model handles this case.
322 if (!m_oldText.endsWith(";"))
323 m_oldText += ";";
324 return result;
325 }
326
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000327 virtual String mergeId()
328 {
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000329 return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false");
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000330 }
331
332 virtual void merge(PassOwnPtr<Action> action)
333 {
334 ASSERT(action->mergeId() == mergeId());
335
336 SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
337 m_text = other->m_text;
338 }
339
340private:
341 InspectorCSSId m_cssId;
342 unsigned m_propertyIndex;
343 String m_text;
344 String m_oldText;
345 bool m_overwrite;
346};
347
348class InspectorCSSAgent::TogglePropertyAction : public InspectorCSSAgent::StyleSheetAction {
349 WTF_MAKE_NONCOPYABLE(TogglePropertyAction);
350public:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000351 TogglePropertyAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, bool disable)
352 : InspectorCSSAgent::StyleSheetAction("ToggleProperty", styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000353 , m_cssId(cssId)
354 , m_propertyIndex(propertyIndex)
355 , m_disable(disable)
356 {
357 }
358
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000359 virtual bool perform(ExceptionCode& ec)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000360 {
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000361 return redo(ec);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000362 }
363
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000364 virtual bool undo(ExceptionCode& ec)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000365 {
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000366 return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, !m_disable, ec);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000367 }
368
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000369 virtual bool redo(ExceptionCode& ec)
370 {
371 return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, m_disable, ec);
372 }
373
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000374private:
375 InspectorCSSId m_cssId;
376 unsigned m_propertyIndex;
377 bool m_disable;
378};
379
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000380class InspectorCSSAgent::SetRuleSelectorAction : public InspectorCSSAgent::StyleSheetAction {
381 WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
382public:
383 SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
384 : InspectorCSSAgent::StyleSheetAction("SetRuleSelector", styleSheet)
385 , m_cssId(cssId)
386 , m_selector(selector)
387 {
388 }
389
390 virtual bool perform(ExceptionCode& ec)
391 {
392 m_oldSelector = m_styleSheet->ruleSelector(m_cssId, ec);
393 if (ec)
394 return false;
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000395 return redo(ec);
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000396 }
397
398 virtual bool undo(ExceptionCode& ec)
399 {
400 return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, ec);
401 }
402
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000403 virtual bool redo(ExceptionCode& ec)
404 {
405 return m_styleSheet->setRuleSelector(m_cssId, m_selector, ec);
406 }
407
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000408private:
409 InspectorCSSId m_cssId;
410 String m_selector;
411 String m_oldSelector;
412};
413
414class InspectorCSSAgent::AddRuleAction : public InspectorCSSAgent::StyleSheetAction {
415 WTF_MAKE_NONCOPYABLE(AddRuleAction);
416public:
417 AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
418 : InspectorCSSAgent::StyleSheetAction("AddRule", styleSheet)
419 , m_selector(selector)
420 {
421 }
422
423 virtual bool perform(ExceptionCode& ec)
424 {
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000425 return redo(ec);
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000426 }
427
428 virtual bool undo(ExceptionCode& ec)
429 {
430 return m_styleSheet->deleteRule(m_newId, ec);
431 }
432
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000433 virtual bool redo(ExceptionCode& ec)
434 {
435 CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, ec);
436 if (ec)
437 return false;
438 m_newId = m_styleSheet->ruleId(cssStyleRule);
439 return true;
440 }
441
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000442 InspectorCSSId newRuleId() { return m_newId; }
443
444private:
445 InspectorCSSId m_newId;
446 String m_selector;
447 String m_oldSelector;
448};
449
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000450// static
andreas.kling@nokia.comf04e49c2011-10-14 21:33:49 +0000451CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000452{
andreas.kling@nokia.com0fb29262011-10-31 15:53:14 +0000453 if (!rule->isStyleRule())
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000454 return 0;
455 return static_cast<CSSStyleRule*>(rule);
456}
457
pfeldman@chromium.orgccc8cd932011-11-28 14:41:48 +0000458InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state, InspectorDOMAgent* domAgent)
pfeldman@chromium.org2f44edb2011-11-29 14:43:10 +0000459 : InspectorBaseAgent<InspectorCSSAgent>("CSS", instrumentingAgents, state)
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000460 , m_frontend(0)
yurys@chromium.org29626f82011-03-04 15:15:45 +0000461 , m_domAgent(domAgent)
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000462 , m_lastPseudoState(0)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000463 , m_lastStyleSheetId(1)
464 , m_lastRuleId(1)
465 , m_lastStyleId(1)
466{
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +0000467 m_domAgent->setDOMListener(this);
apavlov@chromium.org1ed8ba32012-01-19 16:39:55 +0000468 m_instrumentingAgents->setInspectorCSSAgent(this);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000469}
470
471InspectorCSSAgent::~InspectorCSSAgent()
472{
pfeldman@chromium.orgeccfccf2011-12-02 08:21:57 +0000473 ASSERT(!m_domAgent);
yurys@chromium.org29626f82011-03-04 15:15:45 +0000474 m_instrumentingAgents->setInspectorCSSAgent(0);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000475 reset();
476}
477
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000478void InspectorCSSAgent::setFrontend(InspectorFrontend* frontend)
479{
480 ASSERT(!m_frontend);
481 m_frontend = frontend->css();
482}
483
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000484void InspectorCSSAgent::clearFrontend()
485{
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000486 ASSERT(m_frontend);
487 m_frontend = 0;
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000488 clearPseudoState(true);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000489 String errorString;
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000490 stopSelectorProfilerImpl(&errorString);
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000491}
492
pfeldman@chromium.orgeccfccf2011-12-02 08:21:57 +0000493void InspectorCSSAgent::discardAgent()
494{
495 m_domAgent->setDOMListener(0);
496 m_domAgent = 0;
497}
498
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000499void InspectorCSSAgent::restore()
500{
501 if (m_state->getBoolean(CSSAgentState::cssAgentEnabled)) {
502 ErrorString error;
503 enable(&error);
504 }
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000505 if (m_state->getBoolean(CSSAgentState::isSelectorProfiling)) {
506 String errorString;
507 startSelectorProfiler(&errorString);
508 }
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000509}
510
apavlov@chromium.org6dbb39d2010-11-10 17:12:45 +0000511void InspectorCSSAgent::reset()
512{
513 m_idToInspectorStyleSheet.clear();
514 m_cssStyleSheetToInspectorStyleSheet.clear();
515 m_nodeToInspectorStyleSheet.clear();
516 m_documentToInspectorStyleSheet.clear();
517}
518
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000519void InspectorCSSAgent::enable(ErrorString*)
520{
521 m_state->setBoolean(CSSAgentState::cssAgentEnabled, true);
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000522}
523
524void InspectorCSSAgent::disable(ErrorString*)
525{
526 m_state->setBoolean(CSSAgentState::cssAgentEnabled, false);
527}
528
529void InspectorCSSAgent::mediaQueryResultChanged()
530{
531 if (m_frontend)
532 m_frontend->mediaQueryResultChanged();
533}
534
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000535bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType)
536{
537 if (m_lastElementWithPseudoState != element)
538 return false;
539
540 switch (pseudoType) {
541 case CSSSelector::PseudoActive:
542 return m_lastPseudoState & PseudoActive;
543 case CSSSelector::PseudoFocus:
544 return m_lastPseudoState & PseudoFocus;
545 case CSSSelector::PseudoHover:
546 return m_lastPseudoState & PseudoHover;
547 case CSSSelector::PseudoVisited:
548 return m_lastPseudoState & PseudoVisited;
549 default:
550 return false;
551 }
552}
553
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000554void InspectorCSSAgent::recalcStyleForPseudoStateIfNeeded(Element* element, InspectorArray* forcedPseudoClasses)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000555{
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000556 unsigned forcePseudoState = computePseudoClassMask(forcedPseudoClasses);
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000557 bool needStyleRecalc = element != m_lastElementWithPseudoState || forcePseudoState != m_lastPseudoState;
558 m_lastPseudoState = forcePseudoState;
559 m_lastElementWithPseudoState = element;
560 if (needStyleRecalc)
561 element->ownerDocument()->styleSelectorChanged(RecalcStyleImmediately);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000562}
563
yurys@chromium.orgc22f7452012-02-06 07:39:40 +0000564void InspectorCSSAgent::getMatchedStylesForNode(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>* forcedPseudoClasses, const bool* needPseudo, const bool* needInherited, RefPtr<InspectorArray>& matchedCSSRules, RefPtr<InspectorArray>& pseudoIdRules, RefPtr<InspectorArray>& inheritedEntries)
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000565{
566 Element* element = elementForId(errorString, nodeId);
567 if (!element)
568 return;
569
570 recalcStyleForPseudoStateIfNeeded(element, forcedPseudoClasses ? forcedPseudoClasses->get() : 0);
571
572 // Matched rules.
573 CSSStyleSelector* selector = element->ownerDocument()->styleSelector();
574 RefPtr<CSSRuleList> matchedRules = selector->styleRulesForElement(element, CSSStyleSelector::AllCSSRules);
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000575 matchedCSSRules = buildArrayForRuleList(matchedRules.get());
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000576
577 // Pseudo elements.
578 if (!needPseudo || *needPseudo) {
579 RefPtr<InspectorArray> pseudoElements = InspectorArray::create();
580 for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
581 RefPtr<CSSRuleList> matchedRules = selector->pseudoStyleRulesForElement(element, pseudoId, CSSStyleSelector::AllCSSRules);
582 if (matchedRules && matchedRules->length()) {
583 RefPtr<InspectorObject> pseudoStyles = InspectorObject::create();
584 pseudoStyles->setNumber("pseudoId", static_cast<int>(pseudoId));
585 pseudoStyles->setArray("rules", buildArrayForRuleList(matchedRules.get()));
586 pseudoElements->pushObject(pseudoStyles.release());
587 }
588 }
589
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000590 pseudoIdRules = pseudoElements.release();
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000591 }
592
593 // Inherited styles.
594 if (!needInherited || *needInherited) {
595 RefPtr<InspectorArray> inheritedStyles = InspectorArray::create();
596 Element* parentElement = element->parentElement();
597 while (parentElement) {
598 RefPtr<InspectorObject> parentStyle = InspectorObject::create();
599 if (parentElement->style() && parentElement->style()->length()) {
600 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
601 if (styleSheet)
602 parentStyle->setObject("inlineStyle", styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
603 }
604
605 CSSStyleSelector* parentSelector = parentElement->ownerDocument()->styleSelector();
606 RefPtr<CSSRuleList> parentMatchedRules = parentSelector->styleRulesForElement(parentElement, CSSStyleSelector::AllCSSRules);
607 parentStyle->setArray("matchedCSSRules", buildArrayForRuleList(parentMatchedRules.get()));
608 inheritedStyles->pushObject(parentStyle.release());
609 parentElement = parentElement->parentElement();
610 }
611
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000612 inheritedEntries = inheritedStyles.release();
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000613 }
614}
615
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +0000616void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<InspectorObject>& inlineStyle, RefPtr<InspectorObject>& attributesStyle)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000617{
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +0000618 Element* element = elementForId(errorString, nodeId);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000619 if (!element)
620 return;
621
622 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
623 if (!styleSheet)
624 return;
625
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000626 inlineStyle = styleSheet->buildObjectForStyle(element->style());
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +0000627 RefPtr<InspectorObject> attributes = buildObjectForAttributesStyle(element);
628 attributesStyle = attributes ? attributes.release() : 0;
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000629}
630
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000631void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>* forcedPseudoClasses, RefPtr<InspectorArray>& style)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000632{
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +0000633 Element* element = elementForId(errorString, nodeId);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000634 if (!element)
635 return;
636
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000637 recalcStyleForPseudoStateIfNeeded(element, forcedPseudoClasses ? forcedPseudoClasses->get() : 0);
638
antti@apple.comac019f32012-02-10 18:22:24 +0000639 RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(element, true);
yurys@chromium.org418f91f2010-12-24 17:51:25 +0000640 RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000641 style = inspectorStyle->buildArrayForComputedStyle();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000642}
643
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000644void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<InspectorArray>& styleInfos)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000645{
pfeldman@chromium.org840f3482011-02-11 15:23:26 +0000646 Vector<Document*> documents = m_domAgent->documents();
647 for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000648 StyleSheetList* list = (*it)->styleSheets();
649 for (unsigned i = 0; i < list->length(); ++i) {
650 StyleSheet* styleSheet = list->item(i);
apavlov@chromium.orgbe789cf2011-05-18 13:32:07 +0000651 if (styleSheet->isCSSStyleSheet())
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000652 collectStyleSheets(static_cast<CSSStyleSheet*>(styleSheet), styleInfos.get());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000653 }
654 }
655}
656
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000657void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<InspectorObject>& styleSheetObject)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000658{
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000659 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000660 if (!inspectorStyleSheet)
661 return;
662
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000663 styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000664}
665
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000666void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
pfeldman@chromium.org4ee21ff2010-11-24 10:11:39 +0000667{
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000668 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
pfeldman@chromium.org4ee21ff2010-11-24 10:11:39 +0000669 if (!inspectorStyleSheet)
670 return;
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000671
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000672 inspectorStyleSheet->getText(result);
pfeldman@chromium.org4ee21ff2010-11-24 10:11:39 +0000673}
674
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000675void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000676{
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000677 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
678 if (!inspectorStyleSheet)
679 return;
680
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000681 ExceptionCode ec = 0;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000682 m_domAgent->history()->perform(adoptPtr(new SetStyleSheetTextAction(inspectorStyleSheet, text)), ec);
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000683 *errorString = InspectorDOMAgent::toErrorString(ec);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000684}
685
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000686void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<InspectorObject>& result)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000687{
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000688 InspectorCSSId compoundId(fullStyleId);
689 ASSERT(!compoundId.isEmpty());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000690
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000691 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000692 if (!inspectorStyleSheet)
693 return;
694
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000695 ExceptionCode ec = 0;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000696 bool success = m_domAgent->history()->perform(adoptPtr(new SetPropertyTextAction(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite)), ec);
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000697 if (success)
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000698 result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000699 *errorString = InspectorDOMAgent::toErrorString(ec);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000700}
701
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000702void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<InspectorObject>& result)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000703{
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000704 InspectorCSSId compoundId(fullStyleId);
705 ASSERT(!compoundId.isEmpty());
706
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000707 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000708 if (!inspectorStyleSheet)
709 return;
710
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000711 ExceptionCode ec = 0;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000712 bool success = m_domAgent->history()->perform(adoptPtr(new TogglePropertyAction(inspectorStyleSheet, compoundId, propertyIndex, disable)), ec);
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000713 if (success)
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000714 result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000715 *errorString = InspectorDOMAgent::toErrorString(ec);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000716}
717
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000718void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<InspectorObject>& result)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000719{
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000720 InspectorCSSId compoundId(fullRuleId);
721 ASSERT(!compoundId.isEmpty());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000722
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000723 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000724 if (!inspectorStyleSheet)
725 return;
726
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000727 ExceptionCode ec = 0;
728 bool success = m_domAgent->history()->perform(adoptPtr(new SetRuleSelectorAction(inspectorStyleSheet, compoundId, selector)), ec);
729 if (success)
730 result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
731 *errorString = InspectorDOMAgent::toErrorString(ec);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000732
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000733 if (success)
734 result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000735}
736
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000737void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<InspectorObject>& result)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000738{
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000739 Node* node = m_domAgent->assertNode(errorString, contextNodeId);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000740 if (!node)
741 return;
742
743 InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000744 if (!inspectorStyleSheet) {
745 *errorString = "No target stylesheet found";
apavlov@chromium.orgd41cebd2011-01-20 15:46:28 +0000746 return;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000747 }
apavlov@chromium.org6dbb39d2010-11-10 17:12:45 +0000748
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000749 ExceptionCode ec = 0;
750 OwnPtr<AddRuleAction> action = adoptPtr(new AddRuleAction(inspectorStyleSheet, selector));
751 AddRuleAction* rawAction = action.get();
752 bool success = m_domAgent->history()->perform(action.release(), ec);
753 if (!success) {
754 *errorString = InspectorDOMAgent::toErrorString(ec);
755 return;
756 }
757
758 InspectorCSSId ruleId = rawAction->newRuleId();
759 CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
760 result = inspectorStyleSheet->buildObjectForRule(rule);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000761}
762
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000763void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<InspectorArray>& cssProperties)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000764{
765 RefPtr<InspectorArray> properties = InspectorArray::create();
766 for (int i = 0; i < numCSSProperties; ++i)
767 properties->pushString(propertyNameStrings[i]);
768
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000769 cssProperties = properties.release();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000770}
771
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000772void InspectorCSSAgent::startSelectorProfiler(ErrorString*)
773{
774 m_currentSelectorProfile = adoptPtr(new SelectorProfile());
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000775 m_state->setBoolean(CSSAgentState::isSelectorProfiling, true);
776}
777
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000778void InspectorCSSAgent::stopSelectorProfiler(ErrorString* errorString, RefPtr<InspectorObject>& result)
779{
780 stopSelectorProfilerImpl(errorString, &result);
781}
782
783void InspectorCSSAgent::stopSelectorProfilerImpl(ErrorString*, RefPtr<InspectorObject>* result)
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000784{
785 if (!m_state->getBoolean(CSSAgentState::isSelectorProfiling))
786 return;
787 m_state->setBoolean(CSSAgentState::isSelectorProfiling, false);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000788 if (m_frontend && result)
789 *result = m_currentSelectorProfile->toInspectorObject();
790 m_currentSelectorProfile.clear();
791}
792
793void InspectorCSSAgent::willMatchRule(const CSSStyleRule* rule)
794{
apavlov@chromium.org1ed8ba32012-01-19 16:39:55 +0000795 if (m_currentSelectorProfile)
796 m_currentSelectorProfile->startSelector(rule);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000797}
798
799void InspectorCSSAgent::didMatchRule(bool matched)
800{
apavlov@chromium.org1ed8ba32012-01-19 16:39:55 +0000801 if (m_currentSelectorProfile)
802 m_currentSelectorProfile->commitSelector(matched);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000803}
804
805void InspectorCSSAgent::willProcessRule(const CSSStyleRule* rule)
806{
apavlov@chromium.org1ed8ba32012-01-19 16:39:55 +0000807 if (m_currentSelectorProfile)
808 m_currentSelectorProfile->startSelector(rule);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000809}
810
811void InspectorCSSAgent::didProcessRule()
812{
apavlov@chromium.org1ed8ba32012-01-19 16:39:55 +0000813 if (m_currentSelectorProfile)
814 m_currentSelectorProfile->commitSelectorTime();
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000815}
816
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000817InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
818{
819 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
820 if (it == m_nodeToInspectorStyleSheet.end()) {
821 CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
822 if (!style)
823 return 0;
824
825 String newStyleSheetId = String::number(m_lastStyleSheetId++);
pfeldman@chromium.orga1a70a42012-02-14 08:50:19 +0000826 RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(newStyleSheetId, element, "regular", this);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000827 m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
828 m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
829 return inspectorStyleSheet.get();
830 }
831
832 return it->second.get();
833}
834
pfeldman@chromium.org7e420b52011-03-21 07:54:32 +0000835Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000836{
837 Node* node = m_domAgent->nodeForId(nodeId);
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +0000838 if (!node) {
caseq@chromium.orgc2485692011-03-31 15:21:33 +0000839 *errorString = "No node with given id found";
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +0000840 return 0;
841 }
842 if (node->nodeType() != Node::ELEMENT_NODE) {
caseq@chromium.orgc2485692011-03-31 15:21:33 +0000843 *errorString = "Not an element node";
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +0000844 return 0;
845 }
846 return static_cast<Element*>(node);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000847}
848
apavlov@chromium.orgbe789cf2011-05-18 13:32:07 +0000849void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, InspectorArray* result)
850{
851 InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
852 result->pushObject(inspectorStyleSheet->buildObjectForStyleSheetInfo());
853 for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
andreas.kling@nokia.com1678e2b2011-10-14 18:36:31 +0000854 CSSRule* rule = styleSheet->item(i);
855 if (rule->isImportRule()) {
856 CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet();
857 if (importedStyleSheet)
858 collectStyleSheets(importedStyleSheet, result);
apavlov@chromium.orgbe789cf2011-05-18 13:32:07 +0000859 }
860 }
861}
862
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000863InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
864{
865 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
866 if (!inspectorStyleSheet) {
867 String id = String::number(m_lastStyleSheetId++);
rolandsteiner@chromium.orgd4ecb972011-11-08 19:04:43 +0000868 Document* document = styleSheet->findDocument();
pfeldman@chromium.orga1a70a42012-02-14 08:50:19 +0000869 inspectorStyleSheet = InspectorStyleSheet::create(id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000870 m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
871 m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
872 }
873 return inspectorStyleSheet.get();
874}
875
876InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
877{
878 if (!document) {
879 ASSERT(!createIfAbsent);
880 return 0;
881 }
882
883 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
884 if (inspectorStyleSheet || !createIfAbsent)
885 return inspectorStyleSheet.get();
886
887 ExceptionCode ec = 0;
888 RefPtr<Element> styleElement = document->createElement("style", ec);
889 if (!ec)
890 styleElement->setAttribute("type", "text/css", ec);
apavlov@chromium.orgd41cebd2011-01-20 15:46:28 +0000891 if (!ec) {
892 ContainerNode* targetNode;
893 // HEAD is absent in ImageDocuments, for example.
894 if (document->head())
895 targetNode = document->head();
896 else if (document->body())
897 targetNode = document->body();
898 else
899 return 0;
apavlov@chromium.org31442e82012-03-05 10:44:40 +0000900
901 InlineStyleOverrideScope overrideScope(document);
apavlov@chromium.orgd41cebd2011-01-20 15:46:28 +0000902 targetNode->appendChild(styleElement, ec);
903 }
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000904 if (ec)
905 return 0;
906 StyleSheetList* styleSheets = document->styleSheets();
907 StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1);
apavlov@chromium.org31442e82012-03-05 10:44:40 +0000908 if (!styleSheet || !styleSheet->isCSSStyleSheet())
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000909 return 0;
910 CSSStyleSheet* cssStyleSheet = static_cast<CSSStyleSheet*>(styleSheet);
911 String id = String::number(m_lastStyleSheetId++);
pfeldman@chromium.orga1a70a42012-02-14 08:50:19 +0000912 inspectorStyleSheet = InspectorStyleSheet::create(id, cssStyleSheet, "inspector", InspectorDOMAgent::documentURLString(document), this);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000913 m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
914 m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
915 m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
916 return inspectorStyleSheet.get();
917}
918
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000919InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000920{
921 IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +0000922 if (it == m_idToInspectorStyleSheet.end()) {
caseq@chromium.orgc2485692011-03-31 15:21:33 +0000923 *errorString = "No style sheet with given id found";
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +0000924 return 0;
925 }
926 return it->second.get();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000927}
928
929String InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
930{
931 DEFINE_STATIC_LOCAL(String, userAgent, ("user-agent"));
932 DEFINE_STATIC_LOCAL(String, user, ("user"));
933 DEFINE_STATIC_LOCAL(String, inspector, ("inspector"));
934
apavlov@chromium.org5c8558e2011-12-28 12:28:04 +0000935 String origin("regular");
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000936 if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
937 origin = userAgent;
938 else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
939 origin = user;
940 else {
941 InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
942 if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
943 origin = inspector;
944 }
945 return origin;
946}
947
948PassRefPtr<InspectorArray> InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
949{
950 RefPtr<InspectorArray> result = InspectorArray::create();
951 if (!ruleList)
952 return result.release();
953
954 for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
955 CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
956 if (!rule)
957 continue;
958
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000959 InspectorStyleSheet* styleSheet = bindStyleSheet(rule->parentStyleSheet());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000960 if (styleSheet)
961 result->pushObject(styleSheet->buildObjectForRule(rule));
962 }
963 return result.release();
964}
965
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +0000966PassRefPtr<InspectorObject> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000967{
kling@webkit.org119bc4e2012-02-04 12:24:19 +0000968 if (!element->isStyledElement())
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +0000969 return 0;
kling@webkit.org119bc4e2012-02-04 12:24:19 +0000970
kling@webkit.org42c11822012-02-05 08:29:38 +0000971 StylePropertySet* attributeStyle = static_cast<StyledElement*>(element)->attributeStyle();
972 if (!attributeStyle)
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +0000973 return 0;
kling@webkit.org119bc4e2012-02-04 12:24:19 +0000974
kling@webkit.org42c11822012-02-05 08:29:38 +0000975 RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), attributeStyle->ensureCSSStyleDeclaration(), 0);
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +0000976 return inspectorStyle->buildObjectForStyle();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000977}
978
979void InspectorCSSAgent::didRemoveDocument(Document* document)
980{
apavlov@chromium.org6dbb39d2010-11-10 17:12:45 +0000981 if (document)
982 m_documentToInspectorStyleSheet.remove(document);
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000983 clearPseudoState(false);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000984}
985
986void InspectorCSSAgent::didRemoveDOMNode(Node* node)
987{
apavlov@chromium.org6dbb39d2010-11-10 17:12:45 +0000988 if (!node)
989 return;
990
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000991 if (m_lastElementWithPseudoState.get() == node) {
992 clearPseudoState(false);
993 return;
994 }
995
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000996 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
997 if (it == m_nodeToInspectorStyleSheet.end())
998 return;
999
1000 m_idToInspectorStyleSheet.remove(it->second->id());
1001 m_nodeToInspectorStyleSheet.remove(node);
1002}
1003
apavlov@chromium.org93e800a2010-12-24 16:39:32 +00001004void InspectorCSSAgent::didModifyDOMAttr(Element* element)
1005{
1006 if (!element)
1007 return;
1008
1009 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1010 if (it == m_nodeToInspectorStyleSheet.end())
1011 return;
1012
1013 it->second->didModifyElementAttribute();
1014}
1015
pfeldman@chromium.orga1a70a42012-02-14 08:50:19 +00001016void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1017{
1018 if (m_frontend)
1019 m_frontend->styleSheetChanged(styleSheet->id());
1020}
1021
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +00001022void InspectorCSSAgent::clearPseudoState(bool recalcStyles)
1023{
commit-queue@webkit.org78b556c2011-08-24 09:07:59 +00001024 RefPtr<Element> element = m_lastElementWithPseudoState;
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +00001025 m_lastElementWithPseudoState = 0;
1026 m_lastPseudoState = 0;
1027 if (recalcStyles && element) {
1028 Document* document = element->ownerDocument();
1029 if (document)
1030 document->styleSelectorChanged(RecalcStyleImmediately);
1031 }
1032}
1033
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001034} // namespace WebCore
1035
1036#endif // ENABLE(INSPECTOR)