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 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 94 FrameLoaderClientAndroid* FrameLoaderClientAndroid::get(const WebCore::Frame* frame) 95 { 96 return static_cast<FrameLoaderClientAndroid*> (frame->loader()->client()); 97 } 98 99 void FrameLoaderClientAndroid::frameLoaderDestroyed() { 100 registerForIconNotification(false); 101 m_frame = 0; 102 Release(m_webFrame); 103 delete this; 104 } 105 106 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 113 void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) { 114 m_onDemandPluginsEnabled = false; 115 // don't use representation 116 verifiedOk(); 117 } 118 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 126 void FrameLoaderClientAndroid::forceLayoutForNonHTML() { 127 notImplemented(); 128 } 129 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 137 void FrameLoaderClientAndroid::detachedFromParent2() { 138 // FIXME, ready to detach frame from view 139 } 140 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. 149 void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id, 150 DocumentLoader*, const ResourceRequest&) { 151 lowPriority_notImplemented(); 152 } 153 154 void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id, 155 ResourceRequest&, const ResourceResponse&) { 156 lowPriority_notImplemented(); 157 } 158 159 bool FrameLoaderClientAndroid::shouldUseCredentialStorage(DocumentLoader*, unsigned long identifier) 160 { 161 notImplemented(); 162 return false; 163 } 164 165 void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, 166 unsigned long id, const AuthenticationChallenge&) { 167 lowPriority_notImplemented(); 168 } 169 170 void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*, 171 unsigned long id, const AuthenticationChallenge&) { 172 lowPriority_notImplemented(); 173 } 174 175 void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*, 176 unsigned long id, const ResourceResponse&) { 177 lowPriority_notImplemented(); 178 } 179 180 void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*, 181 unsigned long id, int lengthReceived) { 182 lowPriority_notImplemented(); 183 } 184 185 void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*, 186 unsigned long id) { 187 lowPriority_notImplemented(); 188 } 189 190 void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader, 191 unsigned long id, const ResourceError&) { 192 lowPriority_notImplemented(); 193 } 194 195 bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, 196 const ResourceRequest&, const ResourceResponse&, int length) { 197 notImplemented(); 198 return false; 199 } 200 201 void FrameLoaderClientAndroid::dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString&) { 202 return; 203 } 204 205 void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() { 206 } 207 208 void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() { 209 ASSERT(m_frame); 210 // Tell the load it was a redirect. 211 m_webFrame->loadStarted(m_frame); 212 } 213 214 void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() { 215 notImplemented(); 216 } 217 218 void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&, 219 double interval, double fireDate) { 220 notImplemented(); 221 } 222 223 void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() { 224 notImplemented(); 225 } 226 227 void FrameLoaderClientAndroid::dispatchDidPushStateWithinPage() 228 { 229 notImplemented(); 230 } 231 232 void FrameLoaderClientAndroid::dispatchDidReplaceStateWithinPage() 233 { 234 notImplemented(); 235 } 236 237 void FrameLoaderClientAndroid::dispatchDidPopStateWithinPage() 238 { 239 notImplemented(); 240 } 241 242 void FrameLoaderClientAndroid::dispatchWillClose() { 243 notImplemented(); 244 } 245 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 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 282 void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() { 283 notImplemented(); 284 } 285 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 295 void FrameLoaderClientAndroid::dispatchDidCommitLoad() { 296 verifiedOk(); 297 } 298 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 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 380 void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) { 381 // called when page is completed with error 382 didFinishLoad(); 383 } 384 385 void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() { 386 // called when finishedParsing 387 lowPriority_notImplemented(); 388 } 389 390 void FrameLoaderClientAndroid::dispatchDidFinishLoad() { 391 didFinishLoad(); 392 } 393 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 405 void FrameLoaderClientAndroid::dispatchDidFirstVisuallyNonEmptyLayout() 406 { 407 notImplemented(); 408 } 409 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 424 void FrameLoaderClientAndroid::dispatchShow() { 425 ASSERT(m_frame); 426 m_frame->view()->invalidate(); 427 } 428 429 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 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 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 522 void FrameLoaderClientAndroid::cancelPolicyCheck() { 523 lowPriority_notImplemented(); 524 } 525 526 void FrameLoaderClientAndroid::dispatchUnableToImplementPolicy(const ResourceError&) { 527 notImplemented(); 528 } 529 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 555 void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, PassRefPtr<FormState>) { 556 ASSERT(m_frame); 557 ASSERT(func); 558 (m_frame->loader()->policyChecker()->*func)(PolicyUse); 559 } 560 561 void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) { 562 notImplemented(); 563 } 564 565 void FrameLoaderClientAndroid::revertToProvisionalState(DocumentLoader*) { 566 notImplemented(); 567 } 568 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. 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. 590 void FrameLoaderClientAndroid::didChangeEstimatedProgress() { 591 verifiedOk(); 592 } 593 594 // This will give us the initial estimate when the page first starts to load. 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. 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. 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 620 void FrameLoaderClientAndroid::setMainFrameDocumentReady(bool) { 621 // this is only interesting once we provide an external API for the DOM 622 notImplemented(); 623 } 624 625 void FrameLoaderClientAndroid::startDownload(const ResourceRequest&) { 626 notImplemented(); 627 } 628 629 void FrameLoaderClientAndroid::willChangeTitle(DocumentLoader*) { 630 verifiedOk(); 631 } 632 633 void FrameLoaderClientAndroid::didChangeTitle(DocumentLoader* loader) { 634 verifiedOk(); 635 } 636 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 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 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 673 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 679 void FrameLoaderClientAndroid::didDisplayInsecureContent() 680 { 681 notImplemented(); 682 } 683 684 void FrameLoaderClientAndroid::didRunInsecureContent(SecurityOrigin*) 685 { 686 notImplemented(); 687 } 688 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 714 ResourceError FrameLoaderClientAndroid::cancelledError(const ResourceRequest& request) { 715 return ResourceError(String(), InternalErrorCancelled, request.url(), String()); 716 } 717 718 ResourceError FrameLoaderClientAndroid::cannotShowURLError(const ResourceRequest& request) { 719 return ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String()); 720 } 721 722 ResourceError FrameLoaderClientAndroid::interruptForPolicyChangeError(const ResourceRequest& request) { 723 return ResourceError(String(), InternalErrorInterrupted, request.url(), String()); 724 } 725 726 ResourceError FrameLoaderClientAndroid::cannotShowMIMETypeError(const ResourceResponse& request) { 727 return ResourceError(String(), InternalErrorCannotShowMimeType, request.url(), String()); 728 } 729 730 ResourceError FrameLoaderClientAndroid::fileDoesNotExistError(const ResourceResponse& request) { 731 return ResourceError(String(), InternalErrorFileDoesNotExist, request.url(), String()); 732 } 733 734 ResourceError FrameLoaderClientAndroid::pluginWillHandleLoadError(const ResourceResponse& request) { 735 return ResourceError(String(), InternalErrorPluginWillHandleLoadError, request.url(), String()); 736 } 737 738 bool FrameLoaderClientAndroid::shouldFallBack(const ResourceError&) { 739 notImplemented(); 740 return false; 741 } 742 743 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 757 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 774 bool FrameLoaderClientAndroid::representationExistsForURLScheme(const String&) const { 775 // don't use representation 776 verifiedOk(); 777 return false; 778 } 779 780 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 787 void FrameLoaderClientAndroid::frameLoadCompleted() { 788 // copied from Apple port, without this back with sub-frame will trigger ASSERT 789 ASSERT(m_frame); 790 } 791 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 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 823 void FrameLoaderClientAndroid::dispatchDidAddBackForwardItem(HistoryItem* item) const { 824 ASSERT(m_frame); 825 m_webFrame->addHistoryItem(item); 826 } 827 828 void FrameLoaderClientAndroid::dispatchDidRemoveBackForwardItem(HistoryItem* item) const { 829 ASSERT(m_frame); 830 m_webFrame->removeHistoryItem(0); 831 } 832 833 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 840 void FrameLoaderClientAndroid::provisionalLoadStarted() { 841 ASSERT(m_frame); 842 m_webFrame->loadStarted(m_frame); 843 } 844 845 void FrameLoaderClientAndroid::didFinishLoad() { 846 ASSERT(m_frame); 847 m_frame->document()->setExtraLayoutDelay(0); 848 m_webFrame->didFinishLoad(m_frame); 849 } 850 851 void FrameLoaderClientAndroid::prepareForDataSourceReplacement() { 852 verifiedOk(); 853 } 854 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 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 867 String FrameLoaderClientAndroid::userAgent(const KURL& u) { 868 return m_webFrame->userAgentForURL(&u); 869 } 870 871 void FrameLoaderClientAndroid::savePlatformDataToCachedFrame(WebCore::CachedFrame* cachedFrame) { 872 CachedFramePlatformDataAndroid* platformData = new CachedFramePlatformDataAndroid(m_frame->settings()); 873 cachedFrame->setCachedFramePlatformData(platformData); 874 } 875 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 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 920 bool FrameLoaderClientAndroid::canCachePage() const { 921 return true; 922 } 923 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 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 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 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 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: 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 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 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 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 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 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 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. 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. 1229 String FrameLoaderClientAndroid::overrideMediaType() const { 1230 lowPriority_notImplemented(); 1231 return String(); 1232 } 1233 1234 // This function is used to re-attach Javascript<->native code classes. 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 1246 void FrameLoaderClientAndroid::documentElementAvailable() { 1247 } 1248 1249 // functions new to Jun-07 tip of tree merge: 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: 1255 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 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. 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