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