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