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