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