6e08f41ef81e30ee9ecf3ecf8da809a37490c67c
[WebKit-https.git] / Source / WebCore / inspector / InspectorFrontendClientLocal.cpp
1 /*
2  * Copyright (C) 2010 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "InspectorFrontendClientLocal.h"
33
34 #if ENABLE(INSPECTOR)
35
36 #include "Chrome.h"
37 #include "FloatRect.h"
38 #include "Frame.h"
39 #include "FrameView.h"
40 #include "InspectorBackendDispatcher.h"
41 #include "InspectorController.h"
42 #include "InspectorFrontendHost.h"
43 #include "Page.h"
44 #include "PlatformString.h"
45 #include "ScriptFunctionCall.h"
46 #include "ScriptObject.h"
47 #include "Settings.h"
48 #include "Timer.h"
49 #include <wtf/Deque.h>
50
51 namespace WebCore {
52
53 static const char* inspectorAttachedHeightSetting = "inspectorAttachedHeight";
54 static const unsigned defaultAttachedHeight = 300;
55 static const float minimumAttachedHeight = 250.0f;
56 static const float maximumAttachedHeightRatio = 0.75f;
57
58 class InspectorBackendDispatchTask {
59 public:
60     InspectorBackendDispatchTask(InspectorController* inspectorController)
61         : m_inspectorController(inspectorController)
62         , m_timer(this, &InspectorBackendDispatchTask::onTimer)
63     {
64     }
65
66     void dispatch(const String& message)
67     {
68         m_messages.append(message);
69         if (!m_timer.isActive())
70             m_timer.startOneShot(0);
71     }
72
73     void reset()
74     {
75         m_messages.clear();
76         m_timer.stop();
77     }
78
79     void onTimer(Timer<InspectorBackendDispatchTask>*)
80     {
81         if (!m_messages.isEmpty()) {
82             // Dispatch can lead to the timer destruction -> schedule the next shot first.
83             m_timer.startOneShot(0);
84             m_inspectorController->dispatchMessageFromFrontend(m_messages.takeFirst());
85         }
86     }
87
88 private:
89     InspectorController* m_inspectorController;
90     Timer<InspectorBackendDispatchTask> m_timer;
91     Deque<String> m_messages;
92 };
93
94 String InspectorFrontendClientLocal::Settings::getProperty(const String&)
95 {
96     return String();
97 }
98
99 void InspectorFrontendClientLocal::Settings::setProperty(const String&, const String&)
100 {
101 }
102
103 InspectorFrontendClientLocal::InspectorFrontendClientLocal(InspectorController* inspectorController, Page* frontendPage, PassOwnPtr<Settings> settings)
104     : m_inspectorController(inspectorController)
105     , m_frontendPage(frontendPage)
106     , m_frontendScriptState(0)
107     , m_settings(settings)
108 {
109     m_frontendPage->settings()->setAllowFileAccessFromFileURLs(true);
110     m_dispatchTask = adoptPtr(new InspectorBackendDispatchTask(inspectorController));
111 }
112
113 InspectorFrontendClientLocal::~InspectorFrontendClientLocal()
114 {
115     if (m_frontendHost)
116         m_frontendHost->disconnectClient();
117     m_frontendScriptState = 0;
118     m_frontendPage = 0;
119     m_inspectorController = 0;
120 }
121
122 void InspectorFrontendClientLocal::windowObjectCleared()
123 {
124     // FIXME: don't keep reference to the script state
125     m_frontendScriptState = scriptStateFromPage(debuggerWorld(), m_frontendPage);
126     m_frontendHost = InspectorFrontendHost::create(this, m_frontendPage);
127     ScriptGlobalObject::set(m_frontendScriptState, "InspectorFrontendHost", m_frontendHost.get());
128 }
129
130 void InspectorFrontendClientLocal::frontendLoaded()
131 {
132     bringToFront();
133     m_inspectorController->connectFrontend();
134 }
135
136 void InspectorFrontendClientLocal::requestAttachWindow()
137 {
138     if (!canAttachWindow())
139         return;
140     attachWindow();
141     setAttachedWindow(true);
142 }
143
144 void InspectorFrontendClientLocal::requestDetachWindow()
145 {
146     detachWindow();
147     setAttachedWindow(false);
148 }
149
150 bool InspectorFrontendClientLocal::canAttachWindow()
151 {
152     unsigned inspectedPageHeight = m_inspectorController->inspectedPage()->mainFrame()->view()->visibleHeight();
153
154     // Don't allow the attach if the window would be too small to accommodate the minimum inspector height.
155     return minimumAttachedHeight <= inspectedPageHeight * maximumAttachedHeightRatio;
156 }
157
158 void InspectorFrontendClientLocal::changeAttachedWindowHeight(unsigned height)
159 {
160     unsigned totalHeight = m_frontendPage->mainFrame()->view()->visibleHeight() + m_inspectorController->inspectedPage()->mainFrame()->view()->visibleHeight();
161     unsigned attachedHeight = constrainedAttachedWindowHeight(height, totalHeight);
162     m_settings->setProperty(inspectorAttachedHeightSetting, String::number(attachedHeight));
163     setAttachedWindowHeight(attachedHeight);
164 }
165
166 void InspectorFrontendClientLocal::moveWindowBy(float x, float y)
167 {
168     FloatRect frameRect = m_frontendPage->chrome()->windowRect();
169     frameRect.move(x, y);
170     m_frontendPage->chrome()->setWindowRect(frameRect);
171 }
172
173 void InspectorFrontendClientLocal::setAttachedWindow(bool attached)
174 {
175     ScriptObject webInspectorObj;
176     if (!ScriptGlobalObject::get(m_frontendScriptState, "WebInspector", webInspectorObj)) {
177         ASSERT_NOT_REACHED();
178         return;
179     }
180     ScriptFunctionCall function(webInspectorObj, "setAttachedWindow");
181     function.appendArgument(attached);
182     function.call();
183 }
184
185 void InspectorFrontendClientLocal::restoreAttachedWindowHeight()
186 {
187     unsigned inspectedPageHeight = m_inspectorController->inspectedPage()->mainFrame()->view()->visibleHeight();
188     String value = m_settings->getProperty(inspectorAttachedHeightSetting);
189     unsigned preferredHeight = value.isEmpty() ? defaultAttachedHeight : value.toUInt();
190     
191     // This call might not go through (if the window starts out detached), but if the window is initially created attached,
192     // InspectorController::attachWindow is never called, so we need to make sure to set the attachedWindowHeight.
193     // FIXME: Clean up code so we only have to call setAttachedWindowHeight in InspectorController::attachWindow
194     setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight, inspectedPageHeight));
195 }
196
197 unsigned InspectorFrontendClientLocal::constrainedAttachedWindowHeight(unsigned preferredHeight, unsigned totalWindowHeight)
198 {
199     using namespace std;
200     return roundf(max(minimumAttachedHeight, min<float>(preferredHeight, totalWindowHeight * maximumAttachedHeightRatio)));
201 }
202
203 void InspectorFrontendClientLocal::sendMessageToBackend(const String& message)
204 {
205     m_dispatchTask->dispatch(message);
206 }
207
208 } // namespace WebCore
209
210 #endif