1 /*
2 * Copyright 2007, The Android Open Source Project
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 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #define LOG_TAG "WebCore"
27
28 #include "config.h"
29
30 #include "ApplicationCacheStorage.h"
31 #include "ChromeClientAndroid.h"
32 #include "CString.h"
33 #include "DatabaseTracker.h"
34 #include "Document.h"
35 #include "PlatformString.h"
36 #include "FloatRect.h"
37 #include "Frame.h"
38 #include "FrameLoader.h"
39 #include "FrameView.h"
40 #include "Geolocation.h"
41 #include "Page.h"
42 #include "Screen.h"
43 #include "ScriptController.h"
44 #include "WebCoreFrameBridge.h"
45 #include "WebCoreViewBridge.h"
46 #include "WebViewCore.h"
47 #include "WindowFeatures.h"
48 #include "Settings.h"
49
50 namespace android {
51
setWebFrame(android::WebFrame * webframe)52 void ChromeClientAndroid::setWebFrame(android::WebFrame* webframe)
53 {
54 Release(m_webFrame);
55 m_webFrame = webframe;
56 Retain(m_webFrame);
57 }
58
chromeDestroyed()59 void ChromeClientAndroid::chromeDestroyed()
60 {
61 Release(m_webFrame);
62 delete this;
63 }
64
setWindowRect(const FloatRect &)65 void ChromeClientAndroid::setWindowRect(const FloatRect&) { notImplemented(); }
66
windowRect()67 FloatRect ChromeClientAndroid::windowRect() {
68 ASSERT(m_webFrame);
69 if (!m_webFrame)
70 return FloatRect();
71 FrameView* frameView = m_webFrame->page()->mainFrame()->view();
72 if (!frameView)
73 return FloatRect();
74 const WebCoreViewBridge* bridge = frameView->platformWidget();
75 const IntRect& rect = bridge->getWindowBounds();
76 FloatRect fRect(rect.x(), rect.y(), rect.width(), rect.height());
77 return fRect;
78 }
79
pageRect()80 FloatRect ChromeClientAndroid::pageRect() { notImplemented(); return FloatRect(); }
81
scaleFactor()82 float ChromeClientAndroid::scaleFactor()
83 {
84 ASSERT(m_webFrame);
85 return m_webFrame->density();
86 }
87
focus()88 void ChromeClientAndroid::focus() {
89 ASSERT(m_webFrame);
90 // Ask the application to focus this WebView.
91 m_webFrame->requestFocus();
92 }
unfocus()93 void ChromeClientAndroid::unfocus() { notImplemented(); }
94
canTakeFocus(FocusDirection)95 bool ChromeClientAndroid::canTakeFocus(FocusDirection) { notImplemented(); return false; }
takeFocus(FocusDirection)96 void ChromeClientAndroid::takeFocus(FocusDirection) { notImplemented(); }
97
createWindow(Frame * frame,const FrameLoadRequest &,const WindowFeatures & features)98 Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&,
99 const WindowFeatures& features)
100 {
101 ASSERT(frame);
102 #ifdef ANDROID_MULTIPLE_WINDOWS
103 if (frame->settings() && !(frame->settings()->supportMultipleWindows()))
104 // If the client doesn't support multiple windows, just return the current page
105 return frame->page();
106 #endif
107
108 WTF::PassRefPtr<WebCore::Screen> screen = WebCore::Screen::create(frame);
109 bool dialog = features.dialog || !features.resizable
110 || (features.heightSet && features.height < screen.get()->height()
111 && features.widthSet && features.width < screen.get()->width())
112 || (!features.menuBarVisible && !features.statusBarVisible
113 && !features.toolBarVisible && !features.locationBarVisible
114 && !features.scrollbarsVisible);
115 // fullscreen definitely means no dialog
116 if (features.fullscreen)
117 dialog = false;
118 WebCore::Frame* newFrame = m_webFrame->createWindow(dialog,
119 frame->script()->processingUserGesture());
120 if (newFrame) {
121 WebCore::Page* page = newFrame->page();
122 page->setGroupName(frame->page()->groupName());
123 return page;
124 }
125 return NULL;
126 }
127
show()128 void ChromeClientAndroid::show() { notImplemented(); }
129
canRunModal()130 bool ChromeClientAndroid::canRunModal() { notImplemented(); return false; }
runModal()131 void ChromeClientAndroid::runModal() { notImplemented(); }
132
setToolbarsVisible(bool)133 void ChromeClientAndroid::setToolbarsVisible(bool) { notImplemented(); }
toolbarsVisible()134 bool ChromeClientAndroid::toolbarsVisible() { notImplemented(); return false; }
135
setStatusbarVisible(bool)136 void ChromeClientAndroid::setStatusbarVisible(bool) { notImplemented(); }
statusbarVisible()137 bool ChromeClientAndroid::statusbarVisible() { notImplemented(); return false; }
138
setScrollbarsVisible(bool)139 void ChromeClientAndroid::setScrollbarsVisible(bool) { notImplemented(); }
scrollbarsVisible()140 bool ChromeClientAndroid::scrollbarsVisible() { notImplemented(); return false; }
141
setMenubarVisible(bool)142 void ChromeClientAndroid::setMenubarVisible(bool) { notImplemented(); }
menubarVisible()143 bool ChromeClientAndroid::menubarVisible() { notImplemented(); return false; }
144
setResizable(bool)145 void ChromeClientAndroid::setResizable(bool) { notImplemented(); }
146
147 // This function is called by the JavaScript bindings to print usually an error to
148 // a message console. Pass the message to the java side so that the client can
149 // handle it as it sees fit.
addMessageToConsole(MessageSource,MessageType,MessageLevel,const String & message,unsigned int lineNumber,const String & sourceID)150 void ChromeClientAndroid::addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned int lineNumber, const String& sourceID) {
151 android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->addMessageToConsole(message, lineNumber, sourceID);
152 }
153
canRunBeforeUnloadConfirmPanel()154 bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; }
runBeforeUnloadConfirmPanel(const String & message,Frame * frame)155 bool ChromeClientAndroid::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) {
156 String url = frame->document()->documentURI();
157 return android::WebViewCore::getWebViewCore(frame->view())->jsUnload(url, message);
158 }
159
closeWindowSoon()160 void ChromeClientAndroid::closeWindowSoon()
161 {
162 ASSERT(m_webFrame);
163 Page* page = m_webFrame->page();
164 Frame* mainFrame = page->mainFrame();
165 // This will prevent javascript cross-scripting during unload
166 page->setGroupName(String());
167 // Stop loading but do not send the unload event
168 mainFrame->loader()->stopLoading(false);
169 // Cancel all pending loaders
170 mainFrame->loader()->stopAllLoaders();
171 // Remove all event listeners so that no javascript can execute as a result
172 // of mouse/keyboard events.
173 mainFrame->document()->removeAllEventListeners();
174 // Close the window.
175 m_webFrame->closeWindow(android::WebViewCore::getWebViewCore(mainFrame->view()));
176 }
177
runJavaScriptAlert(Frame * frame,const String & message)178 void ChromeClientAndroid::runJavaScriptAlert(Frame* frame, const String& message)
179 {
180 String url = frame->document()->documentURI();
181
182 android::WebViewCore::getWebViewCore(frame->view())->jsAlert(url, message);
183 }
184
runJavaScriptConfirm(Frame * frame,const String & message)185 bool ChromeClientAndroid::runJavaScriptConfirm(Frame* frame, const String& message)
186 {
187 String url = frame->document()->documentURI();
188
189 return android::WebViewCore::getWebViewCore(frame->view())->jsConfirm(url, message);
190 }
191
192 /* This function is called for the javascript method Window.prompt(). A dialog should be shown on
193 * the screen with an input put box. First param is the text, the second is the default value for
194 * the input box, third is return param. If the function returns true, the value set in the third parameter
195 * is provided to javascript, else null is returned to the script.
196 */
runJavaScriptPrompt(Frame * frame,const String & message,const String & defaultValue,String & result)197 bool ChromeClientAndroid::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result)
198 {
199 String url = frame->document()->documentURI();
200 return android::WebViewCore::getWebViewCore(frame->view())->jsPrompt(url, message, defaultValue, result);
201 }
setStatusbarText(const String &)202 void ChromeClientAndroid::setStatusbarText(const String&) { notImplemented(); }
203
204 // This is called by the JavaScript interpreter when a script has been running for a long
205 // time. A dialog should be shown to the user asking them if they would like to cancel the
206 // Javascript. If true is returned, the script is cancelled.
207 // To make a device more responsive, we default to return true to disallow long running script.
208 // This implies that some of scripts will not be completed.
shouldInterruptJavaScript()209 bool ChromeClientAndroid::shouldInterruptJavaScript() {
210 FrameView* frameView = m_webFrame->page()->mainFrame()->view();
211 return android::WebViewCore::getWebViewCore(frameView)->jsInterrupt();
212 }
213
tabsToLinks() const214 bool ChromeClientAndroid::tabsToLinks() const { return false; }
215
windowResizerRect() const216 IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); }
217
218 // new to change 38068 (Nov 6, 2008)
repaint(const IntRect & rect,bool contentChanged,bool immediate,bool repaintContentOnly)219 void ChromeClientAndroid::repaint(const IntRect& rect, bool contentChanged,
220 bool immediate, bool repaintContentOnly) {
221 notImplemented();
222 // was in ScrollViewAndroid::update() : needs to be something like:
223 // android::WebViewCore::getWebViewCore(this)->contentInvalidate(rect);
224 }
225
226 // new to change 38068 (Nov 6, 2008)
scroll(const IntSize & scrollDelta,const IntRect & rectToScroll,const IntRect & clipRect)227 void ChromeClientAndroid::scroll(const IntSize& scrollDelta,
228 const IntRect& rectToScroll, const IntRect& clipRect) {
229 notImplemented();
230 }
231
232 // new to change 38068 (Nov 6, 2008)
screenToWindow(const IntPoint &) const233 IntPoint ChromeClientAndroid::screenToWindow(const IntPoint&) const {
234 notImplemented();
235 return IntPoint();
236 }
237
238 // new to change 38068 (Nov 6, 2008)
windowToScreen(const IntRect &) const239 IntRect ChromeClientAndroid::windowToScreen(const IntRect&) const {
240 notImplemented();
241 return IntRect();
242 }
243
244 // new to change 38068 (Nov 6, 2008)
245 // in place of view()->containingWindow(), webkit now uses view()->hostWindow()->platformWindow()
platformWindow() const246 PlatformWidget ChromeClientAndroid::platformWindow() const {
247 Page* page = m_webFrame->page();
248 Frame* mainFrame = page->mainFrame();
249 FrameView* view = mainFrame->view();
250 PlatformWidget viewBridge = view->platformWidget();
251 return viewBridge;
252 }
253
contentsSizeChanged(Frame *,const IntSize &) const254 void ChromeClientAndroid::contentsSizeChanged(Frame*, const IntSize&) const
255 {
256 notImplemented();
257 }
258
scrollRectIntoView(const IntRect &,const ScrollView *) const259 void ChromeClientAndroid::scrollRectIntoView(const IntRect&, const ScrollView*) const
260 {
261 notImplemented();
262 }
263
formStateDidChange(const Node *)264 void ChromeClientAndroid::formStateDidChange(const Node*)
265 {
266 notImplemented();
267 }
268
mouseDidMoveOverElement(const HitTestResult &,unsigned int)269 void ChromeClientAndroid::mouseDidMoveOverElement(const HitTestResult&, unsigned int) {}
setToolTip(const String &,TextDirection)270 void ChromeClientAndroid::setToolTip(const String&, TextDirection) {}
print(Frame *)271 void ChromeClientAndroid::print(Frame*) {}
272
273 /*
274 * This function is called on the main (webcore) thread by SQLTransaction::deliverQuotaIncreaseCallback.
275 * The way that the callback mechanism is designed inside SQLTransaction means that there must be a new quota
276 * (which may be equal to the old quota if the user did not allow more quota) when this function returns. As
277 * we call into the browser thread to ask what to do with the quota, we block here and get woken up when the
278 * browser calls the native WebViewCore::SetDatabaseQuota method with the new quota value.
279 */
280 #if ENABLE(DATABASE)
exceededDatabaseQuota(Frame * frame,const String & name)281 void ChromeClientAndroid::exceededDatabaseQuota(Frame* frame, const String& name)
282 {
283 SecurityOrigin* origin = frame->document()->securityOrigin();
284
285 // We want to wait on a new quota from the UI thread. Reset the m_newQuota variable to represent we haven't received a new quota.
286 m_newQuota = -1;
287
288 // This origin is being tracked and has exceeded it's quota. Call into
289 // the Java side of things to inform the user.
290 unsigned long long currentQuota = 0;
291 if (WebCore::DatabaseTracker::tracker().hasEntryForOrigin(origin)) {
292 currentQuota = WebCore::DatabaseTracker::tracker().quotaForOrigin(origin);
293 }
294
295 unsigned long long estimatedSize = WebCore::DatabaseTracker::tracker().detailsForNameAndOrigin(name, origin).expectedUsage();
296
297 android::WebViewCore::getWebViewCore(frame->view())->exceededDatabaseQuota(frame->document()->documentURI(), name, currentQuota, estimatedSize);
298
299 // We've sent notification to the browser so now wait for it to come back.
300 m_quotaThreadLock.lock();
301 while (m_newQuota == -1) {
302 m_quotaThreadCondition.wait(m_quotaThreadLock);
303 }
304 m_quotaThreadLock.unlock();
305
306 // Update the DatabaseTracker with the new quota value (if the user declined
307 // new quota, this may equal the old quota)
308 DatabaseTracker::tracker().setQuota(origin, m_newQuota);
309 }
310 #endif
311 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
reachedMaxAppCacheSize(int64_t spaceNeeded)312 void ChromeClientAndroid::reachedMaxAppCacheSize(int64_t spaceNeeded)
313 {
314 // Set m_newQuota before calling into the Java side. If we do this after,
315 // we could overwrite the result passed from the Java side and deadlock in the
316 // wait call below.
317 m_newQuota = -1;
318 Page* page = m_webFrame->page();
319 Frame* mainFrame = page->mainFrame();
320 FrameView* view = mainFrame->view();
321 android::WebViewCore::getWebViewCore(view)->reachedMaxAppCacheSize(spaceNeeded);
322
323 // We've sent notification to the browser so now wait for it to come back.
324 m_quotaThreadLock.lock();
325 while (m_newQuota == -1) {
326 m_quotaThreadCondition.wait(m_quotaThreadLock);
327 }
328 m_quotaThreadLock.unlock();
329 if (m_newQuota > 0) {
330 WebCore::cacheStorage().setMaximumSize(m_newQuota);
331 // Now the app cache will retry the saving the previously failed cache.
332 }
333 }
334 #endif
335
populateVisitedLinks()336 void ChromeClientAndroid::populateVisitedLinks()
337 {
338 Page* page = m_webFrame->page();
339 Frame* mainFrame = page->mainFrame();
340 FrameView* view = mainFrame->view();
341 android::WebViewCore::getWebViewCore(view)->populateVisitedLinks(&page->group());
342 }
343
requestGeolocationPermissionForFrame(Frame * frame,Geolocation * geolocation)344 void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
345 {
346 ASSERT(geolocation);
347 if (!m_geolocationPermissions) {
348 m_geolocationPermissions = new GeolocationPermissions(android::WebViewCore::getWebViewCore(frame->view()),
349 m_webFrame->page()->mainFrame());
350 }
351 m_geolocationPermissions->queryPermissionState(frame);
352 }
353
provideGeolocationPermissions(const String & origin,bool allow,bool remember)354 void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember)
355 {
356 ASSERT(m_geolocationPermissions);
357 m_geolocationPermissions->providePermissionState(origin, allow, remember);
358 }
359
storeGeolocationPermissions()360 void ChromeClientAndroid::storeGeolocationPermissions()
361 {
362 GeolocationPermissions::maybeStorePermanentPermissions();
363 }
364
onMainFrameLoadStarted()365 void ChromeClientAndroid::onMainFrameLoadStarted()
366 {
367 if (m_geolocationPermissions.get())
368 m_geolocationPermissions->resetTemporaryPermissionStates();
369 }
370
runOpenPanel(Frame *,PassRefPtr<FileChooser>)371 void ChromeClientAndroid::runOpenPanel(Frame*, PassRefPtr<FileChooser>) { notImplemented(); }
setCursor(PlatformCursorHandle)372 bool ChromeClientAndroid::setCursor(PlatformCursorHandle)
373 {
374 notImplemented();
375 return false;
376 }
377
wakeUpMainThreadWithNewQuota(long newQuota)378 void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long newQuota) {
379 MutexLocker locker(m_quotaThreadLock);
380 m_newQuota = newQuota;
381 m_quotaThreadCondition.signal();
382 }
383
384 }
385