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->layersDraw();
     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) { notImplemented(); return false; }
    165 void ChromeClientAndroid::takeFocus(FocusDirection) { notImplemented(); }
    166 
    167 void ChromeClientAndroid::focusedNodeChanged(Node* node)
    168 {
    169     android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->focusNodeChanged(node);
    170 }
    171 
    172 void ChromeClientAndroid::focusedFrameChanged(Frame*) { notImplemented(); }
    173 
    174 Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&,
    175         const WindowFeatures& features, const NavigationAction&)
    176 {
    177     ASSERT(frame);
    178 #ifdef ANDROID_MULTIPLE_WINDOWS
    179     if (frame->settings() && !(frame->settings()->supportMultipleWindows()))
    180         // If the client doesn't support multiple windows, just return the current page
    181         return frame->page();
    182 #endif
    183 
    184     const WebCoreViewBridge* bridge = frame->view()->platformWidget();
    185     bool dialog = features.dialog || !features.resizable
    186             || (features.heightSet && features.height < bridge->height()
    187                     && features.widthSet && features.width < bridge->width())
    188             || (!features.menuBarVisible && !features.statusBarVisible
    189                     && !features.toolBarVisible && !features.locationBarVisible
    190                     && !features.scrollbarsVisible);
    191     // fullscreen definitely means no dialog
    192     if (features.fullscreen)
    193         dialog = false;
    194     WebCore::Frame* newFrame = m_webFrame->createWindow(dialog,
    195             ScriptController::processingUserGesture());
    196     if (newFrame) {
    197         WebCore::Page* page = newFrame->page();
    198         page->setGroupName(frame->page()->groupName());
    199         return page;
    200     }
    201     return NULL;
    202 }
    203 
    204 void ChromeClientAndroid::show() { notImplemented(); }
    205 
    206 bool ChromeClientAndroid::canRunModal() { notImplemented(); return false; }
    207 void ChromeClientAndroid::runModal() { notImplemented(); }
    208 
    209 void ChromeClientAndroid::setToolbarsVisible(bool) { notImplemented(); }
    210 bool ChromeClientAndroid::toolbarsVisible() { notImplemented(); return false; }
    211 
    212 void ChromeClientAndroid::setStatusbarVisible(bool) { notImplemented(); }
    213 bool ChromeClientAndroid::statusbarVisible() { notImplemented(); return false; }
    214 
    215 void ChromeClientAndroid::setScrollbarsVisible(bool) { notImplemented(); }
    216 bool ChromeClientAndroid::scrollbarsVisible() { notImplemented(); return false; }
    217 
    218 void ChromeClientAndroid::setMenubarVisible(bool) { notImplemented(); }
    219 bool ChromeClientAndroid::menubarVisible() { notImplemented(); return false; }
    220 
    221 void ChromeClientAndroid::setResizable(bool) { notImplemented(); }
    222 
    223 #if ENABLE(CONTEXT_MENUS)
    224 void ChromeClientAndroid::showContextMenu() { notImplemented(); }
    225 #endif
    226 
    227 // This function is called by the JavaScript bindings to print usually an error to
    228 // a message console. Pass the message to the java side so that the client can
    229 // handle it as it sees fit.
    230 void ChromeClientAndroid::addMessageToConsole(MessageSource, MessageType, MessageLevel msgLevel, const String& message, unsigned int lineNumber, const String& sourceID) {
    231     android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->addMessageToConsole(message, lineNumber, sourceID, msgLevel);
    232 }
    233 
    234 void ChromeClientAndroid::formDidBlur(const WebCore::Node* node)
    235 {
    236     android::WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view())->formDidBlur(node);
    237 }
    238 
    239 bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; }
    240 bool ChromeClientAndroid::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) {
    241     String url = frame->document()->documentURI();
    242     return android::WebViewCore::getWebViewCore(frame->view())->jsUnload(url, message);
    243 }
    244 
    245 void ChromeClientAndroid::closeWindowSoon()
    246 {
    247     ASSERT(m_webFrame);
    248     Page* page = m_webFrame->page();
    249     Frame* mainFrame = page->mainFrame();
    250     // This will prevent javascript cross-scripting during unload
    251     page->setGroupName(String());
    252     // Stop loading but do not send the unload event
    253     mainFrame->loader()->stopLoading(UnloadEventPolicyNone);
    254     // Cancel all pending loaders
    255     mainFrame->loader()->stopAllLoaders();
    256     // Remove all event listeners so that no javascript can execute as a result
    257     // of mouse/keyboard events.
    258     mainFrame->document()->removeAllEventListeners();
    259     // Close the window.
    260     m_webFrame->closeWindow(android::WebViewCore::getWebViewCore(mainFrame->view()));
    261 }
    262 
    263 void ChromeClientAndroid::runJavaScriptAlert(Frame* frame, const String& message)
    264 {
    265     String url = frame->document()->documentURI();
    266 
    267     android::WebViewCore::getWebViewCore(frame->view())->jsAlert(url, message);
    268 }
    269 
    270 bool ChromeClientAndroid::runJavaScriptConfirm(Frame* frame, const String& message)
    271 {
    272     String url = frame->document()->documentURI();
    273 
    274     return android::WebViewCore::getWebViewCore(frame->view())->jsConfirm(url, message);
    275 }
    276 
    277 /* This function is called for the javascript method Window.prompt(). A dialog should be shown on
    278  * the screen with an input put box. First param is the text, the second is the default value for
    279  * the input box, third is return param. If the function returns true, the value set in the third parameter
    280  * is provided to javascript, else null is returned to the script.
    281  */
    282 bool ChromeClientAndroid::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result)
    283 {
    284     String url = frame->document()->documentURI();
    285     return android::WebViewCore::getWebViewCore(frame->view())->jsPrompt(url, message, defaultValue, result);
    286 }
    287 void ChromeClientAndroid::setStatusbarText(const String&) { notImplemented(); }
    288 
    289 // This is called by the JavaScript interpreter when a script has been running for a long
    290 // time. A dialog should be shown to the user asking them if they would like to cancel the
    291 // Javascript. If true is returned, the script is cancelled.
    292 // To make a device more responsive, we default to return true to disallow long running script.
    293 // This implies that some of scripts will not be completed.
    294 bool ChromeClientAndroid::shouldInterruptJavaScript() {
    295   FrameView* frameView = m_webFrame->page()->mainFrame()->view();
    296   return android::WebViewCore::getWebViewCore(frameView)->jsInterrupt();
    297 }
    298 
    299 KeyboardUIMode ChromeClientAndroid::keyboardUIMode()
    300 {
    301     return KeyboardAccessDefault;
    302 }
    303 
    304 IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); }
    305 
    306 void ChromeClientAndroid::invalidateWindow(const IntRect&, bool)
    307 {
    308     notImplemented();
    309 }
    310 
    311 void ChromeClientAndroid::invalidateContentsAndWindow(const IntRect& updateRect, bool /*immediate*/)
    312 {
    313     notImplemented();
    314 }
    315 
    316 void ChromeClientAndroid::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
    317 {
    318     notImplemented();
    319 }
    320 
    321 // new to change 38068 (Nov 6, 2008)
    322 void ChromeClientAndroid::scroll(const IntSize& scrollDelta,
    323         const IntRect& rectToScroll, const IntRect& clipRect) {
    324     notImplemented();
    325 }
    326 
    327 // new to change 38068 (Nov 6, 2008)
    328 IntPoint ChromeClientAndroid::screenToWindow(const IntPoint&) const {
    329     notImplemented();
    330     return IntPoint();
    331 }
    332 
    333 // new to change 38068 (Nov 6, 2008)
    334 IntRect ChromeClientAndroid::windowToScreen(const IntRect&) const {
    335     notImplemented();
    336     return IntRect();
    337 }
    338 
    339 PlatformPageClient ChromeClientAndroid::platformPageClient() const {
    340     Page* page = m_webFrame->page();
    341     Frame* mainFrame = page->mainFrame();
    342     FrameView* view = mainFrame->view();
    343     PlatformWidget viewBridge = view->platformWidget();
    344     return viewBridge;
    345 }
    346 
    347 void ChromeClientAndroid::contentsSizeChanged(Frame*, const IntSize&) const
    348 {
    349     notImplemented();
    350 }
    351 
    352 void ChromeClientAndroid::scrollRectIntoView(const IntRect&, const ScrollView*) const
    353 {
    354     notImplemented();
    355 }
    356 
    357 void ChromeClientAndroid::formStateDidChange(const Node*)
    358 {
    359     notImplemented();
    360 }
    361 
    362 void ChromeClientAndroid::scrollbarsModeDidChange() const
    363 {
    364     notImplemented();
    365 }
    366 
    367 void ChromeClientAndroid::dispatchViewportDataDidChange(const ViewportArguments& input) const {
    368 #ifdef ANDROID_META_SUPPORT
    369     const ViewportArguments emptyArgument;
    370     if (input == emptyArgument) {
    371         // Empty Argument is for a page with no viewport meta tag; so reset everything.
    372         m_webFrame->page()->settings()->resetMetadataSettings();
    373     }
    374     Document* doc = m_webFrame->page()->mainFrame()->document();
    375     if (!doc->ownerElement()) {
    376         FrameView* view = doc->view();
    377         if (view)
    378             PlatformBridge::updateViewport(view);
    379     }
    380 #endif
    381 }
    382 
    383 void ChromeClientAndroid::mouseDidMoveOverElement(const HitTestResult&, unsigned int) {}
    384 void ChromeClientAndroid::setToolTip(const String&, TextDirection) {}
    385 void ChromeClientAndroid::print(Frame*) {}
    386 
    387 /*
    388  * This function is called on the main (webcore) thread by SQLTransaction::deliverQuotaIncreaseCallback.
    389  * The way that the callback mechanism is designed inside SQLTransaction means that there must be a new quota
    390  * (which may be equal to the old quota if the user did not allow more quota) when this function returns. As
    391  * we call into the browser thread to ask what to do with the quota, we block here and get woken up when the
    392  * browser calls the native WebViewCore::SetDatabaseQuota method with the new quota value.
    393  */
    394 #if ENABLE(DATABASE)
    395 void ChromeClientAndroid::exceededDatabaseQuota(Frame* frame, const String& name)
    396 {
    397     SecurityOrigin* origin = frame->document()->securityOrigin();
    398     DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker();
    399 
    400     m_isNewQuotaSet = false;
    401 
    402     // This origin is being tracked and has exceeded it's quota. Call into
    403     // the Java side of things to inform the user.
    404     unsigned long long currentQuota = 0;
    405     if (tracker.hasEntryForOrigin(origin))
    406         currentQuota = tracker.quotaForOrigin(origin);
    407 
    408     unsigned long long estimatedSize = 0;
    409 
    410     // Only update estimatedSize if we are trying to create a a new database, i.e. the usage for the database is 0.
    411     if (tracker.usageForDatabase(name, origin) == 0)
    412         estimatedSize = tracker.detailsForNameAndOrigin(name, origin).expectedUsage();
    413 
    414     if (android::WebViewCore::getWebViewCore(frame->view())->exceededDatabaseQuota(frame->document()->documentURI(), name, currentQuota, estimatedSize)) {
    415         // We've sent notification to the browser so now wait for it to come back.
    416         m_quotaThreadLock.lock();
    417         while (!m_isNewQuotaSet) {
    418             m_quotaThreadCondition.wait(m_quotaThreadLock);
    419         }
    420         m_quotaThreadLock.unlock();
    421     } else {
    422         // We failed to send the message to the UI thread to request a new quota,
    423         // so just use the current quota as a default.
    424         m_newQuota = currentQuota;
    425     }
    426 
    427     if (m_newQuota < currentQuota)
    428         m_newQuota = currentQuota;
    429 
    430     // If new quota is unavailable, we may be able to resolve the situation by
    431     // shrinking the quota of an origin that asked for a lot but is only using a
    432     // little. If we find such a site, shrink it's quota and ask Java to try
    433     // again.
    434     if (m_newQuota == currentQuota && !m_triedToReclaimDBQuota) {
    435         m_triedToReclaimDBQuota = true; // we should only try this once per quota overflow.
    436         unsigned long long reclaimedQuotaBytes = tryToReclaimDatabaseQuota(origin);
    437 
    438         // If we were able to free up enough space, try asking Java again.
    439         // Otherwise, give up and deny the new database. :(
    440         if (reclaimedQuotaBytes >= estimatedSize) {
    441             exceededDatabaseQuota(frame, name);
    442             return;
    443         }
    444     }
    445 
    446     // Update the DatabaseTracker with the new quota value (if the user declined
    447     // new quota, this may equal the old quota)
    448     tracker.setQuota(origin, m_newQuota);
    449     m_triedToReclaimDBQuota = false;
    450 }
    451 
    452 static unsigned long long tryToReclaimDatabaseQuota(SecurityOrigin* originNeedingQuota) {
    453     DatabaseTracker& tracker = WebCore::DatabaseTracker::tracker();
    454     Vector<RefPtr<SecurityOrigin> > origins;
    455     tracker.origins(origins);
    456     unsigned long long reclaimedQuotaBytes = 0;
    457     for (unsigned i = 0; i < origins.size(); i++) {
    458         SecurityOrigin* originToReclaimFrom = origins[i].get();
    459 
    460         // Don't try to reclaim from the origin that has exceeded its quota.
    461         if (originToReclaimFrom->equal(originNeedingQuota))
    462             continue;
    463 
    464         unsigned long long originUsage = tracker.usageForOrigin(originToReclaimFrom);
    465         unsigned long long originQuota = tracker.quotaForOrigin(originToReclaimFrom);
    466         // If the origin has a quota that is more than it's current usage +1MB, shrink it.
    467         static const int ONE_MB = 1 * 1024 * 1024;
    468         if (originUsage + ONE_MB < originQuota) {
    469             unsigned long long newQuota = originUsage + ONE_MB;
    470             tracker.setQuota(originToReclaimFrom, newQuota);
    471             reclaimedQuotaBytes += originQuota - newQuota;
    472         }
    473     }
    474     return reclaimedQuotaBytes;
    475 }
    476 #endif
    477 
    478 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
    479 void ChromeClientAndroid::reachedMaxAppCacheSize(int64_t spaceNeeded)
    480 {
    481     m_isNewQuotaSet = false;
    482     Page* page = m_webFrame->page();
    483     Frame* mainFrame = page->mainFrame();
    484     FrameView* view = mainFrame->view();
    485 
    486     // If we fail to send the message to the UI thread to request a new quota,
    487     // there's nothing to do.
    488     if (!android::WebViewCore::getWebViewCore(view)->reachedMaxAppCacheSize(spaceNeeded))
    489         return;
    490 
    491     // We've sent notification to the browser so now wait for it to come back.
    492     m_quotaThreadLock.lock();
    493     while (!m_isNewQuotaSet) {
    494        m_quotaThreadCondition.wait(m_quotaThreadLock);
    495     }
    496     m_quotaThreadLock.unlock();
    497     if (m_newQuota > 0) {
    498         WebCore::cacheStorage().setMaximumSize(m_newQuota);
    499         // Now the app cache will retry the saving the previously failed cache.
    500     }
    501 }
    502 #endif
    503 
    504 void ChromeClientAndroid::populateVisitedLinks()
    505 {
    506     Page* page = m_webFrame->page();
    507     Frame* mainFrame = page->mainFrame();
    508     FrameView* view = mainFrame->view();
    509     android::WebViewCore::getWebViewCore(view)->populateVisitedLinks(&page->group());
    510 }
    511 
    512 void ChromeClientAndroid::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
    513 {
    514     ASSERT(geolocation);
    515     if (!m_geolocationPermissions) {
    516         m_geolocationPermissions = new GeolocationPermissions(android::WebViewCore::getWebViewCore(frame->view()),
    517                                                               m_webFrame->page()->mainFrame());
    518     }
    519     m_geolocationPermissions->queryPermissionState(frame);
    520 }
    521 
    522 void ChromeClientAndroid::cancelGeolocationPermissionRequestForFrame(Frame* frame, WebCore::Geolocation*)
    523 {
    524     if (m_geolocationPermissions)
    525         m_geolocationPermissions->cancelPermissionStateQuery(frame);
    526 }
    527 
    528 void ChromeClientAndroid::provideGeolocationPermissions(const String &origin, bool allow, bool remember)
    529 {
    530     ASSERT(m_geolocationPermissions);
    531     m_geolocationPermissions->providePermissionState(origin, allow, remember);
    532 }
    533 
    534 void ChromeClientAndroid::storeGeolocationPermissions()
    535 {
    536     GeolocationPermissions::maybeStorePermanentPermissions();
    537 }
    538 
    539 void ChromeClientAndroid::onMainFrameLoadStarted()
    540 {
    541     if (m_geolocationPermissions.get())
    542         m_geolocationPermissions->resetTemporaryPermissionStates();
    543 }
    544 
    545 void ChromeClientAndroid::runOpenPanel(Frame* frame,
    546         PassRefPtr<FileChooser> chooser)
    547 {
    548     android::WebViewCore* core = android::WebViewCore::getWebViewCore(
    549             frame->view());
    550     core->openFileChooser(chooser);
    551 }
    552 
    553 void ChromeClientAndroid::chooseIconForFiles(const Vector<WTF::String>&, FileChooser*)
    554 {
    555     notImplemented();
    556 }
    557 
    558 void ChromeClientAndroid::setCursor(const Cursor&)
    559 {
    560     notImplemented();
    561 }
    562 
    563 void ChromeClientAndroid::wakeUpMainThreadWithNewQuota(long long newQuota) {
    564     MutexLocker locker(m_quotaThreadLock);
    565     m_newQuota = newQuota < 0 ? 0 : newQuota;
    566     m_isNewQuotaSet = true;
    567     m_quotaThreadCondition.signal();
    568 }
    569 
    570 #if ENABLE(TOUCH_EVENTS)
    571 void ChromeClientAndroid::needTouchEvents(bool needTouchEvents)
    572 {
    573     FrameView* frameView = m_webFrame->page()->mainFrame()->view();
    574     android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
    575     if (core)
    576         core->needTouchEvents(needTouchEvents);
    577 }
    578 #endif
    579 
    580 bool ChromeClientAndroid::selectItemWritingDirectionIsNatural()
    581 {
    582     return false;
    583 }
    584 
    585 bool ChromeClientAndroid::selectItemAlignmentFollowsMenuWritingDirection()
    586 {
    587     return false;
    588 }
    589 
    590 PassRefPtr<PopupMenu> ChromeClientAndroid::createPopupMenu(PopupMenuClient* client) const
    591 {
    592     return adoptRef(new PopupMenuAndroid(static_cast<ListPopupMenuClient*>(client)));
    593 }
    594 
    595 PassRefPtr<SearchPopupMenu> ChromeClientAndroid::createSearchPopupMenu(PopupMenuClient*) const
    596 {
    597     return adoptRef(new SearchPopupMenuAndroid);
    598 }
    599 
    600 void ChromeClientAndroid::reachedApplicationCacheOriginQuota(SecurityOrigin*)
    601 {
    602     notImplemented();
    603 }
    604 
    605 #if ENABLE(ANDROID_INSTALLABLE_WEB_APPS)
    606 void ChromeClientAndroid::webAppCanBeInstalled()
    607 {
    608     FrameView* frameView = m_webFrame->page()->mainFrame()->view();
    609     android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
    610     if (core)
    611         core->notifyWebAppCanBeInstalled();
    612 }
    613 #endif
    614 
    615 #if ENABLE(VIDEO)
    616 bool ChromeClientAndroid::supportsFullscreenForNode(const Node* node)
    617 {
    618       return node->hasTagName(HTMLNames::videoTag);
    619 }
    620 
    621 void ChromeClientAndroid::enterFullscreenForNode(Node* node)
    622 {
    623       if (!node->hasTagName(HTMLNames::videoTag))
    624           return;
    625 
    626       HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(node);
    627       String url = videoElement->currentSrc();
    628       LayerAndroid* layer = videoElement->platformLayer();
    629       if (!layer)
    630           return;
    631 
    632       FrameView* frameView = m_webFrame->page()->mainFrame()->view();
    633       android::WebViewCore* core = android::WebViewCore::getWebViewCore(frameView);
    634       m_webFrame->page()->mainFrame()->document()->webkitWillEnterFullScreenForElement(videoElement);
    635       if (core)
    636           core->enterFullscreenForVideoLayer(layer->uniqueId(), url);
    637 }
    638 
    639 void ChromeClientAndroid::exitFullscreenForNode(Node* node)
    640 {
    641 }
    642 #endif
    643 
    644 #if ENABLE(FULLSCREEN_API)
    645 void ChromeClientAndroid::exitFullScreenForElement(Element* element)
    646 {
    647     if (!element)
    648         return;
    649 
    650     HTMLMediaElement* videoElement = static_cast<HTMLMediaElement*>(element);
    651     videoElement->exitFullscreen();
    652 }
    653 #endif
    654 
    655 }
    656