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