Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 #include "core/inspector/InspectorCSSAgent.h"
27
28 #include "CSSPropertyNames.h"
29 #include "FetchInitiatorTypeNames.h"
30 #include "InspectorTypeBuilder.h"
31 #include "StylePropertyShorthand.h"
32 #include "bindings/v8/ExceptionState.h"
33 #include "bindings/v8/ExceptionStatePlaceholder.h"
34 #include "core/css/CSSComputedStyleDeclaration.h"
35 #include "core/css/CSSDefaultStyleSheets.h"
36 #include "core/css/CSSImportRule.h"
37 #include "core/css/CSSMediaRule.h"
38 #include "core/css/CSSRule.h"
39 #include "core/css/CSSRuleList.h"
40 #include "core/css/CSSStyleRule.h"
41 #include "core/css/CSSStyleSheet.h"
42 #include "core/css/MediaList.h"
43 #include "core/css/StylePropertySet.h"
44 #include "core/css/StyleRule.h"
45 #include "core/css/StyleSheet.h"
46 #include "core/css/StyleSheetContents.h"
47 #include "core/css/StyleSheetList.h"
48 #include "core/css/resolver/StyleResolver.h"
49 #include "core/dom/Node.h"
50 #include "core/dom/NodeList.h"
51 #include "core/fetch/CSSStyleSheetResource.h"
52 #include "core/fetch/ResourceClient.h"
53 #include "core/fetch/ResourceFetcher.h"
54 #include "core/fetch/StyleSheetResourceClient.h"
55 #include "core/html/HTMLHeadElement.h"
56 #include "core/inspector/InspectorHistory.h"
57 #include "core/inspector/InspectorPageAgent.h"
58 #include "core/inspector/InspectorResourceAgent.h"
59 #include "core/inspector/InspectorState.h"
60 #include "core/inspector/InstrumentingAgents.h"
61 #include "core/loader/DocumentLoader.h"
62 #include "core/frame/Frame.h"
63 #include "core/page/Page.h"
64 #include "core/rendering/InlineTextBox.h"
65 #include "core/rendering/RenderObject.h"
66 #include "core/rendering/RenderText.h"
67 #include "core/rendering/RenderTextFragment.h"
68 #include "platform/fonts/Font.h"
69 #include "platform/fonts/GlyphBuffer.h"
70 #include "platform/fonts/WidthIterator.h"
71 #include "platform/text/TextRun.h"
72 #include "wtf/CurrentTime.h"
73 #include "wtf/text/CString.h"
74 #include "wtf/text/StringConcatenate.h"
75
76 namespace CSSAgentState {
77 static const char cssAgentEnabled[] = "cssAgentEnabled";
78 }
79
80 typedef WebCore::InspectorBackendDispatcher::CSSCommandHandler::EnableCallback EnableCallback;
81
82 namespace WebCore {
83
84 enum ForcePseudoClassFlags {
85     PseudoNone = 0,
86     PseudoHover = 1 << 0,
87     PseudoFocus = 1 << 1,
88     PseudoActive = 1 << 2,
89     PseudoVisited = 1 << 3
90 };
91
92 static unsigned computePseudoClassMask(JSONArray* pseudoClassArray)
93 {
94     DEFINE_STATIC_LOCAL(String, active, ("active"));
95     DEFINE_STATIC_LOCAL(String, hover, ("hover"));
96     DEFINE_STATIC_LOCAL(String, focus, ("focus"));
97     DEFINE_STATIC_LOCAL(String, visited, ("visited"));
98     if (!pseudoClassArray || !pseudoClassArray->length())
99         return PseudoNone;
100
101     unsigned result = PseudoNone;
102     for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
103         RefPtr<JSONValue> pseudoClassValue = pseudoClassArray->get(i);
104         String pseudoClass;
105         bool success = pseudoClassValue->asString(&pseudoClass);
106         if (!success)
107             continue;
108         if (pseudoClass == active)
109             result |= PseudoActive;
110         else if (pseudoClass == hover)
111             result |= PseudoHover;
112         else if (pseudoClass == focus)
113             result |= PseudoFocus;
114         else if (pseudoClass == visited)
115             result |= PseudoVisited;
116     }
117
118     return result;
119 }
120
121 class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
122     WTF_MAKE_NONCOPYABLE(StyleSheetAction);
123 public:
124     StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
125         : InspectorHistory::Action(name)
126         , m_styleSheet(styleSheet)
127     {
128     }
129
130 protected:
131     RefPtr<InspectorStyleSheet> m_styleSheet;
132 };
133
134 class InspectorCSSAgent::EnableResourceClient FINAL : public StyleSheetResourceClient {
135 public:
136     EnableResourceClient(InspectorCSSAgent*, const Vector<InspectorStyleSheet*>&, PassRefPtr<EnableCallback>);
137
138     virtual void setCSSStyleSheet(const String&, const KURL&, const String&, const CSSStyleSheetResource*) OVERRIDE;
139
140 private:
141     RefPtr<EnableCallback> m_callback;
142     InspectorCSSAgent* m_cssAgent;
143     int m_pendingResources;
144     Vector<InspectorStyleSheet*> m_styleSheets;
145 };
146
147 InspectorCSSAgent::EnableResourceClient::EnableResourceClient(InspectorCSSAgent* cssAgent, const Vector<InspectorStyleSheet*>& styleSheets, PassRefPtr<EnableCallback> callback)
148     : m_callback(callback)
149     , m_cssAgent(cssAgent)
150     , m_pendingResources(styleSheets.size())
151     , m_styleSheets(styleSheets)
152 {
153     for (size_t i = 0; i < styleSheets.size(); ++i) {
154         InspectorStyleSheet* styleSheet = styleSheets.at(i);
155         Document* document = styleSheet->ownerDocument();
156         FetchRequest request(ResourceRequest(styleSheet->finalURL()), FetchInitiatorTypeNames::internal);
157         ResourcePtr<Resource> resource = document->fetcher()->fetchCSSStyleSheet(request);
158         resource->addClient(this);
159     }
160 }
161
162 void InspectorCSSAgent::EnableResourceClient::setCSSStyleSheet(const String&, const KURL& url, const String&, const CSSStyleSheetResource* resource)
163 {
164     const_cast<CSSStyleSheetResource*>(resource)->removeClient(this);
165     --m_pendingResources;
166     if (m_pendingResources)
167         return;
168
169     // enable always succeeds.
170     if (m_callback->isActive())
171         m_cssAgent->wasEnabled(m_callback.release());
172     delete this;
173 }
174
175 class InspectorCSSAgent::SetStyleSheetTextAction FINAL : public InspectorCSSAgent::StyleSheetAction {
176     WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
177 public:
178     SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
179         : InspectorCSSAgent::StyleSheetAction("SetStyleSheetText", styleSheet)
180         , m_text(text)
181     {
182     }
183
184     virtual bool perform(ExceptionState& exceptionState) OVERRIDE
185     {
186         if (!m_styleSheet->getText(&m_oldText))
187             return false;
188         return redo(exceptionState);
189     }
190
191     virtual bool undo(ExceptionState& exceptionState) OVERRIDE
192     {
193         if (m_styleSheet->setText(m_oldText, exceptionState)) {
194             m_styleSheet->reparseStyleSheet(m_oldText);
195             return true;
196         }
197         return false;
198     }
199
200     virtual bool redo(ExceptionState& exceptionState) OVERRIDE
201     {
202         if (m_styleSheet->setText(m_text, exceptionState)) {
203             m_styleSheet->reparseStyleSheet(m_text);
204             return true;
205         }
206         return false;
207     }
208
209     virtual String mergeId() OVERRIDE
210     {
211         return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
212     }
213
214     virtual void merge(PassOwnPtr<Action> action) OVERRIDE
215     {
216         ASSERT(action->mergeId() == mergeId());
217
218         SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get());
219         m_text = other->m_text;
220     }
221
222 private:
223     String m_text;
224     String m_oldText;
225 };
226
227 class InspectorCSSAgent::SetPropertyTextAction FINAL : public InspectorCSSAgent::StyleSheetAction {
228     WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
229 public:
230     SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
231         : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
232         , m_cssId(cssId)
233         , m_propertyIndex(propertyIndex)
234         , m_text(text)
235         , m_overwrite(overwrite)
236     {
237     }
238
239     virtual String toString() OVERRIDE
240     {
241         return mergeId() + ": " + m_oldText + " -> " + m_text;
242     }
243
244     virtual bool perform(ExceptionState& exceptionState) OVERRIDE
245     {
246         return redo(exceptionState);
247     }
248
249     virtual bool undo(ExceptionState& exceptionState) OVERRIDE
250     {
251         String placeholder;
252         return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, exceptionState);
253     }
254
255     virtual bool redo(ExceptionState& exceptionState) OVERRIDE
256     {
257         String oldText;
258         bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, exceptionState);
259         m_oldText = oldText.stripWhiteSpace();
260         return result;
261     }
262
263     virtual String mergeId() OVERRIDE
264     {
265         return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false");
266     }
267
268     virtual void merge(PassOwnPtr<Action> action) OVERRIDE
269     {
270         ASSERT(action->mergeId() == mergeId());
271
272         SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
273         m_text = other->m_text;
274     }
275
276 private:
277     InspectorCSSId m_cssId;
278     unsigned m_propertyIndex;
279     String m_text;
280     String m_oldText;
281     bool m_overwrite;
282 };
283
284 class InspectorCSSAgent::SetRuleSelectorAction FINAL : public InspectorCSSAgent::StyleSheetAction {
285     WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
286 public:
287     SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
288         : InspectorCSSAgent::StyleSheetAction("SetRuleSelector", styleSheet)
289         , m_cssId(cssId)
290         , m_selector(selector)
291     {
292     }
293
294     virtual bool perform(ExceptionState& exceptionState) OVERRIDE
295     {
296         m_oldSelector = m_styleSheet->ruleSelector(m_cssId, exceptionState);
297         if (exceptionState.hadException())
298             return false;
299         return redo(exceptionState);
300     }
301
302     virtual bool undo(ExceptionState& exceptionState) OVERRIDE
303     {
304         return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, exceptionState);
305     }
306
307     virtual bool redo(ExceptionState& exceptionState) OVERRIDE
308     {
309         return m_styleSheet->setRuleSelector(m_cssId, m_selector, exceptionState);
310     }
311
312 private:
313     InspectorCSSId m_cssId;
314     String m_selector;
315     String m_oldSelector;
316 };
317
318 class InspectorCSSAgent::AddRuleAction FINAL : public InspectorCSSAgent::StyleSheetAction {
319     WTF_MAKE_NONCOPYABLE(AddRuleAction);
320 public:
321     AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
322         : InspectorCSSAgent::StyleSheetAction("AddRule", styleSheet)
323         , m_selector(selector)
324     {
325     }
326
327     virtual bool perform(ExceptionState& exceptionState) OVERRIDE
328     {
329         return redo(exceptionState);
330     }
331
332     virtual bool undo(ExceptionState& exceptionState) OVERRIDE
333     {
334         return m_styleSheet->deleteRule(m_newId, exceptionState);
335     }
336
337     virtual bool redo(ExceptionState& exceptionState) OVERRIDE
338     {
339         CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, exceptionState);
340         if (exceptionState.hadException())
341             return false;
342         m_newId = m_styleSheet->ruleId(cssStyleRule);
343         return true;
344     }
345
346     InspectorCSSId newRuleId() { return m_newId; }
347
348 private:
349     InspectorCSSId m_newId;
350     String m_selector;
351     String m_oldSelector;
352 };
353
354 // static
355 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
356 {
357     if (!rule || rule->type() != CSSRule::STYLE_RULE)
358         return 0;
359     return toCSSStyleRule(rule);
360 }
361
362 template <typename CharType, size_t bufferLength>
363 static size_t vendorPrefixLowerCase(const CharType* string, size_t stringLength, char (&buffer)[bufferLength])
364 {
365     static const char lowerCaseOffset = 'a' - 'A';
366
367     if (string[0] != '-')
368         return 0;
369
370     for (size_t i = 0; i < stringLength - 1; i++) {
371         CharType c = string[i + 1];
372         if (c == '-')
373             return i;
374         if (i == bufferLength)
375             break;
376         if (c < 'A' || c > 'z')
377             break;
378         if (c >= 'a')
379             buffer[i] = c;
380         else if (c <= 'Z')
381             buffer[i] = c + lowerCaseOffset;
382         else
383             break;
384     }
385     return 0;
386 }
387
388 InspectorCSSAgent::InspectorCSSAgent(InspectorDOMAgent* domAgent, InspectorPageAgent* pageAgent, InspectorResourceAgent* resourceAgent)
389     : InspectorBaseAgent<InspectorCSSAgent>("CSS")
390     , m_frontend(0)
391     , m_domAgent(domAgent)
392     , m_pageAgent(pageAgent)
393     , m_resourceAgent(resourceAgent)
394     , m_lastStyleSheetId(1)
395     , m_styleSheetsPendingMutation(0)
396     , m_styleDeclarationPendingMutation(false)
397     , m_creatingViaInspectorStyleSheet(false)
398     , m_isSettingStyleSheetText(false)
399 {
400     m_domAgent->setDOMListener(this);
401 }
402
403 InspectorCSSAgent::~InspectorCSSAgent()
404 {
405     ASSERT(!m_domAgent);
406     reset();
407 }
408
409 void InspectorCSSAgent::setFrontend(InspectorFrontend* frontend)
410 {
411     ASSERT(!m_frontend);
412     m_frontend = frontend->css();
413 }
414
415 void InspectorCSSAgent::clearFrontend()
416 {
417     ASSERT(m_frontend);
418     m_frontend = 0;
419     resetNonPersistentData();
420 }
421
422 void InspectorCSSAgent::discardAgent()
423 {
424     m_domAgent->setDOMListener(0);
425     m_domAgent = 0;
426 }
427
428 void InspectorCSSAgent::restore()
429 {
430     if (m_state->getBoolean(CSSAgentState::cssAgentEnabled))
431         wasEnabled(0);
432 }
433
434 void InspectorCSSAgent::reset()
435 {
436     m_idToInspectorStyleSheet.clear();
437     m_cssStyleSheetToInspectorStyleSheet.clear();
438     m_frameToCSSStyleSheets.clear();
439     m_nodeToInspectorStyleSheet.clear();
440     m_documentToViaInspectorStyleSheet.clear();
441     resetNonPersistentData();
442 }
443
444 void InspectorCSSAgent::resetNonPersistentData()
445 {
446     resetPseudoStates();
447 }
448
449 void InspectorCSSAgent::enable(ErrorString*, PassRefPtr<EnableCallback> prpCallback)
450 {
451     m_state->setBoolean(CSSAgentState::cssAgentEnabled, true);
452
453     Vector<InspectorStyleSheet*> styleSheets;
454     collectAllStyleSheets(styleSheets);
455
456     // Re-issue stylesheet requets for resources that are no longer in memory cache.
457     Vector<InspectorStyleSheet*> styleSheetsToFetch;
458     HashSet<String> urlsToFetch;
459     for (size_t i = 0; i < styleSheets.size(); ++i) {
460         InspectorStyleSheet* styleSheet = styleSheets.at(i);
461         String url = styleSheet->finalURL();
462         if (urlsToFetch.contains(url))
463             continue;
464         CSSStyleSheet* pageStyleSheet = styleSheet->pageStyleSheet();
465         if (pageStyleSheet->isInline() || !pageStyleSheet->contents()->loadCompleted())
466             continue;
467         Document* document = styleSheet->ownerDocument();
468         if (!document)
469             continue;
470         Resource* cachedResource = document->fetcher()->cachedResource(document->completeURL(url));
471         if (cachedResource)
472             continue;
473         urlsToFetch.add(styleSheet->finalURL());
474         styleSheetsToFetch.append(styleSheet);
475     }
476
477     if (styleSheetsToFetch.isEmpty()) {
478         wasEnabled(prpCallback);
479         return;
480     }
481     new EnableResourceClient(this, styleSheetsToFetch, prpCallback);
482 }
483
484 void InspectorCSSAgent::wasEnabled(PassRefPtr<EnableCallback> callback)
485 {
486     if (!m_state->getBoolean(CSSAgentState::cssAgentEnabled)) {
487         // We were disabled while fetching resources.
488         return;
489     }
490
491     m_instrumentingAgents->setInspectorCSSAgent(this);
492     Vector<Document*> documents = m_domAgent->documents();
493     for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
494         Document* document = *it;
495         updateActiveStyleSheetsForDocument(document, InitialFrontendLoad);
496     }
497
498     if (callback)
499         callback->sendSuccess();
500 }
501
502 void InspectorCSSAgent::disable(ErrorString*)
503 {
504     m_instrumentingAgents->setInspectorCSSAgent(0);
505     m_state->setBoolean(CSSAgentState::cssAgentEnabled, false);
506 }
507
508 void InspectorCSSAgent::didCommitLoad(Frame* frame, DocumentLoader* loader)
509 {
510     if (loader->frame() == frame->page()->mainFrame()) {
511         reset();
512         return;
513     }
514
515     updateActiveStyleSheets(frame, Vector<CSSStyleSheet*>(), ExistingFrontendRefresh);
516 }
517
518 void InspectorCSSAgent::mediaQueryResultChanged()
519 {
520     if (m_frontend)
521         m_frontend->mediaQueryResultChanged();
522 }
523
524 void InspectorCSSAgent::willMutateRules()
525 {
526     ++m_styleSheetsPendingMutation;
527 }
528
529 void InspectorCSSAgent::didMutateRules(CSSStyleSheet* styleSheet)
530 {
531     --m_styleSheetsPendingMutation;
532     ASSERT(m_styleSheetsPendingMutation >= 0);
533
534     if (!styleSheetEditInProgress()) {
535         Document* owner = styleSheet->ownerDocument();
536         if (owner)
537             owner->modifiedStyleSheet(styleSheet, RecalcStyleDeferred, FullStyleUpdate);
538     }
539 }
540
541 void InspectorCSSAgent::willMutateStyle()
542 {
543     m_styleDeclarationPendingMutation = true;
544 }
545
546 void InspectorCSSAgent::didMutateStyle(CSSStyleDeclaration* style, bool isInlineStyle)
547 {
548     ASSERT(m_styleDeclarationPendingMutation);
549     m_styleDeclarationPendingMutation = false;
550     if (!styleSheetEditInProgress() && !isInlineStyle) {
551         CSSStyleSheet* parentSheet = style->parentStyleSheet();
552         Document* owner = parentSheet ? parentSheet->ownerDocument() : 0;
553         if (owner)
554             owner->modifiedStyleSheet(parentSheet, RecalcStyleDeferred, FullStyleUpdate);
555     }
556 }
557
558 void InspectorCSSAgent::activeStyleSheetsUpdated(Document* document)
559 {
560     if (styleSheetEditInProgress())
561         return;
562     updateActiveStyleSheetsForDocument(document, ExistingFrontendRefresh);
563 }
564
565 void InspectorCSSAgent::updateActiveStyleSheetsForDocument(Document* document, StyleSheetsUpdateType styleSheetsUpdateType)
566 {
567     Frame* frame = document->frame();
568     if (!frame)
569         return;
570     Vector<CSSStyleSheet*> newSheetsVector;
571     collectAllDocumentStyleSheets(document, newSheetsVector);
572     updateActiveStyleSheets(frame, newSheetsVector, styleSheetsUpdateType);
573 }
574
575 void InspectorCSSAgent::updateActiveStyleSheets(Frame* frame, const Vector<CSSStyleSheet*>& allSheetsVector, StyleSheetsUpdateType styleSheetsUpdateType)
576 {
577     bool isInitialFrontendLoad = styleSheetsUpdateType == InitialFrontendLoad;
578
579     HashSet<CSSStyleSheet*>* frameCSSStyleSheets = m_frameToCSSStyleSheets.get(frame);
580     if (!frameCSSStyleSheets) {
581         frameCSSStyleSheets = new HashSet<CSSStyleSheet*>();
582         OwnPtr<HashSet<CSSStyleSheet*> > frameCSSStyleSheetsPtr = adoptPtr(frameCSSStyleSheets);
583         m_frameToCSSStyleSheets.set(frame, frameCSSStyleSheetsPtr.release());
584     }
585
586     HashSet<CSSStyleSheet*> removedSheets;
587     for (HashSet<CSSStyleSheet*>::iterator it = frameCSSStyleSheets->begin(); it != frameCSSStyleSheets->end(); ++it)
588         removedSheets.add(*it);
589
590     HashSet<CSSStyleSheet*> addedSheets;
591     for (Vector<CSSStyleSheet*>::const_iterator it = allSheetsVector.begin(); it != allSheetsVector.end(); ++it) {
592         CSSStyleSheet* cssStyleSheet = *it;
593         if (removedSheets.contains(cssStyleSheet)) {
594             removedSheets.remove(cssStyleSheet);
595             if (isInitialFrontendLoad)
596                 addedSheets.add(cssStyleSheet);
597         } else {
598             addedSheets.add(cssStyleSheet);
599         }
600     }
601
602     for (HashSet<CSSStyleSheet*>::iterator it = removedSheets.begin(); it != removedSheets.end(); ++it) {
603         CSSStyleSheet* cssStyleSheet = *it;
604         RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(cssStyleSheet);
605         ASSERT(inspectorStyleSheet);
606
607         if (m_idToInspectorStyleSheet.contains(inspectorStyleSheet->id())) {
608             String id = unbindStyleSheet(inspectorStyleSheet.get());
609             frameCSSStyleSheets->remove(cssStyleSheet);
610             if (m_frontend && !isInitialFrontendLoad)
611                 m_frontend->styleSheetRemoved(id);
612         }
613     }
614
615     for (HashSet<CSSStyleSheet*>::iterator it = addedSheets.begin(); it != addedSheets.end(); ++it) {
616         CSSStyleSheet* cssStyleSheet = *it;
617         bool isNew = isInitialFrontendLoad || !m_cssStyleSheetToInspectorStyleSheet.contains(cssStyleSheet);
618         if (isNew) {
619             InspectorStyleSheet* newStyleSheet = bindStyleSheet(cssStyleSheet);
620             frameCSSStyleSheets->add(cssStyleSheet);
621             if (m_frontend)
622                 m_frontend->styleSheetAdded(newStyleSheet->buildObjectForStyleSheetInfo());
623         }
624     }
625
626     if (frameCSSStyleSheets->isEmpty())
627         m_frameToCSSStyleSheets.remove(frame);
628 }
629
630 void InspectorCSSAgent::frameDetachedFromParent(Frame* frame)
631 {
632     updateActiveStyleSheets(frame, Vector<CSSStyleSheet*>(), ExistingFrontendRefresh);
633 }
634
635 bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType)
636 {
637     if (m_nodeIdToForcedPseudoState.isEmpty())
638         return false;
639
640     int nodeId = m_domAgent->boundNodeId(element);
641     if (!nodeId)
642         return false;
643
644     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
645     if (it == m_nodeIdToForcedPseudoState.end())
646         return false;
647
648     unsigned forcedPseudoState = it->value;
649     switch (pseudoType) {
650     case CSSSelector::PseudoActive:
651         return forcedPseudoState & PseudoActive;
652     case CSSSelector::PseudoFocus:
653         return forcedPseudoState & PseudoFocus;
654     case CSSSelector::PseudoHover:
655         return forcedPseudoState & PseudoHover;
656     case CSSSelector::PseudoVisited:
657         return forcedPseudoState & PseudoVisited;
658     default:
659         return false;
660     }
661 }
662
663 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)
664 {
665     Element* element = elementForId(errorString, nodeId);
666     if (!element)
667         return;
668
669     Element* originalElement = element;
670     PseudoId elementPseudoId = element->pseudoId();
671     if (elementPseudoId)
672         element = element->parentOrShadowHostElement();
673
674     Document* ownerDocument = element->ownerDocument();
675     // A non-active document has no styles.
676     if (!ownerDocument->isActive())
677         return;
678
679     // FIXME: It's really gross for the inspector to reach in and access StyleResolver
680     // directly here. We need to provide the Inspector better APIs to get this information
681     // without grabbing at internal style classes!
682
683     // Matched rules.
684     StyleResolver& styleResolver = ownerDocument->ensureStyleResolver();
685
686     RefPtr<CSSRuleList> matchedRules = styleResolver.pseudoCSSRulesForElement(element, elementPseudoId, StyleResolver::AllCSSRules);
687     matchedCSSRules = buildArrayForMatchedRuleList(matchedRules.get(), originalElement);
688
689     // Pseudo elements.
690     if (!elementPseudoId && (!includePseudo || *includePseudo)) {
691         RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches> > pseudoElements = TypeBuilder::Array<TypeBuilder::CSS::PseudoIdMatches>::create();
692         for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
693             RefPtr<CSSRuleList> matchedRules = styleResolver.pseudoCSSRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
694             if (matchedRules && matchedRules->length()) {
695                 RefPtr<TypeBuilder::CSS::PseudoIdMatches> matches = TypeBuilder::CSS::PseudoIdMatches::create()
696                     .setPseudoId(static_cast<int>(pseudoId))
697                     .setMatches(buildArrayForMatchedRuleList(matchedRules.get(), element));
698                 pseudoElements->addItem(matches.release());
699             }
700         }
701
702         pseudoIdMatches = pseudoElements.release();
703     }
704
705     // Inherited styles.
706     if (!elementPseudoId && (!includeInherited || *includeInherited)) {
707         RefPtr<TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry> > entries = TypeBuilder::Array<TypeBuilder::CSS::InheritedStyleEntry>::create();
708         Element* parentElement = element->parentElement();
709         while (parentElement) {
710             StyleResolver& parentStyleResolver = parentElement->ownerDocument()->ensureStyleResolver();
711             RefPtr<CSSRuleList> parentMatchedRules = parentStyleResolver.cssRulesForElement(parentElement, StyleResolver::AllCSSRules);
712             RefPtr<TypeBuilder::CSS::InheritedStyleEntry> entry = TypeBuilder::CSS::InheritedStyleEntry::create()
713                 .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules.get(), parentElement));
714             if (parentElement->style() && parentElement->style()->length()) {
715                 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
716                 if (styleSheet)
717                     entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
718             }
719
720             entries->addItem(entry.release());
721             parentElement = parentElement->parentElement();
722         }
723
724         inheritedEntries = entries.release();
725     }
726 }
727
728 void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<TypeBuilder::CSS::CSSStyle>& attributesStyle)
729 {
730     Element* element = elementForId(errorString, nodeId);
731     if (!element)
732         return;
733
734     InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
735     if (!styleSheet)
736         return;
737
738     inlineStyle = styleSheet->buildObjectForStyle(element->style());
739     RefPtr<TypeBuilder::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
740     attributesStyle = attributes ? attributes.release() : 0;
741 }
742
743 void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> >& style)
744 {
745     Node* node = m_domAgent->assertNode(errorString, nodeId);
746     if (!node)
747         return;
748
749     RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(node, true);
750     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
751     style = inspectorStyle->buildArrayForComputedStyle();
752 }
753
754 void InspectorCSSAgent::collectPlatformFontsForRenderer(RenderText* renderer, HashCountedSet<String>* fontStats)
755 {
756     for (InlineTextBox* box = renderer->firstTextBox(); box; box = box->nextTextBox()) {
757         RenderStyle* style = renderer->style(box->isFirstLineStyle());
758         const Font& font = style->font();
759         TextRun run = box->constructTextRunForInspector(style, font);
760         WidthIterator it(&font, run, 0, false);
761         GlyphBuffer glyphBuffer;
762         it.advance(run.length(), &glyphBuffer);
763         for (unsigned i = 0; i < glyphBuffer.size(); ++i) {
764             String familyName = glyphBuffer.fontDataAt(i)->platformData().fontFamilyName();
765             if (familyName.isNull())
766                 familyName = "";
767             fontStats->add(familyName);
768         }
769     }
770 }
771
772 void InspectorCSSAgent::getPlatformFontsForNode(ErrorString* errorString, int nodeId,
773     String* cssFamilyName, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PlatformFontUsage> >& platformFonts)
774 {
775     Node* node = m_domAgent->assertNode(errorString, nodeId);
776     if (!node)
777         return;
778
779     RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(node, true);
780     *cssFamilyName = computedStyleInfo->getPropertyValue(CSSPropertyFontFamily);
781
782     Vector<Node*> textNodes;
783     if (node->nodeType() == Node::TEXT_NODE) {
784         if (node->renderer())
785             textNodes.append(node);
786     } else {
787         for (Node* child = node->firstChild(); child; child = child->nextSibling()) {
788             if (child->nodeType() == Node::TEXT_NODE && child->renderer())
789                 textNodes.append(child);
790         }
791     }
792
793     HashCountedSet<String> fontStats;
794     for (size_t i = 0; i < textNodes.size(); ++i) {
795         RenderText* renderer = toRenderText(textNodes[i]->renderer());
796         collectPlatformFontsForRenderer(renderer, &fontStats);
797         if (renderer->isTextFragment()) {
798             RenderTextFragment* textFragment = toRenderTextFragment(renderer);
799             if (textFragment->firstLetter()) {
800                 RenderObject* firstLetter = textFragment->firstLetter();
801                 for (RenderObject* current = firstLetter->firstChild(); current; current = current->nextSibling()) {
802                     if (current->isText())
803                         collectPlatformFontsForRenderer(toRenderText(current), &fontStats);
804                 }
805             }
806         }
807     }
808
809     platformFonts = TypeBuilder::Array<TypeBuilder::CSS::PlatformFontUsage>::create();
810     for (HashCountedSet<String>::iterator it = fontStats.begin(), end = fontStats.end(); it != end; ++it) {
811         RefPtr<TypeBuilder::CSS::PlatformFontUsage> platformFont = TypeBuilder::CSS::PlatformFontUsage::create()
812             .setFamilyName(it->key)
813             .setGlyphCount(it->value);
814         platformFonts->addItem(platformFont);
815     }
816 }
817
818 void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<TypeBuilder::CSS::CSSStyleSheetBody>& styleSheetObject)
819 {
820     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
821     if (!inspectorStyleSheet)
822         return;
823
824     Document* doc = inspectorStyleSheet->pageStyleSheet() ? inspectorStyleSheet->pageStyleSheet()->ownerDocument() : 0;
825     if (!doc)
826         return;
827
828     RefPtr<TypeBuilder::CSS::CSSStyleSheetBody> result = TypeBuilder::CSS::CSSStyleSheetBody::create()
829         .setRules(buildArrayForRuleList(inspectorStyleSheet->pageStyleSheet()->rules().get()));
830
831     bool success = inspectorStyleSheet->fillObjectForStyleSheet(result);
832     if (success)
833         styleSheetObject = result;
834 }
835
836 void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
837 {
838     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
839     if (!inspectorStyleSheet)
840         return;
841
842     inspectorStyleSheet->getText(result);
843 }
844
845 void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
846 {
847     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
848     if (!inspectorStyleSheet) {
849         *errorString = "Style sheet with id " + styleSheetId + " not found.";
850         return;
851     }
852
853     TrackExceptionState exceptionState;
854     m_domAgent->history()->perform(adoptPtr(new SetStyleSheetTextAction(inspectorStyleSheet, text)), exceptionState);
855     *errorString = InspectorDOMAgent::toErrorString(exceptionState);
856 }
857
858 void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<JSONObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
859 {
860     InspectorCSSId compoundId(fullStyleId);
861     ASSERT(!compoundId.isEmpty());
862
863     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
864     if (!inspectorStyleSheet)
865         return;
866
867     TrackExceptionState exceptionState;
868     bool success = m_domAgent->history()->perform(adoptPtr(new SetPropertyTextAction(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite)), exceptionState);
869     if (success)
870         result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
871     *errorString = InspectorDOMAgent::toErrorString(exceptionState);
872 }
873
874 void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<JSONObject>& fullRuleId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
875 {
876     InspectorCSSId compoundId(fullRuleId);
877     ASSERT(!compoundId.isEmpty());
878
879     InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
880     if (!inspectorStyleSheet)
881         return;
882
883     TrackExceptionState exceptionState;
884     bool success = m_domAgent->history()->perform(adoptPtr(new SetRuleSelectorAction(inspectorStyleSheet, compoundId, selector)), exceptionState);
885
886     if (success) {
887         CSSStyleRule* rule = inspectorStyleSheet->ruleForId(compoundId);
888         result = inspectorStyleSheet->buildObjectForRule(rule, buildMediaListChain(rule));
889     }
890     *errorString = InspectorDOMAgent::toErrorString(exceptionState);
891 }
892
893 void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
894 {
895     Node* node = m_domAgent->assertNode(errorString, contextNodeId);
896     if (!node)
897         return;
898
899     InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(&node->document(), true);
900     if (!inspectorStyleSheet) {
901         *errorString = "No target stylesheet found";
902         return;
903     }
904
905     TrackExceptionState exceptionState;
906     OwnPtr<AddRuleAction> action = adoptPtr(new AddRuleAction(inspectorStyleSheet, selector));
907     AddRuleAction* rawAction = action.get();
908     bool success = m_domAgent->history()->perform(action.release(), exceptionState);
909     if (!success) {
910         *errorString = InspectorDOMAgent::toErrorString(exceptionState);
911         return;
912     }
913
914     InspectorCSSId ruleId = rawAction->newRuleId();
915     CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
916     result = inspectorStyleSheet->buildObjectForRule(rule, buildMediaListChain(rule));
917 }
918
919 void InspectorCSSAgent::forcePseudoState(ErrorString* errorString, int nodeId, const RefPtr<JSONArray>& forcedPseudoClasses)
920 {
921     Element* element = m_domAgent->assertElement(errorString, nodeId);
922     if (!element)
923         return;
924
925     unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses.get());
926     NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
927     unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value;
928     bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState;
929     if (!needStyleRecalc)
930         return;
931
932     if (forcedPseudoState)
933         m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
934     else
935         m_nodeIdToForcedPseudoState.remove(nodeId);
936     element->ownerDocument()->setNeedsStyleRecalc(SubtreeStyleChange);
937 }
938
939 PassRefPtr<TypeBuilder::CSS::CSSMedia> InspectorCSSAgent::buildMediaObject(const MediaList* media, MediaListSource mediaListSource, const String& sourceURL, CSSStyleSheet* parentStyleSheet)
940 {
941     // Make certain compilers happy by initializing |source| up-front.
942     TypeBuilder::CSS::CSSMedia::Source::Enum source = TypeBuilder::CSS::CSSMedia::Source::InlineSheet;
943     switch (mediaListSource) {
944     case MediaListSourceMediaRule:
945         source = TypeBuilder::CSS::CSSMedia::Source::MediaRule;
946         break;
947     case MediaListSourceImportRule:
948         source = TypeBuilder::CSS::CSSMedia::Source::ImportRule;
949         break;
950     case MediaListSourceLinkedSheet:
951         source = TypeBuilder::CSS::CSSMedia::Source::LinkedSheet;
952         break;
953     case MediaListSourceInlineSheet:
954         source = TypeBuilder::CSS::CSSMedia::Source::InlineSheet;
955         break;
956     }
957
958     RefPtr<TypeBuilder::CSS::CSSMedia> mediaObject = TypeBuilder::CSS::CSSMedia::create()
959         .setText(media->mediaText())
960         .setSource(source);
961
962     if (parentStyleSheet && mediaListSource != MediaListSourceLinkedSheet) {
963         if (InspectorStyleSheet* inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(parentStyleSheet))
964             mediaObject->setParentStyleSheetId(inspectorStyleSheet->id());
965     }
966     if (!sourceURL.isEmpty()) {
967         mediaObject->setSourceURL(sourceURL);
968
969         CSSRule* parentRule = media->parentRule();
970         if (!parentRule)
971             return mediaObject.release();
972         InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(parentRule->parentStyleSheet());
973         RefPtr<TypeBuilder::CSS::SourceRange> mediaRange = inspectorStyleSheet->ruleHeaderSourceRange(parentRule);
974         if (mediaRange)
975             mediaObject->setRange(mediaRange);
976     }
977     return mediaObject.release();
978 }
979
980 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSMedia> > InspectorCSSAgent::buildMediaListChain(CSSRule* rule)
981 {
982     if (!rule)
983         return 0;
984     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSMedia> > mediaArray = TypeBuilder::Array<TypeBuilder::CSS::CSSMedia>::create();
985     bool hasItems = false;
986     MediaList* mediaList;
987     CSSRule* parentRule = rule;
988     String sourceURL;
989     while (parentRule) {
990         CSSStyleSheet* parentStyleSheet = 0;
991         bool isMediaRule = true;
992         if (parentRule->type() == CSSRule::MEDIA_RULE) {
993             CSSMediaRule* mediaRule = toCSSMediaRule(parentRule);
994             mediaList = mediaRule->media();
995             parentStyleSheet = mediaRule->parentStyleSheet();
996         } else if (parentRule->type() == CSSRule::IMPORT_RULE) {
997             CSSImportRule* importRule = toCSSImportRule(parentRule);
998             mediaList = importRule->media();
999             parentStyleSheet = importRule->parentStyleSheet();
1000             isMediaRule = false;
1001         } else {
1002             mediaList = 0;
1003         }
1004
1005         if (parentStyleSheet) {
1006             sourceURL = parentStyleSheet->contents()->baseURL();
1007             if (sourceURL.isEmpty())
1008                 sourceURL = InspectorDOMAgent::documentURLString(parentStyleSheet->ownerDocument());
1009         } else {
1010             sourceURL = "";
1011         }
1012
1013         if (mediaList && mediaList->length()) {
1014             mediaArray->addItem(buildMediaObject(mediaList, isMediaRule ? MediaListSourceMediaRule : MediaListSourceImportRule, sourceURL, parentStyleSheet));
1015             hasItems = true;
1016         }
1017
1018         if (parentRule->parentRule()) {
1019             parentRule = parentRule->parentRule();
1020         } else {
1021             CSSStyleSheet* styleSheet = parentRule->parentStyleSheet();
1022             while (styleSheet) {
1023                 mediaList = styleSheet->media();
1024                 if (mediaList && mediaList->length()) {
1025                     Document* doc = styleSheet->ownerDocument();
1026                     if (doc)
1027                         sourceURL = doc->url();
1028                     else if (!styleSheet->contents()->baseURL().isEmpty())
1029                         sourceURL = styleSheet->contents()->baseURL();
1030                     else
1031                         sourceURL = "";
1032                     mediaArray->addItem(buildMediaObject(mediaList, styleSheet->ownerNode() ? MediaListSourceLinkedSheet : MediaListSourceInlineSheet, sourceURL, styleSheet));
1033                     hasItems = true;
1034                 }
1035                 parentRule = styleSheet->ownerRule();
1036                 if (parentRule)
1037                     break;
1038                 styleSheet = styleSheet->parentStyleSheet();
1039             }
1040         }
1041     }
1042     return hasItems ? mediaArray : 0;
1043 }
1044
1045 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
1046 {
1047     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1048     if (it != m_nodeToInspectorStyleSheet.end())
1049         return it->value.get();
1050
1051     CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
1052     if (!style)
1053         return 0;
1054
1055     String newStyleSheetId = String::number(m_lastStyleSheetId++);
1056     RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_pageAgent, m_resourceAgent, newStyleSheetId, element, TypeBuilder::CSS::StyleSheetOrigin::Regular, this);
1057     m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
1058     m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
1059     return inspectorStyleSheet.get();
1060 }
1061
1062 Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
1063 {
1064     Node* node = m_domAgent->nodeForId(nodeId);
1065     if (!node) {
1066         *errorString = "No node with given id found";
1067         return 0;
1068     }
1069     if (!node->isElementNode()) {
1070         *errorString = "Not an element node";
1071         return 0;
1072     }
1073     return toElement(node);
1074 }
1075
1076 void InspectorCSSAgent::collectAllStyleSheets(Vector<InspectorStyleSheet*>& result)
1077 {
1078     Vector<CSSStyleSheet*> cssStyleSheets;
1079     Vector<Document*> documents = m_domAgent->documents();
1080     for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it)
1081         collectAllDocumentStyleSheets(*it, cssStyleSheets);
1082     for (Vector<CSSStyleSheet*>::iterator it = cssStyleSheets.begin(); it != cssStyleSheets.end(); ++it)
1083         result.append(bindStyleSheet(*it));
1084 }
1085
1086 void InspectorCSSAgent::collectAllDocumentStyleSheets(Document* document, Vector<CSSStyleSheet*>& result)
1087 {
1088     const Vector<RefPtr<StyleSheet> > activeStyleSheets = document->styleEngine()->activeStyleSheetsForInspector();
1089     for (Vector<RefPtr<StyleSheet> >::const_iterator it = activeStyleSheets.begin(); it != activeStyleSheets.end(); ++it) {
1090         StyleSheet* styleSheet = (*it).get();
1091         if (styleSheet->isCSSStyleSheet())
1092             collectStyleSheets(toCSSStyleSheet(styleSheet), result);
1093     }
1094 }
1095
1096 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Vector<CSSStyleSheet*>& result)
1097 {
1098     result.append(styleSheet);
1099     for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
1100         CSSRule* rule = styleSheet->item(i);
1101         if (rule->type() == CSSRule::IMPORT_RULE) {
1102             CSSStyleSheet* importedStyleSheet = toCSSImportRule(rule)->styleSheet();
1103             if (importedStyleSheet)
1104                 collectStyleSheets(importedStyleSheet, result);
1105         }
1106     }
1107 }
1108
1109 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
1110 {
1111     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
1112     if (!inspectorStyleSheet) {
1113         String id = String::number(m_lastStyleSheetId++);
1114         Document* document = styleSheet->ownerDocument();
1115         inspectorStyleSheet = InspectorStyleSheet::create(m_pageAgent, m_resourceAgent, id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
1116         m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
1117         m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
1118         if (m_creatingViaInspectorStyleSheet)
1119             m_documentToViaInspectorStyleSheet.add(document, inspectorStyleSheet);
1120     }
1121     return inspectorStyleSheet.get();
1122 }
1123
1124 String InspectorCSSAgent::unbindStyleSheet(InspectorStyleSheet* inspectorStyleSheet)
1125 {
1126     String id = inspectorStyleSheet->id();
1127     m_idToInspectorStyleSheet.remove(id);
1128     if (inspectorStyleSheet->pageStyleSheet())
1129         m_cssStyleSheetToInspectorStyleSheet.remove(inspectorStyleSheet->pageStyleSheet());
1130     return id;
1131 }
1132
1133 InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
1134 {
1135     if (!document) {
1136         ASSERT(!createIfAbsent);
1137         return 0;
1138     }
1139
1140     if (!document->isHTMLDocument() && !document->isSVGDocument())
1141         return 0;
1142
1143     RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToViaInspectorStyleSheet.get(document);
1144     if (inspectorStyleSheet || !createIfAbsent)
1145         return inspectorStyleSheet.get();
1146
1147     TrackExceptionState exceptionState;
1148     RefPtr<Element> styleElement = document->createElement("style", exceptionState);
1149     if (!exceptionState.hadException())
1150         styleElement->setAttribute("type", "text/css", exceptionState);
1151     if (!exceptionState.hadException()) {
1152         ContainerNode* targetNode;
1153         // HEAD is absent in ImageDocuments, for example.
1154         if (document->head())
1155             targetNode = document->head();
1156         else if (document->body())
1157             targetNode = document->body();
1158         else
1159             return 0;
1160
1161         InlineStyleOverrideScope overrideScope(document);
1162         m_creatingViaInspectorStyleSheet = true;
1163         targetNode->appendChild(styleElement, exceptionState);
1164         // At this point the added stylesheet will get bound through the updateActiveStyleSheets() invocation.
1165         // We just need to pick the respective InspectorStyleSheet from m_documentToViaInspectorStyleSheet.
1166         m_creatingViaInspectorStyleSheet = false;
1167     }
1168     if (exceptionState.hadException())
1169         return 0;
1170
1171     return m_documentToViaInspectorStyleSheet.get(document);
1172 }
1173
1174 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
1175 {
1176     IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
1177     if (it == m_idToInspectorStyleSheet.end()) {
1178         *errorString = "No style sheet with given id found";
1179         return 0;
1180     }
1181     return it->value.get();
1182 }
1183
1184 TypeBuilder::CSS::StyleSheetOrigin::Enum InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
1185 {
1186     if (m_creatingViaInspectorStyleSheet)
1187         return TypeBuilder::CSS::StyleSheetOrigin::Inspector;
1188
1189     TypeBuilder::CSS::StyleSheetOrigin::Enum origin = TypeBuilder::CSS::StyleSheetOrigin::Regular;
1190     if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
1191         origin = TypeBuilder::CSS::StyleSheetOrigin::User_agent;
1192     else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->isDocumentNode())
1193         origin = TypeBuilder::CSS::StyleSheetOrigin::User;
1194     else {
1195         InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
1196         if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
1197             origin = TypeBuilder::CSS::StyleSheetOrigin::Inspector;
1198     }
1199     return origin;
1200 }
1201
1202 PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule)
1203 {
1204     if (!rule)
1205         return 0;
1206
1207     // CSSRules returned by StyleResolver::pseudoCSSRulesForElement lack parent pointers if they are coming from
1208     // user agent stylesheets. To work around this issue, we use CSSOM wrapper created by inspector.
1209     if (!rule->parentStyleSheet()) {
1210         if (!m_inspectorUserAgentStyleSheet)
1211             m_inspectorUserAgentStyleSheet = CSSStyleSheet::create(CSSDefaultStyleSheets::instance().defaultStyleSheet());
1212         rule->setParentStyleSheet(m_inspectorUserAgentStyleSheet.get());
1213     }
1214     return bindStyleSheet(rule->parentStyleSheet())->buildObjectForRule(rule, buildMediaListChain(rule));
1215 }
1216
1217 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
1218 {
1219     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSRule>::create();
1220     if (!ruleList)
1221         return result.release();
1222
1223     RefPtr<CSSRuleList> refRuleList = ruleList;
1224     CSSRuleVector rules;
1225     InspectorStyleSheet::collectFlatRules(refRuleList, &rules);
1226
1227     for (unsigned i = 0, size = rules.size(); i < size; ++i) {
1228         CSSStyleRule* styleRule = asCSSStyleRule(rules.at(i).get());
1229         if (!styleRule)
1230             continue;
1231         result->addItem(buildObjectForRule(styleRule));
1232     }
1233
1234     return result.release();
1235 }
1236
1237 static inline bool matchesPseudoElement(const CSSSelector* selector, PseudoId elementPseudoId)
1238 {
1239     // According to http://www.w3.org/TR/css3-selectors/#pseudo-elements, "Only one pseudo-element may appear per selector."
1240     // As such, check the last selector in the tag history.
1241     for (; !selector->isLastInTagHistory(); ++selector) { }
1242     PseudoId selectorPseudoId = selector->matchesPseudoElement() ? CSSSelector::pseudoId(selector->pseudoType()) : NOPSEUDO;
1243
1244     // FIXME: This only covers the case of matching pseudo-element selectors against PseudoElements.
1245     // We should come up with a solution for matching pseudo-element selectors against ordinary Elements, too.
1246     return selectorPseudoId == elementPseudoId;
1247 }
1248
1249 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > InspectorCSSAgent::buildArrayForMatchedRuleList(CSSRuleList* ruleList, Element* element)
1250 {
1251     RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > result = TypeBuilder::Array<TypeBuilder::CSS::RuleMatch>::create();
1252     if (!ruleList)
1253         return result.release();
1254
1255     for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
1256         CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
1257         RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule);
1258         if (!ruleObject)
1259             continue;
1260         RefPtr<TypeBuilder::Array<int> > matchingSelectors = TypeBuilder::Array<int>::create();
1261         const CSSSelectorList& selectorList = rule->styleRule()->selectorList();
1262         long index = 0;
1263         PseudoId elementPseudoId = element->pseudoId();
1264         for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) {
1265             const CSSSelector* firstTagHistorySelector = selector;
1266             bool matched = false;
1267             if (elementPseudoId)
1268                 matched = matchesPseudoElement(selector, elementPseudoId); // Modifies |selector|.
1269             matched |= element->matches(firstTagHistorySelector->selectorText(), IGNORE_EXCEPTION);
1270             if (matched)
1271                 matchingSelectors->addItem(index);
1272             ++index;
1273         }
1274         RefPtr<TypeBuilder::CSS::RuleMatch> match = TypeBuilder::CSS::RuleMatch::create()
1275             .setRule(ruleObject.release())
1276             .setMatchingSelectors(matchingSelectors.release());
1277         result->addItem(match);
1278     }
1279
1280     return result;
1281 }
1282
1283 PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
1284 {
1285     if (!element->isStyledElement())
1286         return 0;
1287
1288     // FIXME: Ugliness below.
1289     StylePropertySet* attributeStyle = const_cast<StylePropertySet*>(element->presentationAttributeStyle());
1290     if (!attributeStyle)
1291         return 0;
1292
1293     MutableStylePropertySet* mutableAttributeStyle = toMutableStylePropertySet(attributeStyle);
1294
1295     RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), 0);
1296     return inspectorStyle->buildObjectForStyle();
1297 }
1298
1299 void InspectorCSSAgent::didRemoveDocument(Document* document)
1300 {
1301     if (document)
1302         m_documentToViaInspectorStyleSheet.remove(document);
1303 }
1304
1305 void InspectorCSSAgent::didRemoveDOMNode(Node* node)
1306 {
1307     if (!node)
1308         return;
1309
1310     int nodeId = m_domAgent->boundNodeId(node);
1311     if (nodeId)
1312         m_nodeIdToForcedPseudoState.remove(nodeId);
1313
1314     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
1315     if (it == m_nodeToInspectorStyleSheet.end())
1316         return;
1317
1318     m_idToInspectorStyleSheet.remove(it->value->id());
1319     m_nodeToInspectorStyleSheet.remove(node);
1320 }
1321
1322 void InspectorCSSAgent::didModifyDOMAttr(Element* element)
1323 {
1324     if (!element)
1325         return;
1326
1327     NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1328     if (it == m_nodeToInspectorStyleSheet.end())
1329         return;
1330
1331     it->value->didModifyElementAttribute();
1332 }
1333
1334 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1335 {
1336     if (m_frontend)
1337         m_frontend->styleSheetChanged(styleSheet->id());
1338 }
1339
1340 void InspectorCSSAgent::willReparseStyleSheet()
1341 {
1342     ASSERT(!m_isSettingStyleSheetText);
1343     m_isSettingStyleSheetText = true;
1344 }
1345
1346 void InspectorCSSAgent::didReparseStyleSheet()
1347 {
1348     ASSERT(m_isSettingStyleSheetText);
1349     m_isSettingStyleSheetText = false;
1350 }
1351
1352 void InspectorCSSAgent::resetPseudoStates()
1353 {
1354     HashSet<Document*> documentsToChange;
1355     for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) {
1356         Element* element = toElement(m_domAgent->nodeForId(it->key));
1357         if (element && element->ownerDocument())
1358             documentsToChange.add(element->ownerDocument());
1359     }
1360
1361     m_nodeIdToForcedPseudoState.clear();
1362     for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
1363         (*it)->setNeedsStyleRecalc(SubtreeStyleChange);
1364 }
1365
1366 } // namespace WebCore
1367