1 /*
2 * Copyright 2007, The Android Open Source Project
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #define LOG_TAG "WebCore"
27
28 #include "config.h"
29 #include "FrameLoaderClientAndroid.h"
30
31 #include "BackForwardList.h"
32 #include "CachedFrame.h"
33 #include "CachedFramePlatformDataAndroid.h"
34 #include "Chrome.h"
35 #include "ChromeClientAndroid.h"
36 #include "DOMImplementation.h"
37 #include "Document.h"
38 #include "DocumentLoader.h"
39 #include "EditorClientAndroid.h"
40 #include "Frame.h"
41 #include "FrameLoader.h"
42 #include "FrameNetworkingContextAndroid.h"
43 #include "FrameTree.h"
44 #include "FrameView.h"
45 #include "GraphicsContext.h"
46 #include "HTMLFrameOwnerElement.h"
47 #include "HTMLPlugInElement.h"
48 #include "HistoryItem.h"
49 #include "IconDatabase.h"
50 #include "MIMETypeRegistry.h"
51 #include "NotImplemented.h"
52 #include "PackageNotifier.h"
53 #include "Page.h"
54 #include "PlatformBridge.h"
55 #include "PlatformGraphicsContext.h"
56 #include "PlatformString.h"
57 #include "PluginDatabase.h"
58 #include "PluginView.h"
59 #include "PluginViewBase.h"
60 #include "ProgressTracker.h"
61 #include "RenderPart.h"
62 #include "RenderView.h"
63 #include "RenderWidget.h"
64 #include "ResourceError.h"
65 #include "ResourceHandle.h"
66 #include "ResourceHandleInternal.h"
67 #include "SelectionController.h"
68 #include "Settings.h"
69 #include "SkCanvas.h"
70 #include "SkRect.h"
71 #include "TextEncoding.h"
72 #include "WebCoreFrameBridge.h"
73 #include "WebCoreResourceLoader.h"
74 #include "WebHistory.h"
75 #include "WebIconDatabase.h"
76 #include "WebFrameView.h"
77 #include "WebViewClientError.h"
78 #include "WebViewCore.h"
79 #include "autofill/WebAutofill.h"
80 #include "android_graphics.h"
81
82 #include <utils/AssetManager.h>
83 #include <wtf/text/CString.h>
84
85 #define verifiedOk() // Verified that we don't need to implement this.
86
87 extern android::AssetManager* globalAssetManager();
88
89 namespace android {
90
91 static const int EXTRA_LAYOUT_DELAY = 1000;
92
FrameLoaderClientAndroid(WebFrame * webframe)93 FrameLoaderClientAndroid::FrameLoaderClientAndroid(WebFrame* webframe)
94 : m_frame(NULL)
95 , m_webFrame(webframe)
96 , m_manualLoader(NULL)
97 , m_hasSentResponseToPlugin(false)
98 , m_onDemandPluginsEnabled(false)
99 , m_didReceiveServerRedirect(false) {
100 Retain(m_webFrame);
101 }
102
get(const WebCore::Frame * frame)103 FrameLoaderClientAndroid* FrameLoaderClientAndroid::get(const WebCore::Frame* frame)
104 {
105 return static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
106 }
107
frameLoaderDestroyed()108 void FrameLoaderClientAndroid::frameLoaderDestroyed() {
109 registerForIconNotification(false);
110 m_frame = 0;
111 Release(m_webFrame);
112 delete this;
113 }
114
hasWebView() const115 bool FrameLoaderClientAndroid::hasWebView() const {
116 // FIXME,
117 // there is one web view per page, or top frame.
118 // as android's view is created from Java side, it is always there.
119 return true;
120 }
121
makeRepresentation(DocumentLoader *)122 void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) {
123 m_onDemandPluginsEnabled = false;
124 // don't use representation
125 verifiedOk();
126 }
127
forceLayout()128 void FrameLoaderClientAndroid::forceLayout() {
129 ASSERT(m_frame);
130 m_frame->view()->forceLayout();
131 // FIXME, should we adjust view size here?
132 m_frame->view()->adjustViewSize();
133 }
134
forceLayoutForNonHTML()135 void FrameLoaderClientAndroid::forceLayoutForNonHTML() {
136 notImplemented();
137 }
138
setCopiesOnScroll()139 void FrameLoaderClientAndroid::setCopiesOnScroll() {
140 // this is a hint about whether we need to force redraws, or can
141 // just copy the scrolled content. Since we always force a redraw
142 // anyways, we can ignore this call.
143 verifiedOk();
144 }
145
detachedFromParent2()146 void FrameLoaderClientAndroid::detachedFromParent2() {
147 // FIXME, ready to detach frame from view
148 }
149
detachedFromParent3()150 void FrameLoaderClientAndroid::detachedFromParent3() {
151 // FIXME, ready to release view
152 notImplemented();
153 }
154
155 // This function is responsible for associating the "id" with a given
156 // subresource load. The following functions that accept an "id" are
157 // called for each subresource, so they should not be dispatched to the m_frame.
assignIdentifierToInitialRequest(unsigned long id,DocumentLoader *,const ResourceRequest &)158 void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id,
159 DocumentLoader*, const ResourceRequest&) {
160 notImplemented();
161 }
162
dispatchWillSendRequest(DocumentLoader *,unsigned long id,ResourceRequest &,const ResourceResponse &)163 void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id,
164 ResourceRequest&, const ResourceResponse&) {
165 notImplemented();
166 }
167
shouldUseCredentialStorage(DocumentLoader *,unsigned long identifier)168 bool FrameLoaderClientAndroid::shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier)
169 {
170 notImplemented();
171 return false;
172 }
173
dispatchDidReceiveAuthenticationChallenge(DocumentLoader *,unsigned long id,const AuthenticationChallenge &)174 void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*,
175 unsigned long id, const AuthenticationChallenge&) {
176 notImplemented();
177 }
178
dispatchDidCancelAuthenticationChallenge(DocumentLoader *,unsigned long id,const AuthenticationChallenge &)179 void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*,
180 unsigned long id, const AuthenticationChallenge&) {
181 notImplemented();
182 }
183
dispatchDidReceiveResponse(DocumentLoader *,unsigned long id,const ResourceResponse &)184 void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*,
185 unsigned long id, const ResourceResponse&) {
186 notImplemented();
187 }
188
dispatchDidReceiveContentLength(DocumentLoader *,unsigned long id,int lengthReceived)189 void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*,
190 unsigned long id, int lengthReceived) {
191 notImplemented();
192 }
193
dispatchDidFinishLoading(DocumentLoader *,unsigned long id)194 void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*,
195 unsigned long id) {
196 notImplemented();
197 }
198
dispatchDidFailLoading(DocumentLoader * docLoader,unsigned long id,const ResourceError &)199 void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader,
200 unsigned long id, const ResourceError&) {
201 notImplemented();
202 }
203
dispatchDidLoadResourceFromMemoryCache(DocumentLoader *,const ResourceRequest &,const ResourceResponse &,int length)204 bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*,
205 const ResourceRequest&, const ResourceResponse&, int length) {
206 notImplemented();
207 return false;
208 }
209
dispatchDidHandleOnloadEvents()210 void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() {
211 }
212
dispatchDidReceiveServerRedirectForProvisionalLoad()213 void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() {
214 ASSERT(!m_didReceiveServerRedirect);
215 m_didReceiveServerRedirect = true;
216 }
217
dispatchDidCancelClientRedirect()218 void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() {
219 notImplemented();
220 }
221
dispatchWillPerformClientRedirect(const KURL &,double interval,double fireDate)222 void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&,
223 double interval, double fireDate) {
224 notImplemented();
225 }
226
dispatchDidChangeLocationWithinPage()227 void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() {
228 notImplemented();
229 }
230
dispatchDidPushStateWithinPage()231 void FrameLoaderClientAndroid::dispatchDidPushStateWithinPage()
232 {
233 notImplemented();
234 }
235
dispatchDidReplaceStateWithinPage()236 void FrameLoaderClientAndroid::dispatchDidReplaceStateWithinPage()
237 {
238 notImplemented();
239 }
240
dispatchDidPopStateWithinPage()241 void FrameLoaderClientAndroid::dispatchDidPopStateWithinPage()
242 {
243 notImplemented();
244 }
245
dispatchWillClose()246 void FrameLoaderClientAndroid::dispatchWillClose() {
247 notImplemented();
248 }
249
dispatchDidReceiveIcon()250 void FrameLoaderClientAndroid::dispatchDidReceiveIcon() {
251 ASSERT(m_frame);
252 if (m_frame->tree() && m_frame->tree()->parent())
253 return;
254 WTF::String url(m_frame->document()->url().string());
255 // Try to obtain the icon image.
256 // FIXME: This method should not be used from outside WebCore and will be removed.
257 // http://trac.webkit.org/changeset/81484
258 WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(url, WebCore::IntSize(16, 16));
259 // If the request fails, try the original request url.
260 if (!icon) {
261 DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
262 KURL originalURL = docLoader->originalRequest().url();
263 // FIXME: This method should not be used from outside WebCore and will be removed.
264 // http://trac.webkit.org/changeset/81484
265 icon = WebCore::iconDatabase().synchronousIconForPageURL(originalURL, WebCore::IntSize(16, 16));
266 }
267 // There is a bug in webkit where cancelling an icon load is treated as a
268 // failure. When this is fixed, we can ASSERT again that we have an icon.
269 if (icon) {
270 LOGV("Received icon (%p) for %s", icon,
271 url.utf8().data());
272 m_webFrame->didReceiveIcon(icon);
273 } else {
274 LOGV("Icon data for %s unavailable, registering for notification...",
275 url.utf8().data());
276 registerForIconNotification();
277 }
278 }
279
dispatchDidReceiveTouchIconURL(const String & url,bool precomposed)280 void FrameLoaderClientAndroid::dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) {
281 ASSERT(m_frame);
282 // Do not report sub frame touch icons
283 if (m_frame->tree() && m_frame->tree()->parent())
284 return;
285 m_webFrame->didReceiveTouchIconURL(url, precomposed);
286 }
287
dispatchDidStartProvisionalLoad()288 void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() {
289 notImplemented();
290 }
291
dispatchDidReceiveTitle(const StringWithDirection & title)292 void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const StringWithDirection& title) {
293 ASSERT(m_frame);
294 // Used to check for FrameLoadTypeStandard but we only want to send the title for
295 // the top frame and not sub-frames.
296 // FIXME: Use direction of title.
297 if (!m_frame->tree() || !m_frame->tree()->parent()) {
298 m_webFrame->setTitle(title.string());
299 }
300 }
301
dispatchDidCommitLoad()302 void FrameLoaderClientAndroid::dispatchDidCommitLoad() {
303 #if ENABLE(WEB_AUTOFILL)
304 if (m_frame == m_frame->page()->mainFrame()) {
305 EditorClientAndroid* editorC = static_cast<EditorClientAndroid*>(m_frame->page()->editorClient());
306 WebAutofill* autoFill = editorC->getAutofill();
307 autoFill->reset();
308 }
309 #endif
310 verifiedOk();
311 }
312
loadDataIntoFrame(Frame * frame,KURL baseUrl,const String & url,const String & data)313 static void loadDataIntoFrame(Frame* frame, KURL baseUrl, const String& url,
314 const String& data) {
315 if (baseUrl.isEmpty()) {
316 baseUrl = blankURL();
317 }
318 ResourceRequest request(baseUrl);
319 CString cstr = data.utf8();
320 RefPtr<WebCore::SharedBuffer> buf = WebCore::SharedBuffer::create(cstr.data(), cstr.length());
321 SubstituteData subData(buf, String("text/html"), String("utf-8"),
322 KURL(KURL(), url));
323 frame->loader()->load(request, subData, false);
324 }
325
dispatchDidFailProvisionalLoad(const ResourceError & error)326 void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) {
327 ASSERT(m_frame);
328 // Ignore ErrorInterrupted since it is due to a policy interruption. This
329 // is caused by a decision to download the main resource rather than
330 // display it.
331 if (error.errorCode() == InternalErrorInterrupted
332 || error.errorCode() == InternalErrorCancelled) {
333 // If we decided to download the main resource or if the user cancelled
334 // it, make sure we report that the load is done.
335 didFinishLoad();
336 return;
337 }
338
339 AssetManager* am = globalAssetManager();
340
341 // Check to see if the error code was not generated internally
342 WebCore::PlatformBridge::rawResId id = WebCore::PlatformBridge::NoDomain;
343 if ((error.errorCode() == ErrorFile ||
344 error.errorCode() == ErrorFileNotFound) &&
345 (!error.localizedDescription().isEmpty())) {
346 id = WebCore::PlatformBridge::LoadError;
347 }
348 String filename = m_webFrame->getRawResourceFilename(id);
349 if (filename.isEmpty())
350 return;
351
352 // Grab the error page from the asset manager
353 Asset* a = am->openNonAsset(
354 filename.utf8().data(), Asset::ACCESS_BUFFER);
355 if (!a)
356 return;
357
358 // Take the failing url and encode html entities so javascript urls are not
359 // executed.
360 CString failingUrl = error.failingURL().utf8();
361 WTF::Vector<char> url;
362 int len = failingUrl.length();
363 const char* data = failingUrl.data();
364 for (int i = 0; i < len; i++) {
365 char c = data[i];
366 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
367 || (c >= '0' && c <= '9'))
368 url.append(c);
369 else {
370 char buf[16];
371 int res = sprintf(buf, "&#%d;", c);
372 buf[res] = 0;
373 url.append(buf, res);
374 }
375 }
376 // Vector sets up its data buffer lazilly, so if failingUrl is the empty
377 // string, the data buffer will be null. This will result in sanitizedUrl
378 // being null, and the string substitution below will be a no-op.
379 // FIXME: Ideally we'd always have a non-empty URL, or at least improve the
380 // wording of the error page in this case. See http://b/5293782.
381 String sanitizedUrl = url.data() ? String(url.data(), url.size()) : "";
382
383 // Replace all occurances of %s with the failing url.
384 String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength());
385 s = s.replace("%s", sanitizedUrl);
386
387 // Replace all occurances of %e with the error text
388 s = s.replace("%e", error.localizedDescription());
389
390 // Create the request and the substitute data and tell the FrameLoader to
391 // load with the replacement data.
392 // use KURL(const char*) as KURL(const String& url) can trigger ASSERT for
393 // invalidate URL string.
394 loadDataIntoFrame(m_frame, KURL(ParsedURLString, data), error.failingURL(), s);
395
396 // Delete the asset.
397 delete a;
398
399 // Report that the load is finished, since it failed.
400 didFinishLoad();
401 }
402
dispatchDidFailLoad(const ResourceError &)403 void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) {
404 // called when page is completed with error
405 didFinishLoad();
406 }
407
dispatchDidFinishDocumentLoad()408 void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() {
409 // called when finishedParsing
410 notImplemented();
411 }
412
dispatchDidFinishLoad()413 void FrameLoaderClientAndroid::dispatchDidFinishLoad() {
414 didFinishLoad();
415 }
416
dispatchDidFirstLayout()417 void FrameLoaderClientAndroid::dispatchDidFirstLayout() {
418 ASSERT(m_frame);
419 // set EXTRA_LAYOUT_DELAY if the loader is not completed yet
420 if (!m_frame->loader()->isComplete())
421 m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY);
422 // we need to do this here instead of dispatchDidFirstVisuallyNonEmptyLayout
423 // so that about:blank will update the screen.
424 if (!m_frame->tree()->parent()) {
425 // Only need to notify Java side for the top frame
426 WebViewCore::getWebViewCore(m_frame->view())->didFirstLayout();
427 }
428 }
429
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 WebFrameView* oldWebFrameView = static_cast<WebFrameView*> (m_frame->view()->platformWidget());
950 IntRect bounds = oldWebFrameView->getBounds();
951 IntRect visBounds = oldWebFrameView->getVisibleBounds();
952 IntRect windowBounds = oldWebFrameView->getWindowBounds();
953 WebCore::FrameView* oldFrameView = oldWebFrameView->view();
954 const float oldZoomFactor = oldFrameView->frame()->textZoomFactor();
955 m_frame->createView(bounds.size(), oldFrameView->baseBackgroundColor(), oldFrameView->isTransparent(),
956 oldFrameView->fixedLayoutSize(), oldFrameView->useFixedLayout());
957 if (oldZoomFactor != 1.0f && oldZoomFactor != m_frame->textZoomFactor()) {
958 m_frame->setTextZoomFactor(oldZoomFactor);
959 }
960
961 // Create a new WebFrameView for the new FrameView
962 WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore);
963
964 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
965 #else
966 webViewCore->clearContent();
967 #endif
968
969 newFrameView->setLocation(bounds.x(), bounds.y());
970 newFrameView->setSize(bounds.width(), bounds.height());
971 newFrameView->setVisibleSize(visBounds.width(), visBounds.height());
972 newFrameView->setWindowBounds(windowBounds.x(), windowBounds.y(), windowBounds.width(), windowBounds.height());
973 // newFrameView attaches itself to FrameView which Retains the reference, so
974 // call Release for newFrameView
975 Release(newFrameView);
976 // WebFrameView Retains webViewCore, so call Release for webViewCore
977 Release(webViewCore);
978
979 m_webFrame->transitionToCommitted(m_frame);
980 }
981
dispatchDidBecomeFrameset(bool)982 void FrameLoaderClientAndroid::dispatchDidBecomeFrameset(bool)
983 {
984 }
985
canCachePage() const986 bool FrameLoaderClientAndroid::canCachePage() const {
987 return true;
988 }
989
download(ResourceHandle * handle,const ResourceRequest &,const ResourceRequest &,const ResourceResponse &)990 void FrameLoaderClientAndroid::download(ResourceHandle* handle, const ResourceRequest&,
991 const ResourceRequest&, const ResourceResponse&) {
992 // Get the C++ side of the load listener and tell it to handle the download
993 handle->getInternal()->m_loader->downloadFile();
994 }
995
createFrame(const KURL & url,const String & name,HTMLFrameOwnerElement * ownerElement,const String & referrer,bool allowsScrolling,int marginWidth,int marginHeight)996 WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL& url, const String& name,
997 HTMLFrameOwnerElement* ownerElement, const String& referrer,
998 bool allowsScrolling, int marginWidth, int marginHeight)
999 {
1000 Frame* parent = ownerElement->document()->frame();
1001 FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(m_webFrame);
1002 RefPtr<Frame> pFrame = Frame::create(parent->page(), ownerElement, loaderC);
1003 Frame* newFrame = pFrame.get();
1004 loaderC->setFrame(newFrame);
1005 // Append the subframe to the parent and set the name of the subframe. The name must be set after
1006 // appending the child so that the name becomes unique.
1007 parent->tree()->appendChild(newFrame);
1008 newFrame->tree()->setName(name);
1009 // Create a new FrameView and WebFrameView for the child frame to draw into.
1010 RefPtr<FrameView> frameView = FrameView::create(newFrame);
1011 WebFrameView* webFrameView = new WebFrameView(frameView.get(),
1012 WebViewCore::getWebViewCore(parent->view()));
1013 // frameView Retains webFrameView, so call Release for webFrameView
1014 Release(webFrameView);
1015 // Attach the frameView to the newFrame.
1016 newFrame->setView(frameView);
1017 newFrame->init();
1018 newFrame->selection()->setFocused(true);
1019 LOGV("::WebCore:: createSubFrame returning %p", newFrame);
1020
1021 // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
1022 if (!pFrame->page())
1023 return 0;
1024
1025 parent->loader()->loadURLIntoChildFrame(url, referrer, pFrame.get());
1026
1027 // onLoad may cuase the frame to be removed from the document. Allow the RefPtr to delete the child frame.
1028 if (!pFrame->tree()->parent())
1029 return NULL;
1030
1031 return pFrame.release();
1032 }
1033
1034 // YouTube flash url path starts with /v/
1035 static const char slash_v_slash[] = { '/', 'v', '/' };
1036 static const char slash_e_slash[] = { '/', 'e', '/' };
1037
isValidYouTubeVideo(const String & path)1038 static bool isValidYouTubeVideo(const String& path)
1039 {
1040 if (!charactersAreAllASCII(path.characters(), path.length()))
1041 return false;
1042 unsigned int len = path.length();
1043 if (len <= sizeof(slash_v_slash)) // check for more than just /v/
1044 return false;
1045 CString str = path.lower().utf8();
1046 const char* data = str.data();
1047 // Youtube flash url can start with /v/ or /e/
1048 if (memcmp(data, slash_v_slash, sizeof(slash_v_slash)) != 0)
1049 if (memcmp(data, slash_e_slash, sizeof(slash_e_slash)) != 0)
1050 return false;
1051 // Start after /v/
1052 for (unsigned int i = sizeof(slash_v_slash); i < len; i++) {
1053 char c = data[i];
1054 // Check for alpha-numeric characters only.
1055 if (WTF::isASCIIAlphanumeric(c) || c == '_' || c == '-')
1056 continue;
1057 // The url can have more parameters such as &hl=en after the video id.
1058 // Once we start seeing extra parameters we can return true.
1059 return c == '&' && i > sizeof(slash_v_slash);
1060 }
1061 return true;
1062 }
1063
isYouTubeUrl(const KURL & url,const String & mimeType)1064 static bool isYouTubeUrl(const KURL& url, const String& mimeType)
1065 {
1066 String host = url.host();
1067 bool youtube = host.endsWith("youtube.com")
1068 || host.endsWith("youtube-nocookie.com");
1069 return youtube && isValidYouTubeVideo(url.path())
1070 && equalIgnoringCase(mimeType, "application/x-shockwave-flash");
1071 }
1072
isYouTubeInstalled()1073 static bool isYouTubeInstalled() {
1074 return WebCore::packageNotifier().isPackageInstalled("com.google.android.youtube");
1075 }
1076
1077 // Use PluginViewBase rather than an Android specific sub class as we do not require any
1078 // Android specific functionality; this just renders a placeholder which will later
1079 // activate the real plugin.
1080 class PluginToggleWidget : public PluginViewBase {
1081 public:
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)1082 PluginToggleWidget(Frame* parent, const IntSize& size,
1083 HTMLPlugInElement* elem, const KURL& url,
1084 const WTF::Vector<String>& paramNames,
1085 const WTF::Vector<String>& paramValues, const String& mimeType,
1086 bool loadManually)
1087 : PluginViewBase(0)
1088 , m_parent(parent)
1089 , m_size(size)
1090 , m_element(elem)
1091 , m_url(url)
1092 , m_paramNames(paramNames)
1093 , m_paramValues(paramValues)
1094 , m_mimeType(mimeType)
1095 , m_loadManually(loadManually)
1096 {
1097 resize(size);
1098 }
1099
paint(GraphicsContext * ctx,const IntRect & rect)1100 virtual void paint(GraphicsContext* ctx, const IntRect& rect)
1101 {
1102 // Most of this code is copied from PluginView::paintMissingPluginIcon
1103 // with slight modification.
1104
1105 static RefPtr<Image> image;
1106 if (!image) {
1107 image = Image::loadPlatformResource("togglePlugin");
1108 }
1109
1110 IntRect imageRect(x(), y(), image->width(), image->height());
1111
1112 int xOffset = (width() - imageRect.width()) >> 1;
1113 int yOffset = (height() - imageRect.height()) >> 1;
1114
1115 imageRect.move(xOffset, yOffset);
1116
1117 if (!rect.intersects(imageRect))
1118 return;
1119
1120 // FIXME: We need to clip similarly to paintMissingPluginIcon but it is
1121 // way screwed up right now. It has something to do with how we tell
1122 // webkit the scroll position and it causes the placeholder to get
1123 // clipped very badly. http://b/issue?id=2533303
1124
1125 ctx->save();
1126 ctx->clip(frameRect());
1127
1128 ctx->setFillColor(Color::white, ColorSpaceDeviceRGB);
1129 ctx->fillRect(frameRect());
1130 if (frameRect().contains(imageRect)) {
1131 // Leave a 2 pixel padding.
1132 const int pixelWidth = 2;
1133 IntRect innerRect = frameRect();
1134 innerRect.inflate(-pixelWidth);
1135 // Draw a 2 pixel light gray border.
1136 ctx->setStrokeColor(Color::lightGray, ColorSpaceDeviceRGB);
1137 ctx->strokeRect(innerRect, pixelWidth);
1138 }
1139
1140 // Draw the image in the center
1141 ctx->drawImage(image.get(), ColorSpaceDeviceRGB, imageRect.location());
1142 ctx->restore();
1143 }
1144
handleEvent(Event * event)1145 virtual void handleEvent(Event* event)
1146 {
1147 if (event->type() != eventNames().clickEvent)
1148 return;
1149
1150 Frame* frame = m_parent->page()->mainFrame();
1151 while (frame) {
1152 RenderView* view = frame->contentRenderer();
1153 const HashSet<RenderWidget*> widgets = view->widgets();
1154 HashSet<RenderWidget*>::const_iterator it = widgets.begin();
1155 HashSet<RenderWidget*>::const_iterator end = widgets.end();
1156 for (; it != end; ++it) {
1157 Widget* widget = (*it)->widget();
1158 // PluginWidget is used only with PluginToggleWidget
1159 if (widget && widget->isPluginViewBase()) {
1160 PluginToggleWidget* ptw =
1161 static_cast<PluginToggleWidget*>(widget);
1162 ptw->swapPlugin(*it);
1163 }
1164 }
1165 frame = frame->tree()->traverseNext();
1166 }
1167 }
1168
swapPlugin(RenderWidget * renderer)1169 void swapPlugin(RenderWidget* renderer) {
1170 typedef FrameLoaderClientAndroid FLCA;
1171 FLCA* client = static_cast<FLCA*>(m_parent->loader()->client());
1172 client->enableOnDemandPlugins();
1173 WTF::PassRefPtr<PluginView> prpWidget =
1174 PluginView::create(m_parent.get(),
1175 m_size,
1176 m_element,
1177 m_url,
1178 m_paramNames,
1179 m_paramValues,
1180 m_mimeType,
1181 m_loadManually);
1182 RefPtr<Widget> myProtector(this);
1183 prpWidget->focusPluginElement();
1184 renderer->setWidget(prpWidget);
1185 }
1186
1187 private:
invalidateRect(const IntRect & rect)1188 void invalidateRect(const IntRect& rect) { }
1189
1190 RefPtr<Frame> m_parent;
1191 IntSize m_size;
1192 HTMLPlugInElement* m_element;
1193 KURL m_url;
1194 WTF::Vector<String> m_paramNames;
1195 WTF::Vector<String> m_paramValues;
1196 String m_mimeType;
1197 bool m_loadManually;
1198 };
1199
createPlugin(const IntSize & size,HTMLPlugInElement * element,const KURL & url,const WTF::Vector<String> & names,const WTF::Vector<String> & values,const String & mimeType,bool loadManually)1200 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createPlugin(
1201 const IntSize& size,
1202 HTMLPlugInElement* element,
1203 const KURL& url,
1204 const WTF::Vector<String>& names,
1205 const WTF::Vector<String>& values,
1206 const String& mimeType,
1207 bool loadManually) {
1208 WTF::PassRefPtr<PluginView> prpWidget = 0;
1209 #ifdef ANDROID_PLUGINS
1210 // This is copied from PluginView.cpp. We need to determine if a plugin
1211 // will be found before doing some of the work in PluginView.
1212 String mimeTypeCopy = mimeType;
1213 PluginPackage* plugin =
1214 PluginDatabase::installedPlugins()->findPlugin(url, mimeTypeCopy);
1215 if (!plugin && PluginDatabase::installedPlugins()->refresh()) {
1216 mimeTypeCopy = mimeType;
1217 plugin = PluginDatabase::installedPlugins()->findPlugin(url,
1218 mimeTypeCopy);
1219 }
1220 Settings* settings = m_frame->settings();
1221 // Do the placeholder if plugins are on-demand and there is a plugin for the
1222 // given mime type.
1223 if (settings && settings->arePluginsOnDemand() && plugin &&
1224 !m_onDemandPluginsEnabled) {
1225 return adoptRef(new PluginToggleWidget(m_frame, size, element, url,
1226 names, values, mimeType, loadManually));
1227 }
1228 prpWidget = PluginView::create(m_frame,
1229 size,
1230 element,
1231 url,
1232 names,
1233 values,
1234 mimeType,
1235 loadManually);
1236 // Return the plugin if it was loaded successfully. Otherwise, fallback to
1237 // the youtube placeholder if possible. No need to check prpWidget as
1238 // PluginView::create will create a PluginView for missing plugins.
1239 // Note: this check really only checks if the plugin was found and not if
1240 // the plugin was loaded.
1241 if (prpWidget->status() == PluginStatusLoadedSuccessfully)
1242 return prpWidget;
1243 #endif
1244 // Create an iframe for youtube urls.
1245 if (isYouTubeUrl(url, mimeType) && isYouTubeInstalled()) {
1246 WTF::RefPtr<Frame> frame = createFrame(blankURL(), String(), element,
1247 String(), false, 0, 0);
1248 if (frame) {
1249 // grab everything after /v/
1250 String videoId = url.path().substring(sizeof(slash_v_slash));
1251 // Extract just the video id
1252 unsigned videoIdEnd = 0;
1253 for (; videoIdEnd < videoId.length(); videoIdEnd++) {
1254 if (videoId[videoIdEnd] == '&') {
1255 videoId = videoId.left(videoIdEnd);
1256 break;
1257 }
1258 }
1259 AssetManager* am = globalAssetManager();
1260 Asset* a = am->open("webkit/youtube.html",
1261 Asset::ACCESS_BUFFER);
1262 if (!a)
1263 return NULL;
1264 String s = String((const char*)a->getBuffer(false), a->getLength());
1265 s = s.replace("VIDEO_ID", videoId);
1266 delete a;
1267 loadDataIntoFrame(frame.get(),
1268 KURL(ParsedURLString, "file:///android_asset/webkit/"), String(), s);
1269 // Transfer ownership to a local refptr.
1270 WTF::RefPtr<Widget> widget(frame->view());
1271 return widget.release();
1272 }
1273 }
1274 return prpWidget;
1275 }
1276
redirectDataToPlugin(Widget * pluginWidget)1277 void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) {
1278 // Do not redirect data if the Widget is our plugin placeholder.
1279 if (pluginWidget->isPluginView()) {
1280 m_manualLoader = static_cast<PluginView*>(pluginWidget);
1281 }
1282 }
1283
createJavaAppletWidget(const IntSize &,HTMLAppletElement *,const KURL & baseURL,const WTF::Vector<String> & paramNames,const WTF::Vector<String> & paramValues)1284 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, HTMLAppletElement*,
1285 const KURL& baseURL, const WTF::Vector<String>& paramNames,
1286 const WTF::Vector<String>& paramValues) {
1287 // don't support widget yet
1288 notImplemented();
1289 return 0;
1290 }
1291
didTransferChildFrameToNewDocument(WebCore::Page *)1292 void FrameLoaderClientAndroid::didTransferChildFrameToNewDocument(WebCore::Page*)
1293 {
1294 ASSERT(m_frame);
1295 // m_webFrame points to the WebFrame for the page that our frame previously
1296 // belonged to. If the frame now belongs to a new page, we need to update
1297 // m_webFrame to point to the WebFrame for the new page.
1298 Page* newPage = m_frame->page();
1299 if (newPage != m_webFrame->page()) {
1300 ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(newPage->chrome()->client());
1301 Release(m_webFrame);
1302 m_webFrame = chromeClient->webFrame();
1303 Retain(m_webFrame);
1304 }
1305 }
1306
transferLoadingResourceFromPage(unsigned long,DocumentLoader *,const ResourceRequest &,Page *)1307 void FrameLoaderClientAndroid::transferLoadingResourceFromPage(unsigned long, DocumentLoader*, const ResourceRequest&, Page*)
1308 {
1309 notImplemented();
1310 }
1311
1312 // This function is used by the <OBJECT> element to determine the type of
1313 // the contents and work out if it can render it.
objectContentType(const KURL & url,const String & mimeType,bool shouldPreferPlugInsForImages)1314 ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url, const String& mimeType, bool shouldPreferPlugInsForImages) {
1315 return FrameLoader::defaultObjectContentType(url, mimeType, shouldPreferPlugInsForImages);
1316 }
1317
1318 // This function allows the application to set the correct CSS media
1319 // style. Android could use it to set the media style 'handheld'. Safari
1320 // may use it to set the media style to 'print' when the user wants to print
1321 // a particular web page.
overrideMediaType() const1322 String FrameLoaderClientAndroid::overrideMediaType() const {
1323 notImplemented();
1324 return String();
1325 }
1326
1327 // This function is used to re-attach Javascript<->native code classes.
dispatchDidClearWindowObjectInWorld(DOMWrapperWorld * world)1328 void FrameLoaderClientAndroid::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
1329 {
1330 if (world != mainThreadNormalWorld())
1331 return;
1332
1333 ASSERT(m_frame);
1334 LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n",
1335 m_frame, m_frame->loader()->url().string().ascii().data());
1336 m_webFrame->windowObjectCleared(m_frame);
1337 }
1338
documentElementAvailable()1339 void FrameLoaderClientAndroid::documentElementAvailable() {
1340 }
1341
1342 // functions new to Jun-07 tip of tree merge:
blockedError(ResourceRequest const & request)1343 ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) {
1344 return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String());
1345 }
1346
1347 // functions new to Nov-07 tip of tree merge:
didPerformFirstNavigation() const1348 void FrameLoaderClientAndroid::didPerformFirstNavigation() const {
1349 // This seems to be just a notification that the UI can listen to, to
1350 // know if the user has performed first navigation action.
1351 // It is called from
1352 // void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
1353 // "Navigation" here means a transition from one page to another that
1354 // ends up in the back/forward list.
1355 }
1356
registerForIconNotification(bool listen)1357 void FrameLoaderClientAndroid::registerForIconNotification(bool listen) {
1358 if (listen)
1359 WebIconDatabase::RegisterForIconNotification(this);
1360 else
1361 WebIconDatabase::UnregisterForIconNotification(this);
1362 }
1363
1364 // This is the WebIconDatabaseClient method for receiving a notification when we
1365 // get the icon for the page.
didAddIconForPageUrl(const String & pageUrl)1366 void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) {
1367 // This call must happen before dispatchDidReceiveIcon since that method
1368 // may register for icon notifications again since the icon data may have
1369 // to be read from disk.
1370 registerForIconNotification(false);
1371 KURL u(ParsedURLString, pageUrl);
1372 if (equalIgnoringFragmentIdentifier(u, m_frame->document()->url())) {
1373 dispatchDidReceiveIcon();
1374 }
1375 }
1376
dispatchDidChangeIcons()1377 void FrameLoaderClientAndroid::dispatchDidChangeIcons() {
1378 notImplemented();
1379 }
1380
createNetworkingContext()1381 PassRefPtr<FrameNetworkingContext> FrameLoaderClientAndroid::createNetworkingContext()
1382 {
1383 return FrameNetworkingContextAndroid::create(getFrame());
1384 }
1385
1386 }
1387