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 #include "FrameLoaderClientAndroid.h"
     30 
     31 #include "BackForwardList.h"
     32 #include "CString.h"
     33 #include "CachedFrame.h"
     34 #include "CachedFramePlatformDataAndroid.h"
     35 #include "DOMImplementation.h"
     36 #include "Document.h"
     37 #include "DocumentLoader.h"
     38 #include "Frame.h"
     39 #include "FrameLoader.h"
     40 #include "FrameTree.h"
     41 #include "FrameView.h"
     42 #include "GraphicsContext.h"
     43 #include "HTMLFrameOwnerElement.h"
     44 #include "HTMLPlugInElement.h"
     45 #include "HistoryItem.h"
     46 #include "IconDatabase.h"
     47 #include "MIMETypeRegistry.h"
     48 #include "NotImplemented.h"
     49 #include "PackageNotifier.h"
     50 #include "Page.h"
     51 #include "PlatformBridge.h"
     52 #include "PlatformGraphicsContext.h"
     53 #include "PlatformString.h"
     54 #include "PluginDatabase.h"
     55 #include "PluginView.h"
     56 #include "PluginWidget.h"
     57 #include "ProgressTracker.h"
     58 #include "RenderPart.h"
     59 #include "RenderView.h"
     60 #include "RenderWidget.h"
     61 #include "ResourceError.h"
     62 #include "ResourceHandle.h"
     63 #include "ResourceHandleInternal.h"
     64 #include "SelectionController.h"
     65 #include "Settings.h"
     66 #include "SkCanvas.h"
     67 #include "SkRect.h"
     68 #include "TextEncoding.h"
     69 #include "WebCoreFrameBridge.h"
     70 #include "WebCoreResourceLoader.h"
     71 #include "WebHistory.h"
     72 #include "WebIconDatabase.h"
     73 #include "WebFrameView.h"
     74 #include "WebViewCore.h"
     75 #include "android_graphics.h"
     76 
     77 #include <utils/AssetManager.h>
     78 
     79 extern android::AssetManager* globalAssetManager();
     80 
     81 namespace android {
     82 
     83 static const int EXTRA_LAYOUT_DELAY = 1000;
     84 
     85 FrameLoaderClientAndroid::FrameLoaderClientAndroid(WebFrame* webframe)
     86     : m_frame(NULL)
     87     , m_webFrame(webframe)
     88     , m_manualLoader(NULL)
     89     , m_hasSentResponseToPlugin(false)
     90     , m_onDemandPluginsEnabled(false) {
     91     Retain(m_webFrame);
     92 }
     93 
     94 FrameLoaderClientAndroid* FrameLoaderClientAndroid::get(const WebCore::Frame* frame)
     95 {
     96     return static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
     97 }
     98 
     99 void FrameLoaderClientAndroid::frameLoaderDestroyed() {
    100     registerForIconNotification(false);
    101     m_frame = 0;
    102     Release(m_webFrame);
    103     delete this;
    104 }
    105 
    106 bool FrameLoaderClientAndroid::hasWebView() const {
    107     // FIXME,
    108     // there is one web view per page, or top frame.
    109     // as android's view is created from Java side, it is always there.
    110     return true;
    111 }
    112 
    113 void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) {
    114     m_onDemandPluginsEnabled = false;
    115     // don't use representation
    116     verifiedOk();
    117 }
    118 
    119 void FrameLoaderClientAndroid::forceLayout() {
    120     ASSERT(m_frame);
    121     m_frame->view()->forceLayout();
    122     // FIXME, should we adjust view size here?
    123     m_frame->view()->adjustViewSize();
    124 }
    125 
    126 void FrameLoaderClientAndroid::forceLayoutForNonHTML() {
    127     notImplemented();
    128 }
    129 
    130 void FrameLoaderClientAndroid::setCopiesOnScroll() {
    131     // this is a hint about whether we need to force redraws, or can
    132     // just copy the scrolled content. Since we always force a redraw
    133     // anyways, we can ignore this call.
    134     verifiedOk();
    135 }
    136 
    137 void FrameLoaderClientAndroid::detachedFromParent2() {
    138     // FIXME, ready to detach frame from view
    139 }
    140 
    141 void FrameLoaderClientAndroid::detachedFromParent3() {
    142     // FIXME, ready to release view
    143     notImplemented();
    144 }
    145 
    146 // This function is responsible for associating the "id" with a given
    147 // subresource load.  The following functions that accept an "id" are
    148 // called for each subresource, so they should not be dispatched to the m_frame.
    149 void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id,
    150                             DocumentLoader*, const ResourceRequest&) {
    151     lowPriority_notImplemented();
    152 }
    153 
    154 void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id,
    155                             ResourceRequest&, const ResourceResponse&) {
    156     lowPriority_notImplemented();
    157 }
    158 
    159 bool FrameLoaderClientAndroid::shouldUseCredentialStorage(DocumentLoader*, unsigned long  identifier)
    160 {
    161     notImplemented();
    162     return false;
    163 }
    164 
    165 void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*,
    166                             unsigned long id, const AuthenticationChallenge&) {
    167     lowPriority_notImplemented();
    168 }
    169 
    170 void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*,
    171                             unsigned long id, const AuthenticationChallenge&) {
    172     lowPriority_notImplemented();
    173 }
    174 
    175 void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*,
    176                             unsigned long id, const ResourceResponse&) {
    177     lowPriority_notImplemented();
    178 }
    179 
    180 void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*,
    181                             unsigned long id, int lengthReceived) {
    182     lowPriority_notImplemented();
    183 }
    184 
    185 void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*,
    186                             unsigned long id) {
    187     lowPriority_notImplemented();
    188 }
    189 
    190 void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader,
    191                             unsigned long id, const ResourceError&) {
    192     lowPriority_notImplemented();
    193 }
    194 
    195 bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*,
    196                             const ResourceRequest&, const ResourceResponse&, int length) {
    197     notImplemented();
    198     return false;
    199 }
    200 
    201 void FrameLoaderClientAndroid::dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString&) {
    202     return;
    203 }
    204 
    205 void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() {
    206 }
    207 
    208 void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() {
    209     ASSERT(m_frame);
    210     // Tell the load it was a redirect.
    211     m_webFrame->loadStarted(m_frame);
    212 }
    213 
    214 void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() {
    215     notImplemented();
    216 }
    217 
    218 void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&,
    219                                 double interval, double fireDate) {
    220     notImplemented();
    221 }
    222 
    223 void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() {
    224     notImplemented();
    225 }
    226 
    227 void FrameLoaderClientAndroid::dispatchDidPushStateWithinPage()
    228 {
    229     notImplemented();
    230 }
    231 
    232 void FrameLoaderClientAndroid::dispatchDidReplaceStateWithinPage()
    233 {
    234     notImplemented();
    235 }
    236 
    237 void FrameLoaderClientAndroid::dispatchDidPopStateWithinPage()
    238 {
    239     notImplemented();
    240 }
    241 
    242 void FrameLoaderClientAndroid::dispatchWillClose() {
    243     notImplemented();
    244 }
    245 
    246 void FrameLoaderClientAndroid::dispatchDidReceiveIcon() {
    247     ASSERT(m_frame);
    248     if (m_frame->tree() && m_frame->tree()->parent())
    249         return;
    250     WebCore::String url(m_frame->loader()->url().string());
    251     // Try to obtain the icon image.
    252     WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(
    253             url, WebCore::IntSize(16, 16));
    254     // If the request fails, try the original request url.
    255     if (!icon) {
    256         DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
    257         KURL originalURL = docLoader->originalRequest().url();
    258         icon = WebCore::iconDatabase()->iconForPageURL(
    259                    originalURL, WebCore::IntSize(16, 16));
    260     }
    261     // There is a bug in webkit where cancelling an icon load is treated as a
    262     // failure. When this is fixed, we can ASSERT again that we have an icon.
    263     if (icon) {
    264         LOGV("Received icon (%p) for %s", icon,
    265                 url.utf8().data());
    266         m_webFrame->didReceiveIcon(icon);
    267     } else {
    268         LOGV("Icon data for %s unavailable, registering for notification...",
    269                 url.utf8().data());
    270         registerForIconNotification();
    271     }
    272 }
    273 
    274 void FrameLoaderClientAndroid::dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) {
    275     ASSERT(m_frame);
    276     // Do not report sub frame touch icons
    277     if (m_frame->tree() && m_frame->tree()->parent())
    278         return;
    279     m_webFrame->didReceiveTouchIconURL(url, precomposed);
    280 }
    281 
    282 void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() {
    283     notImplemented();
    284 }
    285 
    286 void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const String& title) {
    287     ASSERT(m_frame);
    288     // Used to check for FrameLoadTypeStandard but we only want to send the title for
    289     // the top frame and not sub-frames.
    290     if (!m_frame->tree() || !m_frame->tree()->parent()) {
    291         m_webFrame->setTitle(title);
    292     }
    293 }
    294 
    295 void FrameLoaderClientAndroid::dispatchDidCommitLoad() {
    296     verifiedOk();
    297 }
    298 
    299 static void loadDataIntoFrame(Frame* frame, KURL baseUrl, const String& url,
    300         const String& data) {
    301     if (baseUrl.isEmpty()) {
    302         baseUrl = blankURL();
    303     }
    304     ResourceRequest request(baseUrl);
    305     CString cstr = data.utf8();
    306     RefPtr<WebCore::SharedBuffer> buf = WebCore::SharedBuffer::create(cstr.data(), cstr.length());
    307     SubstituteData subData(buf, String("text/html"), String("utf-8"),
    308             KURL(KURL(), url));
    309     frame->loader()->load(request, subData, false);
    310 }
    311 
    312 void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) {
    313     ASSERT(m_frame);
    314     // Ignore ErrorInterrupted since it is due to a policy interruption. This
    315     // is caused by a decision to download the main resource rather than
    316     // display it.
    317     if (error.errorCode() == InternalErrorInterrupted
    318             || error.errorCode() == InternalErrorCancelled) {
    319         // If we decided to download the main resource or if the user cancelled
    320         // it, make sure we report that the load is done.
    321         didFinishLoad();
    322         return;
    323     }
    324 
    325     AssetManager* am = globalAssetManager();
    326 
    327     // Check to see if the error code was not generated internally
    328     WebCore::PlatformBridge::rawResId id = WebCore::PlatformBridge::NoDomain;
    329     if ((error.errorCode() == ErrorFile ||
    330             error.errorCode() == ErrorFileNotFound) &&
    331             (!error.localizedDescription().isEmpty())) {
    332         id = WebCore::PlatformBridge::LoadError;
    333     }
    334     String filename = m_webFrame->getRawResourceFilename(id);
    335     if (filename.isEmpty())
    336         return;
    337 
    338     // Grab the error page from the asset manager
    339     Asset* a = am->openNonAsset(
    340             filename.utf8().data(), Asset::ACCESS_BUFFER);
    341     if (!a)
    342         return;
    343 
    344     // Take the failing url and encode html entities so javascript urls are not
    345     // executed.
    346     CString failingUrl = error.failingURL().utf8();
    347     WTF::Vector<char> url;
    348     int len = failingUrl.length();
    349     const char* data = failingUrl.data();
    350     for (int i = 0; i < len; i++) {
    351         char c = data[i];
    352         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
    353                 || (c >= '0' && c <= '9'))
    354             url.append(c);
    355         else {
    356             char buf[16];
    357             int res = sprintf(buf, "&#%d;", c);
    358             buf[res] = 0;
    359             url.append(buf, res);
    360         }
    361     }
    362 
    363     // Replace all occurances of %s with the failing url.
    364     String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength());
    365     s = s.replace("%s", String(url.data(), url.size()));
    366 
    367     // Replace all occurances of %e with the error text
    368     s = s.replace("%e", error.localizedDescription());
    369 
    370     // Create the request and the substitute data and tell the FrameLoader to
    371     // load with the replacement data.
    372     // use KURL(const char*) as KURL(const String& url) can trigger ASSERT for
    373     // invalidate URL string.
    374     loadDataIntoFrame(m_frame, KURL(ParsedURLString, data), error.failingURL(), s);
    375 
    376     // Delete the asset.
    377     delete a;
    378 }
    379 
    380 void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) {
    381     // called when page is completed with error
    382     didFinishLoad();
    383 }
    384 
    385 void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() {
    386     // called when finishedParsing
    387     lowPriority_notImplemented();
    388 }
    389 
    390 void FrameLoaderClientAndroid::dispatchDidFinishLoad() {
    391     didFinishLoad();
    392 }
    393 
    394 void FrameLoaderClientAndroid::dispatchDidFirstLayout() {
    395     ASSERT(m_frame);
    396     m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY);
    397     // we need to do this here instead of dispatchDidFirstVisuallyNonEmptyLayout
    398     // so that about:blank will update the screen.
    399     if (!m_frame->tree()->parent()) {
    400         // Only need to notify Java side for the top frame
    401         WebViewCore::getWebViewCore(m_frame->view())->didFirstLayout();
    402     }
    403 }
    404 
    405 void FrameLoaderClientAndroid::dispatchDidFirstVisuallyNonEmptyLayout()
    406 {
    407     notImplemented();
    408 }
    409 
    410 Frame* FrameLoaderClientAndroid::dispatchCreatePage() {
    411     ASSERT(m_frame);
    412 #ifdef ANDROID_MULTIPLE_WINDOWS
    413     if (m_frame->settings() && m_frame->settings()->supportMultipleWindows())
    414         // Always a user gesture since window.open maps to
    415         // ChromeClientAndroid::createWindow
    416         return m_webFrame->createWindow(false, true);
    417     else
    418 #endif
    419         // If the client doesn't support multiple windows, just replace the
    420         // current frame's contents.
    421         return m_frame;
    422 }
    423 
    424 void FrameLoaderClientAndroid::dispatchShow() {
    425     ASSERT(m_frame);
    426     m_frame->view()->invalidate();
    427 }
    428 
    429 
    430 static bool TreatAsAttachment(const String& content_disposition) {
    431     // Some broken sites just send
    432     // Content-Disposition: ; filename="file"
    433     // screen those out here.
    434     if (content_disposition.startsWith(";"))
    435         return false;
    436 
    437     if (content_disposition.startsWith("inline", false))
    438         return false;
    439 
    440     // Some broken sites just send
    441     // Content-Disposition: filename="file"
    442     // without a disposition token... screen those out.
    443     if (content_disposition.startsWith("filename", false))
    444         return false;
    445 
    446     // Also in use is Content-Disposition: name="file"
    447     if (content_disposition.startsWith("name", false))
    448         return false;
    449 
    450     // We have a content-disposition of "attachment" or unknown.
    451     // RFC 2183, section 2.8 says that an unknown disposition
    452     // value should be treated as "attachment"
    453     return true;
    454 }
    455 
    456 void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFunction func,
    457                                 const String& MIMEType, const ResourceRequest& request) {
    458     ASSERT(m_frame);
    459     ASSERT(func);
    460     if (!func)
    461         return;
    462     if (request.isNull()) {
    463         (m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
    464         return;
    465     }
    466     // Default to Use (display internally).
    467     PolicyAction action = PolicyUse;
    468     // Check if we should Download instead.
    469     const ResourceResponse& response = m_frame->loader()->activeDocumentLoader()->response();
    470     const String& content_disposition = response.httpHeaderField("Content-Disposition");
    471     if (!content_disposition.isEmpty()) {
    472         // Server wants to override our normal policy.
    473         if (TreatAsAttachment(content_disposition)) {
    474             // Check to see if we are a sub frame (main frame has no owner element)
    475             if (m_frame->ownerElement() != 0)
    476                 action = PolicyIgnore;
    477             else
    478                 action = PolicyDownload;
    479         }
    480     } else {
    481         // Ask if it can be handled internally.
    482         if (!canShowMIMEType(MIMEType)) {
    483             // Check to see if we are a sub frame (main frame has no owner element)
    484             if (m_frame->ownerElement() != 0)
    485                 action = PolicyIgnore;
    486             else
    487                 action = PolicyDownload;
    488         }
    489     }
    490     // A status code of 204 indicates no content change. Ignore the result.
    491     WebCore::DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
    492     if (docLoader->response().httpStatusCode() == 204)
    493         action = PolicyIgnore;
    494     (m_frame->loader()->policyChecker()->*func)(action);
    495 }
    496 
    497 void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,
    498                                 const NavigationAction& action, const ResourceRequest& request,
    499                                 PassRefPtr<FormState> formState, const String& frameName) {
    500     ASSERT(m_frame);
    501     ASSERT(func);
    502     if (!func)
    503         return;
    504 
    505     if (request.isNull()) {
    506         (m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
    507         return;
    508     }
    509 
    510     if (action.type() == NavigationTypeFormSubmitted || action.type() == NavigationTypeFormResubmitted)
    511         m_frame->loader()->resetMultipleFormSubmissionProtection();
    512 
    513     // If we get to this point it means that a link has a target that was not
    514     // found by the frame tree. Instead of creating a new frame, return the
    515     // current frame in dispatchCreatePage.
    516     if (canHandleRequest(request))
    517         (m_frame->loader()->policyChecker()->*func)(PolicyUse);
    518     else
    519         (m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
    520 }
    521 
    522 void FrameLoaderClientAndroid::cancelPolicyCheck() {
    523     lowPriority_notImplemented();
    524 }
    525 
    526 void FrameLoaderClientAndroid::dispatchUnableToImplementPolicy(const ResourceError&) {
    527     notImplemented();
    528 }
    529 
    530 void FrameLoaderClientAndroid::dispatchDecidePolicyForNavigationAction(FramePolicyFunction func,
    531                                 const NavigationAction& action, const ResourceRequest& request,
    532                                 PassRefPtr<FormState> formState) {
    533     ASSERT(m_frame);
    534     ASSERT(func);
    535     if (!func)
    536         return;
    537     if (request.isNull()) {
    538         (m_frame->loader()->policyChecker()->*func)(PolicyIgnore);
    539         return;
    540     }
    541 
    542     // Reset multiple form submission protection. If this is a resubmission, we check with the
    543     // user and reset the protection if they choose to resubmit the form (see WebCoreFrameBridge.cpp)
    544     if (action.type() == NavigationTypeFormSubmitted)
    545         m_frame->loader()->resetMultipleFormSubmissionProtection();
    546 
    547     if (action.type() == NavigationTypeFormResubmitted) {
    548         m_webFrame->decidePolicyForFormResubmission(func);
    549         return;
    550     } else {
    551         (m_frame->loader()->policyChecker()->*func)(PolicyUse);
    552     }
    553 }
    554 
    555 void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, PassRefPtr<FormState>) {
    556     ASSERT(m_frame);
    557     ASSERT(func);
    558     (m_frame->loader()->policyChecker()->*func)(PolicyUse);
    559 }
    560 
    561 void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) {
    562     notImplemented();
    563 }
    564 
    565 void FrameLoaderClientAndroid::revertToProvisionalState(DocumentLoader*) {
    566     notImplemented();
    567 }
    568 
    569 void FrameLoaderClientAndroid::setMainDocumentError(DocumentLoader* docLoader, const ResourceError& error) {
    570     ASSERT(m_frame);
    571     if (m_manualLoader) {
    572         m_manualLoader->didFail(error);
    573         m_manualLoader = NULL;
    574         m_hasSentResponseToPlugin = false;
    575     } else {
    576         if (!error.isNull() && error.errorCode() >= InternalErrorLast)
    577             m_webFrame->reportError(error.errorCode(),
    578                     error.localizedDescription(), error.failingURL());
    579     }
    580 }
    581 
    582 // This function is called right before the progress is updated.
    583 void FrameLoaderClientAndroid::willChangeEstimatedProgress() {
    584     verifiedOk();
    585 }
    586 
    587 // This function is called after the progress has been updated. The bad part
    588 // about this is that when a page is completed, this function is called after
    589 // the progress has been reset to 0.
    590 void FrameLoaderClientAndroid::didChangeEstimatedProgress() {
    591     verifiedOk();
    592 }
    593 
    594 // This will give us the initial estimate when the page first starts to load.
    595 void FrameLoaderClientAndroid::postProgressStartedNotification() {
    596     ASSERT(m_frame);
    597     if (m_frame->page())
    598         m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress());
    599 }
    600 
    601 // This will give us any updated progress including the final progress.
    602 void FrameLoaderClientAndroid::postProgressEstimateChangedNotification() {
    603     ASSERT(m_frame);
    604     if (m_frame->page())
    605         m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress());
    606 }
    607 
    608 // This is just a notification that the progress has finished. Don't call
    609 // setProgress(1) because postProgressEstimateChangedNotification will do so.
    610 void FrameLoaderClientAndroid::postProgressFinishedNotification() {
    611     WebViewCore* core =  WebViewCore::getWebViewCore(m_frame->view());
    612     if (!m_frame->tree()->parent()) {
    613         // only need to notify Java for the top frame
    614         core->notifyProgressFinished();
    615     }
    616     // notify plugins that the frame has loaded
    617     core->notifyPluginsOnFrameLoad(m_frame);
    618 }
    619 
    620 void FrameLoaderClientAndroid::setMainFrameDocumentReady(bool) {
    621     // this is only interesting once we provide an external API for the DOM
    622     notImplemented();
    623 }
    624 
    625 void FrameLoaderClientAndroid::startDownload(const ResourceRequest&) {
    626     notImplemented();
    627 }
    628 
    629 void FrameLoaderClientAndroid::willChangeTitle(DocumentLoader*) {
    630     verifiedOk();
    631 }
    632 
    633 void FrameLoaderClientAndroid::didChangeTitle(DocumentLoader* loader) {
    634     verifiedOk();
    635 }
    636 
    637 void FrameLoaderClientAndroid::finishedLoading(DocumentLoader* docLoader) {
    638     // Telling the frame we received some data and passing 0 as the data is our
    639     // way to get work done that is normally done when the first bit of data is
    640     // received, even for the case of a document with no data (like about:blank)
    641     if (!m_manualLoader) {
    642         committedLoad(docLoader, 0, 0);
    643         return;
    644     }
    645 
    646     m_manualLoader->didFinishLoading();
    647     m_manualLoader = NULL;
    648     m_hasSentResponseToPlugin = false;
    649 }
    650 
    651 void FrameLoaderClientAndroid::updateGlobalHistory() {
    652     ASSERT(m_frame);
    653 
    654     DocumentLoader* docLoader = m_frame->loader()->documentLoader();
    655     ASSERT(docLoader);
    656 
    657     // Code copied from FrameLoader.cpp:createHistoryItem
    658     // Only add this URL to the database if it is a valid page
    659     if (docLoader->unreachableURL().isEmpty()
    660             && docLoader->response().httpStatusCode() < 400) {
    661         m_webFrame->updateVisitedHistory(docLoader->urlForHistory(), false);
    662         if (!docLoader->serverRedirectSourceForHistory().isNull())
    663             m_webFrame->updateVisitedHistory(KURL(ParsedURLString, docLoader->serverRedirectDestinationForHistory()), false);
    664     }
    665 }
    666 
    667 void FrameLoaderClientAndroid::updateGlobalHistoryRedirectLinks() {
    668     // Note, do we need to do anything where there is no HistoryItem? If we call
    669     // updateGlobalHistory(), we will add bunch of "data:xxx" urls for gmail.com
    670     // which is not what we want. Opt to do nothing now.
    671 }
    672 
    673 bool FrameLoaderClientAndroid::shouldGoToHistoryItem(HistoryItem* item) const {
    674     // hmmm, seems like we might do a more thoughtful check
    675     ASSERT(m_frame);
    676     return item != NULL;
    677 }
    678 
    679 void FrameLoaderClientAndroid::didDisplayInsecureContent()
    680 {
    681     notImplemented();
    682 }
    683 
    684 void FrameLoaderClientAndroid::didRunInsecureContent(SecurityOrigin*)
    685 {
    686     notImplemented();
    687 }
    688 
    689 void FrameLoaderClientAndroid::committedLoad(DocumentLoader* loader, const char* data, int length) {
    690     if (!m_manualLoader) {
    691         ASSERT(m_frame);
    692         String encoding = loader->overrideEncoding();
    693         bool userChosen = !encoding.isNull();
    694         if (encoding.isNull())
    695             encoding = loader->response().textEncodingName();
    696         loader->frameLoader()->setEncoding(encoding, userChosen);
    697         Document *doc = m_frame->document();
    698         if (doc)
    699             loader->frameLoader()->addData(data, length);
    700     }
    701     if (m_manualLoader) {
    702         if (!m_hasSentResponseToPlugin) {
    703             m_manualLoader->didReceiveResponse(loader->response());
    704             // Failure could cause the main document to have an error causing
    705             // the manual loader to be reset.
    706             if (!m_manualLoader)
    707                 return;
    708             m_hasSentResponseToPlugin = true;
    709         }
    710         m_manualLoader->didReceiveData(data, length);
    711     }
    712 }
    713 
    714 ResourceError FrameLoaderClientAndroid::cancelledError(const ResourceRequest& request) {
    715     return ResourceError(String(), InternalErrorCancelled, request.url(), String());
    716 }
    717 
    718 ResourceError FrameLoaderClientAndroid::cannotShowURLError(const ResourceRequest& request) {
    719     return ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String());
    720 }
    721 
    722 ResourceError FrameLoaderClientAndroid::interruptForPolicyChangeError(const ResourceRequest& request) {
    723     return ResourceError(String(), InternalErrorInterrupted, request.url(), String());
    724 }
    725 
    726 ResourceError FrameLoaderClientAndroid::cannotShowMIMETypeError(const ResourceResponse& request) {
    727     return ResourceError(String(), InternalErrorCannotShowMimeType, request.url(), String());
    728 }
    729 
    730 ResourceError FrameLoaderClientAndroid::fileDoesNotExistError(const ResourceResponse& request) {
    731     return ResourceError(String(), InternalErrorFileDoesNotExist, request.url(), String());
    732 }
    733 
    734 ResourceError FrameLoaderClientAndroid::pluginWillHandleLoadError(const ResourceResponse& request) {
    735     return ResourceError(String(), InternalErrorPluginWillHandleLoadError, request.url(), String());
    736 }
    737 
    738 bool FrameLoaderClientAndroid::shouldFallBack(const ResourceError&) {
    739     notImplemented();
    740     return false;
    741 }
    742 
    743 bool FrameLoaderClientAndroid::canHandleRequest(const ResourceRequest& request) const {
    744     ASSERT(m_frame);
    745     // Don't allow hijacking of intrapage navigation
    746     if (WebCore::equalIgnoringFragmentIdentifier(request.url(), m_frame->loader()->url()))
    747         return true;
    748 
    749     // Don't allow hijacking of iframe urls that are http or https
    750     if (request.url().protocol().startsWith("http", false) &&
    751             m_frame->tree() && m_frame->tree()->parent())
    752         return true;
    753 
    754     return m_webFrame->canHandleRequest(request);
    755 }
    756 
    757 bool FrameLoaderClientAndroid::canShowMIMEType(const String& mimeType) const {
    758     // FIXME: This looks like it has to do with whether or not a type can be
    759     // shown "internally" (i.e. inside the browser) regardless of whether
    760     // or not the browser is doing the rendering, e.g. a full page plugin.
    761     if (MIMETypeRegistry::isSupportedImageResourceMIMEType(mimeType) ||
    762             MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType) ||
    763             MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) ||
    764             (m_frame && m_frame->settings()
    765                     && m_frame->settings()->arePluginsEnabled()
    766                     && PluginDatabase::installedPlugins()->isMIMETypeRegistered(
    767                             mimeType)) ||
    768             DOMImplementation::isTextMIMEType(mimeType) ||
    769             DOMImplementation::isXMLMIMEType(mimeType))
    770         return true;
    771     return false;
    772 }
    773 
    774 bool FrameLoaderClientAndroid::representationExistsForURLScheme(const String&) const {
    775     // don't use representation
    776     verifiedOk();
    777     return false;
    778 }
    779 
    780 String FrameLoaderClientAndroid::generatedMIMETypeForURLScheme(const String& URLScheme) const {
    781     // FIXME, copy from Apple's port
    782     String mimetype("x-apple-web-kit/");
    783     mimetype.append(URLScheme.lower());
    784     return mimetype;
    785 }
    786 
    787 void FrameLoaderClientAndroid::frameLoadCompleted() {
    788     // copied from Apple port, without this back with sub-frame will trigger ASSERT
    789     ASSERT(m_frame);
    790 }
    791 
    792 void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) {
    793     ASSERT(m_frame);
    794     ASSERT(item);
    795     // We should have added a bridge when the child item was added to its
    796     // parent.
    797     AndroidWebHistoryBridge* bridge = item->bridge();
    798     ASSERT(bridge);
    799     // store the current scale (only) for the top frame
    800     if (!m_frame->tree()->parent()) {
    801         WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
    802         bridge->setScale((int)(webViewCore->scale() * 100));
    803         bridge->setScreenWidthScale((int)(webViewCore->screenWidthScale() * 100));
    804     }
    805 
    806     WebCore::notifyHistoryItemChanged(item);
    807 }
    808 
    809 void FrameLoaderClientAndroid::restoreViewState() {
    810     WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
    811     HistoryItem* item = m_frame->loader()->history()->currentItem();
    812     AndroidWebHistoryBridge* bridge = item->bridge();
    813     // restore the scale (only) for the top frame
    814     if (!m_frame->tree()->parent()) {
    815         int scale = bridge->scale();
    816         webViewCore->restoreScale(scale);
    817         int screenWidthScale = bridge->screenWidthScale();
    818         if (screenWidthScale != scale)
    819             webViewCore->restoreScreenWidthScale(screenWidthScale);
    820     }
    821 }
    822 
    823 void FrameLoaderClientAndroid::dispatchDidAddBackForwardItem(HistoryItem* item) const {
    824     ASSERT(m_frame);
    825     m_webFrame->addHistoryItem(item);
    826 }
    827 
    828 void FrameLoaderClientAndroid::dispatchDidRemoveBackForwardItem(HistoryItem* item) const {
    829     ASSERT(m_frame);
    830     m_webFrame->removeHistoryItem(0);
    831 }
    832 
    833 void FrameLoaderClientAndroid::dispatchDidChangeBackForwardIndex() const {
    834     ASSERT(m_frame);
    835     BackForwardList* list = m_frame->page()->backForwardList();
    836     ASSERT(list);
    837     m_webFrame->updateHistoryIndex(list->backListCount());
    838 }
    839 
    840 void FrameLoaderClientAndroid::provisionalLoadStarted() {
    841     ASSERT(m_frame);
    842     m_webFrame->loadStarted(m_frame);
    843 }
    844 
    845 void FrameLoaderClientAndroid::didFinishLoad() {
    846     ASSERT(m_frame);
    847     m_frame->document()->setExtraLayoutDelay(0);
    848     m_webFrame->didFinishLoad(m_frame);
    849 }
    850 
    851 void FrameLoaderClientAndroid::prepareForDataSourceReplacement() {
    852     verifiedOk();
    853 }
    854 
    855 PassRefPtr<DocumentLoader> FrameLoaderClientAndroid::createDocumentLoader(
    856                     const ResourceRequest& request, const SubstituteData& data) {
    857     RefPtr<DocumentLoader> loader = DocumentLoader::create(request, data);
    858     return loader.release();
    859 }
    860 
    861 void FrameLoaderClientAndroid::setTitle(const String& title, const KURL& url) {
    862     // Not needed. dispatchDidReceiveTitle is called immediately after this.
    863     // url is used to update the Apple port history items.
    864     verifiedOk();
    865 }
    866 
    867 String FrameLoaderClientAndroid::userAgent(const KURL& u) {
    868     return m_webFrame->userAgentForURL(&u);
    869 }
    870 
    871 void FrameLoaderClientAndroid::savePlatformDataToCachedFrame(WebCore::CachedFrame* cachedFrame) {
    872     CachedFramePlatformDataAndroid* platformData = new CachedFramePlatformDataAndroid(m_frame->settings());
    873     cachedFrame->setCachedFramePlatformData(platformData);
    874 }
    875 
    876 void FrameLoaderClientAndroid::transitionToCommittedFromCachedFrame(WebCore::CachedFrame* cachedFrame) {
    877     CachedFramePlatformDataAndroid* platformData = reinterpret_cast<CachedFramePlatformDataAndroid*>(cachedFrame->cachedFramePlatformData());
    878 #ifdef ANDROID_META_SUPPORT
    879    platformData->restoreMetadata(m_frame->settings());
    880 #endif
    881    m_webFrame->transitionToCommitted(m_frame);
    882 }
    883 
    884 void FrameLoaderClientAndroid::transitionToCommittedForNewPage() {
    885     ASSERT(m_frame);
    886 
    887 #ifdef ANDROID_META_SUPPORT
    888     // reset metadata settings for the main frame as they are not preserved cross page
    889     if (m_frame == m_frame->page()->mainFrame() && m_frame->settings())
    890         m_frame->settings()->resetMetadataSettings();
    891 #endif
    892 
    893     // Save the old WebViewCore before creating a new FrameView. There is one
    894     // WebViewCore per page. Each frame, including the main frame and sub frame,
    895     // has a 1:1 FrameView and WebFrameView.
    896     WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
    897     Retain(webViewCore);
    898 
    899     // Save the old WebFrameView's bounds and apply them to the new WebFrameView
    900     WebFrameView* oldWebFrameView = static_cast<WebFrameView*> (m_frame->view()->platformWidget());
    901     IntRect bounds = oldWebFrameView->getBounds();
    902     IntRect windowBounds = oldWebFrameView->getWindowBounds();
    903     WebCore::FrameView* oldFrameView = oldWebFrameView->view();
    904     m_frame->createView(bounds.size(), oldFrameView->baseBackgroundColor(), oldFrameView->isTransparent(), IntSize(), false);
    905 
    906     // Create a new WebFrameView for the new FrameView
    907     WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore);
    908     newFrameView->setLocation(bounds.x(), bounds.y());
    909     newFrameView->setSize(bounds.width(), bounds.height());
    910     newFrameView->setWindowBounds(windowBounds.x(), windowBounds.y(), windowBounds.width(), windowBounds.height());
    911     // newFrameView attaches itself to FrameView which Retains the reference, so
    912     // call Release for newFrameView
    913     Release(newFrameView);
    914     // WebFrameView Retains webViewCore, so call Release for webViewCore
    915     Release(webViewCore);
    916 
    917     m_webFrame->transitionToCommitted(m_frame);
    918 }
    919 
    920 bool FrameLoaderClientAndroid::canCachePage() const {
    921     return true;
    922 }
    923 
    924 void FrameLoaderClientAndroid::download(ResourceHandle* handle, const ResourceRequest&,
    925                                 const ResourceRequest&, const ResourceResponse&) {
    926     // Get the C++ side of the load listener and tell it to handle the download
    927     handle->getInternal()->m_loader->downloadFile();
    928 }
    929 
    930 WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL& url, const String& name,
    931                         HTMLFrameOwnerElement* ownerElement, const String& referrer,
    932                         bool allowsScrolling, int marginWidth, int marginHeight)
    933 {
    934     Frame* parent = ownerElement->document()->frame();
    935     FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(m_webFrame);
    936     RefPtr<Frame> pFrame = Frame::create(parent->page(), ownerElement, loaderC);
    937     Frame* newFrame = pFrame.get();
    938     loaderC->setFrame(newFrame);
    939     // Append the subframe to the parent and set the name of the subframe. The name must be set after
    940     // appending the child so that the name becomes unique.
    941     parent->tree()->appendChild(newFrame);
    942     newFrame->tree()->setName(name);
    943     // Create a new FrameView and WebFrameView for the child frame to draw into.
    944     RefPtr<FrameView> frameView = FrameView::create(newFrame);
    945     WebFrameView* webFrameView = new WebFrameView(frameView.get(),
    946             WebViewCore::getWebViewCore(parent->view()));
    947     // frameView Retains webFrameView, so call Release for webFrameView
    948     Release(webFrameView);
    949     // Attach the frameView to the newFrame.
    950     newFrame->setView(frameView);
    951     newFrame->init();
    952     newFrame->selection()->setFocused(true);
    953     LOGV("::WebCore:: createSubFrame returning %p", newFrame);
    954 
    955     // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
    956     if (!pFrame->page())
    957         return 0;
    958 
    959     parent->loader()->loadURLIntoChildFrame(url, referrer, pFrame.get());
    960 
    961     // onLoad may cuase the frame to be removed from the document. Allow the RefPtr to delete the child frame.
    962     if (!pFrame->tree()->parent())
    963         return NULL;
    964 
    965     return pFrame.release();
    966 }
    967 
    968 // YouTube flash url path starts with /v/
    969 static const char slash_v_slash[] = { '/', 'v', '/' };
    970 
    971 static bool isValidYouTubeVideo(const String& path)
    972 {
    973     if (!charactersAreAllASCII(path.characters(), path.length()))
    974         return false;
    975     unsigned int len = path.length();
    976     if (len <= sizeof(slash_v_slash)) // check for more than just /v/
    977         return false;
    978     CString str = path.lower().utf8();
    979     const char* data = str.data();
    980     if (memcmp(data, slash_v_slash, sizeof(slash_v_slash)) != 0)
    981         return false;
    982     // Start after /v/
    983     for (unsigned int i = sizeof(slash_v_slash); i < len; i++) {
    984         char c = data[i];
    985         // Check for alpha-numeric characters only.
    986         if (WTF::isASCIIAlphanumeric(c) || c == '_' || c == '-')
    987             continue;
    988         // The url can have more parameters such as &hl=en after the video id.
    989         // Once we start seeing extra parameters we can return true.
    990         return c == '&' && i > sizeof(slash_v_slash);
    991     }
    992     return true;
    993 }
    994 
    995 static bool isYouTubeUrl(const KURL& url, const String& mimeType)
    996 {
    997     String host = url.host();
    998     bool youtube = host.endsWith("youtube.com")
    999             || host.endsWith("youtube-nocookie.com");
   1000     return youtube && isValidYouTubeVideo(url.path())
   1001             && equalIgnoringCase(mimeType, "application/x-shockwave-flash");
   1002 }
   1003 
   1004 static bool isYouTubeInstalled() {
   1005     return WebCore::packageNotifier().isPackageInstalled("com.google.android.youtube");
   1006 }
   1007 
   1008 // Use PluginWidget as it is not used by Android for real plugins.
   1009 class PluginToggleWidget : public PluginWidget {
   1010 public:
   1011     PluginToggleWidget(Frame* parent, const IntSize& size,
   1012             HTMLPlugInElement* elem, const KURL& url,
   1013             const WTF::Vector<String>& paramNames,
   1014             const WTF::Vector<String>& paramValues, const String& mimeType,
   1015             bool loadManually)
   1016         : m_parent(parent)
   1017         , m_size(size)
   1018         , m_element(elem)
   1019         , m_url(url)
   1020         , m_paramNames(paramNames)
   1021         , m_paramValues(paramValues)
   1022         , m_mimeType(mimeType)
   1023         , m_loadManually(loadManually)
   1024     {
   1025         resize(size);
   1026     }
   1027 
   1028     virtual void paint(GraphicsContext* ctx, const IntRect& rect)
   1029     {
   1030         // Most of this code is copied from PluginView::paintMissingPluginIcon
   1031         // with slight modification.
   1032 
   1033         static RefPtr<Image> image;
   1034         if (!image) {
   1035             image = Image::loadPlatformResource("togglePlugin");
   1036         }
   1037 
   1038         IntRect imageRect(x(), y(), image->width(), image->height());
   1039 
   1040         int xOffset = (width() - imageRect.width()) >> 1;
   1041         int yOffset = (height() - imageRect.height()) >> 1;
   1042 
   1043         imageRect.move(xOffset, yOffset);
   1044 
   1045         if (!rect.intersects(imageRect))
   1046             return;
   1047 
   1048         // FIXME: We need to clip similarly to paintMissingPluginIcon but it is
   1049         // way screwed up right now. It has something to do with how we tell
   1050         // webkit the scroll position and it causes the placeholder to get
   1051         // clipped very badly. http://b/issue?id=2533303
   1052 
   1053         ctx->save();
   1054         ctx->clip(frameRect());
   1055 
   1056         ctx->setFillColor(Color::white, DeviceColorSpace);
   1057         ctx->fillRect(frameRect());
   1058         if (frameRect().contains(imageRect)) {
   1059             // Leave a 2 pixel padding.
   1060             const int pixelWidth = 2;
   1061             IntRect innerRect = frameRect();
   1062             innerRect.inflate(-pixelWidth);
   1063             // Draw a 2 pixel light gray border.
   1064             ctx->setStrokeColor(Color::lightGray, DeviceColorSpace);
   1065             ctx->strokeRect(innerRect, pixelWidth);
   1066         }
   1067 
   1068         // Draw the image in the center
   1069         ctx->drawImage(image.get(), DeviceColorSpace, imageRect.location());
   1070         ctx->restore();
   1071     }
   1072 
   1073     virtual void handleEvent(Event* event)
   1074     {
   1075         if (event->type() != eventNames().clickEvent)
   1076             return;
   1077 
   1078         Frame* frame = m_parent->page()->mainFrame();
   1079         while (frame) {
   1080             RenderView* view = frame->contentRenderer();
   1081             const HashSet<RenderWidget*> widgets = view->widgets();
   1082             HashSet<RenderWidget*>::const_iterator it = widgets.begin();
   1083             HashSet<RenderWidget*>::const_iterator end = widgets.end();
   1084             for (; it != end; ++it) {
   1085                 Widget* widget = (*it)->widget();
   1086                 // PluginWidget is used only with PluginToggleWidget
   1087                 if (widget->isPluginWidget()) {
   1088                     PluginToggleWidget* ptw =
   1089                             static_cast<PluginToggleWidget*>(widget);
   1090                     ptw->swapPlugin(*it);
   1091                 }
   1092             }
   1093             frame = frame->tree()->traverseNext();
   1094         }
   1095     }
   1096 
   1097     void swapPlugin(RenderWidget* renderer) {
   1098         typedef FrameLoaderClientAndroid FLCA;
   1099         FLCA* client = static_cast<FLCA*>(m_parent->loader()->client());
   1100         client->enableOnDemandPlugins();
   1101         WTF::PassRefPtr<PluginView> prpWidget =
   1102                 PluginView::create(m_parent.get(),
   1103                                    m_size,
   1104                                    m_element,
   1105                                    m_url,
   1106                                    m_paramNames,
   1107                                    m_paramValues,
   1108                                    m_mimeType,
   1109                                    m_loadManually);
   1110         RefPtr<Widget> myProtector(this);
   1111         prpWidget->focusPluginElement();
   1112         renderer->setWidget(prpWidget);
   1113     }
   1114 
   1115 private:
   1116     RefPtr<Frame>       m_parent;
   1117     IntSize             m_size;
   1118     HTMLPlugInElement*  m_element;
   1119     KURL                m_url;
   1120     WTF::Vector<String> m_paramNames;
   1121     WTF::Vector<String> m_paramValues;
   1122     String              m_mimeType;
   1123     bool                m_loadManually;
   1124 };
   1125 
   1126 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createPlugin(
   1127         const IntSize& size,
   1128         HTMLPlugInElement* element,
   1129         const KURL& url,
   1130         const WTF::Vector<String>& names,
   1131         const WTF::Vector<String>& values,
   1132         const String& mimeType,
   1133         bool loadManually) {
   1134     WTF::PassRefPtr<PluginView> prpWidget = 0;
   1135 #ifdef ANDROID_PLUGINS
   1136     // This is copied from PluginView.cpp. We need to determine if a plugin
   1137     // will be found before doing some of the work in PluginView.
   1138     String mimeTypeCopy = mimeType;
   1139     PluginPackage* plugin =
   1140             PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
   1141     if (!plugin && PluginDatabase::installedPlugins()->refresh()) {
   1142         mimeTypeCopy = mimeType;
   1143         plugin = PluginDatabase::installedPlugins()->findPlugin(url,
   1144                                                                 mimeTypeCopy);
   1145     }
   1146     Settings* settings = m_frame->settings();
   1147     // Do the placeholder if plugins are on-demand and there is a plugin for the
   1148     // given mime type.
   1149     if (settings && settings->arePluginsOnDemand() && plugin &&
   1150             !m_onDemandPluginsEnabled) {
   1151         return adoptRef(new PluginToggleWidget(m_frame, size, element, url,
   1152                     names, values, mimeType, loadManually));
   1153     }
   1154     prpWidget = PluginView::create(m_frame,
   1155                                    size,
   1156                                    element,
   1157                                    url,
   1158                                    names,
   1159                                    values,
   1160                                    mimeType,
   1161                                    loadManually);
   1162     // Return the plugin if it was loaded successfully. Otherwise, fallback to
   1163     // the youtube placeholder if possible. No need to check prpWidget as
   1164     // PluginView::create will create a PluginView for missing plugins.
   1165     // Note: this check really only checks if the plugin was found and not if
   1166     // the plugin was loaded.
   1167     if (prpWidget->status() == PluginStatusLoadedSuccessfully)
   1168         return prpWidget;
   1169 #endif
   1170     // Create an iframe for youtube urls.
   1171     if (isYouTubeUrl(url, mimeType) && isYouTubeInstalled()) {
   1172         WTF::RefPtr<Frame> frame = createFrame(blankURL(), String(), element,
   1173                 String(), false, 0, 0);
   1174         if (frame) {
   1175             // grab everything after /v/
   1176             String videoId = url.path().substring(sizeof(slash_v_slash));
   1177             // Extract just the video id
   1178             unsigned videoIdEnd = 0;
   1179             for (; videoIdEnd < videoId.length(); videoIdEnd++) {
   1180                 if (videoId[videoIdEnd] == '&') {
   1181                     videoId = videoId.left(videoIdEnd);
   1182                     break;
   1183                 }
   1184             }
   1185             AssetManager* am = globalAssetManager();
   1186             Asset* a = am->open("webkit/youtube.html",
   1187                     Asset::ACCESS_BUFFER);
   1188             if (!a)
   1189                 return NULL;
   1190             String s = String((const char*)a->getBuffer(false), a->getLength());
   1191             s = s.replace("VIDEO_ID", videoId);
   1192             delete a;
   1193             loadDataIntoFrame(frame.get(),
   1194                     KURL(ParsedURLString, "file:///android_asset/webkit/"), String(), s);
   1195             // Transfer ownership to a local refptr.
   1196             WTF::RefPtr<Widget> widget(frame->view());
   1197             return widget.release();
   1198         }
   1199     }
   1200     return prpWidget;
   1201 }
   1202 
   1203 void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) {
   1204     // Do not redirect data if the Widget is our plugin placeholder.
   1205     if (pluginWidget->isPluginView()) {
   1206         m_manualLoader = static_cast<PluginView*>(pluginWidget);
   1207     }
   1208 }
   1209 
   1210 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, HTMLAppletElement*,
   1211                                         const KURL& baseURL, const WTF::Vector<String>& paramNames,
   1212                                         const WTF::Vector<String>& paramValues) {
   1213     // don't support widget yet
   1214     notImplemented();
   1215     return 0;
   1216 }
   1217 
   1218 // This function is used by the <OBJECT> element to determine the type of
   1219 // the contents and work out if it can render it.
   1220 ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url,
   1221                                         const String& mimeType) {
   1222     return FrameLoader::defaultObjectContentType(url, mimeType);
   1223 }
   1224 
   1225 // This function allows the application to set the correct CSS media
   1226 // style. Android could use it to set the media style 'handheld'. Safari
   1227 // may use it to set the media style to 'print' when the user wants to print
   1228 // a particular web page.
   1229 String FrameLoaderClientAndroid::overrideMediaType() const {
   1230     lowPriority_notImplemented();
   1231     return String();
   1232 }
   1233 
   1234 // This function is used to re-attach Javascript<->native code classes.
   1235 void FrameLoaderClientAndroid::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
   1236 {
   1237     if (world != mainThreadNormalWorld())
   1238         return;
   1239 
   1240     ASSERT(m_frame);
   1241     LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n",
   1242     		m_frame, m_frame->loader()->url().string().ascii().data());
   1243     m_webFrame->windowObjectCleared(m_frame);
   1244 }
   1245 
   1246 void FrameLoaderClientAndroid::documentElementAvailable() {
   1247 }
   1248 
   1249 // functions new to Jun-07 tip of tree merge:
   1250 ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) {
   1251     return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String());
   1252 }
   1253 
   1254 // functions new to Nov-07 tip of tree merge:
   1255 void FrameLoaderClientAndroid::didPerformFirstNavigation() const {
   1256     // This seems to be just a notification that the UI can listen to, to
   1257     // know if the user has performed first navigation action.
   1258     // It is called from
   1259     // void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
   1260     // "Navigation" here means a transition from one page to another that
   1261     // ends up in the back/forward list.
   1262 }
   1263 
   1264 void FrameLoaderClientAndroid::registerForIconNotification(bool listen) {
   1265     if (listen)
   1266         WebIconDatabase::RegisterForIconNotification(this);
   1267     else
   1268         WebIconDatabase::UnregisterForIconNotification(this);
   1269 }
   1270 
   1271 // This is the WebIconDatabaseClient method for receiving a notification when we
   1272 // get the icon for the page.
   1273 void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) {
   1274     // This call must happen before dispatchDidReceiveIcon since that method
   1275     // may register for icon notifications again since the icon data may have
   1276     // to be read from disk.
   1277     registerForIconNotification(false);
   1278     KURL u(ParsedURLString, pageUrl);
   1279     if (equalIgnoringFragmentIdentifier(u, m_frame->loader()->url())) {
   1280         dispatchDidReceiveIcon();
   1281     }
   1282 }
   1283 
   1284 }
   1285