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 THE COPYRIGHT OWNER 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 "DatabaseTracker.h" 33 #include "Document.h" 34 #include "PlatformString.h" 35 #include "FloatRect.h" 36 #include "Frame.h" 37 #include "FrameLoader.h" 38 #include "FrameView.h" 39 #include "Geolocation.h" 40 #include "GraphicsLayerAndroid.h" 41 #include "HTMLMediaElement.h" 42 #include "HTMLNames.h" 43 #include "Icon.h" 44 #include "LayerAndroid.h" 45 #include "Page.h" 46 #include "PopupMenuAndroid.h" 47 #include "RenderLayer.h" 48 #include "RenderLayerCompositor.h" 49 #include "ScriptController.h" 50 #include "SearchPopupMenuAndroid.h" 51 #include "WebCoreFrameBridge.h" 52 #include "WebCoreViewBridge.h" 53 #include "WebViewCore.h" 54 #include "WindowFeatures.h" 55 #include "Settings.h" 56 #include "UserGestureIndicator.h" 57 #include <wtf/text/CString.h> 58 59 namespace android { 60 61 #if ENABLE(DATABASE) 62 static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota); 63 #endif 64 65 #if USE(ACCELERATED_COMPOSITING) 66 67 WebCore::GraphicsLayer* ChromeClientAndroid::layersSync() 68 { 69 if (m_rootGraphicsLayer && m_needsLayerSync && m_webFrame) { 70 // We may have more than one frame, so let's first update all of them 71 // (webkit may want to update the GraphicsLayer tree, and we do *not* want 72 // to find this out when we are painting, as it means we could be summarily 73 // deallocated while painting...) 74 GraphicsLayerAndroid* rootLayer = static_cast<GraphicsLayerAndroid*>(m_rootGraphicsLayer); 75 Vector<const RenderLayer*> listRootLayers; 76 rootLayer->gatherRootLayers(listRootLayers); 77 78 for (unsigned int i = 0; i < listRootLayers.size(); i++) { 79 RenderLayer* layer = const_cast<RenderLayer*>(listRootLayers[i]); 80 layer->compositor()->updateCompositingLayers(); 81 } 82 83 Frame* frame = m_webFrame->page()->mainFrame(); 84 if (FrameView* frameView = frame->view()) 85 frameView->syncCompositingStateIncludingSubframes(); 86 } 87 m_needsLayerSync = false; 88 return m_rootGraphicsLayer; 89 } 90 91 void ChromeClientAndroid::scheduleCompositingLayerSync() 92 { 93 if (m_needsLayerSync) 94 return; 95 m_needsLayerSync = true; 96 WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view()); 97 if (webViewCore) 98 webViewCore->contentDraw(); 99 } 100 101 void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization() 102 { 103 // This should not be needed 104 } 105 106 void ChromeClientAndroid::attachRootGraphicsLayer(WebCore::Frame*, WebCore::GraphicsLayer* layer) 107 { 108 // frame is not used in Android as we should only get root graphics layer for the main frame 109 m_rootGraphicsLayer = layer; 110 if (!layer) 111 return; 112 scheduleCompositingLayerSync(); 113 } 114 115 #endif 116 117 void ChromeClientAndroid::setWebFrame(android::WebFrame* webframe) 118 { 119 Release(m_webFrame); 120 m_webFrame = webframe; 121 Retain(m_webFrame); 122 } 123 124 void ChromeClientAndroid::chromeDestroyed() 125 { 126 Release(m_webFrame); 127 delete this; 128 } 129 130 void ChromeClientAndroid::setWindowRect(const FloatRect&) { notImplemented(); } 131 132 FloatRect ChromeClientAndroid::windowRect() { 133 ASSERT(m_webFrame); 134 if (!m_webFrame) 135 return FloatRect(); 136 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 137 if (!frameView) 138 return FloatRect(); 139 const WebCoreViewBridge* bridge = frameView->platformWidget(); 140 const IntRect& rect = bridge->getWindowBounds(); 141 FloatRect fRect(rect.x(), rect.y(), rect.width(), rect.height()); 142 return fRect; 143 } 144 145 FloatRect ChromeClientAndroid::pageRect() { notImplemented(); return FloatRect(); } 146 147 float ChromeClientAndroid::scaleFactor() 148 { 149 ASSERT(m_webFrame); 150 return m_webFrame->density(); 151 } 152 153 void ChromeClientAndroid::focus() 154 { 155 ASSERT(m_webFrame); 156 bool isUserGesture = UserGestureIndicator::processingUserGesture(); 157 158 // Ask the application to focus this WebView if the action is intiated by the user 159 if (isUserGesture) 160 m_webFrame->requestFocus(); 161 } 162 void ChromeClientAndroid::unfocus() { notImplemented(); } 163 164 bool ChromeClientAndroid::canTakeFocus(FocusDirection direction) 165 { 166 return android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->chromeCanTakeFocus(direction); 167 } 168 169 void ChromeClientAndroid::takeFocus(FocusDirection direction) 170 { 171 android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->chromeTakeFocus(direction); 172 } 173 174 void ChromeClientAndroid::focusedNodeChanged(Node* node) 175 { 176 android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->focusNodeChanged(node); 177 } 178 179 void ChromeClientAndroid::focusedFrameChanged(Frame*) { notImplemented(); } 180 181 Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&, 182 const WindowFeatures& features, const NavigationAction&) 183 { 184 ASSERT(frame); 185 #ifdef ANDROID_MULTIPLE_WINDOWS 186 if (frame->settings() && !(frame->settings()->supportMultipleWindows())) 187 // If the client doesn't support multiple windows, just return the current page 188 return frame->page(); 189 #endif 190 191 FloatRect window = windowRect(); 192 bool dialog = features.dialog || !features.resizable 193 || (features.heightSet && features.height < window.height() 194 && features.widthSet && features.width < window.width()) 195 || (!features.menuBarVisible && !features.statusBarVisible 196 && !features.toolBarVisible && !features.locationBarVisible 197 && !features.scrollbarsVisible); 198 // fullscreen definitely means no dialog 199 if (features.fullscreen) 200 dialog = false; 201 WebCore::Frame* newFrame = m_webFrame->createWindow(dialog, 202 ScriptController::processingUserGesture()); 203 if (newFrame) { 204 WebCore::Page* page = newFrame->page(); 205 page->setGroupName(frame->page()->groupName()); 206 return page; 207 } 208 return NULL; 209 } 210 211 void ChromeClientAndroid::show() { notImplemented(); } 212 213 bool ChromeClientAndroid::canRunModal() { notImplemented(); return false; } 214 void ChromeClientAndroid::runModal() { notImplemented(); } 215 216 void ChromeClientAndroid::setToolbarsVisible(bool) { notImplemented(); } 217 bool ChromeClientAndroid::toolbarsVisible() { notImplemented(); return false; } 218 219 void ChromeClientAndroid::setStatusbarVisible(bool) { notImplemented(); } 220 bool ChromeClientAndroid::statusbarVisible() { notImplemented(); return false; } 221 222 void ChromeClientAndroid::setScrollbarsVisible(bool) { notImplemented(); } 223 bool ChromeClientAndroid::scrollbarsVisible() { notImplemented(); return false; } 224 225 void ChromeClientAndroid::setMenubarVisible(bool) { notImplemented(); } 226 bool ChromeClientAndroid::menubarVisible() { notImplemented(); return false; } 227 228 void ChromeClientAndroid::setResizable(bool) { notImplemented(); } 229 230 #if ENABLE(CONTEXT_MENUS) 231 void ChromeClientAndroid::showContextMenu() { notImplemented(); } 232 #endif 233 234 // This function is called by the JavaScript bindings to print usually an error to 235 // a message console. Pass the message to the java side so that the client can 236 // handle it as it sees fit. 237 void ChromeClientAndroid::addMessageToConsole(MessageSource, MessageType, MessageLevel msgLevel, const String& message, unsigned int lineNumber, const String& sourceID) { 238 android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->addMessageToConsole(message, lineNumber, sourceID, msgLevel); 239 } 240 241 void ChromeClientAndroid::formDidBlur(const WebCore::Node* node) { notImplemented(); } 242 bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; } 243 bool ChromeClientAndroid::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) { 244 String url = frame->document()->documentURI(); 245 return android::WebViewCore::getWebViewCore(frame->view())->jsUnload(url, message); 246 } 247 248 void ChromeClientAndroid::closeWindowSoon() 249 { 250 ASSERT(m_webFrame); 251 Page* page = m_webFrame->page(); 252 Frame* mainFrame = page->mainFrame(); 253 // This will prevent javascript cross-scripting during unload 254 page->setGroupName(String()); 255 // Stop loading but do not send the unload event 256 mainFrame->loader()->stopLoading(UnloadEventPolicyNone); 257 // Cancel all pending loaders 258 mainFrame->loader()->stopAllLoaders(); 259 // Remove all event listeners so that no javascript can execute as a result 260 // of mouse/keyboard events. 261 mainFrame->document()->removeAllEventListeners(); 262 // Close the window. 263 m_webFrame->closeWindow(android::WebViewCore::getWebViewCore(mainFrame->view())); 264 } 265 266 void ChromeClientAndroid::runJavaScriptAlert(Frame* frame, const String& message) 267 { 268 String url = frame->document()->documentURI(); 269 270 android::WebViewCore::getWebViewCore(frame->view())->jsAlert(url, message); 271 } 272 273 bool ChromeClientAndroid::runJavaScriptConfirm(Frame* frame, const String& message) 274 { 275 String url = frame->document()->documentURI(); 276 277 return android::WebViewCore::getWebViewCore(frame->view())->jsConfirm(url, message); 278 } 279 280 /* This function is called for the javascript method Window.prompt(). A dialog should be shown on 281 * the screen with an input put box. First param is the text, the second is the default value for 282 * the input box, third is return param. If the function returns true, the value set in the third parameter 283 * is provided to javascript, else null is returned to the script. 284 */ 285 bool ChromeClientAndroid::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result) 286 { 287 String url = frame->document()->documentURI(); 288 return android::WebViewCore::getWebViewCore(frame->view())->jsPrompt(url, message, defaultValue, result); 289 } 290 void ChromeClientAndroid::setStatusbarText(const String&) { notImplemented(); } 291 292 // This is called by the JavaScript interpreter when a script has been running for a long 293 // time. A dialog should be shown to the user asking them if they would like to cancel the 294 // Javascript. If true is returned, the script is cancelled. 295 // To make a device more responsive, we default to return true to disallow long running script. 296 // This implies that some of scripts will not be completed. 297 bool ChromeClientAndroid::shouldInterruptJavaScript() { 298 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 299 return android::WebViewCore::getWebViewCore(frameView)->jsInterrupt(); 300 } 301 302 KeyboardUIMode ChromeClientAndroid::keyboardUIMode() 303 { 304 return KeyboardAccessTabsToLinks; 305 } 306 307 IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); } 308 309 void ChromeClientAndroid::invalidateWindow(const IntRect&, bool) 310 { 311 notImplemented(); 312 } 313 314 void ChromeClientAndroid::invalidateContentsAndWindow(const IntRect& updateRect, bool /*immediate*/) 315 { 316 notImplemented(); 317 } 318 319 void ChromeClientAndroid::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate) 320 { 321 notImplemented(); 322 } 323 324 // new to change 38068 (Nov 6, 2008) 325 void ChromeClientAndroid::scroll(const IntSize& scrollDelta, 326 const IntRect& rectToScroll, const IntRect& clipRect) { 327 notImplemented(); 328 } 329 330 // new to change 38068 (Nov 6, 2008) 331 IntPoint ChromeClientAndroid::screenToWindow(const IntPoint&) const { 332 notImplemented(); 333 return IntPoint(); 334 } 335 336 // new to change 38068 (Nov 6, 2008) 337 IntRect ChromeClientAndroid::windowToScreen(const IntRect&) const { 338 notImplemented(); 339 return IntRect(); 340 } 341 342 PlatformPageClient ChromeClientAndroid::platformPageClient() const { 343 Page* page = m_webFrame->page(); 344 Frame* mainFrame = page->mainFrame(); 345 FrameView* view = mainFrame->view(); 346 PlatformWidget viewBridge = view->platformWidget(); 347 return viewBridge; 348 } 349 350 void ChromeClientAndroid::contentsSizeChanged(Frame*, const IntSize&) const 351 { 352 notImplemented(); 353 } 354 355 void ChromeClientAndroid::scrollRectIntoView(const IntRect&, const ScrollView*) const 356 { 357 notImplemented(); 358 } 359 360 void ChromeClientAndroid::formStateDidChange(const Node*) 361 { 362 notImplemented(); 363 } 364 365 void ChromeClientAndroid::scrollbarsModeDidChange() const 366 { 367 notImplemented(); 368 } 369 370 void ChromeClientAndroid::dispatchViewportDataDidChange(const ViewportArguments& input) const { 371 #ifdef ANDROID_META_SUPPORT 372 const ViewportArguments emptyArgument; 373 if (input == emptyArgument) { 374 // Empty Argument is for a page with no viewport meta tag; so reset everything. 375 m_webFrame->page()->settings()->resetMetadataSettings(); 376 } 377 Document* doc = m_webFrame->page()->mainFrame()->document(); 378 if (!doc->ownerElement()) { 379 FrameView* view = doc->view(); 380 if (view) 381 PlatformBridge::updateViewport(view); 382 } 383 #endif 384 } 385 386 void ChromeClientAndroid::mouseDidMoveOverElement(const HitTestResult&, unsigned int) {} 387 void ChromeClientAndroid::setToolTip(const String&, TextDirection) {} 388 void ChromeClientAndroid::print(Frame*) {} 389 390 /* 391 * This function is called on the main (webcore) thread by SQLTransaction::deliverQuotaIncreaseCallback. 392 * The way that the callback mechanism is designed inside SQLTransaction means that there must be a new quota 393 * (which may be equal to the old quota if the user did not allow more quota) when this function returns. As 394 * we call into the browser thread to ask what to do with the quota, we block here and get woken up when the 395 * browser calls the native WebViewCore::SetDatabaseQuota method with the new quota value. 396 */ 397 #if ENABLE(DATABASE) 398 void ChromeClientAndroid::exceededDatabaseQuota(Frame* frame, const String& name) 399 { 400 SecurityOrigin* origin = frame->document()->securityOrigin(); 401 DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker(); 402 403 m_isNewQuotaSet = false; 404 405 // This origin is being tracked and has exceeded it's quota. Call into 406 // the Java side of things to inform the user. 407 unsigned long long currentQuota = 0; 408 if (tracker.hasEntryForOrigin(origin)) 409 currentQuota = tracker.quotaForOrigin(origin); 410 411 unsigned long long estimatedSize = 0; 412 413 // Only update estimatedSize if we are trying to create a a new database, i.e. the usage for the database is 0. 414 if (tracker.usageForDatabase(name, origin) == 0) 415 estimatedSize = tracker.detailsForNameAndOrigin(name, origin).expectedUsage(); 416 417 if (android::WebViewCore::getWebViewCore(frame->view())->exceededDatabaseQuota(frame->document()->documentURI(), name, currentQuota, estimatedSize)) { 418 // We've sent notification to the browser so now wait for it to come back. 419 m_quotaThreadLock.lock(); 420 while (!m_isNewQuotaSet) { 421 m_quotaThreadCondition.wait(m_quotaThreadLock); 422 } 423 m_quotaThreadLock.unlock(); 424 } else { 425 // We failed to send the message to the UI thread to request a new quota, 426 // so just use the current quota as a default. 427 m_newQuota = currentQuota; 428 } 429 430 if (m_newQuota < currentQuota) 431 m_newQuota = currentQuota; 432 433 // If new quota is unavailable, we may be able to resolve the situation by 434 // shrinking the quota of an origin that asked for a lot but is only using a 435 // little. If we find such a site, shrink it's quota and ask Java to try 436 // again. 437 if (m_newQuota == currentQuota && !m_triedToReclaimDBQuota) { 438 m_triedToReclaimDBQuota = true; // we should only try this once per quota overflow. 439 unsigned long long reclaimedQuotaBytes = tryToReclaimDatabaseQuota(origin); 440 441 // If we were able to free up enough space, try asking Java again. 442 // Otherwise, give up and deny the new database. :( 443 if (reclaimedQuotaBytes >= estimatedSize) { 444 exceededDatabaseQuota(frame, name); 445 return; 446 } 447 } 448 449 // Update the DatabaseTracker with the new quota value (if the user declined 450 // new quota, this may equal the old quota) 451 tracker.setQuota(origin, m_newQuota); 452 m_triedToReclaimDBQuota = false; 453 } 454 455 static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota) { 456 DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker(); 457 Vector<RefPtr<SecurityOrigin> > origins; 458 tracker.origins(origins); 459 unsigned long long reclaimedQuotaBytes = 0; 460 for (unsigned i = 0; i < origins.size(); i++) { 461 SecurityOrigin* originToReclaimFrom = origins[i].get(); 462 463 // Don't try to reclaim from the origin that has exceeded its quota. 464 if (originToReclaimFrom->equal(originNeedingQuota)) 465 continue; 466 467 unsigned long long originUsage = tracker.usageForOrigin(originToReclaimFrom); 468 unsigned long long originQuota = tracker.quotaForOrigin(originToReclaimFrom); 469 // If the origin has a quota that is more than it's current usage +1MB, shrink it. 470 static const int ONE_MB = 1 * 1024 * 1024; 471 if (originUsage + ONE_MB < originQuota) { 472 unsigned long long newQuota = originUsage + ONE_MB; 473 tracker.setQuota(originToReclaimFrom, newQuota); 474 reclaimedQuotaBytes += originQuota - newQuota; 475 } 476 } 477 return reclaimedQuotaBytes; 478 } 479 #endif 480 481 #if ENABLE(OFFLINE_WEB_APPLICATIONS) 482 void ChromeClientAndroid::reachedMaxAppCacheSize(int64_t spaceNeeded) 483 { 484 m_isNewQuotaSet = false; 485 Page* page = m_webFrame->page(); 486 Frame* mainFrame = page->mainFrame(); 487 FrameView* view = mainFrame->view(); 488 489 // If we fail to send the message to the UI thread to request a new quota, 490 // there's nothing to do. 491 if (!android::WebViewCore::getWebViewCore(view)->reachedMaxAppCacheSize(spaceNeeded)) 492 return; 493 494 // We've sent notification to the browser so now wait for it to come back. 495 m_quotaThreadLock.lock(); 496 while (!m_isNewQuotaSet) { 497 m_quotaThreadCondition.wait(m_quotaThreadLock); 498 } 499 m_quotaThreadLock.unlock(); 500 if (m_newQuota > 0) { 501 WebCore::cacheStorage().setMaximumSize(m_newQuota); 502 // Now the app cache will retry the saving the previously failed cache. 503 } 504 } 505 #endif 506 507 void ChromeClientAndroid::populateVisitedLinks() 508 { 509 Page* page = m_webFrame->page(); 510 Frame* mainFrame = page->mainFrame(); 511 FrameView* view = mainFrame->view(); 512 android::WebViewCore::getWebViewCore(view)->populateVisitedLinks(&page->group()); 513 } 514 515 void ChromeClientAndroid::runOpenPanel(Frame* frame, 516 PassRefPtr<FileChooser> chooser) 517 { 518 android::WebViewCore* core = android::WebViewCore::getWebViewCore( 519 frame->view()); 520 core->openFileChooser(chooser); 521 } 522 523 void ChromeClientAndroid::chooseIconForFiles(const Vector<WTF::String>&, FileChooser*) 524 { 525 notImplemented(); 526 } 527 528 void ChromeClientAndroid::setCursor(const Cursor&) 529 { 530 notImplemented(); 531 } 532 533 void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long long newQuota) { 534 MutexLocker locker(m_quotaThreadLock); 535 m_newQuota = newQuota < 0 ? 0 : newQuota; 536 m_isNewQuotaSet = true; 537 m_quotaThreadCondition.signal(); 538 } 539 540 #if ENABLE(TOUCH_EVENTS) 541 void ChromeClientAndroid::needTouchEvents(bool needTouchEvents) 542 { 543 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 544 android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); 545 if (core) 546 core->needTouchEvents(needTouchEvents); 547 } 548 #endif 549 550 bool ChromeClientAndroid::selectItemWritingDirectionIsNatural() 551 { 552 return false; 553 } 554 555 bool ChromeClientAndroid::selectItemAlignmentFollowsMenuWritingDirection() 556 { 557 return false; 558 } 559 560 PassRefPtr<PopupMenu> ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const 561 { 562 return adoptRef(new PopupMenuAndroid(static_cast<ListPopupMenuClient*>(client))); 563 } 564 565 PassRefPtr<SearchPopupMenu> ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const 566 { 567 return adoptRef(new SearchPopupMenuAndroid); 568 } 569 570 void ChromeClientAndroid::reachedApplicationCacheOriginQuota(SecurityOrigin*) 571 { 572 notImplemented(); 573 } 574 575 #if ENABLE(VIDEO) 576 bool ChromeClientAndroid::supportsFullscreenForNode(const Node* node) 577 { 578 return node->hasTagName(HTMLNames::videoTag); 579 } 580 581 void ChromeClientAndroid::enterFullscreenForNode(Node* node) 582 { 583 if (!node->hasTagName(HTMLNames::videoTag)) 584 return; 585 586 HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node); 587 588 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 589 android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); 590 if (core) 591 core->enterFullscreenForVideoLayer(); 592 593 MediaPlayer* player = videoElement->player(); 594 if (player) { 595 // We need to use the same document object as the 596 // MediaPlayerPrivateAndroid::onStopFullscreen(). 597 Document* doc = player->mediaPlayerClient()->mediaPlayerOwningDocument(); 598 if (doc) 599 doc->webkitWillEnterFullScreenForElement(videoElement); 600 // Now the player is responsible to trigger to the java side for 601 // entering full screen mode. 602 player->enterFullscreenMode(); 603 } 604 } 605 606 void ChromeClientAndroid::exitFullscreenForNode(Node* node) 607 { 608 FrameView* frameView = m_webFrame->page()->mainFrame()->view(); 609 android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView); 610 if (core) 611 core->exitFullscreenVideo(); 612 return; 613 } 614 #endif 615 616 #if ENABLE(FULLSCREEN_API) 617 void ChromeClientAndroid::exitFullScreenForElement(Element* element) 618 { 619 if (!element) 620 return; 621 622 HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(element); 623 videoElement->exitFullscreen(); 624 } 625 #endif 626 627 } 628