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