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