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