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