blob: 2c73db9fd4becda444de9f3b8037876aa28a737b [file] [log] [blame]
/*
* Copyright (C) 2010, Google 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"
#if ENABLE(INSPECTOR)
#include "InspectorCSSAgent.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 "HTMLHeadElement.h"
#include "HTMLStyleElement.h"
#include "InspectorDOMAgent.h"
#include "InspectorHistory.h"
#include "InspectorWebProtocolTypes.h"
#include "InstrumentingAgents.h"
#include "NamedFlowCollection.h"
#include "Node.h"
#include "NodeList.h"
#include "RenderNamedFlowFragment.h"
#include "SVGStyleElement.h"
#include "StyleProperties.h"
#include "StylePropertyShorthand.h"
#include "StyleResolver.h"
#include "StyleRule.h"
#include "StyleSheetList.h"
#include "WebKitNamedFlow.h"
#include <inspector/InspectorValues.h>
#include <wtf/CurrentTime.h>
#include <wtf/HashSet.h>
#include <wtf/Ref.h>
#include <wtf/Vector.h>
#include <wtf/text/CString.h>
#include <wtf/text/StringConcatenate.h>
using namespace Inspector;
namespace WebCore {
enum ForcePseudoClassFlags {
PseudoClassNone = 0,
PseudoClassHover = 1 << 0,
PseudoClassFocus = 1 << 1,
PseudoClassActive = 1 << 2,
PseudoClassVisited = 1 << 3
};
static unsigned computePseudoClassMask(InspectorArray* pseudoClassArray)
{
DEPRECATED_DEFINE_STATIC_LOCAL(String, active, (ASCIILiteral("active")));
DEPRECATED_DEFINE_STATIC_LOCAL(String, hover, (ASCIILiteral("hover")));
DEPRECATED_DEFINE_STATIC_LOCAL(String, focus, (ASCIILiteral("focus")));
DEPRECATED_DEFINE_STATIC_LOCAL(String, visited, (ASCIILiteral("visited")));
if (!pseudoClassArray || !pseudoClassArray->length())
return PseudoClassNone;
unsigned result = PseudoClassNone;
for (size_t i = 0; i < pseudoClassArray->length(); ++i) {
RefPtr<InspectorValue> pseudoClassValue = pseudoClassArray->get(i);
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(Timer<ChangeRegionOversetTask>&);
private:
InspectorCSSAgent* m_cssAgent;
Timer<ChangeRegionOversetTask> m_timer;
HashMap<WebKitNamedFlow*, int> 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(Timer<ChangeRegionOversetTask>&)
{
// The timer is stopped on m_cssAgent destruction, so this method will never be called after m_cssAgent has been destroyed.
for (HashMap<WebKitNamedFlow*, int>::iterator it = m_namedFlows.begin(), end = m_namedFlows.end(); it != end; ++it)
m_cssAgent->regionOversetChanged(it->key, it->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<InspectorStyleSheet> 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> action) override
{
ASSERT(action->mergeId() == mergeId());
SetStyleSheetTextAction* other = static_cast<SetStyleSheetTextAction*>(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> action) override
{
ASSERT(action->mergeId() == mergeId());
SetStyleTextAction* other = static_cast<SetStyleTextAction*>(action.get());
m_text = other->m_text;
}
private:
InspectorCSSId m_cssId;
String m_text;
String m_oldText;
};
class InspectorCSSAgent::SetPropertyTextAction final : public InspectorCSSAgent::StyleSheetAction {
WTF_MAKE_NONCOPYABLE(SetPropertyTextAction);
public:
SetPropertyTextAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, const String& text, bool overwrite)
: InspectorCSSAgent::StyleSheetAction(ASCIILiteral("SetPropertyText"), styleSheet)
, m_cssId(cssId)
, m_propertyIndex(propertyIndex)
, m_text(text)
, m_overwrite(overwrite)
{
}
virtual String toString() override
{
return mergeId() + ": " + m_oldText + " -> " + m_text;
}
virtual bool perform(ExceptionCode& ec) override
{
return redo(ec);
}
virtual bool undo(ExceptionCode& ec) override
{
String placeholder;
return m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_overwrite ? m_oldText : "", true, &placeholder, ec);
}
virtual bool redo(ExceptionCode& ec) override
{
String oldText;
bool result = m_styleSheet->setPropertyText(m_cssId, m_propertyIndex, m_text, m_overwrite, &oldText, ec);
m_oldText = oldText.stripWhiteSpace();
// FIXME: remove this once the model handles this case.
if (!m_oldText.endsWith(';'))
m_oldText.append(';');
return result;
}
virtual String mergeId() override
{
return String::format("SetPropertyText %s:%u:%s", m_styleSheet->id().utf8().data(), m_propertyIndex, m_overwrite ? "true" : "false");
}
virtual void merge(std::unique_ptr<Action> action) override
{
ASSERT(action->mergeId() == mergeId());
SetPropertyTextAction* other = static_cast<SetPropertyTextAction*>(action.get());
m_text = other->m_text;
}
private:
InspectorCSSId m_cssId;
unsigned m_propertyIndex;
String m_text;
String m_oldText;
bool m_overwrite;
};
class InspectorCSSAgent::TogglePropertyAction final : public InspectorCSSAgent::StyleSheetAction {
WTF_MAKE_NONCOPYABLE(TogglePropertyAction);
public:
TogglePropertyAction(InspectorStyleSheet* styleSheet, const InspectorCSSId& cssId, unsigned propertyIndex, bool disable)
: InspectorCSSAgent::StyleSheetAction(ASCIILiteral("ToggleProperty"), styleSheet)
, m_cssId(cssId)
, m_propertyIndex(propertyIndex)
, m_disable(disable)
{
}
virtual bool perform(ExceptionCode& ec) override
{
return redo(ec);
}
virtual bool undo(ExceptionCode& ec) override
{
return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, !m_disable, ec);
}
virtual bool redo(ExceptionCode& ec) override
{
return m_styleSheet->toggleProperty(m_cssId, m_propertyIndex, m_disable, ec);
}
private:
InspectorCSSId m_cssId;
unsigned m_propertyIndex;
bool m_disable;
};
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 (rule->type() != CSSRule::STYLE_RULE)
return nullptr;
return toCSSStyleRule(rule);
}
InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorDOMAgent* domAgent)
: InspectorAgentBase(ASCIILiteral("CSS"), instrumentingAgents)
, m_domAgent(domAgent)
, m_lastStyleSheetId(1)
{
m_domAgent->setDOMListener(this);
}
InspectorCSSAgent::~InspectorCSSAgent()
{
ASSERT(!m_domAgent);
reset();
}
void InspectorCSSAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
{
m_frontendDispatcher = std::make_unique<InspectorCSSFrontendDispatcher>(frontendChannel);
m_backendDispatcher = InspectorCSSBackendDispatcher::create(backendDispatcher, this);
}
void InspectorCSSAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
{
m_frontendDispatcher = nullptr;
m_backendDispatcher.clear();
resetNonPersistentData();
}
void InspectorCSSAgent::discardAgent()
{
m_domAgent->setDOMListener(nullptr);
m_domAgent = nullptr;
}
void InspectorCSSAgent::reset()
{
m_idToInspectorStyleSheet.clear();
m_cssStyleSheetToInspectorStyleSheet.clear();
m_nodeToInspectorStyleSheet.clear();
m_documentToInspectorStyleSheet.clear();
resetNonPersistentData();
}
void InspectorCSSAgent::resetNonPersistentData()
{
m_namedFlowCollectionsRequested.clear();
if (m_changeRegionOversetTask)
m_changeRegionOversetTask->reset();
resetPseudoStates();
}
void InspectorCSSAgent::enable(ErrorString*)
{
m_instrumentingAgents->setInspectorCSSAgent(this);
}
void InspectorCSSAgent::disable(ErrorString*)
{
m_instrumentingAgents->setInspectorCSSAgent(nullptr);
}
void InspectorCSSAgent::mediaQueryResultChanged()
{
if (m_frontendDispatcher)
m_frontendDispatcher->mediaQueryResultChanged();
}
void InspectorCSSAgent::didCreateNamedFlow(Document* document, WebKitNamedFlow* namedFlow)
{
int documentNodeId = documentNodeWithRequestedFlowsId(document);
if (!documentNodeId)
return;
ErrorString errorString;
m_frontendDispatcher->namedFlowCreated(buildObjectForNamedFlow(&errorString, 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<ChangeRegionOversetTask>(this);
m_changeRegionOversetTask->scheduleFor(namedFlow, documentNodeId);
}
void InspectorCSSAgent::regionOversetChanged(WebKitNamedFlow* namedFlow, int documentNodeId)
{
if (namedFlow->flowState() == WebKitNamedFlow::FlowStateNull)
return;
ErrorString errorString;
Ref<WebKitNamedFlow> protect(*namedFlow);
m_frontendDispatcher->regionOversetChanged(buildObjectForNamedFlow(&errorString, namedFlow, documentNodeId));
}
void InspectorCSSAgent::didRegisterNamedFlowContentElement(Document* document, WebKitNamedFlow* namedFlow, Node* contentElement, Node* nextContentElement)
{
int documentNodeId = documentNodeWithRequestedFlowsId(document);
if (!documentNodeId)
return;
ErrorString errorString;
int contentElementNodeId = m_domAgent->pushNodeToFrontend(&errorString, documentNodeId, contentElement);
int nextContentElementNodeId = nextContentElement ? m_domAgent->pushNodeToFrontend(&errorString, 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 errorString;
int contentElementNodeId = m_domAgent->pushNodeToFrontend(&errorString, 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<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>>& matchedCSSRules, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::PseudoIdMatches>>& pseudoIdMatches, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::InheritedStyleEntry>>& inheritedEntries)
{
Element* element = elementForId(errorString, nodeId);
if (!element)
return;
// Matched rules.
StyleResolver& styleResolver = element->document().ensureStyleResolver();
auto matchedRules = styleResolver.styleRulesForElement(element, StyleResolver::AllCSSRules);
matchedCSSRules = buildArrayForMatchedRuleList(matchedRules, styleResolver, element);
// Pseudo elements.
if (!includePseudo || *includePseudo) {
RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::PseudoIdMatches>> pseudoElements = Inspector::Protocol::Array<Inspector::Protocol::CSS::PseudoIdMatches>::create();
for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
auto matchedRules = styleResolver.pseudoStyleRulesForElement(element, pseudoId, StyleResolver::AllCSSRules);
if (!matchedRules.isEmpty()) {
RefPtr<Inspector::Protocol::CSS::PseudoIdMatches> matches = Inspector::Protocol::CSS::PseudoIdMatches::create()
.setPseudoId(static_cast<int>(pseudoId))
.setMatches(buildArrayForMatchedRuleList(matchedRules, styleResolver, element));
pseudoElements->addItem(matches.release());
}
}
pseudoIdMatches = pseudoElements.release();
}
// Inherited styles.
if (!includeInherited || *includeInherited) {
RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::InheritedStyleEntry>> entries = Inspector::Protocol::Array<Inspector::Protocol::CSS::InheritedStyleEntry>::create();
Element* parentElement = element->parentElement();
while (parentElement) {
StyleResolver& parentStyleResolver = parentElement->document().ensureStyleResolver();
auto parentMatchedRules = parentStyleResolver.styleRulesForElement(parentElement, StyleResolver::AllCSSRules);
RefPtr<Inspector::Protocol::CSS::InheritedStyleEntry> entry = Inspector::Protocol::CSS::InheritedStyleEntry::create()
.setMatchedCSSRules(buildArrayForMatchedRuleList(parentMatchedRules, styleResolver, parentElement));
if (parentElement->style() && parentElement->style()->length()) {
InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
if (styleSheet)
entry->setInlineStyle(styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
}
entries->addItem(entry.release());
parentElement = parentElement->parentElement();
}
inheritedEntries = entries.release();
}
}
void InspectorCSSAgent::getInlineStylesForNode(ErrorString* errorString, int nodeId, RefPtr<Inspector::Protocol::CSS::CSSStyle>& inlineStyle, RefPtr<Inspector::Protocol::CSS::CSSStyle>& attributesStyle)
{
Element* element = elementForId(errorString, nodeId);
if (!element)
return;
InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
if (!styleSheet)
return;
inlineStyle = styleSheet->buildObjectForStyle(element->style());
RefPtr<Inspector::Protocol::CSS::CSSStyle> attributes = buildObjectForAttributesStyle(element);
attributesStyle = attributes ? attributes.release() : nullptr;
}
void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSComputedStyleProperty>>& style)
{
Element* element = elementForId(errorString, nodeId);
if (!element)
return;
RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = CSSComputedStyleDeclaration::create(element, true);
RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, nullptr);
style = inspectorStyle->buildArrayForComputedStyle();
}
void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSStyleSheetHeader>>& styleInfos)
{
styleInfos = Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSStyleSheetHeader>::create();
Vector<Document*> documents = m_domAgent->documents();
for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
StyleSheetList& list = (*it)->styleSheets();
for (unsigned i = 0; i < list.length(); ++i) {
StyleSheet& styleSheet = *list.item(i);
if (styleSheet.isCSSStyleSheet())
collectStyleSheets(&toCSSStyleSheet(styleSheet), styleInfos.get());
}
}
}
void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<Inspector::Protocol::CSS::CSSStyleSheetBody>& 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<SetStyleSheetTextAction>(inspectorStyleSheet, text), ec);
*errorString = InspectorDOMAgent::toErrorString(ec);
}
void InspectorCSSAgent::setStyleText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, const String& text, RefPtr<Inspector::Protocol::CSS::CSSStyle>& 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<SetStyleTextAction>(inspectorStyleSheet, compoundId, text), ec);
if (success)
result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
*errorString = InspectorDOMAgent::toErrorString(ec);
}
void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<Inspector::Protocol::CSS::CSSStyle>& 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<SetPropertyTextAction>(inspectorStyleSheet, compoundId, propertyIndex, text, overwrite), ec);
if (success)
result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
*errorString = InspectorDOMAgent::toErrorString(ec);
}
void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<Inspector::Protocol::CSS::CSSStyle>& 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<TogglePropertyAction>(inspectorStyleSheet, compoundId, propertyIndex, disable), ec);
if (success)
result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
*errorString = InspectorDOMAgent::toErrorString(ec);
}
void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<Inspector::Protocol::CSS::CSSRule>& 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<SetRuleSelectorAction>(inspectorStyleSheet, compoundId, selector), ec);
if (success)
result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
*errorString = InspectorDOMAgent::toErrorString(ec);
}
void InspectorCSSAgent::addRule(ErrorString* errorString, const int contextNodeId, const String& selector, RefPtr<Inspector::Protocol::CSS::CSSRule>& result)
{
Node* node = m_domAgent->assertNode(errorString, contextNodeId);
if (!node)
return;
InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(&node->document(), true);
if (!inspectorStyleSheet) {
*errorString = "No target stylesheet found";
return;
}
ExceptionCode ec = 0;
auto action = std::make_unique<AddRuleAction>(inspectorStyleSheet, selector);
AddRuleAction* rawAction = action.get();
bool success = m_domAgent->history()->perform(WTF::move(action), ec);
if (!success) {
*errorString = InspectorDOMAgent::toErrorString(ec);
return;
}
InspectorCSSId ruleId = rawAction->newRuleId();
CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
result = inspectorStyleSheet->buildObjectForRule(rule);
}
void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSPropertyInfo>>& cssProperties)
{
RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSPropertyInfo>> properties = Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSPropertyInfo>::create();
for (int i = firstCSSProperty; i <= lastCSSProperty; ++i) {
CSSPropertyID id = convertToCSSPropertyID(i);
RefPtr<Inspector::Protocol::CSS::CSSPropertyInfo> property = Inspector::Protocol::CSS::CSSPropertyInfo::create()
.setName(getPropertyNameString(id));
const StylePropertyShorthand& shorthand = shorthandForProperty(id);
if (!shorthand.length()) {
properties->addItem(property.release());
continue;
}
RefPtr<Inspector::Protocol::Array<String>> longhands = Inspector::Protocol::Array<String>::create();
for (unsigned j = 0; j < shorthand.length(); ++j) {
CSSPropertyID longhandID = shorthand.properties()[j];
longhands->addItem(getPropertyNameString(longhandID));
}
property->setLonghands(longhands);
properties->addItem(property.release());
}
cssProperties = properties.release();
}
void InspectorCSSAgent::forcePseudoState(ErrorString* errorString, int nodeId, const RefPtr<InspectorArray>& forcedPseudoClasses)
{
Element* element = m_domAgent->assertElement(errorString, nodeId);
if (!element)
return;
unsigned forcedPseudoState = computePseudoClassMask(forcedPseudoClasses.get());
NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.find(nodeId);
unsigned currentForcedPseudoState = it == m_nodeIdToForcedPseudoState.end() ? 0 : it->value;
bool needStyleRecalc = forcedPseudoState != currentForcedPseudoState;
if (!needStyleRecalc)
return;
if (forcedPseudoState)
m_nodeIdToForcedPseudoState.set(nodeId, forcedPseudoState);
else
m_nodeIdToForcedPseudoState.remove(nodeId);
element->document().styleResolverChanged(RecalcStyleImmediately);
}
void InspectorCSSAgent::getNamedFlowCollection(ErrorString* errorString, int documentNodeId, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::NamedFlow>>& result)
{
Document* document = m_domAgent->assertDocument(errorString, documentNodeId);
if (!document)
return;
m_namedFlowCollectionsRequested.add(documentNodeId);
Vector<RefPtr<WebKitNamedFlow>> namedFlowsVector = document->namedFlows().namedFlows();
RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::NamedFlow>> namedFlows = Inspector::Protocol::Array<Inspector::Protocol::CSS::NamedFlow>::create();
for (Vector<RefPtr<WebKitNamedFlow>>::iterator it = namedFlowsVector.begin(); it != namedFlowsVector.end(); ++it)
namedFlows->addItem(buildObjectForNamedFlow(errorString, it->get(), documentNodeId));
result = namedFlows.release();
}
InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
{
NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
if (it == m_nodeToInspectorStyleSheet.end()) {
CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : nullptr;
if (!style)
return nullptr;
String newStyleSheetId = String::number(m_lastStyleSheetId++);
RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(m_domAgent->pageAgent(), newStyleSheetId, element, Inspector::Protocol::CSS::StyleSheetOrigin::Regular, this);
m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
return inspectorStyleSheet.get();
}
return it->value.get();
}
Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
{
Node* node = m_domAgent->nodeForId(nodeId);
if (!node) {
*errorString = "No node with given id found";
return nullptr;
}
if (!node->isElementNode()) {
*errorString = "Not an element node";
return nullptr;
}
return toElement(node);
}
int InspectorCSSAgent::documentNodeWithRequestedFlowsId(Document* document)
{
int documentNodeId = m_domAgent->boundNodeId(document);
if (!documentNodeId || !m_namedFlowCollectionsRequested.contains(documentNodeId))
return 0;
return documentNodeId;
}
void InspectorCSSAgent::collectStyleSheets(CSSStyleSheet* styleSheet, Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSStyleSheetHeader>* result)
{
InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(styleSheet);
result->addItem(inspectorStyleSheet->buildObjectForStyleSheetInfo());
for (unsigned i = 0, size = styleSheet->length(); i < size; ++i) {
CSSRule* rule = styleSheet->item(i);
if (rule->type() == CSSRule::IMPORT_RULE) {
CSSStyleSheet* importedStyleSheet = toCSSImportRule(rule)->styleSheet();
if (importedStyleSheet)
collectStyleSheets(importedStyleSheet, result);
}
}
}
InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
{
RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
if (!inspectorStyleSheet) {
String id = String::number(m_lastStyleSheetId++);
Document* document = styleSheet->ownerDocument();
inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, styleSheet, detectOrigin(styleSheet, document), InspectorDOMAgent::documentURLString(document), this);
m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
}
return inspectorStyleSheet.get();
}
InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
{
if (!document) {
ASSERT(!createIfAbsent);
return nullptr;
}
if (!document->isHTMLDocument() && !document->isSVGDocument())
return nullptr;
RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
if (inspectorStyleSheet || !createIfAbsent)
return inspectorStyleSheet.get();
ExceptionCode ec = 0;
RefPtr<Element> styleElement = document->createElement("style", ec);
if (!ec)
styleElement->setAttribute("type", "text/css", ec);
if (!ec) {
ContainerNode* targetNode;
// HEAD is absent in ImageDocuments, for example.
if (document->head())
targetNode = document->head();
else if (document->body())
targetNode = document->body();
else
return nullptr;
InlineStyleOverrideScope overrideScope(document);
targetNode->appendChild(styleElement, ec);
}
if (ec)
return nullptr;
CSSStyleSheet* cssStyleSheet = nullptr;
if (styleElement->isHTMLElement())
cssStyleSheet = downcast<HTMLStyleElement>(*styleElement).sheet();
else if (styleElement->isSVGElement())
cssStyleSheet = downcast<SVGStyleElement>(*styleElement).sheet();
if (!cssStyleSheet)
return nullptr;
String id = String::number(m_lastStyleSheetId++);
inspectorStyleSheet = InspectorStyleSheet::create(m_domAgent->pageAgent(), id, cssStyleSheet, Inspector::Protocol::CSS::StyleSheetOrigin::Inspector, InspectorDOMAgent::documentURLString(document), this);
m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
return inspectorStyleSheet.get();
}
InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
{
IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
if (it == m_idToInspectorStyleSheet.end()) {
*errorString = "No style sheet with given id found";
return nullptr;
}
return it->value.get();
}
Inspector::Protocol::CSS::StyleSheetOrigin InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
{
Inspector::Protocol::CSS::StyleSheetOrigin origin = Inspector::Protocol::CSS::StyleSheetOrigin::Regular;
if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
origin = Inspector::Protocol::CSS::StyleSheetOrigin::UserAgent;
else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
origin = Inspector::Protocol::CSS::StyleSheetOrigin::User;
else {
InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
origin = Inspector::Protocol::CSS::StyleSheetOrigin::Inspector;
}
return origin;
}
PassRefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(StyleRule* styleRule, StyleResolver& styleResolver)
{
if (!styleRule)
return nullptr;
// StyleRules returned by StyleResolver::styleRulesForElement lack parent pointers since that infomation is not cheaply available.
// Since the inspector wants to walk the parent chain, we construct the full wrappers here.
CSSStyleRule* cssomWrapper = styleResolver.inspectorCSSOMWrappers().getWrapperForRuleInSheets(styleRule, styleResolver.document().styleSheetCollection());
if (!cssomWrapper)
return nullptr;
InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssomWrapper->parentStyleSheet());
return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(cssomWrapper) : nullptr;
}
PassRefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule)
{
if (!rule)
return nullptr;
ASSERT(rule->parentStyleSheet());
InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(rule->parentStyleSheet());
return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(rule) : nullptr;
}
PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSRule>> InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
{
RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSRule>> result = Inspector::Protocol::Array<Inspector::Protocol::CSS::CSSRule>::create();
if (!ruleList)
return result.release();
for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
RefPtr<Inspector::Protocol::CSS::CSSRule> ruleObject = buildObjectForRule(rule);
if (!ruleObject)
continue;
result->addItem(ruleObject);
}
return result.release();
}
PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<StyleRule>>& matchedRules, StyleResolver& styleResolver, Element* element)
{
RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>> result = Inspector::Protocol::Array<Inspector::Protocol::CSS::RuleMatch>::create();
for (unsigned i = 0; i < matchedRules.size(); ++i) {
if (!matchedRules[i]->isStyleRule())
continue;
StyleRule* matchedStyleRule = static_cast<StyleRule*>(matchedRules[i].get());
RefPtr<Inspector::Protocol::CSS::CSSRule> ruleObject = buildObjectForRule(matchedStyleRule, styleResolver);
if (!ruleObject)
continue;
RefPtr<Inspector::Protocol::Array<int>> matchingSelectors = Inspector::Protocol::Array<int>::create();
const CSSSelectorList& selectorList = matchedStyleRule->selectorList();
long index = 0;
for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
bool matched = element->matches(selector->selectorText(), IGNORE_EXCEPTION);
if (matched)
matchingSelectors->addItem(index);
++index;
}
RefPtr<Inspector::Protocol::CSS::RuleMatch> match = Inspector::Protocol::CSS::RuleMatch::create()
.setRule(ruleObject)
.setMatchingSelectors(matchingSelectors);
result->addItem(match);
}
return result.release();
}
PassRefPtr<Inspector::Protocol::CSS::CSSStyle> InspectorCSSAgent::buildObjectForAttributesStyle(Element* element)
{
if (!element->isStyledElement())
return nullptr;
// FIXME: Ugliness below.
StyleProperties* attributeStyle = const_cast<StyleProperties*>(toStyledElement(element)->presentationAttributeStyle());
if (!attributeStyle)
return nullptr;
ASSERT_WITH_SECURITY_IMPLICATION(attributeStyle->isMutable());
MutableStyleProperties* mutableAttributeStyle = static_cast<MutableStyleProperties*>(attributeStyle);
RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), mutableAttributeStyle->ensureCSSStyleDeclaration(), nullptr);
return inspectorStyle->buildObjectForStyle();
}
PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>> InspectorCSSAgent::buildArrayForRegions(ErrorString* errorString, PassRefPtr<NodeList> regionList, int documentNodeId)
{
RefPtr<Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>> regions = Inspector::Protocol::Array<Inspector::Protocol::CSS::Region>::create();
for (unsigned i = 0; i < regionList->length(); ++i) {
Inspector::Protocol::CSS::Region::RegionOverset regionOverset;
switch (toElement(regionList->item(i))->regionOversetState()) {
case RegionFit:
regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Fit;
break;
case RegionEmpty:
regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Empty;
break;
case RegionOverset:
regionOverset = Inspector::Protocol::CSS::Region::RegionOverset::Overset;
break;
case RegionUndefined:
continue;
default:
ASSERT_NOT_REACHED();
continue;
}
RefPtr<Inspector::Protocol::CSS::Region> region = Inspector::Protocol::CSS::Region::create()
.setRegionOverset(regionOverset)
// documentNodeId was previously asserted
.setNodeId(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, regionList->item(i)));
regions->addItem(region);
}
return regions.release();
}
PassRefPtr<Inspector::Protocol::CSS::NamedFlow> InspectorCSSAgent::buildObjectForNamedFlow(ErrorString* errorString, WebKitNamedFlow* webkitNamedFlow, int documentNodeId)
{
RefPtr<NodeList> contentList = webkitNamedFlow->getContent();
RefPtr<Inspector::Protocol::Array<int>> content = Inspector::Protocol::Array<int>::create();
for (unsigned i = 0; i < contentList->length(); ++i) {
// documentNodeId was previously asserted
content->addItem(m_domAgent->pushNodeToFrontend(errorString, documentNodeId, contentList->item(i)));
}
RefPtr<Inspector::Protocol::CSS::NamedFlow> namedFlow = Inspector::Protocol::CSS::NamedFlow::create()
.setDocumentNodeId(documentNodeId)
.setName(webkitNamedFlow->name().string())
.setOverset(webkitNamedFlow->overset())
.setContent(content)
.setRegions(buildArrayForRegions(errorString, webkitNamedFlow->getRegions(), documentNodeId));
return namedFlow.release();
}
void InspectorCSSAgent::didRemoveDocument(Document* document)
{
if (document)
m_documentToInspectorStyleSheet.remove(document);
}
void InspectorCSSAgent::didRemoveDOMNode(Node* node)
{
if (!node)
return;
int nodeId = m_domAgent->boundNodeId(node);
if (nodeId)
m_nodeIdToForcedPseudoState.remove(nodeId);
NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
if (it == m_nodeToInspectorStyleSheet.end())
return;
m_idToInspectorStyleSheet.remove(it->value->id());
m_nodeToInspectorStyleSheet.remove(node);
}
void InspectorCSSAgent::didModifyDOMAttr(Element* element)
{
if (!element)
return;
NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
if (it == m_nodeToInspectorStyleSheet.end())
return;
it->value->didModifyElementAttribute();
}
void InspectorCSSAgent::styleSheetChanged(InspectorStyleSheet* styleSheet)
{
if (m_frontendDispatcher)
m_frontendDispatcher->styleSheetChanged(styleSheet->id());
}
void InspectorCSSAgent::resetPseudoStates()
{
HashSet<Document*> documentsToChange;
for (NodeIdToForcedPseudoState::iterator it = m_nodeIdToForcedPseudoState.begin(), end = m_nodeIdToForcedPseudoState.end(); it != end; ++it) {
if (Element* element = toElement(m_domAgent->nodeForId(it->key)))
documentsToChange.add(&element->document());
}
m_nodeIdToForcedPseudoState.clear();
for (HashSet<Document*>::iterator it = documentsToChange.begin(), end = documentsToChange.end(); it != end; ++it)
(*it)->styleResolverChanged(RecalcStyleImmediately);
}
} // namespace WebCore
#endif // ENABLE(INSPECTOR)