da018b9e37a777b0a252be964c84c661994e3bcf
[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 "ExceptionCodePlaceholder.h"
42 #include "HTMLHeadElement.h"
43 #include "HTMLStyleElement.h"
44 #include "InspectorDOMAgent.h"
45 #include "InspectorHistory.h"
46 #include "InspectorState.h"
47 #include "InspectorTypeBuilder.h"
48 #include "InspectorValues.h"
49 #include "InstrumentingAgents.h"
50 #include "NamedFlowCollection.h"
51 #include "Node.h"
52 #include "NodeList.h"
53 #include "RenderRegion.h"
54 #include "SVGStyleElement.h"
55 #include "StylePropertySet.h"
56 #include "StylePropertyShorthand.h"
57 #include "StyleResolver.h"
58 #include "StyleRule.h"
59 #include "StyleSheetList.h"
60 #include "WebKitNamedFlow.h"
61
62 #include <wtf/CurrentTime.h>
63 #include <wtf/HashSet.h>
64 #include <wtf/Vector.h>
65 #include <wtf/text/CString.h>
66 #include <wtf/text/StringConcatenate.h>
67
68 namespace CSSAgentState {
69 static const char cssAgentEnabled[] = "cssAgentEnabled";
70 static const char isSelectorProfiling[] = "isSelectorProfiling";
71 }
72
73 namespace WebCore {
74
75 enum ForcePseudoClassFlags {
76     PseudoNone = 0,
77     PseudoHover = 1 << 0,
78     PseudoFocus = 1 << 1,
79     PseudoActive = 1 << 2,
80     PseudoVisited = 1 << 3
81 };
82
83 struct RuleMatchData {
84     String selector;
85     String url;
86     unsigned lineNumber;
87     double startTime;
88 };
89
90 struct RuleMatchingStats {
91     RuleMatchingStats()
92         : lineNumber(0), totalTime(0.0), hits(0), matches(0)
93     {
94     }
95     RuleMatchingStats(const RuleMatchData& data, double totalTime, unsigned hits, unsigned matches)
96         : selector(data.selector), url(data.url), lineNumber(data.lineNumber), totalTime(totalTime), hits(hits), matches(matches)
97     {
98     }
99
100     String selector;
101     String url;
102     unsigned lineNumber;
103     double totalTime;
104     unsigned hits;
105     unsigned matches;
106 };
107
108 class SelectorProfile {
109     WTF_MAKE_FAST_ALLOCATED;
110 public:
111     SelectorProfile()
112         : m_totalMatchingTimeMS(0.0)
113     {
114     }
115     virtual ~SelectorProfile()
116     {
117     }
118
119     double totalMatchingTimeMs() const { return m_totalMatchingTimeMS; }
120
121     String makeKey();
122     void startSelector(const CSSStyleRule*);
123     void commitSelector(bool);
124     void commitSelectorTime();
125     PassRefPtr<TypeBuilder::CSS::SelectorProfile> toInspectorObject() const;
126
127 private:
128
129     // Key is "selector?url:line".
130     typedef HashMap<String, RuleMatchingStats> RuleMatchingStatsMap;
131
132     double m_totalMatchingTimeMS;
133     RuleMatchingStatsMap m_ruleMatchingStats;
134     RuleMatchData m_currentMatchData;
135 };
136
137
138 static unsigned computePseudoClassMask(InspectorArray* pseudoClassArray)
139 {
140     DEFINE_STATIC_LOCAL(String, active, (ASCIILiteral("active")));
141     DEFINE_STATIC_LOCAL(String, hover, (ASCIILiteral("hover")));
142     DEFINE_STATIC_LOCAL(String, focus, (ASCIILiteral("focus")));
143     DEFINE_STATIC_LOCAL(String, visited, (ASCIILiteral("visited")));
144     if (!pseudoClassArray || !pseudoClassArray->length())
145         return PseudoNone;
146
147     unsigned result = PseudoNone;
148     for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
149         RefPtr<InspectorValue> pseudoClassValue = pseudoClassArray->get(i);
150         String pseudoClass;
151         bool success = pseudoClassValue->asString(&pseudoClass);
152         if (!success)
153             continue;
154         if (pseudoClass == active)
155             result |= PseudoActive;
156         else if (pseudoClass == hover)
157             result |= PseudoHover;
158         else if (pseudoClass == focus)
159             result |= PseudoFocus;
160         else if (pseudoClass == visited)
161             result |= PseudoVisited;
162     }
163
164     return result;
165 }
166
167 inline String SelectorProfile::makeKey()
168 {
169     return makeString(m_currentMatchData.selector, "?", m_currentMatchData.url, ":", String::number(m_currentMatchData.lineNumber));
170 }
171
172 inline void SelectorProfile::startSelector(const CSSStyleRule* rule)
173 {
174     m_currentMatchData.selector = rule->selectorText();
175     CSSStyleSheet* styleSheet = rule->parentStyleSheet();
176     String url = emptyString();
177     if (styleSheet) {
178         url = InspectorStyleSheet::styleSheetURL(styleSheet);
179         if (url.isEmpty())
180             url = InspectorDOMAgent::documentURLString(styleSheet->ownerDocument());
181     }
182     m_currentMatchData.url = url;
183     m_currentMatchData.lineNumber = rule->styleRule()->sourceLine();
184     m_currentMatchData.startTime = monotonicallyIncreasingTimeMS();
185 }
186
187 inline void SelectorProfile::commitSelector(bool matched)
188 {
189     double matchTimeMS = monotonicallyIncreasingTimeMS() - m_currentMatchData.startTime;
190     m_totalMatchingTimeMS += matchTimeMS;
191
192     RuleMatchingStatsMap::AddResult result = m_ruleMatchingStats.add(makeKey(), RuleMatchingStats(m_currentMatchData, matchTimeMS, 1, matched ? 1 : 0));
193     if (!result.isNewEntry) {
194         result.iterator->value.totalTime += matchTimeMS;
195         result.iterator->value.hits += 1;
196         if (matched)
197             result.iterator->value.matches += 1;
198     }
199 }
200
201 inline void SelectorProfile::commitSelectorTime()
202 {
203     double processingTimeMS = monotonicallyIncreasingTimeMS() - m_currentMatchData.startTime;
204     m_totalMatchingTimeMS += processingTimeMS;
205
206     RuleMatchingStatsMap::iterator it = m_ruleMatchingStats.find(makeKey());
207     if (it == m_ruleMatchingStats.end())
208         return;
209
210     it->value.totalTime += processingTimeMS;
211 }
212
213 PassRefPtr<TypeBuilder::CSS::SelectorProfile> SelectorProfile::toInspectorObject() const
214 {
215     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry> > selectorProfileData = TypeBuilder::Array<TypeBuilder::CSS::SelectorProfileEntry>::create();
216     for (RuleMatchingStatsMap::const_iterator it = m_ruleMatchingStats.begin(); it != m_ruleMatchingStats.end(); ++it) {
217         RefPtr<TypeBuilder::CSS::SelectorProfileEntry> entry = TypeBuilder::CSS::SelectorProfileEntry::create()
218             .setSelector(it->value.selector)
219             .setUrl(it->value.url)
220             .setLineNumber(it->value.lineNumber)
221             .setTime(it->value.totalTime)
222             .setHitCount(it->value.hits)
223             .setMatchCount(it->value.matches);
224         selectorProfileData->addItem(entry.release());
225     }
226
227     RefPtr<TypeBuilder::CSS::SelectorProfile> result = TypeBuilder::CSS::SelectorProfile::create()
228         .setTotalTime(totalMatchingTimeMs())
229         .setData(selectorProfileData);
230     return result.release();
231 }
232
233 class UpdateRegionLayoutTask {
234 public:
235     UpdateRegionLayoutTask(InspectorCSSAgent*);
236     void scheduleFor(WebKitNamedFlow*, int documentNodeId);
237     void unschedule(WebKitNamedFlow*);
238     void reset();
239     void onTimer(Timer<UpdateRegionLayoutTask>*);
240
241 private:
242     InspectorCSSAgent* m_cssAgent;
243     Timer<UpdateRegionLayoutTask> m_timer;
244     HashMap<WebKitNamedFlow*, int> m_namedFlows;
245 };
246
247 UpdateRegionLayoutTask::UpdateRegionLayoutTask(InspectorCSSAgent* cssAgent)
248     : m_cssAgent(cssAgent)
249     , m_timer(this, &UpdateRegionLayoutTask::onTimer)
250 {
251 }
252
253 void UpdateRegionLayoutTask::scheduleFor(WebKitNamedFlow* namedFlow, int documentNodeId)
254 {
255     m_namedFlows.add(namedFlow, documentNodeId);
256
257     if (!m_timer.isActive())
258         m_timer.startOneShot(0);
259 }
260
261 void UpdateRegionLayoutTask::unschedule(WebKitNamedFlow* namedFlow)
262 {
263     m_namedFlows.remove(namedFlow);
264 }
265
266 void UpdateRegionLayoutTask::reset()
267 {
268     m_timer.stop();
269     m_namedFlows.clear();
270 }
271
272 void UpdateRegionLayoutTask::onTimer(Timer<UpdateRegionLayoutTask>*)
273 {
274     // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed.
275     Vector<std::pair<WebKitNamedFlow*, int> > namedFlows;
276
277     for (HashMap<WebKitNamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it)
278         namedFlows.append(std::make_pair(it->key, it->value));
279
280     for (unsigned i = 0, size = namedFlows.size(); i < size; ++i) {
281         WebKitNamedFlow* namedFlow = namedFlows.at(i).first;
282         int documentNodeId = namedFlows.at(i).second;
283
284         if (m_namedFlows.contains(namedFlow)) {
285             m_cssAgent->regionLayoutUpdated(namedFlow, documentNodeId);
286             m_namedFlows.remove(namedFlow);
287         }
288     }
289
290     if (!m_namedFlows.isEmpty() && !m_timer.isActive())
291         m_timer.startOneShot(0);
292 }
293     
294 class ChangeRegionOversetTask {
295 public:
296     ChangeRegionOversetTask(InspectorCSSAgent*);
297     void scheduleFor(WebKitNamedFlow*, int documentNodeId);
298     void unschedule(WebKitNamedFlow*);
299     void reset();
300     void onTimer(Timer<ChangeRegionOversetTask>*);
301     
302 private:
303     InspectorCSSAgent* m_cssAgent;
304     Timer<ChangeRegionOversetTask> m_timer;
305     HashMap<WebKitNamedFlow*, int> m_namedFlows;
306 };
307
308 ChangeRegionOversetTask::ChangeRegionOversetTask(InspectorCSSAgent* cssAgent)
309     : m_cssAgent(cssAgent)
310     , m_timer(this, &ChangeRegionOversetTask::onTimer)
311 {
312 }
313
314 void ChangeRegionOversetTask::scheduleFor(WebKitNamedFlow* namedFlow, int documentNodeId)
315 {
316     m_namedFlows.add(namedFlow, documentNodeId);
317     
318     if (!m_timer.isActive())
319         m_timer.startOneShot(0);
320 }
321
322 void ChangeRegionOversetTask::unschedule(WebKitNamedFlow* namedFlow)
323 {
324     m_namedFlows.remove(namedFlow);
325 }
326
327 void ChangeRegionOversetTask::reset()
328 {
329     m_timer.stop();
330     m_namedFlows.clear();
331 }
332
333 void ChangeRegionOversetTask::onTimer(Timer<ChangeRegionOversetTask>*)
334 {
335     // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed.
336     for (HashMap<WebKitNamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it)
337         m_cssAgent->regionOversetChanged(it->key, it->value);
338
339     m_namedFlows.clear();
340 }
341
342 class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
343     WTF_MAKE_NONCOPYABLE(StyleSheetAction);
344 public:
345     StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
346         : InspectorHistory::Action(name)
347         , m_styleSheet(styleSheet)
348     {
349     }
350
351 protected:
352     RefPtr<InspectorStyleSheet> m_styleSheet;
353 };
354
355 class InspectorCSSAgent::SetStyleSheetTextAction : public InspectorCSSAgent::StyleSheetAction {
356     WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
357 public:
358     SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
359         : InspectorCSSAgent::StyleSheetAction("SetStyleSheetText", styleSheet)
360         , m_text(text)
361     {
362     }
363
364     virtual bool perform(ExceptionCode& ec)
365     {
366         if (!m_styleSheet->getText(&m_oldText))
367             return false;
368         return redo(ec);
369     }
370
371     virtual bool undo(ExceptionCode& ec)
372     {
373         if (m_styleSheet->setText(m_oldText, ec)) {
374             m_styleSheet->reparseStyleSheet(m_oldText);
375             return true;
376         }
377         return false;
378     }
379
380     virtual bool redo(ExceptionCode& ec)
381     {
382         if (m_styleSheet->setText(m_text, ec)) {
383             m_styleSheet->reparseStyleSheet(m_text);
384             return true;
385         }
386         return false;
387     }
388
389     virtual String mergeId()
390     {
391         return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
392     }
393
394     virtual void merge(PassOwnPtr<Action> action)
395     {
396         ASSERT(action->mergeId() == mergeId());
397
398         SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get());
399         m_text = other->m_text;
400     }
401
402 private:
403     String m_text;
404     String m_oldText;
405 };
406
407 class InspectorCSSAgent::SetStyleTextAction : public InspectorCSSAgent::StyleSheetAction {
408     WTF_MAKE_NONCOPYABLE(SetStyleTextAction);
409 public:
410     SetStyleTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& text)
411         : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetStyleText"), styleSheet)
412         , m_cssId(cssId)
413         , m_text(text)
414     {
415     }
416
417     virtual bool perform(ExceptionCode& ec)
418     {
419         return redo(ec);
420     }
421
422     virtual bool undo(ExceptionCode& ec)
423     {
424         return m_styleSheet->setStyleText(m_cssId, m_oldText, 0, ec);
425     }
426
427     virtual bool redo(ExceptionCode& ec)
428     {
429         return m_styleSheet->setStyleText(m_cssId, m_text, &m_oldText, ec);
430     }
431
432     virtual String mergeId()
433     {
434         ASSERT(m_styleSheet->id() == m_cssId.styleSheetId());
435         return String::format("SetStyleText %s:%u", m_styleSheet->id().utf8().data(), m_cssId.ordinal());
436     }
437
438     virtual void merge(PassOwnPtr<Action> action)
439     {
440         ASSERT(action->mergeId() == mergeId());
441
442         SetStyleTextAction* other = static_cast<SetStyleTextAction*>(action.get());
443         m_text = other->m_text;
444     }
445
446 private:
447     InspectorCSSId m_cssId;
448     String m_text;
449     String m_oldText;
450 };
451
452 class InspectorCSSAgent::SetPropertyTextAction : public InspectorCSSAgent::StyleSheetAction {
453     WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
454 public:
455     SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
456         : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
457         , m_cssId(cssId)
458         , m_propertyIndex(propertyIndex)
459         , m_text(text)
460         , m_overwrite(overwrite)
461     {
462     }
463
464     virtual String toString()
465     {
466         return mergeId() + ": " + m_oldText + " -> " + m_text;
467     }
468
469     virtual bool perform(ExceptionCode& ec)
470     {
471         return redo(ec);
472     }
473
474     virtual bool undo(ExceptionCode& ec)
475     {
476         String placeholder;
477         return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, ec);
478     }
479
480     virtual bool redo(ExceptionCode& ec)
481     {
482         String oldText;
483         bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, ec);
484         m_oldText = oldText.stripWhiteSpace();
485         // FIXME: remove this once the model handles this case.
486         if (!m_oldText.endsWith(';'))
487             m_oldText.append(';');
488
489         return result;
490     }
491
492     virtual String mergeId()
493     {
494         return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false");
495     }
496
497     virtual void merge(PassOwnPtr<Action> action)
498     {
499         ASSERT(action->mergeId() == mergeId());
500
501         SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
502         m_text = other->m_text;
503     }
504
505 private:
506     InspectorCSSId m_cssId;
507     unsigned m_propertyIndex;
508     String m_text;
509     String m_oldText;
510     bool m_overwrite;
511 };
512
513 class InspectorCSSAgent::TogglePropertyAction : public InspectorCSSAgent::StyleSheetAction {
514     WTF_MAKE_NONCOPYABLE(TogglePropertyAction);
515 public:
516     TogglePropertyAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, bool disable)
517         : InspectorCSSAgent::StyleSheetAction("ToggleProperty", styleSheet)
518         , m_cssId(cssId)
519         , m_propertyIndex(propertyIndex)
520         , m_disable(disable)
521     {
522     }
523
524     virtual bool perform(ExceptionCode& ec)
525     {
526         return redo(ec);
527     }
528
529     virtual bool undo(ExceptionCode& ec)
530     {
531         return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, !m_disable, ec);
532     }
533
534     virtual bool redo(ExceptionCode& ec)
535     {
536         return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, m_disable, ec);
537     }
538
539 private:
540     InspectorCSSId m_cssId;
541     unsigned m_propertyIndex;
542     bool m_disable;
543 };
544
545 class InspectorCSSAgent::SetRuleSelectorAction : public InspectorCSSAgent::StyleSheetAction {
546     WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
547 public:
548     SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
549         : InspectorCSSAgent::StyleSheetAction("SetRuleSelector", styleSheet)
550         , m_cssId(cssId)
551         , m_selector(selector)
552     {
553     }
554
555     virtual bool perform(ExceptionCode& ec)
556     {
557         m_oldSelector = m_styleSheet->ruleSelector(m_cssId, ec);
558         if (ec)
559             return false;
560         return redo(ec);
561     }
562
563     virtual bool undo(ExceptionCode& ec)
564     {
565         return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, ec);
566     }
567
568     virtual bool redo(ExceptionCode& ec)
569     {
570         return m_styleSheet->setRuleSelector(m_cssId, m_selector, ec);
571     }
572
573 private:
574     InspectorCSSId m_cssId;
575     String m_selector;
576     String m_oldSelector;
577 };
578
579 class InspectorCSSAgent::AddRuleAction : public InspectorCSSAgent::StyleSheetAction {
580     WTF_MAKE_NONCOPYABLE(AddRuleAction);
581 public:
582     AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
583         : InspectorCSSAgent::StyleSheetAction("AddRule", styleSheet)
584         , m_selector(selector)
585     {
586     }
587
588     virtual bool perform(ExceptionCode& ec)
589     {
590         return redo(ec);
591     }
592
593     virtual bool undo(ExceptionCode& ec)
594     {
595         return m_styleSheet->deleteRule(m_newId, ec);
596     }
597
598     virtual bool redo(ExceptionCode& ec)
599     {
600         CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, ec);
601         if (ec)
602             return false;
603         m_newId = m_styleSheet->ruleId(cssStyleRule);
604         return true;
605     }
606
607     InspectorCSSId newRuleId() { return m_newId; }
608
609 private:
610     InspectorCSSId m_newId;
611     String m_selector;
612     String m_oldSelector;
613 };
614
615 // static
616 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
617 {
618     if (rule->type() != CSSRule::STYLE_RULE)
619         return 0;
620     return static_cast<CSSStyleRule*>(rule);
621 }
622
623 InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* state, InspectorDOMAgent* domAgent)
624     : InspectorBaseAgent<InspectorCSSAgent>("CSS", instrumentingAgents, state)
625     , m_frontend(0)
626     , m_domAgent(domAgent)
627     , m_lastStyleSheetId(1)
628 {
629     m_domAgent->setDOMListener(this);
630 }
631
632 InspectorCSSAgent::~InspectorCSSAgent()
633 {
634     ASSERT(!m_domAgent);
635     reset();
636 }
637
638 void InspectorCSSAgent::setFrontend(InspectorFrontend* frontend)
639 {
640     ASSERT(!m_frontend);
641     m_frontend = frontend->css();
642 }
643
644 void InspectorCSSAgent::clearFrontend()
645 {
646     ASSERT(m_frontend);
647     m_frontend = 0;
648     resetNonPersistentData();
649     String errorString;
650     stopSelectorProfilerImpl(&errorString, false);
651 }
652
653 void InspectorCSSAgent::discardAgent()
654 {
655     m_domAgent->setDOMListener(0);
656     m_domAgent = 0;
657 }
658
659 void InspectorCSSAgent::restore()
660 {
661     if (m_state->getBoolean(CSSAgentState::cssAgentEnabled)) {
662         ErrorString error;
663         enable(&error);
664     }
665     if (m_state->getBoolean(CSSAgentState::isSelectorProfiling)) {
666         String errorString;
667         startSelectorProfiler(&errorString);
668     }
669 }
670
671 void InspectorCSSAgent::reset()
672 {
673     m_idToInspectorStyleSheet.clear();
674     m_cssStyleSheetToInspectorStyleSheet.clear();
675     m_nodeToInspectorStyleSheet.clear();
676     m_documentToInspectorStyleSheet.clear();
677     resetNonPersistentData();
678 }
679
680 void InspectorCSSAgent::resetNonPersistentData()
681 {
682     m_namedFlowCollectionsRequested.clear();
683     if (m_updateRegionLayoutTask)
684         m_updateRegionLayoutTask->reset();
685     if (m_changeRegionOversetTask)
686         m_changeRegionOversetTask->reset();
687     resetPseudoStates();
688 }
689
690 void InspectorCSSAgent::enable(ErrorString*)
691 {
692     m_state->setBoolean(CSSAgentState::cssAgentEnabled, true);
693     m_instrumentingAgents->setInspectorCSSAgent(this);
694 }
695
696 void InspectorCSSAgent::disable(ErrorString*)
697 {
698     m_instrumentingAgents->setInspectorCSSAgent(0);
699     m_state->setBoolean(CSSAgentState::cssAgentEnabled, false);
700 }
701
702 void InspectorCSSAgent::mediaQueryResultChanged()
703 {
704     if (m_frontend)
705         m_frontend->mediaQueryResultChanged();
706 }
707
708 void InspectorCSSAgent::didCreateNamedFlow(Document* document, WebKitNamedFlow* namedFlow)
709 {
710     int documentNodeId = documentNodeWithRequestedFlowsId(document);
711     if (!documentNodeId)
712         return;
713
714     ErrorString errorString;
715     m_frontend->namedFlowCreated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
716 }
717
718 void InspectorCSSAgent::willRemoveNamedFlow(Document* document, WebKitNamedFlow* namedFlow)
719 {
720     int documentNodeId = documentNodeWithRequestedFlowsId(document);
721     if (!documentNodeId)
722         return;
723
724     if (m_updateRegionLayoutTask)
725         m_updateRegionLayoutTask->unschedule(namedFlow);
726     
727     if (m_changeRegionOversetTask)
728         m_changeRegionOversetTask->unschedule(namedFlow);
729
730     m_frontend->namedFlowRemoved(documentNodeId, namedFlow->name().string());
731 }
732
733 void InspectorCSSAgent::didUpdateRegionLayout(Document* document, WebKitNamedFlow* namedFlow)
734 {
735     int documentNodeId = documentNodeWithRequestedFlowsId(document);
736     if (!documentNodeId)
737         return;
738
739     if (!m_updateRegionLayoutTask)
740         m_updateRegionLayoutTask = adoptPtr(new UpdateRegionLayoutTask(this));
741     m_updateRegionLayoutTask->scheduleFor(namedFlow, documentNodeId);
742 }
743
744 void InspectorCSSAgent::regionLayoutUpdated(WebKitNamedFlow* namedFlow, int documentNodeId)
745 {
746     if (namedFlow->flowState() == WebKitNamedFlow::FlowStateNull)
747         return;
748
749     ErrorString errorString;
750     RefPtr<WebKitNamedFlow> protector(namedFlow);
751
752     m_frontend->regionLayoutUpdated(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
753 }
754
755 void InspectorCSSAgent::didChangeRegionOverset(Document* document, WebKitNamedFlow* namedFlow)
756 {
757     int documentNodeId = documentNodeWithRequestedFlowsId(document);
758     if (!documentNodeId)
759         return;
760     
761     if (!m_changeRegionOversetTask)
762         m_changeRegionOversetTask = adoptPtr(new ChangeRegionOversetTask(this));
763     m_changeRegionOversetTask->scheduleFor(namedFlow, documentNodeId);
764 }
765
766 void InspectorCSSAgent::regionOversetChanged(WebKitNamedFlow* namedFlow, int documentNodeId)
767 {
768     if (namedFlow->flowState() == WebKitNamedFlow::FlowStateNull)
769         return;
770     
771     ErrorString errorString;
772     RefPtr<WebKitNamedFlow> protector(namedFlow);
773     
774     m_frontend->regionOversetChanged(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
775 }
776
777 bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType)
778 {
779     if (m_nodeIdToForcedPseudoState.isEmpty())
780         return false;
781
782     int nodeId = m_domAgent->boundNodeId(element);
783     if (!nodeId)
784         return false;
785
786     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
787     if (it == m_nodeIdToForcedPseudoState.end())
788         return false;
789
790     unsigned forcedPseudoState = it->value;
791     switch (pseudoType) {
792     case CSSSelector::PseudoActive:
793         return forcedPseudoState & PseudoActive;
794     case CSSSelector::PseudoFocus:
795         return forcedPseudoState & PseudoFocus;
796     case CSSSelector::PseudoHover:
797         return forcedPseudoState & PseudoHover;
798     case CSSSelector::PseudoVisited:
799         return forcedPseudoState & PseudoVisited;
800     default:
801         return false;
802     }
803 }
804
805 void 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)
806 {
807     Element* element = elementForId(errorString, nodeId);
808     if (!element)
809         return;
810
811     // Matched rules.
812     StyleResolver& styleResolver = element->document()->ensureStyleResolver();
813     Vector<RefPtr<StyleRuleBase> > matchedRules = styleResolver.styleRulesForElement(element, StyleResolver::AllCSSRules);
814     matchedCSSRules = buildArrayForMatchedRuleList(matchedRules, styleResolver, element);
815
816     // Pseudo elements.
817     if (!includePseudo || *includePseudo) {
818         RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> > pseudoElements = TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches>::create();
819         for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
820             Vector<RefPtr<StyleRuleBase> > matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
821             if (!matchedRules.isEmpty()) {
822                 RefPtr<TypeBuilder::CSS::PseudoIdMatches> matches = TypeBuilder::CSS::PseudoIdMatches::create()
823                     .setPseudoId(static_cast<int>(pseudoId))
824                     .setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, element));
825                 pseudoElements->addItem(matches.release());
826             }
827         }
828
829         pseudoIdMatches = pseudoElements.release();
830     }
831
832     // Inherited styles.
833     if (!includeInherited || *includeInherited) {
834         RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> > entries = TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry>::create();
835         Element* parentElement = element->parentElement();
836         while (parentElement) {
837             StyleResolver& parentStyleResolver = parentElement->document()->ensureStyleResolver();
838             Vector<RefPtr<StyleRuleBase> > parentMatchedRules = parentStyleResolver.styleRulesForElement(parentElement, StyleResolver::AllCSSRules);
839             RefPtr<TypeBuilder::CSS::InheritedStyleEntry> entry = TypeBuilder::CSS::InheritedStyleEntry::create()
840                 .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules, styleResolver, parentElement));
841             if (parentElement->style() && parentElement->style()->length()) {
842                 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
843                 if (styleSheet)
844                     entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
845             }
846
847             entries->addItem(entry.release());
848             parentElement = parentElement->parentElement();
849         }
850
851         inheritedEntries = entries.release();
852     }
853 }
854
855 void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<TypeBuilder::CSS::CSSStyle>& attributesStyle)
856 {
857     Element* element = elementForId(errorString, nodeId);
858     if (!element)
859         return;
860
861     InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
862     if (!styleSheet)
863         return;
864
865     inlineStyle = styleSheet->buildObjectForStyle(element->style());
866     RefPtr<TypeBuilder::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
867     attributesStyle = attributes ? attributes.release() : 0;
868 }
869
870 void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> >& style)
871 {
872     Element* element = elementForId(errorString, nodeId);
873     if (!element)
874         return;
875
876     RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(element, true);
877     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
878     style = inspectorStyle->buildArrayForComputedStyle();
879 }
880
881 void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader> >& styleInfos)
882 {
883     styleInfos = TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>::create();
884     Vector<Document*> documents = m_domAgent->documents();
885     for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
886         StyleSheetList* list = (*it)->styleSheets();
887         for (unsigned i = 0; i < list->length(); ++i) {
888             StyleSheet* styleSheet = list->item(i);
889             if (styleSheet->isCSSStyleSheet())
890                 collectStyleSheets(static_cast<CSSStyleSheet*>(styleSheet), styleInfos.get());
891         }
892     }
893 }
894
895 void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<TypeBuilder::CSS::CSSStyleSheetBody>& styleSheetObject)
896 {
897     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
898     if (!inspectorStyleSheet)
899         return;
900
901     styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
902 }
903
904 void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
905 {
906     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
907     if (!inspectorStyleSheet)
908         return;
909
910     inspectorStyleSheet->getText(result);
911 }
912
913 void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
914 {
915     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
916     if (!inspectorStyleSheet)
917         return;
918
919     ExceptionCode ec = 0;
920     m_domAgent->history()->perform(adoptPtr(new SetStyleSheetTextAction(inspectorStyleSheet, text)), ec);
921     *errorString = InspectorDOMAgent::toErrorString(ec);
922 }
923
924 void InspectorCSSAgent::setStyleText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, const String& text, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
925 {
926     InspectorCSSId compoundId(fullStyleId);
927     ASSERT(!compoundId.isEmpty());
928
929     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
930     if (!inspectorStyleSheet)
931         return;
932
933     ExceptionCode ec = 0;
934     bool success = m_domAgent->history()->perform(adoptPtr(new SetStyleTextAction(inspectorStyleSheet, compoundId, text)), ec);
935     if (success)
936         result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
937     *errorString = InspectorDOMAgent::toErrorString(ec);
938 }
939
940 void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
941 {
942     InspectorCSSId compoundId(fullStyleId);
943     ASSERT(!compoundId.isEmpty());
944
945     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
946     if (!inspectorStyleSheet)
947         return;
948
949     ExceptionCode ec = 0;
950     bool success = m_domAgent->history()->perform(adoptPtr(new SetPropertyTextAction(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite)), ec);
951     if (success)
952         result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
953     *errorString = InspectorDOMAgent::toErrorString(ec);
954 }
955
956 void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
957 {
958     InspectorCSSId compoundId(fullStyleId);
959     ASSERT(!compoundId.isEmpty());
960
961     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
962     if (!inspectorStyleSheet)
963         return;
964
965     ExceptionCode ec = 0;
966     bool success = m_domAgent->history()->perform(adoptPtr(new TogglePropertyAction(inspectorStyleSheet, compoundId, propertyIndex, disable)), ec);
967     if (success)
968         result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
969     *errorString = InspectorDOMAgent::toErrorString(ec);
970 }
971
972 void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
973 {
974     InspectorCSSId compoundId(fullRuleId);
975     ASSERT(!compoundId.isEmpty());
976
977     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
978     if (!inspectorStyleSheet)
979         return;
980
981     ExceptionCode ec = 0;
982     bool success = m_domAgent->history()->perform(adoptPtr(new SetRuleSelectorAction(inspectorStyleSheet, compoundId, selector)), ec);
983
984     if (success)
985         result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
986     *errorString = InspectorDOMAgent::toErrorString(ec);
987 }
988
989 void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
990 {
991     Node* node = m_domAgent->assertNode(errorString, contextNodeId);
992     if (!node)
993         return;
994
995     InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
996     if (!inspectorStyleSheet) {
997         *errorString = "No target stylesheet found";
998         return;
999     }
1000
1001     ExceptionCode ec = 0;
1002     OwnPtr<AddRuleAction> action = adoptPtr(new AddRuleAction(inspectorStyleSheet, selector));
1003     AddRuleAction* rawAction = action.get();
1004     bool success = m_domAgent->history()->perform(action.release(), ec);
1005     if (!success) {
1006         *errorString = InspectorDOMAgent::toErrorString(ec);
1007         return;
1008     }
1009
1010     InspectorCSSId ruleId = rawAction->newRuleId();
1011     CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
1012     result = inspectorStyleSheet->buildObjectForRule(rule);
1013 }
1014
1015 void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> >& cssProperties)
1016 {
1017     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo> > properties = TypeBuilder::Array<TypeBuilder::CSS::CSSPropertyInfo>::create();
1018     for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
1019         CSSPropertyID id = convertToCSSPropertyID(i);
1020         RefPtr<TypeBuilder::CSS::CSSPropertyInfo> property = TypeBuilder::CSS::CSSPropertyInfo::create()
1021             .setName(getPropertyNameString(id));
1022
1023         const StylePropertyShorthand& shorthand = shorthandForProperty(id);
1024         if (!shorthand.length()) {
1025             properties->addItem(property.release());
1026             continue;
1027         }
1028         RefPtr<TypeBuilder::Array<String> > longhands = TypeBuilder::Array<String>::create();
1029         for (unsigned j = 0; j < shorthand.length(); ++j) {
1030             CSSPropertyID longhandID = shorthand.properties()[j];
1031             longhands->addItem(getPropertyNameString(longhandID));
1032         }
1033         property->setLonghands(longhands);
1034         properties->addItem(property.release());
1035     }
1036     cssProperties = properties.release();
1037 }
1038
1039 void InspectorCSSAgent::forcePseudoState(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>& forcedPseudoClasses)
1040 {
1041     Element* element = m_domAgent->assertElement(errorString, nodeId);
1042     if (!element)
1043         return;
1044
1045     unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses.get());
1046     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
1047     unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value;
1048     bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState;
1049     if (!needStyleRecalc)
1050         return;
1051
1052     if (forcedPseudoState)
1053         m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
1054     else
1055         m_nodeIdToForcedPseudoState.remove(nodeId);
1056     element->document()->styleResolverChanged(RecalcStyleImmediately);
1057 }
1058
1059 void InspectorCSSAgent::getNamedFlowCollection(ErrorString* errorString, int documentNodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> >& result)
1060 {
1061     Document* document = m_domAgent->assertDocument(errorString, documentNodeId);
1062     if (!document)
1063         return;
1064
1065     m_namedFlowCollectionsRequested.add(documentNodeId);
1066
1067     Vector<RefPtr<WebKitNamedFlow> > namedFlowsVector = document->namedFlows()->namedFlows();
1068     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::NamedFlow> > namedFlows = TypeBuilder::Array<TypeBuilder::CSS::NamedFlow>::create();
1069
1070     for (Vector<RefPtr<WebKitNamedFlow> >::iterator it = namedFlowsVector.begin(); it != namedFlowsVector.end(); ++it)
1071         namedFlows->addItem(buildObjectForNamedFlow(errorString, it->get(), documentNodeId));
1072
1073     result = namedFlows.release();
1074 }
1075
1076 void InspectorCSSAgent::startSelectorProfiler(ErrorString*)
1077 {
1078     m_currentSelectorProfile = adoptPtr(new SelectorProfile());
1079     m_state->setBoolean(CSSAgentState::isSelectorProfiling, true);
1080 }
1081
1082 void InspectorCSSAgent::stopSelectorProfiler(ErrorString* errorString, RefPtr<TypeBuilder::CSS::SelectorProfile>& result)
1083 {
1084     result = stopSelectorProfilerImpl(errorString, true);
1085 }
1086
1087 PassRefPtr<TypeBuilder::CSS::SelectorProfile> InspectorCSSAgent::stopSelectorProfilerImpl(ErrorString*, bool needProfile)
1088 {
1089     if (!m_state->getBoolean(CSSAgentState::isSelectorProfiling))
1090         return 0;
1091     m_state->setBoolean(CSSAgentState::isSelectorProfiling, false);
1092     RefPtr<TypeBuilder::CSS::SelectorProfile> result;
1093     if (m_frontend && needProfile)
1094         result = m_currentSelectorProfile->toInspectorObject();
1095     m_currentSelectorProfile.clear();
1096     return result.release();
1097 }
1098
1099 void InspectorCSSAgent::willMatchRule(StyleRule* rule, InspectorCSSOMWrappers& inspectorCSSOMWrappers, DocumentStyleSheetCollection* styleSheetCollection)
1100 {
1101 //    printf("InspectorCSSAgent::willMatchRule %s\n", rule->selectorList().selectorsText().utf8().data());
1102     if (m_currentSelectorProfile)
1103         m_currentSelectorProfile->startSelector(inspectorCSSOMWrappers.getWrapperForRuleInSheets(rule, styleSheetCollection));
1104 }
1105
1106 void InspectorCSSAgent::didMatchRule(bool matched)
1107 {
1108     if (m_currentSelectorProfile)
1109         m_currentSelectorProfile->commitSelector(matched);
1110 }
1111
1112 void InspectorCSSAgent::willProcessRule(StyleRule* rule, StyleResolver& styleResolver)
1113 {
1114     if (m_currentSelectorProfile)
1115         m_currentSelectorProfile->startSelector(styleResolver.inspectorCSSOMWrappers().getWrapperForRuleInSheets(rule, styleResolver.document()->styleSheetCollection()));
1116 }
1117
1118 void InspectorCSSAgent::didProcessRule()
1119 {
1120     if (m_currentSelectorProfile)
1121         m_currentSelectorProfile->commitSelectorTime();
1122 }
1123
1124 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
1125 {
1126     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1127     if (it == m_nodeToInspectorStyleSheet.end()) {
1128         CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
1129         if (!style)
1130             return 0;
1131
1132         String newStyleSheetId = String::number(m_lastStyleSheetId++);
1133         RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_domAgent->pageAgent(), newStyleSheetId, element, TypeBuilder::CSS::StyleSheetOrigin::Regular, this);
1134         m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
1135         m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
1136         return inspectorStyleSheet.get();
1137     }
1138
1139     return it->value.get();
1140 }
1141
1142 Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
1143 {
1144     Node* node = m_domAgent->nodeForId(nodeId);
1145     if (!node) {
1146         *errorString = "No node with given id found";
1147         return 0;
1148     }
1149     if (node->nodeType() != Node::ELEMENT_NODE) {
1150         *errorString = "Not an element node";
1151         return 0;
1152     }
1153     return toElement(node);
1154 }
1155
1156 int InspectorCSSAgent::documentNodeWithRequestedFlowsId(Document* document)
1157 {
1158     int documentNodeId = m_domAgent->boundNodeId(document);
1159     if (!documentNodeId || !m_namedFlowCollectionsRequested.contains(documentNodeId))
1160         return 0;
1161
1162     return documentNodeId;
1163 }
1164
1165 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, TypeBuilder::Array<TypeBuilder::CSS::CSSStyleSheetHeader>* result)
1166 {
1167     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
1168     result->addItem(inspectorStyleSheet->buildObjectForStyleSheetInfo());
1169     for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
1170         CSSRule* rule = styleSheet->item(i);
1171         if (rule->type() == CSSRule::IMPORT_RULE) {
1172             CSSStyleSheet* importedStyleSheet = static_cast<CSSImportRule*>(rule)->styleSheet();
1173             if (importedStyleSheet)
1174                 collectStyleSheets(importedStyleSheet, result);
1175         }
1176     }
1177 }
1178
1179 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
1180 {
1181     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
1182     if (!inspectorStyleSheet) {
1183         String id = String::number(m_lastStyleSheetId++);
1184         Document* document = styleSheet->ownerDocument();
1185         inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
1186         m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
1187         m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
1188     }
1189     return inspectorStyleSheet.get();
1190 }
1191
1192 InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
1193 {
1194     if (!document) {
1195         ASSERT(!createIfAbsent);
1196         return 0;
1197     }
1198
1199     if (!document->isHTMLDocument() && !document->isSVGDocument())
1200         return 0;
1201
1202     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
1203     if (inspectorStyleSheet || !createIfAbsent)
1204         return inspectorStyleSheet.get();
1205
1206     ExceptionCode ec = 0;
1207     RefPtr<Element> styleElement = document->createElement("style", ec);
1208     if (!ec)
1209         styleElement->setAttribute("type", "text/css", ec);
1210     if (!ec) {
1211         ContainerNode* targetNode;
1212         // HEAD is absent in ImageDocuments, for example.
1213         if (document->head())
1214             targetNode = document->head();
1215         else if (document->body())
1216             targetNode = document->body();
1217         else
1218             return 0;
1219
1220         InlineStyleOverrideScope overrideScope(document);
1221         targetNode->appendChild(styleElement, ec);
1222     }
1223     if (ec)
1224         return 0;
1225
1226     CSSStyleSheet* cssStyleSheet = 0;
1227     if (styleElement->isHTMLElement())
1228         cssStyleSheet = toHTMLStyleElement(styleElement.get())->sheet();
1229 #if ENABLE(SVG)
1230     else if (styleElement->isSVGElement())
1231         cssStyleSheet = static_cast<SVGStyleElement*>(styleElement.get())->sheet();
1232 #endif
1233
1234     if (!cssStyleSheet)
1235         return 0;
1236
1237     String id = String::number(m_lastStyleSheetId++);
1238     inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, cssStyleSheet, TypeBuilder::CSS::StyleSheetOrigin::Inspector, InspectorDOMAgent::documentURLString(document), this);
1239     m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
1240     m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
1241     m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
1242     return inspectorStyleSheet.get();
1243 }
1244
1245 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
1246 {
1247     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
1248     if (it == m_idToInspectorStyleSheet.end()) {
1249         *errorString = "No style sheet with given id found";
1250         return 0;
1251     }
1252     return it->value.get();
1253 }
1254
1255 TypeBuilder::CSS::StyleSheetOrigin::Enum InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
1256 {
1257     TypeBuilder::CSS::StyleSheetOrigin::Enum origin = TypeBuilder::CSS::StyleSheetOrigin::Regular;
1258     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
1259         origin = TypeBuilder::CSS::StyleSheetOrigin::User_agent;
1260     else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
1261         origin = TypeBuilder::CSS::StyleSheetOrigin::User;
1262     else {
1263         InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
1264         if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
1265             origin = TypeBuilder::CSS::StyleSheetOrigin::Inspector;
1266     }
1267     return origin;
1268 }
1269
1270 PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(StyleRule* styleRule, StyleResolver& styleResolver)
1271 {
1272     if (!styleRule)
1273         return 0;
1274
1275     // StyleRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
1276     // Since the inspector wants to walk the parent chain, we construct the full wrappers here.
1277     CSSStyleRule* cssomWrapper = styleResolver.inspectorCSSOMWrappers().getWrapperForRuleInSheets(styleRule, styleResolver.document()->styleSheetCollection());
1278     if (!cssomWrapper)
1279         return 0;
1280     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssomWrapper->parentStyleSheet());
1281     return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(cssomWrapper) : 0;
1282 }
1283
1284 PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule)
1285 {
1286     if (!rule)
1287         return 0;
1288
1289     ASSERT(rule->parentStyleSheet());
1290     InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(rule->parentStyleSheet());
1291     return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(rule) : 0;
1292 }
1293
1294 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
1295 {
1296     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSRule>::create();
1297     if (!ruleList)
1298         return result.release();
1299
1300     for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
1301         CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
1302         RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule);
1303         if (!ruleObject)
1304             continue;
1305         result->addItem(ruleObject);
1306     }
1307     return result.release();
1308 }
1309
1310 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRuleBase> >& matchedRules, StyleResolver& styleResolver, Element* element)
1311 {
1312     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > result = TypeBuilder::Array<TypeBuilder::CSS::RuleMatch>::create();
1313
1314     for (unsigned i = 0; i < matchedRules.size(); ++i) {
1315         if (!matchedRules[i]->isStyleRule())
1316             continue;
1317         StyleRule* matchedStyleRule = static_cast<StyleRule*>(matchedRules[i].get());
1318         RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(matchedStyleRule, styleResolver);
1319         if (!ruleObject)
1320             continue;
1321         RefPtr<TypeBuilder::Array<int> > matchingSelectors = TypeBuilder::Array<int>::create();
1322         const CSSSelectorList& selectorList = matchedStyleRule->selectorList();
1323         long index = 0;
1324         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
1325             bool matched = element->webkitMatchesSelector(selector->selectorText(), IGNORE_EXCEPTION);
1326             if (matched)
1327                 matchingSelectors->addItem(index);
1328             ++index;
1329         }
1330         RefPtr<TypeBuilder::CSS::RuleMatch> match = TypeBuilder::CSS::RuleMatch::create()
1331             .setRule(ruleObject)
1332             .setMatchingSelectors(matchingSelectors);
1333         result->addItem(match);
1334     }
1335
1336     return result.release();
1337 }
1338
1339 PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
1340 {
1341     if (!element->isStyledElement())
1342         return 0;
1343
1344     // FIXME: Ugliness below.
1345     StylePropertySet* attributeStyle = const_cast<StylePropertySet*>(static_cast<StyledElement*>(element)->presentationAttributeStyle());
1346     if (!attributeStyle)
1347         return 0;
1348
1349     ASSERT(attributeStyle->isMutable());
1350     MutableStylePropertySet* mutableAttributeStyle = static_cast<MutableStylePropertySet*>(attributeStyle);
1351
1352     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), 0);
1353     return inspectorStyle->buildObjectForStyle();
1354 }
1355
1356 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > InspectorCSSAgent::buildArrayForRegions(ErrorString* errorString, PassRefPtr<NodeList> regionList, int documentNodeId)
1357 {
1358     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::Region> > regions = TypeBuilder::Array<TypeBuilder::CSS::Region>::create();
1359
1360     for (unsigned i = 0; i < regionList->length(); ++i) {
1361         TypeBuilder::CSS::Region::RegionOverset::Enum regionOverset;
1362
1363         switch (toElement(regionList->item(i))->renderRegion()->regionOversetState()) {
1364         case RegionFit:
1365             regionOverset = TypeBuilder::CSS::Region::RegionOverset::Fit;
1366             break;
1367         case RegionEmpty:
1368             regionOverset = TypeBuilder::CSS::Region::RegionOverset::Empty;
1369             break;
1370         case RegionOverset:
1371             regionOverset = TypeBuilder::CSS::Region::RegionOverset::Overset;
1372             break;
1373         case RegionUndefined:
1374             continue;
1375         default:
1376             ASSERT_NOT_REACHED();
1377             continue;
1378         }
1379
1380         RefPtr<TypeBuilder::CSS::Region> region = TypeBuilder::CSS::Region::create()
1381             .setRegionOverset(regionOverset)
1382             // documentNodeId was previously asserted
1383             .setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i)));
1384
1385         regions->addItem(region);
1386     }
1387
1388     return regions.release();
1389 }
1390
1391 PassRefPtr<TypeBuilder::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString* errorString, WebKitNamedFlow* webkitNamedFlow, int documentNodeId)
1392 {
1393     RefPtr<NodeList> contentList = webkitNamedFlow->getContent();
1394     RefPtr<TypeBuilder::Array<int> > content = TypeBuilder::Array<int>::create();
1395
1396     for (unsigned i = 0; i < contentList->length(); ++i) {
1397         // documentNodeId was previously asserted
1398         content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i)));
1399     }
1400
1401     RefPtr<TypeBuilder::CSS::NamedFlow> namedFlow = TypeBuilder::CSS::NamedFlow::create()
1402         .setDocumentNodeId(documentNodeId)
1403         .setName(webkitNamedFlow->name().string())
1404         .setOverset(webkitNamedFlow->overset())
1405         .setContent(content)
1406         .setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId));
1407
1408     return namedFlow.release();
1409 }
1410
1411 void InspectorCSSAgent::didRemoveDocument(Document* document)
1412 {
1413     if (document)
1414         m_documentToInspectorStyleSheet.remove(document);
1415 }
1416
1417 void InspectorCSSAgent::didRemoveDOMNode(Node* node)
1418 {
1419     if (!node)
1420         return;
1421
1422     int nodeId = m_domAgent->boundNodeId(node);
1423     if (nodeId)
1424         m_nodeIdToForcedPseudoState.remove(nodeId);
1425
1426     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
1427     if (it == m_nodeToInspectorStyleSheet.end())
1428         return;
1429
1430     m_idToInspectorStyleSheet.remove(it->value->id());
1431     m_nodeToInspectorStyleSheet.remove(node);
1432 }
1433
1434 void InspectorCSSAgent::didModifyDOMAttr(Element* element)
1435 {
1436     if (!element)
1437         return;
1438
1439     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1440     if (it == m_nodeToInspectorStyleSheet.end())
1441         return;
1442
1443     it->value->didModifyElementAttribute();
1444 }
1445
1446 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1447 {
1448     if (m_frontend)
1449         m_frontend->styleSheetChanged(styleSheet->id());
1450 }
1451
1452 void InspectorCSSAgent::resetPseudoStates()
1453 {
1454     HashSet<Document*> documentsToChange;
1455     for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) {
1456         Element* element = toElement(m_domAgent->nodeForId(it->key));
1457         if (element && element->document())
1458             documentsToChange.add(element->document());
1459     }
1460
1461     m_nodeIdToForcedPseudoState.clear();
1462     for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
1463         (*it)->styleResolverChanged(RecalcStyleImmediately);
1464 }
1465
1466 } // namespace WebCore
1467
1468 #endif // ENABLE(INSPECTOR)