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