/* * Copyright (C) 2010 Google Inc. All rights reserved. * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "InspectorCSSAgent.h" #include "AuthorStyleSheets.h" #include "CSSComputedStyleDeclaration.h" #include "CSSImportRule.h" #include "CSSPropertyNames.h" #include "CSSPropertySourceData.h" #include "CSSRule.h" #include "CSSRuleList.h" #include "CSSStyleRule.h" #include "CSSStyleSheet.h" #include "ContentSecurityPolicy.h" #include "DOMWindow.h" #include "ExceptionCodePlaceholder.h" #include "FontCache.h" #include "HTMLHeadElement.h" #include "HTMLStyleElement.h" #include "InspectorDOMAgent.h" #include "InspectorHistory.h" #include "InspectorPageAgent.h" #include "InstrumentingAgents.h" #include "NamedFlowCollection.h" #include "Node.h" #include "NodeList.h" #include "PseudoElement.h" #include "RenderNamedFlowFragment.h" #include "SVGStyleElement.h" #include "SelectorChecker.h" #include "StyleProperties.h" #include "StylePropertyShorthand.h" #include "StyleResolver.h" #include "StyleRule.h" #include "StyleSheetList.h" #include "WebKitNamedFlow.h" #include #include #include #include #include #include using namespace Inspector; namespace WebCore { enum ForcePseudoClassFlags { PseudoClassNone = 0, PseudoClassHover = 1 << 0, PseudoClassFocus = 1 << 1, PseudoClassActive = 1 << 2, PseudoClassVisited = 1 << 3 }; static unsigned computePseudoClassMask(const InspectorArray& pseudoClassArray) { static NeverDestroyed active(ASCIILiteral("active")); static NeverDestroyed hover(ASCIILiteral("hover")); static NeverDestroyed focus(ASCIILiteral("focus")); static NeverDestroyed visited(ASCIILiteral("visited")); if (!pseudoClassArray.length()) return PseudoClassNone; unsigned result = PseudoClassNone; for (auto& pseudoClassValue : pseudoClassArray) { String pseudoClass; bool success = pseudoClassValue->asString(pseudoClass); if (!success) continue; if (pseudoClass == active) result |= PseudoClassActive; else if (pseudoClass == hover) result |= PseudoClassHover; else if (pseudoClass == focus) result |= PseudoClassFocus; else if (pseudoClass == visited) result |= PseudoClassVisited; } return result; } class ChangeRegionOversetTask { public: ChangeRegionOversetTask(InspectorCSSAgent*); void scheduleFor(WebKitNamedFlow*, int documentNodeId); void unschedule(WebKitNamedFlow*); void reset(); void timerFired(); private: InspectorCSSAgent* m_cssAgent; Timer m_timer; HashMap m_namedFlows; }; ChangeRegionOversetTask::ChangeRegionOversetTask(InspectorCSSAgent* cssAgent) : m_cssAgent(cssAgent) , m_timer(*this, &ChangeRegionOversetTask::timerFired) { } void ChangeRegionOversetTask::scheduleFor(WebKitNamedFlow* namedFlow, int documentNodeId) { m_namedFlows.add(namedFlow, documentNodeId); if (!m_timer.isActive()) m_timer.startOneShot(0); } void ChangeRegionOversetTask::unschedule(WebKitNamedFlow* namedFlow) { m_namedFlows.remove(namedFlow); } void ChangeRegionOversetTask::reset() { m_timer.stop(); m_namedFlows.clear(); } void ChangeRegionOversetTask::timerFired() { // The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed. for (auto& namedFlow : m_namedFlows) m_cssAgent->regionOversetChanged(namedFlow.key, namedFlow.value); m_namedFlows.clear(); } class InspectorCSSAgent::StyleSheetAction : public InspectorHistory::Action { WTF_MAKE_NONCOPYABLE(StyleSheetAction); public: StyleSheetAction(const String& name, InspectorStyleSheet* styleSheet) : InspectorHistory::Action(name) , m_styleSheet(styleSheet) { } protected: RefPtr m_styleSheet; }; class InspectorCSSAgent::SetStyleSheetTextAction final : public InspectorCSSAgent::StyleSheetAction { WTF_MAKE_NONCOPYABLE(SetStyleSheetTextAction); public: SetStyleSheetTextAction(InspectorStyleSheet* styleSheet, const String& text) : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetStyleSheetText"), styleSheet) , m_text(text) { } virtual bool perform(ExceptionCode& ec) override { if (!m_styleSheet->getText(&m_oldText)) return false; return redo(ec); } virtual bool undo(ExceptionCode& ec) override { if (m_styleSheet->setText(m_oldText, ec)) { m_styleSheet->reparseStyleSheet(m_oldText); return true; } return false; } virtual bool redo(ExceptionCode& ec) override { if (m_styleSheet->setText(m_text, ec)) { m_styleSheet->reparseStyleSheet(m_text); return true; } return false; } virtual String mergeId() override { return String::format("SetStyleSheetText %s", m_styleSheet->id().utf8().data()); } virtual void merge(std::unique_ptr action) override { ASSERT(action->mergeId() == mergeId()); SetStyleSheetTextAction* other = static_cast(action.get()); m_text = other->m_text; } private: String m_text; String m_oldText; }; class InspectorCSSAgent::SetStyleTextAction final : public InspectorCSSAgent::StyleSheetAction { WTF_MAKE_NONCOPYABLE(SetStyleTextAction); public: SetStyleTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& text) : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetStyleText"), styleSheet) , m_cssId(cssId) , m_text(text) { } virtual bool perform(ExceptionCode& ec) override { return redo(ec); } virtual bool undo(ExceptionCode& ec) override { return m_styleSheet->setStyleText(m_cssId, m_oldText, nullptr, ec); } virtual bool redo(ExceptionCode& ec) override { return m_styleSheet->setStyleText(m_cssId, m_text, &m_oldText, ec); } virtual String mergeId() override { ASSERT(m_styleSheet->id() == m_cssId.styleSheetId()); return String::format("SetStyleText %s:%u", m_styleSheet->id().utf8().data(), m_cssId.ordinal()); } virtual void merge(std::unique_ptr action) override { ASSERT(action->mergeId() == mergeId()); SetStyleTextAction* other = static_cast(action.get()); m_text = other->m_text; } private: InspectorCSSId m_cssId; String m_text; String m_oldText; }; class InspectorCSSAgent::SetRuleSelectorAction final : public InspectorCSSAgent::StyleSheetAction { WTF_MAKE_NONCOPYABLE(SetRuleSelectorAction); public: SetRuleSelectorAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, const String& selector) : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetRuleSelector"), styleSheet) , m_cssId(cssId) , m_selector(selector) { } virtual bool perform(ExceptionCode& ec) override { m_oldSelector = m_styleSheet->ruleSelector(m_cssId, ec); if (ec) return false; return redo(ec); } virtual bool undo(ExceptionCode& ec) override { return m_styleSheet->setRuleSelector(m_cssId, m_oldSelector, ec); } virtual bool redo(ExceptionCode& ec) override { return m_styleSheet->setRuleSelector(m_cssId, m_selector, ec); } private: InspectorCSSId m_cssId; String m_selector; String m_oldSelector; }; class InspectorCSSAgent::AddRuleAction final : public InspectorCSSAgent::StyleSheetAction { WTF_MAKE_NONCOPYABLE(AddRuleAction); public: AddRuleAction(InspectorStyleSheet* styleSheet, const String& selector) : InspectorCSSAgent::StyleSheetAction(ASCIILiteral("AddRule"), styleSheet) , m_selector(selector) { } virtual bool perform(ExceptionCode& ec) override { return redo(ec); } virtual bool undo(ExceptionCode& ec) override { return m_styleSheet->deleteRule(m_newId, ec); } virtual bool redo(ExceptionCode& ec) override { CSSStyleRule* cssStyleRule = m_styleSheet->addRule(m_selector, ec); if (ec) return false; m_newId = m_styleSheet->ruleId(cssStyleRule); return true; } InspectorCSSId newRuleId() { return m_newId; } private: InspectorCSSId m_newId; String m_selector; String m_oldSelector; }; // static CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(CSSRule& rule) { if (!is(rule)) return nullptr; return downcast(&rule); } InspectorCSSAgent::InspectorCSSAgent(WebAgentContext& context, InspectorDOMAgent* domAgent) : InspectorAgentBase(ASCIILiteral("CSS"), context) , m_frontendDispatcher(std::make_unique(context.frontendRouter)) , m_backendDispatcher(CSSBackendDispatcher::create(context.backendDispatcher, this)) , m_domAgent(domAgent) { m_domAgent->setDOMListener(this); } InspectorCSSAgent::~InspectorCSSAgent() { ASSERT(!m_domAgent); reset(); } void InspectorCSSAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) { } void InspectorCSSAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) { resetNonPersistentData(); String unused; disable(unused); } void InspectorCSSAgent::discardAgent() { m_domAgent->setDOMListener(nullptr); m_domAgent = nullptr; } void InspectorCSSAgent::reset() { // FIXME: Should we be resetting on main frame navigations? m_idToInspectorStyleSheet.clear(); m_cssStyleSheetToInspectorStyleSheet.clear(); m_nodeToInspectorStyleSheet.clear(); m_documentToInspectorStyleSheet.clear(); m_documentToKnownCSSStyleSheets.clear(); resetNonPersistentData(); } void InspectorCSSAgent::resetNonPersistentData() { m_namedFlowCollectionsRequested.clear(); if (m_changeRegionOversetTask) m_changeRegionOversetTask->reset(); resetPseudoStates(); } void InspectorCSSAgent::enable(ErrorString&) { m_instrumentingAgents.setInspectorCSSAgent(this); for (auto* document : m_domAgent->documents()) activeStyleSheetsUpdated(*document); } void InspectorCSSAgent::disable(ErrorString&) { m_instrumentingAgents.setInspectorCSSAgent(nullptr); } void InspectorCSSAgent::documentDetached(Document& document) { Vector emptyList; setActiveStyleSheetsForDocument(document, emptyList); m_documentToKnownCSSStyleSheets.remove(&document); } void InspectorCSSAgent::mediaQueryResultChanged() { m_frontendDispatcher->mediaQueryResultChanged(); } void InspectorCSSAgent::activeStyleSheetsUpdated(Document& document) { Vector cssStyleSheets; collectAllDocumentStyleSheets(document, cssStyleSheets); setActiveStyleSheetsForDocument(document, cssStyleSheets); } void InspectorCSSAgent::setActiveStyleSheetsForDocument(Document& document, Vector& activeStyleSheets) { HashSet& previouslyKnownActiveStyleSheets = m_documentToKnownCSSStyleSheets.add(&document, HashSet()).iterator->value; HashSet removedStyleSheets(previouslyKnownActiveStyleSheets); Vector addedStyleSheets; for (auto& activeStyleSheet : activeStyleSheets) { if (removedStyleSheets.contains(activeStyleSheet)) removedStyleSheets.remove(activeStyleSheet); else addedStyleSheets.append(activeStyleSheet); } for (auto* cssStyleSheet : removedStyleSheets) { previouslyKnownActiveStyleSheets.remove(cssStyleSheet); RefPtr inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(cssStyleSheet); if (m_idToInspectorStyleSheet.contains(inspectorStyleSheet->id())) { String id = unbindStyleSheet(inspectorStyleSheet.get()); m_frontendDispatcher->styleSheetRemoved(id); } } for (auto* cssStyleSheet : addedStyleSheets) { previouslyKnownActiveStyleSheets.add(cssStyleSheet); if (!m_cssStyleSheetToInspectorStyleSheet.contains(cssStyleSheet)) { InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssStyleSheet); m_frontendDispatcher->styleSheetAdded(inspectorStyleSheet->buildObjectForStyleSheetInfo()); } } } void InspectorCSSAgent::didCreateNamedFlow(Document& document, WebKitNamedFlow& namedFlow) { int documentNodeId = documentNodeWithRequestedFlowsId(&document); if (!documentNodeId) return; ErrorString unused; m_frontendDispatcher->namedFlowCreated(buildObjectForNamedFlow(unused, &namedFlow, documentNodeId)); } void InspectorCSSAgent::willRemoveNamedFlow(Document& document, WebKitNamedFlow& namedFlow) { int documentNodeId = documentNodeWithRequestedFlowsId(&document); if (!documentNodeId) return; if (m_changeRegionOversetTask) m_changeRegionOversetTask->unschedule(&namedFlow); m_frontendDispatcher->namedFlowRemoved(documentNodeId, namedFlow.name().string()); } void InspectorCSSAgent::didChangeRegionOverset(Document& document, WebKitNamedFlow& namedFlow) { int documentNodeId = documentNodeWithRequestedFlowsId(&document); if (!documentNodeId) return; if (!m_changeRegionOversetTask) m_changeRegionOversetTask = std::make_unique(this); m_changeRegionOversetTask->scheduleFor(&namedFlow, documentNodeId); } void InspectorCSSAgent::regionOversetChanged(WebKitNamedFlow* namedFlow, int documentNodeId) { if (namedFlow->flowState() == WebKitNamedFlow::FlowStateNull) return; ErrorString unused; Ref protect(*namedFlow); m_frontendDispatcher->regionOversetChanged(buildObjectForNamedFlow(unused, namedFlow, documentNodeId)); } void InspectorCSSAgent::didRegisterNamedFlowContentElement(Document& document, WebKitNamedFlow& namedFlow, Node& contentElement, Node* nextContentElement) { int documentNodeId = documentNodeWithRequestedFlowsId(&document); if (!documentNodeId) return; ErrorString unused; int contentElementNodeId = m_domAgent->pushNodeToFrontend(unused, documentNodeId, &contentElement); int nextContentElementNodeId = nextContentElement ? m_domAgent->pushNodeToFrontend(unused, documentNodeId, nextContentElement) : 0; m_frontendDispatcher->registeredNamedFlowContentElement(documentNodeId, namedFlow.name().string(), contentElementNodeId, nextContentElementNodeId); } void InspectorCSSAgent::didUnregisterNamedFlowContentElement(Document& document, WebKitNamedFlow& namedFlow, Node& contentElement) { int documentNodeId = documentNodeWithRequestedFlowsId(&document); if (!documentNodeId) return; ErrorString unused; int contentElementNodeId = m_domAgent->pushNodeToFrontend(unused, documentNodeId, &contentElement); if (!contentElementNodeId) { // We've already notified that the DOM node was removed from the DOM, so there's no need to send another event. return; } m_frontendDispatcher->unregisteredNamedFlowContentElement(documentNodeId, namedFlow.name().string(), contentElementNodeId); } bool InspectorCSSAgent::forcePseudoState(Element& element, CSSSelector::PseudoClassType pseudoClassType) { if (m_nodeIdToForcedPseudoState.isEmpty()) return false; int nodeId = m_domAgent->boundNodeId(&element); if (!nodeId) return false; NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId); if (it == m_nodeIdToForcedPseudoState.end()) return false; unsigned forcedPseudoState = it->value; switch (pseudoClassType) { case CSSSelector::PseudoClassActive: return forcedPseudoState & PseudoClassActive; case CSSSelector::PseudoClassFocus: return forcedPseudoState & PseudoClassFocus; case CSSSelector::PseudoClassHover: return forcedPseudoState & PseudoClassHover; case CSSSelector::PseudoClassVisited: return forcedPseudoState & PseudoClassVisited; default: return false; } } void InspectorCSSAgent::getMatchedStylesForNode(ErrorString& errorString, int nodeId, const bool* includePseudo, const bool* includeInherited, RefPtr>& matchedCSSRules, RefPtr>& pseudoIdMatches, RefPtr>& inheritedEntries) { Element* element = elementForId(errorString, nodeId); if (!element) return; Element* originalElement = element; PseudoId elementPseudoId = element->pseudoId(); if (elementPseudoId) { element = downcast(*element).hostElement(); if (!element) { errorString = ASCIILiteral("Pseudo element has no parent"); return; } } // Matched rules. StyleResolver& styleResolver = element->styleResolver(); auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, elementPseudoId, StyleResolver::AllCSSRules); matchedCSSRules = buildArrayForMatchedRuleList(matchedRules, styleResolver, element, elementPseudoId); if (!originalElement->isPseudoElement()) { // Pseudo elements. if (!includePseudo || *includePseudo) { auto pseudoElements = Inspector::Protocol::Array::create(); for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast(pseudoId + 1)) { auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules); if (!matchedRules.isEmpty()) { auto matches = Inspector::Protocol::CSS::PseudoIdMatches::create() .setPseudoId(static_cast(pseudoId)) .setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, element, pseudoId)) .release(); pseudoElements->addItem(WTFMove(matches)); } } pseudoIdMatches = WTFMove(pseudoElements); } // Inherited styles. if (!includeInherited || *includeInherited) { auto entries = Inspector::Protocol::Array::create(); Element* parentElement = element->parentElement(); while (parentElement) { StyleResolver& parentStyleResolver = parentElement->styleResolver(); auto parentMatchedRules = parentStyleResolver.styleRulesForElement(parentElement, StyleResolver::AllCSSRules); auto entry = Inspector::Protocol::CSS::InheritedStyleEntry::create() .setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules, styleResolver, parentElement, NOPSEUDO)) .release(); if (parentElement->cssomStyle() && parentElement->cssomStyle()->length()) { if (InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement)) entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0)))); } entries->addItem(WTFMove(entry)); parentElement = parentElement->parentElement(); } inheritedEntries = WTFMove(entries); } } } void InspectorCSSAgent::getInlineStylesForNode(ErrorString& errorString, int nodeId, RefPtr& inlineStyle, RefPtr& attributesStyle) { Element* element = elementForId(errorString, nodeId); if (!element) return; InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element); if (!styleSheet) return; inlineStyle = styleSheet->buildObjectForStyle(element->cssomStyle()); RefPtr attributes = buildObjectForAttributesStyle(element); attributesStyle = attributes ? attributes.release() : nullptr; } void InspectorCSSAgent::getComputedStyleForNode(ErrorString& errorString, int nodeId, RefPtr>& style) { Element* element = elementForId(errorString, nodeId); if (!element) return; RefPtr computedStyleInfo = CSSComputedStyleDeclaration::create(element, true); Ref inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, nullptr); style = inspectorStyle->buildArrayForComputedStyle(); } void InspectorCSSAgent::getAllStyleSheets(ErrorString&, RefPtr>& styleInfos) { styleInfos = Inspector::Protocol::Array::create(); Vector inspectorStyleSheets; collectAllStyleSheets(inspectorStyleSheets); for (auto* inspectorStyleSheet : inspectorStyleSheets) styleInfos->addItem(inspectorStyleSheet->buildObjectForStyleSheetInfo()); } void InspectorCSSAgent::collectAllStyleSheets(Vector& result) { Vector cssStyleSheets; for (auto* document : m_domAgent->documents()) collectAllDocumentStyleSheets(*document, cssStyleSheets); for (auto* cssStyleSheet : cssStyleSheets) result.append(bindStyleSheet(cssStyleSheet)); } void InspectorCSSAgent::collectAllDocumentStyleSheets(Document& document, Vector& result) { auto cssStyleSheets = document.authorStyleSheets().activeStyleSheetsForInspector(); for (auto& cssStyleSheet : cssStyleSheets) collectStyleSheets(cssStyleSheet.get(), result); } void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Vector& result) { result.append(styleSheet); for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) { CSSRule* rule = styleSheet->item(i); if (is(*rule)) { if (CSSStyleSheet* importedStyleSheet = downcast(*rule).styleSheet()) collectStyleSheets(importedStyleSheet, result); } } } void InspectorCSSAgent::getStyleSheet(ErrorString& errorString, const String& styleSheetId, RefPtr& styleSheetObject) { InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId); if (!inspectorStyleSheet) return; styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet(); } void InspectorCSSAgent::getStyleSheetText(ErrorString& errorString, const String& styleSheetId, String* result) { InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId); if (!inspectorStyleSheet) return; inspectorStyleSheet->getText(result); } void InspectorCSSAgent::setStyleSheetText(ErrorString& errorString, const String& styleSheetId, const String& text) { InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId); if (!inspectorStyleSheet) return; ExceptionCode ec = 0; m_domAgent->history()->perform(std::make_unique(inspectorStyleSheet, text), ec); errorString = InspectorDOMAgent::toErrorString(ec); } void InspectorCSSAgent::setStyleText(ErrorString& errorString, const InspectorObject& fullStyleId, const String& text, RefPtr& result) { InspectorCSSId compoundId(fullStyleId); ASSERT(!compoundId.isEmpty()); InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId()); if (!inspectorStyleSheet) return; ExceptionCode ec = 0; bool success = m_domAgent->history()->perform(std::make_unique(inspectorStyleSheet, compoundId, text), ec); if (success) result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId)); errorString = InspectorDOMAgent::toErrorString(ec); } void InspectorCSSAgent::setRuleSelector(ErrorString& errorString, const InspectorObject& fullRuleId, const String& selector, RefPtr& result) { InspectorCSSId compoundId(fullRuleId); ASSERT(!compoundId.isEmpty()); InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId()); if (!inspectorStyleSheet) return; ExceptionCode ec = 0; bool success = m_domAgent->history()->perform(std::make_unique(inspectorStyleSheet, compoundId, selector), ec); if (success) result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId), nullptr); errorString = InspectorDOMAgent::toErrorString(ec); } void InspectorCSSAgent::createStyleSheet(ErrorString& errorString, const String& frameId, String* styleSheetId) { Frame* frame = m_domAgent->pageAgent()->frameForId(frameId); if (!frame) { errorString = ASCIILiteral("No frame for given id found"); return; } Document* document = frame->document(); if (!document) { errorString = ASCIILiteral("No document for frame"); return; } InspectorStyleSheet* inspectorStyleSheet = createInspectorStyleSheetForDocument(*document); if (!inspectorStyleSheet) { errorString = ASCIILiteral("Could not create stylesheet for the frame."); return; } *styleSheetId = inspectorStyleSheet->id(); } InspectorStyleSheet* InspectorCSSAgent::createInspectorStyleSheetForDocument(Document& document) { if (!document.isHTMLDocument() && !document.isSVGDocument()) return nullptr; Ref styleElement = document.createElement(HTMLNames::styleTag, false); styleElement->setAttribute(HTMLNames::typeAttr, "text/css"); ContainerNode* targetNode; // HEAD is absent in ImageDocuments, for example. if (auto* head = document.head()) targetNode = head; else if (auto* body = document.bodyOrFrameset()) targetNode = body; else return nullptr; // Inserting this