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