Home | History | Annotate | Download | only in WebCoreSupport
      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::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
    516 {
    517     ASSERT(geolocation);
    518     if (!m_geolocationPermissions) {
    519         m_geolocationPermissions = new GeolocationPermissions(android::WebViewCore::getWebViewCore(frame->view()),
    520                                                               m_webFrame->page()->mainFrame());
    521     }
    522     m_geolocationPermissions->queryPermissionState(frame);
    523 }
    524 
    525 void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame, WebCore::Geolocation*)
    526 {
    527     if (m_geolocationPermissions)
    528         m_geolocationPermissions->cancelPermissionStateQuery(frame);
    529 }
    530 
    531 void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember)
    532 {
    533     ASSERT(m_geolocationPermissions);
    534     m_geolocationPermissions->providePermissionState(origin, allow, remember);
    535 }
    536 
    537 void ChromeClientAndroid::storeGeolocationPermissions()
    538 {
    539     GeolocationPermissions::maybeStorePermanentPermissions();
    540 }
    541 
    542 void ChromeClientAndroid::onMainFrameLoadStarted()
    543 {
    544     if (m_geolocationPermissions.get())
    545         m_geolocationPermissions->resetTemporaryPermissionStates();
    546 }
    547 
    548 void ChromeClientAndroid::runOpenPanel(Frame* frame,
    549         PassRefPtr<FileChooser> chooser)
    550 {
    551     android::WebViewCore* core = android::WebViewCore::getWebViewCore(
    552             frame->view());
    553     core->openFileChooser(chooser);
    554 }
    555 
    556 void ChromeClientAndroid::chooseIconForFiles(const Vector<WTF::String>&, FileChooser*)
    557 {
    558     notImplemented();
    559 }
    560 
    561 void ChromeClientAndroid::setCursor(const Cursor&)
    562 {
    563     notImplemented();
    564 }
    565 
    566 void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long long newQuota) {
    567     MutexLocker locker(m_quotaThreadLock);
    568     m_newQuota = newQuota < 0 ? 0 : newQuota;
    569     m_isNewQuotaSet = true;
    570     m_quotaThreadCondition.signal();
    571 }
    572 
    573 #if ENABLE(TOUCH_EVENTS)
    574 void ChromeClientAndroid::needTouchEvents(bool needTouchEvents)
    575 {
    576     FrameView* frameView = m_webFrame->page()->mainFrame()->view();
    577     android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
    578     if (core)
    579         core->needTouchEvents(needTouchEvents);
    580 }
    581 #endif
    582 
    583 bool ChromeClientAndroid::selectItemWritingDirectionIsNatural()
    584 {
    585     return false;
    586 }
    587 
    588 bool ChromeClientAndroid::selectItemAlignmentFollowsMenuWritingDirection()
    589 {
    590     return false;
    591 }
    592 
    593 PassRefPtr<PopupMenu> ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const
    594 {
    595     return adoptRef(new PopupMenuAndroid(static_cast<ListPopupMenuClient*>(client)));
    596 }
    597 
    598 PassRefPtr<SearchPopupMenu> ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const
    599 {
    600     return adoptRef(new SearchPopupMenuAndroid);
    601 }
    602 
    603 void ChromeClientAndroid::reachedApplicationCacheOriginQuota(SecurityOrigin*)
    604 {
    605     notImplemented();
    606 }
    607 
    608 #if ENABLE(ANDROID_INSTALLABLE_WEB_APPS)
    609 void ChromeClientAndroid::webAppCanBeInstalled()
    610 {
    611     FrameView* frameView = m_webFrame->page()->mainFrame()->view();
    612     android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
    613     if (core)
    614         core->notifyWebAppCanBeInstalled();
    615 }
    616 #endif
    617 
    618 #if ENABLE(VIDEO)
    619 bool ChromeClientAndroid::supportsFullscreenForNode(const Node* node)
    620 {
    621       return node->hasTagName(HTMLNames::videoTag);
    622 }
    623 
    624 void ChromeClientAndroid::enterFullscreenForNode(Node* node)
    625 {
    626       if (!node->hasTagName(HTMLNames::videoTag))
    627           return;
    628 
    629       HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node);
    630       String url = videoElement->currentSrc();
    631       LayerAndroid* layer = videoElement->platformLayer();
    632       if (!layer)
    633           return;
    634 
    635       FrameView* frameView = m_webFrame->page()->mainFrame()->view();
    636       android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
    637       m_webFrame->page()->mainFrame()->document()->webkitWillEnterFullScreenForElement(videoElement);
    638       if (core)
    639           core->enterFullscreenForVideoLayer(layer->uniqueId(), url);
    640 }
    641 
    642 void ChromeClientAndroid::exitFullscreenForNode(Node* node)
    643 {
    644     FrameView* frameView = m_webFrame->page()->mainFrame()->view();
    645     android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
    646     if (core)
    647         core->exitFullscreenVideo();
    648     return;
    649 }
    650 #endif
    651 
    652 #if ENABLE(FULLSCREEN_API)
    653 void ChromeClientAndroid::exitFullScreenForElement(Element* element)
    654 {
    655     if (!element)
    656         return;
    657 
    658     HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(element);
    659     videoElement->exitFullscreen();
    660 }
    661 #endif
    662 
    663 }
    664