• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 APPLE COMPUTER, INC. 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 #define LOG_TAG "WebCore"
26 
27 #include "config.h"
28 
29 #include "android_graphics.h"
30 #include "CString.h"
31 #include "DocumentLoader.h"
32 #include "DOMImplementation.h"
33 #include "Frame.h"
34 #include "FrameLoader.h"
35 #include "FrameLoaderClientAndroid.h"
36 #include "FrameTree.h"
37 #include "GraphicsContext.h"
38 #include "HTMLFrameOwnerElement.h"
39 #include "HTMLPlugInElement.h"
40 #include "IconDatabase.h"
41 #include "MIMETypeRegistry.h"
42 #include "NotImplemented.h"
43 #include "Page.h"
44 #include "PlatformGraphicsContext.h"
45 #include "PlatformString.h"
46 #include "PluginDatabase.h"
47 #include "PluginView.h"
48 #include "ProgressTracker.h"
49 #include "RenderPart.h"
50 #include "ResourceError.h"
51 #include "SelectionController.h"
52 #include "SkCanvas.h"
53 #include "SkRect.h"
54 #include "TextEncoding.h"
55 #include "Document.h"
56 #include "FrameView.h"
57 #include "HistoryItem.h"
58 #include "ResourceHandle.h"
59 #include "ResourceHandleInternal.h"
60 #include "WebCoreFrameBridge.h"
61 #include "WebCoreResourceLoader.h"
62 #include "WebHistory.h"
63 #include "WebIconDatabase.h"
64 #include "WebFrameView.h"
65 #include "WebViewCore.h"
66 #include "Settings.h"
67 
68 #include <utils/AssetManager.h>
69 
70 extern android::AssetManager* globalAssetManager();
71 
72 namespace android {
73 
74 static const int EXTRA_LAYOUT_DELAY = 1000;
75 
FrameLoaderClientAndroid(WebFrame * webframe)76 FrameLoaderClientAndroid::FrameLoaderClientAndroid(WebFrame* webframe)
77     : m_frame(NULL)
78     , m_webFrame(webframe) {
79     Retain(m_webFrame);
80 }
81 
get(const WebCore::Frame * frame)82 FrameLoaderClientAndroid* FrameLoaderClientAndroid::get(const WebCore::Frame* frame)
83 {
84     return static_cast<FrameLoaderClientAndroid*> (frame->loader()->client());
85 }
86 
frameLoaderDestroyed()87 void FrameLoaderClientAndroid::frameLoaderDestroyed() {
88     registerForIconNotification(false);
89     m_frame = 0;
90     Release(m_webFrame);
91     delete this;
92 }
93 
hasWebView() const94 bool FrameLoaderClientAndroid::hasWebView() const {
95     // FIXME,
96     // there is one web view per page, or top frame.
97     // as android's view is created from Java side, it is always there.
98     return true;
99 }
100 
makeRepresentation(DocumentLoader *)101 void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) {
102     // don't use representation
103     verifiedOk();
104 }
105 
forceLayout()106 void FrameLoaderClientAndroid::forceLayout() {
107     ASSERT(m_frame);
108     m_frame->view()->forceLayout();
109     // FIXME, should we adjust view size here?
110     m_frame->view()->adjustViewSize();
111 }
112 
forceLayoutForNonHTML()113 void FrameLoaderClientAndroid::forceLayoutForNonHTML() {
114     notImplemented();
115 }
116 
setCopiesOnScroll()117 void FrameLoaderClientAndroid::setCopiesOnScroll() {
118     // this is a hint about whether we need to force redraws, or can
119     // just copy the scrolled content. Since we always force a redraw
120     // anyways, we can ignore this call.
121     verifiedOk();
122 }
123 
detachedFromParent2()124 void FrameLoaderClientAndroid::detachedFromParent2() {
125     // FIXME, ready to detach frame from view
126 }
127 
detachedFromParent3()128 void FrameLoaderClientAndroid::detachedFromParent3() {
129     // FIXME, ready to release view
130     notImplemented();
131 }
132 
133 // This function is responsible for associating the "id" with a given
134 // subresource load.  The following functions that accept an "id" are
135 // called for each subresource, so they should not be dispatched to the m_frame.
assignIdentifierToInitialRequest(unsigned long id,DocumentLoader *,const ResourceRequest &)136 void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id,
137                             DocumentLoader*, const ResourceRequest&) {
138     lowPriority_notImplemented();
139 }
140 
dispatchWillSendRequest(DocumentLoader *,unsigned long id,ResourceRequest &,const ResourceResponse &)141 void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id,
142                             ResourceRequest&, const ResourceResponse&) {
143     lowPriority_notImplemented();
144 }
145 
shouldUseCredentialStorage(DocumentLoader *,unsigned long identifier)146 bool FrameLoaderClientAndroid::shouldUseCredentialStorage(DocumentLoader*, unsigned long  identifier)
147 {
148     notImplemented();
149     return false;
150 }
151 
dispatchDidReceiveAuthenticationChallenge(DocumentLoader *,unsigned long id,const AuthenticationChallenge &)152 void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*,
153                             unsigned long id, const AuthenticationChallenge&) {
154     lowPriority_notImplemented();
155 }
156 
dispatchDidCancelAuthenticationChallenge(DocumentLoader *,unsigned long id,const AuthenticationChallenge &)157 void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*,
158                             unsigned long id, const AuthenticationChallenge&) {
159     lowPriority_notImplemented();
160 }
161 
dispatchDidReceiveResponse(DocumentLoader *,unsigned long id,const ResourceResponse &)162 void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*,
163                             unsigned long id, const ResourceResponse&) {
164     lowPriority_notImplemented();
165 }
166 
dispatchDidReceiveContentLength(DocumentLoader *,unsigned long id,int lengthReceived)167 void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*,
168                             unsigned long id, int lengthReceived) {
169     lowPriority_notImplemented();
170 }
171 
dispatchDidFinishLoading(DocumentLoader *,unsigned long id)172 void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*,
173                             unsigned long id) {
174     lowPriority_notImplemented();
175 }
176 
dispatchDidFailLoading(DocumentLoader * docLoader,unsigned long id,const ResourceError &)177 void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader,
178                             unsigned long id, const ResourceError&) {
179     lowPriority_notImplemented();
180 }
181 
dispatchDidLoadResourceFromMemoryCache(DocumentLoader *,const ResourceRequest &,const ResourceResponse &,int length)182 bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*,
183                             const ResourceRequest&, const ResourceResponse&, int length) {
184     notImplemented();
185     return false;
186 }
187 
dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier,const ScriptString &)188 void FrameLoaderClientAndroid::dispatchDidLoadResourceByXMLHttpRequest(unsigned long identifier, const ScriptString&) {
189     return;
190 }
191 
dispatchDidHandleOnloadEvents()192 void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() {
193 }
194 
dispatchDidReceiveServerRedirectForProvisionalLoad()195 void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() {
196     ASSERT(m_frame);
197     // Tell the load it was a redirect.
198     m_webFrame->loadStarted(m_frame);
199 }
200 
dispatchDidCancelClientRedirect()201 void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() {
202     notImplemented();
203 }
204 
dispatchWillPerformClientRedirect(const KURL &,double interval,double fireDate)205 void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&,
206                                 double interval, double fireDate) {
207     notImplemented();
208 }
209 
dispatchDidChangeLocationWithinPage()210 void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() {
211     notImplemented();
212 }
213 
dispatchWillClose()214 void FrameLoaderClientAndroid::dispatchWillClose() {
215     notImplemented();
216 }
217 
dispatchDidReceiveIcon()218 void FrameLoaderClientAndroid::dispatchDidReceiveIcon() {
219     ASSERT(m_frame);
220     if (m_frame->tree() && m_frame->tree()->parent())
221         return;
222     WebCore::String url(m_frame->loader()->url().string());
223     // Try to obtain the icon image.
224     WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(
225             url, WebCore::IntSize(16, 16));
226     // If the request fails, try the original request url.
227     if (!icon) {
228         DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
229         KURL originalURL = docLoader->originalRequest().url();
230         icon = WebCore::iconDatabase()->iconForPageURL(
231                    originalURL, WebCore::IntSize(16, 16));
232     }
233     // There is a bug in webkit where cancelling an icon load is treated as a
234     // failure. When this is fixed, we can ASSERT again that we have an icon.
235     if (icon) {
236         LOGV("Received icon (%p) for %s", icon,
237                 url.utf8().data());
238         m_webFrame->didReceiveIcon(icon);
239     } else {
240         LOGV("Icon data for %s unavailable, registering for notification...",
241                 url.utf8().data());
242         registerForIconNotification();
243     }
244 }
245 
dispatchDidReceiveTouchIconURL(const String & url,bool precomposed)246 void FrameLoaderClientAndroid::dispatchDidReceiveTouchIconURL(const String& url, bool precomposed) {
247     ASSERT(m_frame);
248     // Do not report sub frame touch icons
249     if (m_frame->tree() && m_frame->tree()->parent())
250         return;
251     m_webFrame->didReceiveTouchIconURL(url, precomposed);
252 }
253 
dispatchDidStartProvisionalLoad()254 void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() {
255     notImplemented();
256 }
257 
dispatchDidReceiveTitle(const String & title)258 void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const String& title) {
259     ASSERT(m_frame);
260     // Used to check for FrameLoadTypeStandard but we only want to send the title for
261     // the top frame and not sub-frames.
262     if (!m_frame->tree() || !m_frame->tree()->parent()) {
263         m_webFrame->setTitle(title);
264     }
265 }
266 
dispatchDidCommitLoad()267 void FrameLoaderClientAndroid::dispatchDidCommitLoad() {
268     verifiedOk();
269 }
270 
loadDataIntoFrame(Frame * frame,KURL baseUrl,const String & url,const String & data)271 static void loadDataIntoFrame(Frame* frame, KURL baseUrl, const String& url,
272         const String& data) {
273     if (baseUrl.isEmpty()) {
274         baseUrl = blankURL();
275     }
276     ResourceRequest request(baseUrl);
277     CString cstr = data.utf8();
278     RefPtr<WebCore::SharedBuffer> buf = WebCore::SharedBuffer::create(cstr.data(), cstr.length());
279     SubstituteData subData(buf, String("text/html"), String("utf-8"),
280             KURL(KURL(), url));
281     frame->loader()->load(request, subData, false);
282 }
283 
dispatchDidFailProvisionalLoad(const ResourceError & error)284 void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) {
285     ASSERT(m_frame);
286     // Ignore ErrorInterrupted since it is due to a policy interruption. This
287     // is caused by a decision to download the main resource rather than
288     // display it.
289     if (error.errorCode() == InternalErrorInterrupted
290             || error.errorCode() == InternalErrorCancelled) {
291         // If we decided to download the main resource or if the user cancelled
292         // it, make sure we report that the load is done.
293         didFinishLoad();
294         return;
295     }
296 
297     AssetManager* am = globalAssetManager();
298 
299     // Check to see if the error code was not generated internally
300     WebFrame::RAW_RES_ID id = WebFrame::NODOMAIN;
301     if ((error.errorCode() == ErrorFile ||
302             error.errorCode() == ErrorFileNotFound) &&
303             (!error.localizedDescription().isEmpty())) {
304         id = WebFrame::LOADERROR;
305     }
306     String filename = m_webFrame->getRawResourceFilename(id);
307     if (filename.isEmpty())
308         return;
309 
310     // Grab the error page from the asset manager
311     Asset* a = am->openNonAsset(
312             filename.utf8().data(), Asset::ACCESS_BUFFER);
313     if (!a)
314         return;
315 
316     // Take the failing url and encode html entities so javascript urls are not
317     // executed.
318     CString failingUrl = error.failingURL().utf8();
319     WTF::Vector<char> url;
320     int len = failingUrl.length();
321     const char* data = failingUrl.data();
322     for (int i = 0; i < len; i++) {
323         char c = data[i];
324         if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
325                 || (c >= '0' && c <= '9'))
326             url.append(c);
327         else {
328             char buf[16];
329             int res = sprintf(buf, "&#%d;", c);
330             buf[res] = 0;
331             url.append(buf, res);
332         }
333     }
334 
335     // Replace all occurances of %s with the failing url.
336     String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength());
337     s = s.replace("%s", String(url.data(), url.size()));
338 
339     // Replace all occurances of %e with the error text
340     s = s.replace("%e", error.localizedDescription());
341 
342     // Create the request and the substitute data and tell the FrameLoader to
343     // load with the replacement data.
344     // use KURL(const char*) as KURL(const String& url) can trigger ASSERT for
345     // invalidate URL string.
346     loadDataIntoFrame(m_frame, KURL(data), error.failingURL(), s);
347 
348     // Delete the asset.
349     delete a;
350 }
351 
dispatchDidFailLoad(const ResourceError &)352 void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) {
353     // called when page is completed with error
354     didFinishLoad();
355 }
356 
dispatchDidFinishDocumentLoad()357 void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() {
358     // called when finishedParsing
359     lowPriority_notImplemented();
360 }
361 
dispatchDidFinishLoad()362 void FrameLoaderClientAndroid::dispatchDidFinishLoad() {
363     didFinishLoad();
364 }
365 
dispatchDidFirstLayout()366 void FrameLoaderClientAndroid::dispatchDidFirstLayout() {
367     ASSERT(m_frame);
368     m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY);
369     // we need to do this here instead of dispatchDidFirstVisuallyNonEmptyLayout
370     // so that about:blank will update the screen.
371     if (!m_frame->tree()->parent()) {
372         // Only need to notify Java side for the top frame
373         WebViewCore::getWebViewCore(m_frame->view())->didFirstLayout();
374     }
375 }
376 
dispatchDidFirstVisuallyNonEmptyLayout()377 void FrameLoaderClientAndroid::dispatchDidFirstVisuallyNonEmptyLayout()
378 {
379     notImplemented();
380 }
381 
dispatchCreatePage()382 Frame* FrameLoaderClientAndroid::dispatchCreatePage() {
383     ASSERT(m_frame);
384 #ifdef ANDROID_MULTIPLE_WINDOWS
385     if (m_frame->settings() && m_frame->settings()->supportMultipleWindows())
386         // Always a user gesture since window.open maps to
387         // ChromeClientAndroid::createWindow
388         return m_webFrame->createWindow(false, true);
389     else
390 #endif
391         // If the client doesn't support multiple windows, just replace the
392         // current frame's contents.
393         return m_frame;
394 }
395 
dispatchShow()396 void FrameLoaderClientAndroid::dispatchShow() {
397     ASSERT(m_frame);
398     m_frame->view()->invalidate();
399 }
400 
401 
TreatAsAttachment(const String & content_disposition)402 static bool TreatAsAttachment(const String& content_disposition) {
403     // Some broken sites just send
404     // Content-Disposition: ; filename="file"
405     // screen those out here.
406     if (content_disposition.startsWith(";"))
407         return false;
408 
409     if (content_disposition.startsWith("inline", false))
410         return false;
411 
412     // Some broken sites just send
413     // Content-Disposition: filename="file"
414     // without a disposition token... screen those out.
415     if (content_disposition.startsWith("filename", false))
416         return false;
417 
418     // Also in use is Content-Disposition: name="file"
419     if (content_disposition.startsWith("name", false))
420         return false;
421 
422     // We have a content-disposition of "attachment" or unknown.
423     // RFC 2183, section 2.8 says that an unknown disposition
424     // value should be treated as "attachment"
425     return true;
426 }
427 
dispatchDecidePolicyForMIMEType(FramePolicyFunction func,const String & MIMEType,const ResourceRequest & request)428 void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFunction func,
429                                 const String& MIMEType, const ResourceRequest& request) {
430     ASSERT(m_frame);
431     ASSERT(func);
432     if (!func)
433         return;
434     if (request.isNull()) {
435         (m_frame->loader()->*func)(PolicyIgnore);
436         return;
437     }
438     // Default to Use (display internally).
439     PolicyAction action = PolicyUse;
440     // Check if we should Download instead.
441     const ResourceResponse& response = m_frame->loader()->activeDocumentLoader()->response();
442     const String& content_disposition = response.httpHeaderField("Content-Disposition");
443     if (!content_disposition.isEmpty()) {
444         // Server wants to override our normal policy.
445         if (TreatAsAttachment(content_disposition)) {
446             // Check to see if we are a sub frame (main frame has no owner element)
447             if (m_frame->ownerElement() != 0)
448                 action = PolicyIgnore;
449             else
450                 action = PolicyDownload;
451         }
452     } else {
453         // Ask if it can be handled internally.
454         if (!canShowMIMEType(MIMEType)) {
455             // Check to see if we are a sub frame (main frame has no owner element)
456             if (m_frame->ownerElement() != 0)
457                 action = PolicyIgnore;
458             else
459                 action = PolicyDownload;
460         }
461     }
462     // A status code of 204 indicates no content change. Ignore the result.
463     WebCore::DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
464     if (docLoader->response().httpStatusCode() == 204)
465         action = PolicyIgnore;
466     (m_frame->loader()->*func)(action);
467 }
468 
dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,const NavigationAction & action,const ResourceRequest & request,PassRefPtr<FormState> formState,const String & frameName)469 void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,
470                                 const NavigationAction& action, const ResourceRequest& request,
471                                 PassRefPtr<FormState> formState, const String& frameName) {
472     ASSERT(m_frame);
473     ASSERT(func);
474     if (!func)
475         return;
476 
477     if (request.isNull()) {
478         (m_frame->loader()->*func)(PolicyIgnore);
479         return;
480     }
481 
482     if (action.type() == NavigationTypeFormSubmitted || action.type() == NavigationTypeFormResubmitted)
483         m_frame->loader()->resetMultipleFormSubmissionProtection();
484 
485     // If we get to this point it means that a link has a target that was not
486     // found by the frame tree. Instead of creating a new frame, return the
487     // current frame in dispatchCreatePage.
488     if (canHandleRequest(request))
489         (m_frame->loader()->*func)(PolicyUse);
490     else
491         (m_frame->loader()->*func)(PolicyIgnore);
492 }
493 
cancelPolicyCheck()494 void FrameLoaderClientAndroid::cancelPolicyCheck() {
495     lowPriority_notImplemented();
496 }
497 
dispatchUnableToImplementPolicy(const ResourceError &)498 void FrameLoaderClientAndroid::dispatchUnableToImplementPolicy(const ResourceError&) {
499     notImplemented();
500 }
501 
dispatchDecidePolicyForNavigationAction(FramePolicyFunction func,const NavigationAction & action,const ResourceRequest & request,PassRefPtr<FormState> formState)502 void FrameLoaderClientAndroid::dispatchDecidePolicyForNavigationAction(FramePolicyFunction func,
503                                 const NavigationAction& action, const ResourceRequest& request,
504                                 PassRefPtr<FormState> formState) {
505     ASSERT(m_frame);
506     ASSERT(func);
507     if (!func)
508         return;
509     if (request.isNull()) {
510         (m_frame->loader()->*func)(PolicyIgnore);
511         return;
512     }
513 
514     // Reset multiple form submission protection. If this is a resubmission, we check with the
515     // user and reset the protection if they choose to resubmit the form (see WebCoreFrameBridge.cpp)
516     if (action.type() == NavigationTypeFormSubmitted)
517         m_frame->loader()->resetMultipleFormSubmissionProtection();
518 
519     if (action.type() == NavigationTypeFormResubmitted) {
520         m_webFrame->decidePolicyForFormResubmission(func);
521         return;
522     } else {
523         (m_frame->loader()->*func)(PolicyUse);
524     }
525 }
526 
dispatchWillSubmitForm(FramePolicyFunction func,PassRefPtr<FormState>)527 void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, PassRefPtr<FormState>) {
528     ASSERT(m_frame);
529     ASSERT(func);
530     (m_frame->loader()->*func)(PolicyUse);
531 }
532 
dispatchDidLoadMainResource(DocumentLoader *)533 void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) {
534     notImplemented();
535 }
536 
revertToProvisionalState(DocumentLoader *)537 void FrameLoaderClientAndroid::revertToProvisionalState(DocumentLoader*) {
538     notImplemented();
539 }
540 
setMainDocumentError(DocumentLoader * docLoader,const ResourceError & error)541 void FrameLoaderClientAndroid::setMainDocumentError(DocumentLoader* docLoader, const ResourceError& error) {
542     ASSERT(m_frame);
543     if (!error.isNull() && error.errorCode() >= InternalErrorLast)
544         m_webFrame->reportError(error.errorCode(),
545                 error.localizedDescription(), error.failingURL());
546 }
547 
548 // This function is called right before the progress is updated.
willChangeEstimatedProgress()549 void FrameLoaderClientAndroid::willChangeEstimatedProgress() {
550     verifiedOk();
551 }
552 
553 // This function is called after the progress has been updated. The bad part
554 // about this is that when a page is completed, this function is called after
555 // the progress has been reset to 0.
didChangeEstimatedProgress()556 void FrameLoaderClientAndroid::didChangeEstimatedProgress() {
557     verifiedOk();
558 }
559 
560 // This will give us the initial estimate when the page first starts to load.
postProgressStartedNotification()561 void FrameLoaderClientAndroid::postProgressStartedNotification() {
562     ASSERT(m_frame);
563     if (m_frame->page())
564         m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress());
565 }
566 
567 // This will give us any updated progress including the final progress.
postProgressEstimateChangedNotification()568 void FrameLoaderClientAndroid::postProgressEstimateChangedNotification() {
569     ASSERT(m_frame);
570     if (m_frame->page())
571         m_webFrame->setProgress(m_frame->page()->progress()->estimatedProgress());
572 }
573 
574 // This is just a notification that the progress has finished. Don't call
575 // setProgress(1) because postProgressEstimateChangedNotification will do so.
postProgressFinishedNotification()576 void FrameLoaderClientAndroid::postProgressFinishedNotification() {
577     WebViewCore* core =  WebViewCore::getWebViewCore(m_frame->view());
578     if (!m_frame->tree()->parent()) {
579         // only need to notify Java for the top frame
580         core->notifyProgressFinished();
581     }
582     // notify plugins that the frame has loaded
583     core->notifyPluginsOnFrameLoad(m_frame);
584 }
585 
setMainFrameDocumentReady(bool)586 void FrameLoaderClientAndroid::setMainFrameDocumentReady(bool) {
587     // this is only interesting once we provide an external API for the DOM
588     notImplemented();
589 }
590 
startDownload(const ResourceRequest &)591 void FrameLoaderClientAndroid::startDownload(const ResourceRequest&) {
592     notImplemented();
593 }
594 
willChangeTitle(DocumentLoader *)595 void FrameLoaderClientAndroid::willChangeTitle(DocumentLoader*) {
596     verifiedOk();
597 }
598 
didChangeTitle(DocumentLoader * loader)599 void FrameLoaderClientAndroid::didChangeTitle(DocumentLoader* loader) {
600     verifiedOk();
601 }
602 
finishedLoading(DocumentLoader * docLoader)603 void FrameLoaderClientAndroid::finishedLoading(DocumentLoader* docLoader) {
604     // Telling the frame we received some data and passing 0 as the data is our
605     // way to get work done that is normally done when the first bit of data is
606     // received, even for the case of a document with no data (like about:blank)
607     committedLoad(docLoader, 0, 0);
608 }
609 
updateGlobalHistory()610 void FrameLoaderClientAndroid::updateGlobalHistory() {
611     ASSERT(m_frame);
612 
613     DocumentLoader* docLoader = m_frame->loader()->documentLoader();
614     ASSERT(docLoader);
615 
616     // Code copied from FrameLoader.cpp:createHistoryItem
617     // Only add this URL to the database if it is a valid page
618     if (docLoader->unreachableURL().isEmpty()
619             && docLoader->response().httpStatusCode() < 400) {
620         m_webFrame->updateVisitedHistory(docLoader->urlForHistory(), false);
621         if (!docLoader->serverRedirectSourceForHistory().isNull())
622             m_webFrame->updateVisitedHistory(KURL(docLoader->serverRedirectDestinationForHistory()), false);
623     }
624 }
625 
updateGlobalHistoryRedirectLinks()626 void FrameLoaderClientAndroid::updateGlobalHistoryRedirectLinks() {
627     // Note, do we need to do anything where there is no HistoryItem? If we call
628     // updateGlobalHistory(), we will add bunch of "data:xxx" urls for gmail.com
629     // which is not what we want. Opt to do nothing now.
630 }
631 
shouldGoToHistoryItem(HistoryItem * item) const632 bool FrameLoaderClientAndroid::shouldGoToHistoryItem(HistoryItem* item) const {
633     // hmmm, seems like we might do a more thoughtful check
634     ASSERT(m_frame);
635     return item != NULL;
636 }
637 
committedLoad(DocumentLoader * loader,const char * data,int length)638 void FrameLoaderClientAndroid::committedLoad(DocumentLoader* loader, const char* data, int length) {
639     ASSERT(m_frame);
640     String encoding = loader->overrideEncoding();
641     bool userChosen = !encoding.isNull();
642     if (encoding.isNull())
643         encoding = loader->response().textEncodingName();
644     loader->frameLoader()->setEncoding(encoding, userChosen);
645     Document *doc = m_frame->document();
646     if (doc) {
647         loader->frameLoader()->addData(data, length);
648     }
649 }
650 
cancelledError(const ResourceRequest & request)651 ResourceError FrameLoaderClientAndroid::cancelledError(const ResourceRequest& request) {
652     return ResourceError(String(), InternalErrorCancelled, request.url(), String());
653 }
654 
cannotShowURLError(const ResourceRequest & request)655 ResourceError FrameLoaderClientAndroid::cannotShowURLError(const ResourceRequest& request) {
656     return ResourceError(String(), InternalErrorCannotShowUrl, request.url(), String());
657 }
658 
interruptForPolicyChangeError(const ResourceRequest & request)659 ResourceError FrameLoaderClientAndroid::interruptForPolicyChangeError(const ResourceRequest& request) {
660     return ResourceError(String(), InternalErrorInterrupted, request.url(), String());
661 }
662 
cannotShowMIMETypeError(const ResourceResponse & request)663 ResourceError FrameLoaderClientAndroid::cannotShowMIMETypeError(const ResourceResponse& request) {
664     return ResourceError(String(), InternalErrorCannotShowMimeType, request.url(), String());
665 }
666 
fileDoesNotExistError(const ResourceResponse & request)667 ResourceError FrameLoaderClientAndroid::fileDoesNotExistError(const ResourceResponse& request) {
668     return ResourceError(String(), InternalErrorFileDoesNotExist, request.url(), String());
669 }
670 
pluginWillHandleLoadError(const ResourceResponse & request)671 ResourceError FrameLoaderClientAndroid::pluginWillHandleLoadError(const ResourceResponse& request) {
672     return ResourceError(String(), InternalErrorPluginWillHandleLoadError, request.url(), String());
673 }
674 
shouldFallBack(const ResourceError &)675 bool FrameLoaderClientAndroid::shouldFallBack(const ResourceError&) {
676     notImplemented();
677     return false;
678 }
679 
canHandleRequest(const ResourceRequest & request) const680 bool FrameLoaderClientAndroid::canHandleRequest(const ResourceRequest& request) const {
681     ASSERT(m_frame);
682     // Don't allow hijacking of intrapage navigation
683     if (WebCore::equalIgnoringFragmentIdentifier(request.url(), m_frame->loader()->url()))
684         return true;
685 
686     // Don't allow hijacking of iframe urls that are http or https
687     if (request.url().protocol().startsWith("http", false) &&
688             m_frame->tree() && m_frame->tree()->parent())
689         return true;
690 
691     return m_webFrame->canHandleRequest(request);
692 }
693 
canShowMIMEType(const String & mimeType) const694 bool FrameLoaderClientAndroid::canShowMIMEType(const String& mimeType) const {
695     // FIXME: This looks like it has to do with whether or not a type can be
696     // shown "internally" (i.e. inside the browser) regardless of whether
697     // or not the browser is doing the rendering, e.g. a full page plugin.
698     if (MIMETypeRegistry::isSupportedImageResourceMIMEType(mimeType) ||
699             MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType) ||
700             MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) ||
701             PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType) ||
702             DOMImplementation::isTextMIMEType(mimeType) ||
703             DOMImplementation::isXMLMIMEType(mimeType))
704         return true;
705     return false;
706 }
707 
representationExistsForURLScheme(const String &) const708 bool FrameLoaderClientAndroid::representationExistsForURLScheme(const String&) const {
709     // don't use representation
710     verifiedOk();
711     return false;
712 }
713 
generatedMIMETypeForURLScheme(const String & URLScheme) const714 String FrameLoaderClientAndroid::generatedMIMETypeForURLScheme(const String& URLScheme) const {
715     // FIXME, copy from Apple's port
716     String mimetype("x-apple-web-kit/");
717     mimetype.append(URLScheme.lower());
718     return mimetype;
719 }
720 
frameLoadCompleted()721 void FrameLoaderClientAndroid::frameLoadCompleted() {
722     // copied from Apple port, without this back with sub-frame will trigger ASSERT
723     ASSERT(m_frame);
724 }
725 
saveViewStateToItem(HistoryItem * item)726 void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) {
727 #ifdef ANDROID_HISTORY_CLIENT
728     ASSERT(m_frame);
729     ASSERT(item);
730     // We should have added a bridge when the child item was added to its
731     // parent.
732     WebHistoryItem* bridge = item->bridge();
733     ASSERT(bridge);
734     // store the current scale (only) for the top frame
735     if (!m_frame->tree()->parent()) {
736         WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
737         bridge->setScale((int)(webViewCore->scale() * 100));
738         bridge->setScreenWidthScale((int)(webViewCore->screenWidthScale() * 100));
739     }
740 
741     WebCore::notifyHistoryItemChanged(item);
742 #endif
743 }
744 
restoreViewState()745 void FrameLoaderClientAndroid::restoreViewState() {
746 #ifdef ANDROID_HISTORY_CLIENT
747     WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view());
748     HistoryItem* item = m_frame->loader()->currentHistoryItem();
749     // restore the scale (only) for the top frame
750     if (!m_frame->tree()->parent()) {
751         int scale = item->bridge()->scale();
752         webViewCore->restoreScale(scale);
753         int screenWidthScale = item->bridge()->screenWidthScale();
754         if (screenWidthScale != scale)
755             webViewCore->restoreScreenWidthScale(screenWidthScale);
756     }
757 #endif
758 }
759 
760 #ifdef ANDROID_HISTORY_CLIENT
dispatchDidAddHistoryItem(HistoryItem * item) const761 void FrameLoaderClientAndroid::dispatchDidAddHistoryItem(HistoryItem* item) const {
762     ASSERT(m_frame);
763     m_webFrame->addHistoryItem(item);
764 }
765 
dispatchDidRemoveHistoryItem(HistoryItem * item,int index) const766 void FrameLoaderClientAndroid::dispatchDidRemoveHistoryItem(HistoryItem* item, int index) const {
767     ASSERT(m_frame);
768     m_webFrame->removeHistoryItem(index);
769 }
770 
dispatchDidChangeHistoryIndex(BackForwardList * list) const771 void FrameLoaderClientAndroid::dispatchDidChangeHistoryIndex(
772         BackForwardList* list) const {
773     ASSERT(m_frame);
774     m_webFrame->updateHistoryIndex(list->backListCount());
775 }
776 #endif
777 
provisionalLoadStarted()778 void FrameLoaderClientAndroid::provisionalLoadStarted() {
779     ASSERT(m_frame);
780     m_webFrame->loadStarted(m_frame);
781 }
782 
didFinishLoad()783 void FrameLoaderClientAndroid::didFinishLoad() {
784     ASSERT(m_frame);
785     m_frame->document()->setExtraLayoutDelay(0);
786     m_webFrame->didFinishLoad(m_frame);
787 }
788 
prepareForDataSourceReplacement()789 void FrameLoaderClientAndroid::prepareForDataSourceReplacement() {
790     verifiedOk();
791 }
792 
createDocumentLoader(const ResourceRequest & request,const SubstituteData & data)793 PassRefPtr<DocumentLoader> FrameLoaderClientAndroid::createDocumentLoader(
794                     const ResourceRequest& request, const SubstituteData& data) {
795     RefPtr<DocumentLoader> loader = DocumentLoader::create(request, data);
796     return loader.release();
797 }
798 
setTitle(const String & title,const KURL & url)799 void FrameLoaderClientAndroid::setTitle(const String& title, const KURL& url) {
800     // Not needed. dispatchDidReceiveTitle is called immediately after this.
801     // url is used to update the Apple port history items.
802     verifiedOk();
803 }
804 
userAgent(const KURL & u)805 String FrameLoaderClientAndroid::userAgent(const KURL& u) {
806     return m_webFrame->userAgentForURL(&u);
807 }
808 
savePlatformDataToCachedFrame(WebCore::CachedFrame *)809 void FrameLoaderClientAndroid::savePlatformDataToCachedFrame(WebCore::CachedFrame*) {
810     notImplemented();
811 }
812 
transitionToCommittedFromCachedFrame(WebCore::CachedFrame *)813 void FrameLoaderClientAndroid::transitionToCommittedFromCachedFrame(WebCore::CachedFrame*) {
814     notImplemented();
815 }
816 
transitionToCommittedForNewPage()817 void FrameLoaderClientAndroid::transitionToCommittedForNewPage() {
818     ASSERT(m_frame);
819 
820 #ifdef ANDROID_META_SUPPORT
821     // reset metadata settings for the main frame as they are not preserved cross page
822     if (m_frame == m_frame->page()->mainFrame() && m_frame->settings())
823         m_frame->settings()->resetMetadataSettings();
824 #endif
825 
826     if (m_frame->settings() && !m_frame->settings()->usesPageCache()) {
827         m_webFrame->transitionToCommitted(m_frame);
828         return;
829     }
830 
831     // Remember the old WebFrameView
832     WebFrameView* webFrameView = static_cast<WebFrameView*> (
833             m_frame->view()->platformWidget());
834     Retain(webFrameView);
835 
836     // Remove the old FrameView
837     m_frame->setView(NULL);
838 
839     // Create a new FrameView and associate it with the saved webFrameView
840     RefPtr<FrameView> view = FrameView::create(m_frame);
841     webFrameView->setView(view.get());
842 
843     Release(webFrameView);
844 
845     // Give the new FrameView to the Frame
846     m_frame->setView(view);
847 
848     if (m_frame->ownerRenderer())
849         m_frame->ownerRenderer()->setWidget(view.get());
850 
851     m_frame->view()->initScrollbars();
852 
853     m_webFrame->transitionToCommitted(m_frame);
854 }
855 
canCachePage() const856 bool FrameLoaderClientAndroid::canCachePage() const {
857     return true;
858 }
859 
download(ResourceHandle * handle,const ResourceRequest &,const ResourceRequest &,const ResourceResponse &)860 void FrameLoaderClientAndroid::download(ResourceHandle* handle, const ResourceRequest&,
861                                 const ResourceRequest&, const ResourceResponse&) {
862     // Get the C++ side of the load listener and tell it to handle the download
863     WebCoreResourceLoader* loader = handle->getInternal()->m_loader;
864     loader->downloadFile();
865 }
866 
createFrame(const KURL & url,const String & name,HTMLFrameOwnerElement * ownerElement,const String & referrer,bool allowsScrolling,int marginWidth,int marginHeight)867 WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL& url, const String& name,
868                         HTMLFrameOwnerElement* ownerElement, const String& referrer,
869                         bool allowsScrolling, int marginWidth, int marginHeight)
870 {
871     Frame* parent = ownerElement->document()->frame();
872     FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid(m_webFrame);
873     RefPtr<Frame> pFrame = Frame::create(parent->page(), ownerElement, loaderC);
874     Frame* newFrame = pFrame.get();
875     loaderC->setFrame(newFrame);
876     // Append the subframe to the parent and set the name of the subframe. The name must be set after
877     // appending the child so that the name becomes unique.
878     parent->tree()->appendChild(newFrame);
879     newFrame->tree()->setName(name);
880     // Create a new FrameView and WebFrameView for the child frame to draw into.
881     RefPtr<FrameView> frameView = FrameView::create(newFrame);
882     WebFrameView* webFrameView = new WebFrameView(frameView.get(),
883             WebViewCore::getWebViewCore(parent->view()));
884     // frameView Retains webFrameView, so call Release for webFrameView
885     Release(webFrameView);
886     // Attach the frameView to the newFrame.
887     newFrame->setView(frameView);
888     newFrame->init();
889     newFrame->selection()->setFocused(true);
890     LOGV("::WebCore:: createSubFrame returning %p", newFrame);
891 
892     // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
893     if (!pFrame->page())
894         return 0;
895 
896     parent->loader()->loadURLIntoChildFrame(url, referrer, pFrame.get());
897 
898     // onLoad may cuase the frame to be removed from the document. Allow the RefPtr to delete the child frame.
899     if (!pFrame->tree()->parent())
900         return NULL;
901 
902     return pFrame.release();
903 }
904 
905 // YouTube flash url path starts with /v/
906 static const char slash_v_slash[] = { '/', 'v', '/' };
907 
isValidYouTubeVideo(const String & path)908 static bool isValidYouTubeVideo(const String& path)
909 {
910     if (!charactersAreAllASCII(path.characters(), path.length()))
911         return false;
912     unsigned int len = path.length();
913     if (len <= sizeof(slash_v_slash)) // check for more than just /v/
914         return false;
915     CString str = path.lower().utf8();
916     const char* data = str.data();
917     if (memcmp(data, slash_v_slash, sizeof(slash_v_slash)) != 0)
918         return false;
919     // Start after /v/
920     for (unsigned int i = sizeof(slash_v_slash); i < len; i++) {
921         char c = data[i];
922         // Check for alpha-numeric characters only.
923         if (WTF::isASCIIAlphanumeric(c) || c == '_' || c == '-')
924             continue;
925         // The url can have more parameters such as &hl=en after the video id.
926         // Once we start seeing extra parameters we can return true.
927         return c == '&' && i > sizeof(slash_v_slash);
928     }
929     return true;
930 }
931 
isYouTubeUrl(const KURL & url,const String & mimeType)932 static bool isYouTubeUrl(const KURL& url, const String& mimeType)
933 {
934     String host = url.host();
935     bool youtube = host.endsWith("youtube.com")
936             || host.endsWith("youtube-nocookie.com");
937     return youtube && isValidYouTubeVideo(url.path())
938             && equalIgnoringCase(mimeType, "application/x-shockwave-flash");
939 }
940 
createPlugin(const IntSize & size,HTMLPlugInElement * element,const KURL & url,const WTF::Vector<String> & names,const WTF::Vector<String> & values,const String & mimeType,bool loadManually)941 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createPlugin(
942         const IntSize& size,
943         HTMLPlugInElement* element,
944         const KURL& url,
945         const WTF::Vector<String>& names,
946         const WTF::Vector<String>& values,
947         const String& mimeType,
948         bool loadManually) {
949     // Create an iframe for youtube urls.
950     if (isYouTubeUrl(url, mimeType)) {
951         WTF::RefPtr<Frame> frame = createFrame(blankURL(), String(), element,
952                 String(), false, 0, 0);
953         if (frame) {
954             // grab everything after /v/
955             String videoId = url.path().substring(sizeof(slash_v_slash));
956             // Extract just the video id
957             unsigned videoIdEnd = 0;
958             for (; videoIdEnd < videoId.length(); videoIdEnd++) {
959                 if (videoId[videoIdEnd] == '&') {
960                     videoId = videoId.left(videoIdEnd);
961                     break;
962                 }
963             }
964             AssetManager* am = globalAssetManager();
965             Asset* a = am->open("webkit/youtube.html",
966                     Asset::ACCESS_BUFFER);
967             if (!a)
968                 return NULL;
969             String s = String((const char*)a->getBuffer(false), a->getLength());
970             s = s.replace("VIDEO_ID", videoId);
971             delete a;
972             loadDataIntoFrame(frame.get(),
973                     KURL("file:///android_asset/webkit/"), String(), s);
974             // Transfer ownership to a local refptr.
975             WTF::RefPtr<Widget> widget(frame->view());
976             return widget.release();
977         }
978         return NULL;
979     }
980 #ifdef ANDROID_PLUGINS
981     return PluginView::create(m_frame,
982                               size,
983                               element,
984                               url,
985                               names,
986                               values,
987                               mimeType,
988                               loadManually);
989 #else
990     return NULL;
991 #endif
992 }
993 
redirectDataToPlugin(Widget * pluginWidget)994 void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) {
995     // don't support plugin yet
996     notImplemented();
997 }
998 
createJavaAppletWidget(const IntSize &,HTMLAppletElement *,const KURL & baseURL,const WTF::Vector<String> & paramNames,const WTF::Vector<String> & paramValues)999 WTF::PassRefPtr<Widget> FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, HTMLAppletElement*,
1000                                         const KURL& baseURL, const WTF::Vector<String>& paramNames,
1001                                         const WTF::Vector<String>& paramValues) {
1002     // don't support widget yet
1003     notImplemented();
1004     return 0;
1005 }
1006 
1007 // This function is used by the <OBJECT> element to determine the type of
1008 // the contents and work out if it can render it.
objectContentType(const KURL & url,const String & mimeType)1009 ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url,
1010                                         const String& mimeType) {
1011     if (mimeType.length() == 0)
1012     {
1013         // Guess the mimeType from the extension
1014         if (url.hasPath())
1015         {
1016             String path = url.path();
1017             int lastIndex = path.reverseFind('.');
1018             static const String image("image/");
1019             if (lastIndex >= 0)
1020             {
1021                 String mime(path.substring(lastIndex + 1));
1022                 mime.insert(image, 0);
1023                 if (Image::supportsType(mime))
1024                     return ObjectContentImage;
1025             }
1026         }
1027         return ObjectContentFrame;
1028     }
1029 
1030     if (Image::supportsType(mimeType))
1031         return ObjectContentImage;
1032 
1033     if (PluginDatabase::installedPlugins()->isMIMETypeRegistered(mimeType))
1034         return ObjectContentOtherPlugin;
1035 
1036     if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType))
1037         return ObjectContentFrame;
1038 
1039     return ObjectContentNone;
1040 }
1041 
1042 // This function allows the application to set the correct CSS media
1043 // style. Android could use it to set the media style 'handheld'. Safari
1044 // may use it to set the media style to 'print' when the user wants to print
1045 // a particular web page.
overrideMediaType() const1046 String FrameLoaderClientAndroid::overrideMediaType() const {
1047     lowPriority_notImplemented();
1048     return String();
1049 }
1050 
1051 // This function is used to re-attach Javascript<->native code classes.
windowObjectCleared()1052 void FrameLoaderClientAndroid::windowObjectCleared() {
1053     ASSERT(m_frame);
1054     LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n",
1055     		m_frame, m_frame->loader()->url().string().ascii().data());
1056     m_webFrame->windowObjectCleared(m_frame);
1057 }
1058 
documentElementAvailable()1059 void FrameLoaderClientAndroid::documentElementAvailable() {
1060 }
1061 
1062 // functions new to Jun-07 tip of tree merge:
blockedError(ResourceRequest const & request)1063 ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) {
1064     return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String());
1065 }
1066 
1067 // functions new to Nov-07 tip of tree merge:
didPerformFirstNavigation() const1068 void FrameLoaderClientAndroid::didPerformFirstNavigation() const {
1069     // This seems to be just a notification that the UI can listen to, to
1070     // know if the user has performed first navigation action.
1071     // It is called from
1072     // void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
1073     // "Navigation" here means a transition from one page to another that
1074     // ends up in the back/forward list.
1075 }
1076 
registerForIconNotification(bool listen)1077 void FrameLoaderClientAndroid::registerForIconNotification(bool listen) {
1078     if (listen)
1079         WebIconDatabase::RegisterForIconNotification(this);
1080     else
1081         WebIconDatabase::UnregisterForIconNotification(this);
1082 }
1083 
1084 // This is the WebIconDatabaseClient method for receiving a notification when we
1085 // get the icon for the page.
didAddIconForPageUrl(const String & pageUrl)1086 void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) {
1087     // This call must happen before dispatchDidReceiveIcon since that method
1088     // may register for icon notifications again since the icon data may have
1089     // to be read from disk.
1090     registerForIconNotification(false);
1091     KURL u(pageUrl);
1092     if (equalIgnoringFragmentIdentifier(u, m_frame->loader()->url())) {
1093         dispatchDidReceiveIcon();
1094     }
1095 }
1096 
1097 }
1098