JavaScriptCore:
[WebKit-https.git] / WebCore / page / InspectorController.cpp
1 /*
2  * Copyright (C) 2007 Apple 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "InspectorController.h"
31
32 #include "CString.h"
33 #include "CachedResource.h"
34 #include "DocLoader.h"
35 #include "Document.h"
36 #include "DocumentLoader.h"
37 #include "Element.h"
38 #include "FloatRect.h"
39 #include "Frame.h"
40 #include "FrameLoader.h"
41 #include "FrameTree.h"
42 #include "HTMLFrameOwnerElement.h"
43 #include "InspectorClient.h"
44 #include "JSRange.h"
45 #include "Page.h"
46 #include "Range.h"
47 #include "ResourceError.h"
48 #include "ResourceRequest.h"
49 #include "ResourceResponse.h"
50 #include "Shared.h"
51 #include "SharedBuffer.h"
52 #include "SystemTime.h"
53 #include "TextEncoding.h"
54 #include "TextIterator.h"
55 #include "kjs_dom.h"
56 #include "kjs_proxy.h"
57 #include "kjs_window.h"
58
59 #include <JavaScriptCore/APICast.h>
60 #include <JavaScriptCore/JSLock.h>
61
62 namespace WebCore {
63
64 struct ConsoleMessage {
65     ConsoleMessage(MessageSource s, MessageLevel l, const String& m, unsigned li, const String& u)
66         : source(s)
67         , level(l)
68         , message(m)
69         , line(li)
70         , url(u)
71     {
72     }
73
74     MessageSource source;
75     MessageLevel level;
76     String message;
77     unsigned line;
78     String url;
79 };
80
81 struct InspectorResource : public Shared<InspectorResource> {
82     // Keep these in sync with WebInspector.Resource.Type
83     enum Type {
84         Doc,
85         Stylesheet,
86         Image,
87         Script,
88         Other
89     };
90
91     InspectorResource(long long identifier, DocumentLoader* documentLoader, Frame* frame)
92         : identifier(identifier)
93         , loader(documentLoader)
94         , frame(frame)
95         , scriptContext(0)
96         , scriptObject(0)
97         , cached(false)
98         , finished(false)
99         , failed(false)
100         , length(0)
101         , startTime(-1.0)
102         , responseReceivedTime(-1.0)
103         , endTime(-1.0)
104     {
105     }
106
107     ~InspectorResource()
108     {
109         setScriptObject(0, 0);
110     }
111
112     Type type() const
113     {
114         if (request.isNull() || response.isNull())
115             return Other;
116
117         if (request.url() == loader->requestURL())
118             return Doc;
119
120         FrameLoader* frameLoader = loader->frameLoader();
121         if (!frameLoader)
122             return Other;
123
124         if (request.url() == frameLoader->iconURL())
125             return Image;
126
127         Document* doc = frameLoader->frame()->document();
128         if (!doc)
129             return Other;
130
131         CachedResource* cachedResource = doc->docLoader()->cachedResource(request.url().url());
132         if (!cachedResource)
133             return Other;
134
135         switch (cachedResource->type()) {
136             case CachedResource::ImageResource:
137                 return Image;
138             case CachedResource::CSSStyleSheet:
139 #if ENABLE(XSLT)
140             case CachedResource::XSLStyleSheet:
141 #endif
142                 return Stylesheet;
143             case CachedResource::Script:
144                 return Script;
145             default:
146                 return Other;
147         }
148     }
149
150     void setScriptObject(JSContextRef context, JSObjectRef newScriptObject)
151     {
152         if (scriptContext && scriptObject)
153             JSValueUnprotect(scriptContext, scriptObject);
154
155         scriptObject = newScriptObject;
156         scriptContext = context;
157
158         ASSERT((context && newScriptObject) || (!context && !newScriptObject));
159         if (context && newScriptObject)
160             JSValueProtect(context, newScriptObject);
161     }
162
163     long long identifier;
164     RefPtr<DocumentLoader> loader;
165     RefPtr<Frame> frame;
166     ResourceRequest request;
167     ResourceResponse response;
168     ResourceResponse redirectResponse;
169     ResourceError error;
170     JSContextRef scriptContext;
171     JSObjectRef scriptObject;
172     bool cached;
173     bool finished;
174     bool failed;
175     int length;
176     double startTime;
177     double responseReceivedTime;
178     double endTime;
179 };
180
181 static JSValueRef addSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
182 {
183     JSValueRef undefined = JSValueMakeUndefined(ctx);
184
185     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
186     if (argumentCount < 2 || !controller)
187         return undefined;
188
189     JSValueRef identifierValue = arguments[0];
190     if (!JSValueIsNumber(ctx, identifierValue))
191         return undefined;
192
193     unsigned long identifier = static_cast<unsigned long>(JSValueToNumber(ctx, identifierValue, 0));
194     RefPtr<InspectorResource> resource = controller->resources().get(identifier);
195     ASSERT(resource);
196     if (!resource)
197         return undefined;
198
199     RefPtr<SharedBuffer> buffer;
200     if (resource->request.url() == resource->loader->requestURL())
201         buffer = resource->loader->mainResourceData();
202     else {
203         FrameLoader* frameLoader = resource->loader->frameLoader();
204         if (!frameLoader)
205             return undefined;
206
207         Document* doc = frameLoader->frame()->document();
208         if (!doc)
209             return undefined;
210
211         CachedResource* cachedResource = doc->docLoader()->cachedResource(resource->request.url().url());
212         if (!cachedResource)
213             return undefined;
214
215         buffer = cachedResource->data();
216     }
217
218     if (!buffer)
219         return undefined;
220
221     String textEncodingName = resource->loader->overrideEncoding();
222     if (!textEncodingName)
223         textEncodingName = resource->response.textEncodingName();
224
225     TextEncoding encoding(textEncodingName);
226     if (!encoding.isValid())
227         encoding = WindowsLatin1Encoding();
228     String sourceString = encoding.decode(buffer->data(), buffer->size());
229
230     Node* node = toNode(toJS(arguments[1]));
231     ASSERT(node);
232     if (!node)
233         return undefined;
234
235     if (!node->attached()) {
236         ASSERT_NOT_REACHED();
237         return undefined;
238     }
239
240     ASSERT(node->isElementNode());
241     if (!node->isElementNode())
242         return undefined;
243
244     Element* element = static_cast<Element*>(node);
245     ASSERT(element->isFrameOwnerElement());
246     if (!element->isFrameOwnerElement())
247         return undefined;
248
249     HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element);
250     ASSERT(frameOwner->contentFrame());
251     if (!frameOwner->contentFrame())
252         return undefined;
253
254     FrameLoader* loader = frameOwner->contentFrame()->loader();
255
256     loader->setResponseMIMEType(resource->response.mimeType());
257     loader->begin();
258     loader->write(sourceString);
259     loader->end();
260
261     return undefined;
262 }
263
264 static JSValueRef getResourceDocumentNode(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
265 {
266     JSValueRef undefined = JSValueMakeUndefined(ctx);
267
268     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
269     if (!argumentCount || argumentCount > 1 || !controller)
270         return undefined;
271
272     JSValueRef identifierValue = arguments[0];
273     if (!JSValueIsNumber(ctx, identifierValue))
274         return undefined;
275
276     unsigned long identifier = static_cast<unsigned long>(JSValueToNumber(ctx, identifierValue, 0));
277     RefPtr<InspectorResource> resource = controller->resources().get(identifier);
278     ASSERT(resource);
279     if (!resource)
280         return undefined;
281
282     FrameLoader* frameLoader = resource->loader->frameLoader();
283     if (!frameLoader)
284         return undefined;
285
286     Document* document = frameLoader->frame()->document();
287     if (!document)
288         return undefined;
289
290     if (document->isPluginDocument() || document->isImageDocument())
291         return undefined;
292
293     KJS::JSLock lock;
294     JSValueRef documentValue = toRef(toJS(toJS(controller->scriptContext()), document));
295     return documentValue;
296 }
297
298 static JSValueRef highlightDOMNode(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
299 {
300     JSValueRef undefined = JSValueMakeUndefined(context);
301
302     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
303     if (argumentCount < 1 || !controller)
304         return undefined;
305
306     Node* node = toNode(toJS(arguments[0]));
307     if (!node)
308         return undefined;
309
310     controller->highlight(node);
311
312     return undefined;
313 }
314
315 static JSValueRef hideDOMNodeHighlight(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
316 {
317     JSValueRef undefined = JSValueMakeUndefined(context);
318
319     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
320     if (argumentCount || !controller)
321         return undefined;
322
323     controller->hideHighlight();
324
325     return undefined;
326 }
327
328 static JSValueRef loaded(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
329 {
330     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
331     if (!controller)
332         return JSValueMakeUndefined(ctx);
333
334     controller->scriptObjectReady();
335     return JSValueMakeUndefined(ctx);
336 }
337
338 static JSValueRef unloading(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
339 {
340     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
341     if (!controller)
342         return JSValueMakeUndefined(ctx);
343
344     controller->windowUnloading();
345     return JSValueMakeUndefined(ctx);
346 }
347
348 static JSValueRef attach(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
349 {
350     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
351     if (!controller)
352         return JSValueMakeUndefined(ctx);
353
354     controller->attachWindow();
355     return JSValueMakeUndefined(ctx);
356 }
357
358 static JSValueRef detach(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
359 {
360     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
361     if (!controller)
362         return JSValueMakeUndefined(ctx);
363
364     controller->detachWindow();
365     return JSValueMakeUndefined(ctx);
366 }
367
368 static JSValueRef log(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef /*thisObject*/, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
369 {
370     if (argumentCount < 1 || !JSValueIsString(ctx, arguments[0]))
371         return JSValueMakeUndefined(ctx);
372
373 #ifndef NDEBUG
374     JSStringRef string = JSValueToStringCopy(ctx, arguments[0], 0);
375     String message(JSStringGetCharactersPtr(string), JSStringGetLength(string));
376     JSStringRelease(string);
377
378     fprintf(stderr, "%s\n", message.latin1().data());
379 #endif
380
381     return JSValueMakeUndefined(ctx);
382 }
383
384 static JSValueRef search(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
385 {
386     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
387     if (!controller)
388         return JSValueMakeUndefined(ctx);
389
390     if (argumentCount < 2 || !JSValueIsString(ctx, arguments[1]))
391         return JSValueMakeUndefined(ctx);
392
393     Node* node = toNode(toJS(arguments[0]));
394     if (!node)
395         return JSValueMakeUndefined(ctx);
396
397     JSStringRef string = JSValueToStringCopy(ctx, arguments[1], 0);
398     String target(JSStringGetCharactersPtr(string), JSStringGetLength(string));
399     JSStringRelease(string);
400
401     JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
402     JSStringRef constructorString = JSStringCreateWithUTF8CString("Array");
403     JSObjectRef arrayConstructor = JSValueToObject(ctx, JSObjectGetProperty(ctx, globalObject, constructorString, 0), 0);
404     JSStringRelease(constructorString);
405     JSObjectRef array = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, 0);
406
407     JSStringRef pushString = JSStringCreateWithUTF8CString("push");
408     JSValueRef pushValue = JSObjectGetProperty(ctx, array, pushString, 0);
409     JSStringRelease(pushString);
410     JSObjectRef push = JSValueToObject(ctx, pushValue, 0);
411
412     RefPtr<Range> searchRange(rangeOfContents(node));
413
414     int exception = 0;
415     do {
416         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false));
417         if (resultRange->collapsed(exception))
418             break;
419
420         // A non-collapsed result range can in some funky whitespace cases still not
421         // advance the range's start position (4509328). Break to avoid infinite loop.
422         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
423         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
424             break;
425
426         KJS::JSLock lock;
427         JSValueRef arg0 = toRef(toJS(toJS(ctx), resultRange.get()));
428         JSObjectCallAsFunction(ctx, push, array, 1, &arg0, 0);
429
430         setStart(searchRange.get(), newStart);
431     } while (true);
432
433     return array;
434 }
435
436 static JSValueRef inspectedWindow(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
437 {
438     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
439     if (!controller)
440         return JSValueMakeUndefined(ctx);
441
442     return toRef(KJS::Window::retrieve(controller->inspectedPage()->mainFrame()));
443 }
444
445 InspectorController::InspectorController(Page* page, InspectorClient* client)
446     : m_inspectedPage(page)
447     , m_client(client)
448     , m_page(0)
449     , m_scriptObject(0)
450     , m_controllerScriptObject(0)
451     , m_scriptContext(0)
452     , m_windowVisible(false)
453     , m_nextIdentifier(-2)
454 {
455     ASSERT_ARG(page, page);
456     ASSERT_ARG(client, client);
457 }
458
459 InspectorController::~InspectorController()
460 {
461     if (m_scriptContext) {
462         JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
463         JSStringRef controllerProperty = JSStringCreateWithUTF8CString("InspectorController");
464         JSObjectRef controller = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, global, controllerProperty, 0), 0);
465         JSStringRelease(controllerProperty);
466         JSObjectSetPrivate(controller, 0);
467     }
468
469     m_client->closeWindow();
470     m_client->inspectorDestroyed();
471
472     if (m_page)
473         m_page->setParentInspectorController(0);
474
475     deleteAllValues(m_frameResources);
476     deleteAllValues(m_consoleMessages);
477 }
478
479 void InspectorController::inspect(Node* node)
480 {
481     if (!node)
482         return;
483
484     if (!m_page) {
485         m_page = m_client->createPage();
486         if (!m_page)
487             return;
488
489         m_page->setParentInspectorController(this);
490     }
491
492     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
493         node = node->parentNode();
494     m_nodeToFocus = node;
495
496     if (!m_scriptObject)
497         return;
498
499     if (windowVisible())
500         focusNode();
501     else
502         m_client->showWindow();
503 }
504
505 void InspectorController::focusNode()
506 {
507     ASSERT(m_scriptContext);
508     ASSERT(m_scriptObject);
509     ASSERT(m_nodeToFocus);
510
511     JSValueRef arg0;
512
513     {
514         KJS::JSLock lock;
515         arg0 = toRef(toJS(toJS(m_scriptContext), m_nodeToFocus.get()));
516     }
517
518     m_nodeToFocus = 0;
519
520     JSStringRef functionProperty = JSStringCreateWithUTF8CString("updateFocusedNode");
521     JSObjectRef function = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, functionProperty, 0), 0);
522     JSStringRelease(functionProperty);
523     ASSERT(function);
524
525     JSObjectCallAsFunction(m_scriptContext, function, m_scriptObject, 1, &arg0, 0);
526 }
527
528 void InspectorController::highlight(Node* node)
529 {
530     ASSERT_ARG(node, node);
531
532     m_client->highlight(node);
533 }
534
535 void InspectorController::hideHighlight()
536 {
537     m_client->hideHighlight();
538 }
539
540 bool InspectorController::windowVisible()
541 {
542     return m_windowVisible;
543 }
544
545 void InspectorController::setWindowVisible(bool visible)
546 {
547     if (visible == m_windowVisible)
548         return;
549
550     m_windowVisible = visible;
551
552     if (!m_scriptContext || !m_scriptObject)
553         return;
554
555     if (m_windowVisible) {
556         populateScriptResources();
557         if (m_nodeToFocus)
558             focusNode();
559     } else {
560         clearScriptResources();
561         clearScriptConsoleMessages();
562         clearNetworkTimeline();
563     }
564 }
565
566 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
567 {
568     ConsoleMessage* consoleMessage = new ConsoleMessage(source, level, message, lineNumber, sourceID);
569     m_consoleMessages.append(consoleMessage);
570
571     if (windowVisible())
572         addScriptConsoleMessage(consoleMessage);
573 }
574
575 void InspectorController::attachWindow()
576 {
577     m_client->attachWindow();
578 }
579
580 void InspectorController::detachWindow()
581 {
582     m_client->detachWindow();
583 }
584
585 void InspectorController::windowScriptObjectAvailable()
586 {
587     ASSERT(m_page);
588
589     m_scriptContext = toRef(m_page->mainFrame()->scriptProxy()->interpreter()->globalExec());
590
591     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
592     ASSERT(global);
593
594     static JSStaticFunction staticFunctions[] = {
595         { "addSourceToFrame", addSourceToFrame, kJSPropertyAttributeNone },
596         { "getResourceDocumentNode", getResourceDocumentNode, kJSPropertyAttributeNone },
597         { "highlightDOMNode", highlightDOMNode, kJSPropertyAttributeNone },
598         { "hideDOMNodeHighlight", hideDOMNodeHighlight, kJSPropertyAttributeNone },
599         { "loaded", loaded, kJSPropertyAttributeNone },
600         { "windowUnloading", unloading, kJSPropertyAttributeNone },
601         { "attach", attach, kJSPropertyAttributeNone },
602         { "detach", detach, kJSPropertyAttributeNone },
603         { "log", log, kJSPropertyAttributeNone },
604         { "search", search, kJSPropertyAttributeNone },
605         { "inspectedWindow", inspectedWindow, kJSPropertyAttributeNone },
606         { 0, 0, 0 }
607     };
608
609     JSClassDefinition inspectorControllerDefinition = {
610         0, kJSClassAttributeNone, "InspectorController", 0, 0, staticFunctions,
611         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
612     };
613
614     JSClassRef controllerClass = JSClassCreate(&inspectorControllerDefinition);
615     ASSERT(controllerClass);
616
617     m_controllerScriptObject = JSObjectMake(m_scriptContext, controllerClass, reinterpret_cast<void*>(this));
618     ASSERT(m_controllerScriptObject);
619
620     JSStringRef controllerObjectString = JSStringCreateWithUTF8CString("InspectorController");
621     JSObjectSetProperty(m_scriptContext, global, controllerObjectString, m_controllerScriptObject, kJSPropertyAttributeNone, 0);
622     JSStringRelease(controllerObjectString);
623 }
624
625 void InspectorController::scriptObjectReady()
626 {
627     ASSERT(m_scriptContext);
628     if (!m_scriptContext)
629         return;
630
631     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
632     ASSERT(global);
633
634     JSStringRef inspectorString = JSStringCreateWithUTF8CString("WebInspector");
635     JSValueRef inspectorValue = JSObjectGetProperty(m_scriptContext, global, inspectorString, 0);
636     JSStringRelease(inspectorString);
637
638     ASSERT(inspectorValue);
639     if (!inspectorValue)
640         return;
641
642     m_scriptObject = JSValueToObject(m_scriptContext, inspectorValue, 0);
643     ASSERT(m_scriptObject);
644
645     JSValueProtect(m_scriptContext, m_scriptObject);
646
647     // Make sure our window is visible now that the page loaded
648     m_client->showWindow();
649 }
650
651 void InspectorController::windowUnloading()
652 {
653     m_client->closeWindow();
654     m_page->setParentInspectorController(0);
655
656     ASSERT(m_scriptContext && m_scriptObject);
657     JSValueUnprotect(m_scriptContext, m_scriptObject);
658
659     m_page = 0;
660     m_scriptObject = 0;
661     m_scriptContext = 0;
662 }
663
664 static void addHeaders(JSContextRef context, JSObjectRef object, const HTTPHeaderMap& headers)
665 {
666     ASSERT_ARG(context, context);
667     ASSERT_ARG(object, object);
668     
669     HTTPHeaderMap::const_iterator end = headers.end();
670     for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) {
671         JSStringRef field = JSStringCreateWithCharacters(it->first.characters(), it->first.length());
672         JSStringRef valueString = JSStringCreateWithCharacters(it->second.characters(), it->second.length());
673         JSValueRef value = JSValueMakeString(context, valueString);
674         JSObjectSetProperty(context, object, field, value, kJSPropertyAttributeNone, 0);
675         JSStringRelease(field);
676         JSStringRelease(valueString);
677     }
678 }
679
680 static JSObjectRef objectForRequest(JSContextRef context, const ResourceRequest& request)
681 {
682     ASSERT_ARG(context, context);
683     
684     JSObjectRef object = JSObjectMake(context, 0, 0);
685     addHeaders(context, object, request.httpHeaderFields());
686     
687     return object;
688 }
689
690 static JSObjectRef objectForResponse(JSContextRef context, const ResourceResponse& response)
691 {
692     ASSERT_ARG(context, context);
693     
694     JSObjectRef object = JSObjectMake(context, 0, 0);
695     addHeaders(context, object, response.httpHeaderFields());
696     
697     return object;
698 }
699
700 JSObjectRef InspectorController::addScriptResource(InspectorResource* resource)
701 {
702     ASSERT_ARG(resource, resource);
703     ASSERT(!resource->scriptObject);
704
705     ASSERT(m_scriptContext);
706     ASSERT(m_scriptObject);
707     if (!m_scriptContext || !m_scriptObject)
708         return 0;
709
710     JSStringRef resourceString = JSStringCreateWithUTF8CString("Resource");
711     JSObjectRef resourceConstructor = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, resourceString, 0), 0);
712     JSStringRelease(resourceString);
713
714     String urlString = resource->request.url().url();
715     JSStringRef url = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
716     JSValueRef urlValue = JSValueMakeString(m_scriptContext, url);
717     JSStringRelease(url);
718
719     urlString = resource->request.url().host();
720     JSStringRef domain = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
721     JSValueRef domainValue = JSValueMakeString(m_scriptContext, domain);
722     JSStringRelease(domain);
723
724     urlString = resource->request.url().path();
725     JSStringRef path = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
726     JSValueRef pathValue = JSValueMakeString(m_scriptContext, path);
727     JSStringRelease(path);
728
729     urlString = resource->request.url().lastPathComponent();
730     JSStringRef lastPathComponent = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
731     JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, lastPathComponent);
732     JSStringRelease(lastPathComponent);
733
734     JSValueRef identifier = JSValueMakeNumber(m_scriptContext, resource->identifier);
735     JSValueRef mainResource = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
736     JSValueRef cached = JSValueMakeBoolean(m_scriptContext, resource->cached);
737
738     JSValueRef arguments[] = { objectForRequest(m_scriptContext, resource->request), urlValue, domainValue, pathValue, lastPathComponentValue, identifier, mainResource, cached };
739     JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, resourceConstructor, 8, arguments, 0);
740
741     resource->setScriptObject(m_scriptContext, result);
742
743     ASSERT(result);
744
745     JSStringRef addResourceString = JSStringCreateWithUTF8CString("addResource");
746     JSObjectRef addResourceFunction = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, addResourceString, 0), 0);
747     JSStringRelease(addResourceString);
748
749     JSValueRef addArguments[] = { result };
750     JSObjectCallAsFunction(m_scriptContext, addResourceFunction, m_scriptObject, 1, addArguments, 0);
751
752     return result;
753 }
754
755 JSObjectRef InspectorController::addAndUpdateScriptResource(InspectorResource* resource)
756 {
757     ASSERT_ARG(resource, resource);
758
759     JSObjectRef scriptResource = addScriptResource(resource);
760     updateScriptResource(resource, resource->response);
761     updateScriptResource(resource, resource->length);
762     updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
763     updateScriptResource(resource, resource->finished, resource->failed);
764     return scriptResource;
765 }
766
767 void InspectorController::removeScriptResource(InspectorResource* resource)
768 {
769     ASSERT(m_scriptContext);
770     ASSERT(m_scriptObject);
771     if (!m_scriptContext || !m_scriptObject)
772         return;
773
774     ASSERT(resource);
775     ASSERT(resource->scriptObject);
776     if (!resource || !resource->scriptObject)
777         return;
778
779     JSStringRef removeResourceString = JSStringCreateWithUTF8CString("removeResource");
780     JSObjectRef removeResourceFunction = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, removeResourceString, 0), 0);
781     JSStringRelease(removeResourceString);
782
783     JSValueRef arguments[] = { resource->scriptObject };
784     JSObjectCallAsFunction(m_scriptContext, removeResourceFunction, m_scriptObject, 1, arguments, 0);
785
786     resource->setScriptObject(0, 0);
787 }
788
789 void InspectorController::updateScriptResource(InspectorResource* resource, const ResourceRequest& request)
790 {
791     ASSERT(resource->scriptObject);
792     ASSERT(m_scriptContext);
793     if (!resource->scriptObject || !m_scriptContext)
794         return;
795
796     String urlString = request.url().url();
797     JSStringRef url = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
798     JSValueRef urlValue = JSValueMakeString(m_scriptContext, url);
799     JSStringRelease(url);
800
801     urlString = request.url().host();
802     JSStringRef domain = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
803     JSValueRef domainValue = JSValueMakeString(m_scriptContext, domain);
804     JSStringRelease(domain);
805
806     urlString = request.url().path();
807     JSStringRef path = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
808     JSValueRef pathValue = JSValueMakeString(m_scriptContext, path);
809     JSStringRelease(path);
810
811     urlString = request.url().lastPathComponent();
812     JSStringRef lastPathComponent = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
813     JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, lastPathComponent);
814     JSStringRelease(lastPathComponent);
815
816     JSValueRef mainResourceValue = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
817
818     JSStringRef propertyName = JSStringCreateWithUTF8CString("url");
819     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, urlValue, kJSPropertyAttributeNone, 0);
820     JSStringRelease(propertyName);
821
822     propertyName = JSStringCreateWithUTF8CString("domain");
823     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, domainValue, kJSPropertyAttributeNone, 0);
824     JSStringRelease(propertyName);
825
826     propertyName = JSStringCreateWithUTF8CString("path");
827     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, pathValue, kJSPropertyAttributeNone, 0);
828     JSStringRelease(propertyName);
829
830     propertyName = JSStringCreateWithUTF8CString("lastPathComponent");
831     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, lastPathComponentValue, kJSPropertyAttributeNone, 0);
832     JSStringRelease(propertyName);
833
834     propertyName = JSStringCreateWithUTF8CString("requestHeaders");
835     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, objectForRequest(m_scriptContext, request), kJSPropertyAttributeNone, 0);
836     JSStringRelease(propertyName);
837
838     propertyName = JSStringCreateWithUTF8CString("mainResource");
839     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, mainResourceValue, kJSPropertyAttributeNone, 0);
840     JSStringRelease(propertyName);
841 }
842
843 void InspectorController::updateScriptResource(InspectorResource* resource, const ResourceResponse& response, bool /*redirect*/)
844 {
845     ASSERT(resource->scriptObject);
846     ASSERT(m_scriptContext);
847     if (!resource->scriptObject || !m_scriptContext)
848         return;
849
850     JSStringRef mimeType = JSStringCreateWithCharacters(response.mimeType().characters(), response.mimeType().length());
851     JSValueRef mimeTypeValue = JSValueMakeString(m_scriptContext, mimeType);
852     JSStringRelease(mimeType);
853
854     JSStringRef suggestedFilename = JSStringCreateWithCharacters(response.suggestedFilename().characters(), response.suggestedFilename().length());
855     JSValueRef suggestedFilenameValue = JSValueMakeString(m_scriptContext, suggestedFilename);
856     JSStringRelease(suggestedFilename);
857
858     JSValueRef expectedContentLengthValue = JSValueMakeNumber(m_scriptContext, static_cast<double>(response.expectedContentLength()));
859     JSValueRef statusCodeValue = JSValueMakeNumber(m_scriptContext, response.httpStatusCode());
860
861     JSStringRef propertyName = JSStringCreateWithUTF8CString("mimeType");
862     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, mimeTypeValue, kJSPropertyAttributeNone, 0);
863     JSStringRelease(propertyName);
864
865     propertyName = JSStringCreateWithUTF8CString("suggestedFilename");
866     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, suggestedFilenameValue, kJSPropertyAttributeNone, 0);
867     JSStringRelease(propertyName);
868
869     propertyName = JSStringCreateWithUTF8CString("expectedContentLength");
870     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, expectedContentLengthValue, kJSPropertyAttributeNone, 0);
871     JSStringRelease(propertyName);
872
873     propertyName = JSStringCreateWithUTF8CString("statusCode");
874     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, statusCodeValue, kJSPropertyAttributeNone, 0);
875     JSStringRelease(propertyName);
876     
877     propertyName = JSStringCreateWithUTF8CString("responseHeaders");
878     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, objectForResponse(m_scriptContext, response), kJSPropertyAttributeNone, 0);
879     JSStringRelease(propertyName);
880
881     JSValueRef typeValue = JSValueMakeNumber(m_scriptContext, resource->type());
882     propertyName = JSStringCreateWithUTF8CString("type");
883     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, typeValue, kJSPropertyAttributeNone, 0);
884     JSStringRelease(propertyName);
885 }
886
887 void InspectorController::updateScriptResource(InspectorResource*, const ResourceError&)
888 {
889     // FIXME: Do something here when we start showing HTTP errors in the Inspector.
890 }
891
892 void InspectorController::updateScriptResource(InspectorResource* resource, int length)
893 {
894     ASSERT(resource->scriptObject);
895     ASSERT(m_scriptContext);
896     if (!resource->scriptObject || !m_scriptContext)
897         return;
898
899     JSValueRef lengthValue = JSValueMakeNumber(m_scriptContext, length);
900
901     JSStringRef propertyName = JSStringCreateWithUTF8CString("contentLength");
902     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, lengthValue, kJSPropertyAttributeNone, 0);
903     JSStringRelease(propertyName);
904 }
905
906 void InspectorController::updateScriptResource(InspectorResource* resource, bool finished, bool failed)
907 {
908     ASSERT(resource->scriptObject);
909     ASSERT(m_scriptContext);
910     if (!resource->scriptObject || !m_scriptContext)
911         return;
912
913     JSValueRef failedValue = JSValueMakeBoolean(m_scriptContext, failed);
914     JSValueRef finishedValue = JSValueMakeBoolean(m_scriptContext, finished);
915
916     JSStringRef propertyName = JSStringCreateWithUTF8CString("failed");
917     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, failedValue, kJSPropertyAttributeNone, 0);
918     JSStringRelease(propertyName);
919
920     propertyName = JSStringCreateWithUTF8CString("finished");
921     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, finishedValue, kJSPropertyAttributeNone, 0);
922     JSStringRelease(propertyName);
923
924 }
925
926 void InspectorController::updateScriptResource(InspectorResource* resource, double startTime, double responseReceivedTime, double endTime)
927 {
928     ASSERT(resource->scriptObject);
929     ASSERT(m_scriptContext);
930     if (!resource->scriptObject || !m_scriptContext)
931         return;
932
933     JSValueRef startTimeValue = JSValueMakeNumber(m_scriptContext, startTime);
934     JSValueRef responseReceivedTimeValue = JSValueMakeNumber(m_scriptContext, responseReceivedTime);
935     JSValueRef endTimeValue = JSValueMakeNumber(m_scriptContext, endTime);
936
937     JSStringRef propertyName = JSStringCreateWithUTF8CString("startTime");
938     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, startTimeValue, kJSPropertyAttributeNone, 0);
939     JSStringRelease(propertyName);
940
941     propertyName = JSStringCreateWithUTF8CString("responseReceivedTime");
942     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, responseReceivedTimeValue, kJSPropertyAttributeNone, 0);
943     JSStringRelease(propertyName);
944
945     propertyName = JSStringCreateWithUTF8CString("endTime");
946     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, endTimeValue, kJSPropertyAttributeNone, 0);
947     JSStringRelease(propertyName);
948 }
949
950 void InspectorController::populateScriptResources()
951 {
952     ASSERT(m_scriptContext);
953     if (!m_scriptContext)
954         return;
955
956     clearScriptResources();
957     clearScriptConsoleMessages();
958     clearNetworkTimeline();
959
960     ResourcesMap::iterator resourcesEnd = m_resources.end();
961     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
962         addAndUpdateScriptResource(it->second.get());
963
964     unsigned messageCount = m_consoleMessages.size();
965     for (unsigned i = 0; i < messageCount; ++i)
966         addScriptConsoleMessage(m_consoleMessages[i]);
967 }
968
969 void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message)
970 {
971     ASSERT_ARG(message, message);
972
973     JSStringRef messageConstructorString = JSStringCreateWithUTF8CString("ConsoleMessage");
974     JSObjectRef messageConstructor = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, messageConstructorString, 0), 0);
975     JSStringRelease(messageConstructorString);
976
977     JSStringRef addMessageString = JSStringCreateWithUTF8CString("addMessageToConsole");
978     JSObjectRef addMessage = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, addMessageString, 0), 0);
979     JSStringRelease(addMessageString);
980
981     JSValueRef sourceValue = JSValueMakeNumber(m_scriptContext, message->source);
982     JSValueRef levelValue = JSValueMakeNumber(m_scriptContext, message->level);
983     JSStringRef messageString = JSStringCreateWithCharacters(message->message.characters(), message->message.length());
984     JSValueRef messageValue = JSValueMakeString(m_scriptContext, messageString);
985     JSValueRef lineValue = JSValueMakeNumber(m_scriptContext, message->line);
986     JSStringRef urlString = JSStringCreateWithCharacters(message->url.characters(), message->url.length());
987     JSValueRef urlValue = JSValueMakeString(m_scriptContext, urlString);
988
989     JSValueRef args[] = { sourceValue, levelValue, messageValue, lineValue, urlValue };
990     JSObjectRef messageObject = JSObjectCallAsConstructor(m_scriptContext, messageConstructor, 5, args, 0);
991     JSStringRelease(messageString);
992     JSStringRelease(urlString);
993
994     JSObjectCallAsFunction(m_scriptContext, addMessage, m_scriptObject, 1, &messageObject, 0);
995 }
996
997 static void callClearFunction(JSContextRef context, JSObjectRef thisObject, const char* functionName)
998 {
999     ASSERT_ARG(context, context);
1000     ASSERT_ARG(thisObject, thisObject);
1001
1002     JSStringRef string = JSStringCreateWithUTF8CString(functionName);
1003     JSObjectRef function = JSValueToObject(context, JSObjectGetProperty(context, thisObject, string, 0), 0);
1004     JSStringRelease(string);
1005
1006     JSObjectCallAsFunction(context, function, thisObject, 0, 0, 0);
1007 }
1008
1009 void InspectorController::clearScriptResources()
1010 {
1011     if (!m_scriptContext || !m_scriptObject)
1012         return;
1013
1014     ResourcesMap::iterator resourcesEnd = m_resources.end();
1015     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
1016         InspectorResource* resource = it->second.get();
1017         resource->setScriptObject(0, 0);
1018     }
1019
1020     callClearFunction(m_scriptContext, m_scriptObject, "clearResources");
1021 }
1022
1023 void InspectorController::clearScriptConsoleMessages()
1024 {
1025     if (!m_scriptContext || !m_scriptObject)
1026         return;
1027
1028     callClearFunction(m_scriptContext, m_scriptObject, "clearConsoleMessages");
1029 }
1030
1031 void InspectorController::clearNetworkTimeline()
1032 {
1033     if (!m_scriptContext || !m_scriptObject)
1034         return;
1035
1036     callClearFunction(m_scriptContext, m_scriptObject, "clearNetworkTimeline");
1037 }
1038
1039 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
1040 {
1041     ASSERT_ARG(resourceMap, resourceMap);
1042
1043     ResourcesMap mapCopy(*resourceMap);
1044     ResourcesMap::iterator end = mapCopy.end();
1045     for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
1046         InspectorResource* resource = (*it).second.get();
1047         if (resource == m_mainResource)
1048             continue;
1049
1050         if (!loaderToKeep || resource->loader != loaderToKeep) {
1051             removeResource(resource);
1052             if (windowVisible() && resource->scriptObject)
1053                 removeScriptResource(resource);
1054         }
1055     }
1056 }
1057
1058 void InspectorController::didCommitLoad(DocumentLoader* loader)
1059 {
1060     if (loader->frame() == m_inspectedPage->mainFrame()) {
1061         ASSERT(m_mainResource);
1062         // FIXME: Should look into asserting that m_mainResource->loader == loader here.
1063
1064         m_client->inspectedURLChanged(loader->URL().url());
1065         deleteAllValues(m_consoleMessages);
1066         m_consoleMessages.clear();
1067         if (windowVisible()) {
1068             clearScriptConsoleMessages();
1069             clearNetworkTimeline();
1070
1071             // We don't add the main resource until its load is committed. This
1072             // is needed to keep the load for a user-entered URL from showing
1073             // up in the list of resources for the page they are navigating
1074             // away from.
1075             addAndUpdateScriptResource(m_mainResource.get());
1076         }
1077     }
1078
1079     for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
1080         if (ResourcesMap* resourceMap = m_frameResources.get(frame))
1081             pruneResources(resourceMap, loader);
1082 }
1083
1084 void InspectorController::frameDetachedFromParent(Frame* frame)
1085 {
1086     if (ResourcesMap* resourceMap = m_frameResources.get(frame))
1087         removeAllResources(resourceMap);
1088 }
1089
1090 void InspectorController::addResource(InspectorResource* resource)
1091 {
1092     m_resources.set(resource->identifier, resource);
1093
1094     Frame* frame = resource->frame.get();
1095     ResourcesMap* resourceMap = m_frameResources.get(frame);
1096     if (resourceMap)
1097         resourceMap->set(resource->identifier, resource);
1098     else {
1099         resourceMap = new ResourcesMap;
1100         resourceMap->set(resource->identifier, resource);
1101         m_frameResources.set(frame, resourceMap);
1102     }
1103 }
1104
1105 void InspectorController::removeResource(InspectorResource* resource)
1106 {
1107     m_resources.remove(resource->identifier);
1108
1109     Frame* frame = resource->frame.get();
1110     ResourcesMap* resourceMap = m_frameResources.get(frame);
1111     if (!resourceMap) {
1112         ASSERT_NOT_REACHED();
1113         return;
1114     }
1115
1116     resourceMap->remove(resource->identifier);
1117     if (resourceMap->isEmpty()) {
1118         m_frameResources.remove(frame);
1119         delete resourceMap;
1120     }
1121 }
1122
1123 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse& response, int length)
1124 {
1125     InspectorResource* resource = new InspectorResource(m_nextIdentifier--, loader, loader->frame());
1126     resource->finished = true;
1127     resource->request = request;
1128     resource->response = response;
1129     resource->length = length;
1130     resource->cached = true;
1131     resource->startTime = currentTime();
1132     resource->responseReceivedTime = resource->startTime;
1133     resource->endTime = resource->startTime;
1134
1135     if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
1136         m_mainResource = resource;
1137
1138     addResource(resource);
1139
1140     if (windowVisible())
1141         addAndUpdateScriptResource(resource);
1142 }
1143
1144 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
1145 {
1146     InspectorResource* resource = new InspectorResource(identifier, loader, loader->frame());
1147     resource->request = request;
1148
1149     if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
1150         m_mainResource = resource;
1151
1152     addResource(resource);
1153 }
1154
1155 void InspectorController::willSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
1156 {
1157     InspectorResource* resource = m_resources.get(identifier).get();
1158     if (!resource)
1159         return;
1160
1161     resource->startTime = currentTime();
1162
1163     if (resource->request != request)
1164         resource->request = request;
1165
1166     if (!redirectResponse.isNull())
1167         resource->redirectResponse = redirectResponse;
1168
1169     if (resource != m_mainResource && windowVisible()) {
1170         if (!resource->scriptObject)
1171             addScriptResource(resource);
1172         else
1173             updateScriptResource(resource, resource->request);
1174
1175         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1176
1177         if (!redirectResponse.isNull())
1178             updateScriptResource(resource, redirectResponse, true);
1179     }
1180 }
1181
1182 void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse& response)
1183 {
1184     InspectorResource* resource = m_resources.get(identifier).get();
1185     if (!resource)
1186         return;
1187
1188     resource->response = response;
1189     resource->responseReceivedTime = currentTime();
1190
1191     if (windowVisible() && resource->scriptObject) {
1192         updateScriptResource(resource, response);
1193         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1194     }
1195 }
1196
1197 void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived)
1198 {
1199     InspectorResource* resource = m_resources.get(identifier).get();
1200     if (!resource)
1201         return;
1202
1203     resource->length += lengthReceived;
1204
1205     if (windowVisible() && resource->scriptObject)
1206         updateScriptResource(resource, resource->length);
1207 }
1208
1209 void InspectorController::didFinishLoading(DocumentLoader* loader, unsigned long identifier)
1210 {
1211     RefPtr<InspectorResource> resource = m_resources.get(identifier);
1212     if (!resource)
1213         return;
1214
1215     removeResource(resource.get());
1216
1217     resource->finished = true;
1218     resource->endTime = currentTime();
1219
1220     addResource(resource.get());
1221
1222     if (windowVisible() && resource->scriptObject) {
1223         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
1224         updateScriptResource(resource.get(), resource->finished);
1225     }
1226 }
1227
1228 void InspectorController::didFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& error)
1229 {
1230     RefPtr<InspectorResource> resource = m_resources.get(identifier);
1231     if (!resource)
1232         return;
1233
1234     removeResource(resource.get());
1235
1236     resource->finished = true;
1237     resource->failed = true;
1238     resource->error = error;
1239     resource->endTime = currentTime();
1240
1241     addResource(resource.get());
1242
1243     if (windowVisible() && resource->scriptObject) {
1244         updateScriptResource(resource.get(), resource->error);
1245         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
1246         updateScriptResource(resource.get(), resource->finished, resource->failed);
1247     }
1248 }
1249
1250 } // namespace WebCore