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