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