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