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