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