Adds a debugger toggle button to the scripts status bar that will start
[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 "Console.h"
35 #include "DOMWindow.h"
36 #include "DocLoader.h"
37 #include "Document.h"
38 #include "DocumentLoader.h"
39 #include "Element.h"
40 #include "FloatConversion.h"
41 #include "FloatRect.h"
42 #include "Frame.h"
43 #include "FrameLoader.h"
44 #include "FrameTree.h"
45 #include "FrameView.h"
46 #include "GraphicsContext.h"
47 #include "HTMLFrameOwnerElement.h"
48 #include "InspectorClient.h"
49 #include "JSDOMWindow.h"
50 #include "JSInspectedObjectWrapper.h"
51 #include "JSInspectorCallbackWrapper.h"
52 #include "JSNode.h"
53 #include "JSRange.h"
54 #include "JavaScriptDebugServer.h"
55 #include "Page.h"
56 #include "Range.h"
57 #include "ResourceRequest.h"
58 #include "ResourceResponse.h"
59 #include "Settings.h"
60 #include "SharedBuffer.h"
61 #include "SystemTime.h"
62 #include "TextEncoding.h"
63 #include "TextIterator.h"
64 #include "kjs_proxy.h"
65 #include <JavaScriptCore/APICast.h>
66 #include <JavaScriptCore/JSLock.h>
67 #include <JavaScriptCore/JSRetainPtr.h>
68 #include <JavaScriptCore/JSStringRef.h>
69 #include <kjs/ustring.h>
70 #include <wtf/RefCounted.h>
71
72 #if ENABLE(DATABASE)
73 #include "Database.h"
74 #include "JSDatabase.h"
75 #endif
76
77 using namespace KJS;
78 using namespace std;
79
80 namespace WebCore {
81
82 static JSRetainPtr<JSStringRef> jsStringRef(const char* str)
83 {
84     return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(str));
85 }
86
87 static JSRetainPtr<JSStringRef> jsStringRef(const String& str)
88 {
89     return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithCharacters(str.characters(), str.length()));
90 }
91
92 #define HANDLE_EXCEPTION(exception) handleException((exception), __LINE__)
93
94 JSValueRef InspectorController::callSimpleFunction(JSContextRef context, JSObjectRef thisObject, const char* functionName) const
95 {
96     ASSERT_ARG(context, context);
97     ASSERT_ARG(thisObject, thisObject);
98
99     JSValueRef exception = 0;
100
101     JSValueRef functionProperty = JSObjectGetProperty(context, thisObject, jsStringRef(functionName).get(), &exception);
102     if (HANDLE_EXCEPTION(exception))
103         return JSValueMakeUndefined(context);
104
105     JSObjectRef function = JSValueToObject(context, functionProperty, &exception);
106     if (HANDLE_EXCEPTION(exception))
107         return JSValueMakeUndefined(context);
108
109     JSValueRef result = JSObjectCallAsFunction(context, function, thisObject, 0, 0, &exception);
110     if (HANDLE_EXCEPTION(exception))
111         return JSValueMakeUndefined(context);
112
113     return result;
114 }
115
116 #pragma mark -
117 #pragma mark ConsoleMessage Struct
118
119 struct ConsoleMessage {
120     ConsoleMessage(MessageSource s, MessageLevel l, const String& m, unsigned li, const String& u)
121         : source(s)
122         , level(l)
123         , message(m)
124         , line(li)
125         , url(u)
126     {
127     }
128
129     ConsoleMessage(MessageSource s, MessageLevel l, ExecState* exec, const List& args, unsigned li, const String& u)
130         : source(s)
131         , level(l)
132         , wrappedArguments(args.size())
133         , line(li)
134         , url(u)
135     {
136         JSLock lock;
137         for (unsigned i = 0; i < args.size(); ++i)
138             wrappedArguments[i] = JSInspectedObjectWrapper::wrap(exec, args[i]);
139     }
140
141     MessageSource source;
142     MessageLevel level;
143     String message;
144     Vector<ProtectedPtr<JSValue> > wrappedArguments;
145     unsigned line;
146     String url;
147 };
148
149 #pragma mark -
150 #pragma mark XMLHttpRequestResource Class
151
152 struct XMLHttpRequestResource {
153     XMLHttpRequestResource(KJS::UString& sourceString)
154     {
155         KJS::JSLock lock;
156         this->sourceString = sourceString.rep();
157     }
158
159     ~XMLHttpRequestResource()
160     {
161         KJS::JSLock lock;
162         sourceString.clear();
163     }
164
165     RefPtr<KJS::UString::Rep> sourceString;
166 };
167
168 #pragma mark -
169 #pragma mark InspectorResource Struct
170
171 struct InspectorResource : public RefCounted<InspectorResource> {
172     // Keep these in sync with WebInspector.Resource.Type
173     enum Type {
174         Doc,
175         Stylesheet,
176         Image,
177         Font,
178         Script,
179         XHR,
180         Other
181     };
182
183     static PassRefPtr<InspectorResource> create(long long identifier, DocumentLoader* documentLoader, Frame* frame)
184     {
185         return adoptRef(new InspectorResource(identifier, documentLoader, frame));
186     }
187     
188     ~InspectorResource()
189     {
190         setScriptObject(0, 0);
191     }
192
193     Type type() const
194     {
195         if (xmlHttpRequestResource)
196             return XHR;
197
198         if (requestURL == loader->requestURL())
199             return Doc;
200
201         if (loader->frameLoader() && requestURL == loader->frameLoader()->iconURL())
202             return Image;
203
204         CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string());
205         if (!cachedResource)
206             return Other;
207
208         switch (cachedResource->type()) {
209             case CachedResource::ImageResource:
210                 return Image;
211             case CachedResource::FontResource:
212                 return Font;
213             case CachedResource::CSSStyleSheet:
214 #if ENABLE(XSLT)
215             case CachedResource::XSLStyleSheet:
216 #endif
217                 return Stylesheet;
218             case CachedResource::Script:
219                 return Script;
220             default:
221                 return Other;
222         }
223     }
224
225     void setScriptObject(JSContextRef context, JSObjectRef newScriptObject)
226     {
227         if (scriptContext && scriptObject)
228             JSValueUnprotect(scriptContext, scriptObject);
229
230         scriptObject = newScriptObject;
231         scriptContext = context;
232
233         ASSERT((context && newScriptObject) || (!context && !newScriptObject));
234         if (context && newScriptObject)
235             JSValueProtect(context, newScriptObject);
236     }
237
238     void setXMLHttpRequestProperties(KJS::UString& data)
239     {
240         xmlHttpRequestResource.set(new XMLHttpRequestResource(data));
241     }
242     
243     String sourceString() const
244      {
245          if (xmlHttpRequestResource)
246             return KJS::UString(xmlHttpRequestResource->sourceString);
247
248         RefPtr<SharedBuffer> buffer;
249         String textEncodingName;
250
251         if (requestURL == loader->requestURL()) {
252             buffer = loader->mainResourceData();
253             textEncodingName = frame->document()->inputEncoding();
254         } else {
255             CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string());
256             if (!cachedResource)
257                 return String();
258
259             buffer = cachedResource->data();
260             textEncodingName = cachedResource->encoding();
261         }
262
263         if (!buffer)
264             return String();
265
266         TextEncoding encoding(textEncodingName);
267         if (!encoding.isValid())
268             encoding = WindowsLatin1Encoding();
269         return encoding.decode(buffer->data(), buffer->size());
270      }
271
272     long long identifier;
273     RefPtr<DocumentLoader> loader;
274     RefPtr<Frame> frame;
275     OwnPtr<XMLHttpRequestResource> xmlHttpRequestResource;
276     KURL requestURL;
277     HTTPHeaderMap requestHeaderFields;
278     HTTPHeaderMap responseHeaderFields;
279     String mimeType;
280     String suggestedFilename;
281     JSContextRef scriptContext;
282     JSObjectRef scriptObject;
283     long long expectedContentLength;
284     bool cached;
285     bool finished;
286     bool failed;
287     int length;
288     int responseStatusCode;
289     double startTime;
290     double responseReceivedTime;
291     double endTime;
292
293 protected:
294     InspectorResource(long long identifier, DocumentLoader* documentLoader, Frame* frame)
295         : identifier(identifier)
296         , loader(documentLoader)
297         , frame(frame)
298         , xmlHttpRequestResource(0)
299         , scriptContext(0)
300         , scriptObject(0)
301         , expectedContentLength(0)
302         , cached(false)
303         , finished(false)
304         , failed(false)
305         , length(0)
306         , responseStatusCode(0)
307         , startTime(-1.0)
308         , responseReceivedTime(-1.0)
309         , endTime(-1.0)
310     {
311     }
312 };
313
314 #pragma mark -
315 #pragma mark InspectorDatabaseResource Struct
316
317 #if ENABLE(DATABASE)
318 struct InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> {
319     static PassRefPtr<InspectorDatabaseResource> create(Database* database, const String& domain, const String& name, const String& version)
320     {
321         return adoptRef(new InspectorDatabaseResource(database, domain, name, version));
322     }
323
324     void setScriptObject(JSContextRef context, JSObjectRef newScriptObject)
325     {
326         if (scriptContext && scriptObject)
327             JSValueUnprotect(scriptContext, scriptObject);
328
329         scriptObject = newScriptObject;
330         scriptContext = context;
331
332         ASSERT((context && newScriptObject) || (!context && !newScriptObject));
333         if (context && newScriptObject)
334             JSValueProtect(context, newScriptObject);
335     }
336
337     RefPtr<Database> database;
338     String domain;
339     String name;
340     String version;
341     JSContextRef scriptContext;
342     JSObjectRef scriptObject;
343     
344 private:
345     InspectorDatabaseResource(Database* database, const String& domain, const String& name, const String& version)
346         : database(database)
347         , domain(domain)
348         , name(name)
349         , version(version)
350         , scriptContext(0)
351         , scriptObject(0)
352     {
353     }
354 };
355 #endif
356
357 #pragma mark -
358 #pragma mark JavaScript Callbacks
359
360 static JSValueRef addSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
361 {
362     JSValueRef undefined = JSValueMakeUndefined(ctx);
363
364     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
365     if (argumentCount < 2 || !controller)
366         return undefined;
367
368     JSValueRef identifierValue = arguments[0];
369     if (!JSValueIsNumber(ctx, identifierValue))
370         return undefined;
371
372     unsigned long identifier = static_cast<unsigned long>(JSValueToNumber(ctx, identifierValue, exception));
373     if (exception && *exception)
374         return undefined;
375
376     RefPtr<InspectorResource> resource = controller->resources().get(identifier);
377     ASSERT(resource);
378     if (!resource)
379         return undefined;
380
381     String sourceString = resource->sourceString();
382     if (sourceString.isEmpty())
383         return undefined;
384
385     Node* node = toNode(toJS(arguments[1]));
386     ASSERT(node);
387     if (!node)
388         return undefined;
389
390     if (!node->attached()) {
391         ASSERT_NOT_REACHED();
392         return undefined;
393     }
394
395     ASSERT(node->isElementNode());
396     if (!node->isElementNode())
397         return undefined;
398
399     Element* element = static_cast<Element*>(node);
400     ASSERT(element->isFrameOwnerElement());
401     if (!element->isFrameOwnerElement())
402         return undefined;
403
404     HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element);
405     ASSERT(frameOwner->contentFrame());
406     if (!frameOwner->contentFrame())
407         return undefined;
408
409     FrameLoader* loader = frameOwner->contentFrame()->loader();
410
411     loader->setResponseMIMEType(resource->mimeType);
412     loader->begin();
413     loader->write(sourceString);
414     loader->end();
415
416     return undefined;
417 }
418
419 static JSValueRef getResourceDocumentNode(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
420 {
421     JSValueRef undefined = JSValueMakeUndefined(ctx);
422
423     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
424     if (!argumentCount || argumentCount > 1 || !controller)
425         return undefined;
426
427     JSValueRef identifierValue = arguments[0];
428     if (!JSValueIsNumber(ctx, identifierValue))
429         return undefined;
430
431     unsigned long identifier = static_cast<unsigned long>(JSValueToNumber(ctx, identifierValue, exception));
432     if (exception && *exception)
433         return undefined;
434
435     RefPtr<InspectorResource> resource = controller->resources().get(identifier);
436     ASSERT(resource);
437     if (!resource)
438         return undefined;
439
440     Frame* frame = resource->frame.get();
441
442     Document* document = frame->document();
443     if (!document)
444         return undefined;
445
446     if (document->isPluginDocument() || document->isImageDocument())
447         return undefined;
448
449     ExecState* exec = toJSDOMWindowWrapper(resource->frame.get())->window()->globalExec();
450
451     KJS::JSLock lock;
452     JSValueRef documentValue = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, document)));
453     return documentValue;
454 }
455
456 static JSValueRef highlightDOMNode(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
457 {
458     JSValueRef undefined = JSValueMakeUndefined(context);
459
460     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
461     if (argumentCount < 1 || !controller)
462         return undefined;
463
464     JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(toJS(arguments[0]));
465     if (!wrapper)
466         return undefined;
467     Node* node = toNode(wrapper->unwrappedObject());
468     if (!node)
469         return undefined;
470
471     controller->highlight(node);
472
473     return undefined;
474 }
475
476 static JSValueRef hideDOMNodeHighlight(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
477 {
478     JSValueRef undefined = JSValueMakeUndefined(context);
479
480     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
481     if (argumentCount || !controller)
482         return undefined;
483
484     controller->hideHighlight();
485
486     return undefined;
487 }
488
489 static JSValueRef loaded(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
490 {
491     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
492     if (!controller)
493         return JSValueMakeUndefined(ctx);
494
495     controller->scriptObjectReady();
496     return JSValueMakeUndefined(ctx);
497 }
498
499 static JSValueRef unloading(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
500 {
501     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
502     if (!controller)
503         return JSValueMakeUndefined(ctx);
504
505     controller->close();
506     return JSValueMakeUndefined(ctx);
507 }
508
509 static JSValueRef attach(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
510 {
511     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
512     if (!controller)
513         return JSValueMakeUndefined(ctx);
514
515     controller->attachWindow();
516     return JSValueMakeUndefined(ctx);
517 }
518
519 static JSValueRef detach(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
520 {
521     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
522     if (!controller)
523         return JSValueMakeUndefined(ctx);
524
525     controller->detachWindow();
526     return JSValueMakeUndefined(ctx);
527 }
528
529 static JSValueRef search(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
530 {
531     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
532     if (!controller)
533         return JSValueMakeUndefined(ctx);
534
535     if (argumentCount < 2 || !JSValueIsString(ctx, arguments[1]))
536         return JSValueMakeUndefined(ctx);
537
538     Node* node = toNode(toJS(arguments[0]));
539     if (!node)
540         return JSValueMakeUndefined(ctx);
541
542     JSRetainPtr<JSStringRef> searchString(Adopt, JSValueToStringCopy(ctx, arguments[1], exception));
543     if (exception && *exception)
544         return JSValueMakeUndefined(ctx);
545
546     String target(JSStringGetCharactersPtr(searchString.get()), JSStringGetLength(searchString.get()));
547
548     JSObjectRef global = JSContextGetGlobalObject(ctx);
549
550     JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception);
551     if (exception && *exception)
552         return JSValueMakeUndefined(ctx);
553
554     JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
555     if (exception && *exception)
556         return JSValueMakeUndefined(ctx);
557
558     JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
559     if (exception && *exception)
560         return JSValueMakeUndefined(ctx);
561
562     JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception);
563     if (exception && *exception)
564         return JSValueMakeUndefined(ctx);
565
566     JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
567     if (exception && *exception)
568         return JSValueMakeUndefined(ctx);
569
570     RefPtr<Range> searchRange(rangeOfContents(node));
571
572     ExceptionCode ec = 0;
573     do {
574         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false));
575         if (resultRange->collapsed(ec))
576             break;
577
578         // A non-collapsed result range can in some funky whitespace cases still not
579         // advance the range's start position (4509328). Break to avoid infinite loop.
580         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
581         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
582             break;
583
584         KJS::JSLock lock;
585         JSValueRef arg0 = toRef(toJS(toJS(ctx), resultRange.get()));
586         JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
587         if (exception && *exception)
588             return JSValueMakeUndefined(ctx);
589
590         setStart(searchRange.get(), newStart);
591     } while (true);
592
593     return result;
594 }
595
596 #if ENABLE(DATABASE)
597 static JSValueRef databaseTableNames(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
598 {
599     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
600     if (!controller)
601         return JSValueMakeUndefined(ctx);
602
603     if (argumentCount < 1)
604         return JSValueMakeUndefined(ctx);
605
606     JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(toJS(arguments[0]));
607     if (!wrapper)
608         return JSValueMakeUndefined(ctx);
609
610     Database* database = toDatabase(wrapper->unwrappedObject());
611     if (!database)
612         return JSValueMakeUndefined(ctx);
613
614     JSObjectRef global = JSContextGetGlobalObject(ctx);
615
616     JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception);
617     if (exception && *exception)
618         return JSValueMakeUndefined(ctx);
619
620     JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
621     if (exception && *exception)
622         return JSValueMakeUndefined(ctx);
623
624     JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
625     if (exception && *exception)
626         return JSValueMakeUndefined(ctx);
627
628     JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception);
629     if (exception && *exception)
630         return JSValueMakeUndefined(ctx);
631
632     JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
633     if (exception && *exception)
634         return JSValueMakeUndefined(ctx);
635
636     Vector<String> tableNames = database->tableNames();
637     unsigned length = tableNames.size();
638     for (unsigned i = 0; i < length; ++i) {
639         String tableName = tableNames[i];
640         JSValueRef tableNameValue = JSValueMakeString(ctx, jsStringRef(tableName).get());
641
642         JSValueRef pushArguments[] = { tableNameValue };
643         JSObjectCallAsFunction(ctx, pushFunction, result, 1, pushArguments, exception);
644         if (exception && *exception)
645             return JSValueMakeUndefined(ctx);
646     }
647
648     return result;
649 }
650 #endif
651
652 static JSValueRef inspectedWindow(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
653 {
654     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
655     if (!controller)
656         return JSValueMakeUndefined(ctx);
657
658     JSDOMWindow* inspectedWindow = toJSDOMWindow(controller->inspectedPage()->mainFrame());
659     JSLock lock;
660     return toRef(JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), inspectedWindow));
661 }
662
663 static JSValueRef localizedStrings(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
664 {
665     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
666     if (!controller)
667         return JSValueMakeUndefined(ctx);
668
669     String url = controller->localizedStringsURL();
670     if (url.isNull())
671         return JSValueMakeNull(ctx);
672
673     return JSValueMakeString(ctx, jsStringRef(url).get());
674 }
675
676 static JSValueRef platform(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
677 {
678 #if PLATFORM(MAC)
679 #ifdef BUILDING_ON_TIGER
680     static const String platform = "mac-tiger";
681 #else
682     static const String platform = "mac-leopard";
683 #endif
684 #elif PLATFORM(WIN_OS)
685     static const String platform = "windows";
686 #elif PLATFORM(QT)
687     static const String platform = "qt";
688 #elif PLATFORM(GTK)
689     static const String platform = "gtk";
690 #elif PLATFORM(WX)
691     static const String platform = "wx";
692 #else
693     static const String platform = "unknown";
694 #endif
695
696     JSValueRef platformValue = JSValueMakeString(ctx, jsStringRef(platform).get());
697
698     return platformValue;
699 }
700
701 static JSValueRef moveByUnrestricted(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
702 {
703     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
704     if (!controller)
705         return JSValueMakeUndefined(ctx);
706
707     if (argumentCount < 2)
708         return JSValueMakeUndefined(ctx);
709
710     double x = JSValueToNumber(ctx, arguments[0], exception);
711     if (exception && *exception)
712         return JSValueMakeUndefined(ctx);
713
714     double y = JSValueToNumber(ctx, arguments[1], exception);
715     if (exception && *exception)
716         return JSValueMakeUndefined(ctx);
717
718     controller->moveWindowBy(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y));
719
720     return JSValueMakeUndefined(ctx);
721 }
722
723 static JSValueRef wrapCallback(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
724 {
725     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
726     if (!controller)
727         return JSValueMakeUndefined(ctx);
728
729     if (argumentCount < 1)
730         return JSValueMakeUndefined(ctx);
731
732     JSLock lock;
733     return toRef(JSInspectorCallbackWrapper::wrap(toJS(ctx), toJS(arguments[0])));
734 }
735
736 static JSValueRef startDebuggingAndReloadInspectedPage(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
737 {
738     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
739     if (!controller)
740         return JSValueMakeUndefined(ctx);
741
742     controller->startDebuggingAndReloadInspectedPage();
743
744     return JSValueMakeUndefined(ctx);
745 }
746
747 static JSValueRef stopDebugging(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
748 {
749     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
750     if (!controller)
751         return JSValueMakeUndefined(ctx);
752
753     controller->stopDebugging();
754
755     return JSValueMakeUndefined(ctx);
756 }
757
758 static JSValueRef debuggerAttached(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
759 {
760     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
761     if (!controller)
762         return JSValueMakeUndefined(ctx);
763     return JSValueMakeBoolean(ctx, controller->debuggerAttached());
764 }
765
766 #pragma mark -
767 #pragma mark InspectorController Class
768
769 InspectorController::InspectorController(Page* page, InspectorClient* client)
770     : m_inspectedPage(page)
771     , m_client(client)
772     , m_page(0)
773     , m_scriptObject(0)
774     , m_controllerScriptObject(0)
775     , m_scriptContext(0)
776     , m_windowVisible(false)
777     , m_debuggerAttached(false)
778     , m_showAfterVisible(FocusedNodeDocumentPanel)
779     , m_nextIdentifier(-2)
780 {
781     ASSERT_ARG(page, page);
782     ASSERT_ARG(client, client);
783 }
784
785 InspectorController::~InspectorController()
786 {
787     m_client->inspectorDestroyed();
788
789     if (m_scriptContext) {
790         JSValueRef exception = 0;
791
792         JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
793         JSValueRef controllerProperty = JSObjectGetProperty(m_scriptContext, global, jsStringRef("InspectorController").get(), &exception);
794         if (!HANDLE_EXCEPTION(exception)) {
795             if (JSObjectRef controller = JSValueToObject(m_scriptContext, controllerProperty, &exception)) {
796                 if (!HANDLE_EXCEPTION(exception))
797                     JSObjectSetPrivate(controller, 0);
798             }
799         }
800     }
801
802     if (m_page)
803         m_page->setParentInspectorController(0);
804
805     stopDebugging();
806
807     deleteAllValues(m_frameResources);
808     deleteAllValues(m_consoleMessages);
809 }
810
811 bool InspectorController::enabled() const
812 {
813     return m_inspectedPage->settings()->developerExtrasEnabled();
814 }
815
816 String InspectorController::localizedStringsURL()
817 {
818     if (!enabled())
819         return String();
820     return m_client->localizedStringsURL();
821 }
822
823 // Trying to inspect something in a frame with JavaScript disabled would later lead to
824 // crashes trying to create JavaScript wrappers. Some day we could fix this issue, but
825 // for now prevent crashes here by never targeting a node in such a frame.
826 static bool canPassNodeToJavaScript(Node* node)
827 {
828     if (!node)
829         return false;
830     Frame* frame = node->document()->frame();
831     return frame && frame->scriptProxy()->isEnabled();
832 }
833
834 void InspectorController::inspect(Node* node)
835 {
836     if (!canPassNodeToJavaScript(node) || !enabled())
837         return;
838
839     show();
840
841     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
842         node = node->parentNode();
843     m_nodeToFocus = node;
844
845     if (!m_scriptObject) {
846         m_showAfterVisible = FocusedNodeDocumentPanel;
847         return;
848     }
849
850     if (windowVisible())
851         focusNode();
852 }
853
854 void InspectorController::focusNode()
855 {
856     if (!enabled())
857         return;
858
859     ASSERT(m_scriptContext);
860     ASSERT(m_scriptObject);
861     ASSERT(m_nodeToFocus);
862
863     Frame* frame = m_nodeToFocus->document()->frame();
864     if (!frame)
865         return;
866
867     ExecState* exec = toJSDOMWindow(frame)->globalExec();
868
869     JSValueRef arg0;
870
871     {
872         KJS::JSLock lock;
873         arg0 = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, m_nodeToFocus.get())));
874     }
875
876     m_nodeToFocus = 0;
877
878     JSValueRef exception = 0;
879
880     JSValueRef functionProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("updateFocusedNode").get(), &exception);
881     if (HANDLE_EXCEPTION(exception))
882         return;
883
884     JSObjectRef function = JSValueToObject(m_scriptContext, functionProperty, &exception);
885     if (HANDLE_EXCEPTION(exception))
886         return;
887
888     ASSERT(function);
889
890     JSObjectCallAsFunction(m_scriptContext, function, m_scriptObject, 1, &arg0, &exception);
891     HANDLE_EXCEPTION(exception);
892 }
893
894 void InspectorController::highlight(Node* node)
895 {
896     if (!enabled())
897         return;
898     ASSERT_ARG(node, node);
899     m_highlightedNode = node;
900     m_client->highlight(node);
901 }
902
903 void InspectorController::hideHighlight()
904 {
905     if (!enabled())
906         return;
907     m_client->hideHighlight();
908 }
909
910 bool InspectorController::windowVisible()
911 {
912     return m_windowVisible;
913 }
914
915 void InspectorController::setWindowVisible(bool visible)
916 {
917     if (visible == m_windowVisible)
918         return;
919
920     m_windowVisible = visible;
921
922     if (!m_scriptContext || !m_scriptObject)
923         return;
924
925     if (m_windowVisible) {
926         populateScriptObjects();
927         if (m_nodeToFocus)
928             focusNode();
929         if (m_showAfterVisible == ConsolePanel)
930             showConsole();
931         else if (m_showAfterVisible == TimelinePanel)
932             showTimeline();
933     } else
934         resetScriptObjects();
935
936     m_showAfterVisible = FocusedNodeDocumentPanel;
937 }
938
939 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, ExecState* exec, const List& arguments, unsigned lineNumber, const String& sourceURL)
940 {
941     if (!enabled())
942         return;
943
944     addConsoleMessage(new ConsoleMessage(source, level, exec, arguments, lineNumber, sourceURL));
945 }
946
947 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
948 {
949     if (!enabled())
950         return;
951
952     addConsoleMessage(new ConsoleMessage(source, level, message, lineNumber, sourceID));
953 }
954
955 void InspectorController::addConsoleMessage(ConsoleMessage* consoleMessage)
956 {
957     ASSERT(enabled());
958     ASSERT_ARG(consoleMessage, consoleMessage);
959
960     m_consoleMessages.append(consoleMessage);
961
962     if (windowVisible())
963         addScriptConsoleMessage(consoleMessage);
964 }
965
966 void InspectorController::attachWindow()
967 {
968     if (!enabled())
969         return;
970     m_client->attachWindow();
971 }
972
973 void InspectorController::detachWindow()
974 {
975     if (!enabled())
976         return;
977     m_client->detachWindow();
978 }
979
980 void InspectorController::windowScriptObjectAvailable()
981 {
982     if (!m_page || !enabled())
983         return;
984
985     m_scriptContext = toRef(m_page->mainFrame()->scriptProxy()->globalObject()->globalExec());
986
987     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
988     ASSERT(global);
989
990     static JSStaticFunction staticFunctions[] = {
991         { "addSourceToFrame", addSourceToFrame, kJSPropertyAttributeNone },
992         { "getResourceDocumentNode", getResourceDocumentNode, kJSPropertyAttributeNone },
993         { "highlightDOMNode", highlightDOMNode, kJSPropertyAttributeNone },
994         { "hideDOMNodeHighlight", hideDOMNodeHighlight, kJSPropertyAttributeNone },
995         { "loaded", loaded, kJSPropertyAttributeNone },
996         { "windowUnloading", unloading, kJSPropertyAttributeNone },
997         { "attach", attach, kJSPropertyAttributeNone },
998         { "detach", detach, kJSPropertyAttributeNone },
999         { "search", search, kJSPropertyAttributeNone },
1000 #if ENABLE(DATABASE)
1001         { "databaseTableNames", databaseTableNames, kJSPropertyAttributeNone },
1002 #endif
1003         { "inspectedWindow", inspectedWindow, kJSPropertyAttributeNone },
1004         { "localizedStringsURL", localizedStrings, kJSPropertyAttributeNone },
1005         { "platform", platform, kJSPropertyAttributeNone },
1006         { "moveByUnrestricted", moveByUnrestricted, kJSPropertyAttributeNone },
1007         { "wrapCallback", wrapCallback, kJSPropertyAttributeNone },
1008         { "startDebuggingAndReloadInspectedPage", WebCore::startDebuggingAndReloadInspectedPage, kJSPropertyAttributeNone },
1009         { "stopDebugging", WebCore::stopDebugging, kJSPropertyAttributeNone },
1010         { "debuggerAttached", WebCore::debuggerAttached, kJSPropertyAttributeNone },
1011         { 0, 0, 0 }
1012     };
1013
1014     JSClassDefinition inspectorControllerDefinition = {
1015         0, kJSClassAttributeNone, "InspectorController", 0, 0, staticFunctions,
1016         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1017     };
1018
1019     JSClassRef controllerClass = JSClassCreate(&inspectorControllerDefinition);
1020     ASSERT(controllerClass);
1021
1022     m_controllerScriptObject = JSObjectMake(m_scriptContext, controllerClass, reinterpret_cast<void*>(this));
1023     ASSERT(m_controllerScriptObject);
1024
1025     JSObjectSetProperty(m_scriptContext, global, jsStringRef("InspectorController").get(), m_controllerScriptObject, kJSPropertyAttributeNone, 0);
1026 }
1027
1028 void InspectorController::scriptObjectReady()
1029 {
1030     ASSERT(m_scriptContext);
1031     if (!m_scriptContext)
1032         return;
1033
1034     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
1035     ASSERT(global);
1036
1037     JSValueRef exception = 0;
1038
1039     JSValueRef inspectorValue = JSObjectGetProperty(m_scriptContext, global, jsStringRef("WebInspector").get(), &exception);
1040     if (HANDLE_EXCEPTION(exception))
1041         return;
1042
1043     ASSERT(inspectorValue);
1044     if (!inspectorValue)
1045         return;
1046
1047     m_scriptObject = JSValueToObject(m_scriptContext, inspectorValue, &exception);
1048     if (HANDLE_EXCEPTION(exception))
1049         return;
1050
1051     ASSERT(m_scriptObject);
1052
1053     JSValueProtect(m_scriptContext, m_scriptObject);
1054
1055     // Make sure our window is visible now that the page loaded
1056     showWindow();
1057 }
1058
1059 void InspectorController::show()
1060 {
1061     if (!enabled())
1062         return;
1063
1064     if (!m_page) {
1065         m_page = m_client->createPage();
1066         if (!m_page)
1067             return;
1068         m_page->setParentInspectorController(this);
1069
1070         // showWindow() will be called after the page loads in scriptObjectReady()
1071         return;
1072     }
1073
1074     showWindow();
1075 }
1076
1077 void InspectorController::showConsole()
1078 {
1079     if (!enabled())
1080         return;
1081
1082     show();
1083
1084     if (!m_scriptObject) {
1085         m_showAfterVisible = ConsolePanel;
1086         return;
1087     }
1088
1089     callSimpleFunction(m_scriptContext, m_scriptObject, "showConsole");
1090 }
1091
1092 void InspectorController::showTimeline()
1093 {
1094     if (!enabled())
1095         return;
1096
1097     show();
1098
1099     if (!m_scriptObject) {
1100         m_showAfterVisible = TimelinePanel;
1101         return;
1102     }
1103
1104     callSimpleFunction(m_scriptContext, m_scriptObject, "showTimeline");
1105 }
1106
1107 void InspectorController::close()
1108 {
1109     if (!enabled())
1110         return;
1111
1112     closeWindow();
1113     if (m_page)
1114         m_page->setParentInspectorController(0);
1115
1116     ASSERT(m_scriptContext && m_scriptObject);
1117     JSValueUnprotect(m_scriptContext, m_scriptObject);
1118
1119     m_page = 0;
1120     m_scriptObject = 0;
1121     m_scriptContext = 0;
1122 }
1123
1124 void InspectorController::showWindow()
1125 {
1126     ASSERT(enabled());
1127
1128     m_client->showWindow();
1129 }
1130
1131 void InspectorController::closeWindow()
1132 {
1133     stopDebugging();
1134     m_client->closeWindow();
1135 }
1136
1137 static void addHeaders(JSContextRef context, JSObjectRef object, const HTTPHeaderMap& headers, JSValueRef* exception)
1138 {
1139     ASSERT_ARG(context, context);
1140     ASSERT_ARG(object, object);
1141
1142     HTTPHeaderMap::const_iterator end = headers.end();
1143     for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) {
1144         JSValueRef value = JSValueMakeString(context, jsStringRef(it->second).get());
1145         JSObjectSetProperty(context, object, jsStringRef(it->first).get(), value, kJSPropertyAttributeNone, exception);
1146         if (exception && *exception)
1147             return;
1148     }
1149 }
1150
1151 static JSObjectRef scriptObjectForRequest(JSContextRef context, const InspectorResource* resource, JSValueRef* exception)
1152 {
1153     ASSERT_ARG(context, context);
1154
1155     JSObjectRef object = JSObjectMake(context, 0, 0);
1156     addHeaders(context, object, resource->requestHeaderFields, exception);
1157
1158     return object;
1159 }
1160
1161 static JSObjectRef scriptObjectForResponse(JSContextRef context, const InspectorResource* resource, JSValueRef* exception)
1162 {
1163     ASSERT_ARG(context, context);
1164
1165     JSObjectRef object = JSObjectMake(context, 0, 0);
1166     addHeaders(context, object, resource->responseHeaderFields, exception);
1167
1168     return object;
1169 }
1170
1171 JSObjectRef InspectorController::addScriptResource(InspectorResource* resource)
1172 {
1173     ASSERT_ARG(resource, resource);
1174
1175     ASSERT(m_scriptContext);
1176     ASSERT(m_scriptObject);
1177     if (!m_scriptContext || !m_scriptObject)
1178         return 0;
1179
1180     if (!resource->scriptObject) {
1181         JSValueRef exception = 0;
1182
1183         JSValueRef resourceProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("Resource").get(), &exception);
1184         if (HANDLE_EXCEPTION(exception))
1185             return 0;
1186
1187         JSObjectRef resourceConstructor = JSValueToObject(m_scriptContext, resourceProperty, &exception);
1188         if (HANDLE_EXCEPTION(exception))
1189             return 0;
1190
1191         JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.string()).get());
1192         JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.host()).get());
1193         JSValueRef pathValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.path()).get());
1194         JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.lastPathComponent()).get());
1195
1196         JSValueRef identifier = JSValueMakeNumber(m_scriptContext, resource->identifier);
1197         JSValueRef mainResource = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
1198         JSValueRef cached = JSValueMakeBoolean(m_scriptContext, resource->cached);
1199
1200         JSObjectRef scriptObject = scriptObjectForRequest(m_scriptContext, resource, &exception);
1201         if (HANDLE_EXCEPTION(exception))
1202             return 0;
1203
1204         JSValueRef arguments[] = { scriptObject, urlValue, domainValue, pathValue, lastPathComponentValue, identifier, mainResource, cached };
1205         JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, resourceConstructor, 8, arguments, &exception);
1206         if (HANDLE_EXCEPTION(exception))
1207             return 0;
1208
1209         ASSERT(result);
1210
1211         resource->setScriptObject(m_scriptContext, result);
1212     }
1213
1214     JSValueRef exception = 0;
1215
1216     JSValueRef addResourceProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("addResource").get(), &exception);
1217     if (HANDLE_EXCEPTION(exception))
1218         return 0;
1219
1220     JSObjectRef addResourceFunction = JSValueToObject(m_scriptContext, addResourceProperty, &exception);
1221     if (HANDLE_EXCEPTION(exception))
1222         return 0;
1223
1224     JSValueRef addArguments[] = { resource->scriptObject };
1225     JSObjectCallAsFunction(m_scriptContext, addResourceFunction, m_scriptObject, 1, addArguments, &exception);
1226     if (HANDLE_EXCEPTION(exception))
1227         return 0;
1228
1229     return resource->scriptObject;
1230 }
1231
1232 JSObjectRef InspectorController::addAndUpdateScriptResource(InspectorResource* resource)
1233 {
1234     ASSERT_ARG(resource, resource);
1235
1236     JSObjectRef scriptResource = addScriptResource(resource);
1237     if (!scriptResource)
1238         return 0;
1239
1240     updateScriptResourceResponse(resource);
1241     updateScriptResource(resource, resource->length);
1242     updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1243     updateScriptResource(resource, resource->finished, resource->failed);
1244     return scriptResource;
1245 }
1246
1247 void InspectorController::removeScriptResource(InspectorResource* resource)
1248 {
1249     ASSERT(m_scriptContext);
1250     ASSERT(m_scriptObject);
1251     if (!m_scriptContext || !m_scriptObject)
1252         return;
1253
1254     ASSERT(resource);
1255     ASSERT(resource->scriptObject);
1256     if (!resource || !resource->scriptObject)
1257         return;
1258
1259     JSObjectRef scriptObject = resource->scriptObject;
1260     resource->setScriptObject(0, 0);
1261
1262     JSValueRef exception = 0;
1263
1264     JSValueRef removeResourceProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("removeResource").get(), &exception);
1265     if (HANDLE_EXCEPTION(exception))
1266         return;
1267
1268     JSObjectRef removeResourceFunction = JSValueToObject(m_scriptContext, removeResourceProperty, &exception);
1269     if (HANDLE_EXCEPTION(exception))
1270         return;
1271
1272     JSValueRef arguments[] = { scriptObject };
1273     JSObjectCallAsFunction(m_scriptContext, removeResourceFunction, m_scriptObject, 1, arguments, &exception);
1274     HANDLE_EXCEPTION(exception);
1275 }
1276
1277 static void updateResourceRequest(InspectorResource* resource, const ResourceRequest& request)
1278 {
1279     resource->requestHeaderFields = request.httpHeaderFields();
1280     resource->requestURL = request.url();
1281 }
1282
1283 static void updateResourceResponse(InspectorResource* resource, const ResourceResponse& response)
1284 {
1285     resource->expectedContentLength = response.expectedContentLength();
1286     resource->mimeType = response.mimeType();
1287     resource->responseHeaderFields = response.httpHeaderFields();
1288     resource->responseStatusCode = response.httpStatusCode();
1289     resource->suggestedFilename = response.suggestedFilename();
1290 }
1291
1292 void InspectorController::updateScriptResourceRequest(InspectorResource* resource)
1293 {
1294     ASSERT(resource->scriptObject);
1295     ASSERT(m_scriptContext);
1296     if (!resource->scriptObject || !m_scriptContext)
1297         return;
1298
1299     JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.string()).get());
1300     JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.host()).get());
1301     JSValueRef pathValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.path()).get());
1302     JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.lastPathComponent()).get());
1303
1304     JSValueRef mainResourceValue = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
1305
1306     JSValueRef exception = 0;
1307
1308     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("url").get(), urlValue, kJSPropertyAttributeNone, &exception);
1309     if (HANDLE_EXCEPTION(exception))
1310         return;
1311
1312     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("domain").get(), domainValue, kJSPropertyAttributeNone, &exception);
1313     if (HANDLE_EXCEPTION(exception))
1314         return;
1315
1316     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("path").get(), pathValue, kJSPropertyAttributeNone, &exception);
1317     if (HANDLE_EXCEPTION(exception))
1318         return;
1319
1320     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("lastPathComponent").get(), lastPathComponentValue, kJSPropertyAttributeNone, &exception);
1321     if (HANDLE_EXCEPTION(exception))
1322         return;
1323
1324     JSObjectRef scriptObject = scriptObjectForRequest(m_scriptContext, resource, &exception);
1325     if (HANDLE_EXCEPTION(exception))
1326         return;
1327
1328     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("requestHeaders").get(), scriptObject, kJSPropertyAttributeNone, &exception);
1329     if (HANDLE_EXCEPTION(exception))
1330         return;
1331
1332     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("mainResource").get(), mainResourceValue, kJSPropertyAttributeNone, &exception);
1333     HANDLE_EXCEPTION(exception);
1334 }
1335
1336 void InspectorController::updateScriptResourceResponse(InspectorResource* resource)
1337 {
1338     ASSERT(resource->scriptObject);
1339     ASSERT(m_scriptContext);
1340     if (!resource->scriptObject || !m_scriptContext)
1341         return;
1342
1343     JSValueRef mimeTypeValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->mimeType).get());
1344
1345     JSValueRef suggestedFilenameValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->suggestedFilename).get());
1346
1347     JSValueRef expectedContentLengthValue = JSValueMakeNumber(m_scriptContext, static_cast<double>(resource->expectedContentLength));
1348     JSValueRef statusCodeValue = JSValueMakeNumber(m_scriptContext, resource->responseStatusCode);
1349
1350     JSValueRef exception = 0;
1351
1352     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("mimeType").get(), mimeTypeValue, kJSPropertyAttributeNone, &exception);
1353     if (HANDLE_EXCEPTION(exception))
1354         return;
1355
1356     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("suggestedFilename").get(), suggestedFilenameValue, kJSPropertyAttributeNone, &exception);
1357     if (HANDLE_EXCEPTION(exception))
1358         return;
1359
1360     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("expectedContentLength").get(), expectedContentLengthValue, kJSPropertyAttributeNone, &exception);
1361     if (HANDLE_EXCEPTION(exception))
1362         return;
1363
1364     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("statusCode").get(), statusCodeValue, kJSPropertyAttributeNone, &exception);
1365     if (HANDLE_EXCEPTION(exception))
1366         return;
1367
1368     JSObjectRef scriptObject = scriptObjectForResponse(m_scriptContext, resource, &exception);
1369     if (HANDLE_EXCEPTION(exception))
1370         return;
1371
1372     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("responseHeaders").get(), scriptObject, kJSPropertyAttributeNone, &exception);
1373     if (HANDLE_EXCEPTION(exception))
1374         return;
1375
1376     JSValueRef typeValue = JSValueMakeNumber(m_scriptContext, resource->type());
1377     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("type").get(), typeValue, kJSPropertyAttributeNone, &exception);
1378     HANDLE_EXCEPTION(exception);
1379 }
1380
1381 void InspectorController::updateScriptResource(InspectorResource* resource, int length)
1382 {
1383     ASSERT(resource->scriptObject);
1384     ASSERT(m_scriptContext);
1385     if (!resource->scriptObject || !m_scriptContext)
1386         return;
1387
1388     JSValueRef lengthValue = JSValueMakeNumber(m_scriptContext, length);
1389
1390     JSValueRef exception = 0;
1391
1392     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("contentLength").get(), lengthValue, kJSPropertyAttributeNone, &exception);
1393     HANDLE_EXCEPTION(exception);
1394 }
1395
1396 void InspectorController::updateScriptResource(InspectorResource* resource, bool finished, bool failed)
1397 {
1398     ASSERT(resource->scriptObject);
1399     ASSERT(m_scriptContext);
1400     if (!resource->scriptObject || !m_scriptContext)
1401         return;
1402
1403     JSValueRef failedValue = JSValueMakeBoolean(m_scriptContext, failed);
1404     JSValueRef finishedValue = JSValueMakeBoolean(m_scriptContext, finished);
1405
1406     JSValueRef exception = 0;
1407
1408     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("failed").get(), failedValue, kJSPropertyAttributeNone, &exception);
1409     if (HANDLE_EXCEPTION(exception))
1410         return;
1411
1412     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("finished").get(), finishedValue, kJSPropertyAttributeNone, &exception);
1413     HANDLE_EXCEPTION(exception);
1414 }
1415
1416 void InspectorController::updateScriptResource(InspectorResource* resource, double startTime, double responseReceivedTime, double endTime)
1417 {
1418     ASSERT(resource->scriptObject);
1419     ASSERT(m_scriptContext);
1420     if (!resource->scriptObject || !m_scriptContext)
1421         return;
1422
1423     JSValueRef startTimeValue = JSValueMakeNumber(m_scriptContext, startTime);
1424     JSValueRef responseReceivedTimeValue = JSValueMakeNumber(m_scriptContext, responseReceivedTime);
1425     JSValueRef endTimeValue = JSValueMakeNumber(m_scriptContext, endTime);
1426
1427     JSValueRef exception = 0;
1428
1429     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("startTime").get(), startTimeValue, kJSPropertyAttributeNone, &exception);
1430     if (HANDLE_EXCEPTION(exception))
1431         return;
1432
1433     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("responseReceivedTime").get(), responseReceivedTimeValue, kJSPropertyAttributeNone, &exception);
1434     if (HANDLE_EXCEPTION(exception))
1435         return;
1436
1437     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("endTime").get(), endTimeValue, kJSPropertyAttributeNone, &exception);
1438     HANDLE_EXCEPTION(exception);
1439 }
1440
1441 void InspectorController::populateScriptObjects()
1442 {
1443     ASSERT(m_scriptContext);
1444     if (!m_scriptContext)
1445         return;
1446
1447     ResourcesMap::iterator resourcesEnd = m_resources.end();
1448     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
1449         addAndUpdateScriptResource(it->second.get());
1450
1451     unsigned messageCount = m_consoleMessages.size();
1452     for (unsigned i = 0; i < messageCount; ++i)
1453         addScriptConsoleMessage(m_consoleMessages[i]);
1454
1455 #if ENABLE(DATABASE)
1456     DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
1457     for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
1458         addDatabaseScriptResource((*it).get());
1459 #endif
1460 }
1461
1462 #if ENABLE(DATABASE)
1463 JSObjectRef InspectorController::addDatabaseScriptResource(InspectorDatabaseResource* resource)
1464 {
1465     ASSERT_ARG(resource, resource);
1466
1467     if (resource->scriptObject)
1468         return resource->scriptObject;
1469
1470     ASSERT(m_scriptContext);
1471     ASSERT(m_scriptObject);
1472     if (!m_scriptContext || !m_scriptObject)
1473         return 0;
1474
1475     Frame* frame = resource->database->document()->frame();
1476     if (!frame)
1477         return 0;
1478
1479     JSValueRef exception = 0;
1480
1481     JSValueRef databaseProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("Database").get(), &exception);
1482     if (HANDLE_EXCEPTION(exception))
1483         return 0;
1484
1485     JSObjectRef databaseConstructor = JSValueToObject(m_scriptContext, databaseProperty, &exception);
1486     if (HANDLE_EXCEPTION(exception))
1487         return 0;
1488
1489     ExecState* exec = toJSDOMWindow(frame)->globalExec();
1490
1491     JSValueRef database;
1492
1493     {
1494         KJS::JSLock lock;
1495         database = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, resource->database.get())));
1496     }
1497
1498     JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->domain).get());
1499     JSValueRef nameValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->name).get());
1500     JSValueRef versionValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->version).get());
1501
1502     JSValueRef arguments[] = { database, domainValue, nameValue, versionValue };
1503     JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, databaseConstructor, 4, arguments, &exception);
1504     if (HANDLE_EXCEPTION(exception))
1505         return 0;
1506
1507     ASSERT(result);
1508
1509     JSValueRef addDatabaseProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("addDatabase").get(), &exception);
1510     if (HANDLE_EXCEPTION(exception))
1511         return 0;
1512
1513     JSObjectRef addDatabaseFunction = JSValueToObject(m_scriptContext, addDatabaseProperty, &exception);
1514     if (HANDLE_EXCEPTION(exception))
1515         return 0;
1516
1517     JSValueRef addArguments[] = { result };
1518     JSObjectCallAsFunction(m_scriptContext, addDatabaseFunction, m_scriptObject, 1, addArguments, &exception);
1519     if (HANDLE_EXCEPTION(exception))
1520         return 0;
1521
1522     resource->setScriptObject(m_scriptContext, result);
1523
1524     return result;
1525 }
1526
1527 void InspectorController::removeDatabaseScriptResource(InspectorDatabaseResource* resource)
1528 {
1529     ASSERT(m_scriptContext);
1530     ASSERT(m_scriptObject);
1531     if (!m_scriptContext || !m_scriptObject)
1532         return;
1533
1534     ASSERT(resource);
1535     ASSERT(resource->scriptObject);
1536     if (!resource || !resource->scriptObject)
1537         return;
1538
1539     JSObjectRef scriptObject = resource->scriptObject;
1540     resource->setScriptObject(0, 0);
1541
1542     JSValueRef exception = 0;
1543
1544     JSValueRef removeDatabaseProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("removeDatabase").get(), &exception);
1545     if (HANDLE_EXCEPTION(exception))
1546         return;
1547
1548     JSObjectRef removeDatabaseFunction = JSValueToObject(m_scriptContext, removeDatabaseProperty, &exception);
1549     if (HANDLE_EXCEPTION(exception))
1550         return;
1551
1552     JSValueRef arguments[] = { scriptObject };
1553     JSObjectCallAsFunction(m_scriptContext, removeDatabaseFunction, m_scriptObject, 1, arguments, &exception);
1554     HANDLE_EXCEPTION(exception);
1555 }
1556 #endif
1557
1558 void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message)
1559 {
1560     ASSERT_ARG(message, message);
1561
1562     JSValueRef exception = 0;
1563
1564     JSValueRef messageConstructorProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("ConsoleMessage").get(), &exception);
1565     if (HANDLE_EXCEPTION(exception))
1566         return;
1567
1568     JSObjectRef messageConstructor = JSValueToObject(m_scriptContext, messageConstructorProperty, &exception);
1569     if (HANDLE_EXCEPTION(exception))
1570         return;
1571
1572     JSValueRef addMessageProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("addMessageToConsole").get(), &exception);
1573     if (HANDLE_EXCEPTION(exception))
1574         return;
1575
1576     JSObjectRef addMessage = JSValueToObject(m_scriptContext, addMessageProperty, &exception);
1577     if (HANDLE_EXCEPTION(exception))
1578         return;
1579
1580     JSValueRef sourceValue = JSValueMakeNumber(m_scriptContext, message->source);
1581     JSValueRef levelValue = JSValueMakeNumber(m_scriptContext, message->level);
1582     JSValueRef lineValue = JSValueMakeNumber(m_scriptContext, message->line);
1583     JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(message->url).get());
1584
1585     static const unsigned maximumMessageArguments = 256;
1586     JSValueRef arguments[maximumMessageArguments];
1587     unsigned argumentCount = 0;
1588     arguments[argumentCount++] = sourceValue;
1589     arguments[argumentCount++] = levelValue;
1590     arguments[argumentCount++] = lineValue;
1591     arguments[argumentCount++] = urlValue;
1592
1593     if (!message->wrappedArguments.isEmpty()) {
1594         unsigned remainingSpaceInArguments = maximumMessageArguments - argumentCount;
1595         unsigned argumentsToAdd = min(remainingSpaceInArguments, static_cast<unsigned>(message->wrappedArguments.size()));
1596         for (unsigned i = 0; i < argumentsToAdd; ++i)
1597             arguments[argumentCount++] = toRef(message->wrappedArguments[i]);
1598     } else {
1599         JSValueRef messageValue = JSValueMakeString(m_scriptContext, jsStringRef(message->message).get());
1600         arguments[argumentCount++] = messageValue;
1601     }
1602
1603     JSObjectRef messageObject = JSObjectCallAsConstructor(m_scriptContext, messageConstructor, argumentCount, arguments, &exception);
1604     if (HANDLE_EXCEPTION(exception))
1605         return;
1606
1607     JSObjectCallAsFunction(m_scriptContext, addMessage, m_scriptObject, 1, &messageObject, &exception);
1608     HANDLE_EXCEPTION(exception);
1609 }
1610
1611 void InspectorController::resetScriptObjects()
1612 {
1613     if (!m_scriptContext || !m_scriptObject)
1614         return;
1615
1616     ResourcesMap::iterator resourcesEnd = m_resources.end();
1617     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
1618         InspectorResource* resource = it->second.get();
1619         resource->setScriptObject(0, 0);
1620     }
1621
1622 #if ENABLE(DATABASE)
1623     DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
1624     for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) {
1625         InspectorDatabaseResource* resource = (*it).get();
1626         resource->setScriptObject(0, 0);
1627     }
1628 #endif
1629
1630     callSimpleFunction(m_scriptContext, m_scriptObject, "reset");
1631 }
1632
1633 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
1634 {
1635     ASSERT_ARG(resourceMap, resourceMap);
1636
1637     ResourcesMap mapCopy(*resourceMap);
1638     ResourcesMap::iterator end = mapCopy.end();
1639     for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
1640         InspectorResource* resource = (*it).second.get();
1641         if (resource == m_mainResource)
1642             continue;
1643
1644         if (!loaderToKeep || resource->loader != loaderToKeep) {
1645             removeResource(resource);
1646             if (windowVisible() && resource->scriptObject)
1647                 removeScriptResource(resource);
1648         }
1649     }
1650 }
1651
1652 void InspectorController::didCommitLoad(DocumentLoader* loader)
1653 {
1654     if (!enabled())
1655         return;
1656
1657     if (loader->frame() == m_inspectedPage->mainFrame()) {
1658         m_client->inspectedURLChanged(loader->url().string());
1659
1660         deleteAllValues(m_consoleMessages);
1661         m_consoleMessages.clear();
1662
1663 #if ENABLE(DATABASE)
1664         m_databaseResources.clear();
1665 #endif
1666
1667         if (windowVisible()) {
1668             resetScriptObjects();
1669
1670             if (!loader->isLoadingFromCachedPage()) {
1671                 ASSERT(m_mainResource && m_mainResource->loader == loader);
1672                 // We don't add the main resource until its load is committed. This is
1673                 // needed to keep the load for a user-entered URL from showing up in the
1674                 // list of resources for the page they are navigating away from.
1675                 addAndUpdateScriptResource(m_mainResource.get());
1676             } else {
1677                 // Pages loaded from the page cache are committed before
1678                 // m_mainResource is the right resource for this load, so we
1679                 // clear it here. It will be re-assigned in
1680                 // identifierForInitialRequest.
1681                 m_mainResource = 0;
1682             }
1683         }
1684     }
1685
1686     for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
1687         if (ResourcesMap* resourceMap = m_frameResources.get(frame))
1688             pruneResources(resourceMap, loader);
1689 }
1690
1691 void InspectorController::frameDetachedFromParent(Frame* frame)
1692 {
1693     if (!enabled())
1694         return;
1695     if (ResourcesMap* resourceMap = m_frameResources.get(frame))
1696         removeAllResources(resourceMap);
1697 }
1698
1699 void InspectorController::addResource(InspectorResource* resource)
1700 {
1701     m_resources.set(resource->identifier, resource);
1702
1703     Frame* frame = resource->frame.get();
1704     ResourcesMap* resourceMap = m_frameResources.get(frame);
1705     if (resourceMap)
1706         resourceMap->set(resource->identifier, resource);
1707     else {
1708         resourceMap = new ResourcesMap;
1709         resourceMap->set(resource->identifier, resource);
1710         m_frameResources.set(frame, resourceMap);
1711     }
1712 }
1713
1714 void InspectorController::removeResource(InspectorResource* resource)
1715 {
1716     m_resources.remove(resource->identifier);
1717
1718     Frame* frame = resource->frame.get();
1719     ResourcesMap* resourceMap = m_frameResources.get(frame);
1720     if (!resourceMap) {
1721         ASSERT_NOT_REACHED();
1722         return;
1723     }
1724
1725     resourceMap->remove(resource->identifier);
1726     if (resourceMap->isEmpty()) {
1727         m_frameResources.remove(frame);
1728         delete resourceMap;
1729     }
1730 }
1731
1732 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse& response, int length)
1733 {
1734     if (!enabled())
1735         return;
1736
1737     RefPtr<InspectorResource> resource = InspectorResource::create(m_nextIdentifier--, loader, loader->frame());
1738     resource->finished = true;
1739
1740     updateResourceRequest(resource.get(), request);
1741     updateResourceResponse(resource.get(), response);
1742
1743     resource->length = length;
1744     resource->cached = true;
1745     resource->startTime = currentTime();
1746     resource->responseReceivedTime = resource->startTime;
1747     resource->endTime = resource->startTime;
1748
1749     if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
1750         m_mainResource = resource;
1751
1752     addResource(resource.get());
1753
1754     if (windowVisible())
1755         addAndUpdateScriptResource(resource.get());
1756 }
1757
1758 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
1759 {
1760     if (!enabled())
1761         return;
1762
1763     RefPtr<InspectorResource> resource = InspectorResource::create(identifier, loader, loader->frame());
1764
1765     updateResourceRequest(resource.get(), request);
1766
1767     if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
1768         m_mainResource = resource;
1769
1770     addResource(resource.get());
1771
1772     if (windowVisible() && loader->isLoadingFromCachedPage() && resource == m_mainResource)
1773         addAndUpdateScriptResource(resource.get());
1774 }
1775
1776 void InspectorController::willSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
1777 {
1778     if (!enabled())
1779         return;
1780
1781     InspectorResource* resource = m_resources.get(identifier).get();
1782     if (!resource)
1783         return;
1784
1785     resource->startTime = currentTime();
1786
1787     if (!redirectResponse.isNull()) {
1788         updateResourceRequest(resource, request);
1789         updateResourceResponse(resource, redirectResponse);
1790     }
1791
1792     if (resource != m_mainResource && windowVisible()) {
1793         if (!resource->scriptObject)
1794             addScriptResource(resource);
1795         else
1796             updateScriptResourceRequest(resource);
1797
1798         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1799
1800         if (!redirectResponse.isNull())
1801             updateScriptResourceResponse(resource);
1802     }
1803 }
1804
1805 void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse& response)
1806 {
1807     if (!enabled())
1808         return;
1809
1810     InspectorResource* resource = m_resources.get(identifier).get();
1811     if (!resource)
1812         return;
1813
1814     updateResourceResponse(resource, response);
1815
1816     resource->responseReceivedTime = currentTime();
1817
1818     if (windowVisible() && resource->scriptObject) {
1819         updateScriptResourceResponse(resource);
1820         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1821     }
1822 }
1823
1824 void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived)
1825 {
1826     if (!enabled())
1827         return;
1828
1829     InspectorResource* resource = m_resources.get(identifier).get();
1830     if (!resource)
1831         return;
1832
1833     resource->length += lengthReceived;
1834
1835     if (windowVisible() && resource->scriptObject)
1836         updateScriptResource(resource, resource->length);
1837 }
1838
1839 void InspectorController::didFinishLoading(DocumentLoader* loader, unsigned long identifier)
1840 {
1841     if (!enabled())
1842         return;
1843
1844     RefPtr<InspectorResource> resource = m_resources.get(identifier);
1845     if (!resource)
1846         return;
1847
1848     removeResource(resource.get());
1849
1850     resource->finished = true;
1851     resource->endTime = currentTime();
1852
1853     addResource(resource.get());
1854
1855     if (windowVisible() && resource->scriptObject) {
1856         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
1857         updateScriptResource(resource.get(), resource->finished);
1858     }
1859 }
1860
1861 void InspectorController::didFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& /*error*/)
1862 {
1863     if (!enabled())
1864         return;
1865
1866     RefPtr<InspectorResource> resource = m_resources.get(identifier);
1867     if (!resource)
1868         return;
1869
1870     removeResource(resource.get());
1871
1872     resource->finished = true;
1873     resource->failed = true;
1874     resource->endTime = currentTime();
1875
1876     addResource(resource.get());
1877
1878     if (windowVisible() && resource->scriptObject) {
1879         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
1880         updateScriptResource(resource.get(), resource->finished, resource->failed);
1881     }
1882 }
1883
1884 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, KJS::UString& sourceString)
1885 {
1886     if (!enabled())
1887         return;
1888
1889     InspectorResource* resource = m_resources.get(identifier).get();
1890     if (!resource)
1891         return;
1892
1893     resource->setXMLHttpRequestProperties(sourceString);
1894 }
1895
1896
1897 #if ENABLE(DATABASE)
1898 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
1899 {
1900     if (!enabled())
1901         return;
1902
1903     RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
1904
1905     m_databaseResources.add(resource);
1906
1907     if (windowVisible())
1908         addDatabaseScriptResource(resource.get());
1909 }
1910 #endif
1911
1912 void InspectorController::moveWindowBy(float x, float y) const
1913 {
1914     if (!m_page || !enabled())
1915         return;
1916
1917     FloatRect frameRect = m_page->chrome()->windowRect();
1918     frameRect.move(x, y);
1919     m_page->chrome()->setWindowRect(frameRect);
1920 }
1921
1922 void InspectorController::startDebuggingAndReloadInspectedPage()
1923 {
1924     JavaScriptDebugServer::shared().addListener(this, m_inspectedPage);
1925     m_debuggerAttached = true;
1926     m_inspectedPage->mainFrame()->loader()->reload();
1927 }
1928
1929 void InspectorController::stopDebugging()
1930 {
1931     JavaScriptDebugServer::shared().removeListener(this, m_inspectedPage);
1932     m_debuggerAttached = false;
1933 }
1934
1935 static void drawOutlinedRect(GraphicsContext& context, const IntRect& rect, const Color& fillColor)
1936 {
1937     static const int outlineThickness = 1;
1938     static const Color outlineColor(62, 86, 180, 228);
1939
1940     IntRect outline = rect;
1941     outline.inflate(outlineThickness);
1942
1943     context.clearRect(outline);
1944
1945     context.save();
1946     context.clipOut(rect);
1947     context.fillRect(outline, outlineColor);
1948     context.restore();
1949
1950     context.fillRect(rect, fillColor);
1951 }
1952
1953 static void drawHighlightForBoxes(GraphicsContext& context, const Vector<IntRect>& lineBoxRects, const IntRect& contentBox, const IntRect& paddingBox, const IntRect& borderBox, const IntRect& marginBox)
1954 {
1955     static const Color contentBoxColor(125, 173, 217, 128);
1956     static const Color paddingBoxColor(125, 173, 217, 160);
1957     static const Color borderBoxColor(125, 173, 217, 192);
1958     static const Color marginBoxColor(125, 173, 217, 228);
1959
1960     if (!lineBoxRects.isEmpty()) {
1961         for (size_t i = 0; i < lineBoxRects.size(); ++i)
1962             drawOutlinedRect(context, lineBoxRects[i], contentBoxColor);
1963         return;
1964     }
1965
1966     if (marginBox != borderBox)
1967         drawOutlinedRect(context, marginBox, marginBoxColor);
1968     if (borderBox != paddingBox)
1969         drawOutlinedRect(context, borderBox, borderBoxColor);
1970     if (paddingBox != contentBox)
1971         drawOutlinedRect(context, paddingBox, paddingBoxColor);
1972     drawOutlinedRect(context, contentBox, contentBoxColor);
1973 }
1974
1975 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
1976 {
1977     if (!m_highlightedNode)
1978         return;
1979
1980     RenderObject* renderer = m_highlightedNode->renderer();
1981     if (!renderer)
1982         return;
1983
1984     IntRect contentBox = renderer->absoluteContentBox();
1985     // FIXME: Should we add methods to RenderObject to obtain these rects?
1986     IntRect paddingBox(contentBox.x() - renderer->paddingLeft(), contentBox.y() - renderer->paddingTop(), contentBox.width() + renderer->paddingLeft() + renderer->paddingRight(), contentBox.height() + renderer->paddingTop() + renderer->paddingBottom());
1987     IntRect borderBox(paddingBox.x() - renderer->borderLeft(), paddingBox.y() - renderer->borderTop(), paddingBox.width() + renderer->borderLeft() + renderer->borderRight(), paddingBox.height() + renderer->borderTop() + renderer->borderBottom());
1988     IntRect marginBox(borderBox.x() - renderer->marginLeft(), borderBox.y() - renderer->marginTop(), borderBox.width() + renderer->marginLeft() + renderer->marginRight(), borderBox.height() + renderer->marginTop() + renderer->marginBottom());
1989
1990     IntRect boundingBox = renderer->absoluteBoundingBoxRect();
1991
1992     Vector<IntRect> lineBoxRects;
1993     if (renderer->isInline() || (renderer->isText() && !m_highlightedNode->isSVGElement())) {
1994         // FIXME: We should show margins/padding/border for inlines.
1995         renderer->addLineBoxRects(lineBoxRects);
1996     }
1997     if (lineBoxRects.isEmpty() && contentBox.isEmpty()) {
1998         // If we have no line boxes and our content box is empty, we'll just draw our bounding box.
1999         // This can happen, e.g., with an <a> enclosing an <img style="float:right">.
2000         // FIXME: Can we make this better/more accurate? The <a> in the above case has no
2001         // width/height but the highlight makes it appear to be the size of the <img>.
2002         lineBoxRects.append(boundingBox);
2003     }
2004
2005     FrameView* view = m_inspectedPage->mainFrame()->view();
2006     FloatRect overlayRect = view->visibleContentRect();
2007
2008     if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect))) {
2009         Element* element;
2010         if (m_highlightedNode->isElementNode())
2011             element = static_cast<Element*>(m_highlightedNode.get());
2012         else
2013             element = static_cast<Element*>(m_highlightedNode->parent());
2014         element->scrollIntoViewIfNeeded();
2015         overlayRect = view->visibleContentRect();
2016     }
2017
2018     context.translate(-overlayRect.x(), -overlayRect.y());
2019
2020     drawHighlightForBoxes(context, lineBoxRects, contentBox, paddingBox, borderBox, marginBox);
2021 }
2022
2023 bool InspectorController::handleException(JSValueRef exception, unsigned lineNumber) const
2024 {
2025     if (!exception)
2026         return false;
2027
2028     if (!m_page)
2029         return true;
2030
2031     JSRetainPtr<JSStringRef> messageString(Adopt, JSValueToStringCopy(m_scriptContext, exception, 0));
2032     String message(JSStringGetCharactersPtr(messageString.get()), JSStringGetLength(messageString.get()));
2033
2034     m_page->mainFrame()->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, __FILE__);
2035     return true;
2036 }
2037
2038 #pragma mark -
2039 #pragma mark JavaScriptDebugListener functions
2040
2041 void InspectorController::didParseSource(ExecState*, const UString& /*source*/, int /*startingLineNumber*/, const UString& /*sourceURL*/, int /*sourceID*/)
2042 {
2043 }
2044
2045 void InspectorController::failedToParseSource(ExecState*, const UString& /*source*/, int /*startingLineNumber*/, const UString& /*sourceURL*/, int /*errorLine*/, const UString& /*errorMessage*/)
2046 {
2047 }
2048
2049 void InspectorController::didEnterCallFrame(ExecState*, int /*sourceID*/, int /*lineNumber*/)
2050 {
2051 }
2052
2053 void InspectorController::willExecuteStatement(ExecState*, int /*sourceID*/, int /*lineNumber*/)
2054 {
2055 }
2056
2057 void InspectorController::willLeaveCallFrame(ExecState*, int /*sourceID*/, int /*lineNumber*/)
2058 {
2059 }
2060
2061 void InspectorController::exceptionWasRaised(ExecState*, int /*sourceID*/, int /*lineNumber*/)
2062 {
2063 }
2064
2065 } // namespace WebCore