blob: 775063d788a3f3a6757e42951a825db6f6c7d44e [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"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000026
27#if ENABLE(INSPECTOR)
28
yurys@chromium.org83110c82012-03-15 16:44:09 +000029#include "InspectorCSSAgent.h"
30
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000031#include "CSSComputedStyleDeclaration.h"
apavlov@chromium.orgbe789cf2011-05-18 13:32:07 +000032#include "CSSImportRule.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000033#include "CSSPropertyNames.h"
34#include "CSSPropertySourceData.h"
35#include "CSSRule.h"
36#include "CSSRuleList.h"
37#include "CSSStyleRule.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000038#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.org47bfc332012-03-26 14:04:50 +000045#include "InspectorTypeBuilder.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000046#include "InspectorValues.h"
yurys@chromium.org29626f82011-03-04 15:15:45 +000047#include "InstrumentingAgents.h"
rniwa@webkit.org3fc452e2012-08-24 21:46:24 +000048#include "NamedFlowCollection.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000049#include "Node.h"
pfeldman@chromium.org840f3482011-02-11 15:23:26 +000050#include "NodeList.h"
commit-queue@webkit.orge2bb32c2012-08-10 09:58:35 +000051#include "RenderRegion.h"
antti@apple.comf6601802012-02-03 22:41:09 +000052#include "StylePropertySet.h"
pfeldman@chromium.orga7128942012-07-25 13:48:47 +000053#include "StylePropertyShorthand.h"
alexis.menard@openbossa.orge6db2f62012-04-25 15:49:08 +000054#include "StyleResolver.h"
antti@apple.com8be9b562012-02-28 17:44:18 +000055#include "StyleRule.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000056#include "StyleSheetList.h"
commit-queue@webkit.org285994b2012-07-24 12:00:33 +000057#include "WebKitNamedFlow.h"
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000058
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000059#include <wtf/CurrentTime.h>
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000060#include <wtf/HashSet.h>
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000061#include <wtf/Vector.h>
62#include <wtf/text/CString.h>
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000063#include <wtf/text/StringConcatenate.h>
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000064
apavlov@chromium.orgad517d02011-12-15 09:23:19 +000065namespace CSSAgentState {
66static const char cssAgentEnabled[] = "cssAgentEnabled";
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000067static const char isSelectorProfiling[] = "isSelectorProfiling";
apavlov@chromium.orgad517d02011-12-15 09:23:19 +000068}
69
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +000070namespace WebCore {
71
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +000072enum ForcePseudoClassFlags {
73 PseudoNone = 0,
74 PseudoHover = 1 << 0,
75 PseudoFocus = 1 << 1,
76 PseudoActive = 1 << 2,
77 PseudoVisited = 1 << 3
78};
79
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000080struct RuleMatchData {
81 String selector;
82 String url;
83 unsigned lineNumber;
84 double startTime;
85};
86
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000087struct RuleMatchingStats {
88 RuleMatchingStats()
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000089 : lineNumber(0), totalTime(0.0), hits(0), matches(0)
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000090 {
91 }
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000092 RuleMatchingStats(const RuleMatchData& data, double totalTime, unsigned hits, unsigned matches)
93 : selector(data.selector), url(data.url), lineNumber(data.lineNumber), totalTime(totalTime), hits(hits), matches(matches)
apavlov@chromium.orgba905e82011-12-19 15:14:14 +000094 {
95 }
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +000096
97 String selector;
98 String url;
99 unsigned lineNumber;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000100 double totalTime;
101 unsigned hits;
102 unsigned matches;
103};
104
105class SelectorProfile {
zoltan@webkit.org2eb7bec2012-09-14 09:12:48 +0000106 WTF_MAKE_FAST_ALLOCATED;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000107public:
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000108 SelectorProfile()
109 : m_totalMatchingTimeMs(0.0)
110 {
111 }
112 virtual ~SelectorProfile()
113 {
114 }
115
116 double totalMatchingTimeMs() const { return m_totalMatchingTimeMs; }
117
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000118 String makeKey();
119 void startSelector(const CSSStyleRule*);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000120 void commitSelector(bool);
121 void commitSelectorTime();
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000122 PassRefPtr<TypeBuilder::CSS::SelectorProfile> toInspectorObject() const;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000123
124private:
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000125
126 // Key is "selector?url:line".
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000127 typedef HashMap<String, RuleMatchingStats> RuleMatchingStatsMap;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000128
129 double m_totalMatchingTimeMs;
130 RuleMatchingStatsMap m_ruleMatchingStats;
131 RuleMatchData m_currentMatchData;
132};
133
134
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000135static unsigned computePseudoClassMask(InspectorArray* pseudoClassArray)
136{
abarth@webkit.orgf6d1b8c2012-08-29 07:38:10 +0000137 DEFINE_STATIC_LOCAL(String, active, (ASCIILiteral("active")));
138 DEFINE_STATIC_LOCAL(String, hover, (ASCIILiteral("hover")));
139 DEFINE_STATIC_LOCAL(String, focus, (ASCIILiteral("focus")));
140 DEFINE_STATIC_LOCAL(String, visited, (ASCIILiteral("visited")));
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000141 if (!pseudoClassArray || !pseudoClassArray->length())
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000142 return PseudoNone;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000143
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000144 unsigned result = PseudoNone;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000145 for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
146 RefPtr<InspectorValue> pseudoClassValue = pseudoClassArray->get(i);
147 String pseudoClass;
148 bool success = pseudoClassValue->asString(&pseudoClass);
149 if (!success)
150 continue;
151 if (pseudoClass == active)
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000152 result |= PseudoActive;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000153 else if (pseudoClass == hover)
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000154 result |= PseudoHover;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000155 else if (pseudoClass == focus)
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000156 result |= PseudoFocus;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000157 else if (pseudoClass == visited)
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000158 result |= PseudoVisited;
apavlov@chromium.org6678c9b2011-06-28 12:07:48 +0000159 }
160
161 return result;
162}
163
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000164inline String SelectorProfile::makeKey()
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000165{
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000166 return makeString(m_currentMatchData.selector, "?", m_currentMatchData.url, ":", String::number(m_currentMatchData.lineNumber));
167}
168
169inline void SelectorProfile::startSelector(const CSSStyleRule* rule)
170{
171 m_currentMatchData.selector = rule->selectorText();
172 CSSStyleSheet* styleSheet = rule->parentStyleSheet();
173 String url = emptyString();
174 if (styleSheet) {
175 url = InspectorStyleSheet::styleSheetURL(styleSheet);
176 if (url.isEmpty())
antti@apple.comfe126eb2012-04-25 22:42:47 +0000177 url = InspectorDOMAgent::documentURLString(styleSheet->ownerDocument());
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000178 }
179 m_currentMatchData.url = url;
antti@apple.com972c0822012-02-28 09:38:51 +0000180 m_currentMatchData.lineNumber = rule->styleRule()->sourceLine();
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000181 m_currentMatchData.startTime = WTF::currentTimeMS();
182}
183
184inline void SelectorProfile::commitSelector(bool matched)
185{
186 double matchTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTime;
187 m_totalMatchingTimeMs += matchTimeMs;
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000188
caio.oliveira@openbossa.org4c11ee02012-03-29 18:48:23 +0000189 RuleMatchingStatsMap::AddResult result = m_ruleMatchingStats.add(makeKey(), RuleMatchingStats(m_currentMatchData, matchTimeMs, 1, matched ? 1 : 0));
190 if (!result.isNewEntry) {
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000191 result.iterator->value.totalTime += matchTimeMs;
192 result.iterator->value.hits += 1;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000193 if (matched)
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000194 result.iterator->value.matches += 1;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000195 }
196}
197
198inline void SelectorProfile::commitSelectorTime()
199{
200 double processingTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTime;
201 m_totalMatchingTimeMs += processingTimeMs;
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000202
203 RuleMatchingStatsMap::iterator it = m_ruleMatchingStats.find(makeKey());
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000204 if (it == m_ruleMatchingStats.end())
205 return;
206
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000207 it->value.totalTime += processingTimeMs;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000208}
209
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000210PassRefPtr<TypeBuilder::CSS::SelectorProfile> SelectorProfile::toInspectorObject() const
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000211{
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000212 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry> > selectorProfileData = TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry>::create();
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000213 for (RuleMatchingStatsMap::const_iterator it = m_ruleMatchingStats.begin(); it != m_ruleMatchingStats.end(); ++it) {
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000214 RefPtr<TypeBuilder::CSS::SelectorProfileEntry> entry = TypeBuilder::CSS::SelectorProfileEntry::create()
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000215 .setSelector(it->value.selector)
216 .setUrl(it->value.url)
217 .setLineNumber(it->value.lineNumber)
218 .setTime(it->value.totalTime)
219 .setHitCount(it->value.hits)
220 .setMatchCount(it->value.matches);
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000221 selectorProfileData->addItem(entry.release());
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000222 }
223
224 RefPtr<TypeBuilder::CSS::SelectorProfile> result = TypeBuilder::CSS::SelectorProfile::create()
225 .setTotalTime(totalMatchingTimeMs())
apavlov@chromium.org5ee19fd2012-01-11 15:14:44 +0000226 .setData(selectorProfileData);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000227 return result.release();
228}
229
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000230class UpdateRegionLayoutTask {
231public:
232 UpdateRegionLayoutTask(InspectorCSSAgent*);
233 void scheduleFor(WebKitNamedFlow*, int documentNodeId);
234 void unschedule(WebKitNamedFlow*);
235 void reset();
236 void onTimer(Timer<UpdateRegionLayoutTask>*);
237
238private:
239 InspectorCSSAgent* m_cssAgent;
240 Timer<UpdateRegionLayoutTask> m_timer;
241 HashMap<WebKitNamedFlow*, int> m_namedFlows;
242};
243
244UpdateRegionLayoutTask::UpdateRegionLayoutTask(InspectorCSSAgent* cssAgent)
245 : m_cssAgent(cssAgent)
246 , m_timer(this, &UpdateRegionLayoutTask::onTimer)
247{
248}
249
250void UpdateRegionLayoutTask::scheduleFor(WebKitNamedFlow* namedFlow, int documentNodeId)
251{
252 m_namedFlows.add(namedFlow, documentNodeId);
253
254 if (!m_timer.isActive())
255 m_timer.startOneShot(0);
256}
257
258void UpdateRegionLayoutTask::unschedule(WebKitNamedFlow* namedFlow)
259{
260 m_namedFlows.remove(namedFlow);
261}
262
263void UpdateRegionLayoutTask::reset()
264{
265 m_timer.stop();
266 m_namedFlows.clear();
267}
268
269void UpdateRegionLayoutTask::onTimer(Timer<UpdateRegionLayoutTask>*)
270{
271 // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed.
272 Vector<std::pair<WebKitNamedFlow*, int> > namedFlows;
273
274 for (HashMap<WebKitNamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it)
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000275 namedFlows.append(std::make_pair(it->key, it->value));
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000276
277 for (unsigned i = 0, size = namedFlows.size(); i < size; ++i) {
278 WebKitNamedFlow* namedFlow = namedFlows.at(i).first;
279 int documentNodeId = namedFlows.at(i).second;
280
281 if (m_namedFlows.contains(namedFlow)) {
282 m_cssAgent->regionLayoutUpdated(namedFlow, documentNodeId);
283 m_namedFlows.remove(namedFlow);
284 }
285 }
286
287 if (!m_namedFlows.isEmpty() && !m_timer.isActive())
288 m_timer.startOneShot(0);
289}
290
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000291class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
292 WTF_MAKE_NONCOPYABLE(StyleSheetAction);
293public:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000294 StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000295 : InspectorHistory::Action(name)
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000296 , m_styleSheet(styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000297 {
298 }
299
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000300protected:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000301 RefPtr<InspectorStyleSheet> m_styleSheet;
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000302};
303
304class InspectorCSSAgent::SetStyleSheetTextAction : public InspectorCSSAgent::StyleSheetAction {
305 WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
306public:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000307 SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
308 : InspectorCSSAgent::StyleSheetAction("SetStyleSheetText", styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000309 , m_text(text)
310 {
311 }
312
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000313 virtual bool perform(ExceptionCode& ec)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000314 {
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000315 if (!m_styleSheet->getText(&m_oldText))
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000316 return false;
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000317 return redo(ec);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000318 }
319
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000320 virtual bool undo(ExceptionCode&)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000321 {
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000322 if (m_styleSheet->setText(m_oldText)) {
323 m_styleSheet->reparseStyleSheet(m_oldText);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000324 return true;
325 }
326 return false;
327 }
328
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000329 virtual bool redo(ExceptionCode&)
330 {
331 if (m_styleSheet->setText(m_text)) {
332 m_styleSheet->reparseStyleSheet(m_text);
333 return true;
334 }
335 return false;
336 }
337
pfeldman@chromium.orga1a70a42012-02-14 08:50:19 +0000338 virtual String mergeId()
339 {
340 return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
341 }
342
343 virtual void merge(PassOwnPtr<Action> action)
344 {
345 ASSERT(action->mergeId() == mergeId());
346
347 SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get());
348 m_text = other->m_text;
349 }
350
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000351private:
352 String m_text;
353 String m_oldText;
354};
355
356class InspectorCSSAgent::SetPropertyTextAction : public InspectorCSSAgent::StyleSheetAction {
357 WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
358public:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000359 SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
360 : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000361 , m_cssId(cssId)
362 , m_propertyIndex(propertyIndex)
363 , m_text(text)
364 , m_overwrite(overwrite)
365 {
366 }
367
368 virtual String toString()
369 {
370 return mergeId() + ": " + m_oldText + " -> " + m_text;
371 }
372
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000373 virtual bool perform(ExceptionCode& ec)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000374 {
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000375 return redo(ec);
376 }
377
378 virtual bool undo(ExceptionCode& ec)
379 {
380 String placeholder;
381 return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, ec);
382 }
383
384 virtual bool redo(ExceptionCode& ec)
385 {
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000386 String oldText;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000387 bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, ec);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000388 m_oldText = oldText.stripWhiteSpace();
389 // FIXME: remove this once the model handles this case.
benjamin@webkit.org127cec2c2012-04-30 21:32:44 +0000390 if (!m_oldText.endsWith(';'))
abarth@webkit.org96a2c952012-08-31 01:25:43 +0000391 m_oldText.append(';');
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000392 return result;
393 }
394
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000395 virtual String mergeId()
396 {
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000397 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 +0000398 }
399
400 virtual void merge(PassOwnPtr<Action> action)
401 {
402 ASSERT(action->mergeId() == mergeId());
403
404 SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
405 m_text = other->m_text;
406 }
407
408private:
409 InspectorCSSId m_cssId;
410 unsigned m_propertyIndex;
411 String m_text;
412 String m_oldText;
413 bool m_overwrite;
414};
415
416class InspectorCSSAgent::TogglePropertyAction : public InspectorCSSAgent::StyleSheetAction {
417 WTF_MAKE_NONCOPYABLE(TogglePropertyAction);
418public:
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000419 TogglePropertyAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, bool disable)
420 : InspectorCSSAgent::StyleSheetAction("ToggleProperty", styleSheet)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000421 , m_cssId(cssId)
422 , m_propertyIndex(propertyIndex)
423 , m_disable(disable)
424 {
425 }
426
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000427 virtual bool perform(ExceptionCode& ec)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000428 {
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000429 return redo(ec);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000430 }
431
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000432 virtual bool undo(ExceptionCode& ec)
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000433 {
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000434 return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, !m_disable, ec);
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000435 }
436
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000437 virtual bool redo(ExceptionCode& ec)
438 {
439 return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, m_disable, ec);
440 }
441
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000442private:
443 InspectorCSSId m_cssId;
444 unsigned m_propertyIndex;
445 bool m_disable;
446};
447
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000448class InspectorCSSAgent::SetRuleSelectorAction : public InspectorCSSAgent::StyleSheetAction {
449 WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
450public:
451 SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
452 : InspectorCSSAgent::StyleSheetAction("SetRuleSelector", styleSheet)
453 , m_cssId(cssId)
454 , m_selector(selector)
455 {
456 }
457
458 virtual bool perform(ExceptionCode& ec)
459 {
460 m_oldSelector = m_styleSheet->ruleSelector(m_cssId, ec);
461 if (ec)
462 return false;
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000463 return redo(ec);
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000464 }
465
466 virtual bool undo(ExceptionCode& ec)
467 {
468 return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, ec);
469 }
470
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000471 virtual bool redo(ExceptionCode& ec)
472 {
473 return m_styleSheet->setRuleSelector(m_cssId, m_selector, ec);
474 }
475
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000476private:
477 InspectorCSSId m_cssId;
478 String m_selector;
479 String m_oldSelector;
480};
481
482class InspectorCSSAgent::AddRuleAction : public InspectorCSSAgent::StyleSheetAction {
483 WTF_MAKE_NONCOPYABLE(AddRuleAction);
484public:
485 AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
486 : InspectorCSSAgent::StyleSheetAction("AddRule", styleSheet)
487 , m_selector(selector)
488 {
489 }
490
491 virtual bool perform(ExceptionCode& ec)
492 {
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000493 return redo(ec);
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000494 }
495
496 virtual bool undo(ExceptionCode& ec)
497 {
498 return m_styleSheet->deleteRule(m_newId, ec);
499 }
500
pfeldman@chromium.orga9730c42012-02-15 09:12:15 +0000501 virtual bool redo(ExceptionCode& ec)
502 {
503 CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, ec);
504 if (ec)
505 return false;
506 m_newId = m_styleSheet->ruleId(cssStyleRule);
507 return true;
508 }
509
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000510 InspectorCSSId newRuleId() { return m_newId; }
511
512private:
513 InspectorCSSId m_newId;
514 String m_selector;
515 String m_oldSelector;
516};
517
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000518// static
andreas.kling@nokia.comf04e49c2011-10-14 21:33:49 +0000519CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000520{
akling@apple.comc713db32012-11-22 03:45:40 +0000521 if (rule->type() != CSSRule::STYLE_RULE)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000522 return 0;
523 return static_cast<CSSStyleRule*>(rule);
524}
525
pfeldman@chromium.orgccc8cd932011-11-28 14:41:48 +0000526InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state, InspectorDOMAgent* domAgent)
pfeldman@chromium.org2f44edb2011-11-29 14:43:10 +0000527 : InspectorBaseAgent<InspectorCSSAgent>("CSS", instrumentingAgents, state)
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000528 , m_frontend(0)
yurys@chromium.org29626f82011-03-04 15:15:45 +0000529 , m_domAgent(domAgent)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000530 , m_lastStyleSheetId(1)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000531{
yurys@chromium.orgd8e367c2011-02-21 14:38:24 +0000532 m_domAgent->setDOMListener(this);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000533}
534
535InspectorCSSAgent::~InspectorCSSAgent()
536{
pfeldman@chromium.orgeccfccf2011-12-02 08:21:57 +0000537 ASSERT(!m_domAgent);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000538 reset();
539}
540
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000541void InspectorCSSAgent::setFrontend(InspectorFrontend* frontend)
542{
543 ASSERT(!m_frontend);
544 m_frontend = frontend->css();
545}
546
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000547void InspectorCSSAgent::clearFrontend()
548{
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000549 ASSERT(m_frontend);
550 m_frontend = 0;
apavlov@chromium.orgd63acd82012-09-13 08:41:26 +0000551 resetNonPersistentData();
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000552 String errorString;
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000553 stopSelectorProfilerImpl(&errorString, false);
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000554}
555
pfeldman@chromium.orgeccfccf2011-12-02 08:21:57 +0000556void InspectorCSSAgent::discardAgent()
557{
558 m_domAgent->setDOMListener(0);
559 m_domAgent = 0;
560}
561
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000562void InspectorCSSAgent::restore()
563{
564 if (m_state->getBoolean(CSSAgentState::cssAgentEnabled)) {
565 ErrorString error;
566 enable(&error);
567 }
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000568 if (m_state->getBoolean(CSSAgentState::isSelectorProfiling)) {
569 String errorString;
570 startSelectorProfiler(&errorString);
571 }
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000572}
573
apavlov@chromium.org6dbb39d2010-11-10 17:12:45 +0000574void InspectorCSSAgent::reset()
575{
576 m_idToInspectorStyleSheet.clear();
577 m_cssStyleSheetToInspectorStyleSheet.clear();
578 m_nodeToInspectorStyleSheet.clear();
579 m_documentToInspectorStyleSheet.clear();
apavlov@chromium.orgd63acd82012-09-13 08:41:26 +0000580 resetNonPersistentData();
581}
582
583void InspectorCSSAgent::resetNonPersistentData()
584{
commit-queue@webkit.org5c25fc42012-08-06 16:39:56 +0000585 m_namedFlowCollectionsRequested.clear();
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000586 if (m_updateRegionLayoutTask)
587 m_updateRegionLayoutTask->reset();
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +0000588 resetPseudoStates();
apavlov@chromium.org6dbb39d2010-11-10 17:12:45 +0000589}
590
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000591void InspectorCSSAgent::enable(ErrorString*)
592{
593 m_state->setBoolean(CSSAgentState::cssAgentEnabled, true);
apavlov@chromium.orgd63acd82012-09-13 08:41:26 +0000594 m_instrumentingAgents->setInspectorCSSAgent(this);
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000595}
596
597void InspectorCSSAgent::disable(ErrorString*)
598{
apavlov@chromium.orgd63acd82012-09-13 08:41:26 +0000599 m_instrumentingAgents->setInspectorCSSAgent(0);
apavlov@chromium.orgad517d02011-12-15 09:23:19 +0000600 m_state->setBoolean(CSSAgentState::cssAgentEnabled, false);
601}
602
603void InspectorCSSAgent::mediaQueryResultChanged()
604{
605 if (m_frontend)
606 m_frontend->mediaQueryResultChanged();
607}
608
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000609void InspectorCSSAgent::didCreateNamedFlow(Document* document, WebKitNamedFlow* namedFlow)
commit-queue@webkit.org5c25fc42012-08-06 16:39:56 +0000610{
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000611 int documentNodeId = documentNodeWithRequestedFlowsId(document);
612 if (!documentNodeId)
commit-queue@webkit.org5c25fc42012-08-06 16:39:56 +0000613 return;
614
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000615 ErrorString errorString;
616 m_frontend->namedFlowCreated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
commit-queue@webkit.org5c25fc42012-08-06 16:39:56 +0000617}
618
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000619void InspectorCSSAgent::willRemoveNamedFlow(Document* document, WebKitNamedFlow* namedFlow)
commit-queue@webkit.org5c25fc42012-08-06 16:39:56 +0000620{
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000621 int documentNodeId = documentNodeWithRequestedFlowsId(document);
622 if (!documentNodeId)
commit-queue@webkit.org5c25fc42012-08-06 16:39:56 +0000623 return;
624
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000625 if (m_updateRegionLayoutTask)
626 m_updateRegionLayoutTask->unschedule(namedFlow);
627
628 m_frontend->namedFlowRemoved(documentNodeId, namedFlow->name().string());
629}
630
631void InspectorCSSAgent::didUpdateRegionLayout(Document* document, WebKitNamedFlow* namedFlow)
632{
633 int documentNodeId = documentNodeWithRequestedFlowsId(document);
634 if (!documentNodeId)
635 return;
636
637 if (!m_updateRegionLayoutTask)
638 m_updateRegionLayoutTask = adoptPtr(new UpdateRegionLayoutTask(this));
639 m_updateRegionLayoutTask->scheduleFor(namedFlow, documentNodeId);
640}
641
642void InspectorCSSAgent::regionLayoutUpdated(WebKitNamedFlow* namedFlow, int documentNodeId)
643{
644 if (namedFlow->flowState() == WebKitNamedFlow::FlowStateNull)
645 return;
646
647 ErrorString errorString;
648 RefPtr<WebKitNamedFlow> protector(namedFlow);
649
650 m_frontend->regionLayoutUpdated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
commit-queue@webkit.org5c25fc42012-08-06 16:39:56 +0000651}
652
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000653bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType)
654{
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +0000655 if (m_nodeIdToForcedPseudoState.isEmpty())
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000656 return false;
657
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +0000658 int nodeId = m_domAgent->boundNodeId(element);
659 if (!nodeId)
660 return false;
661
662 NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
663 if (it == m_nodeIdToForcedPseudoState.end())
664 return false;
665
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000666 unsigned forcedPseudoState = it->value;
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000667 switch (pseudoType) {
668 case CSSSelector::PseudoActive:
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +0000669 return forcedPseudoState & PseudoActive;
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000670 case CSSSelector::PseudoFocus:
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +0000671 return forcedPseudoState & PseudoFocus;
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000672 case CSSSelector::PseudoHover:
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +0000673 return forcedPseudoState & PseudoHover;
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000674 case CSSSelector::PseudoVisited:
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +0000675 return forcedPseudoState & PseudoVisited;
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +0000676 default:
677 return false;
678 }
679}
680
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000681void InspectorCSSAgent::getMatchedStylesForNode(ErrorString* errorString, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> >& matchedCSSRules, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> >& pseudoIdMatches, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> >& inheritedEntries)
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000682{
683 Element* element = elementForId(errorString, nodeId);
684 if (!element)
685 return;
686
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000687 // Matched rules.
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +0000688 StyleResolver* styleResolver = element->ownerDocument()->styleResolver();
689 RefPtr<CSSRuleList> matchedRules = styleResolver->styleRulesForElement(element, StyleResolver::AllCSSRules);
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000690 matchedCSSRules = buildArrayForMatchedRuleList(matchedRules.get(), styleResolver, element);
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000691
692 // Pseudo elements.
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000693 if (!includePseudo || *includePseudo) {
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000694 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> > pseudoElements = TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches>::create();
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000695 for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +0000696 RefPtr<CSSRuleList> matchedRules = styleResolver->pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000697 if (matchedRules && matchedRules->length()) {
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000698 RefPtr<TypeBuilder::CSS::PseudoIdMatches> matches = TypeBuilder::CSS::PseudoIdMatches::create()
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000699 .setPseudoId(static_cast<int>(pseudoId))
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000700 .setMatches(buildArrayForMatchedRuleList(matchedRules.get(), styleResolver, element));
701 pseudoElements->addItem(matches.release());
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000702 }
703 }
704
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000705 pseudoIdMatches = pseudoElements.release();
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000706 }
707
708 // Inherited styles.
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000709 if (!includeInherited || *includeInherited) {
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000710 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> > entries = TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry>::create();
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000711 Element* parentElement = element->parentElement();
712 while (parentElement) {
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000713 StyleResolver* parentStyleResolver = parentElement->ownerDocument()->styleResolver();
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +0000714 RefPtr<CSSRuleList> parentMatchedRules = parentStyleResolver->styleRulesForElement(parentElement, StyleResolver::AllCSSRules);
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000715 RefPtr<TypeBuilder::CSS::InheritedStyleEntry> entry = TypeBuilder::CSS::InheritedStyleEntry::create()
716 .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules.get(), styleResolver, parentElement));
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000717 if (parentElement->style() && parentElement->style()->length()) {
718 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
719 if (styleSheet)
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000720 entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000721 }
722
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000723 entries->addItem(entry.release());
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000724 parentElement = parentElement->parentElement();
725 }
726
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +0000727 inheritedEntries = entries.release();
apavlov@chromium.orgd35f1492011-11-21 12:19:52 +0000728 }
729}
730
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000731void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<TypeBuilder::CSS::CSSStyle>& attributesStyle)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000732{
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +0000733 Element* element = elementForId(errorString, nodeId);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000734 if (!element)
735 return;
736
737 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
738 if (!styleSheet)
739 return;
740
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000741 inlineStyle = styleSheet->buildObjectForStyle(element->style());
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000742 RefPtr<TypeBuilder::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +0000743 attributesStyle = attributes ? attributes.release() : 0;
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000744}
745
apavlov@chromium.orgd728ecd2012-08-13 09:06:15 +0000746void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> >& style)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000747{
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +0000748 Element* element = elementForId(errorString, nodeId);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000749 if (!element)
750 return;
751
antti@apple.comac019f32012-02-10 18:22:24 +0000752 RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(element, true);
yurys@chromium.org418f91f2010-12-24 17:51:25 +0000753 RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000754 style = inspectorStyle->buildArrayForComputedStyle();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000755}
756
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000757void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader> >& styleInfos)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000758{
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000759 styleInfos = TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>::create();
pfeldman@chromium.org840f3482011-02-11 15:23:26 +0000760 Vector<Document*> documents = m_domAgent->documents();
761 for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000762 StyleSheetList* list = (*it)->styleSheets();
763 for (unsigned i = 0; i < list->length(); ++i) {
764 StyleSheet* styleSheet = list->item(i);
apavlov@chromium.orgbe789cf2011-05-18 13:32:07 +0000765 if (styleSheet->isCSSStyleSheet())
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000766 collectStyleSheets(static_cast<CSSStyleSheet*>(styleSheet), styleInfos.get());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000767 }
768 }
769}
770
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000771void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<TypeBuilder::CSS::CSSStyleSheetBody>& styleSheetObject)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000772{
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000773 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000774 if (!inspectorStyleSheet)
775 return;
776
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000777 styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000778}
779
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000780void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
pfeldman@chromium.org4ee21ff2010-11-24 10:11:39 +0000781{
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000782 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
pfeldman@chromium.org4ee21ff2010-11-24 10:11:39 +0000783 if (!inspectorStyleSheet)
784 return;
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000785
pfeldman@chromium.org94451152012-02-07 17:00:32 +0000786 inspectorStyleSheet->getText(result);
pfeldman@chromium.org4ee21ff2010-11-24 10:11:39 +0000787}
788
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000789void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000790{
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000791 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
792 if (!inspectorStyleSheet)
793 return;
794
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000795 ExceptionCode ec = 0;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000796 m_domAgent->history()->perform(adoptPtr(new SetStyleSheetTextAction(inspectorStyleSheet, text)), ec);
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000797 *errorString = InspectorDOMAgent::toErrorString(ec);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000798}
799
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000800void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000801{
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000802 InspectorCSSId compoundId(fullStyleId);
803 ASSERT(!compoundId.isEmpty());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000804
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000805 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000806 if (!inspectorStyleSheet)
807 return;
808
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000809 ExceptionCode ec = 0;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000810 bool success = m_domAgent->history()->perform(adoptPtr(new SetPropertyTextAction(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite)), ec);
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000811 if (success)
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000812 result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000813 *errorString = InspectorDOMAgent::toErrorString(ec);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000814}
815
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000816void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000817{
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000818 InspectorCSSId compoundId(fullStyleId);
819 ASSERT(!compoundId.isEmpty());
820
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000821 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000822 if (!inspectorStyleSheet)
823 return;
824
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000825 ExceptionCode ec = 0;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000826 bool success = m_domAgent->history()->perform(adoptPtr(new TogglePropertyAction(inspectorStyleSheet, compoundId, propertyIndex, disable)), ec);
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000827 if (success)
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000828 result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
pfeldman@chromium.orgb5db6a12012-02-10 13:15:12 +0000829 *errorString = InspectorDOMAgent::toErrorString(ec);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000830}
831
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000832void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000833{
apavlov@chromium.orgfc8a58c2010-10-22 15:04:52 +0000834 InspectorCSSId compoundId(fullRuleId);
835 ASSERT(!compoundId.isEmpty());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000836
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +0000837 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000838 if (!inspectorStyleSheet)
839 return;
840
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000841 ExceptionCode ec = 0;
842 bool success = m_domAgent->history()->perform(adoptPtr(new SetRuleSelectorAction(inspectorStyleSheet, compoundId, selector)), ec);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000843
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000844 if (success)
845 result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000846 *errorString = InspectorDOMAgent::toErrorString(ec);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000847}
848
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000849void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000850{
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000851 Node* node = m_domAgent->assertNode(errorString, contextNodeId);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000852 if (!node)
853 return;
854
855 InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000856 if (!inspectorStyleSheet) {
857 *errorString = "No target stylesheet found";
apavlov@chromium.orgd41cebd2011-01-20 15:46:28 +0000858 return;
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000859 }
apavlov@chromium.org6dbb39d2010-11-10 17:12:45 +0000860
pfeldman@chromium.org8ef57362012-02-13 13:12:15 +0000861 ExceptionCode ec = 0;
862 OwnPtr<AddRuleAction> action = adoptPtr(new AddRuleAction(inspectorStyleSheet, selector));
863 AddRuleAction* rawAction = action.get();
864 bool success = m_domAgent->history()->perform(action.release(), ec);
865 if (!success) {
866 *errorString = InspectorDOMAgent::toErrorString(ec);
867 return;
868 }
869
870 InspectorCSSId ruleId = rawAction->newRuleId();
871 CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
872 result = inspectorStyleSheet->buildObjectForRule(rule);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000873}
874
pfeldman@chromium.orga7128942012-07-25 13:48:47 +0000875void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> >& cssProperties)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000876{
pfeldman@chromium.orga7128942012-07-25 13:48:47 +0000877 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> > properties = TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo>::create();
878 for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
879 CSSPropertyID id = convertToCSSPropertyID(i);
880 RefPtr<TypeBuilder::CSS::CSSPropertyInfo> property = TypeBuilder::CSS::CSSPropertyInfo::create()
benjamin@webkit.org5ab707f2012-08-17 21:24:15 +0000881 .setName(getPropertyNameString(id));
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000882
pfeldman@chromium.orga7128942012-07-25 13:48:47 +0000883 const StylePropertyShorthand& shorthand = shorthandForProperty(id);
884 if (!shorthand.length()) {
885 properties->addItem(property.release());
886 continue;
887 }
888 RefPtr<TypeBuilder::Array<String> > longhands = TypeBuilder::Array<String>::create();
889 for (unsigned j = 0; j < shorthand.length(); ++j) {
890 CSSPropertyID longhandID = shorthand.properties()[j];
benjamin@webkit.org5ab707f2012-08-17 21:24:15 +0000891 longhands->addItem(getPropertyNameString(longhandID));
pfeldman@chromium.orga7128942012-07-25 13:48:47 +0000892 }
893 property->setLonghands(longhands);
894 properties->addItem(property.release());
895 }
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000896 cssProperties = properties.release();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000897}
898
apavlov@chromium.orgd728ecd2012-08-13 09:06:15 +0000899void InspectorCSSAgent::forcePseudoState(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>& forcedPseudoClasses)
900{
901 Element* element = m_domAgent->assertElement(errorString, nodeId);
902 if (!element)
903 return;
904
905 unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses.get());
906 NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000907 unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value;
apavlov@chromium.orgd728ecd2012-08-13 09:06:15 +0000908 bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState;
909 if (!needStyleRecalc)
910 return;
911
912 if (forcedPseudoState)
913 m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
914 else
915 m_nodeIdToForcedPseudoState.remove(nodeId);
916 element->ownerDocument()->styleResolverChanged(RecalcStyleImmediately);
917}
918
commit-queue@webkit.orge2bb32c2012-08-10 09:58:35 +0000919void InspectorCSSAgent::getNamedFlowCollection(ErrorString* errorString, int documentNodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> >& result)
commit-queue@webkit.org6f859512012-07-20 12:34:58 +0000920{
commit-queue@webkit.orge2bb32c2012-08-10 09:58:35 +0000921 Document* document = m_domAgent->assertDocument(errorString, documentNodeId);
commit-queue@webkit.org6f859512012-07-20 12:34:58 +0000922 if (!document)
923 return;
924
commit-queue@webkit.orge2bb32c2012-08-10 09:58:35 +0000925 m_namedFlowCollectionsRequested.add(documentNodeId);
commit-queue@webkit.org65563d42012-09-12 12:07:24 +0000926
commit-queue@webkit.orge2bb32c2012-08-10 09:58:35 +0000927 Vector<RefPtr<WebKitNamedFlow> > namedFlowsVector = document->namedFlows()->namedFlows();
928 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> > namedFlows = TypeBuilder::Array<TypeBuilder::CSS::NamedFlow>::create();
commit-queue@webkit.org5c25fc42012-08-06 16:39:56 +0000929
commit-queue@webkit.orge2bb32c2012-08-10 09:58:35 +0000930 for (Vector<RefPtr<WebKitNamedFlow> >::iterator it = namedFlowsVector.begin(); it != namedFlowsVector.end(); ++it)
931 namedFlows->addItem(buildObjectForNamedFlow(errorString, it->get(), documentNodeId));
commit-queue@webkit.org6f859512012-07-20 12:34:58 +0000932
933 result = namedFlows.release();
934}
935
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000936void InspectorCSSAgent::startSelectorProfiler(ErrorString*)
937{
938 m_currentSelectorProfile = adoptPtr(new SelectorProfile());
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000939 m_state->setBoolean(CSSAgentState::isSelectorProfiling, true);
940}
941
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000942void InspectorCSSAgent::stopSelectorProfiler(ErrorString* errorString, RefPtr<TypeBuilder::CSS::SelectorProfile>& result)
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000943{
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000944 result = stopSelectorProfilerImpl(errorString, true);
loislo@chromium.orgf37187e2011-12-21 05:51:31 +0000945}
946
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000947PassRefPtr<TypeBuilder::CSS::SelectorProfile> InspectorCSSAgent::stopSelectorProfilerImpl(ErrorString*, bool needProfile)
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000948{
949 if (!m_state->getBoolean(CSSAgentState::isSelectorProfiling))
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000950 return 0;
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000951 m_state->setBoolean(CSSAgentState::isSelectorProfiling, false);
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000952 RefPtr<TypeBuilder::CSS::SelectorProfile> result;
953 if (m_frontend && needProfile)
954 result = m_currentSelectorProfile->toInspectorObject();
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000955 m_currentSelectorProfile.clear();
apavlov@chromium.org47bfc332012-03-26 14:04:50 +0000956 return result.release();
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000957}
958
959void InspectorCSSAgent::willMatchRule(const CSSStyleRule* rule)
960{
apavlov@chromium.org1ed8ba32012-01-19 16:39:55 +0000961 if (m_currentSelectorProfile)
962 m_currentSelectorProfile->startSelector(rule);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000963}
964
965void InspectorCSSAgent::didMatchRule(bool matched)
966{
apavlov@chromium.org1ed8ba32012-01-19 16:39:55 +0000967 if (m_currentSelectorProfile)
968 m_currentSelectorProfile->commitSelector(matched);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000969}
970
971void InspectorCSSAgent::willProcessRule(const CSSStyleRule* rule)
972{
apavlov@chromium.org1ed8ba32012-01-19 16:39:55 +0000973 if (m_currentSelectorProfile)
974 m_currentSelectorProfile->startSelector(rule);
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000975}
976
977void InspectorCSSAgent::didProcessRule()
978{
apavlov@chromium.org1ed8ba32012-01-19 16:39:55 +0000979 if (m_currentSelectorProfile)
980 m_currentSelectorProfile->commitSelectorTime();
apavlov@chromium.orgba905e82011-12-19 15:14:14 +0000981}
982
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000983InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
984{
985 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
986 if (it == m_nodeToInspectorStyleSheet.end()) {
987 CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
988 if (!style)
989 return 0;
990
991 String newStyleSheetId = String::number(m_lastStyleSheetId++);
apavlov@chromium.org0c1c3732012-05-25 16:24:48 +0000992 RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_domAgent->pageAgent(), newStyleSheetId, element, TypeBuilder::CSS::StyleSheetOrigin::Regular, this);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000993 m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
994 m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
995 return inspectorStyleSheet.get();
996 }
997
benjamin@webkit.orgee554052012-10-07 23:12:07 +0000998 return it->value.get();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +0000999}
1000
pfeldman@chromium.org7e420b52011-03-21 07:54:32 +00001001Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001002{
1003 Node* node = m_domAgent->nodeForId(nodeId);
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +00001004 if (!node) {
caseq@chromium.orgc2485692011-03-31 15:21:33 +00001005 *errorString = "No node with given id found";
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +00001006 return 0;
1007 }
1008 if (node->nodeType() != Node::ELEMENT_NODE) {
caseq@chromium.orgc2485692011-03-31 15:21:33 +00001009 *errorString = "Not an element node";
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +00001010 return 0;
1011 }
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +00001012 return toElement(node);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001013}
1014
commit-queue@webkit.org65563d42012-09-12 12:07:24 +00001015int InspectorCSSAgent::documentNodeWithRequestedFlowsId(Document* document)
1016{
1017 int documentNodeId = m_domAgent->boundNodeId(document);
1018 if (!documentNodeId || !m_namedFlowCollectionsRequested.contains(documentNodeId))
1019 return 0;
1020
1021 return documentNodeId;
1022}
1023
apavlov@chromium.org47bfc332012-03-26 14:04:50 +00001024void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>* result)
apavlov@chromium.orgbe789cf2011-05-18 13:32:07 +00001025{
1026 InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
apavlov@chromium.org47bfc332012-03-26 14:04:50 +00001027 result->addItem(inspectorStyleSheet->buildObjectForStyleSheetInfo());
apavlov@chromium.orgbe789cf2011-05-18 13:32:07 +00001028 for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
andreas.kling@nokia.com1678e2b2011-10-14 18:36:31 +00001029 CSSRule* rule = styleSheet->item(i);
akling@apple.comc713db32012-11-22 03:45:40 +00001030 if (rule->type() == CSSRule::IMPORT_RULE) {
andreas.kling@nokia.com1678e2b2011-10-14 18:36:31 +00001031 CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet();
1032 if (importedStyleSheet)
1033 collectStyleSheets(importedStyleSheet, result);
apavlov@chromium.orgbe789cf2011-05-18 13:32:07 +00001034 }
1035 }
1036}
1037
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001038InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
1039{
1040 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
1041 if (!inspectorStyleSheet) {
1042 String id = String::number(m_lastStyleSheetId++);
antti@apple.comfe126eb2012-04-25 22:42:47 +00001043 Document* document = styleSheet->ownerDocument();
pfeldman@chromium.orgf9adb6a2012-05-24 14:35:50 +00001044 inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001045 m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
1046 m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
1047 }
1048 return inspectorStyleSheet.get();
1049}
1050
1051InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
1052{
1053 if (!document) {
1054 ASSERT(!createIfAbsent);
1055 return 0;
1056 }
1057
1058 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
1059 if (inspectorStyleSheet || !createIfAbsent)
1060 return inspectorStyleSheet.get();
1061
1062 ExceptionCode ec = 0;
1063 RefPtr<Element> styleElement = document->createElement("style", ec);
1064 if (!ec)
1065 styleElement->setAttribute("type", "text/css", ec);
apavlov@chromium.orgd41cebd2011-01-20 15:46:28 +00001066 if (!ec) {
1067 ContainerNode* targetNode;
1068 // HEAD is absent in ImageDocuments, for example.
1069 if (document->head())
1070 targetNode = document->head();
1071 else if (document->body())
1072 targetNode = document->body();
1073 else
1074 return 0;
apavlov@chromium.org31442e82012-03-05 10:44:40 +00001075
1076 InlineStyleOverrideScope overrideScope(document);
apavlov@chromium.orgd41cebd2011-01-20 15:46:28 +00001077 targetNode->appendChild(styleElement, ec);
1078 }
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001079 if (ec)
1080 return 0;
1081 StyleSheetList* styleSheets = document->styleSheets();
1082 StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1);
apavlov@chromium.org31442e82012-03-05 10:44:40 +00001083 if (!styleSheet || !styleSheet->isCSSStyleSheet())
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001084 return 0;
1085 CSSStyleSheet* cssStyleSheet = static_cast<CSSStyleSheet*>(styleSheet);
1086 String id = String::number(m_lastStyleSheetId++);
apavlov@chromium.org0c1c3732012-05-25 16:24:48 +00001087 inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, cssStyleSheet, TypeBuilder::CSS::StyleSheetOrigin::Inspector, InspectorDOMAgent::documentURLString(document), this);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001088 m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
1089 m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
1090 m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
1091 return inspectorStyleSheet.get();
1092}
1093
pfeldman@chromium.org8f286ef2011-04-15 12:39:32 +00001094InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001095{
1096 IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +00001097 if (it == m_idToInspectorStyleSheet.end()) {
caseq@chromium.orgc2485692011-03-31 15:21:33 +00001098 *errorString = "No style sheet with given id found";
pfeldman@chromium.orge573fa32011-03-17 18:10:15 +00001099 return 0;
1100 }
benjamin@webkit.orgee554052012-10-07 23:12:07 +00001101 return it->value.get();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001102}
1103
apavlov@chromium.org0c1c3732012-05-25 16:24:48 +00001104TypeBuilder::CSS::StyleSheetOrigin::Enum InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001105{
apavlov@chromium.org0c1c3732012-05-25 16:24:48 +00001106 TypeBuilder::CSS::StyleSheetOrigin::Enum origin = TypeBuilder::CSS::StyleSheetOrigin::Regular;
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001107 if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
apavlov@chromium.org0c1c3732012-05-25 16:24:48 +00001108 origin = TypeBuilder::CSS::StyleSheetOrigin::User_agent;
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001109 else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
apavlov@chromium.org0c1c3732012-05-25 16:24:48 +00001110 origin = TypeBuilder::CSS::StyleSheetOrigin::User;
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001111 else {
1112 InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
1113 if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
apavlov@chromium.org0c1c3732012-05-25 16:24:48 +00001114 origin = TypeBuilder::CSS::StyleSheetOrigin::Inspector;
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001115 }
1116 return origin;
1117}
1118
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +00001119PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule, StyleResolver* styleResolver)
1120{
1121 if (!rule)
1122 return 0;
1123
1124 // CSSRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
1125 // Since the inspector wants to walk the parent chain, we construct the full wrappers here.
1126 // FIXME: This could be factored better. StyleResolver::styleRulesForElement should return a StyleRule vector, not a CSSRuleList.
1127 if (!rule->parentStyleSheet()) {
1128 rule = styleResolver->ensureFullCSSOMWrapperForInspector(rule->styleRule());
1129 if (!rule)
1130 return 0;
1131 }
1132 InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(rule->parentStyleSheet());
1133 return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(rule) : 0;
1134}
1135
alexis.menard@openbossa.org31b77cb2012-04-24 23:51:22 +00001136PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList, StyleResolver* styleResolver)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001137{
apavlov@chromium.org47bfc332012-03-26 14:04:50 +00001138 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSRule>::create();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001139 if (!ruleList)
1140 return result.release();
1141
1142 for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
1143 CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +00001144 RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule, styleResolver);
1145 if (!ruleObject)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001146 continue;
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +00001147 result->addItem(ruleObject);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001148 }
1149 return result.release();
1150}
1151
apavlov@chromium.orgcecb43f2012-09-25 08:05:18 +00001152PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > InspectorCSSAgent::buildArrayForMatchedRuleList(CSSRuleList* ruleList, StyleResolver* styleResolver, Element* element)
1153{
1154 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > result = TypeBuilder::Array<TypeBuilder::CSS::RuleMatch>::create();
1155 if (!ruleList)
1156 return result.release();
1157
1158 for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
1159 CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
1160 RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule, styleResolver);
1161 if (!ruleObject)
1162 continue;
1163 RefPtr<TypeBuilder::Array<int> > matchingSelectors = TypeBuilder::Array<int>::create();
1164 const CSSSelectorList& selectorList = rule->styleRule()->selectorList();
1165 long index = 0;
1166 for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
1167 ExceptionCode ec;
1168 bool matched = element->webkitMatchesSelector(selector->selectorText(), ec);
1169 if (matched)
1170 matchingSelectors->addItem(index);
1171 ++index;
1172 }
1173 RefPtr<TypeBuilder::CSS::RuleMatch> match = TypeBuilder::CSS::RuleMatch::create()
1174 .setRule(ruleObject)
1175 .setMatchingSelectors(matchingSelectors);
1176 result->addItem(match);
1177 }
1178
1179 return result;
1180}
1181
apavlov@chromium.org47bfc332012-03-26 14:04:50 +00001182PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001183{
kling@webkit.org119bc4e2012-02-04 12:24:19 +00001184 if (!element->isStyledElement())
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +00001185 return 0;
kling@webkit.org119bc4e2012-02-04 12:24:19 +00001186
kling@webkit.org569556d2012-11-12 23:52:12 +00001187 const StylePropertySet* attributeStyle = static_cast<StyledElement*>(element)->presentationAttributeStyle();
commit-queue@webkit.org844de9e2012-11-05 10:47:35 +00001188 if (!attributeStyle)
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +00001189 return 0;
kling@webkit.org119bc4e2012-02-04 12:24:19 +00001190
commit-queue@webkit.org844de9e2012-11-05 10:47:35 +00001191 RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), const_cast<StylePropertySet*>(attributeStyle)->ensureCSSStyleDeclaration(), 0);
apavlov@chromium.org0d4c01a2012-02-09 12:41:37 +00001192 return inspectorStyle->buildObjectForStyle();
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001193}
1194
commit-queue@webkit.orge2bb32c2012-08-10 09:58:35 +00001195PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > InspectorCSSAgent::buildArrayForRegions(ErrorString* errorString, PassRefPtr<NodeList> regionList, int documentNodeId)
1196{
1197 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > regions = TypeBuilder::Array<TypeBuilder::CSS::Region>::create();
1198
1199 for (unsigned i = 0; i < regionList->length(); ++i) {
1200 TypeBuilder::CSS::Region::RegionOverset::Enum regionOverset;
1201
1202 switch (toElement(regionList->item(i))->renderRegion()->regionState()) {
1203 case RenderRegion::RegionFit:
1204 regionOverset = TypeBuilder::CSS::Region::RegionOverset::Fit;
1205 break;
1206 case RenderRegion::RegionEmpty:
1207 regionOverset = TypeBuilder::CSS::Region::RegionOverset::Empty;
1208 break;
1209 case RenderRegion::RegionOverset:
1210 regionOverset = TypeBuilder::CSS::Region::RegionOverset::Overset;
1211 break;
1212 case RenderRegion::RegionUndefined:
1213 continue;
1214 default:
1215 ASSERT_NOT_REACHED();
1216 continue;
1217 }
1218
1219 RefPtr<TypeBuilder::CSS::Region> region = TypeBuilder::CSS::Region::create()
1220 .setRegionOverset(regionOverset)
1221 // documentNodeId was previously asserted
1222 .setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i)));
1223
1224 regions->addItem(region);
1225 }
1226
1227 return regions.release();
1228}
1229
1230PassRefPtr<TypeBuilder::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString* errorString, WebKitNamedFlow* webkitNamedFlow, int documentNodeId)
1231{
1232 RefPtr<NodeList> contentList = webkitNamedFlow->getContent();
1233 RefPtr<TypeBuilder::Array<int> > content = TypeBuilder::Array<int>::create();
1234
1235 for (unsigned i = 0; i < contentList->length(); ++i) {
1236 // documentNodeId was previously asserted
1237 content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i)));
1238 }
1239
1240 RefPtr<TypeBuilder::CSS::NamedFlow> namedFlow = TypeBuilder::CSS::NamedFlow::create()
1241 .setDocumentNodeId(documentNodeId)
1242 .setName(webkitNamedFlow->name().string())
1243 .setOverset(webkitNamedFlow->overset())
1244 .setContent(content)
1245 .setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId));
1246
1247 return namedFlow.release();
1248}
1249
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001250void InspectorCSSAgent::didRemoveDocument(Document* document)
1251{
apavlov@chromium.org6dbb39d2010-11-10 17:12:45 +00001252 if (document)
1253 m_documentToInspectorStyleSheet.remove(document);
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001254}
1255
1256void InspectorCSSAgent::didRemoveDOMNode(Node* node)
1257{
apavlov@chromium.org6dbb39d2010-11-10 17:12:45 +00001258 if (!node)
1259 return;
1260
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +00001261 int nodeId = m_domAgent->boundNodeId(node);
1262 if (nodeId)
1263 m_nodeIdToForcedPseudoState.remove(nodeId);
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +00001264
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001265 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
1266 if (it == m_nodeToInspectorStyleSheet.end())
1267 return;
1268
benjamin@webkit.orgee554052012-10-07 23:12:07 +00001269 m_idToInspectorStyleSheet.remove(it->value->id());
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001270 m_nodeToInspectorStyleSheet.remove(node);
1271}
1272
apavlov@chromium.org93e800a2010-12-24 16:39:32 +00001273void InspectorCSSAgent::didModifyDOMAttr(Element* element)
1274{
1275 if (!element)
1276 return;
1277
1278 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1279 if (it == m_nodeToInspectorStyleSheet.end())
1280 return;
1281
benjamin@webkit.orgee554052012-10-07 23:12:07 +00001282 it->value->didModifyElementAttribute();
apavlov@chromium.org93e800a2010-12-24 16:39:32 +00001283}
1284
pfeldman@chromium.orga1a70a42012-02-14 08:50:19 +00001285void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1286{
1287 if (m_frontend)
1288 m_frontend->styleSheetChanged(styleSheet->id());
1289}
1290
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +00001291void InspectorCSSAgent::resetPseudoStates()
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +00001292{
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +00001293 HashSet<Document*> documentsToChange;
1294 for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) {
benjamin@webkit.orgee554052012-10-07 23:12:07 +00001295 Element* element = toElement(m_domAgent->nodeForId(it->key));
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +00001296 if (element && element->ownerDocument())
1297 documentsToChange.add(element->ownerDocument());
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +00001298 }
apavlov@chromium.orgcc4fd4a2012-07-04 16:10:45 +00001299
1300 m_nodeIdToForcedPseudoState.clear();
1301 for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
1302 (*it)->styleResolverChanged(RecalcStyleImmediately);
pfeldman@chromium.orgefb43862011-08-16 17:15:06 +00001303}
1304
apavlov@chromium.org8d79d7f2010-10-07 09:53:40 +00001305} // namespace WebCore
1306
1307#endif // ENABLE(INSPECTOR)