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