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