3884c38aa34a0327ee2e4975a9f2deba12db5aa1
[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 localizedStrings(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     String url = controller->localizedStringsURL();
754     if (url.isNull())
755         return JSValueMakeNull(ctx);
756
757     return JSValueMakeString(ctx, jsStringRef(url).get());
758 }
759
760 static JSValueRef platform(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
761 {
762 #if PLATFORM(MAC)
763 #ifdef BUILDING_ON_TIGER
764     static const String platform = "mac-tiger";
765 #else
766     static const String platform = "mac-leopard";
767 #endif
768 #elif PLATFORM(WIN_OS)
769     static const String platform = "windows";
770 #elif PLATFORM(QT)
771     static const String platform = "qt";
772 #elif PLATFORM(GTK)
773     static const String platform = "gtk";
774 #elif PLATFORM(WX)
775     static const String platform = "wx";
776 #else
777     static const String platform = "unknown";
778 #endif
779
780     JSValueRef platformValue = JSValueMakeString(ctx, jsStringRef(platform).get());
781
782     return platformValue;
783 }
784
785 static JSValueRef moveByUnrestricted(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
786 {
787     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
788     if (!controller)
789         return JSValueMakeUndefined(ctx);
790
791     if (argumentCount < 2)
792         return JSValueMakeUndefined(ctx);
793
794     double x = JSValueToNumber(ctx, arguments[0], exception);
795     if (exception && *exception)
796         return JSValueMakeUndefined(ctx);
797
798     double y = JSValueToNumber(ctx, arguments[1], exception);
799     if (exception && *exception)
800         return JSValueMakeUndefined(ctx);
801
802     controller->moveWindowBy(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y));
803
804     return JSValueMakeUndefined(ctx);
805 }
806
807 static JSValueRef setAttachedWindowHeight(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
808 {
809     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
810     if (!controller)
811         return JSValueMakeUndefined(ctx);
812
813     if (argumentCount < 1)
814         return JSValueMakeUndefined(ctx);
815
816     unsigned height = static_cast<unsigned>(JSValueToNumber(ctx, arguments[0], exception));
817     if (exception && *exception)
818         return JSValueMakeUndefined(ctx);
819
820     controller->setAttachedWindowHeight(height);
821
822     return JSValueMakeUndefined(ctx);
823 }
824
825 static JSValueRef wrapCallback(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
826 {
827     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
828     if (!controller)
829         return JSValueMakeUndefined(ctx);
830
831     if (argumentCount < 1)
832         return JSValueMakeUndefined(ctx);
833
834     JSLock lock(false);
835     return toRef(JSInspectorCallbackWrapper::wrap(toJS(ctx), toJS(arguments[0])));
836 }
837
838 #if ENABLE(JAVASCRIPT_DEBUGGER)
839 static JSValueRef currentCallFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/)
840 {
841     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
842     if (!controller)
843         return JSValueMakeUndefined(ctx);
844
845     JavaScriptCallFrame* callFrame = controller->currentCallFrame();
846     if (!callFrame || !callFrame->isValid())
847         return JSValueMakeNull(ctx);
848
849     ExecState* globalExec = callFrame->scopeChain()->globalObject()->globalExec();
850
851     JSLock lock(false);
852     return toRef(JSInspectedObjectWrapper::wrap(globalExec, toJS(toJS(ctx), callFrame)));
853 }
854
855 static JSValueRef setPauseOnExceptions(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
856 {
857     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
858     if (!controller)
859         return JSValueMakeUndefined(ctx);
860
861     if (argumentCount < 1)
862         return JSValueMakeUndefined(ctx);
863
864     controller->setPauseOnExceptions(JSValueToBoolean(ctx, arguments[0]));
865
866     return JSValueMakeUndefined(ctx);
867 }
868
869 static JSValueRef addBreakpoint(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
870 {
871     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
872     if (!controller)
873         return JSValueMakeUndefined(ctx);
874
875     if (argumentCount < 2)
876         return JSValueMakeUndefined(ctx);
877
878     double sourceID = JSValueToNumber(ctx, arguments[0], exception);
879     if (exception && *exception)
880         return JSValueMakeUndefined(ctx);
881
882     double lineNumber = JSValueToNumber(ctx, arguments[1], exception);
883     if (exception && *exception)
884         return JSValueMakeUndefined(ctx);
885
886     controller->addBreakpoint(static_cast<int>(sourceID), static_cast<unsigned>(lineNumber));
887
888     return JSValueMakeUndefined(ctx);
889 }
890
891 static JSValueRef removeBreakpoint(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
892 {
893     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
894     if (!controller)
895         return JSValueMakeUndefined(ctx);
896
897     if (argumentCount < 2)
898         return JSValueMakeUndefined(ctx);
899
900     double sourceID = JSValueToNumber(ctx, arguments[0], exception);
901     if (exception && *exception)
902         return JSValueMakeUndefined(ctx);
903
904     double lineNumber = JSValueToNumber(ctx, arguments[1], exception);
905     if (exception && *exception)
906         return JSValueMakeUndefined(ctx);
907
908     controller->removeBreakpoint(static_cast<int>(sourceID), static_cast<unsigned>(lineNumber));
909
910     return JSValueMakeUndefined(ctx);
911 }
912 #endif
913
914 static JSValueRef profiles(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* exception)
915 {
916     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
917     if (!controller)
918         return JSValueMakeUndefined(ctx);
919
920     JSLock lock(false);
921
922     const Vector<RefPtr<Profile> >& profiles = controller->profiles();
923
924     JSObjectRef global = JSContextGetGlobalObject(ctx);
925
926     JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception);
927     if (exception && *exception)
928         return JSValueMakeUndefined(ctx);
929
930     JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception);
931     if (exception && *exception)
932         return JSValueMakeUndefined(ctx);
933
934     JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception);
935     if (exception && *exception)
936         return JSValueMakeUndefined(ctx);
937
938     JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception);
939     if (exception && *exception)
940         return JSValueMakeUndefined(ctx);
941
942     JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception);
943     if (exception && *exception)
944         return JSValueMakeUndefined(ctx);
945
946     for (size_t i = 0; i < profiles.size(); ++i) {
947         JSValueRef arg0 = toRef(toJS(toJS(ctx), profiles[i].get()));
948         JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception);
949         if (exception && *exception)
950             return JSValueMakeUndefined(ctx);
951     }
952
953     return result;
954 }
955
956 // InspectorController Class
957
958 InspectorController::InspectorController(Page* page, InspectorClient* client)
959     : m_inspectedPage(page)
960     , m_client(client)
961     , m_page(0)
962     , m_scriptObject(0)
963     , m_controllerScriptObject(0)
964     , m_scriptContext(0)
965     , m_windowVisible(false)
966 #if ENABLE(JAVASCRIPT_DEBUGGER)
967     , m_debuggerAttached(false)
968     , m_attachDebuggerWhenShown(false)
969 #endif
970     , m_recordingUserInitiatedProfile(false)
971     , m_showAfterVisible(ElementsPanel)
972     , m_nextIdentifier(-2)
973     , m_groupLevel(0)
974     , m_searchingForNode(false)
975     , m_currentUserInitiatedProfileNumber(-1)
976     , m_nextUserInitiatedProfileNumber(1)
977     , m_previousMessage(0)
978 {
979     ASSERT_ARG(page, page);
980     ASSERT_ARG(client, client);
981 }
982
983 InspectorController::~InspectorController()
984 {
985     m_client->inspectorDestroyed();
986
987     if (m_scriptContext) {
988         JSValueRef exception = 0;
989
990         JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
991         JSValueRef controllerProperty = JSObjectGetProperty(m_scriptContext, global, jsStringRef("InspectorController").get(), &exception);
992         if (!HANDLE_EXCEPTION(m_scriptContext, exception)) {
993             if (JSObjectRef controller = JSValueToObject(m_scriptContext, controllerProperty, &exception)) {
994                 if (!HANDLE_EXCEPTION(m_scriptContext, exception))
995                     JSObjectSetPrivate(controller, 0);
996             }
997         }
998     }
999
1000     if (m_page)
1001         m_page->setParentInspectorController(0);
1002
1003     // m_inspectedPage should have been cleared in inspectedPageDestroyed().
1004     ASSERT(!m_inspectedPage);
1005
1006     deleteAllValues(m_frameResources);
1007     deleteAllValues(m_consoleMessages);
1008 }
1009
1010 void InspectorController::inspectedPageDestroyed()
1011 {
1012     close();
1013
1014     ASSERT(m_inspectedPage);
1015     m_inspectedPage = 0;
1016 }
1017
1018 bool InspectorController::enabled() const
1019 {
1020     if (!m_inspectedPage)
1021         return false;
1022
1023     return m_inspectedPage->settings()->developerExtrasEnabled();
1024 }
1025
1026 String InspectorController::localizedStringsURL()
1027 {
1028     if (!enabled())
1029         return String();
1030     return m_client->localizedStringsURL();
1031 }
1032
1033 // Trying to inspect something in a frame with JavaScript disabled would later lead to
1034 // crashes trying to create JavaScript wrappers. Some day we could fix this issue, but
1035 // for now prevent crashes here by never targeting a node in such a frame.
1036 static bool canPassNodeToJavaScript(Node* node)
1037 {
1038     if (!node)
1039         return false;
1040     Frame* frame = node->document()->frame();
1041     return frame && frame->script()->isEnabled();
1042 }
1043
1044 void InspectorController::inspect(Node* node)
1045 {
1046     if (!canPassNodeToJavaScript(node) || !enabled())
1047         return;
1048
1049     show();
1050
1051     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
1052         node = node->parentNode();
1053     m_nodeToFocus = node;
1054
1055     if (!m_scriptObject) {
1056         m_showAfterVisible = ElementsPanel;
1057         return;
1058     }
1059
1060     if (windowVisible())
1061         focusNode();
1062 }
1063
1064 void InspectorController::focusNode()
1065 {
1066     if (!enabled())
1067         return;
1068
1069     ASSERT(m_scriptContext);
1070     ASSERT(m_scriptObject);
1071     ASSERT(m_nodeToFocus);
1072
1073     Frame* frame = m_nodeToFocus->document()->frame();
1074     if (!frame)
1075         return;
1076
1077     ExecState* exec = toJSDOMWindow(frame)->globalExec();
1078
1079     JSValueRef arg0;
1080
1081     {
1082         JSC::JSLock lock(false);
1083         arg0 = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, m_nodeToFocus.get())));
1084     }
1085
1086     m_nodeToFocus = 0;
1087
1088     JSValueRef exception = 0;
1089     callFunction(m_scriptContext, m_scriptObject, "updateFocusedNode", 1, &arg0, exception);
1090 }
1091
1092 void InspectorController::highlight(Node* node)
1093 {
1094     if (!enabled())
1095         return;
1096     ASSERT_ARG(node, node);
1097     m_highlightedNode = node;
1098     m_client->highlight(node);
1099 }
1100
1101 void InspectorController::hideHighlight()
1102 {
1103     if (!enabled())
1104         return;
1105     m_client->hideHighlight();
1106 }
1107
1108 bool InspectorController::windowVisible()
1109 {
1110     return m_windowVisible;
1111 }
1112
1113 void InspectorController::setWindowVisible(bool visible, bool attached)
1114 {
1115     if (visible == m_windowVisible)
1116         return;
1117
1118     m_windowVisible = visible;
1119
1120     if (!m_scriptContext || !m_scriptObject)
1121         return;
1122
1123     if (m_windowVisible) {
1124         setAttachedWindow(attached);
1125         populateScriptObjects();
1126         if (m_nodeToFocus)
1127             focusNode();
1128 #if ENABLE(JAVASCRIPT_DEBUGGER)
1129         if (m_attachDebuggerWhenShown)
1130             startDebugging();
1131 #endif
1132         if (m_showAfterVisible != CurrentPanel)
1133             showPanel(m_showAfterVisible);
1134     } else {
1135 #if ENABLE(JAVASCRIPT_DEBUGGER)
1136         stopDebugging();
1137 #endif
1138         resetScriptObjects();
1139     }
1140
1141     m_showAfterVisible = CurrentPanel;
1142 }
1143
1144 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, ExecState* exec, const ArgList& arguments, unsigned lineNumber, const String& sourceURL)
1145 {
1146     if (!enabled())
1147         return;
1148
1149     addConsoleMessage(exec, new ConsoleMessage(source, level, exec, arguments, lineNumber, sourceURL, m_groupLevel));
1150 }
1151
1152 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
1153 {
1154     if (!enabled())
1155         return;
1156
1157     addConsoleMessage(0, new ConsoleMessage(source, level, message, lineNumber, sourceID, m_groupLevel));
1158 }
1159
1160 void InspectorController::addConsoleMessage(ExecState* exec, ConsoleMessage* consoleMessage)
1161 {
1162     ASSERT(enabled());
1163     ASSERT_ARG(consoleMessage, consoleMessage);
1164
1165     if (m_previousMessage && m_previousMessage->isEqual(exec, consoleMessage)) {
1166         ++m_previousMessage->repeatCount;
1167         delete consoleMessage;
1168     } else {
1169         m_previousMessage = consoleMessage;
1170         m_consoleMessages.append(consoleMessage);
1171     }
1172
1173     if (windowVisible())
1174         addScriptConsoleMessage(m_previousMessage);
1175 }
1176
1177 void InspectorController::clearConsoleMessages()
1178 {
1179     deleteAllValues(m_consoleMessages);
1180     m_consoleMessages.clear();
1181     m_previousMessage = 0;
1182     m_groupLevel = 0;
1183 }
1184
1185 void InspectorController::toggleRecordButton(bool isProfiling)
1186 {
1187     if (!m_scriptContext)
1188         return;
1189
1190     JSValueRef exception = 0;
1191     JSValueRef isProvingValue = JSValueMakeBoolean(m_scriptContext, isProfiling);
1192     callFunction(m_scriptContext, m_scriptObject, "setRecordingProfile", 1, &isProvingValue, exception);
1193 }
1194
1195 void InspectorController::startGroup(MessageSource source, ExecState* exec, const ArgList& arguments, unsigned lineNumber, const String& sourceURL)
1196 {    
1197     ++m_groupLevel;
1198
1199     addConsoleMessage(exec, new ConsoleMessage(source, StartGroupMessageLevel, exec, arguments, lineNumber, sourceURL, m_groupLevel));
1200 }
1201
1202 void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL)
1203 {
1204     if (m_groupLevel == 0)
1205         return;
1206
1207     --m_groupLevel;
1208
1209     addConsoleMessage(0, new ConsoleMessage(source, EndGroupMessageLevel, String(), lineNumber, sourceURL, m_groupLevel));
1210 }
1211
1212 void InspectorController::addProfile(PassRefPtr<Profile> prpProfile, unsigned lineNumber, const UString& sourceURL)
1213 {
1214     if (!enabled())
1215         return;
1216
1217     RefPtr<Profile> profile = prpProfile;
1218     m_profiles.append(profile);
1219
1220     if (windowVisible())
1221         addScriptProfile(profile.get());
1222
1223     addProfileMessageToConsole(profile, lineNumber, sourceURL);
1224 }
1225
1226 void InspectorController::addProfileMessageToConsole(PassRefPtr<Profile> prpProfile, unsigned lineNumber, const UString& sourceURL)
1227 {
1228     RefPtr<Profile> profile = prpProfile;
1229
1230     UString message = "Profile \"webkit-profile://";
1231     message += encodeWithURLEscapeSequences(profile->title());
1232     message += "/";
1233     message += UString::from(profile->uid());
1234     message += "\" finished.";
1235     addMessageToConsole(JSMessageSource, LogMessageLevel, message, lineNumber, sourceURL);
1236 }
1237
1238 void InspectorController::attachWindow()
1239 {
1240     if (!enabled())
1241         return;
1242     m_client->attachWindow();
1243 }
1244
1245 void InspectorController::detachWindow()
1246 {
1247     if (!enabled())
1248         return;
1249     m_client->detachWindow();
1250 }
1251
1252 void InspectorController::setAttachedWindow(bool attached)
1253 {
1254     if (!enabled() || !m_scriptContext || !m_scriptObject)
1255         return;
1256
1257     JSValueRef attachedValue = JSValueMakeBoolean(m_scriptContext, attached);
1258
1259     JSValueRef exception = 0;
1260     callFunction(m_scriptContext, m_scriptObject, "setAttachedWindow", 1, &attachedValue, exception);
1261 }
1262
1263 void InspectorController::setAttachedWindowHeight(unsigned height)
1264 {
1265     if (!enabled())
1266         return;
1267     m_client->setAttachedWindowHeight(height);
1268 }
1269
1270 void InspectorController::toggleSearchForNodeInPage()
1271 {
1272     if (!enabled())
1273         return;
1274
1275     m_searchingForNode = !m_searchingForNode;
1276     if (!m_searchingForNode)
1277         hideHighlight();
1278 }
1279
1280 void InspectorController::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags)
1281 {
1282     if (!enabled() || !m_searchingForNode)
1283         return;
1284
1285     Node* node = result.innerNode();
1286     if (node)
1287         highlight(node);
1288 }
1289
1290 void InspectorController::handleMousePressOnNode(Node* node)
1291 {
1292     if (!enabled())
1293         return;
1294
1295     ASSERT(m_searchingForNode);
1296     ASSERT(node);
1297     if (!node)
1298         return;
1299
1300     // inspect() will implicitly call ElementsPanel's focusedNodeChanged() and the hover feedback will be stopped there.
1301     inspect(node);
1302 }
1303
1304 void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame)
1305 {
1306     if (!enabled() || !m_scriptContext || !m_scriptObject)
1307         return;
1308
1309     JSDOMWindow* win = toJSDOMWindow(frame);
1310     ExecState* exec = win->globalExec();
1311
1312     JSValueRef arg0;
1313
1314     {
1315         JSC::JSLock lock(false);
1316         arg0 = toRef(JSInspectedObjectWrapper::wrap(exec, win));
1317     }
1318
1319     JSValueRef exception = 0;
1320     callFunction(m_scriptContext, m_scriptObject, "inspectedWindowCleared", 1, &arg0, exception);
1321 }
1322
1323 void InspectorController::windowScriptObjectAvailable()
1324 {
1325     if (!m_page || !enabled())
1326         return;
1327
1328     m_scriptContext = toRef(m_page->mainFrame()->script()->globalObject()->globalExec());
1329
1330     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
1331     ASSERT(global);
1332
1333     static JSStaticFunction staticFunctions[] = {
1334         // SIMPLE_INSPECTOR_CALLBACK
1335         { "hideDOMNodeHighlight", WebCore::hideDOMNodeHighlight, kJSPropertyAttributeNone },
1336         { "loaded", WebCore::loaded, kJSPropertyAttributeNone },
1337         { "windowUnloading", WebCore::unloading, kJSPropertyAttributeNone },
1338         { "attach", WebCore::attach, kJSPropertyAttributeNone },
1339         { "detach", WebCore::detach, kJSPropertyAttributeNone },
1340 #if ENABLE(JAVASCRIPT_DEBUGGER)
1341         { "startDebugging", WebCore::startDebugging, kJSPropertyAttributeNone },
1342         { "stopDebugging", WebCore::stopDebugging, kJSPropertyAttributeNone },
1343         { "pauseInDebugger", WebCore::pauseInDebugger, kJSPropertyAttributeNone },
1344         { "resumeDebugger", WebCore::resumeDebugger, kJSPropertyAttributeNone },
1345         { "stepOverStatementInDebugger", WebCore::stepOverStatementInDebugger, kJSPropertyAttributeNone },
1346         { "stepIntoStatementInDebugger", WebCore::stepIntoStatementInDebugger, kJSPropertyAttributeNone },
1347         { "stepOutOfFunctionInDebugger", WebCore::stepOutOfFunctionInDebugger, kJSPropertyAttributeNone },
1348 #endif
1349         { "closeWindow", WebCore::closeWindow, kJSPropertyAttributeNone },
1350         { "clearMessages", WebCore::clearMessages, kJSPropertyAttributeNone },
1351         { "startProfiling", WebCore::startProfiling, kJSPropertyAttributeNone },
1352         { "stopProfiling", WebCore::stopProfiling, kJSPropertyAttributeNone },
1353         { "toggleNodeSearch", WebCore::toggleNodeSearch, kJSPropertyAttributeNone },
1354
1355         // BOOL_INSPECTOR_CALLBACK
1356 #if ENABLE(JAVASCRIPT_DEBUGGER)
1357         { "debuggerAttached", WebCore::debuggerAttached, kJSPropertyAttributeNone },
1358         { "pauseOnExceptions", WebCore::pauseOnExceptions, kJSPropertyAttributeNone },
1359 #endif
1360         { "isWindowVisible", WebCore::isWindowVisible, kJSPropertyAttributeNone },
1361         { "searchingForNode", WebCore::searchingForNode, kJSPropertyAttributeNone },
1362
1363         // Custom callbacks
1364         { "addResourceSourceToFrame", WebCore::addResourceSourceToFrame, kJSPropertyAttributeNone },
1365         { "addSourceToFrame", WebCore::addSourceToFrame, kJSPropertyAttributeNone },
1366         { "getResourceDocumentNode", WebCore::getResourceDocumentNode, kJSPropertyAttributeNone },
1367         { "highlightDOMNode", WebCore::highlightDOMNode, kJSPropertyAttributeNone },
1368         { "search", WebCore::search, kJSPropertyAttributeNone },
1369 #if ENABLE(DATABASE)
1370         { "databaseTableNames", WebCore::databaseTableNames, kJSPropertyAttributeNone },
1371 #endif
1372         { "inspectedWindow", WebCore::inspectedWindow, kJSPropertyAttributeNone },
1373         { "localizedStringsURL", WebCore::localizedStrings, kJSPropertyAttributeNone },
1374         { "platform", WebCore::platform, kJSPropertyAttributeNone },
1375         { "moveByUnrestricted", WebCore::moveByUnrestricted, kJSPropertyAttributeNone },
1376         { "setAttachedWindowHeight", WebCore::setAttachedWindowHeight, kJSPropertyAttributeNone },
1377         { "wrapCallback", WebCore::wrapCallback, kJSPropertyAttributeNone },
1378 #if ENABLE(JAVASCRIPT_DEBUGGER)
1379         { "currentCallFrame", WebCore::currentCallFrame, kJSPropertyAttributeNone },
1380         { "setPauseOnExceptions", WebCore::setPauseOnExceptions, kJSPropertyAttributeNone },
1381         { "addBreakpoint", WebCore::addBreakpoint, kJSPropertyAttributeNone },
1382         { "removeBreakpoint", WebCore::removeBreakpoint, kJSPropertyAttributeNone },
1383 #endif
1384         { "profiles", WebCore::profiles, kJSPropertyAttributeNone },
1385         { 0, 0, 0 }
1386     };
1387
1388     JSClassDefinition inspectorControllerDefinition = {
1389         0, kJSClassAttributeNone, "InspectorController", 0, 0, staticFunctions,
1390         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1391     };
1392
1393     JSClassRef controllerClass = JSClassCreate(&inspectorControllerDefinition);
1394     ASSERT(controllerClass);
1395
1396     m_controllerScriptObject = JSObjectMake(m_scriptContext, controllerClass, reinterpret_cast<void*>(this));
1397     ASSERT(m_controllerScriptObject);
1398
1399     JSObjectSetProperty(m_scriptContext, global, jsStringRef("InspectorController").get(), m_controllerScriptObject, kJSPropertyAttributeNone, 0);
1400 }
1401
1402 void InspectorController::scriptObjectReady()
1403 {
1404     ASSERT(m_scriptContext);
1405     if (!m_scriptContext)
1406         return;
1407
1408     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
1409     ASSERT(global);
1410
1411     JSValueRef exception = 0;
1412
1413     JSValueRef inspectorValue = JSObjectGetProperty(m_scriptContext, global, jsStringRef("WebInspector").get(), &exception);
1414     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1415         return;
1416
1417     ASSERT(inspectorValue);
1418     if (!inspectorValue)
1419         return;
1420
1421     m_scriptObject = JSValueToObject(m_scriptContext, inspectorValue, &exception);
1422     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1423         return;
1424
1425     ASSERT(m_scriptObject);
1426
1427     JSValueProtect(m_scriptContext, m_scriptObject);
1428
1429     // Make sure our window is visible now that the page loaded
1430     showWindow();
1431 }
1432
1433 void InspectorController::show()
1434 {
1435     if (!enabled())
1436         return;
1437
1438     if (!m_page) {
1439         m_page = m_client->createPage();
1440         if (!m_page)
1441             return;
1442         m_page->setParentInspectorController(this);
1443
1444         // showWindow() will be called after the page loads in scriptObjectReady()
1445         return;
1446     }
1447
1448     showWindow();
1449 }
1450
1451 void InspectorController::showPanel(SpecialPanels panel)
1452 {
1453     if (!enabled())
1454         return;
1455
1456     show();
1457
1458     if (!m_scriptObject) {
1459         m_showAfterVisible = panel;
1460         return;
1461     }
1462
1463     if (panel == CurrentPanel)
1464         return;
1465
1466     const char* showFunctionName;
1467     switch (panel) {
1468         case ConsolePanel:
1469             showFunctionName = "showConsole";
1470             break;
1471         case DatabasesPanel:
1472             showFunctionName = "showDatabasesPanel";
1473             break;
1474         case ElementsPanel:
1475             showFunctionName = "showElementsPanel";
1476             break;
1477         case ProfilesPanel:
1478             showFunctionName = "showProfilesPanel";
1479             break;
1480         case ResourcesPanel:
1481             showFunctionName = "showResourcesPanel";
1482             break;
1483         case ScriptsPanel:
1484             showFunctionName = "showScriptsPanel";
1485             break;
1486         default:
1487             ASSERT_NOT_REACHED();
1488             showFunctionName = 0;
1489     }
1490
1491     if (showFunctionName)
1492         callSimpleFunction(m_scriptContext, m_scriptObject, showFunctionName);
1493 }
1494
1495 void InspectorController::close()
1496 {
1497     if (!enabled())
1498         return;
1499
1500     stopUserInitiatedProfiling();
1501 #if ENABLE(JAVASCRIPT_DEBUGGER)
1502     stopDebugging();
1503 #endif
1504     closeWindow();
1505
1506     if (m_scriptContext && m_scriptObject)
1507         JSValueUnprotect(m_scriptContext, m_scriptObject);
1508
1509     m_scriptObject = 0;
1510     m_scriptContext = 0;
1511 }
1512
1513 void InspectorController::showWindow()
1514 {
1515     ASSERT(enabled());
1516     m_client->showWindow();
1517 }
1518
1519 void InspectorController::closeWindow()
1520 {
1521     m_client->closeWindow();
1522 }
1523
1524 void InspectorController::startUserInitiatedProfiling()
1525 {
1526     if (!enabled())
1527         return;
1528
1529     m_recordingUserInitiatedProfile = true;
1530
1531     ExecState* exec = toJSDOMWindow(m_inspectedPage->mainFrame())->globalExec();
1532     m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
1533     UString title = UserInitiatedProfileName;
1534     title += ".";
1535     title += UString::from(m_currentUserInitiatedProfileNumber);
1536     Profiler::profiler()->startProfiling(exec, title);
1537     toggleRecordButton(true);
1538 }
1539
1540 void InspectorController::stopUserInitiatedProfiling()
1541 {
1542     if (!enabled())
1543         return;
1544
1545     m_recordingUserInitiatedProfile = false;
1546
1547     ExecState* exec = toJSDOMWindow(m_inspectedPage->mainFrame())->globalExec();
1548     UString title =  UserInitiatedProfileName;
1549     title += ".";
1550     title += UString::from(m_currentUserInitiatedProfileNumber);
1551     RefPtr<Profile> profile = Profiler::profiler()->stopProfiling(exec, title);
1552     if (profile)
1553         addProfile(profile, 0, UString());
1554     toggleRecordButton(false);
1555 }
1556
1557
1558 static void addHeaders(JSContextRef context, JSObjectRef object, const HTTPHeaderMap& headers, JSValueRef* exception)
1559 {
1560     ASSERT_ARG(context, context);
1561     ASSERT_ARG(object, object);
1562
1563     HTTPHeaderMap::const_iterator end = headers.end();
1564     for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) {
1565         JSValueRef value = JSValueMakeString(context, jsStringRef(it->second).get());
1566         JSObjectSetProperty(context, object, jsStringRef(it->first).get(), value, kJSPropertyAttributeNone, exception);
1567         if (exception && *exception)
1568             return;
1569     }
1570 }
1571
1572 static JSObjectRef scriptObjectForRequest(JSContextRef context, const InspectorResource* resource, JSValueRef* exception)
1573 {
1574     ASSERT_ARG(context, context);
1575
1576     JSObjectRef object = JSObjectMake(context, 0, 0);
1577     addHeaders(context, object, resource->requestHeaderFields, exception);
1578
1579     return object;
1580 }
1581
1582 static JSObjectRef scriptObjectForResponse(JSContextRef context, const InspectorResource* resource, JSValueRef* exception)
1583 {
1584     ASSERT_ARG(context, context);
1585
1586     JSObjectRef object = JSObjectMake(context, 0, 0);
1587     addHeaders(context, object, resource->responseHeaderFields, exception);
1588
1589     return object;
1590 }
1591
1592 JSObjectRef InspectorController::addScriptResource(InspectorResource* resource)
1593 {
1594     ASSERT_ARG(resource, resource);
1595
1596     ASSERT(m_scriptContext);
1597     ASSERT(m_scriptObject);
1598     if (!m_scriptContext || !m_scriptObject)
1599         return 0;
1600
1601     if (!resource->scriptObject) {
1602         JSValueRef exception = 0;
1603
1604         JSValueRef resourceProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("Resource").get(), &exception);
1605         if (HANDLE_EXCEPTION(m_scriptContext, exception))
1606             return 0;
1607
1608         JSObjectRef resourceConstructor = JSValueToObject(m_scriptContext, resourceProperty, &exception);
1609         if (HANDLE_EXCEPTION(m_scriptContext, exception))
1610             return 0;
1611
1612         JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.string()).get());
1613         JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.host()).get());
1614         JSValueRef pathValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.path()).get());
1615         JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.lastPathComponent()).get());
1616
1617         JSValueRef identifier = JSValueMakeNumber(m_scriptContext, resource->identifier);
1618         JSValueRef mainResource = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
1619         JSValueRef cached = JSValueMakeBoolean(m_scriptContext, resource->cached);
1620
1621         JSObjectRef scriptObject = scriptObjectForRequest(m_scriptContext, resource, &exception);
1622         if (HANDLE_EXCEPTION(m_scriptContext, exception))
1623             return 0;
1624
1625         JSValueRef arguments[] = { scriptObject, urlValue, domainValue, pathValue, lastPathComponentValue, identifier, mainResource, cached };
1626         JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, resourceConstructor, 8, arguments, &exception);
1627         if (HANDLE_EXCEPTION(m_scriptContext, exception))
1628             return 0;
1629
1630         ASSERT(result);
1631
1632         resource->setScriptObject(m_scriptContext, result);
1633     }
1634
1635     JSValueRef exception = 0;
1636     callFunction(m_scriptContext, m_scriptObject, "addResource", 1, &resource->scriptObject, exception);
1637
1638     if (exception)
1639         return 0;
1640
1641     return resource->scriptObject;
1642 }
1643
1644 JSObjectRef InspectorController::addAndUpdateScriptResource(InspectorResource* resource)
1645 {
1646     ASSERT_ARG(resource, resource);
1647
1648     JSObjectRef scriptResource = addScriptResource(resource);
1649     if (!scriptResource)
1650         return 0;
1651
1652     updateScriptResourceResponse(resource);
1653     updateScriptResource(resource, resource->length);
1654     updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1655     updateScriptResource(resource, resource->finished, resource->failed);
1656     return scriptResource;
1657 }
1658
1659 void InspectorController::removeScriptResource(InspectorResource* resource)
1660 {
1661     ASSERT(m_scriptContext);
1662     ASSERT(m_scriptObject);
1663     if (!m_scriptContext || !m_scriptObject)
1664         return;
1665
1666     ASSERT(resource);
1667     ASSERT(resource->scriptObject);
1668     if (!resource || !resource->scriptObject)
1669         return;
1670
1671     JSObjectRef scriptObject = resource->scriptObject;
1672     resource->setScriptObject(0, 0);
1673
1674     JSValueRef exception = 0;
1675     callFunction(m_scriptContext, m_scriptObject, "removeResource", 1, &scriptObject, exception);
1676 }
1677
1678 static void updateResourceRequest(InspectorResource* resource, const ResourceRequest& request)
1679 {
1680     resource->requestHeaderFields = request.httpHeaderFields();
1681     resource->requestURL = request.url();
1682 }
1683
1684 static void updateResourceResponse(InspectorResource* resource, const ResourceResponse& response)
1685 {
1686     resource->expectedContentLength = response.expectedContentLength();
1687     resource->mimeType = response.mimeType();
1688     resource->responseHeaderFields = response.httpHeaderFields();
1689     resource->responseStatusCode = response.httpStatusCode();
1690     resource->suggestedFilename = response.suggestedFilename();
1691 }
1692
1693 void InspectorController::updateScriptResourceRequest(InspectorResource* resource)
1694 {
1695     ASSERT(resource->scriptObject);
1696     ASSERT(m_scriptContext);
1697     if (!resource->scriptObject || !m_scriptContext)
1698         return;
1699
1700     JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.string()).get());
1701     JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.host()).get());
1702     JSValueRef pathValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.path()).get());
1703     JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->requestURL.lastPathComponent()).get());
1704
1705     JSValueRef mainResourceValue = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
1706
1707     JSValueRef exception = 0;
1708
1709     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("url").get(), urlValue, kJSPropertyAttributeNone, &exception);
1710     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1711         return;
1712
1713     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("domain").get(), domainValue, kJSPropertyAttributeNone, &exception);
1714     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1715         return;
1716
1717     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("path").get(), pathValue, kJSPropertyAttributeNone, &exception);
1718     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1719         return;
1720
1721     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("lastPathComponent").get(), lastPathComponentValue, kJSPropertyAttributeNone, &exception);
1722     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1723         return;
1724
1725     JSObjectRef scriptObject = scriptObjectForRequest(m_scriptContext, resource, &exception);
1726     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1727         return;
1728
1729     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("requestHeaders").get(), scriptObject, kJSPropertyAttributeNone, &exception);
1730     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1731         return;
1732
1733     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("mainResource").get(), mainResourceValue, kJSPropertyAttributeNone, &exception);
1734     HANDLE_EXCEPTION(m_scriptContext, exception);
1735 }
1736
1737 void InspectorController::updateScriptResourceResponse(InspectorResource* resource)
1738 {
1739     ASSERT(resource->scriptObject);
1740     ASSERT(m_scriptContext);
1741     if (!resource->scriptObject || !m_scriptContext)
1742         return;
1743
1744     JSValueRef mimeTypeValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->mimeType).get());
1745
1746     JSValueRef suggestedFilenameValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->suggestedFilename).get());
1747
1748     JSValueRef expectedContentLengthValue = JSValueMakeNumber(m_scriptContext, static_cast<double>(resource->expectedContentLength));
1749     JSValueRef statusCodeValue = JSValueMakeNumber(m_scriptContext, resource->responseStatusCode);
1750
1751     JSValueRef exception = 0;
1752
1753     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("mimeType").get(), mimeTypeValue, kJSPropertyAttributeNone, &exception);
1754     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1755         return;
1756
1757     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("suggestedFilename").get(), suggestedFilenameValue, kJSPropertyAttributeNone, &exception);
1758     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1759         return;
1760
1761     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("expectedContentLength").get(), expectedContentLengthValue, kJSPropertyAttributeNone, &exception);
1762     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1763         return;
1764
1765     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("statusCode").get(), statusCodeValue, kJSPropertyAttributeNone, &exception);
1766     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1767         return;
1768
1769     JSObjectRef scriptObject = scriptObjectForResponse(m_scriptContext, resource, &exception);
1770     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1771         return;
1772
1773     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("responseHeaders").get(), scriptObject, kJSPropertyAttributeNone, &exception);
1774     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1775         return;
1776
1777     updateScriptResourceType(resource);
1778 }
1779
1780 void InspectorController::updateScriptResourceType(InspectorResource* resource)
1781 {
1782     ASSERT(resource->scriptObject);
1783     ASSERT(m_scriptContext);
1784     if (!resource->scriptObject || !m_scriptContext)
1785         return;
1786
1787     JSValueRef exception = 0;
1788
1789     JSValueRef typeValue = JSValueMakeNumber(m_scriptContext, resource->type());
1790     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("type").get(), typeValue, kJSPropertyAttributeNone, &exception);
1791     HANDLE_EXCEPTION(m_scriptContext, exception);
1792 }
1793
1794 void InspectorController::updateScriptResource(InspectorResource* resource, int length)
1795 {
1796     ASSERT(resource->scriptObject);
1797     ASSERT(m_scriptContext);
1798     if (!resource->scriptObject || !m_scriptContext)
1799         return;
1800
1801     JSValueRef lengthValue = JSValueMakeNumber(m_scriptContext, length);
1802
1803     JSValueRef exception = 0;
1804
1805     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("contentLength").get(), lengthValue, kJSPropertyAttributeNone, &exception);
1806     HANDLE_EXCEPTION(m_scriptContext, exception);
1807 }
1808
1809 void InspectorController::updateScriptResource(InspectorResource* resource, bool finished, bool failed)
1810 {
1811     ASSERT(resource->scriptObject);
1812     ASSERT(m_scriptContext);
1813     if (!resource->scriptObject || !m_scriptContext)
1814         return;
1815
1816     JSValueRef failedValue = JSValueMakeBoolean(m_scriptContext, failed);
1817     JSValueRef finishedValue = JSValueMakeBoolean(m_scriptContext, finished);
1818
1819     JSValueRef exception = 0;
1820
1821     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("failed").get(), failedValue, kJSPropertyAttributeNone, &exception);
1822     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1823         return;
1824
1825     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("finished").get(), finishedValue, kJSPropertyAttributeNone, &exception);
1826     HANDLE_EXCEPTION(m_scriptContext, exception);
1827 }
1828
1829 void InspectorController::updateScriptResource(InspectorResource* resource, double startTime, double responseReceivedTime, double endTime)
1830 {
1831     ASSERT(resource->scriptObject);
1832     ASSERT(m_scriptContext);
1833     if (!resource->scriptObject || !m_scriptContext)
1834         return;
1835
1836     JSValueRef startTimeValue = JSValueMakeNumber(m_scriptContext, startTime);
1837     JSValueRef responseReceivedTimeValue = JSValueMakeNumber(m_scriptContext, responseReceivedTime);
1838     JSValueRef endTimeValue = JSValueMakeNumber(m_scriptContext, endTime);
1839
1840     JSValueRef exception = 0;
1841
1842     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("startTime").get(), startTimeValue, kJSPropertyAttributeNone, &exception);
1843     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1844         return;
1845
1846     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("responseReceivedTime").get(), responseReceivedTimeValue, kJSPropertyAttributeNone, &exception);
1847     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1848         return;
1849
1850     JSObjectSetProperty(m_scriptContext, resource->scriptObject, jsStringRef("endTime").get(), endTimeValue, kJSPropertyAttributeNone, &exception);
1851     HANDLE_EXCEPTION(m_scriptContext, exception);
1852 }
1853
1854 void InspectorController::populateScriptObjects()
1855 {
1856     ASSERT(m_scriptContext);
1857     if (!m_scriptContext)
1858         return;
1859
1860     ResourcesMap::iterator resourcesEnd = m_resources.end();
1861     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
1862         addAndUpdateScriptResource(it->second.get());
1863
1864     unsigned messageCount = m_consoleMessages.size();
1865     for (unsigned i = 0; i < messageCount; ++i)
1866         addScriptConsoleMessage(m_consoleMessages[i]);
1867
1868 #if ENABLE(DATABASE)
1869     DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
1870     for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
1871         addDatabaseScriptResource((*it).get());
1872 #endif
1873
1874     callSimpleFunction(m_scriptContext, m_scriptObject, "populateInterface");
1875 }
1876
1877 #if ENABLE(DATABASE)
1878 JSObjectRef InspectorController::addDatabaseScriptResource(InspectorDatabaseResource* resource)
1879 {
1880     ASSERT_ARG(resource, resource);
1881
1882     if (resource->scriptObject)
1883         return resource->scriptObject;
1884
1885     ASSERT(m_scriptContext);
1886     ASSERT(m_scriptObject);
1887     if (!m_scriptContext || !m_scriptObject)
1888         return 0;
1889
1890     Frame* frame = resource->database->document()->frame();
1891     if (!frame)
1892         return 0;
1893
1894     JSValueRef exception = 0;
1895
1896     JSValueRef databaseProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("Database").get(), &exception);
1897     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1898         return 0;
1899
1900     JSObjectRef databaseConstructor = JSValueToObject(m_scriptContext, databaseProperty, &exception);
1901     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1902         return 0;
1903
1904     ExecState* exec = toJSDOMWindow(frame)->globalExec();
1905
1906     JSValueRef database;
1907
1908     {
1909         JSC::JSLock lock(false);
1910         database = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, resource->database.get())));
1911     }
1912
1913     JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->domain).get());
1914     JSValueRef nameValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->name).get());
1915     JSValueRef versionValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->version).get());
1916
1917     JSValueRef arguments[] = { database, domainValue, nameValue, versionValue };
1918     JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, databaseConstructor, 4, arguments, &exception);
1919     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1920         return 0;
1921
1922     ASSERT(result);
1923
1924     callFunction(m_scriptContext, m_scriptObject, "addDatabase", 1, &result, exception);
1925
1926     if (exception)
1927         return 0;
1928
1929     resource->setScriptObject(m_scriptContext, result);
1930
1931     return result;
1932 }
1933
1934 void InspectorController::removeDatabaseScriptResource(InspectorDatabaseResource* resource)
1935 {
1936     ASSERT(m_scriptContext);
1937     ASSERT(m_scriptObject);
1938     if (!m_scriptContext || !m_scriptObject)
1939         return;
1940
1941     ASSERT(resource);
1942     ASSERT(resource->scriptObject);
1943     if (!resource || !resource->scriptObject)
1944         return;
1945
1946     JSObjectRef scriptObject = resource->scriptObject;
1947     resource->setScriptObject(0, 0);
1948
1949     JSValueRef exception = 0;
1950     callFunction(m_scriptContext, m_scriptObject, "removeDatabase", 1, &scriptObject, exception);
1951 }
1952 #endif
1953
1954 void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message)
1955 {
1956     ASSERT_ARG(message, message);
1957
1958     JSValueRef exception = 0;
1959
1960     JSValueRef messageConstructorProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("ConsoleMessage").get(), &exception);
1961     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1962         return;
1963
1964     JSObjectRef messageConstructor = JSValueToObject(m_scriptContext, messageConstructorProperty, &exception);
1965     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1966         return;
1967
1968     JSValueRef sourceValue = JSValueMakeNumber(m_scriptContext, message->source);
1969     JSValueRef levelValue = JSValueMakeNumber(m_scriptContext, message->level);
1970     JSValueRef lineValue = JSValueMakeNumber(m_scriptContext, message->line);
1971     JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(message->url).get());
1972     JSValueRef groupLevelValue = JSValueMakeNumber(m_scriptContext, message->groupLevel);
1973     JSValueRef repeatCountValue = JSValueMakeNumber(m_scriptContext, message->repeatCount);
1974
1975     static const unsigned maximumMessageArguments = 256;
1976     JSValueRef arguments[maximumMessageArguments];
1977     unsigned argumentCount = 0;
1978     arguments[argumentCount++] = sourceValue;
1979     arguments[argumentCount++] = levelValue;
1980     arguments[argumentCount++] = lineValue;
1981     arguments[argumentCount++] = urlValue;
1982     arguments[argumentCount++] = groupLevelValue;
1983     arguments[argumentCount++] = repeatCountValue;
1984
1985     if (!message->wrappedArguments.isEmpty()) {
1986         unsigned remainingSpaceInArguments = maximumMessageArguments - argumentCount;
1987         unsigned argumentsToAdd = min(remainingSpaceInArguments, static_cast<unsigned>(message->wrappedArguments.size()));
1988         for (unsigned i = 0; i < argumentsToAdd; ++i)
1989             arguments[argumentCount++] = toRef(message->wrappedArguments[i]);
1990     } else {
1991         JSValueRef messageValue = JSValueMakeString(m_scriptContext, jsStringRef(message->message).get());
1992         arguments[argumentCount++] = messageValue;
1993     }
1994
1995     JSObjectRef messageObject = JSObjectCallAsConstructor(m_scriptContext, messageConstructor, argumentCount, arguments, &exception);
1996     if (HANDLE_EXCEPTION(m_scriptContext, exception))
1997         return;
1998
1999     callFunction(m_scriptContext, m_scriptObject, "addMessageToConsole", 1, &messageObject, exception);
2000 }
2001
2002 void InspectorController::addScriptProfile(Profile* profile)
2003 {
2004     JSLock lock(false);
2005     JSValueRef exception = 0;
2006     JSValueRef profileObject = toRef(toJS(toJS(m_scriptContext), profile));
2007     callFunction(m_scriptContext, m_scriptObject, "addProfile", 1, &profileObject, exception);
2008 }
2009
2010 void InspectorController::resetScriptObjects()
2011 {
2012     if (!m_scriptContext || !m_scriptObject)
2013         return;
2014
2015     ResourcesMap::iterator resourcesEnd = m_resources.end();
2016     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
2017         InspectorResource* resource = it->second.get();
2018         resource->setScriptObject(0, 0);
2019     }
2020
2021 #if ENABLE(DATABASE)
2022     DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
2023     for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) {
2024         InspectorDatabaseResource* resource = (*it).get();
2025         resource->setScriptObject(0, 0);
2026     }
2027 #endif
2028
2029     callSimpleFunction(m_scriptContext, m_scriptObject, "reset");
2030 }
2031
2032 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
2033 {
2034     ASSERT_ARG(resourceMap, resourceMap);
2035
2036     ResourcesMap mapCopy(*resourceMap);
2037     ResourcesMap::iterator end = mapCopy.end();
2038     for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
2039         InspectorResource* resource = (*it).second.get();
2040         if (resource == m_mainResource)
2041             continue;
2042
2043         if (!loaderToKeep || resource->loader != loaderToKeep) {
2044             removeResource(resource);
2045             if (windowVisible() && resource->scriptObject)
2046                 removeScriptResource(resource);
2047         }
2048     }
2049 }
2050
2051 void InspectorController::didCommitLoad(DocumentLoader* loader)
2052 {
2053     if (!enabled())
2054         return;
2055
2056     ASSERT(m_inspectedPage);
2057
2058     if (loader->frame() == m_inspectedPage->mainFrame()) {
2059         m_client->inspectedURLChanged(loader->url().string());
2060
2061         clearConsoleMessages();
2062
2063         m_times.clear();
2064         m_counts.clear();
2065         m_profiles.clear();
2066
2067 #if ENABLE(DATABASE)
2068         m_databaseResources.clear();
2069 #endif
2070
2071         if (windowVisible()) {
2072             resetScriptObjects();
2073
2074             if (!loader->isLoadingFromCachedPage()) {
2075                 ASSERT(m_mainResource && m_mainResource->loader == loader);
2076                 // We don't add the main resource until its load is committed. This is
2077                 // needed to keep the load for a user-entered URL from showing up in the
2078                 // list of resources for the page they are navigating away from.
2079                 addAndUpdateScriptResource(m_mainResource.get());
2080             } else {
2081                 // Pages loaded from the page cache are committed before
2082                 // m_mainResource is the right resource for this load, so we
2083                 // clear it here. It will be re-assigned in
2084                 // identifierForInitialRequest.
2085                 m_mainResource = 0;
2086             }
2087         }
2088     }
2089
2090     for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
2091         if (ResourcesMap* resourceMap = m_frameResources.get(frame))
2092             pruneResources(resourceMap, loader);
2093 }
2094
2095 void InspectorController::frameDetachedFromParent(Frame* frame)
2096 {
2097     if (!enabled())
2098         return;
2099     if (ResourcesMap* resourceMap = m_frameResources.get(frame))
2100         removeAllResources(resourceMap);
2101 }
2102
2103 void InspectorController::addResource(InspectorResource* resource)
2104 {
2105     m_resources.set(resource->identifier, resource);
2106     m_knownResources.add(resource->requestURL.string());
2107
2108     Frame* frame = resource->frame.get();
2109     ResourcesMap* resourceMap = m_frameResources.get(frame);
2110     if (resourceMap)
2111         resourceMap->set(resource->identifier, resource);
2112     else {
2113         resourceMap = new ResourcesMap;
2114         resourceMap->set(resource->identifier, resource);
2115         m_frameResources.set(frame, resourceMap);
2116     }
2117 }
2118
2119 void InspectorController::removeResource(InspectorResource* resource)
2120 {
2121     m_resources.remove(resource->identifier);
2122     m_knownResources.remove(resource->requestURL.string());
2123
2124     Frame* frame = resource->frame.get();
2125     ResourcesMap* resourceMap = m_frameResources.get(frame);
2126     if (!resourceMap) {
2127         ASSERT_NOT_REACHED();
2128         return;
2129     }
2130
2131     resourceMap->remove(resource->identifier);
2132     if (resourceMap->isEmpty()) {
2133         m_frameResources.remove(frame);
2134         delete resourceMap;
2135     }
2136 }
2137
2138 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse& response, int length)
2139 {
2140     if (!enabled())
2141         return;
2142
2143     // If the resource URL is already known, we don't need to add it again since this is just a cached load.
2144     if (m_knownResources.contains(request.url().string()))
2145         return;
2146
2147     RefPtr<InspectorResource> resource = InspectorResource::create(m_nextIdentifier--, loader, loader->frame());
2148     resource->finished = true;
2149
2150     updateResourceRequest(resource.get(), request);
2151     updateResourceResponse(resource.get(), response);
2152
2153     resource->length = length;
2154     resource->cached = true;
2155     resource->startTime = currentTime();
2156     resource->responseReceivedTime = resource->startTime;
2157     resource->endTime = resource->startTime;
2158
2159     ASSERT(m_inspectedPage);
2160
2161     if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
2162         m_mainResource = resource;
2163
2164     addResource(resource.get());
2165
2166     if (windowVisible())
2167         addAndUpdateScriptResource(resource.get());
2168 }
2169
2170 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
2171 {
2172     if (!enabled())
2173         return;
2174
2175     RefPtr<InspectorResource> resource = InspectorResource::create(identifier, loader, loader->frame());
2176
2177     updateResourceRequest(resource.get(), request);
2178
2179     ASSERT(m_inspectedPage);
2180
2181     if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
2182         m_mainResource = resource;
2183
2184     addResource(resource.get());
2185
2186     if (windowVisible() && loader->isLoadingFromCachedPage() && resource == m_mainResource)
2187         addAndUpdateScriptResource(resource.get());
2188 }
2189
2190 void InspectorController::willSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
2191 {
2192     if (!enabled())
2193         return;
2194
2195     InspectorResource* resource = m_resources.get(identifier).get();
2196     if (!resource)
2197         return;
2198
2199     resource->startTime = currentTime();
2200
2201     if (!redirectResponse.isNull()) {
2202         updateResourceRequest(resource, request);
2203         updateResourceResponse(resource, redirectResponse);
2204     }
2205
2206     if (resource != m_mainResource && windowVisible()) {
2207         if (!resource->scriptObject)
2208             addScriptResource(resource);
2209         else
2210             updateScriptResourceRequest(resource);
2211
2212         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
2213
2214         if (!redirectResponse.isNull())
2215             updateScriptResourceResponse(resource);
2216     }
2217 }
2218
2219 void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse& response)
2220 {
2221     if (!enabled())
2222         return;
2223
2224     InspectorResource* resource = m_resources.get(identifier).get();
2225     if (!resource)
2226         return;
2227
2228     updateResourceResponse(resource, response);
2229
2230     resource->responseReceivedTime = currentTime();
2231
2232     if (windowVisible() && resource->scriptObject) {
2233         updateScriptResourceResponse(resource);
2234         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
2235     }
2236 }
2237
2238 void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived)
2239 {
2240     if (!enabled())
2241         return;
2242
2243     InspectorResource* resource = m_resources.get(identifier).get();
2244     if (!resource)
2245         return;
2246
2247     resource->length += lengthReceived;
2248
2249     if (windowVisible() && resource->scriptObject)
2250         updateScriptResource(resource, resource->length);
2251 }
2252
2253 void InspectorController::didFinishLoading(DocumentLoader* loader, unsigned long identifier)
2254 {
2255     if (!enabled())
2256         return;
2257
2258     RefPtr<InspectorResource> resource = m_resources.get(identifier);
2259     if (!resource)
2260         return;
2261
2262     removeResource(resource.get());
2263
2264     resource->finished = true;
2265     resource->endTime = currentTime();
2266
2267     addResource(resource.get());
2268
2269     if (windowVisible() && resource->scriptObject) {
2270         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
2271         updateScriptResource(resource.get(), resource->finished);
2272     }
2273 }
2274
2275 void InspectorController::didFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& /*error*/)
2276 {
2277     if (!enabled())
2278         return;
2279
2280     RefPtr<InspectorResource> resource = m_resources.get(identifier);
2281     if (!resource)
2282         return;
2283
2284     removeResource(resource.get());
2285
2286     resource->finished = true;
2287     resource->failed = true;
2288     resource->endTime = currentTime();
2289
2290     addResource(resource.get());
2291
2292     if (windowVisible() && resource->scriptObject) {
2293         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
2294         updateScriptResource(resource.get(), resource->finished, resource->failed);
2295     }
2296 }
2297
2298 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, JSC::UString& sourceString)
2299 {
2300     if (!enabled())
2301         return;
2302
2303     InspectorResource* resource = m_resources.get(identifier).get();
2304     if (!resource)
2305         return;
2306
2307     resource->setXMLHttpRequestProperties(sourceString);
2308
2309     if (windowVisible() && resource->scriptObject)
2310         updateScriptResourceType(resource);
2311 }
2312
2313
2314 #if ENABLE(DATABASE)
2315 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
2316 {
2317     if (!enabled())
2318         return;
2319
2320     RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
2321
2322     m_databaseResources.add(resource);
2323
2324     if (windowVisible())
2325         addDatabaseScriptResource(resource.get());
2326 }
2327 #endif
2328
2329 void InspectorController::moveWindowBy(float x, float y) const
2330 {
2331     if (!m_page || !enabled())
2332         return;
2333
2334     FloatRect frameRect = m_page->chrome()->windowRect();
2335     frameRect.move(x, y);
2336     m_page->chrome()->setWindowRect(frameRect);
2337 }
2338
2339 #if ENABLE(JAVASCRIPT_DEBUGGER)
2340 void InspectorController::startDebugging()
2341 {
2342     if (!enabled())
2343         return;
2344
2345     if (!m_scriptContext || !m_scriptObject) {
2346         m_attachDebuggerWhenShown = true;
2347         return;
2348     }
2349
2350     ASSERT(m_inspectedPage);
2351
2352     JavaScriptDebugServer::shared().addListener(this, m_inspectedPage);
2353     JavaScriptDebugServer::shared().clearBreakpoints();
2354
2355     m_debuggerAttached = true;
2356     m_attachDebuggerWhenShown = false;
2357
2358     callSimpleFunction(m_scriptContext, m_scriptObject, "debuggerAttached");
2359 }
2360
2361 void InspectorController::stopDebugging()
2362 {
2363     if (!enabled())
2364         return;
2365
2366     ASSERT(m_inspectedPage);
2367
2368     JavaScriptDebugServer::shared().removeListener(this, m_inspectedPage);
2369     m_debuggerAttached = false;
2370
2371     if (m_scriptContext && m_scriptObject)
2372         callSimpleFunction(m_scriptContext, m_scriptObject, "debuggerDetached");
2373 }
2374
2375 JavaScriptCallFrame* InspectorController::currentCallFrame() const
2376 {
2377     return JavaScriptDebugServer::shared().currentCallFrame();
2378 }
2379
2380 bool InspectorController::pauseOnExceptions()
2381 {
2382     return JavaScriptDebugServer::shared().pauseOnExceptions();
2383 }
2384
2385 void InspectorController::setPauseOnExceptions(bool pause)
2386 {
2387     JavaScriptDebugServer::shared().setPauseOnExceptions(pause);
2388 }
2389
2390 void InspectorController::pauseInDebugger()
2391 {
2392     if (!m_debuggerAttached)
2393         return;
2394     JavaScriptDebugServer::shared().pauseProgram();
2395 }
2396
2397 void InspectorController::resumeDebugger()
2398 {
2399     if (!m_debuggerAttached)
2400         return;
2401     JavaScriptDebugServer::shared().continueProgram();
2402 }
2403
2404 void InspectorController::stepOverStatementInDebugger()
2405 {
2406     if (!m_debuggerAttached)
2407         return;
2408     JavaScriptDebugServer::shared().stepOverStatement();
2409 }
2410
2411 void InspectorController::stepIntoStatementInDebugger()
2412 {
2413     if (!m_debuggerAttached)
2414         return;
2415     JavaScriptDebugServer::shared().stepIntoStatement();
2416 }
2417
2418 void InspectorController::stepOutOfFunctionInDebugger()
2419 {
2420     if (!m_debuggerAttached)
2421         return;
2422     JavaScriptDebugServer::shared().stepOutOfFunction();
2423 }
2424
2425 void InspectorController::addBreakpoint(intptr_t sourceID, unsigned lineNumber)
2426 {
2427     JavaScriptDebugServer::shared().addBreakpoint(sourceID, lineNumber);
2428 }
2429
2430 void InspectorController::removeBreakpoint(intptr_t sourceID, unsigned lineNumber)
2431 {
2432     JavaScriptDebugServer::shared().removeBreakpoint(sourceID, lineNumber);
2433 }
2434 #endif
2435
2436 static void drawOutlinedRect(GraphicsContext& context, const IntRect& rect, const Color& fillColor)
2437 {
2438     static const int outlineThickness = 1;
2439     static const Color outlineColor(62, 86, 180, 228);
2440
2441     IntRect outline = rect;
2442     outline.inflate(outlineThickness);
2443
2444     context.clearRect(outline);
2445
2446     context.save();
2447     context.clipOut(rect);
2448     context.fillRect(outline, outlineColor);
2449     context.restore();
2450
2451     context.fillRect(rect, fillColor);
2452 }
2453
2454 static void drawHighlightForBoxes(GraphicsContext& context, const Vector<IntRect>& lineBoxRects, const IntRect& contentBox, const IntRect& paddingBox, const IntRect& borderBox, const IntRect& marginBox)
2455 {
2456     static const Color contentBoxColor(125, 173, 217, 128);
2457     static const Color paddingBoxColor(125, 173, 217, 160);
2458     static const Color borderBoxColor(125, 173, 217, 192);
2459     static const Color marginBoxColor(125, 173, 217, 228);
2460
2461     if (!lineBoxRects.isEmpty()) {
2462         for (size_t i = 0; i < lineBoxRects.size(); ++i)
2463             drawOutlinedRect(context, lineBoxRects[i], contentBoxColor);
2464         return;
2465     }
2466
2467     if (marginBox != borderBox)
2468         drawOutlinedRect(context, marginBox, marginBoxColor);
2469     if (borderBox != paddingBox)
2470         drawOutlinedRect(context, borderBox, borderBoxColor);
2471     if (paddingBox != contentBox)
2472         drawOutlinedRect(context, paddingBox, paddingBoxColor);
2473     drawOutlinedRect(context, contentBox, contentBoxColor);
2474 }
2475
2476 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
2477 {
2478     rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
2479 }
2480
2481 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
2482 {
2483     if (!m_highlightedNode)
2484         return;
2485
2486     RenderObject* renderer = m_highlightedNode->renderer();
2487     Frame* containingFrame = m_highlightedNode->document()->frame();
2488     if (!renderer || !containingFrame)
2489         return;
2490
2491     IntRect contentBox = renderer->absoluteContentBox();
2492     IntRect boundingBox = renderer->absoluteBoundingBoxRect();
2493
2494     // FIXME: Should we add methods to RenderObject to obtain these rects?
2495     IntRect paddingBox(contentBox.x() - renderer->paddingLeft(), contentBox.y() - renderer->paddingTop(), contentBox.width() + renderer->paddingLeft() + renderer->paddingRight(), contentBox.height() + renderer->paddingTop() + renderer->paddingBottom());
2496     IntRect borderBox(paddingBox.x() - renderer->borderLeft(), paddingBox.y() - renderer->borderTop(), paddingBox.width() + renderer->borderLeft() + renderer->borderRight(), paddingBox.height() + renderer->borderTop() + renderer->borderBottom());
2497     IntRect marginBox(borderBox.x() - renderer->marginLeft(), borderBox.y() - renderer->marginTop(), borderBox.width() + renderer->marginLeft() + renderer->marginRight(), borderBox.height() + renderer->marginTop() + renderer->marginBottom());
2498
2499     convertFromFrameToMainFrame(containingFrame, contentBox);
2500     convertFromFrameToMainFrame(containingFrame, paddingBox);
2501     convertFromFrameToMainFrame(containingFrame, borderBox);
2502     convertFromFrameToMainFrame(containingFrame, marginBox);
2503     convertFromFrameToMainFrame(containingFrame, boundingBox);
2504
2505     Vector<IntRect> lineBoxRects;
2506     if (renderer->isInline() || (renderer->isText() && !m_highlightedNode->isSVGElement())) {
2507         // FIXME: We should show margins/padding/border for inlines.
2508         renderer->addLineBoxRects(lineBoxRects);
2509     }
2510
2511     for (unsigned i = 0; i < lineBoxRects.size(); ++i)
2512         convertFromFrameToMainFrame(containingFrame, lineBoxRects[i]);
2513
2514     if (lineBoxRects.isEmpty() && contentBox.isEmpty()) {
2515         // If we have no line boxes and our content box is empty, we'll just draw our bounding box.
2516         // This can happen, e.g., with an <a> enclosing an <img style="float:right">.
2517         // FIXME: Can we make this better/more accurate? The <a> in the above case has no
2518         // width/height but the highlight makes it appear to be the size of the <img>.
2519         lineBoxRects.append(boundingBox);
2520     }
2521
2522     ASSERT(m_inspectedPage);
2523
2524     FrameView* view = m_inspectedPage->mainFrame()->view();
2525     FloatRect overlayRect = view->visibleContentRect();
2526
2527     if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect))) {
2528         Element* element;
2529         if (m_highlightedNode->isElementNode())
2530             element = static_cast<Element*>(m_highlightedNode.get());
2531         else
2532             element = static_cast<Element*>(m_highlightedNode->parent());
2533         overlayRect = view->visibleContentRect();
2534     }
2535
2536     context.translate(-overlayRect.x(), -overlayRect.y());
2537
2538     drawHighlightForBoxes(context, lineBoxRects, contentBox, paddingBox, borderBox, marginBox);
2539 }
2540
2541 void InspectorController::count(const UString& title, unsigned lineNumber, const String& sourceID)
2542 {
2543     String identifier = String(title) + String::format("@%s:%d", sourceID.utf8().data(), lineNumber);
2544     HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
2545     int count;
2546     if (it == m_counts.end())
2547         count = 1;
2548     else {
2549         count = it->second + 1;
2550         m_counts.remove(it);
2551     }
2552
2553     m_counts.add(identifier, count);
2554
2555     String message = String::format("%s: %d", title.UTF8String().c_str(), count);
2556     addMessageToConsole(JSMessageSource, LogMessageLevel, message, lineNumber, sourceID);
2557 }
2558
2559 void InspectorController::startTiming(const UString& title)
2560 {
2561     m_times.add(title, currentTime() * 1000);
2562 }
2563
2564 bool InspectorController::stopTiming(const UString& title, double& elapsed)
2565 {
2566     HashMap<String, double>::iterator it = m_times.find(title);
2567     if (it == m_times.end())
2568         return false;
2569
2570     double startTime = it->second;
2571     m_times.remove(it);
2572     
2573     elapsed = currentTime() * 1000 - startTime;
2574     return true;
2575 }
2576
2577 bool InspectorController::handleException(JSContextRef context, JSValueRef exception, unsigned lineNumber) const
2578 {
2579     if (!exception)
2580         return false;
2581
2582     if (!m_page)
2583         return true;
2584
2585     String message = toString(context, exception, 0);
2586     String file(__FILE__);
2587
2588     if (JSObjectRef exceptionObject = JSValueToObject(context, exception, 0)) {
2589         JSValueRef lineValue = JSObjectGetProperty(context, exceptionObject, jsStringRef("line").get(), NULL);
2590         if (lineValue)
2591             lineNumber = static_cast<unsigned>(JSValueToNumber(context, lineValue, 0));
2592
2593         JSValueRef fileValue = JSObjectGetProperty(context, exceptionObject, jsStringRef("sourceURL").get(), NULL);
2594         if (fileValue)
2595             file = toString(context, fileValue, 0);
2596     }
2597
2598     m_page->mainFrame()->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, file);
2599     return true;
2600 }
2601
2602 #if ENABLE(JAVASCRIPT_DEBUGGER)
2603 // JavaScriptDebugListener functions
2604
2605 void InspectorController::didParseSource(ExecState* exec, const SourceCode& source)
2606 {
2607     JSValueRef sourceIDValue = JSValueMakeNumber(m_scriptContext, source.provider()->asID());
2608     JSValueRef sourceURLValue = JSValueMakeString(m_scriptContext, jsStringRef(source.provider()->url()).get());
2609     JSValueRef sourceValue = JSValueMakeString(m_scriptContext, jsStringRef(source).get());
2610     JSValueRef firstLineValue = JSValueMakeNumber(m_scriptContext, source.firstLine());
2611
2612     JSValueRef exception = 0;
2613     JSValueRef arguments[] = { sourceIDValue, sourceURLValue, sourceValue, firstLineValue };
2614     callFunction(m_scriptContext, m_scriptObject, "parsedScriptSource", 4, arguments, exception);
2615 }
2616
2617 void InspectorController::failedToParseSource(ExecState* exec, const SourceCode& source, int errorLine, const UString& errorMessage)
2618 {
2619     JSValueRef sourceURLValue = JSValueMakeString(m_scriptContext, jsStringRef(source.provider()->url()).get());
2620     JSValueRef sourceValue = JSValueMakeString(m_scriptContext, jsStringRef(source.data()).get());
2621     JSValueRef firstLineValue = JSValueMakeNumber(m_scriptContext, source.firstLine());
2622     JSValueRef errorLineValue = JSValueMakeNumber(m_scriptContext, errorLine);
2623     JSValueRef errorMessageValue = JSValueMakeString(m_scriptContext, jsStringRef(errorMessage).get());
2624
2625     JSValueRef exception = 0;
2626     JSValueRef arguments[] = { sourceURLValue, sourceValue, firstLineValue, errorLineValue, errorMessageValue };
2627     callFunction(m_scriptContext, m_scriptObject, "failedToParseScriptSource", 5, arguments, exception);
2628 }
2629
2630 void InspectorController::didPause()
2631 {
2632     JSValueRef exception = 0;
2633     callFunction(m_scriptContext, m_scriptObject, "pausedScript", 0, 0, exception);
2634 }
2635 #endif
2636
2637 } // namespace WebCore