Simplify CSSOM style declaration's grabbing at internals.
[WebKit-https.git] / Source / WebCore / inspector / InspectorCSSAgent.cpp
1 /*
2  * Copyright (C) 2010, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 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
27 #if ENABLE(INSPECTOR)
28
29 #include "InspectorCSSAgent.h"
30
31 #include "CSSComputedStyleDeclaration.h"
32 #include "CSSImportRule.h"
33 #include "CSSPropertyNames.h"
34 #include "CSSPropertySourceData.h"
35 #include "CSSRule.h"
36 #include "CSSRuleList.h"
37 #include "CSSStyleRule.h"
38 #include "CSSStyleSheet.h"
39 #include "ContentSecurityPolicy.h"
40 #include "DOMWindow.h"
41 #include "HTMLHeadElement.h"
42 #include "InspectorDOMAgent.h"
43 #include "InspectorHistory.h"
44 #include "InspectorState.h"
45 #include "InspectorTypeBuilder.h"
46 #include "InspectorValues.h"
47 #include "InstrumentingAgents.h"
48 #include "Node.h"
49 #include "NodeList.h"
50 #include "StylePropertySet.h"
51 #include "StylePropertyShorthand.h"
52 #include "StyleResolver.h"
53 #include "StyleRule.h"
54 #include "StyleSheetList.h"
55 #include "WebKitNamedFlow.h"
56 #include "WebKitNamedFlowCollection.h"
57
58 #include <wtf/CurrentTime.h>
59 #include <wtf/HashSet.h>
60 #include <wtf/Vector.h>
61 #include <wtf/text/CString.h>
62 #include <wtf/text/StringConcatenate.h>
63
64 namespace CSSAgentState {
65 static const char cssAgentEnabled[] = "cssAgentEnabled";
66 static const char isSelectorProfiling[] = "isSelectorProfiling";
67 }
68
69 namespace WebCore {
70
71 enum ForcePseudoClassFlags {
72     PseudoNone = 0,
73     PseudoHover = 1 << 0,
74     PseudoFocus = 1 << 1,
75     PseudoActive = 1 << 2,
76     PseudoVisited = 1 << 3
77 };
78
79 struct RuleMatchData {
80     String selector;
81     String url;
82     unsigned lineNumber;
83     double startTime;
84 };
85
86 struct RuleMatchingStats {
87     RuleMatchingStats()
88         : lineNumber(0), totalTime(0.0), hits(0), matches(0)
89     {
90     }
91     RuleMatchingStats(const RuleMatchData& data, double totalTime, unsigned hits, unsigned matches)
92         : selector(data.selector), url(data.url), lineNumber(data.lineNumber), totalTime(totalTime), hits(hits), matches(matches)
93     {
94     }
95
96     String selector;
97     String url;
98     unsigned lineNumber;
99     double totalTime;
100     unsigned hits;
101     unsigned matches;
102 };
103
104 class SelectorProfile {
105 public:
106     SelectorProfile()
107         : m_totalMatchingTimeMs(0.0)
108     {
109     }
110     virtual ~SelectorProfile()
111     {
112     }
113
114     double totalMatchingTimeMs() const { return m_totalMatchingTimeMs; }
115
116     String makeKey();
117     void startSelector(const CSSStyleRule*);
118     void commitSelector(bool);
119     void commitSelectorTime();
120     PassRefPtr<TypeBuilder::CSS::SelectorProfile> toInspectorObject() const;
121
122 private:
123
124     // Key is "selector?url:line".
125     typedef HashMap<String, RuleMatchingStats> RuleMatchingStatsMap;
126
127     double m_totalMatchingTimeMs;
128     RuleMatchingStatsMap m_ruleMatchingStats;
129     RuleMatchData m_currentMatchData;
130 };
131
132
133 static unsigned computePseudoClassMask(InspectorArray* pseudoClassArray)
134 {
135     DEFINE_STATIC_LOCAL(String, active, ("active"));
136     DEFINE_STATIC_LOCAL(String, hover, ("hover"));
137     DEFINE_STATIC_LOCAL(String, focus, ("focus"));
138     DEFINE_STATIC_LOCAL(String, visited, ("visited"));
139     if (!pseudoClassArray || !pseudoClassArray->length())
140         return PseudoNone;
141
142     unsigned result = PseudoNone;
143     for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
144         RefPtr<InspectorValue> pseudoClassValue = pseudoClassArray->get(i);
145         String pseudoClass;
146         bool success = pseudoClassValue->asString(&pseudoClass);
147         if (!success)
148             continue;
149         if (pseudoClass == active)
150             result |= PseudoActive;
151         else if (pseudoClass == hover)
152             result |= PseudoHover;
153         else if (pseudoClass == focus)
154             result |= PseudoFocus;
155         else if (pseudoClass == visited)
156             result |= PseudoVisited;
157     }
158
159     return result;
160 }
161
162 inline String SelectorProfile::makeKey()
163 {
164     return makeString(m_currentMatchData.selector, "?", m_currentMatchData.url, ":", String::number(m_currentMatchData.lineNumber));
165 }
166
167 inline void SelectorProfile::startSelector(const CSSStyleRule* rule)
168 {
169     m_currentMatchData.selector = rule->selectorText();
170     CSSStyleSheet* styleSheet = rule->parentStyleSheet();
171     String url = emptyString();
172     if (styleSheet) {
173         url = InspectorStyleSheet::styleSheetURL(styleSheet);
174         if (url.isEmpty())
175             url = InspectorDOMAgent::documentURLString(styleSheet->ownerDocument());
176     }
177     m_currentMatchData.url = url;
178     m_currentMatchData.lineNumber = rule->styleRule()->sourceLine();
179     m_currentMatchData.startTime = WTF::currentTimeMS();
180 }
181
182 inline void SelectorProfile::commitSelector(bool matched)
183 {
184     double matchTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTime;
185     m_totalMatchingTimeMs += matchTimeMs;
186
187     RuleMatchingStatsMap::AddResult result = m_ruleMatchingStats.add(makeKey(), RuleMatchingStats(m_currentMatchData, matchTimeMs, 1, matched ? 1 : 0));
188     if (!result.isNewEntry) {
189         result.iterator->second.totalTime += matchTimeMs;
190         result.iterator->second.hits += 1;
191         if (matched)
192             result.iterator->second.matches += 1;
193     }
194 }
195
196 inline void SelectorProfile::commitSelectorTime()
197 {
198     double processingTimeMs = WTF::currentTimeMS() - m_currentMatchData.startTime;
199     m_totalMatchingTimeMs += processingTimeMs;
200
201     RuleMatchingStatsMap::iterator it = m_ruleMatchingStats.find(makeKey());
202     if (it == m_ruleMatchingStats.end())
203         return;
204
205     it->second.totalTime += processingTimeMs;
206 }
207
208 PassRefPtr<TypeBuilder::CSS::SelectorProfile> SelectorProfile::toInspectorObject() const
209 {
210     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry> > selectorProfileData = TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry>::create();
211     for (RuleMatchingStatsMap::const_iterator it = m_ruleMatchingStats.begin(); it != m_ruleMatchingStats.end(); ++it) {
212         RefPtr<TypeBuilder::CSS::SelectorProfileEntry> entry = TypeBuilder::CSS::SelectorProfileEntry::create()
213             .setSelector(it->second.selector)
214             .setUrl(it->second.url)
215             .setLineNumber(it->second.lineNumber)
216             .setTime(it->second.totalTime)
217             .setHitCount(it->second.hits)
218             .setMatchCount(it->second.matches);
219         selectorProfileData->addItem(entry.release());
220     }
221
222     RefPtr<TypeBuilder::CSS::SelectorProfile> result = TypeBuilder::CSS::SelectorProfile::create()
223         .setTotalTime(totalMatchingTimeMs())
224         .setData(selectorProfileData);
225     return result.release();
226 }
227
228 class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
229     WTF_MAKE_NONCOPYABLE(StyleSheetAction);
230 public:
231     StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
232         : InspectorHistory::Action(name)
233         , m_styleSheet(styleSheet)
234     {
235     }
236
237 protected:
238     RefPtr<InspectorStyleSheet> m_styleSheet;
239 };
240
241 class InspectorCSSAgent::SetStyleSheetTextAction : public InspectorCSSAgent::StyleSheetAction {
242     WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
243 public:
244     SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
245         : InspectorCSSAgent::StyleSheetAction("SetStyleSheetText", styleSheet)
246         , m_text(text)
247     {
248     }
249
250     virtual bool perform(ExceptionCode& ec)
251     {
252         if (!m_styleSheet->getText(&m_oldText))
253             return false;
254         return redo(ec);
255     }
256
257     virtual bool undo(ExceptionCode&)
258     {
259         if (m_styleSheet->setText(m_oldText)) {
260             m_styleSheet->reparseStyleSheet(m_oldText);
261             return true;
262         }
263         return false;
264     }
265
266     virtual bool redo(ExceptionCode&)
267     {
268         if (m_styleSheet->setText(m_text)) {
269             m_styleSheet->reparseStyleSheet(m_text);
270             return true;
271         }
272         return false;
273     }
274
275     virtual String mergeId()
276     {
277         return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
278     }
279
280     virtual void merge(PassOwnPtr<Action> action)
281     {
282         ASSERT(action->mergeId() == mergeId());
283
284         SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get());
285         m_text = other->m_text;
286     }
287
288 private:
289     String m_text;
290     String m_oldText;
291 };
292
293 class InspectorCSSAgent::SetPropertyTextAction : public InspectorCSSAgent::StyleSheetAction {
294     WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
295 public:
296     SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
297         : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
298         , m_cssId(cssId)
299         , m_propertyIndex(propertyIndex)
300         , m_text(text)
301         , m_overwrite(overwrite)
302     {
303     }
304
305     virtual String toString()
306     {
307         return mergeId() + ": " + m_oldText + " -> " + m_text;
308     }
309
310     virtual bool perform(ExceptionCode& ec)
311     {
312         return redo(ec);
313     }
314
315     virtual bool undo(ExceptionCode& ec)
316     {
317         String placeholder;
318         return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, ec);
319     }
320
321     virtual bool redo(ExceptionCode& ec)
322     {
323         String oldText;
324         bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, ec);
325         m_oldText = oldText.stripWhiteSpace();
326         // FIXME: remove this once the model handles this case.
327         if (!m_oldText.endsWith(';'))
328             m_oldText += ";";
329         return result;
330     }
331
332     virtual String mergeId()
333     {
334         return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false");
335     }
336
337     virtual void merge(PassOwnPtr<Action> action)
338     {
339         ASSERT(action->mergeId() == mergeId());
340
341         SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
342         m_text = other->m_text;
343     }
344
345 private:
346     InspectorCSSId m_cssId;
347     unsigned m_propertyIndex;
348     String m_text;
349     String m_oldText;
350     bool m_overwrite;
351 };
352
353 class InspectorCSSAgent::TogglePropertyAction : public InspectorCSSAgent::StyleSheetAction {
354     WTF_MAKE_NONCOPYABLE(TogglePropertyAction);
355 public:
356     TogglePropertyAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, bool disable)
357         : InspectorCSSAgent::StyleSheetAction("ToggleProperty", styleSheet)
358         , m_cssId(cssId)
359         , m_propertyIndex(propertyIndex)
360         , m_disable(disable)
361     {
362     }
363
364     virtual bool perform(ExceptionCode& ec)
365     {
366         return redo(ec);
367     }
368
369     virtual bool undo(ExceptionCode& ec)
370     {
371         return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, !m_disable, ec);
372     }
373
374     virtual bool redo(ExceptionCode& ec)
375     {
376         return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, m_disable, ec);
377     }
378
379 private:
380     InspectorCSSId m_cssId;
381     unsigned m_propertyIndex;
382     bool m_disable;
383 };
384
385 class InspectorCSSAgent::SetRuleSelectorAction : public InspectorCSSAgent::StyleSheetAction {
386     WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
387 public:
388     SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
389         : InspectorCSSAgent::StyleSheetAction("SetRuleSelector", styleSheet)
390         , m_cssId(cssId)
391         , m_selector(selector)
392     {
393     }
394
395     virtual bool perform(ExceptionCode& ec)
396     {
397         m_oldSelector = m_styleSheet->ruleSelector(m_cssId, ec);
398         if (ec)
399             return false;
400         return redo(ec);
401     }
402
403     virtual bool undo(ExceptionCode& ec)
404     {
405         return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, ec);
406     }
407
408     virtual bool redo(ExceptionCode& ec)
409     {
410         return m_styleSheet->setRuleSelector(m_cssId, m_selector, ec);
411     }
412
413 private:
414     InspectorCSSId m_cssId;
415     String m_selector;
416     String m_oldSelector;
417 };
418
419 class InspectorCSSAgent::AddRuleAction : public InspectorCSSAgent::StyleSheetAction {
420     WTF_MAKE_NONCOPYABLE(AddRuleAction);
421 public:
422     AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
423         : InspectorCSSAgent::StyleSheetAction("AddRule", styleSheet)
424         , m_selector(selector)
425     {
426     }
427
428     virtual bool perform(ExceptionCode& ec)
429     {
430         return redo(ec);
431     }
432
433     virtual bool undo(ExceptionCode& ec)
434     {
435         return m_styleSheet->deleteRule(m_newId, ec);
436     }
437
438     virtual bool redo(ExceptionCode& ec)
439     {
440         CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, ec);
441         if (ec)
442             return false;
443         m_newId = m_styleSheet->ruleId(cssStyleRule);
444         return true;
445     }
446
447     InspectorCSSId newRuleId() { return m_newId; }
448
449 private:
450     InspectorCSSId m_newId;
451     String m_selector;
452     String m_oldSelector;
453 };
454
455 // static
456 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
457 {
458     if (!rule->isStyleRule())
459         return 0;
460     return static_cast<CSSStyleRule*>(rule);
461 }
462
463 InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state, InspectorDOMAgent* domAgent)
464     : InspectorBaseAgent<InspectorCSSAgent>("CSS", instrumentingAgents, state)
465     , m_frontend(0)
466     , m_domAgent(domAgent)
467     , m_lastStyleSheetId(1)
468 {
469     m_domAgent->setDOMListener(this);
470 }
471
472 InspectorCSSAgent::~InspectorCSSAgent()
473 {
474     ASSERT(!m_domAgent);
475     reset();
476 }
477
478 void InspectorCSSAgent::setFrontend(InspectorFrontend* frontend)
479 {
480     ASSERT(!m_frontend);
481     m_frontend = frontend->css();
482     m_instrumentingAgents->setInspectorCSSAgent(this);
483 }
484
485 void InspectorCSSAgent::clearFrontend()
486 {
487     ASSERT(m_frontend);
488     m_frontend = 0;
489     m_instrumentingAgents->setInspectorCSSAgent(0);
490     resetPseudoStates();
491     String errorString;
492     stopSelectorProfilerImpl(&errorString, false);
493 }
494
495 void InspectorCSSAgent::discardAgent()
496 {
497     m_domAgent->setDOMListener(0);
498     m_domAgent = 0;
499 }
500
501 void InspectorCSSAgent::restore()
502 {
503     if (m_state->getBoolean(CSSAgentState::cssAgentEnabled)) {
504         ErrorString error;
505         enable(&error);
506     }
507     if (m_state->getBoolean(CSSAgentState::isSelectorProfiling)) {
508         String errorString;
509         startSelectorProfiler(&errorString);
510     }
511 }
512
513 void InspectorCSSAgent::reset()
514 {
515     m_idToInspectorStyleSheet.clear();
516     m_cssStyleSheetToInspectorStyleSheet.clear();
517     m_nodeToInspectorStyleSheet.clear();
518     m_documentToInspectorStyleSheet.clear();
519     m_namedFlowCollectionsRequested.clear();
520     resetPseudoStates();
521 }
522
523 void InspectorCSSAgent::enable(ErrorString*)
524 {
525     m_state->setBoolean(CSSAgentState::cssAgentEnabled, true);
526 }
527
528 void InspectorCSSAgent::disable(ErrorString*)
529 {
530     m_state->setBoolean(CSSAgentState::cssAgentEnabled, false);
531 }
532
533 void InspectorCSSAgent::mediaQueryResultChanged()
534 {
535     if (m_frontend)
536         m_frontend->mediaQueryResultChanged();
537 }
538
539 void InspectorCSSAgent::didCreateNamedFlow(Document* document, const AtomicString& name)
540 {
541     int nodeId = m_domAgent->boundNodeId(document);
542     if (!nodeId || !m_namedFlowCollectionsRequested.contains(nodeId))
543         return;
544
545     m_frontend->namedFlowCreated(nodeId, name.string());
546 }
547
548 void InspectorCSSAgent::didRemoveNamedFlow(Document* document, const AtomicString& name)
549 {
550     int nodeId = m_domAgent->boundNodeId(document);
551     if (!nodeId || !m_namedFlowCollectionsRequested.contains(nodeId))
552         return;
553
554     m_frontend->namedFlowRemoved(nodeId, name.string());
555 }
556
557 bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType)
558 {
559     if (m_nodeIdToForcedPseudoState.isEmpty())
560         return false;
561
562     int nodeId = m_domAgent->boundNodeId(element);
563     if (!nodeId)
564         return false;
565
566     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
567     if (it == m_nodeIdToForcedPseudoState.end())
568         return false;
569
570     unsigned forcedPseudoState = it->second;
571     switch (pseudoType) {
572     case CSSSelector::PseudoActive:
573         return forcedPseudoState & PseudoActive;
574     case CSSSelector::PseudoFocus:
575         return forcedPseudoState & PseudoFocus;
576     case CSSSelector::PseudoHover:
577         return forcedPseudoState & PseudoHover;
578     case CSSSelector::PseudoVisited:
579         return forcedPseudoState & PseudoVisited;
580     default:
581         return false;
582     }
583 }
584
585 void InspectorCSSAgent::recalcStyleForPseudoStateIfNeeded(Element* element, InspectorArray* forcedPseudoClasses)
586 {
587     int nodeId = m_domAgent->boundNodeId(element);
588     if (!nodeId)
589         return;
590
591     unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses);
592     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
593     unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->second;
594     bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState;
595     if (!needStyleRecalc)
596         return;
597
598     if (forcedPseudoState)
599         m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
600     else
601         m_nodeIdToForcedPseudoState.remove(nodeId);
602     element->ownerDocument()->styleResolverChanged(RecalcStyleImmediately);
603 }
604
605 void InspectorCSSAgent::getMatchedStylesForNode(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>* forcedPseudoClasses, const bool* includePseudo, const bool* includeInherited, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> >& matchedCSSRules, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdRules> >& pseudoIdRules, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> >& inheritedEntries)
606 {
607     Element* element = elementForId(errorString, nodeId);
608     if (!element)
609         return;
610
611     recalcStyleForPseudoStateIfNeeded(element, forcedPseudoClasses ? forcedPseudoClasses->get() : 0);
612
613     // Matched rules.
614     StyleResolver* styleResolver = element->ownerDocument()->styleResolver();
615     RefPtr<CSSRuleList> matchedRules = styleResolver->styleRulesForElement(element, StyleResolver::AllCSSRules);
616     matchedCSSRules = buildArrayForRuleList(matchedRules.get(), styleResolver);
617
618     // Pseudo elements.
619     if (!includePseudo || *includePseudo) {
620         RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdRules> > pseudoElements = TypeBuilder::Array<TypeBuilder::CSS::PseudoIdRules>::create();
621         for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
622             RefPtr<CSSRuleList> matchedRules = styleResolver->pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
623             if (matchedRules && matchedRules->length()) {
624                 RefPtr<TypeBuilder::CSS::PseudoIdRules> pseudoStyles = TypeBuilder::CSS::PseudoIdRules::create()
625                     .setPseudoId(static_cast<int>(pseudoId))
626                     .setRules(buildArrayForRuleList(matchedRules.get(), styleResolver));
627                 pseudoElements->addItem(pseudoStyles.release());
628             }
629         }
630
631         pseudoIdRules = pseudoElements.release();
632     }
633
634     // Inherited styles.
635     if (!includeInherited || *includeInherited) {
636         RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> > inheritedStyles = TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry>::create();
637         Element* parentElement = element->parentElement();
638         while (parentElement) {
639             StyleResolver* parentStyleResolver= parentElement->ownerDocument()->styleResolver();
640             RefPtr<CSSRuleList> parentMatchedRules = parentStyleResolver->styleRulesForElement(parentElement, StyleResolver::AllCSSRules);
641             RefPtr<TypeBuilder::CSS::InheritedStyleEntry> parentStyle = TypeBuilder::CSS::InheritedStyleEntry::create()
642                 .setMatchedCSSRules(buildArrayForRuleList(parentMatchedRules.get(), styleResolver));
643             if (parentElement->style() && parentElement->style()->length()) {
644                 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
645                 if (styleSheet)
646                     parentStyle->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
647             }
648
649             inheritedStyles->addItem(parentStyle.release());
650             parentElement = parentElement->parentElement();
651         }
652
653         inheritedEntries = inheritedStyles.release();
654     }
655 }
656
657 void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<TypeBuilder::CSS::CSSStyle>& attributesStyle)
658 {
659     Element* element = elementForId(errorString, nodeId);
660     if (!element)
661         return;
662
663     InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
664     if (!styleSheet)
665         return;
666
667     inlineStyle = styleSheet->buildObjectForStyle(element->style());
668     RefPtr<TypeBuilder::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
669     attributesStyle = attributes ? attributes.release() : 0;
670 }
671
672 void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>* forcedPseudoClasses, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> >& style)
673 {
674     Element* element = elementForId(errorString, nodeId);
675     if (!element)
676         return;
677
678     recalcStyleForPseudoStateIfNeeded(element, forcedPseudoClasses ? forcedPseudoClasses->get() : 0);
679
680     RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(element, true);
681     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
682     style = inspectorStyle->buildArrayForComputedStyle();
683 }
684
685 void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader> >& styleInfos)
686 {
687     styleInfos = TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>::create();
688     Vector<Document*> documents = m_domAgent->documents();
689     for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
690         StyleSheetList* list = (*it)->styleSheets();
691         for (unsigned i = 0; i < list->length(); ++i) {
692             StyleSheet* styleSheet = list->item(i);
693             if (styleSheet->isCSSStyleSheet())
694                 collectStyleSheets(static_cast<CSSStyleSheet*>(styleSheet), styleInfos.get());
695         }
696     }
697 }
698
699 void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<TypeBuilder::CSS::CSSStyleSheetBody>& styleSheetObject)
700 {
701     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
702     if (!inspectorStyleSheet)
703         return;
704
705     styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
706 }
707
708 void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
709 {
710     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
711     if (!inspectorStyleSheet)
712         return;
713
714     inspectorStyleSheet->getText(result);
715 }
716
717 void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
718 {
719     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
720     if (!inspectorStyleSheet)
721         return;
722
723     ExceptionCode ec = 0;
724     m_domAgent->history()->perform(adoptPtr(new SetStyleSheetTextAction(inspectorStyleSheet, text)), ec);
725     *errorString = InspectorDOMAgent::toErrorString(ec);
726 }
727
728 void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
729 {
730     InspectorCSSId compoundId(fullStyleId);
731     ASSERT(!compoundId.isEmpty());
732
733     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
734     if (!inspectorStyleSheet)
735         return;
736
737     ExceptionCode ec = 0;
738     bool success = m_domAgent->history()->perform(adoptPtr(new SetPropertyTextAction(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite)), ec);
739     if (success)
740         result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
741     *errorString = InspectorDOMAgent::toErrorString(ec);
742 }
743
744 void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
745 {
746     InspectorCSSId compoundId(fullStyleId);
747     ASSERT(!compoundId.isEmpty());
748
749     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
750     if (!inspectorStyleSheet)
751         return;
752
753     ExceptionCode ec = 0;
754     bool success = m_domAgent->history()->perform(adoptPtr(new TogglePropertyAction(inspectorStyleSheet, compoundId, propertyIndex, disable)), ec);
755     if (success)
756         result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
757     *errorString = InspectorDOMAgent::toErrorString(ec);
758 }
759
760 void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
761 {
762     InspectorCSSId compoundId(fullRuleId);
763     ASSERT(!compoundId.isEmpty());
764
765     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
766     if (!inspectorStyleSheet)
767         return;
768
769     ExceptionCode ec = 0;
770     bool success = m_domAgent->history()->perform(adoptPtr(new SetRuleSelectorAction(inspectorStyleSheet, compoundId, selector)), ec);
771
772     if (success)
773         result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
774     *errorString = InspectorDOMAgent::toErrorString(ec);
775 }
776
777 void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
778 {
779     Node* node = m_domAgent->assertNode(errorString, contextNodeId);
780     if (!node)
781         return;
782
783     InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
784     if (!inspectorStyleSheet) {
785         *errorString = "No target stylesheet found";
786         return;
787     }
788
789     ExceptionCode ec = 0;
790     OwnPtr<AddRuleAction> action = adoptPtr(new AddRuleAction(inspectorStyleSheet, selector));
791     AddRuleAction* rawAction = action.get();
792     bool success = m_domAgent->history()->perform(action.release(), ec);
793     if (!success) {
794         *errorString = InspectorDOMAgent::toErrorString(ec);
795         return;
796     }
797
798     InspectorCSSId ruleId = rawAction->newRuleId();
799     CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
800     result = inspectorStyleSheet->buildObjectForRule(rule);
801 }
802
803 void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> >& cssProperties)
804 {
805     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> > properties = TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo>::create();
806     for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
807         CSSPropertyID id = convertToCSSPropertyID(i);
808         RefPtr<TypeBuilder::CSS::CSSPropertyInfo> property = TypeBuilder::CSS::CSSPropertyInfo::create()
809             .setName(getPropertyName(id));
810
811         const StylePropertyShorthand& shorthand = shorthandForProperty(id);
812         if (!shorthand.length()) {
813             properties->addItem(property.release());
814             continue;
815         }
816         RefPtr<TypeBuilder::Array<String> > longhands = TypeBuilder::Array<String>::create();
817         for (unsigned j = 0; j < shorthand.length(); ++j) {
818             CSSPropertyID longhandID = shorthand.properties()[j];
819             longhands->addItem(getPropertyName(longhandID));
820         }
821         property->setLonghands(longhands);
822         properties->addItem(property.release());
823     }
824     cssProperties = properties.release();
825 }
826
827 void InspectorCSSAgent::getNamedFlowCollection(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<String> >& result)
828 {
829     Document* document = m_domAgent->assertDocument(errorString, nodeId);
830     if (!document)
831         return;
832
833     m_namedFlowCollectionsRequested.add(nodeId);
834
835     Vector<String> namedFlowsVector = document->namedFlows()->namedFlowsNames();
836     RefPtr<TypeBuilder::Array<String> > namedFlows = TypeBuilder::Array<String>::create();
837
838     for (Vector<String>::iterator it = namedFlowsVector.begin(); it != namedFlowsVector.end(); ++it)
839         namedFlows->addItem(*it);
840
841     result = namedFlows.release();
842 }
843
844 void InspectorCSSAgent::getFlowByName(ErrorString* errorString, int nodeId, const String& flowName, RefPtr<TypeBuilder::CSS::NamedFlow>& result)
845 {
846     Document* document = m_domAgent->assertDocument(errorString, nodeId);
847     if (!document)
848         return;
849
850     WebKitNamedFlow* namedFlow = document->namedFlows()->flowByName(flowName);
851     if (!namedFlow) {
852         *errorString = "No target CSS Named Flow found";
853         return;
854     }
855
856     result = TypeBuilder::CSS::NamedFlow::create()
857         .setNodeId(nodeId)
858         .setName(flowName)
859         .setOverset(namedFlow->overset());
860 }
861
862 void InspectorCSSAgent::startSelectorProfiler(ErrorString*)
863 {
864     m_currentSelectorProfile = adoptPtr(new SelectorProfile());
865     m_state->setBoolean(CSSAgentState::isSelectorProfiling, true);
866 }
867
868 void InspectorCSSAgent::stopSelectorProfiler(ErrorString* errorString, RefPtr<TypeBuilder::CSS::SelectorProfile>& result)
869 {
870     result = stopSelectorProfilerImpl(errorString, true);
871 }
872
873 PassRefPtr<TypeBuilder::CSS::SelectorProfile> InspectorCSSAgent::stopSelectorProfilerImpl(ErrorString*, bool needProfile)
874 {
875     if (!m_state->getBoolean(CSSAgentState::isSelectorProfiling))
876         return 0;
877     m_state->setBoolean(CSSAgentState::isSelectorProfiling, false);
878     RefPtr<TypeBuilder::CSS::SelectorProfile> result;
879     if (m_frontend && needProfile)
880         result = m_currentSelectorProfile->toInspectorObject();
881     m_currentSelectorProfile.clear();
882     return result.release();
883 }
884
885 void InspectorCSSAgent::willMatchRule(const CSSStyleRule* rule)
886 {
887     if (m_currentSelectorProfile)
888         m_currentSelectorProfile->startSelector(rule);
889 }
890
891 void InspectorCSSAgent::didMatchRule(bool matched)
892 {
893     if (m_currentSelectorProfile)
894         m_currentSelectorProfile->commitSelector(matched);
895 }
896
897 void InspectorCSSAgent::willProcessRule(const CSSStyleRule* rule)
898 {
899     if (m_currentSelectorProfile)
900         m_currentSelectorProfile->startSelector(rule);
901 }
902
903 void InspectorCSSAgent::didProcessRule()
904 {
905     if (m_currentSelectorProfile)
906         m_currentSelectorProfile->commitSelectorTime();
907 }
908
909 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
910 {
911     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
912     if (it == m_nodeToInspectorStyleSheet.end()) {
913         CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
914         if (!style)
915             return 0;
916
917         String newStyleSheetId = String::number(m_lastStyleSheetId++);
918         RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_domAgent->pageAgent(), newStyleSheetId, element, TypeBuilder::CSS::StyleSheetOrigin::Regular, this);
919         m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
920         m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
921         return inspectorStyleSheet.get();
922     }
923
924     return it->second.get();
925 }
926
927 Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
928 {
929     Node* node = m_domAgent->nodeForId(nodeId);
930     if (!node) {
931         *errorString = "No node with given id found";
932         return 0;
933     }
934     if (node->nodeType() != Node::ELEMENT_NODE) {
935         *errorString = "Not an element node";
936         return 0;
937     }
938     return toElement(node);
939 }
940
941 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>* result)
942 {
943     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
944     result->addItem(inspectorStyleSheet->buildObjectForStyleSheetInfo());
945     for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
946         CSSRule* rule = styleSheet->item(i);
947         if (rule->isImportRule()) {
948             CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet();
949             if (importedStyleSheet)
950                 collectStyleSheets(importedStyleSheet, result);
951         }
952     }
953 }
954
955 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
956 {
957     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
958     if (!inspectorStyleSheet) {
959         String id = String::number(m_lastStyleSheetId++);
960         Document* document = styleSheet->ownerDocument();
961         inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
962         m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
963         m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
964     }
965     return inspectorStyleSheet.get();
966 }
967
968 InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
969 {
970     if (!document) {
971         ASSERT(!createIfAbsent);
972         return 0;
973     }
974
975     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
976     if (inspectorStyleSheet || !createIfAbsent)
977         return inspectorStyleSheet.get();
978
979     ExceptionCode ec = 0;
980     RefPtr<Element> styleElement = document->createElement("style", ec);
981     if (!ec)
982         styleElement->setAttribute("type", "text/css", ec);
983     if (!ec) {
984         ContainerNode* targetNode;
985         // HEAD is absent in ImageDocuments, for example.
986         if (document->head())
987             targetNode = document->head();
988         else if (document->body())
989             targetNode = document->body();
990         else
991             return 0;
992
993         InlineStyleOverrideScope overrideScope(document);
994         targetNode->appendChild(styleElement, ec);
995     }
996     if (ec)
997         return 0;
998     StyleSheetList* styleSheets = document->styleSheets();
999     StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1);
1000     if (!styleSheet || !styleSheet->isCSSStyleSheet())
1001         return 0;
1002     CSSStyleSheet* cssStyleSheet = static_cast<CSSStyleSheet*>(styleSheet);
1003     String id = String::number(m_lastStyleSheetId++);
1004     inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, cssStyleSheet, TypeBuilder::CSS::StyleSheetOrigin::Inspector, InspectorDOMAgent::documentURLString(document), this);
1005     m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
1006     m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
1007     m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
1008     return inspectorStyleSheet.get();
1009 }
1010
1011 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
1012 {
1013     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
1014     if (it == m_idToInspectorStyleSheet.end()) {
1015         *errorString = "No style sheet with given id found";
1016         return 0;
1017     }
1018     return it->second.get();
1019 }
1020
1021 TypeBuilder::CSS::StyleSheetOrigin::Enum InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
1022 {
1023     TypeBuilder::CSS::StyleSheetOrigin::Enum origin = TypeBuilder::CSS::StyleSheetOrigin::Regular;
1024     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
1025         origin = TypeBuilder::CSS::StyleSheetOrigin::User_agent;
1026     else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
1027         origin = TypeBuilder::CSS::StyleSheetOrigin::User;
1028     else {
1029         InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
1030         if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
1031             origin = TypeBuilder::CSS::StyleSheetOrigin::Inspector;
1032     }
1033     return origin;
1034 }
1035
1036 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList, StyleResolver* styleResolver)
1037 {
1038     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSRule>::create();
1039     if (!ruleList)
1040         return result.release();
1041
1042     for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
1043         CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
1044         if (!rule)
1045             continue;
1046
1047         // CSSRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
1048         // Since the inspector wants to walk the parent chain, we construct the full wrappers here.
1049         // FIXME: This could be factored better. StyleResolver::styleRulesForElement should return a StyleRule vector, not a CSSRuleList.
1050         if (!rule->parentStyleSheet()) {
1051             rule = styleResolver->ensureFullCSSOMWrapperForInspector(rule->styleRule());
1052             if (!rule)
1053                 continue;
1054         }
1055         InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(rule->parentStyleSheet());
1056         if (inspectorStyleSheet)
1057             result->addItem(inspectorStyleSheet->buildObjectForRule(rule));
1058     }
1059     return result.release();
1060 }
1061
1062 PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
1063 {
1064     if (!element->isStyledElement())
1065         return 0;
1066
1067     const StylePropertySet* attributeStyle = static_cast<StyledElement*>(element)->attributeStyle();
1068     if (!attributeStyle)
1069         return 0;
1070
1071     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), const_cast<StylePropertySet*>(attributeStyle)->ensureCSSStyleDeclaration(), 0);
1072     return inspectorStyle->buildObjectForStyle();
1073 }
1074
1075 void InspectorCSSAgent::didRemoveDocument(Document* document)
1076 {
1077     if (document)
1078         m_documentToInspectorStyleSheet.remove(document);
1079 }
1080
1081 void InspectorCSSAgent::didRemoveDOMNode(Node* node)
1082 {
1083     if (!node)
1084         return;
1085
1086     int nodeId = m_domAgent->boundNodeId(node);
1087     if (nodeId)
1088         m_nodeIdToForcedPseudoState.remove(nodeId);
1089
1090     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
1091     if (it == m_nodeToInspectorStyleSheet.end())
1092         return;
1093
1094     m_idToInspectorStyleSheet.remove(it->second->id());
1095     m_nodeToInspectorStyleSheet.remove(node);
1096 }
1097
1098 void InspectorCSSAgent::didModifyDOMAttr(Element* element)
1099 {
1100     if (!element)
1101         return;
1102
1103     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1104     if (it == m_nodeToInspectorStyleSheet.end())
1105         return;
1106
1107     it->second->didModifyElementAttribute();
1108 }
1109
1110 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1111 {
1112     if (m_frontend)
1113         m_frontend->styleSheetChanged(styleSheet->id());
1114 }
1115
1116 void InspectorCSSAgent::resetPseudoStates()
1117 {
1118     HashSet<Document*> documentsToChange;
1119     for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) {
1120         Element* element = toElement(m_domAgent->nodeForId(it->first));
1121         if (element && element->ownerDocument())
1122             documentsToChange.add(element->ownerDocument());
1123     }
1124
1125     m_nodeIdToForcedPseudoState.clear();
1126     for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
1127         (*it)->styleResolverChanged(RecalcStyleImmediately);
1128 }
1129
1130 } // namespace WebCore
1131
1132 #endif // ENABLE(INSPECTOR)