• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "WebHistory.h"
74 #include "WebIconDatabase.h"
75 #include "WebFrameView.h"
76 #include "WebViewClientError.h"
77 #include "WebViewCore.h"
78 #include "autofill/WebAutofill.h"
79 
80 #include <androidfw/AssetManager.h>
81 #include <wtf/text/CString.h>
82 
83 #define verifiedOk() // Verified that we don't need to implement this.
84 
85 extern android::AssetManager* globalAssetManager();
86 
87 namespace android {
88 
89 static const int EXTRA_LAYOUT_DELAY = 1000;
90 
FrameLoaderClientAndroid(WebFrame * webframe)91 FrameLoaderClientAndroid::FrameLoaderClientAndroid(WebFrame* webframe)
92     : m_frame(NULL)
93     , m_webFrame(webframe)
94     , m_manualLoader(NULL)
95     , m_hasSentResponseToPlugin(false)
96     , m_onDemandPluginsEnabled(false)
97     , m_didReceiveServerRedirect(false) {
98     Retain(m_webFrame);
99 }
100 
get(const WebCore::Frame * frame)101 FrameLoaderClientAndroid* FrameLoaderClientAndroid::get(const WebCore::Frame* frame)
102 {
103     return static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
104 }
105 
frameLoaderDestroyed()106 void FrameLoaderClientAndroid::frameLoaderDestroyed() {
107     registerForIconNotification(false);
108     m_frame = 0;
109     Release(m_webFrame);
110     delete this;
111 }
112 
hasWebView() const113 bool FrameLoaderClientAndroid::hasWebView() const {
114     // FIXME,
115     // there is one web view per page, or top frame.
116     // as android's view is created from Java side, it is always there.
117     return true;
118 }
119 
makeRepresentation(DocumentLoader *)120 void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) {
121     m_onDemandPluginsEnabled = false;
122     // don't use representation
123     verifiedOk();
124 }
125 
forceLayout()126 void FrameLoaderClientAndroid::forceLayout() {
127     ASSERT(m_frame);
128     m_frame->view()->forceLayout();
129     // FIXME, should we adjust view size here?
130     m_frame->view()->adjustViewSize();
131 }
132 
forceLayoutForNonHTML()133 void FrameLoaderClientAndroid::forceLayoutForNonHTML() {
134     notImplemented();
135 }
136 
setCopiesOnScroll()137 void FrameLoaderClientAndroid::setCopiesOnScroll() {
138     // this is a hint about whether we need to force redraws, or can
139     // just copy the scrolled content. Since we always force a redraw
140     // anyways, we can ignore this call.
141     verifiedOk();
142 }
143 
detachedFromParent2()144 void FrameLoaderClientAndroid::detachedFromParent2() {
145     // FIXME, ready to detach frame from view
146 }
147 
detachedFromParent3()148 void FrameLoaderClientAndroid::detachedFromParent3() {
149     // FIXME, ready to release view
150     notImplemented();
151 }
152 
153 // This function is responsible for associating the "id" with a given
154 // subresource load.  The following functions that accept an "id" are
155 // called for each subresource, so they should not be dispatched to the m_frame.
assignIdentifierToInitialRequest(unsigned long id,DocumentLoader *,const ResourceRequest &)156 void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id,
157                             DocumentLoader*, const ResourceRequest&) {
158     notImplemented();
159 }
160 
dispatchWillSendRequest(DocumentLoader *,unsigned long id,ResourceRequest &,const ResourceResponse &)161 void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id,
162                             ResourceRequest&, const ResourceResponse&) {
163     notImplemented();
164 }
165 
shouldUseCredentialStorage(DocumentLoader *,unsigned long identifier)166 bool FrameLoaderClientAndroid::shouldUseCredentialStorage(DocumentLoader*, unsigned long  identifier)
167 {
168     notImplemented();
169     return false;
170 }
171 
dispatchDidReceiveAuthenticationChallenge(DocumentLoader *,unsigned long id,const AuthenticationChallenge &)172 void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*,
173                             unsigned long id, const AuthenticationChallenge&) {
174     notImplemented();
175 }
176 
dispatchDidCancelAuthenticationChallenge(DocumentLoader *,unsigned long id,const AuthenticationChallenge &)177 void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*,
178                             unsigned long id, const AuthenticationChallenge&) {
179     notImplemented();
180 }
181 
dispatchDidReceiveResponse(DocumentLoader *,unsigned long id,const ResourceResponse &)182 void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*,
183                             unsigned long id, const ResourceResponse&) {
184     notImplemented();
185 }
186 
dispatchDidReceiveContentLength(DocumentLoader *,unsigned long id,int lengthReceived)187 void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*,
188                             unsigned long id, int lengthReceived) {
189     notImplemented();
190 }
191 
dispatchDidFinishLoading(DocumentLoader *,unsigned long id)192 void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*,
193                             unsigned long id) {
194     notImplemented();
195 }
196 
dispatchDidFailLoading(DocumentLoader * docLoader,unsigned long id,const ResourceError &)197 void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader,
198                             unsigned long id, const ResourceError&) {
199     notImplemented();
200 }
201 
dispatchDidLoadResourceFromMemoryCache(DocumentLoader *,const ResourceRequest &,const ResourceResponse &,int length)202 bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*,
203                             const ResourceRequest&, const ResourceResponse&, int length) {
204     notImplemented();
205     return false;
206 }
207 
dispatchDidHandleOnloadEvents()208 void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() {
209 }
210 
dispatchDidReceiveServerRedirectForProvisionalLoad()211 void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() {
212     ASSERT(!m_didReceiveServerRedirect);
213     m_didReceiveServerRedirect = true;
214 }
215 
dispatchDidCancelClientRedirect()216 void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() {
217     notImplemented();
218 }
219 
dispatchWillPerformClientRedirect(const KURL &,double interval,double fireDate)220 void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&,
221                                 double interval, double fireDate) {
222     notImplemented();
223 }
224 
dispatchDidChangeLocationWithinPage()225 void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() {
226     notImplemented();
227 }
228 
dispatchDidPushStateWithinPage()229 void FrameLoaderClientAndroid::dispatchDidPushStateWithinPage()
230 {
231     notImplemented();
232 }
233 
dispatchDidReplaceStateWithinPage()234 void FrameLoaderClientAndroid::dispatchDidReplaceStateWithinPage()
235 {
236     notImplemented();
237 }
238 
dispatchDidPopStateWithinPage()239 void FrameLoaderClientAndroid::dispatchDidPopStateWithinPage()
240 {
241     notImplemented();
242 }
243 
dispatchWillClose()244 void FrameLoaderClientAndroid::dispatchWillClose() {
245     notImplemented();
246 }
247 
dispatchDidReceiveIcon()248 void FrameLoaderClientAndroid::dispatchDidReceiveIcon() {
249     ASSERT(m_frame);
250     if (m_frame->tree() && m_frame->tree()->parent())
251         return;
252     WTF::String url(m_frame->document()->url().string());
253     // Try to obtain the icon image.
254     // FIXME: This method should not be used from outside WebCore and will be removed.
255     // http://trac.webkit.org/changeset/81484
256     WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(url, WebCore::IntSize(16, 16));
257     // If the request fails, try the original request url.
258     if (!icon) {
259         DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
260         KURL originalURL = docLoader->originalRequest().url();
261         // FIXME: This method should not be used from outside WebCore and will be removed.
262         // http://trac.webkit.org/changeset/81484
263         icon = WebCore::iconDatabase().synchronousIconForPageURL(originalURL, WebCore::IntSize(16, 16));
264     }
265     // There is a bug in webkit where cancelling an icon load is treated as a
266     // failure. When this is fixed, we can ASSERT again that we have an icon.
267     if (icon) {
268         ALOGV("Received icon (%p) for %s", icon,
269                 url.utf8().data());
270         m_webFrame->didReceiveIcon(icon);
271     } else {
272         ALOGV("Icon data for %s unavailable, registering for notification...",
273                 url.utf8().data());
274         registerForIconNotification();
275     }
276 }
277 
dispatchDidReceiveTouchIconURL(const String & url,bool precomposed)278 void FrameLoaderClientAndroid::dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) {
279     ASSERT(m_frame);
280     // Do not report sub frame touch icons
281     if (m_frame->tree() && m_frame->tree()->parent())
282         return;
283     m_webFrame->didReceiveTouchIconURL(url, precomposed);
284 }
285 
dispatchDidStartProvisionalLoad()286 void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() {
287     notImplemented();
288 }
289 
dispatchDidReceiveTitle(const StringWithDirection & title)290 void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const StringWithDirection& title) {
291     ASSERT(m_frame);
292     // Used to check for FrameLoadTypeStandard but we only want to send the title for
293     // the top frame and not sub-frames.
294     // FIXME: Use direction of title.
295     if (!m_frame->tree() || !m_frame->tree()->parent()) {
296         m_webFrame->setTitle(title.string());
297     }
298 }
299 
dispatchDidCommitLoad()300 void FrameLoaderClientAndroid::dispatchDidCommitLoad() {
301 #if ENABLE(WEB_AUTOFILL)
302     if (m_frame == m_frame->page()->mainFrame()) {
303         EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(m_frame->page()->editorClient());
304         WebAutofill* autoFill = editorC->getAutofill();
305         autoFill->reset();
306     }
307 #endif
308     verifiedOk();
309 }
310 
loadDataIntoFrame(Frame * frame,KURL baseUrl,const String & url,const String & data)311 static void loadDataIntoFrame(Frame* frame, KURL baseUrl, const String& url,
312         const String& data) {
313     if (baseUrl.isEmpty()) {
314         baseUrl = blankURL();
315     }
316     ResourceRequest request(baseUrl);
317     CString cstr = data.utf8();
318     RefPtr<WebCore::SharedBuffer> buf = WebCore::SharedBuffer::create(cstr.data(), cstr.length());
319     SubstituteData subData(buf, String("text/html"), String("utf-8"),
320             KURL(KURL(), url));
321     frame->loader()->load(request, subData, false);
322 }
323 
dispatchDidFailProvisionalLoad(const ResourceError & error)324 void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) {
325     ASSERT(m_frame);
326     // Ignore ErrorInterrupted since it is due to a policy interruption. This
327     // is caused by a decision to download the main resource rather than
328     // display it.
329     if (error.errorCode() == InternalErrorInterrupted
330             || error.errorCode() == InternalErrorCancelled) {
331         // If we decided to download the main resource or if the user cancelled
332         // it, make sure we report that the load is done.
333         didFinishLoad();
334         return;
335     }
336 
337     AssetManager* am = globalAssetManager();
338 
339     // Check to see if the error code was not generated internally
340     WebCore::PlatformBridge::rawResId id = WebCore::PlatformBridge::NoDomain;
341     if ((error.errorCode() == ErrorFile ||
342             error.errorCode() == ErrorFileNotFound) &&
343             (!error.localizedDescription().isEmpty())) {
344         id = WebCore::PlatformBridge::LoadError;
345     }
346     String filename = m_webFrame->getRawResourceFilename(id);
347     if (filename.isEmpty())
348         return;
349 
350     // Grab the error page from the asset manager
351     Asset* a = am->openNonAsset(
352             filename.utf8().data(), Asset::ACCESS_BUFFER);
353     if (!a)
354         return;
355 
356     // Take the failing url and encode html entities so javascript urls are not
357     // executed.
358     CString failingUrl = error.failingURL().utf8();
359     WTF::Vector<char> url;
360     int len = failingUrl.length();
361     const char* data = failingUrl.data();
362     for (int i = 0; i < len; i++) {
363         char c = data[i];
364         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
365                 || (c >= '0' && c <= '9'))
366             url.append(c);
367         else {
368             char buf[16];
369             int res = sprintf(buf, "&#%d;", c);
370             buf[res] = 0;
371             url.append(buf, res);
372         }
373     }
374     // Vector sets up its data buffer lazilly, so if failingUrl is the empty
375     // string, the data buffer will be null. This will result in sanitizedUrl
376     // being null, and the string substitution below will be a no-op.
377     // FIXME: Ideally we'd always have a non-empty URL, or at least improve the
378     // wording of the error page in this case. See http://b/5293782.
379     String sanitizedUrl = url.data() ? String(url.data(), url.size()) : "";
380 
381     // Replace all occurances of %s with the failing url.
382     String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength());
383     s = s.replace("%s", sanitizedUrl);
384 
385     // Replace all occurances of %e with the error text
386     s = s.replace("%e", error.localizedDescription());
387 
388     // Create the request and the substitute data and tell the FrameLoader to
389     // load with the replacement data.
390     // use KURL(const char*) as KURL(const String& url) can trigger ASSERT for
391     // invalidate URL string.
392     loadDataIntoFrame(m_frame, KURL(ParsedURLString, data), error.failingURL(), s);
393 
394     // Delete the asset.
395     delete a;
396 
397     // Report that the load is finished, since it failed.
398     didFinishLoad();
399 }
400 
dispatchDidFailLoad(const ResourceError &)401 void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) {
402     // called when page is completed with error
403     didFinishLoad();
404 }
405 
dispatchDidFinishDocumentLoad()406 void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() {
407     // called when finishedParsing
408     notImplemented();
409 }
410 
dispatchDidFinishLoad()411 void FrameLoaderClientAndroid::dispatchDidFinishLoad() {
412     didFinishLoad();
413 }
414 
dispatchDidFirstLayout()415 void FrameLoaderClientAndroid::dispatchDidFirstLayout() {
416     ASSERT(m_frame);
417     // set EXTRA_LAYOUT_DELAY if the loader is not completed yet
418     if (!m_frame->loader()->isComplete())
419         m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY);
420     // we need to do this here instead of dispatchDidFirstVisuallyNonEmptyLayout
421     // so that about:blank will update the screen.
422     if (!m_frame->tree()->parent()) {
423         // Only need to notify Java side for the top frame
424         WebViewCore* core = WebViewCore::getWebViewCore(m_frame->view());
425         if (core)
426             core->didFirstLayout();
427     }
428 }
429 
dispatchDidFirstVisuallyNonEmptyLayout()430 void FrameLoaderClientAndroid::dispatchDidFirstVisuallyNonEmptyLayout()
431 {
432     notImplemented();
433 }
434 
dispatchCreatePage(const NavigationAction &)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 
dispatchShow()449 void FrameLoaderClientAndroid::dispatchShow() {
450     ASSERT(m_frame);
451     m_frame->view()->invalidate();
452 }
453 
454 
TreatAsAttachment(const String & content_disposition)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 
dispatchDecidePolicyForResponse(FramePolicyFunction func,const ResourceResponse & response,const ResourceRequest & request)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 
dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,const NavigationAction & action,const ResourceRequest & request,PassRefPtr<FormState> formState,const String & frameName)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 
cancelPolicyCheck()552 void FrameLoaderClientAndroid::cancelPolicyCheck() {
553     notImplemented();
554 }
555 
dispatchUnableToImplementPolicy(const ResourceError &)556 void FrameLoaderClientAndroid::dispatchUnableToImplementPolicy(const ResourceError&) {
557     notImplemented();
558 }
559 
dispatchDecidePolicyForNavigationAction(FramePolicyFunction func,const NavigationAction & action,const ResourceRequest & request,PassRefPtr<FormState> formState)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 
dispatchWillSubmitForm(FramePolicyFunction func,PassRefPtr<FormState>)584 void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, PassRefPtr<FormState>) {
585     ASSERT(m_frame);
586     ASSERT(func);
587     (m_frame->loader()->policyChecker()->*func)(PolicyUse);
588 }
589 
dispatchWillSendSubmitEvent(HTMLFormElement * form)590 void FrameLoaderClientAndroid::dispatchWillSendSubmitEvent(HTMLFormElement* form)
591 {
592     if (m_webFrame->shouldSaveFormData())
593         m_webFrame->saveFormData(form);
594 }
595 
dispatchDidLoadMainResource(DocumentLoader *)596 void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) {
597     notImplemented();
598 }
599 
revertToProvisionalState(DocumentLoader *)600 void FrameLoaderClientAndroid::revertToProvisionalState(DocumentLoader*) {
601     notImplemented();
602 }
603 
setMainDocumentError(DocumentLoader * docLoader,const ResourceError & error)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.
willChangeEstimatedProgress()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.
didChangeEstimatedProgress()625 void FrameLoaderClientAndroid::didChangeEstimatedProgress() {
626     verifiedOk();
627 }
628 
629 // This will give us the initial estimate when the page first starts to load.
postProgressStartedNotification()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.
postProgressEstimateChangedNotification()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.
postProgressFinishedNotification()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 
setMainFrameDocumentReady(bool)655 void FrameLoaderClientAndroid::setMainFrameDocumentReady(bool) {
656     // this is only interesting once we provide an external API for the DOM
657     notImplemented();
658 }
659 
startDownload(const ResourceRequest &)660 void FrameLoaderClientAndroid::startDownload(const ResourceRequest&) {
661     notImplemented();
662 }
663 
willChangeTitle(DocumentLoader *)664 void FrameLoaderClientAndroid::willChangeTitle(DocumentLoader*) {
665     verifiedOk();
666 }
667 
didChangeTitle(DocumentLoader * loader)668 void FrameLoaderClientAndroid::didChangeTitle(DocumentLoader* loader) {
669     verifiedOk();
670 }
671 
finishedLoading(DocumentLoader * docLoader)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 
updateGlobalHistory()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 
updateGlobalHistoryRedirectLinks()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 
shouldGoToHistoryItem(HistoryItem * item) const708 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 
shouldStopLoadingForHistoryItem(HistoryItem * item) const714 bool FrameLoaderClientAndroid::shouldStopLoadingForHistoryItem(HistoryItem* item) const
715 {
716     return true;
717 }
718 
didDisplayInsecureContent()719 void FrameLoaderClientAndroid::didDisplayInsecureContent()
720 {
721     notImplemented();
722 }
723 
didRunInsecureContent(SecurityOrigin *,const KURL &)724 void FrameLoaderClientAndroid::didRunInsecureContent(SecurityOrigin*, const KURL&)
725 {
726     notImplemented();
727 }
728 
committedLoad(DocumentLoader * loader,const char * data,int length)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 
cancelledError(const ResourceRequest & request)747 ResourceError FrameLoaderClientAndroid::cancelledError(const ResourceRequest& request) {
748     return ResourceError(String(), InternalErrorCancelled, request.url(), String());
749 }
750 
cannotShowURLError(const ResourceRequest & request)751 ResourceError FrameLoaderClientAndroid::cannotShowURLError(const ResourceRequest& request) {
752     return ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String());
753 }
754 
interruptForPolicyChangeError(const ResourceRequest & request)755 ResourceError FrameLoaderClientAndroid::interruptForPolicyChangeError(const ResourceRequest& request) {
756     return ResourceError(String(), InternalErrorInterrupted, request.url(), String());
757 }
758 
cannotShowMIMETypeError(const ResourceResponse & request)759 ResourceError FrameLoaderClientAndroid::cannotShowMIMETypeError(const ResourceResponse& request) {
760     return ResourceError(String(), InternalErrorCannotShowMimeType, request.url(), String());
761 }
762 
fileDoesNotExistError(const ResourceResponse & request)763 ResourceError FrameLoaderClientAndroid::fileDoesNotExistError(const ResourceResponse& request) {
764     return ResourceError(String(), InternalErrorFileDoesNotExist, request.url(), String());
765 }
766 
pluginWillHandleLoadError(const ResourceResponse & request)767 ResourceError FrameLoaderClientAndroid::pluginWillHandleLoadError(const ResourceResponse& request) {
768     return ResourceError(String(), InternalErrorPluginWillHandleLoadError, request.url(), String());
769 }
770 
shouldFallBack(const ResourceError &)771 bool FrameLoaderClientAndroid::shouldFallBack(const ResourceError&) {
772     notImplemented();
773     return false;
774 }
775 
canHandleRequest(const ResourceRequest & request) const776 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 
canShowMIMEType(const String & mimeType) const797 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 
canShowMIMETypeAsHTML(const String & mimeType) const815 bool FrameLoaderClientAndroid::canShowMIMETypeAsHTML(const String& mimeType) const {
816     return false;
817 }
818 
representationExistsForURLScheme(const String &) const819 bool FrameLoaderClientAndroid::representationExistsForURLScheme(const String&) const {
820     // don't use representation
821     verifiedOk();
822     return false;
823 }
824 
generatedMIMETypeForURLScheme(const String & URLScheme) const825 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 
frameLoadCompleted()832 void FrameLoaderClientAndroid::frameLoadCompleted() {
833     // copied from Apple port, without this back with sub-frame will trigger ASSERT
834     ASSERT(m_frame);
835 }
836 
saveViewStateToItem(HistoryItem * item)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 
restoreViewState()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 
dispatchDidAddBackForwardItem(HistoryItem * item) const864 void FrameLoaderClientAndroid::dispatchDidAddBackForwardItem(HistoryItem* item) const {
865     ASSERT(m_frame);
866     m_webFrame->addHistoryItem(item);
867 }
868 
dispatchDidRemoveBackForwardItem(HistoryItem * item) const869 void FrameLoaderClientAndroid::dispatchDidRemoveBackForwardItem(HistoryItem* item) const {
870     ASSERT(m_frame);
871     m_webFrame->removeHistoryItem(0);
872 }
873 
dispatchDidChangeBackForwardIndex() const874 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 
provisionalLoadStarted()881 void FrameLoaderClientAndroid::provisionalLoadStarted() {
882     ASSERT(m_frame);
883     m_webFrame->loadStarted(m_frame);
884 }
885 
didFinishLoad()886 void FrameLoaderClientAndroid::didFinishLoad() {
887     ASSERT(m_frame);
888     m_frame->document()->setExtraLayoutDelay(0);
889     m_webFrame->didFinishLoad(m_frame);
890 }
891 
prepareForDataSourceReplacement()892 void FrameLoaderClientAndroid::prepareForDataSourceReplacement() {
893     verifiedOk();
894 }
895 
createDocumentLoader(const ResourceRequest & request,const SubstituteData & data)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 
setTitle(const StringWithDirection & title,const KURL & url)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 
userAgent(const KURL & u)908 String FrameLoaderClientAndroid::userAgent(const KURL& u) {
909     return m_webFrame->userAgentForURL(&u);
910 }
911 
savePlatformDataToCachedFrame(WebCore::CachedFrame * cachedFrame)912 void FrameLoaderClientAndroid::savePlatformDataToCachedFrame(WebCore::CachedFrame* cachedFrame) {
913     CachedFramePlatformDataAndroid* platformData = new CachedFramePlatformDataAndroid(m_frame->settings());
914     cachedFrame->setCachedFramePlatformData(platformData);
915 }
916 
transitionToCommittedFromCachedFrame(WebCore::CachedFrame * cachedFrame)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 
transitionToCommittedForNewPage()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     RefPtr<WebCore::FrameView> oldFrameView = m_frame->view();
950     WebFrameView* oldWebFrameView = static_cast<WebFrameView*> (oldFrameView->platformWidget());
951     IntRect bounds;
952     if (oldWebFrameView)
953         bounds = oldWebFrameView->getBounds();
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     if (oldWebFrameView) {
962         IntRect visBounds = oldWebFrameView->getVisibleBounds();
963         IntRect windowBounds = oldWebFrameView->getWindowBounds();
964         // Create a new WebFrameView for the new FrameView
965         WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore);
966         newFrameView->setLocation(bounds.x(), bounds.y());
967         newFrameView->setSize(bounds.width(), bounds.height());
968         newFrameView->setVisibleSize(visBounds.width(), visBounds.height());
969         newFrameView->setWindowBounds(windowBounds.x(), windowBounds.y(), windowBounds.width(), windowBounds.height());
970         // newFrameView attaches itself to FrameView which Retains the reference, so
971         // call Release for newFrameView
972         Release(newFrameView);
973     }
974     // WebFrameView Retains webViewCore, so call Release for webViewCore
975     Release(webViewCore);
976 
977     m_webFrame->transitionToCommitted(m_frame);
978 }
979 
dispatchDidBecomeFrameset(bool)980 void FrameLoaderClientAndroid::dispatchDidBecomeFrameset(bool)
981 {
982 }
983 
canCachePage() const984 bool FrameLoaderClientAndroid::canCachePage() const {
985     return true;
986 }
987 
download(ResourceHandle * handle,const ResourceRequest &,const ResourceRequest &,const ResourceResponse &)988 void FrameLoaderClientAndroid::download(ResourceHandle* handle, const ResourceRequest&,
989                                 const ResourceRequest&, const ResourceResponse&) {
990     // Get the C++ side of the load listener and tell it to handle the download
991     handle->getInternal()->m_loader->downloadFile();
992 }
993 
createFrame(const KURL & url,const String & name,HTMLFrameOwnerElement * ownerElement,const String & referrer,bool allowsScrolling,int marginWidth,int marginHeight)994 WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL& url, const String& name,
995                         HTMLFrameOwnerElement* ownerElement, const String& referrer,
996                         bool allowsScrolling, int marginWidth, int marginHeight)
997 {
998     Frame* parent = ownerElement->document()->frame();
999     FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(m_webFrame);
1000     RefPtr<Frame> pFrame = Frame::create(parent->page(), ownerElement, loaderC);
1001     Frame* newFrame = pFrame.get();
1002     loaderC->setFrame(newFrame);
1003     // Append the subframe to the parent and set the name of the subframe. The name must be set after
1004     // appending the child so that the name becomes unique.
1005     parent->tree()->appendChild(newFrame);
1006     newFrame->tree()->setName(name);
1007     // Create a new FrameView and WebFrameView for the child frame to draw into.
1008     RefPtr<FrameView> frameView = FrameView::create(newFrame);
1009     // Attach the frameView to the newFrame.
1010     newFrame->setView(frameView);
1011     newFrame->init();
1012     newFrame->selection()->setFocused(true);
1013     ALOGV("::WebCore:: createSubFrame returning %p", newFrame);
1014 
1015     // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
1016     if (!pFrame->page())
1017         return 0;
1018 
1019     parent->loader()->loadURLIntoChildFrame(url, referrer, pFrame.get());
1020 
1021     // onLoad may cuase the frame to be removed from the document. Allow the RefPtr to delete the child frame.
1022     if (!pFrame->tree()->parent())
1023         return NULL;
1024 
1025     return pFrame.release();
1026 }
1027 
1028 // YouTube flash url path starts with /v/
1029 static const char slash_v_slash[] = { '/', 'v', '/' };
1030 static const char slash_e_slash[] = { '/', 'e', '/' };
1031 
isValidYouTubeVideo(const String & path)1032 static bool isValidYouTubeVideo(const String& path)
1033 {
1034     if (!charactersAreAllASCII(path.characters(), path.length()))
1035         return false;
1036     unsigned int len = path.length();
1037     if (len <= sizeof(slash_v_slash)) // check for more than just /v/
1038         return false;
1039     CString str = path.lower().utf8();
1040     const char* data = str.data();
1041     // Youtube flash url can start with /v/ or /e/
1042     if (memcmp(data, slash_v_slash, sizeof(slash_v_slash)) != 0)
1043         if (memcmp(data, slash_e_slash, sizeof(slash_e_slash)) != 0)
1044             return false;
1045     // Start after /v/
1046     for (unsigned int i = sizeof(slash_v_slash); i < len; i++) {
1047         char c = data[i];
1048         // Check for alpha-numeric characters only.
1049         if (WTF::isASCIIAlphanumeric(c) || c == '_' || c == '-')
1050             continue;
1051         // The url can have more parameters such as &hl=en after the video id.
1052         // Once we start seeing extra parameters we can return true.
1053         return c == '&' && i > sizeof(slash_v_slash);
1054     }
1055     return true;
1056 }
1057 
isYouTubeUrl(const KURL & url,const String & mimeType)1058 static bool isYouTubeUrl(const KURL& url, const String& mimeType)
1059 {
1060     String host = url.host();
1061     bool youtube = host.endsWith("youtube.com")
1062             || host.endsWith("youtube-nocookie.com");
1063     return youtube && isValidYouTubeVideo(url.path())
1064             && equalIgnoringCase(mimeType, "application/x-shockwave-flash");
1065 }
1066 
isYouTubeInstalled()1067 static bool isYouTubeInstalled() {
1068     return WebCore::packageNotifier().isPackageInstalled("com.google.android.youtube");
1069 }
1070 
1071 // Use PluginViewBase rather than an Android specific sub class as we do not require any
1072 // Android specific functionality; this just renders a placeholder which will later
1073 // activate the real plugin.
1074 class PluginToggleWidget : public PluginViewBase {
1075 public:
PluginToggleWidget(Frame * parent,const IntSize & size,HTMLPlugInElement * elem,const KURL & url,const WTF::Vector<String> & paramNames,const WTF::Vector<String> & paramValues,const String & mimeType,bool loadManually)1076     PluginToggleWidget(Frame* parent, const IntSize& size,
1077             HTMLPlugInElement* elem, const KURL& url,
1078             const WTF::Vector<String>& paramNames,
1079             const WTF::Vector<String>& paramValues, const String& mimeType,
1080             bool loadManually)
1081         : PluginViewBase(0)
1082         , m_parent(parent)
1083         , m_size(size)
1084         , m_element(elem)
1085         , m_url(url)
1086         , m_paramNames(paramNames)
1087         , m_paramValues(paramValues)
1088         , m_mimeType(mimeType)
1089         , m_loadManually(loadManually)
1090     {
1091         resize(size);
1092     }
1093 
paint(GraphicsContext * ctx,const IntRect & rect)1094     virtual void paint(GraphicsContext* ctx, const IntRect& rect)
1095     {
1096         // Most of this code is copied from PluginView::paintMissingPluginIcon
1097         // with slight modification.
1098 
1099         static RefPtr<Image> image;
1100         if (!image) {
1101             image = Image::loadPlatformResource("togglePlugin");
1102         }
1103 
1104         IntRect imageRect(x(), y(), image->width(), image->height());
1105 
1106         int xOffset = (width() - imageRect.width()) >> 1;
1107         int yOffset = (height() - imageRect.height()) >> 1;
1108 
1109         imageRect.move(xOffset, yOffset);
1110 
1111         if (!rect.intersects(imageRect))
1112             return;
1113 
1114         // FIXME: We need to clip similarly to paintMissingPluginIcon but it is
1115         // way screwed up right now. It has something to do with how we tell
1116         // webkit the scroll position and it causes the placeholder to get
1117         // clipped very badly. http://b/issue?id=2533303
1118 
1119         ctx->save();
1120         ctx->clip(frameRect());
1121 
1122         ctx->setFillColor(Color::white, ColorSpaceDeviceRGB);
1123         ctx->fillRect(frameRect());
1124         if (frameRect().contains(imageRect)) {
1125             // Leave a 2 pixel padding.
1126             const int pixelWidth = 2;
1127             IntRect innerRect = frameRect();
1128             innerRect.inflate(-pixelWidth);
1129             // Draw a 2 pixel light gray border.
1130             ctx->setStrokeColor(Color::lightGray, ColorSpaceDeviceRGB);
1131             ctx->strokeRect(innerRect, pixelWidth);
1132         }
1133 
1134         // Draw the image in the center
1135         ctx->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect.location());
1136         ctx->restore();
1137     }
1138 
handleEvent(Event * event)1139     virtual void handleEvent(Event* event)
1140     {
1141         if (event->type() != eventNames().clickEvent)
1142             return;
1143 
1144         Frame* frame = m_parent->page()->mainFrame();
1145         while (frame) {
1146             RenderView* view = frame->contentRenderer();
1147             const HashSet<RenderWidget*> widgets = view->widgets();
1148             HashSet<RenderWidget*>::const_iterator it = widgets.begin();
1149             HashSet<RenderWidget*>::const_iterator end = widgets.end();
1150             for (; it != end; ++it) {
1151                 Widget* widget = (*it)->widget();
1152                 // PluginWidget is used only with PluginToggleWidget
1153                 if (widget && widget->isPluginViewBase()) {
1154                     PluginToggleWidget* ptw =
1155                             static_cast<PluginToggleWidget*>(widget);
1156                     ptw->swapPlugin(*it);
1157                 }
1158             }
1159             frame = frame->tree()->traverseNext();
1160         }
1161     }
1162 
swapPlugin(RenderWidget * renderer)1163     void swapPlugin(RenderWidget* renderer) {
1164         typedef FrameLoaderClientAndroid FLCA;
1165         FLCA* client = static_cast<FLCA*>(m_parent->loader()->client());
1166         client->enableOnDemandPlugins();
1167         WTF::PassRefPtr<PluginView> prpWidget =
1168                 PluginView::create(m_parent.get(),
1169                                    m_size,
1170                                    m_element,
1171                                    m_url,
1172                                    m_paramNames,
1173                                    m_paramValues,
1174                                    m_mimeType,
1175                                    m_loadManually);
1176         RefPtr<Widget> myProtector(this);
1177         prpWidget->focusPluginElement();
1178         renderer->setWidget(prpWidget);
1179     }
1180 
1181 private:
invalidateRect(const IntRect & rect)1182     void invalidateRect(const IntRect& rect) { }
1183 
1184     RefPtr<Frame>       m_parent;
1185     IntSize             m_size;
1186     HTMLPlugInElement*  m_element;
1187     KURL                m_url;
1188     WTF::Vector<String> m_paramNames;
1189     WTF::Vector<String> m_paramValues;
1190     String              m_mimeType;
1191     bool                m_loadManually;
1192 };
1193 
createPlugin(const IntSize & size,HTMLPlugInElement * element,const KURL & url,const WTF::Vector<String> & names,const WTF::Vector<String> & values,const String & mimeType,bool loadManually)1194 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createPlugin(
1195         const IntSize& size,
1196         HTMLPlugInElement* element,
1197         const KURL& url,
1198         const WTF::Vector<String>& names,
1199         const WTF::Vector<String>& values,
1200         const String& mimeType,
1201         bool loadManually) {
1202     WTF::PassRefPtr<PluginView> prpWidget = 0;
1203 #ifdef ANDROID_PLUGINS
1204     // This is copied from PluginView.cpp. We need to determine if a plugin
1205     // will be found before doing some of the work in PluginView.
1206     String mimeTypeCopy = mimeType;
1207     PluginPackage* plugin =
1208             PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
1209     if (!plugin && PluginDatabase::installedPlugins()->refresh()) {
1210         mimeTypeCopy = mimeType;
1211         plugin = PluginDatabase::installedPlugins()->findPlugin(url,
1212                                                                 mimeTypeCopy);
1213     }
1214     Settings* settings = m_frame->settings();
1215     // Do the placeholder if plugins are on-demand and there is a plugin for the
1216     // given mime type.
1217     if (settings && settings->arePluginsOnDemand() && plugin &&
1218             !m_onDemandPluginsEnabled) {
1219         return adoptRef(new PluginToggleWidget(m_frame, size, element, url,
1220                     names, values, mimeType, loadManually));
1221     }
1222     prpWidget = PluginView::create(m_frame,
1223                                    size,
1224                                    element,
1225                                    url,
1226                                    names,
1227                                    values,
1228                                    mimeType,
1229                                    loadManually);
1230     // Return the plugin if it was loaded successfully. Otherwise, fallback to
1231     // the youtube placeholder if possible. No need to check prpWidget as
1232     // PluginView::create will create a PluginView for missing plugins.
1233     // Note: this check really only checks if the plugin was found and not if
1234     // the plugin was loaded.
1235     if (prpWidget->status() == PluginStatusLoadedSuccessfully)
1236         return prpWidget;
1237 #endif
1238     // Create an iframe for youtube urls.
1239     if (isYouTubeUrl(url, mimeType) && isYouTubeInstalled()) {
1240         WTF::RefPtr<Frame> frame = createFrame(blankURL(), String(), element,
1241                 String(), false, 0, 0);
1242         if (frame) {
1243             // grab everything after /v/
1244             String videoId = url.path().substring(sizeof(slash_v_slash));
1245             // Extract just the video id
1246             unsigned videoIdEnd = 0;
1247             for (; videoIdEnd < videoId.length(); videoIdEnd++) {
1248                 if (videoId[videoIdEnd] == '&') {
1249                     videoId = videoId.left(videoIdEnd);
1250                     break;
1251                 }
1252             }
1253             AssetManager* am = globalAssetManager();
1254             Asset* a = am->open("webkit/youtube.html",
1255                     Asset::ACCESS_BUFFER);
1256             if (!a)
1257                 return NULL;
1258             String s = String((const char*)a->getBuffer(false), a->getLength());
1259             s = s.replace("VIDEO_ID", videoId);
1260             delete a;
1261             loadDataIntoFrame(frame.get(),
1262                     KURL(ParsedURLString, "file:///android_asset/webkit/"), String(), s);
1263             // Transfer ownership to a local refptr.
1264             WTF::RefPtr<Widget> widget(frame->view());
1265             return widget.release();
1266         }
1267     }
1268     return prpWidget;
1269 }
1270 
redirectDataToPlugin(Widget * pluginWidget)1271 void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) {
1272     // Do not redirect data if the Widget is our plugin placeholder.
1273     if (pluginWidget->isPluginView()) {
1274         m_manualLoader = static_cast<PluginView*>(pluginWidget);
1275     }
1276 }
1277 
createJavaAppletWidget(const IntSize &,HTMLAppletElement *,const KURL & baseURL,const WTF::Vector<String> & paramNames,const WTF::Vector<String> & paramValues)1278 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, HTMLAppletElement*,
1279                                         const KURL& baseURL, const WTF::Vector<String>& paramNames,
1280                                         const WTF::Vector<String>& paramValues) {
1281     // don't support widget yet
1282     notImplemented();
1283     return 0;
1284 }
1285 
didTransferChildFrameToNewDocument(WebCore::Page *)1286 void FrameLoaderClientAndroid::didTransferChildFrameToNewDocument(WebCore::Page*)
1287 {
1288     ASSERT(m_frame);
1289     // m_webFrame points to the WebFrame for the page that our frame previously
1290     // belonged to. If the frame now belongs to a new page, we need to update
1291     // m_webFrame to point to the WebFrame for the new page.
1292     Page* newPage = m_frame->page();
1293     if (newPage != m_webFrame->page()) {
1294         ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(newPage->chrome()->client());
1295         Release(m_webFrame);
1296         m_webFrame = chromeClient->webFrame();
1297         Retain(m_webFrame);
1298     }
1299 }
1300 
transferLoadingResourceFromPage(unsigned long,DocumentLoader *,const ResourceRequest &,Page *)1301 void FrameLoaderClientAndroid::transferLoadingResourceFromPage(unsigned long, DocumentLoader*, const ResourceRequest&, Page*)
1302 {
1303     notImplemented();
1304 }
1305 
1306 // This function is used by the <OBJECT> element to determine the type of
1307 // the contents and work out if it can render it.
objectContentType(const KURL & url,const String & mimeType,bool shouldPreferPlugInsForImages)1308 ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url, const String& mimeType, bool shouldPreferPlugInsForImages) {
1309     return FrameLoader::defaultObjectContentType(url, mimeType, shouldPreferPlugInsForImages);
1310 }
1311 
1312 // This function allows the application to set the correct CSS media
1313 // style. Android could use it to set the media style 'handheld'. Safari
1314 // may use it to set the media style to 'print' when the user wants to print
1315 // a particular web page.
overrideMediaType() const1316 String FrameLoaderClientAndroid::overrideMediaType() const {
1317     notImplemented();
1318     return String();
1319 }
1320 
1321 // This function is used to re-attach Javascript<->native code classes.
dispatchDidClearWindowObjectInWorld(DOMWrapperWorld * world)1322 void FrameLoaderClientAndroid::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
1323 {
1324     if (world != mainThreadNormalWorld())
1325         return;
1326 
1327     ASSERT(m_frame);
1328     ALOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n",
1329             m_frame, m_frame->document()->url().string().ascii().data());
1330     m_webFrame->windowObjectCleared(m_frame);
1331 }
1332 
documentElementAvailable()1333 void FrameLoaderClientAndroid::documentElementAvailable() {
1334 }
1335 
1336 // functions new to Jun-07 tip of tree merge:
blockedError(ResourceRequest const & request)1337 ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) {
1338     return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String());
1339 }
1340 
1341 // functions new to Nov-07 tip of tree merge:
didPerformFirstNavigation() const1342 void FrameLoaderClientAndroid::didPerformFirstNavigation() const {
1343     // This seems to be just a notification that the UI can listen to, to
1344     // know if the user has performed first navigation action.
1345     // It is called from
1346     // void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
1347     // "Navigation" here means a transition from one page to another that
1348     // ends up in the back/forward list.
1349 }
1350 
registerForIconNotification(bool listen)1351 void FrameLoaderClientAndroid::registerForIconNotification(bool listen) {
1352     if (listen)
1353         WebIconDatabase::RegisterForIconNotification(this);
1354     else
1355         WebIconDatabase::UnregisterForIconNotification(this);
1356 }
1357 
1358 // This is the WebIconDatabaseClient method for receiving a notification when we
1359 // get the icon for the page.
didAddIconForPageUrl(const String & pageUrl)1360 void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) {
1361     // This call must happen before dispatchDidReceiveIcon since that method
1362     // may register for icon notifications again since the icon data may have
1363     // to be read from disk.
1364     registerForIconNotification(false);
1365     KURL u(ParsedURLString, pageUrl);
1366     if (equalIgnoringFragmentIdentifier(u, m_frame->document()->url())) {
1367         dispatchDidReceiveIcon();
1368     }
1369 }
1370 
dispatchDidChangeIcons()1371 void FrameLoaderClientAndroid::dispatchDidChangeIcons() {
1372     notImplemented();
1373 }
1374 
createNetworkingContext()1375 PassRefPtr<FrameNetworkingContext> FrameLoaderClientAndroid::createNetworkingContext()
1376 {
1377     return FrameNetworkingContextAndroid::create(getFrame());
1378 }
1379 
1380 }
1381