1/*
2 * Copyright (C) 2010, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1.  Redistributions of source code must retain the above copyright
8 *     notice, this list of conditions and the following disclaimer.
9 * 2.  Redistributions in binary form must reproduce the above copyright
10 *     notice, this list of conditions and the following disclaimer in the
11 *     documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "config.h"
26#include "InspectorCSSAgent.h"
27
28#if ENABLE(INSPECTOR)
29
30#include "CSSComputedStyleDeclaration.h"
31#include "CSSMutableStyleDeclaration.h"
32#include "CSSPropertyNames.h"
33#include "CSSPropertySourceData.h"
34#include "CSSRule.h"
35#include "CSSRuleList.h"
36#include "CSSStyleRule.h"
37#include "CSSStyleSelector.h"
38#include "CSSStyleSheet.h"
39#include "DOMWindow.h"
40#include "HTMLHeadElement.h"
41#include "InspectorDOMAgent.h"
42#include "InspectorValues.h"
43#include "InstrumentingAgents.h"
44#include "Node.h"
45#include "NodeList.h"
46#include "StyleSheetList.h"
47
48#include <wtf/HashSet.h>
49#include <wtf/Vector.h>
50#include <wtf/text/CString.h>
51
52// Currently implemented model:
53//
54// cssProperty = {
55//    name          : <string>,
56//    value         : <string>,
57//    priority      : <string>, // "" for non-parsedOk properties
58//    implicit      : <boolean>,
59//    parsedOk      : <boolean>, // whether property is understood by WebCore
60//    status        : <string>, // "disabled" | "active" | "inactive" | "style"
61//    shorthandName : <string>,
62//    startOffset   : <number>, // Optional - property text start offset in enclosing style declaration. Absent for computed styles and such.
63//    endOffset     : <number>, // Optional - property text end offset in enclosing style declaration. Absent for computed styles and such.
64// }
65//
66// name + value + priority : present when the property is enabled
67// text                    : present when the property is disabled
68//
69// For disabled properties, startOffset === endOffset === insertion point for the property.
70//
71// status:
72// "disabled" == property disabled by user
73// "active" == property participates in the computed style calculation
74// "inactive" == property does no participate in the computed style calculation (i.e. overridden by a subsequent property with the same name)
75// "style" == property is active and originates from the WebCore CSSStyleDeclaration rather than CSS source code (e.g. implicit longhand properties)
76//
77// cssStyle = {
78//    styleId            : <string>, // Optional
79//    cssProperties      : [
80//                          #cssProperty,
81//                          ...
82//                          #cssProperty
83//                         ],
84//    shorthandEntries   : [
85//                          #shorthandEntry,
86//                          ...
87//                          #shorthandEntry
88//                         ],
89//    cssText            : <string>, // Optional - declaration text
90//    properties         : {
91//                          width,
92//                          height,
93//                          startOffset, // Optional - for source-based styles only
94//                          endOffset, // Optional - for source-based styles only
95//                         }
96// }
97//
98// shorthandEntry = {
99//    name: <string>,
100//    value: <string>
101// }
102//
103// cssRule = {
104//    ruleId       : <string>, // Optional
105//    selectorText : <string>,
106//    sourceURL    : <string>,
107//    sourceLine   : <string>,
108//    origin       : <string>, // "" || "user-agent" || "user" || "inspector"
109//    style        : #cssStyle,
110//    selectorRange: { start: <number>, end: <number> } // Optional - for source-based rules only
111// }
112//
113// cssStyleSheetInfo = {
114//    styleSheetId : <number>
115//    sourceURL    : <string>
116//    title        : <string>
117//    disabled     : <boolean>
118// }
119//
120// cssStyleSheet = {
121//    styleSheetId : <number>
122//    rules        : [
123//                       #cssRule,
124//                       ...
125//                       #cssRule
126//                   ]
127//    text         : <string> // Optional - whenever the text is available for a text-based stylesheet
128// }
129
130namespace WebCore {
131
132// static
133CSSStyleSheet* InspectorCSSAgent::parentStyleSheet(StyleBase* styleBase)
134{
135    if (!styleBase)
136        return 0;
137
138    StyleSheet* styleSheet = styleBase->stylesheet();
139    if (styleSheet && styleSheet->isCSSStyleSheet())
140        return static_cast<CSSStyleSheet*>(styleSheet);
141
142    return 0;
143}
144
145// static
146CSSStyleRule* InspectorCSSAgent::asCSSStyleRule(StyleBase* styleBase)
147{
148    if (!styleBase->isStyleRule())
149        return 0;
150    CSSRule* rule = static_cast<CSSRule*>(styleBase);
151    if (rule->type() != CSSRule::STYLE_RULE)
152        return 0;
153    return static_cast<CSSStyleRule*>(rule);
154}
155
156InspectorCSSAgent::InspectorCSSAgent(InstrumentingAgents* instrumentingAgents, InspectorDOMAgent* domAgent)
157    : m_instrumentingAgents(instrumentingAgents)
158    , m_domAgent(domAgent)
159    , m_lastStyleSheetId(1)
160    , m_lastRuleId(1)
161    , m_lastStyleId(1)
162{
163    m_domAgent->setDOMListener(this);
164    m_instrumentingAgents->setInspectorCSSAgent(this);
165}
166
167InspectorCSSAgent::~InspectorCSSAgent()
168{
169    m_instrumentingAgents->setInspectorCSSAgent(0);
170    // DOM agent should be destroyed after CSS agent.
171    m_domAgent->setDOMListener(0);
172    m_domAgent = 0;
173    reset();
174}
175
176void InspectorCSSAgent::reset()
177{
178    m_idToInspectorStyleSheet.clear();
179    m_cssStyleSheetToInspectorStyleSheet.clear();
180    m_nodeToInspectorStyleSheet.clear();
181    m_documentToInspectorStyleSheet.clear();
182}
183
184void InspectorCSSAgent::getStylesForNode(ErrorString* errorString, int nodeId, RefPtr<InspectorObject>* result)
185{
186    Element* element = elementForId(errorString, nodeId);
187    if (!element)
188        return;
189
190    RefPtr<InspectorObject> resultObject = InspectorObject::create();
191
192    InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
193    if (styleSheet)
194        resultObject->setObject("inlineStyle", styleSheet->buildObjectForStyle(element->style()));
195
196    RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = computedStyle(element, true); // Support the viewing of :visited information in computed style.
197    RefPtr<InspectorStyle> computedInspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
198    resultObject->setObject("computedStyle", computedInspectorStyle->buildObjectForStyle());
199
200    CSSStyleSelector* selector = element->ownerDocument()->styleSelector();
201    RefPtr<CSSRuleList> matchedRules = selector->styleRulesForElement(element, false, true);
202    resultObject->setArray("matchedCSSRules", buildArrayForRuleList(matchedRules.get()));
203
204    resultObject->setArray("styleAttributes", buildArrayForAttributeStyles(element));
205
206    RefPtr<InspectorArray> pseudoElements = InspectorArray::create();
207    for (PseudoId pseudoId = FIRST_PUBLIC_PSEUDOID; pseudoId < AFTER_LAST_INTERNAL_PSEUDOID; pseudoId = static_cast<PseudoId>(pseudoId + 1)) {
208        RefPtr<CSSRuleList> matchedRules = selector->pseudoStyleRulesForElement(element, pseudoId, false, true);
209        if (matchedRules && matchedRules->length()) {
210            RefPtr<InspectorObject> pseudoStyles = InspectorObject::create();
211            pseudoStyles->setNumber("pseudoId", static_cast<int>(pseudoId));
212            pseudoStyles->setArray("rules", buildArrayForRuleList(matchedRules.get()));
213            pseudoElements->pushObject(pseudoStyles.release());
214        }
215    }
216    resultObject->setArray("pseudoElements", pseudoElements.release());
217
218    RefPtr<InspectorArray> inheritedStyles = InspectorArray::create();
219    Element* parentElement = element->parentElement();
220    while (parentElement) {
221        RefPtr<InspectorObject> parentStyle = InspectorObject::create();
222        if (parentElement->style() && parentElement->style()->length()) {
223            InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement);
224            if (styleSheet)
225                parentStyle->setObject("inlineStyle", styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0))));
226        }
227
228        CSSStyleSelector* parentSelector = parentElement->ownerDocument()->styleSelector();
229        RefPtr<CSSRuleList> parentMatchedRules = parentSelector->styleRulesForElement(parentElement, false, true);
230        parentStyle->setArray("matchedCSSRules", buildArrayForRuleList(parentMatchedRules.get()));
231        inheritedStyles->pushObject(parentStyle.release());
232        parentElement = parentElement->parentElement();
233    }
234    resultObject->setArray("inherited", inheritedStyles.release());
235
236    *result = resultObject.release();
237}
238
239void InspectorCSSAgent::getInlineStyleForNode(ErrorString* errorString, int nodeId, RefPtr<InspectorObject>* style)
240{
241    Element* element = elementForId(errorString, nodeId);
242    if (!element)
243        return;
244
245    InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(element);
246    if (!styleSheet)
247        return;
248
249    *style = styleSheet->buildObjectForStyle(element->style());
250}
251
252void InspectorCSSAgent::getComputedStyleForNode(ErrorString* errorString, int nodeId, RefPtr<InspectorObject>* style)
253{
254    Element* element = elementForId(errorString, nodeId);
255    if (!element)
256        return;
257
258    RefPtr<CSSComputedStyleDeclaration> computedStyleInfo = computedStyle(element, true);
259    RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), computedStyleInfo, 0);
260    *style = inspectorStyle->buildObjectForStyle();
261}
262
263void InspectorCSSAgent::getAllStyleSheets(ErrorString*, RefPtr<InspectorArray>* styleInfos)
264{
265    Vector<Document*> documents = m_domAgent->documents();
266    for (Vector<Document*>::iterator it = documents.begin(); it != documents.end(); ++it) {
267        StyleSheetList* list = (*it)->styleSheets();
268        for (unsigned i = 0; i < list->length(); ++i) {
269            StyleSheet* styleSheet = list->item(i);
270            if (styleSheet->isCSSStyleSheet()) {
271                InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(static_cast<CSSStyleSheet*>(styleSheet));
272                (*styleInfos)->pushObject(inspectorStyleSheet->buildObjectForStyleSheetInfo());
273            }
274        }
275    }
276}
277
278void InspectorCSSAgent::getStyleSheet(ErrorString* errorString, const String& styleSheetId, RefPtr<InspectorObject>* styleSheetObject)
279{
280    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
281    if (!inspectorStyleSheet)
282        return;
283
284    *styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet();
285}
286
287void InspectorCSSAgent::getStyleSheetText(ErrorString* errorString, const String& styleSheetId, String* result)
288{
289    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
290    if (!inspectorStyleSheet)
291        return;
292
293    inspectorStyleSheet->text(result);
294}
295
296void InspectorCSSAgent::setStyleSheetText(ErrorString* errorString, const String& styleSheetId, const String& text)
297{
298    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, styleSheetId);
299    if (!inspectorStyleSheet)
300        return;
301
302    if (inspectorStyleSheet->setText(text))
303        inspectorStyleSheet->reparseStyleSheet(text);
304    else
305        *errorString = "Internal error setting style sheet text";
306}
307
308void InspectorCSSAgent::setPropertyText(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, const String& text, bool overwrite, RefPtr<InspectorObject>* result)
309{
310    InspectorCSSId compoundId(fullStyleId);
311    ASSERT(!compoundId.isEmpty());
312
313    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
314    if (!inspectorStyleSheet)
315        return;
316
317    bool success = inspectorStyleSheet->setPropertyText(errorString, compoundId, propertyIndex, text, overwrite);
318    if (success)
319        *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
320}
321
322void InspectorCSSAgent::toggleProperty(ErrorString* errorString, const RefPtr<InspectorObject>& fullStyleId, int propertyIndex, bool disable, RefPtr<InspectorObject>* result)
323{
324    InspectorCSSId compoundId(fullStyleId);
325    ASSERT(!compoundId.isEmpty());
326
327    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
328    if (!inspectorStyleSheet)
329        return;
330
331    bool success = inspectorStyleSheet->toggleProperty(errorString, compoundId, propertyIndex, disable);
332    if (success)
333        *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId));
334}
335
336void InspectorCSSAgent::setRuleSelector(ErrorString* errorString, const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<InspectorObject>* result)
337{
338    InspectorCSSId compoundId(fullRuleId);
339    ASSERT(!compoundId.isEmpty());
340
341    InspectorStyleSheet* inspectorStyleSheet = assertStyleSheetForId(errorString, compoundId.styleSheetId());
342    if (!inspectorStyleSheet)
343        return;
344
345    bool success = inspectorStyleSheet->setRuleSelector(compoundId, selector);
346    if (!success)
347        return;
348
349    *result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
350}
351
352void InspectorCSSAgent::addRule(ErrorString*, const int contextNodeId, const String& selector, RefPtr<InspectorObject>* result)
353{
354    Node* node = m_domAgent->nodeForId(contextNodeId);
355    if (!node)
356        return;
357
358    InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true);
359    if (!inspectorStyleSheet)
360        return;
361    CSSStyleRule* newRule = inspectorStyleSheet->addRule(selector);
362    if (!newRule)
363        return;
364
365    *result = inspectorStyleSheet->buildObjectForRule(newRule);
366}
367
368void InspectorCSSAgent::getSupportedCSSProperties(ErrorString*, RefPtr<InspectorArray>* cssProperties)
369{
370    RefPtr<InspectorArray> properties = InspectorArray::create();
371    for (int i = 0; i < numCSSProperties; ++i)
372        properties->pushString(propertyNameStrings[i]);
373
374    *cssProperties = properties.release();
375}
376
377// static
378Element* InspectorCSSAgent::inlineStyleElement(CSSStyleDeclaration* style)
379{
380    if (!style || !style->isMutableStyleDeclaration())
381        return 0;
382    Node* node = static_cast<CSSMutableStyleDeclaration*>(style)->node();
383    if (!node || !node->isStyledElement() || static_cast<StyledElement*>(node)->getInlineStyleDecl() != style)
384        return 0;
385    return static_cast<Element*>(node);
386}
387
388InspectorStyleSheetForInlineStyle* InspectorCSSAgent::asInspectorStyleSheet(Element* element)
389{
390    NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
391    if (it == m_nodeToInspectorStyleSheet.end()) {
392        CSSStyleDeclaration* style = element->isStyledElement() ? element->style() : 0;
393        if (!style)
394            return 0;
395
396        String newStyleSheetId = String::number(m_lastStyleSheetId++);
397        RefPtr<InspectorStyleSheetForInlineStyle> inspectorStyleSheet = InspectorStyleSheetForInlineStyle::create(newStyleSheetId, element, "");
398        m_idToInspectorStyleSheet.set(newStyleSheetId, inspectorStyleSheet);
399        m_nodeToInspectorStyleSheet.set(element, inspectorStyleSheet);
400        return inspectorStyleSheet.get();
401    }
402
403    return it->second.get();
404}
405
406Element* InspectorCSSAgent::elementForId(ErrorString* errorString, int nodeId)
407{
408    Node* node = m_domAgent->nodeForId(nodeId);
409    if (!node) {
410        *errorString = "No node with given id found";
411        return 0;
412    }
413    if (node->nodeType() != Node::ELEMENT_NODE) {
414        *errorString = "Not an element node";
415        return 0;
416    }
417    return static_cast<Element*>(node);
418}
419
420InspectorStyleSheet* InspectorCSSAgent::bindStyleSheet(CSSStyleSheet* styleSheet)
421{
422    RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_cssStyleSheetToInspectorStyleSheet.get(styleSheet);
423    if (!inspectorStyleSheet) {
424        String id = String::number(m_lastStyleSheetId++);
425        inspectorStyleSheet = InspectorStyleSheet::create(id, styleSheet, detectOrigin(styleSheet, styleSheet->document()), m_domAgent->documentURLString(styleSheet->document()));
426        m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
427        m_cssStyleSheetToInspectorStyleSheet.set(styleSheet, inspectorStyleSheet);
428    }
429    return inspectorStyleSheet.get();
430}
431
432InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* document, bool createIfAbsent)
433{
434    if (!document) {
435        ASSERT(!createIfAbsent);
436        return 0;
437    }
438
439    RefPtr<InspectorStyleSheet> inspectorStyleSheet = m_documentToInspectorStyleSheet.get(document);
440    if (inspectorStyleSheet || !createIfAbsent)
441        return inspectorStyleSheet.get();
442
443    ExceptionCode ec = 0;
444    RefPtr<Element> styleElement = document->createElement("style", ec);
445    if (!ec)
446        styleElement->setAttribute("type", "text/css", ec);
447    if (!ec) {
448        ContainerNode* targetNode;
449        // HEAD is absent in ImageDocuments, for example.
450        if (document->head())
451            targetNode = document->head();
452        else if (document->body())
453            targetNode = document->body();
454        else
455            return 0;
456        targetNode->appendChild(styleElement, ec);
457    }
458    if (ec)
459        return 0;
460    StyleSheetList* styleSheets = document->styleSheets();
461    StyleSheet* styleSheet = styleSheets->item(styleSheets->length() - 1);
462    if (!styleSheet->isCSSStyleSheet())
463        return 0;
464    CSSStyleSheet* cssStyleSheet = static_cast<CSSStyleSheet*>(styleSheet);
465    String id = String::number(m_lastStyleSheetId++);
466    inspectorStyleSheet = InspectorStyleSheet::create(id, cssStyleSheet, "inspector", m_domAgent->documentURLString(document));
467    m_idToInspectorStyleSheet.set(id, inspectorStyleSheet);
468    m_cssStyleSheetToInspectorStyleSheet.set(cssStyleSheet, inspectorStyleSheet);
469    m_documentToInspectorStyleSheet.set(document, inspectorStyleSheet);
470    return inspectorStyleSheet.get();
471}
472
473InspectorStyleSheet* InspectorCSSAgent::assertStyleSheetForId(ErrorString* errorString, const String& styleSheetId)
474{
475    IdToInspectorStyleSheet::iterator it = m_idToInspectorStyleSheet.find(styleSheetId);
476    if (it == m_idToInspectorStyleSheet.end()) {
477        *errorString = "No style sheet with given id found";
478        return 0;
479    }
480    return it->second.get();
481}
482
483String InspectorCSSAgent::detectOrigin(CSSStyleSheet* pageStyleSheet, Document* ownerDocument)
484{
485    DEFINE_STATIC_LOCAL(String, userAgent, ("user-agent"));
486    DEFINE_STATIC_LOCAL(String, user, ("user"));
487    DEFINE_STATIC_LOCAL(String, inspector, ("inspector"));
488
489    String origin("");
490    if (pageStyleSheet && !pageStyleSheet->ownerNode() && pageStyleSheet->href().isEmpty())
491        origin = userAgent;
492    else if (pageStyleSheet && pageStyleSheet->ownerNode() && pageStyleSheet->ownerNode()->nodeName() == "#document")
493        origin = user;
494    else {
495        InspectorStyleSheet* viaInspectorStyleSheetForOwner = viaInspectorStyleSheet(ownerDocument, false);
496        if (viaInspectorStyleSheetForOwner && pageStyleSheet == viaInspectorStyleSheetForOwner->pageStyleSheet())
497            origin = inspector;
498    }
499    return origin;
500}
501
502PassRefPtr<InspectorArray> InspectorCSSAgent::buildArrayForRuleList(CSSRuleList* ruleList)
503{
504    RefPtr<InspectorArray> result = InspectorArray::create();
505    if (!ruleList)
506        return result.release();
507
508    for (unsigned i = 0, size = ruleList->length(); i < size; ++i) {
509        CSSStyleRule* rule = asCSSStyleRule(ruleList->item(i));
510        if (!rule)
511            continue;
512
513        InspectorStyleSheet* styleSheet = bindStyleSheet(parentStyleSheet(rule));
514        if (styleSheet)
515            result->pushObject(styleSheet->buildObjectForRule(rule));
516    }
517    return result.release();
518}
519
520PassRefPtr<InspectorArray> InspectorCSSAgent::buildArrayForAttributeStyles(Element* element)
521{
522    RefPtr<InspectorArray> attrStyles = InspectorArray::create();
523    NamedNodeMap* attributes = element->attributes();
524    for (unsigned i = 0; attributes && i < attributes->length(); ++i) {
525        Attribute* attribute = attributes->attributeItem(i);
526        if (attribute->style()) {
527            RefPtr<InspectorObject> attrStyleObject = InspectorObject::create();
528            String attributeName = attribute->localName();
529            RefPtr<InspectorStyle> inspectorStyle = InspectorStyle::create(InspectorCSSId(), attribute->style(), 0);
530            attrStyleObject->setString("name", attributeName.utf8().data());
531            attrStyleObject->setObject("style", inspectorStyle->buildObjectForStyle());
532            attrStyles->pushObject(attrStyleObject.release());
533        }
534    }
535
536    return attrStyles.release();
537}
538
539void InspectorCSSAgent::didRemoveDocument(Document* document)
540{
541    if (document)
542        m_documentToInspectorStyleSheet.remove(document);
543}
544
545void InspectorCSSAgent::didRemoveDOMNode(Node* node)
546{
547    if (!node)
548        return;
549
550    NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(node);
551    if (it == m_nodeToInspectorStyleSheet.end())
552        return;
553
554    m_idToInspectorStyleSheet.remove(it->second->id());
555    m_nodeToInspectorStyleSheet.remove(node);
556}
557
558void InspectorCSSAgent::didModifyDOMAttr(Element* element)
559{
560    if (!element)
561        return;
562
563    NodeToInspectorStyleSheet::iterator it = m_nodeToInspectorStyleSheet.find(element);
564    if (it == m_nodeToInspectorStyleSheet.end())
565        return;
566
567    it->second->didModifyElementAttribute();
568}
569
570} // namespace WebCore
571
572#endif // ENABLE(INSPECTOR)
573