Reviewed by Mark Rowe.
[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 "Database.h"
35 #include "DocLoader.h"
36 #include "Document.h"
37 #include "DocumentLoader.h"
38 #include "Element.h"
39 #include "FloatConversion.h"
40 #include "FloatRect.h"
41 #include "Frame.h"
42 #include "FrameLoader.h"
43 #include "FrameTree.h"
44 #include "HTMLFrameOwnerElement.h"
45 #include "InspectorClient.h"
46 #include "JSRange.h"
47 #include "Page.h"
48 #include "Range.h"
49 #include "ResourceRequest.h"
50 #include "ResourceResponse.h"
51 #include "Settings.h"
52 #include "SharedBuffer.h"
53 #include "SystemTime.h"
54 #include "TextEncoding.h"
55 #include "TextIterator.h"
56 #include "kjs_dom.h"
57 #include "kjs_proxy.h"
58 #include "kjs_window.h"
59 #include <JavaScriptCore/APICast.h>
60 #include <JavaScriptCore/JSLock.h>
61 #include <JavaScriptCore/JSRetainPtr.h>
62 #include <JavaScriptCore/JSStringRef.h>
63 #include <wtf/RefCounted.h>
64
65 #if ENABLE(DATABASE)
66 #include "JSDatabase.h"
67 #endif
68
69 namespace WebCore {
70
71 static void callSimpleFunction(JSContextRef context, JSObjectRef thisObject, const char* functionName)
72 {
73     ASSERT_ARG(context, context);
74     ASSERT_ARG(thisObject, thisObject);
75
76     JSStringRef string = JSStringCreateWithUTF8CString(functionName);
77     JSObjectRef function = JSValueToObject(context, JSObjectGetProperty(context, thisObject, string, 0), 0);
78     JSStringRelease(string);
79
80     JSObjectCallAsFunction(context, function, thisObject, 0, 0, 0);
81 }
82
83 struct ConsoleMessage {
84     ConsoleMessage(MessageSource s, MessageLevel l, const String& m, unsigned li, const String& u)
85         : source(s)
86         , level(l)
87         , message(m)
88         , line(li)
89         , url(u)
90     {
91     }
92
93     MessageSource source;
94     MessageLevel level;
95     String message;
96     unsigned line;
97     String url;
98 };
99
100 struct InspectorResource : public RefCounted<InspectorResource> {
101     // Keep these in sync with WebInspector.Resource.Type
102     enum Type {
103         Doc,
104         Stylesheet,
105         Image,
106         Font,
107         Script,
108         Other
109     };
110
111     InspectorResource(long long identifier, DocumentLoader* documentLoader, Frame* frame)
112         : identifier(identifier)
113         , loader(documentLoader)
114         , frame(frame)
115         , scriptContext(0)
116         , scriptObject(0)
117         , expectedContentLength(0)
118         , cached(false)
119         , finished(false)
120         , failed(false)
121         , length(0)
122         , responseStatusCode(0)
123         , startTime(-1.0)
124         , responseReceivedTime(-1.0)
125         , endTime(-1.0)
126     {
127     }
128
129     ~InspectorResource()
130     {
131         setScriptObject(0, 0);
132     }
133
134     Type type() const
135     {
136         if (requestURL == loader->requestURL())
137             return Doc;
138
139         FrameLoader* frameLoader = loader->frameLoader();
140         if (!frameLoader)
141             return Other;
142
143         if (requestURL == frameLoader->iconURL())
144             return Image;
145
146         Document* doc = frameLoader->frame()->document();
147         if (!doc)
148             return Other;
149
150         CachedResource* cachedResource = doc->docLoader()->cachedResource(requestURL.string());
151         if (!cachedResource)
152             return Other;
153
154         switch (cachedResource->type()) {
155             case CachedResource::ImageResource:
156                 return Image;
157             case CachedResource::FontResource:
158                 return Font;
159             case CachedResource::CSSStyleSheet:
160 #if ENABLE(XSLT)
161             case CachedResource::XSLStyleSheet:
162 #endif
163                 return Stylesheet;
164             case CachedResource::Script:
165                 return Script;
166             default:
167                 return Other;
168         }
169     }
170
171     void setScriptObject(JSContextRef context, JSObjectRef newScriptObject)
172     {
173         if (scriptContext && scriptObject)
174             JSValueUnprotect(scriptContext, scriptObject);
175
176         scriptObject = newScriptObject;
177         scriptContext = context;
178
179         ASSERT((context && newScriptObject) || (!context && !newScriptObject));
180         if (context && newScriptObject)
181             JSValueProtect(context, newScriptObject);
182     }
183
184     long long identifier;
185     RefPtr<DocumentLoader> loader;
186     RefPtr<Frame> frame;
187     KURL requestURL;
188     HTTPHeaderMap requestHeaderFields;
189     HTTPHeaderMap responseHeaderFields;
190     String mimeType;
191     String suggestedFilename;
192     JSContextRef scriptContext;
193     JSObjectRef scriptObject;
194     long long expectedContentLength;
195     bool cached;
196     bool finished;
197     bool failed;
198     int length;
199     int responseStatusCode;
200     double startTime;
201     double responseReceivedTime;
202     double endTime;
203 };
204
205 #if ENABLE(DATABASE)
206 struct InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> {
207     InspectorDatabaseResource(Database* database, String domain, String name, String version)
208         : database(database)
209         , domain(domain)
210         , name(name)
211         , version(version)
212         , scriptContext(0)
213         , scriptObject(0)
214     {
215     }
216
217     InspectorDatabaseResource()
218     {
219         setScriptObject(0, 0);
220     }
221
222     void setScriptObject(JSContextRef context, JSObjectRef newScriptObject)
223     {
224         if (scriptContext && scriptObject)
225             JSValueUnprotect(scriptContext, scriptObject);
226
227         scriptObject = newScriptObject;
228         scriptContext = context;
229
230         ASSERT((context && newScriptObject) || (!context && !newScriptObject));
231         if (context && newScriptObject)
232             JSValueProtect(context, newScriptObject);
233     }
234
235     RefPtr<Database> database;
236     String domain;
237     String name;
238     String version;
239     JSContextRef scriptContext;
240     JSObjectRef scriptObject;
241 };
242 #endif
243
244 static JSValueRef addSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
245 {
246     JSValueRef undefined = JSValueMakeUndefined(ctx);
247
248     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
249     if (argumentCount < 2 || !controller)
250         return undefined;
251
252     JSValueRef identifierValue = arguments[0];
253     if (!JSValueIsNumber(ctx, identifierValue))
254         return undefined;
255
256     unsigned long identifier = static_cast<unsigned long>(JSValueToNumber(ctx, identifierValue, 0));
257     RefPtr<InspectorResource> resource = controller->resources().get(identifier);
258     ASSERT(resource);
259     if (!resource)
260         return undefined;
261
262     RefPtr<SharedBuffer> buffer;
263     String textEncodingName;
264     if (resource->requestURL == resource->loader->requestURL()) {
265         buffer = resource->loader->mainResourceData();
266         textEncodingName = resource->loader->frame()->document()->inputEncoding();
267     } else {
268         FrameLoader* frameLoader = resource->loader->frameLoader();
269         if (!frameLoader)
270             return undefined;
271
272         Document* doc = frameLoader->frame()->document();
273         if (!doc)
274             return undefined;
275
276         CachedResource* cachedResource = doc->docLoader()->cachedResource(resource->requestURL.string());
277         if (!cachedResource)
278             return undefined;
279
280         buffer = cachedResource->data();
281         textEncodingName = cachedResource->encoding();
282     }
283
284     if (!buffer)
285         return undefined;
286
287     TextEncoding encoding(textEncodingName);
288     if (!encoding.isValid())
289         encoding = WindowsLatin1Encoding();
290     String sourceString = encoding.decode(buffer->data(), buffer->size());
291
292     Node* node = toNode(toJS(arguments[1]));
293     ASSERT(node);
294     if (!node)
295         return undefined;
296
297     if (!node->attached()) {
298         ASSERT_NOT_REACHED();
299         return undefined;
300     }
301
302     ASSERT(node->isElementNode());
303     if (!node->isElementNode())
304         return undefined;
305
306     Element* element = static_cast<Element*>(node);
307     ASSERT(element->isFrameOwnerElement());
308     if (!element->isFrameOwnerElement())
309         return undefined;
310
311     HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element);
312     ASSERT(frameOwner->contentFrame());
313     if (!frameOwner->contentFrame())
314         return undefined;
315
316     FrameLoader* loader = frameOwner->contentFrame()->loader();
317
318     loader->setResponseMIMEType(resource->mimeType);
319     loader->begin();
320     loader->write(sourceString);
321     loader->end();
322
323     return undefined;
324 }
325
326 static JSValueRef getResourceDocumentNode(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
327 {
328     JSValueRef undefined = JSValueMakeUndefined(ctx);
329
330     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
331     if (!argumentCount || argumentCount > 1 || !controller)
332         return undefined;
333
334     JSValueRef identifierValue = arguments[0];
335     if (!JSValueIsNumber(ctx, identifierValue))
336         return undefined;
337
338     unsigned long identifier = static_cast<unsigned long>(JSValueToNumber(ctx, identifierValue, 0));
339     RefPtr<InspectorResource> resource = controller->resources().get(identifier);
340     ASSERT(resource);
341     if (!resource)
342         return undefined;
343
344     FrameLoader* frameLoader = resource->loader->frameLoader();
345     if (!frameLoader)
346         return undefined;
347
348     Document* document = frameLoader->frame()->document();
349     if (!document)
350         return undefined;
351
352     if (document->isPluginDocument() || document->isImageDocument())
353         return undefined;
354
355     KJS::JSLock lock;
356     JSValueRef documentValue = toRef(toJS(toJS(controller->scriptContext()), document));
357     return documentValue;
358 }
359
360 static JSValueRef highlightDOMNode(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
361 {
362     JSValueRef undefined = JSValueMakeUndefined(context);
363
364     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
365     if (argumentCount < 1 || !controller)
366         return undefined;
367
368     Node* node = toNode(toJS(arguments[0]));
369     if (!node)
370         return undefined;
371
372     controller->highlight(node);
373
374     return undefined;
375 }
376
377 static JSValueRef hideDOMNodeHighlight(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
378 {
379     JSValueRef undefined = JSValueMakeUndefined(context);
380
381     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
382     if (argumentCount || !controller)
383         return undefined;
384
385     controller->hideHighlight();
386
387     return undefined;
388 }
389
390 static JSValueRef loaded(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
391 {
392     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
393     if (!controller)
394         return JSValueMakeUndefined(ctx);
395
396     controller->scriptObjectReady();
397     return JSValueMakeUndefined(ctx);
398 }
399
400 static JSValueRef unloading(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
401 {
402     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
403     if (!controller)
404         return JSValueMakeUndefined(ctx);
405
406     controller->close();
407     return JSValueMakeUndefined(ctx);
408 }
409
410 static JSValueRef attach(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
411 {
412     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
413     if (!controller)
414         return JSValueMakeUndefined(ctx);
415
416     controller->attachWindow();
417     return JSValueMakeUndefined(ctx);
418 }
419
420 static JSValueRef detach(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
421 {
422     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
423     if (!controller)
424         return JSValueMakeUndefined(ctx);
425
426     controller->detachWindow();
427     return JSValueMakeUndefined(ctx);
428 }
429
430 static JSValueRef search(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
431 {
432     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
433     if (!controller)
434         return JSValueMakeUndefined(ctx);
435
436     if (argumentCount < 2 || !JSValueIsString(ctx, arguments[1]))
437         return JSValueMakeUndefined(ctx);
438
439     Node* node = toNode(toJS(arguments[0]));
440     if (!node)
441         return JSValueMakeUndefined(ctx);
442
443     JSStringRef string = JSValueToStringCopy(ctx, arguments[1], 0);
444     String target(JSStringGetCharactersPtr(string), JSStringGetLength(string));
445     JSStringRelease(string);
446
447     JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
448     JSStringRef constructorString = JSStringCreateWithUTF8CString("Array");
449     JSObjectRef arrayConstructor = JSValueToObject(ctx, JSObjectGetProperty(ctx, globalObject, constructorString, 0), 0);
450     JSStringRelease(constructorString);
451     JSObjectRef array = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, 0);
452
453     JSStringRef pushString = JSStringCreateWithUTF8CString("push");
454     JSValueRef pushValue = JSObjectGetProperty(ctx, array, pushString, 0);
455     JSStringRelease(pushString);
456     JSObjectRef push = JSValueToObject(ctx, pushValue, 0);
457
458     RefPtr<Range> searchRange(rangeOfContents(node));
459
460     int exception = 0;
461     do {
462         RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false));
463         if (resultRange->collapsed(exception))
464             break;
465
466         // A non-collapsed result range can in some funky whitespace cases still not
467         // advance the range's start position (4509328). Break to avoid infinite loop.
468         VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
469         if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
470             break;
471
472         KJS::JSLock lock;
473         JSValueRef arg0 = toRef(toJS(toJS(ctx), resultRange.get()));
474         JSObjectCallAsFunction(ctx, push, array, 1, &arg0, 0);
475
476         setStart(searchRange.get(), newStart);
477     } while (true);
478
479     return array;
480 }
481
482 #if ENABLE(DATABASE)
483 static JSValueRef databaseTableNames(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
484 {
485     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
486     if (!controller)
487         return JSValueMakeUndefined(ctx);
488
489     if (argumentCount < 1)
490         return JSValueMakeUndefined(ctx);
491
492     Database* database = toDatabase(toJS(arguments[0]));
493     if (!database)
494         return JSValueMakeUndefined(ctx);
495
496     JSObjectRef global = JSContextGetGlobalObject(ctx);
497     JSStringRef arrayString = JSStringCreateWithUTF8CString("Array");
498     JSObjectRef arrayConstructor = JSValueToObject(ctx, JSObjectGetProperty(ctx, global, arrayString, 0), 0);
499     JSStringRelease(arrayString);
500
501     JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, 0);
502
503     JSStringRef pushString = JSStringCreateWithUTF8CString("push");
504     JSObjectRef pushFunction = JSValueToObject(ctx, JSObjectGetProperty(ctx, result, pushString, 0), 0);
505     JSStringRelease(pushString);
506
507     Vector<String> tableNames = database->tableNames();
508     unsigned length = tableNames.size();
509     for (unsigned i = 0; i < length; ++i) {
510         String tableName = tableNames[i];
511         JSStringRef tableNameString = JSStringCreateWithCharacters(tableName.characters(), tableName.length());
512         JSValueRef tableNameValue = JSValueMakeString(ctx, tableNameString);
513         JSStringRelease(tableNameString);
514
515         JSValueRef pushArguments[] = { tableNameValue };
516         JSObjectCallAsFunction(ctx, pushFunction, result, 1, pushArguments, 0);
517     }
518
519     return result;
520 }
521 #endif
522
523 static JSValueRef inspectedWindow(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
524 {
525     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
526     if (!controller)
527         return JSValueMakeUndefined(ctx);
528
529     return toRef(KJS::Window::retrieve(controller->inspectedPage()->mainFrame()));
530 }
531
532 static JSValueRef localizedStrings(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
533 {
534     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
535     if (!controller)
536         return JSValueMakeUndefined(ctx);
537
538     String url = controller->localizedStringsURL();
539     if (url.isNull())
540         return JSValueMakeNull(ctx);
541
542     JSStringRef urlString = JSStringCreateWithCharacters(url.characters(), url.length());
543     JSValueRef urlValue = JSValueMakeString(ctx, urlString);
544     JSStringRelease(urlString);
545
546     return urlValue;
547 }
548
549 static JSValueRef platform(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/)
550 {
551 #if PLATFORM(MAC)
552 #ifdef BUILDING_ON_TIGER
553     static const String platform = "mac-tiger";
554 #else
555     static const String platform = "mac-leopard";
556 #endif
557 #elif PLATFORM(WIN_OS)
558     static const String platform = "windows";
559 #elif PLATFORM(QT)
560     static const String platform = "qt";
561 #elif PLATFORM(GTK)
562     static const String platform = "gtk";
563 #elif PLATFORM(WX)
564     static const String platform = "wx";
565 #else
566     static const String platform = "unknown";
567 #endif
568
569     JSRetainPtr<JSStringRef> platformString(Adopt, JSStringCreateWithCharacters(platform.characters(), platform.length()));
570     JSValueRef platformValue = JSValueMakeString(ctx, platformString.get());
571
572     return platformValue;
573 }
574
575 static JSValueRef moveByUnrestricted(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
576 {
577     InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
578     if (!controller)
579         return JSValueMakeUndefined(ctx);
580
581     if (argumentCount < 2)
582         return JSValueMakeUndefined(ctx);
583
584     controller->moveWindowBy(narrowPrecisionToFloat(JSValueToNumber(ctx, arguments[0], 0)), narrowPrecisionToFloat(JSValueToNumber(ctx, arguments[1], 0)));
585
586     return JSValueMakeUndefined(ctx);
587 }
588
589 InspectorController::InspectorController(Page* page, InspectorClient* client)
590     : m_inspectedPage(page)
591     , m_client(client)
592     , m_page(0)
593     , m_scriptObject(0)
594     , m_controllerScriptObject(0)
595     , m_scriptContext(0)
596     , m_windowVisible(false)
597     , m_showAfterVisible(FocusedNodeDocumentPanel)
598     , m_nextIdentifier(-2)
599 {
600     ASSERT_ARG(page, page);
601     ASSERT_ARG(client, client);
602 }
603
604 InspectorController::~InspectorController()
605 {
606     m_client->inspectorDestroyed();
607
608     if (m_scriptContext) {
609         JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
610         JSStringRef controllerProperty = JSStringCreateWithUTF8CString("InspectorController");
611         JSObjectRef controller = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, global, controllerProperty, 0), 0);
612         JSStringRelease(controllerProperty);
613         JSObjectSetPrivate(controller, 0);
614     }
615
616     if (m_page)
617         m_page->setParentInspectorController(0);
618
619     deleteAllValues(m_frameResources);
620     deleteAllValues(m_consoleMessages);
621 }
622
623 bool InspectorController::enabled() const
624 {
625     return m_inspectedPage->settings()->developerExtrasEnabled();
626 }
627
628 String InspectorController::localizedStringsURL()
629 {
630     if (!enabled())
631         return String();
632     return m_client->localizedStringsURL();
633 }
634
635 void InspectorController::inspect(Node* node)
636 {
637     if (!node || !enabled())
638         return;
639
640     show();
641
642     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
643         node = node->parentNode();
644     m_nodeToFocus = node;
645
646     if (!m_scriptObject) {
647         m_showAfterVisible = FocusedNodeDocumentPanel;
648         return;
649     }
650
651     if (windowVisible())
652         focusNode();
653 }
654
655 void InspectorController::focusNode()
656 {
657     if (!enabled())
658         return;
659
660     ASSERT(m_scriptContext);
661     ASSERT(m_scriptObject);
662     ASSERT(m_nodeToFocus);
663
664     JSValueRef arg0;
665
666     {
667         KJS::JSLock lock;
668         arg0 = toRef(toJS(toJS(m_scriptContext), m_nodeToFocus.get()));
669     }
670
671     m_nodeToFocus = 0;
672
673     JSStringRef functionProperty = JSStringCreateWithUTF8CString("updateFocusedNode");
674     JSObjectRef function = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, functionProperty, 0), 0);
675     JSStringRelease(functionProperty);
676     ASSERT(function);
677
678     JSObjectCallAsFunction(m_scriptContext, function, m_scriptObject, 1, &arg0, 0);
679 }
680
681 void InspectorController::highlight(Node* node)
682 {
683     if (!enabled())
684         return;
685     ASSERT_ARG(node, node);
686     m_client->highlight(node);
687 }
688
689 void InspectorController::hideHighlight()
690 {
691     if (!enabled())
692         return;
693     m_client->hideHighlight();
694 }
695
696 bool InspectorController::windowVisible()
697 {
698     return m_windowVisible;
699 }
700
701 void InspectorController::setWindowVisible(bool visible)
702 {
703     if (visible == m_windowVisible)
704         return;
705
706     m_windowVisible = visible;
707
708     if (!m_scriptContext || !m_scriptObject)
709         return;
710
711     if (m_windowVisible) {
712         populateScriptResources();
713         if (m_nodeToFocus)
714             focusNode();
715         if (m_showAfterVisible == ConsolePanel)
716             showConsole();
717         else if (m_showAfterVisible == TimelinePanel)
718             showTimeline();
719     } else {
720         clearScriptResources();
721         clearScriptConsoleMessages();
722         clearDatabaseScriptResources();
723         clearNetworkTimeline();
724     }
725
726     m_showAfterVisible = FocusedNodeDocumentPanel;
727 }
728
729 void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
730 {
731     if (!enabled())
732         return;
733
734     ConsoleMessage* consoleMessage = new ConsoleMessage(source, level, message, lineNumber, sourceID);
735     m_consoleMessages.append(consoleMessage);
736
737     if (windowVisible())
738         addScriptConsoleMessage(consoleMessage);
739 }
740
741 void InspectorController::attachWindow()
742 {
743     if (!enabled())
744         return;
745     m_client->attachWindow();
746 }
747
748 void InspectorController::detachWindow()
749 {
750     if (!enabled())
751         return;
752     m_client->detachWindow();
753 }
754
755 void InspectorController::windowScriptObjectAvailable()
756 {
757     if (!m_page || !enabled())
758         return;
759
760     m_scriptContext = toRef(m_page->mainFrame()->scriptProxy()->globalObject()->globalExec());
761
762     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
763     ASSERT(global);
764
765     static JSStaticFunction staticFunctions[] = {
766         { "addSourceToFrame", addSourceToFrame, kJSPropertyAttributeNone },
767         { "getResourceDocumentNode", getResourceDocumentNode, kJSPropertyAttributeNone },
768         { "highlightDOMNode", highlightDOMNode, kJSPropertyAttributeNone },
769         { "hideDOMNodeHighlight", hideDOMNodeHighlight, kJSPropertyAttributeNone },
770         { "loaded", loaded, kJSPropertyAttributeNone },
771         { "windowUnloading", unloading, kJSPropertyAttributeNone },
772         { "attach", attach, kJSPropertyAttributeNone },
773         { "detach", detach, kJSPropertyAttributeNone },
774         { "search", search, kJSPropertyAttributeNone },
775 #if ENABLE(DATABASE)
776         { "databaseTableNames", databaseTableNames, kJSPropertyAttributeNone },
777 #endif
778         { "inspectedWindow", inspectedWindow, kJSPropertyAttributeNone },
779         { "localizedStringsURL", localizedStrings, kJSPropertyAttributeNone },
780         { "platform", platform, kJSPropertyAttributeNone },
781         { "moveByUnrestricted", moveByUnrestricted, kJSPropertyAttributeNone },
782         { 0, 0, 0 }
783     };
784
785     JSClassDefinition inspectorControllerDefinition = {
786         0, kJSClassAttributeNone, "InspectorController", 0, 0, staticFunctions,
787         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
788     };
789
790     JSClassRef controllerClass = JSClassCreate(&inspectorControllerDefinition);
791     ASSERT(controllerClass);
792
793     m_controllerScriptObject = JSObjectMake(m_scriptContext, controllerClass, reinterpret_cast<void*>(this));
794     ASSERT(m_controllerScriptObject);
795
796     JSStringRef controllerObjectString = JSStringCreateWithUTF8CString("InspectorController");
797     JSObjectSetProperty(m_scriptContext, global, controllerObjectString, m_controllerScriptObject, kJSPropertyAttributeNone, 0);
798     JSStringRelease(controllerObjectString);
799 }
800
801 void InspectorController::scriptObjectReady()
802 {
803     ASSERT(m_scriptContext);
804     if (!m_scriptContext)
805         return;
806
807     JSObjectRef global = JSContextGetGlobalObject(m_scriptContext);
808     ASSERT(global);
809
810     JSStringRef inspectorString = JSStringCreateWithUTF8CString("WebInspector");
811     JSValueRef inspectorValue = JSObjectGetProperty(m_scriptContext, global, inspectorString, 0);
812     JSStringRelease(inspectorString);
813
814     ASSERT(inspectorValue);
815     if (!inspectorValue)
816         return;
817
818     m_scriptObject = JSValueToObject(m_scriptContext, inspectorValue, 0);
819     ASSERT(m_scriptObject);
820
821     JSValueProtect(m_scriptContext, m_scriptObject);
822
823     // Make sure our window is visible now that the page loaded
824     m_client->showWindow();
825 }
826
827 void InspectorController::show()
828 {
829     if (!enabled())
830         return;
831
832     if (!m_page) {
833         m_page = m_client->createPage();
834         if (!m_page)
835             return;
836         m_page->setParentInspectorController(this);
837
838         // m_client->showWindow() will be called after the page loads in scriptObjectReady()
839         return;
840     }
841
842     m_client->showWindow();
843 }
844
845 void InspectorController::showConsole()
846 {
847     if (!enabled())
848         return;
849
850     show();
851
852     if (!m_scriptObject) {
853         m_showAfterVisible = ConsolePanel;
854         return;
855     }
856
857     callSimpleFunction(m_scriptContext, m_scriptObject, "showConsole");
858 }
859
860 void InspectorController::showTimeline()
861 {
862     if (!enabled())
863         return;
864
865     show();
866
867     if (!m_scriptObject) {
868         m_showAfterVisible = TimelinePanel;
869         return;
870     }
871
872     callSimpleFunction(m_scriptContext, m_scriptObject, "showTimeline");
873 }
874
875 void InspectorController::close()
876 {
877     if (!enabled())
878         return;
879
880     m_client->closeWindow();
881     if (m_page)
882         m_page->setParentInspectorController(0);
883
884     ASSERT(m_scriptContext && m_scriptObject);
885     JSValueUnprotect(m_scriptContext, m_scriptObject);
886
887     m_page = 0;
888     m_scriptObject = 0;
889     m_scriptContext = 0;
890 }
891
892 static void addHeaders(JSContextRef context, JSObjectRef object, const HTTPHeaderMap& headers)
893 {
894     ASSERT_ARG(context, context);
895     ASSERT_ARG(object, object);
896     
897     HTTPHeaderMap::const_iterator end = headers.end();
898     for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) {
899         JSStringRef field = JSStringCreateWithCharacters(it->first.characters(), it->first.length());
900         JSStringRef valueString = JSStringCreateWithCharacters(it->second.characters(), it->second.length());
901         JSValueRef value = JSValueMakeString(context, valueString);
902         JSObjectSetProperty(context, object, field, value, kJSPropertyAttributeNone, 0);
903         JSStringRelease(field);
904         JSStringRelease(valueString);
905     }
906 }
907
908 static JSObjectRef scriptObjectForRequest(JSContextRef context, const InspectorResource* resource)
909 {
910     ASSERT_ARG(context, context);
911
912     JSObjectRef object = JSObjectMake(context, 0, 0);
913     addHeaders(context, object, resource->requestHeaderFields);
914
915     return object;
916 }
917
918 static JSObjectRef scriptObjectForResponse(JSContextRef context, const InspectorResource* resource)
919 {
920     ASSERT_ARG(context, context);
921
922     JSObjectRef object = JSObjectMake(context, 0, 0);
923     addHeaders(context, object, resource->responseHeaderFields);
924
925     return object;
926 }
927
928 JSObjectRef InspectorController::addScriptResource(InspectorResource* resource)
929 {
930     ASSERT_ARG(resource, resource);
931
932     // This happens for pages loaded from the back/forward cache.
933     if (resource->scriptObject)
934         return resource->scriptObject;
935
936     ASSERT(m_scriptContext);
937     ASSERT(m_scriptObject);
938     if (!m_scriptContext || !m_scriptObject)
939         return 0;
940
941     JSStringRef resourceString = JSStringCreateWithUTF8CString("Resource");
942     JSObjectRef resourceConstructor = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, resourceString, 0), 0);
943     JSStringRelease(resourceString);
944
945     String urlString = resource->requestURL.string();
946     JSStringRef url = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
947     JSValueRef urlValue = JSValueMakeString(m_scriptContext, url);
948     JSStringRelease(url);
949
950     urlString = resource->requestURL.host();
951     JSStringRef domain = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
952     JSValueRef domainValue = JSValueMakeString(m_scriptContext, domain);
953     JSStringRelease(domain);
954
955     urlString = resource->requestURL.path();
956     JSStringRef path = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
957     JSValueRef pathValue = JSValueMakeString(m_scriptContext, path);
958     JSStringRelease(path);
959
960     urlString = resource->requestURL.lastPathComponent();
961     JSStringRef lastPathComponent = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
962     JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, lastPathComponent);
963     JSStringRelease(lastPathComponent);
964
965     JSValueRef identifier = JSValueMakeNumber(m_scriptContext, resource->identifier);
966     JSValueRef mainResource = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
967     JSValueRef cached = JSValueMakeBoolean(m_scriptContext, resource->cached);
968
969     JSValueRef arguments[] = { scriptObjectForRequest(m_scriptContext, resource), urlValue, domainValue, pathValue, lastPathComponentValue, identifier, mainResource, cached };
970     JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, resourceConstructor, 8, arguments, 0);
971
972     resource->setScriptObject(m_scriptContext, result);
973
974     ASSERT(result);
975
976     JSStringRef addResourceString = JSStringCreateWithUTF8CString("addResource");
977     JSObjectRef addResourceFunction = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, addResourceString, 0), 0);
978     JSStringRelease(addResourceString);
979
980     JSValueRef addArguments[] = { result };
981     JSObjectCallAsFunction(m_scriptContext, addResourceFunction, m_scriptObject, 1, addArguments, 0);
982
983     return result;
984 }
985
986 JSObjectRef InspectorController::addAndUpdateScriptResource(InspectorResource* resource)
987 {
988     ASSERT_ARG(resource, resource);
989
990     JSObjectRef scriptResource = addScriptResource(resource);
991     updateScriptResourceResponse(resource);
992     updateScriptResource(resource, resource->length);
993     updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
994     updateScriptResource(resource, resource->finished, resource->failed);
995     return scriptResource;
996 }
997
998 void InspectorController::removeScriptResource(InspectorResource* resource)
999 {
1000     ASSERT(m_scriptContext);
1001     ASSERT(m_scriptObject);
1002     if (!m_scriptContext || !m_scriptObject)
1003         return;
1004
1005     ASSERT(resource);
1006     ASSERT(resource->scriptObject);
1007     if (!resource || !resource->scriptObject)
1008         return;
1009
1010     JSStringRef removeResourceString = JSStringCreateWithUTF8CString("removeResource");
1011     JSObjectRef removeResourceFunction = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, removeResourceString, 0), 0);
1012     JSStringRelease(removeResourceString);
1013
1014     JSValueRef arguments[] = { resource->scriptObject };
1015     JSObjectCallAsFunction(m_scriptContext, removeResourceFunction, m_scriptObject, 1, arguments, 0);
1016
1017     resource->setScriptObject(0, 0);
1018 }
1019
1020 static void updateResourceRequest(InspectorResource* resource, const ResourceRequest& request)
1021 {
1022     resource->requestHeaderFields = request.httpHeaderFields();
1023     resource->requestURL = request.url();
1024 }
1025
1026 static void updateResourceResponse(InspectorResource* resource, const ResourceResponse& response)
1027 {
1028     resource->expectedContentLength = response.expectedContentLength();
1029     resource->mimeType = response.mimeType();
1030     resource->responseHeaderFields = response.httpHeaderFields();
1031     resource->responseStatusCode = response.httpStatusCode();
1032     resource->suggestedFilename = response.suggestedFilename();
1033 }
1034
1035 void InspectorController::updateScriptResourceRequest(InspectorResource* resource)
1036 {
1037     ASSERT(resource->scriptObject);
1038     ASSERT(m_scriptContext);
1039     if (!resource->scriptObject || !m_scriptContext)
1040         return;
1041
1042     String urlString = resource->requestURL.string();
1043     JSStringRef url = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
1044     JSValueRef urlValue = JSValueMakeString(m_scriptContext, url);
1045     JSStringRelease(url);
1046
1047     urlString = resource->requestURL.host();
1048     JSStringRef domain = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
1049     JSValueRef domainValue = JSValueMakeString(m_scriptContext, domain);
1050     JSStringRelease(domain);
1051
1052     urlString = resource->requestURL.path();
1053     JSStringRef path = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
1054     JSValueRef pathValue = JSValueMakeString(m_scriptContext, path);
1055     JSStringRelease(path);
1056
1057     urlString = resource->requestURL.lastPathComponent();
1058     JSStringRef lastPathComponent = JSStringCreateWithCharacters(urlString.characters(), urlString.length());
1059     JSValueRef lastPathComponentValue = JSValueMakeString(m_scriptContext, lastPathComponent);
1060     JSStringRelease(lastPathComponent);
1061
1062     JSValueRef mainResourceValue = JSValueMakeBoolean(m_scriptContext, m_mainResource == resource);
1063
1064     JSStringRef propertyName = JSStringCreateWithUTF8CString("url");
1065     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, urlValue, kJSPropertyAttributeNone, 0);
1066     JSStringRelease(propertyName);
1067
1068     propertyName = JSStringCreateWithUTF8CString("domain");
1069     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, domainValue, kJSPropertyAttributeNone, 0);
1070     JSStringRelease(propertyName);
1071
1072     propertyName = JSStringCreateWithUTF8CString("path");
1073     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, pathValue, kJSPropertyAttributeNone, 0);
1074     JSStringRelease(propertyName);
1075
1076     propertyName = JSStringCreateWithUTF8CString("lastPathComponent");
1077     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, lastPathComponentValue, kJSPropertyAttributeNone, 0);
1078     JSStringRelease(propertyName);
1079
1080     propertyName = JSStringCreateWithUTF8CString("requestHeaders");
1081     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, scriptObjectForRequest(m_scriptContext, resource), kJSPropertyAttributeNone, 0);
1082     JSStringRelease(propertyName);
1083
1084     propertyName = JSStringCreateWithUTF8CString("mainResource");
1085     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, mainResourceValue, kJSPropertyAttributeNone, 0);
1086     JSStringRelease(propertyName);
1087 }
1088
1089 void InspectorController::updateScriptResourceResponse(InspectorResource* resource)
1090 {
1091     ASSERT(resource->scriptObject);
1092     ASSERT(m_scriptContext);
1093     if (!resource->scriptObject || !m_scriptContext)
1094         return;
1095
1096     JSStringRef mimeType = JSStringCreateWithCharacters(resource->mimeType.characters(), resource->mimeType.length());
1097     JSValueRef mimeTypeValue = JSValueMakeString(m_scriptContext, mimeType);
1098     JSStringRelease(mimeType);
1099
1100     JSStringRef suggestedFilename = JSStringCreateWithCharacters(resource->suggestedFilename.characters(), resource->suggestedFilename.length());
1101     JSValueRef suggestedFilenameValue = JSValueMakeString(m_scriptContext, suggestedFilename);
1102     JSStringRelease(suggestedFilename);
1103
1104     JSValueRef expectedContentLengthValue = JSValueMakeNumber(m_scriptContext, static_cast<double>(resource->expectedContentLength));
1105     JSValueRef statusCodeValue = JSValueMakeNumber(m_scriptContext, resource->responseStatusCode);
1106
1107     JSStringRef propertyName = JSStringCreateWithUTF8CString("mimeType");
1108     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, mimeTypeValue, kJSPropertyAttributeNone, 0);
1109     JSStringRelease(propertyName);
1110
1111     propertyName = JSStringCreateWithUTF8CString("suggestedFilename");
1112     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, suggestedFilenameValue, kJSPropertyAttributeNone, 0);
1113     JSStringRelease(propertyName);
1114
1115     propertyName = JSStringCreateWithUTF8CString("expectedContentLength");
1116     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, expectedContentLengthValue, kJSPropertyAttributeNone, 0);
1117     JSStringRelease(propertyName);
1118
1119     propertyName = JSStringCreateWithUTF8CString("statusCode");
1120     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, statusCodeValue, kJSPropertyAttributeNone, 0);
1121     JSStringRelease(propertyName);
1122     
1123     propertyName = JSStringCreateWithUTF8CString("responseHeaders");
1124     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, scriptObjectForResponse(m_scriptContext, resource), kJSPropertyAttributeNone, 0);
1125     JSStringRelease(propertyName);
1126
1127     JSValueRef typeValue = JSValueMakeNumber(m_scriptContext, resource->type());
1128     propertyName = JSStringCreateWithUTF8CString("type");
1129     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, typeValue, kJSPropertyAttributeNone, 0);
1130     JSStringRelease(propertyName);
1131 }
1132
1133 void InspectorController::updateScriptResource(InspectorResource* resource, int length)
1134 {
1135     ASSERT(resource->scriptObject);
1136     ASSERT(m_scriptContext);
1137     if (!resource->scriptObject || !m_scriptContext)
1138         return;
1139
1140     JSValueRef lengthValue = JSValueMakeNumber(m_scriptContext, length);
1141
1142     JSStringRef propertyName = JSStringCreateWithUTF8CString("contentLength");
1143     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, lengthValue, kJSPropertyAttributeNone, 0);
1144     JSStringRelease(propertyName);
1145 }
1146
1147 void InspectorController::updateScriptResource(InspectorResource* resource, bool finished, bool failed)
1148 {
1149     ASSERT(resource->scriptObject);
1150     ASSERT(m_scriptContext);
1151     if (!resource->scriptObject || !m_scriptContext)
1152         return;
1153
1154     JSValueRef failedValue = JSValueMakeBoolean(m_scriptContext, failed);
1155     JSValueRef finishedValue = JSValueMakeBoolean(m_scriptContext, finished);
1156
1157     JSStringRef propertyName = JSStringCreateWithUTF8CString("failed");
1158     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, failedValue, kJSPropertyAttributeNone, 0);
1159     JSStringRelease(propertyName);
1160
1161     propertyName = JSStringCreateWithUTF8CString("finished");
1162     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, finishedValue, kJSPropertyAttributeNone, 0);
1163     JSStringRelease(propertyName);
1164
1165 }
1166
1167 void InspectorController::updateScriptResource(InspectorResource* resource, double startTime, double responseReceivedTime, double endTime)
1168 {
1169     ASSERT(resource->scriptObject);
1170     ASSERT(m_scriptContext);
1171     if (!resource->scriptObject || !m_scriptContext)
1172         return;
1173
1174     JSValueRef startTimeValue = JSValueMakeNumber(m_scriptContext, startTime);
1175     JSValueRef responseReceivedTimeValue = JSValueMakeNumber(m_scriptContext, responseReceivedTime);
1176     JSValueRef endTimeValue = JSValueMakeNumber(m_scriptContext, endTime);
1177
1178     JSStringRef propertyName = JSStringCreateWithUTF8CString("startTime");
1179     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, startTimeValue, kJSPropertyAttributeNone, 0);
1180     JSStringRelease(propertyName);
1181
1182     propertyName = JSStringCreateWithUTF8CString("responseReceivedTime");
1183     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, responseReceivedTimeValue, kJSPropertyAttributeNone, 0);
1184     JSStringRelease(propertyName);
1185
1186     propertyName = JSStringCreateWithUTF8CString("endTime");
1187     JSObjectSetProperty(m_scriptContext, resource->scriptObject, propertyName, endTimeValue, kJSPropertyAttributeNone, 0);
1188     JSStringRelease(propertyName);
1189 }
1190
1191 void InspectorController::populateScriptResources()
1192 {
1193     ASSERT(m_scriptContext);
1194     if (!m_scriptContext)
1195         return;
1196
1197     clearScriptResources();
1198     clearScriptConsoleMessages();
1199     clearDatabaseScriptResources();
1200     clearNetworkTimeline();
1201
1202     ResourcesMap::iterator resourcesEnd = m_resources.end();
1203     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
1204         addAndUpdateScriptResource(it->second.get());
1205
1206     unsigned messageCount = m_consoleMessages.size();
1207     for (unsigned i = 0; i < messageCount; ++i)
1208         addScriptConsoleMessage(m_consoleMessages[i]);
1209
1210 #if ENABLE(DATABASE)
1211     DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
1212     for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
1213         addDatabaseScriptResource((*it).get());
1214 #endif
1215 }
1216
1217 #if ENABLE(DATABASE)
1218 JSObjectRef InspectorController::addDatabaseScriptResource(InspectorDatabaseResource* resource)
1219 {
1220     ASSERT_ARG(resource, resource);
1221
1222     if (resource->scriptObject)
1223         return resource->scriptObject;
1224
1225     ASSERT(m_scriptContext);
1226     ASSERT(m_scriptObject);
1227     if (!m_scriptContext || !m_scriptObject)
1228         return 0;
1229
1230     JSStringRef databaseString = JSStringCreateWithUTF8CString("Database");
1231     JSObjectRef databaseConstructor = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, databaseString, 0), 0);
1232     JSStringRelease(databaseString);
1233
1234     JSValueRef database = toRef(toJS(toJS(m_scriptContext), resource->database.get()));
1235
1236     JSStringRef domain = JSStringCreateWithCharacters(resource->domain.characters(), resource->domain.length());
1237     JSValueRef domainValue = JSValueMakeString(m_scriptContext, domain);
1238     JSStringRelease(domain);
1239
1240     JSStringRef name = JSStringCreateWithCharacters(resource->name.characters(), resource->name.length());
1241     JSValueRef nameValue = JSValueMakeString(m_scriptContext, name);
1242     JSStringRelease(name);
1243
1244     JSStringRef version = JSStringCreateWithCharacters(resource->version.characters(), resource->version.length());
1245     JSValueRef versionValue = JSValueMakeString(m_scriptContext, version);
1246     JSStringRelease(version);
1247
1248     JSValueRef arguments[] = { database, domainValue, nameValue, versionValue };
1249     JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, databaseConstructor, 4, arguments, 0);
1250
1251     resource->setScriptObject(m_scriptContext, result);
1252
1253     ASSERT(result);
1254
1255     JSStringRef addResourceString = JSStringCreateWithUTF8CString("addResource");
1256     JSObjectRef addResourceFunction = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, addResourceString, 0), 0);
1257     JSStringRelease(addResourceString);
1258
1259     JSValueRef addArguments[] = { result };
1260     JSObjectCallAsFunction(m_scriptContext, addResourceFunction, m_scriptObject, 1, addArguments, 0);
1261
1262     return result;
1263 }
1264
1265 void InspectorController::removeDatabaseScriptResource(InspectorDatabaseResource* resource)
1266 {
1267     ASSERT(m_scriptContext);
1268     ASSERT(m_scriptObject);
1269     if (!m_scriptContext || !m_scriptObject)
1270         return;
1271
1272     ASSERT(resource);
1273     ASSERT(resource->scriptObject);
1274     if (!resource || !resource->scriptObject)
1275         return;
1276
1277     JSStringRef removeResourceString = JSStringCreateWithUTF8CString("removeResource");
1278     JSObjectRef removeResourceFunction = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, removeResourceString, 0), 0);
1279     JSStringRelease(removeResourceString);
1280
1281     JSValueRef arguments[] = { resource->scriptObject };
1282     JSObjectCallAsFunction(m_scriptContext, removeResourceFunction, m_scriptObject, 1, arguments, 0);
1283
1284     resource->setScriptObject(0, 0);
1285 }
1286 #endif
1287
1288 void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message)
1289 {
1290     ASSERT_ARG(message, message);
1291
1292     JSStringRef messageConstructorString = JSStringCreateWithUTF8CString("ConsoleMessage");
1293     JSObjectRef messageConstructor = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, messageConstructorString, 0), 0);
1294     JSStringRelease(messageConstructorString);
1295
1296     JSStringRef addMessageString = JSStringCreateWithUTF8CString("addMessageToConsole");
1297     JSObjectRef addMessage = JSValueToObject(m_scriptContext, JSObjectGetProperty(m_scriptContext, m_scriptObject, addMessageString, 0), 0);
1298     JSStringRelease(addMessageString);
1299
1300     JSValueRef sourceValue = JSValueMakeNumber(m_scriptContext, message->source);
1301     JSValueRef levelValue = JSValueMakeNumber(m_scriptContext, message->level);
1302     JSStringRef messageString = JSStringCreateWithCharacters(message->message.characters(), message->message.length());
1303     JSValueRef messageValue = JSValueMakeString(m_scriptContext, messageString);
1304     JSValueRef lineValue = JSValueMakeNumber(m_scriptContext, message->line);
1305     JSStringRef urlString = JSStringCreateWithCharacters(message->url.characters(), message->url.length());
1306     JSValueRef urlValue = JSValueMakeString(m_scriptContext, urlString);
1307
1308     JSValueRef args[] = { sourceValue, levelValue, messageValue, lineValue, urlValue };
1309     JSObjectRef messageObject = JSObjectCallAsConstructor(m_scriptContext, messageConstructor, 5, args, 0);
1310     JSStringRelease(messageString);
1311     JSStringRelease(urlString);
1312
1313     JSObjectCallAsFunction(m_scriptContext, addMessage, m_scriptObject, 1, &messageObject, 0);
1314 }
1315
1316 void InspectorController::clearScriptResources()
1317 {
1318     if (!m_scriptContext || !m_scriptObject)
1319         return;
1320
1321     ResourcesMap::iterator resourcesEnd = m_resources.end();
1322     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
1323         InspectorResource* resource = it->second.get();
1324         resource->setScriptObject(0, 0);
1325     }
1326
1327     callSimpleFunction(m_scriptContext, m_scriptObject, "clearResources");
1328 }
1329
1330 void InspectorController::clearDatabaseScriptResources()
1331 {
1332 #if ENABLE(DATABASE)
1333     if (!m_scriptContext || !m_scriptObject)
1334         return;
1335
1336     DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end();
1337     for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) {
1338         InspectorDatabaseResource* resource = (*it).get();
1339         resource->setScriptObject(0, 0);
1340     }
1341
1342     callSimpleFunction(m_scriptContext, m_scriptObject, "clearDatabaseResources");
1343 #endif
1344 }
1345
1346 void InspectorController::clearScriptConsoleMessages()
1347 {
1348     if (!m_scriptContext || !m_scriptObject)
1349         return;
1350
1351     callSimpleFunction(m_scriptContext, m_scriptObject, "clearConsoleMessages");
1352 }
1353
1354 void InspectorController::clearNetworkTimeline()
1355 {
1356     if (!m_scriptContext || !m_scriptObject)
1357         return;
1358
1359     callSimpleFunction(m_scriptContext, m_scriptObject, "clearNetworkTimeline");
1360 }
1361
1362 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
1363 {
1364     ASSERT_ARG(resourceMap, resourceMap);
1365
1366     ResourcesMap mapCopy(*resourceMap);
1367     ResourcesMap::iterator end = mapCopy.end();
1368     for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
1369         InspectorResource* resource = (*it).second.get();
1370         if (resource == m_mainResource)
1371             continue;
1372
1373         if (!loaderToKeep || resource->loader != loaderToKeep) {
1374             removeResource(resource);
1375             if (windowVisible() && resource->scriptObject)
1376                 removeScriptResource(resource);
1377         }
1378     }
1379 }
1380
1381 void InspectorController::didCommitLoad(DocumentLoader* loader)
1382 {
1383     if (!enabled())
1384         return;
1385
1386     if (loader->frame() == m_inspectedPage->mainFrame()) {
1387         ASSERT(m_mainResource);
1388         // FIXME: Should look into asserting that m_mainResource->loader == loader here.
1389
1390         m_client->inspectedURLChanged(loader->url().string());
1391
1392         deleteAllValues(m_consoleMessages);
1393         m_consoleMessages.clear();
1394
1395 #if ENABLE(DATABASE)
1396         m_databaseResources.clear();
1397 #endif
1398
1399         if (windowVisible()) {
1400             clearScriptConsoleMessages();
1401 #if ENABLE(DATABASE)
1402             clearDatabaseScriptResources();
1403 #endif
1404             clearNetworkTimeline();
1405
1406             // We don't add the main resource until its load is committed. This
1407             // is needed to keep the load for a user-entered URL from showing
1408             // up in the list of resources for the page they are navigating
1409             // away from.
1410             addAndUpdateScriptResource(m_mainResource.get());
1411         }
1412     }
1413
1414     for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
1415         if (ResourcesMap* resourceMap = m_frameResources.get(frame))
1416             pruneResources(resourceMap, loader);
1417 }
1418
1419 void InspectorController::frameDetachedFromParent(Frame* frame)
1420 {
1421     if (!enabled())
1422         return;
1423     if (ResourcesMap* resourceMap = m_frameResources.get(frame))
1424         removeAllResources(resourceMap);
1425 }
1426
1427 void InspectorController::addResource(InspectorResource* resource)
1428 {
1429     m_resources.set(resource->identifier, resource);
1430
1431     Frame* frame = resource->frame.get();
1432     ResourcesMap* resourceMap = m_frameResources.get(frame);
1433     if (resourceMap)
1434         resourceMap->set(resource->identifier, resource);
1435     else {
1436         resourceMap = new ResourcesMap;
1437         resourceMap->set(resource->identifier, resource);
1438         m_frameResources.set(frame, resourceMap);
1439     }
1440 }
1441
1442 void InspectorController::removeResource(InspectorResource* resource)
1443 {
1444     m_resources.remove(resource->identifier);
1445
1446     Frame* frame = resource->frame.get();
1447     ResourcesMap* resourceMap = m_frameResources.get(frame);
1448     if (!resourceMap) {
1449         ASSERT_NOT_REACHED();
1450         return;
1451     }
1452
1453     resourceMap->remove(resource->identifier);
1454     if (resourceMap->isEmpty()) {
1455         m_frameResources.remove(frame);
1456         delete resourceMap;
1457     }
1458 }
1459
1460 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse& response, int length)
1461 {
1462     if (!enabled())
1463         return;
1464
1465     InspectorResource* resource = new InspectorResource(m_nextIdentifier--, loader, loader->frame());
1466     resource->finished = true;
1467
1468     updateResourceRequest(resource, request);
1469     updateResourceResponse(resource, response);
1470
1471     resource->length = length;
1472     resource->cached = true;
1473     resource->startTime = currentTime();
1474     resource->responseReceivedTime = resource->startTime;
1475     resource->endTime = resource->startTime;
1476
1477     if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
1478         m_mainResource = resource;
1479
1480     addResource(resource);
1481
1482     if (windowVisible())
1483         addAndUpdateScriptResource(resource);
1484 }
1485
1486 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
1487 {
1488     if (!enabled())
1489         return;
1490
1491     InspectorResource* resource = new InspectorResource(identifier, loader, loader->frame());
1492
1493     updateResourceRequest(resource, request);
1494
1495     if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL())
1496         m_mainResource = resource;
1497
1498     addResource(resource);
1499 }
1500
1501 void InspectorController::willSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
1502 {
1503     if (!enabled())
1504         return;
1505
1506     InspectorResource* resource = m_resources.get(identifier).get();
1507     if (!resource)
1508         return;
1509
1510     resource->startTime = currentTime();
1511
1512     if (!redirectResponse.isNull()) {
1513         updateResourceRequest(resource, request);
1514         updateResourceResponse(resource, redirectResponse);
1515     }
1516
1517     if (resource != m_mainResource && windowVisible()) {
1518         if (!resource->scriptObject)
1519             addScriptResource(resource);
1520         else
1521             updateScriptResourceRequest(resource);
1522
1523         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1524
1525         if (!redirectResponse.isNull())
1526             updateScriptResourceResponse(resource);
1527     }
1528 }
1529
1530 void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse& response)
1531 {
1532     if (!enabled())
1533         return;
1534
1535     InspectorResource* resource = m_resources.get(identifier).get();
1536     if (!resource)
1537         return;
1538
1539     updateResourceResponse(resource, response);
1540
1541     resource->responseReceivedTime = currentTime();
1542
1543     if (windowVisible() && resource->scriptObject) {
1544         updateScriptResourceResponse(resource);
1545         updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime);
1546     }
1547 }
1548
1549 void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived)
1550 {
1551     if (!enabled())
1552         return;
1553
1554     InspectorResource* resource = m_resources.get(identifier).get();
1555     if (!resource)
1556         return;
1557
1558     resource->length += lengthReceived;
1559
1560     if (windowVisible() && resource->scriptObject)
1561         updateScriptResource(resource, resource->length);
1562 }
1563
1564 void InspectorController::didFinishLoading(DocumentLoader* loader, unsigned long identifier)
1565 {
1566     if (!enabled())
1567         return;
1568
1569     RefPtr<InspectorResource> resource = m_resources.get(identifier);
1570     if (!resource)
1571         return;
1572
1573     removeResource(resource.get());
1574
1575     resource->finished = true;
1576     resource->endTime = currentTime();
1577
1578     addResource(resource.get());
1579
1580     if (windowVisible() && resource->scriptObject) {
1581         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
1582         updateScriptResource(resource.get(), resource->finished);
1583     }
1584 }
1585
1586 void InspectorController::didFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& /*error*/)
1587 {
1588     if (!enabled())
1589         return;
1590
1591     RefPtr<InspectorResource> resource = m_resources.get(identifier);
1592     if (!resource)
1593         return;
1594
1595     removeResource(resource.get());
1596
1597     resource->finished = true;
1598     resource->failed = true;
1599     resource->endTime = currentTime();
1600
1601     addResource(resource.get());
1602
1603     if (windowVisible() && resource->scriptObject) {
1604         updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime);
1605         updateScriptResource(resource.get(), resource->finished, resource->failed);
1606     }
1607 }
1608
1609 #if ENABLE(DATABASE)
1610 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
1611 {
1612     if (!enabled())
1613         return;
1614
1615     InspectorDatabaseResource* resource = new InspectorDatabaseResource(database, domain, name, version);
1616
1617     m_databaseResources.add(resource);
1618
1619     if (windowVisible())
1620         addDatabaseScriptResource(resource);
1621 }
1622 #endif
1623
1624 void InspectorController::moveWindowBy(float x, float y) const
1625 {
1626     if (!m_page || !enabled())
1627         return;
1628
1629     FloatRect frameRect = m_page->chrome()->windowRect();
1630     frameRect.move(x, y);
1631     m_page->chrome()->setWindowRect(frameRect);
1632 }
1633
1634 } // namespace WebCore