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