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