2 * Copyright (C) 2010, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #include "core/inspector/InspectorCSSAgent.h"
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"
76 namespace CSSAgentState {
77 static const char cssAgentEnabled[] = "cssAgentEnabled";
80 typedef WebCore::InspectorBackendDispatcher::CSSCommandHandler::EnableCallback EnableCallback;
84 enum ForcePseudoClassFlags {
88 PseudoActive = 1 << 2,
89 PseudoVisited = 1 << 3
92 static unsigned computePseudoClassMask(JSONArray* pseudoClassArray)
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())
101 unsigned result = PseudoNone;
102 for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
103 RefPtr<JSONValue> pseudoClassValue = pseudoClassArray->get(i);
105 bool success = pseudoClassValue->asString(&pseudoClass);
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;
121 class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action {
122 WTF_MAKE_NONCOPYABLE(StyleSheetAction);
124 StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet)
125 : InspectorHistory::Action(name)
126 , m_styleSheet(styleSheet)
131 RefPtr<InspectorStyleSheet> m_styleSheet;
134 class InspectorCSSAgent::EnableResourceClient FINAL : public StyleSheetResourceClient {
136 EnableResourceClient(InspectorCSSAgent*, const Vector<InspectorStyleSheet*>&, PassRefPtr<EnableCallback>);
138 virtual void setCSSStyleSheet(const String&, const KURL&, const String&, const CSSStyleSheetResource*) OVERRIDE;
141 RefPtr<EnableCallback> m_callback;
142 InspectorCSSAgent* m_cssAgent;
143 int m_pendingResources;
144 Vector<InspectorStyleSheet*> m_styleSheets;
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)
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);
162 void InspectorCSSAgent::EnableResourceClient::setCSSStyleSheet(const String&, const KURL& url, const String&, const CSSStyleSheetResource* resource)
164 const_cast<CSSStyleSheetResource*>(resource)->removeClient(this);
165 --m_pendingResources;
166 if (m_pendingResources)
169 // enable always succeeds.
170 if (m_callback->isActive())
171 m_cssAgent->wasEnabled(m_callback.release());
175 class InspectorCSSAgent::SetStyleSheetTextAction FINAL : public InspectorCSSAgent::StyleSheetAction {
176 WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction);
178 SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text)
179 : InspectorCSSAgent::StyleSheetAction("SetStyleSheetText", styleSheet)
184 virtual bool perform(ExceptionState& exceptionState) OVERRIDE
186 if (!m_styleSheet->getText(&m_oldText))
188 return redo(exceptionState);
191 virtual bool undo(ExceptionState& exceptionState) OVERRIDE
193 if (m_styleSheet->setText(m_oldText, exceptionState)) {
194 m_styleSheet->reparseStyleSheet(m_oldText);
200 virtual bool redo(ExceptionState& exceptionState) OVERRIDE
202 if (m_styleSheet->setText(m_text, exceptionState)) {
203 m_styleSheet->reparseStyleSheet(m_text);
209 virtual String mergeId() OVERRIDE
211 return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data());
214 virtual void merge(PassOwnPtr<Action> action) OVERRIDE
216 ASSERT(action->mergeId() == mergeId());
218 SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(action.get());
219 m_text = other->m_text;
227 class InspectorCSSAgent::SetPropertyTextAction FINAL : public InspectorCSSAgent::StyleSheetAction {
228 WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
230 SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
231 : InspectorCSSAgent::StyleSheetAction("SetPropertyText", styleSheet)
233 , m_propertyIndex(propertyIndex)
235 , m_overwrite(overwrite)
239 virtual String toString() OVERRIDE
241 return mergeId() + ": " + m_oldText + " -> " + m_text;
244 virtual bool perform(ExceptionState& exceptionState) OVERRIDE
246 return redo(exceptionState);
249 virtual bool undo(ExceptionState& exceptionState) OVERRIDE
252 return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, exceptionState);
255 virtual bool redo(ExceptionState& exceptionState) OVERRIDE
258 bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, exceptionState);
259 m_oldText = oldText.stripWhiteSpace();
263 virtual String mergeId() OVERRIDE
265 return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false");
268 virtual void merge(PassOwnPtr<Action> action) OVERRIDE
270 ASSERT(action->mergeId() == mergeId());
272 SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
273 m_text = other->m_text;
277 InspectorCSSId m_cssId;
278 unsigned m_propertyIndex;
284 class InspectorCSSAgent::SetRuleSelectorAction FINAL : public InspectorCSSAgent::StyleSheetAction {
285 WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction);
287 SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector)
288 : InspectorCSSAgent::StyleSheetAction("SetRuleSelector", styleSheet)
290 , m_selector(selector)
294 virtual bool perform(ExceptionState& exceptionState) OVERRIDE
296 m_oldSelector = m_styleSheet->ruleSelector(m_cssId, exceptionState);
297 if (exceptionState.hadException())
299 return redo(exceptionState);
302 virtual bool undo(ExceptionState& exceptionState) OVERRIDE
304 return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, exceptionState);
307 virtual bool redo(ExceptionState& exceptionState) OVERRIDE
309 return m_styleSheet->setRuleSelector(m_cssId, m_selector, exceptionState);
313 InspectorCSSId m_cssId;
315 String m_oldSelector;
318 class InspectorCSSAgent::AddRuleAction FINAL : public InspectorCSSAgent::StyleSheetAction {
319 WTF_MAKE_NONCOPYABLE(AddRuleAction);
321 AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector)
322 : InspectorCSSAgent::StyleSheetAction("AddRule", styleSheet)
323 , m_selector(selector)
327 virtual bool perform(ExceptionState& exceptionState) OVERRIDE
329 return redo(exceptionState);
332 virtual bool undo(ExceptionState& exceptionState) OVERRIDE
334 return m_styleSheet->deleteRule(m_newId, exceptionState);
337 virtual bool redo(ExceptionState& exceptionState) OVERRIDE
339 CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, exceptionState);
340 if (exceptionState.hadException())
342 m_newId = m_styleSheet->ruleId(cssStyleRule);
346 InspectorCSSId newRuleId() { return m_newId; }
349 InspectorCSSId m_newId;
351 String m_oldSelector;
355 CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule* rule)
357 if (!rule || rule->type() != CSSRule::STYLE_RULE)
359 return toCSSStyleRule(rule);
362 template <typename CharType, size_t bufferLength>
363 static size_t vendorPrefixLowerCase(const CharType* string, size_t stringLength, char (&buffer)[bufferLength])
365 static const char lowerCaseOffset = 'a' - 'A';
367 if (string[0] != '-')
370 for (size_t i = 0; i < stringLength - 1; i++) {
371 CharType c = string[i + 1];
374 if (i == bufferLength)
376 if (c < 'A' || c > 'z')
381 buffer[i] = c + lowerCaseOffset;
388 InspectorCSSAgent::InspectorCSSAgent(InspectorDOMAgent* domAgent, InspectorPageAgent* pageAgent, InspectorResourceAgent* resourceAgent)
389 : InspectorBaseAgent<InspectorCSSAgent>("CSS")
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)
400 m_domAgent->setDOMListener(this);
403 InspectorCSSAgent::~InspectorCSSAgent()
409 void InspectorCSSAgent::setFrontend(InspectorFrontend* frontend)
412 m_frontend = frontend->css();
415 void InspectorCSSAgent::clearFrontend()
419 resetNonPersistentData();
422 void InspectorCSSAgent::discardAgent()
424 m_domAgent->setDOMListener(0);
428 void InspectorCSSAgent::restore()
430 if (m_state->getBoolean(CSSAgentState::cssAgentEnabled))
434 void InspectorCSSAgent::reset()
436 m_idToInspectorStyleSheet.clear();
437 m_cssStyleSheetToInspectorStyleSheet.clear();
438 m_frameToCSSStyleSheets.clear();
439 m_nodeToInspectorStyleSheet.clear();
440 m_documentToViaInspectorStyleSheet.clear();
441 resetNonPersistentData();
444 void InspectorCSSAgent::resetNonPersistentData()
449 void InspectorCSSAgent::enable(ErrorString*, PassRefPtr<EnableCallback> prpCallback)
451 m_state->setBoolean(CSSAgentState::cssAgentEnabled, true);
453 Vector<InspectorStyleSheet*> styleSheets;
454 collectAllStyleSheets(styleSheets);
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))
464 CSSStyleSheet* pageStyleSheet = styleSheet->pageStyleSheet();
465 if (pageStyleSheet->isInline() || !pageStyleSheet->contents()->loadCompleted())
467 Document* document = styleSheet->ownerDocument();
470 Resource* cachedResource = document->fetcher()->cachedResource(document->completeURL(url));
473 urlsToFetch.add(styleSheet->finalURL());
474 styleSheetsToFetch.append(styleSheet);
477 if (styleSheetsToFetch.isEmpty()) {
478 wasEnabled(prpCallback);
481 new EnableResourceClient(this, styleSheetsToFetch, prpCallback);
484 void InspectorCSSAgent::wasEnabled(PassRefPtr<EnableCallback> callback)
486 if (!m_state->getBoolean(CSSAgentState::cssAgentEnabled)) {
487 // We were disabled while fetching resources.
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);
499 callback->sendSuccess();
502 void InspectorCSSAgent::disable(ErrorString*)
504 m_instrumentingAgents->setInspectorCSSAgent(0);
505 m_state->setBoolean(CSSAgentState::cssAgentEnabled, false);
508 void InspectorCSSAgent::didCommitLoad(Frame* frame, DocumentLoader* loader)
510 if (loader->frame() == frame->page()->mainFrame()) {
515 updateActiveStyleSheets(frame, Vector<CSSStyleSheet*>(), ExistingFrontendRefresh);
518 void InspectorCSSAgent::mediaQueryResultChanged()
521 m_frontend->mediaQueryResultChanged();
524 void InspectorCSSAgent::willMutateRules()
526 ++m_styleSheetsPendingMutation;
529 void InspectorCSSAgent::didMutateRules(CSSStyleSheet* styleSheet)
531 --m_styleSheetsPendingMutation;
532 ASSERT(m_styleSheetsPendingMutation >= 0);
534 if (!styleSheetEditInProgress()) {
535 Document* owner = styleSheet->ownerDocument();
537 owner->modifiedStyleSheet(styleSheet, RecalcStyleDeferred, FullStyleUpdate);
541 void InspectorCSSAgent::willMutateStyle()
543 m_styleDeclarationPendingMutation = true;
546 void InspectorCSSAgent::didMutateStyle(CSSStyleDeclaration* style, bool isInlineStyle)
548 ASSERT(m_styleDeclarationPendingMutation);
549 m_styleDeclarationPendingMutation = false;
550 if (!styleSheetEditInProgress() && !isInlineStyle) {
551 CSSStyleSheet* parentSheet = style->parentStyleSheet();
552 Document* owner = parentSheet ? parentSheet->ownerDocument() : 0;
554 owner->modifiedStyleSheet(parentSheet, RecalcStyleDeferred, FullStyleUpdate);
558 void InspectorCSSAgent::activeStyleSheetsUpdated(Document* document)
560 if (styleSheetEditInProgress())
562 updateActiveStyleSheetsForDocument(document, ExistingFrontendRefresh);
565 void InspectorCSSAgent::updateActiveStyleSheetsForDocument(Document* document, StyleSheetsUpdateType styleSheetsUpdateType)
567 Frame* frame = document->frame();
570 Vector<CSSStyleSheet*> newSheetsVector;
571 collectAllDocumentStyleSheets(document, newSheetsVector);
572 updateActiveStyleSheets(frame, newSheetsVector, styleSheetsUpdateType);
575 void InspectorCSSAgent::updateActiveStyleSheets(Frame* frame, const Vector<CSSStyleSheet*>& allSheetsVector, StyleSheetsUpdateType styleSheetsUpdateType)
577 bool isInitialFrontendLoad = styleSheetsUpdateType == InitialFrontendLoad;
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());
586 HashSet<CSSStyleSheet*> removedSheets;
587 for (HashSet<CSSStyleSheet*>::iterator it = frameCSSStyleSheets->begin(); it != frameCSSStyleSheets->end(); ++it)
588 removedSheets.add(*it);
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);
598 addedSheets.add(cssStyleSheet);
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);
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);
615 for (HashSet<CSSStyleSheet*>::iterator it = addedSheets.begin(); it != addedSheets.end(); ++it) {
616 CSSStyleSheet* cssStyleSheet = *it;
617 bool isNew = isInitialFrontendLoad || !m_cssStyleSheetToInspectorStyleSheet.contains(cssStyleSheet);
619 InspectorStyleSheet* newStyleSheet = bindStyleSheet(cssStyleSheet);
620 frameCSSStyleSheets->add(cssStyleSheet);
622 m_frontend->styleSheetAdded(newStyleSheet->buildObjectForStyleSheetInfo());
626 if (frameCSSStyleSheets->isEmpty())
627 m_frameToCSSStyleSheets.remove(frame);
630 void InspectorCSSAgent::frameDetachedFromParent(Frame* frame)
632 updateActiveStyleSheets(frame, Vector<CSSStyleSheet*>(), ExistingFrontendRefresh);
635 bool InspectorCSSAgent::forcePseudoState(Element* element, CSSSelector::PseudoType pseudoType)
637 if (m_nodeIdToForcedPseudoState.isEmpty())
640 int nodeId = m_domAgent->boundNodeId(element);
644 NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
645 if (it == m_nodeIdToForcedPseudoState.end())
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;
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)
665 Element* element = elementForId(errorString, nodeId);
669 Element* originalElement = element;
670 PseudoId elementPseudoId = element->pseudoId();
672 element = element->parentOrShadowHostElement();
674 Document* ownerDocument = element->ownerDocument();
675 // A non-active document has no styles.
676 if (!ownerDocument->isActive())
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!
684 StyleResolver& styleResolver = ownerDocument->ensureStyleResolver();
686 RefPtr<CSSRuleList> matchedRules = styleResolver.pseudoCSSRulesForElement(element, elementPseudoId, StyleResolver::AllCSSRules);
687 matchedCSSRules = buildArrayForMatchedRuleList(matchedRules.get(), originalElement);
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());
702 pseudoIdMatches = pseudoElements.release();
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);
717 entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
720 entries->addItem(entry.release());
721 parentElement = parentElement->parentElement();
724 inheritedEntries = entries.release();
728 void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::CSS::CSSStyle>& inlineStyle, RefPtr<TypeBuilder::CSS::CSSStyle>& attributesStyle)
730 Element* element = elementForId(errorString, nodeId);
734 InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
738 inlineStyle = styleSheet->buildObjectForStyle(element->style());
739 RefPtr<TypeBuilder::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
740 attributesStyle = attributes ? attributes.release() : 0;
743 void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSComputedStyleProperty> >& style)
745 Node* node = m_domAgent->assertNode(errorString, nodeId);
749 RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(node, true);
750 RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
751 style = inspectorStyle->buildArrayForComputedStyle();
754 void InspectorCSSAgent::collectPlatformFontsForRenderer(RenderText* renderer, HashCountedSet<String>* fontStats)
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())
767 fontStats->add(familyName);
772 void InspectorCSSAgent::getPlatformFontsForNode(ErrorString* errorString, int nodeId,
773 String* cssFamilyName, RefPtr<TypeBuilder::Array<TypeBuilder::CSS::PlatformFontUsage> >& platformFonts)
775 Node* node = m_domAgent->assertNode(errorString, nodeId);
779 RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(node, true);
780 *cssFamilyName = computedStyleInfo->getPropertyValue(CSSPropertyFontFamily);
782 Vector<Node*> textNodes;
783 if (node->nodeType() == Node::TEXT_NODE) {
784 if (node->renderer())
785 textNodes.append(node);
787 for (Node* child = node->firstChild(); child; child = child->nextSibling()) {
788 if (child->nodeType() == Node::TEXT_NODE && child->renderer())
789 textNodes.append(child);
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);
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);
818 void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<TypeBuilder::CSS::CSSStyleSheetBody>& styleSheetObject)
820 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
821 if (!inspectorStyleSheet)
824 Document* doc = inspectorStyleSheet->pageStyleSheet() ? inspectorStyleSheet->pageStyleSheet()->ownerDocument() : 0;
828 RefPtr<TypeBuilder::CSS::CSSStyleSheetBody> result = TypeBuilder::CSS::CSSStyleSheetBody::create()
829 .setRules(buildArrayForRuleList(inspectorStyleSheet->pageStyleSheet()->rules().get()));
831 bool success = inspectorStyleSheet->fillObjectForStyleSheet(result);
833 styleSheetObject = result;
836 void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
838 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
839 if (!inspectorStyleSheet)
842 inspectorStyleSheet->getText(result);
845 void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
847 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
848 if (!inspectorStyleSheet) {
849 *errorString = "Style sheet with id " + styleSheetId + " not found.";
853 TrackExceptionState exceptionState;
854 m_domAgent->history()->perform(adoptPtr(new SetStyleSheetTextAction(inspectorStyleSheet, text)), exceptionState);
855 *errorString = InspectorDOMAgent::toErrorString(exceptionState);
858 void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<JSONObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<TypeBuilder::CSS::CSSStyle>& result)
860 InspectorCSSId compoundId(fullStyleId);
861 ASSERT(!compoundId.isEmpty());
863 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
864 if (!inspectorStyleSheet)
867 TrackExceptionState exceptionState;
868 bool success = m_domAgent->history()->perform(adoptPtr(new SetPropertyTextAction(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite)), exceptionState);
870 result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
871 *errorString = InspectorDOMAgent::toErrorString(exceptionState);
874 void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<JSONObject>& fullRuleId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
876 InspectorCSSId compoundId(fullRuleId);
877 ASSERT(!compoundId.isEmpty());
879 InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
880 if (!inspectorStyleSheet)
883 TrackExceptionState exceptionState;
884 bool success = m_domAgent->history()->perform(adoptPtr(new SetRuleSelectorAction(inspectorStyleSheet, compoundId, selector)), exceptionState);
887 CSSStyleRule* rule = inspectorStyleSheet->ruleForId(compoundId);
888 result = inspectorStyleSheet->buildObjectForRule(rule, buildMediaListChain(rule));
890 *errorString = InspectorDOMAgent::toErrorString(exceptionState);
893 void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<TypeBuilder::CSS::CSSRule>& result)
895 Node* node = m_domAgent->assertNode(errorString, contextNodeId);
899 InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(&node->document(), true);
900 if (!inspectorStyleSheet) {
901 *errorString = "No target stylesheet found";
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);
910 *errorString = InspectorDOMAgent::toErrorString(exceptionState);
914 InspectorCSSId ruleId = rawAction->newRuleId();
915 CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
916 result = inspectorStyleSheet->buildObjectForRule(rule, buildMediaListChain(rule));
919 void InspectorCSSAgent::forcePseudoState(ErrorString* errorString, int nodeId, const RefPtr<JSONArray>& forcedPseudoClasses)
921 Element* element = m_domAgent->assertElement(errorString, nodeId);
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)
932 if (forcedPseudoState)
933 m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
935 m_nodeIdToForcedPseudoState.remove(nodeId);
936 element->ownerDocument()->setNeedsStyleRecalc(SubtreeStyleChange);
939 PassRefPtr<TypeBuilder::CSS::CSSMedia> InspectorCSSAgent::buildMediaObject(const MediaList* media, MediaListSource mediaListSource, const String& sourceURL, CSSStyleSheet* parentStyleSheet)
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;
947 case MediaListSourceImportRule:
948 source = TypeBuilder::CSS::CSSMedia::Source::ImportRule;
950 case MediaListSourceLinkedSheet:
951 source = TypeBuilder::CSS::CSSMedia::Source::LinkedSheet;
953 case MediaListSourceInlineSheet:
954 source = TypeBuilder::CSS::CSSMedia::Source::InlineSheet;
958 RefPtr<TypeBuilder::CSS::CSSMedia> mediaObject = TypeBuilder::CSS::CSSMedia::create()
959 .setText(media->mediaText())
962 if (parentStyleSheet && mediaListSource != MediaListSourceLinkedSheet) {
963 if (InspectorStyleSheet* inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(parentStyleSheet))
964 mediaObject->setParentStyleSheetId(inspectorStyleSheet->id());
966 if (!sourceURL.isEmpty()) {
967 mediaObject->setSourceURL(sourceURL);
969 CSSRule* parentRule = media->parentRule();
971 return mediaObject.release();
972 InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(parentRule->parentStyleSheet());
973 RefPtr<TypeBuilder::CSS::SourceRange> mediaRange = inspectorStyleSheet->ruleHeaderSourceRange(parentRule);
975 mediaObject->setRange(mediaRange);
977 return mediaObject.release();
980 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSMedia> > InspectorCSSAgent::buildMediaListChain(CSSRule* rule)
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;
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;
1005 if (parentStyleSheet) {
1006 sourceURL = parentStyleSheet->contents()->baseURL();
1007 if (sourceURL.isEmpty())
1008 sourceURL = InspectorDOMAgent::documentURLString(parentStyleSheet->ownerDocument());
1013 if (mediaList && mediaList->length()) {
1014 mediaArray->addItem(buildMediaObject(mediaList, isMediaRule ? MediaListSourceMediaRule : MediaListSourceImportRule, sourceURL, parentStyleSheet));
1018 if (parentRule->parentRule()) {
1019 parentRule = parentRule->parentRule();
1021 CSSStyleSheet* styleSheet = parentRule->parentStyleSheet();
1022 while (styleSheet) {
1023 mediaList = styleSheet->media();
1024 if (mediaList && mediaList->length()) {
1025 Document* doc = styleSheet->ownerDocument();
1027 sourceURL = doc->url();
1028 else if (!styleSheet->contents()->baseURL().isEmpty())
1029 sourceURL = styleSheet->contents()->baseURL();
1032 mediaArray->addItem(buildMediaObject(mediaList, styleSheet->ownerNode() ? MediaListSourceLinkedSheet : MediaListSourceInlineSheet, sourceURL, styleSheet));
1035 parentRule = styleSheet->ownerRule();
1038 styleSheet = styleSheet->parentStyleSheet();
1042 return hasItems ? mediaArray : 0;
1045 InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
1047 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1048 if (it != m_nodeToInspectorStyleSheet.end())
1049 return it->value.get();
1051 CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
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();
1062 Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
1064 Node* node = m_domAgent->nodeForId(nodeId);
1066 *errorString = "No node with given id found";
1069 if (!node->isElementNode()) {
1070 *errorString = "Not an element node";
1073 return toElement(node);
1076 void InspectorCSSAgent::collectAllStyleSheets(Vector<InspectorStyleSheet*>& result)
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));
1086 void InspectorCSSAgent::collectAllDocumentStyleSheets(Document* document, Vector<CSSStyleSheet*>& result)
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);
1096 void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Vector<CSSStyleSheet*>& result)
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);
1109 InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
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);
1121 return inspectorStyleSheet.get();
1124 String InspectorCSSAgent::unbindStyleSheet(InspectorStyleSheet* inspectorStyleSheet)
1126 String id = inspectorStyleSheet->id();
1127 m_idToInspectorStyleSheet.remove(id);
1128 if (inspectorStyleSheet->pageStyleSheet())
1129 m_cssStyleSheetToInspectorStyleSheet.remove(inspectorStyleSheet->pageStyleSheet());
1133 InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
1136 ASSERT(!createIfAbsent);
1140 if (!document->isHTMLDocument() && !document->isSVGDocument())
1143 RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToViaInspectorStyleSheet.get(document);
1144 if (inspectorStyleSheet || !createIfAbsent)
1145 return inspectorStyleSheet.get();
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();
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;
1168 if (exceptionState.hadException())
1171 return m_documentToViaInspectorStyleSheet.get(document);
1174 InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
1176 IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
1177 if (it == m_idToInspectorStyleSheet.end()) {
1178 *errorString = "No style sheet with given id found";
1181 return it->value.get();
1184 TypeBuilder::CSS::StyleSheetOrigin::Enum InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
1186 if (m_creatingViaInspectorStyleSheet)
1187 return TypeBuilder::CSS::StyleSheetOrigin::Inspector;
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;
1195 InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
1196 if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
1197 origin = TypeBuilder::CSS::StyleSheetOrigin::Inspector;
1202 PassRefPtr<TypeBuilder::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule)
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());
1214 return bindStyleSheet(rule->parentStyleSheet())->buildObjectForRule(rule, buildMediaListChain(rule));
1217 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
1219 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSRule> > result = TypeBuilder::Array<TypeBuilder::CSS::CSSRule>::create();
1221 return result.release();
1223 RefPtr<CSSRuleList> refRuleList = ruleList;
1224 CSSRuleVector rules;
1225 InspectorStyleSheet::collectFlatRules(refRuleList, &rules);
1227 for (unsigned i = 0, size = rules.size(); i < size; ++i) {
1228 CSSStyleRule* styleRule = asCSSStyleRule(rules.at(i).get());
1231 result->addItem(buildObjectForRule(styleRule));
1234 return result.release();
1237 static inline bool matchesPseudoElement(const CSSSelector* selector, PseudoId elementPseudoId)
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;
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;
1249 PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > InspectorCSSAgent::buildArrayForMatchedRuleList(CSSRuleList* ruleList, Element* element)
1251 RefPtr<TypeBuilder::Array<TypeBuilder::CSS::RuleMatch> > result = TypeBuilder::Array<TypeBuilder::CSS::RuleMatch>::create();
1253 return result.release();
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);
1260 RefPtr<TypeBuilder::Array<int> > matchingSelectors = TypeBuilder::Array<int>::create();
1261 const CSSSelectorList& selectorList = rule->styleRule()->selectorList();
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);
1271 matchingSelectors->addItem(index);
1274 RefPtr<TypeBuilder::CSS::RuleMatch> match = TypeBuilder::CSS::RuleMatch::create()
1275 .setRule(ruleObject.release())
1276 .setMatchingSelectors(matchingSelectors.release());
1277 result->addItem(match);
1283 PassRefPtr<TypeBuilder::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
1285 if (!element->isStyledElement())
1288 // FIXME: Ugliness below.
1289 StylePropertySet* attributeStyle = const_cast<StylePropertySet*>(element->presentationAttributeStyle());
1290 if (!attributeStyle)
1293 MutableStylePropertySet* mutableAttributeStyle = toMutableStylePropertySet(attributeStyle);
1295 RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), 0);
1296 return inspectorStyle->buildObjectForStyle();
1299 void InspectorCSSAgent::didRemoveDocument(Document* document)
1302 m_documentToViaInspectorStyleSheet.remove(document);
1305 void InspectorCSSAgent::didRemoveDOMNode(Node* node)
1310 int nodeId = m_domAgent->boundNodeId(node);
1312 m_nodeIdToForcedPseudoState.remove(nodeId);
1314 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
1315 if (it == m_nodeToInspectorStyleSheet.end())
1318 m_idToInspectorStyleSheet.remove(it->value->id());
1319 m_nodeToInspectorStyleSheet.remove(node);
1322 void InspectorCSSAgent::didModifyDOMAttr(Element* element)
1327 NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
1328 if (it == m_nodeToInspectorStyleSheet.end())
1331 it->value->didModifyElementAttribute();
1334 void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
1337 m_frontend->styleSheetChanged(styleSheet->id());
1340 void InspectorCSSAgent::willReparseStyleSheet()
1342 ASSERT(!m_isSettingStyleSheetText);
1343 m_isSettingStyleSheetText = true;
1346 void InspectorCSSAgent::didReparseStyleSheet()
1348 ASSERT(m_isSettingStyleSheetText);
1349 m_isSettingStyleSheetText = false;
1352 void InspectorCSSAgent::resetPseudoStates()
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());
1361 m_nodeIdToForcedPseudoState.clear();
1362 for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
1363 (*it)->setNeedsStyleRecalc(SubtreeStyleChange);
1366 } // namespace WebCore