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