7ab1e71b7ef134109d38022bffde1fd6a9e7c217
[WebKit-https.git] / Source / WebKit / blackberry / WebCoreSupport / FrameLoaderClientBlackBerry.cpp
1 /*
2  * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20 #include "FrameLoaderClientBlackBerry.h"
21
22 #include "BackForwardController.h"
23 #include "BackForwardListImpl.h"
24 #include "BackingStoreClient.h"
25 #include "BackingStore_p.h"
26 #include "Base64.h"
27 #include "CachedImage.h"
28 #include "Chrome.h"
29 #include "ChromeClientBlackBerry.h"
30 #include "ClientExtension.h"
31 #include "CookieManager.h"
32 #include "DumpRenderTreeClient.h"
33 #include "FrameNetworkingContextBlackBerry.h"
34 #include "FrameView.h"
35 #include "HTMLFormElement.h"
36 #include "HTMLHeadElement.h"
37 #include "HTMLImageElement.h"
38 #include "HTMLLinkElement.h"
39 #include "HTMLMediaElement.h"
40 #include "HTMLMetaElement.h"
41 #include "HTMLNames.h"
42 #include "HTMLPlugInElement.h"
43 #include "HTTPParsers.h"
44 #include "HistoryItem.h"
45 #include "IconDatabase.h"
46 #include "Image.h"
47 #include "InputHandler.h"
48 #include "MIMETypeRegistry.h"
49 #include "NativeImageSkia.h"
50 #include "NetworkManager.h"
51 #include "NodeList.h"
52 #include "Page.h"
53 #include "PluginView.h"
54 #include "ProgressTracker.h"
55 #include "ScopePointer.h"
56 #include "SharedBuffer.h"
57 #include "TextEncoding.h"
58 #include "TouchEventHandler.h"
59 #if ENABLE(WEBDOM)
60 #include "WebDOMDocument.h"
61 #endif
62 #include "WebPageClient.h"
63
64 #include <BlackBerryPlatformLog.h>
65 #include <BlackBerryPlatformScreen.h>
66 #include <JavaScriptCore/APICast.h>
67 #include <network/FilterStream.h>
68 #include <network/NetworkRequest.h>
69
70 using WTF::String;
71 using namespace WebCore;
72 using namespace BlackBerry::WebKit;
73
74 // This was copied from file "WebKit/Source/WebKit/mac/Misc/WebKitErrors.h".
75 enum {
76     WebKitErrorCannotShowMIMEType =                             100,
77     WebKitErrorCannotShowURL =                                  101,
78     WebKitErrorFrameLoadInterruptedByPolicyChange =             102,
79     WebKitErrorCannotUseRestrictedPort =                        103,
80     WebKitErrorCannotFindPlugIn =                               200,
81     WebKitErrorCannotLoadPlugIn =                               201,
82     WebKitErrorJavaUnavailable =                                202,
83     WebKitErrorPluginWillHandleLoad =                           203
84 };
85
86 namespace WebCore {
87
88 FrameLoaderClientBlackBerry::FrameLoaderClientBlackBerry()
89     : m_frame(0)
90     , m_webPagePrivate(0)
91     , m_sentReadyToRender(false)
92     , m_pendingFragmentScrollPolicyFunction(0)
93     , m_loadingErrorPage(false)
94     , m_clientRedirectIsPending(false)
95     , m_childFrameCreationSuppressed(false)
96     , m_pluginView(0)
97     , m_hasSentResponseToPlugin(false)
98     , m_cancelLoadOnNextData(false)
99 {
100     m_deferredJobsTimer = new Timer<FrameLoaderClientBlackBerry>(this, &FrameLoaderClientBlackBerry::deferredJobsTimerFired);
101 }
102
103 FrameLoaderClientBlackBerry::~FrameLoaderClientBlackBerry()
104 {
105     delete m_deferredJobsTimer;
106     m_deferredJobsTimer = 0;
107 }
108
109 int FrameLoaderClientBlackBerry::playerId() const
110 {
111     if (m_webPagePrivate && m_webPagePrivate->m_client)
112         return m_webPagePrivate->m_client->getInstanceId();
113     return 0;
114 }
115
116 bool FrameLoaderClientBlackBerry::cookiesEnabled() const
117 {
118     return m_webPagePrivate->m_webSettings->areCookiesEnabled();
119 }
120
121 void FrameLoaderClientBlackBerry::dispatchDidAddBackForwardItem(HistoryItem* item) const
122 {
123     // Inform the client that the back/forward list has changed.
124     invalidateBackForwardList();
125 }
126
127 void FrameLoaderClientBlackBerry::dispatchDidRemoveBackForwardItem(HistoryItem* item) const
128 {
129     invalidateBackForwardList();
130 }
131
132 void FrameLoaderClientBlackBerry::dispatchDidChangeBackForwardIndex() const
133 {
134     invalidateBackForwardList();
135 }
136
137 void FrameLoaderClientBlackBerry::dispatchDidChangeLocationWithinPage()
138 {
139     if (!isMainFrame())
140         return;
141
142     String url = m_frame->document()->url().string();
143     String token = m_frame->loader()->documentLoader()->request().token();
144
145     m_webPagePrivate->m_client->notifyLoadToAnchor(url.characters(), url.length(), token.characters(), token.length());
146 }
147
148 void FrameLoaderClientBlackBerry::dispatchDidPushStateWithinPage()
149 {
150     // FIXME: As a workaround we abuse anchor navigation to achieve history push. See PR #119779 for more details.
151     dispatchDidChangeLocationWithinPage();
152 }
153
154 void FrameLoaderClientBlackBerry::dispatchDidReplaceStateWithinPage()
155 {
156     // FIXME: As a workaround we abuse anchor navigation to achieve history replace. See PR #119779 for more details.
157     dispatchDidChangeLocationWithinPage();
158 }
159
160 void FrameLoaderClientBlackBerry::dispatchDidPopStateWithinPage()
161 {
162     // Not needed.
163 }
164
165 void FrameLoaderClientBlackBerry::dispatchDidCancelClientRedirect()
166 {
167     m_clientRedirectIsPending = false;
168 }
169
170 void FrameLoaderClientBlackBerry::dispatchWillPerformClientRedirect(const KURL&, double, double)
171 {
172     if (m_webPagePrivate->m_dumpRenderTree)
173         m_webPagePrivate->m_dumpRenderTree->didDispatchWillPerformClientRedirect();
174
175     m_clientRedirectIsPending = true;
176 }
177
178 void FrameLoaderClientBlackBerry::dispatchDecidePolicyForResponse(FramePolicyFunction function, const ResourceResponse& response, const ResourceRequest& request)
179 {
180     // FIXME: What should we do for HTTP status code 204 and 205 and "application/zip"?
181     PolicyAction policy = PolicyIgnore;
182
183     if (contentDispositionType(response.httpHeaderField("Content-Disposition")) == ContentDispositionAttachment
184         || request.forceDownload())
185         policy = PolicyDownload;
186     else if (canShowMIMEType(response.mimeType()))
187         policy = PolicyUse;
188     else if ((ResourceRequest::TargetIsMainFrame == request.targetType())
189              && m_webPagePrivate->m_client->downloadAllowed(request.url().string().utf8().data()))
190         policy = PolicyDownload;
191
192     (m_frame->loader()->policyChecker()->*function)(policy);
193 }
194
195 void FrameLoaderClientBlackBerry::dispatchDecidePolicyForNavigationAction(FramePolicyFunction function, const NavigationAction& action, const ResourceRequest& request, PassRefPtr<FormState>)
196 {
197     PolicyAction decision = PolicyUse;
198
199     const KURL& url = request.url();
200
201     // Fragment scrolls on the same page should always be handled internally.
202     // (Only count as a fragment scroll if we are scrolling to a #fragment url, not back to the top, and reloading
203     // the same url is not a fragment scroll even if it has a #fragment.)
204     const KURL& currentUrl = m_frame->document()->url();
205     bool isFragmentScroll = url.hasFragmentIdentifier() && url != currentUrl && equalIgnoringFragmentIdentifier(currentUrl, url);
206     if (decision == PolicyUse)
207         decision = decidePolicyForExternalLoad(request, isFragmentScroll);
208
209     // Let the client have a chance to say whether this navigation should
210     // be ignored or not.
211     BlackBerry::Platform::NetworkRequest platformRequest;
212     request.initializePlatformRequest(platformRequest, false /*isInitial*/);
213     if (isMainFrame() && !m_webPagePrivate->m_client->acceptNavigationRequest(
214         platformRequest, BlackBerry::Platform::NavigationType(action.type()))) {
215         if (action.type() == NavigationTypeFormSubmitted
216             || action.type() == NavigationTypeFormResubmitted)
217             m_frame->loader()->resetMultipleFormSubmissionProtection();
218
219         if (action.type() == NavigationTypeLinkClicked && url.hasFragmentIdentifier()) {
220             ResourceRequest emptyRequest;
221             m_frame->loader()->activeDocumentLoader()->setLastCheckedRequest(emptyRequest);
222         }
223         decision = PolicyIgnore;
224     }
225
226     // If we abort here, dispatchDidCancelClientRedirect will not be called.
227     // So call it by hand.
228     if (decision == PolicyIgnore)
229         dispatchDidCancelClientRedirect();
230
231     (m_frame->loader()->policyChecker()->*function)(decision);
232
233     if (m_webPagePrivate->m_dumpRenderTree)
234         m_webPagePrivate->m_dumpRenderTree->didDecidePolicyForNavigationAction(action, request);
235 }
236
237 void FrameLoaderClientBlackBerry::delayPolicyCheckUntilFragmentExists(const String& fragment, FramePolicyFunction function)
238 {
239     ASSERT(isMainFrame());
240
241     if (m_webPagePrivate->loadState() < WebPagePrivate::Finished && !m_frame->document()->findAnchor(fragment)) {
242         // Tell the client we need more data, in case the fragment exists but is being held back.
243         m_webPagePrivate->m_client->needMoreData();
244         m_pendingFragmentScrollPolicyFunction = function;
245         m_pendingFragmentScroll = fragment;
246         return;
247     }
248
249     (m_frame->loader()->policyChecker()->*function)(PolicyUse);
250 }
251
252 void FrameLoaderClientBlackBerry::cancelPolicyCheck()
253 {
254     m_pendingFragmentScrollPolicyFunction = 0;
255     m_pendingFragmentScroll = String();
256 }
257
258 void FrameLoaderClientBlackBerry::doPendingFragmentScroll()
259 {
260     if (m_pendingFragmentScroll.isNull())
261         return;
262
263     // Make sure to clear the pending members first to avoid recursion.
264     String fragment = m_pendingFragmentScroll;
265     m_pendingFragmentScroll = String();
266
267     FramePolicyFunction function = m_pendingFragmentScrollPolicyFunction;
268     m_pendingFragmentScrollPolicyFunction = 0;
269
270     delayPolicyCheckUntilFragmentExists(fragment, function);
271 }
272
273 void FrameLoaderClientBlackBerry::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction function, const NavigationAction& action, const ResourceRequest& request, PassRefPtr<FormState>, const String& frameName)
274 {
275     if (request.isRequestedByPlugin() && ScriptController::processingUserGesture() && !m_webPagePrivate->m_pluginMayOpenNewTab)
276         (m_frame->loader()->policyChecker()->*function)(PolicyIgnore);
277
278     // A new window can never be a fragment scroll.
279     PolicyAction decision = decidePolicyForExternalLoad(request, false);
280     // Let the client have a chance to say whether this navigation should
281     // be ignored or not.
282     BlackBerry::Platform::NetworkRequest platformRequest;
283     request.initializePlatformRequest(platformRequest, false /*isInitial*/);
284     if (isMainFrame() && !m_webPagePrivate->m_client->acceptNavigationRequest(
285         platformRequest, BlackBerry::Platform::NavigationType(action.type()))) {
286         if (action.type() == NavigationTypeFormSubmitted || action.type() == NavigationTypeFormResubmitted)
287             m_frame->loader()->resetMultipleFormSubmissionProtection();
288
289         if (action.type() == NavigationTypeLinkClicked && request.url().hasFragmentIdentifier()) {
290             ResourceRequest emptyRequest;
291             m_frame->loader()->activeDocumentLoader()->setLastCheckedRequest(emptyRequest);
292         }
293         decision = PolicyIgnore;
294     }
295
296     (m_frame->loader()->policyChecker()->*function)(decision);
297 }
298
299 void FrameLoaderClientBlackBerry::committedLoad(DocumentLoader* loader, const char* data, int length)
300 {
301     // The structure of this code may seem...a bit odd. It's structured with two checks on the state
302     // of m_pluginView because it's actually receivedData that may cause the request to re-direct data
303     // to a PluginView. This is because receivedData may decide to create a PluginDocument containing
304     // a PluginView. The PluginView will request that the main resource for the frame be redirected
305     // to the PluginView. So after receivedData has been called, this code needs to check whether
306     // re-direction to a PluginView has been requested and pass the same data on to the PluginView.
307     // Thereafter, all data will be re-directed to the PluginView; i.e., no additional data will go
308     // to receivedData.
309
310     if (!m_pluginView) {
311         const String& textEncoding = loader->response().textEncodingName();
312         receivedData(data, length, textEncoding);
313     }
314
315     if (m_pluginView) {
316         if (!m_hasSentResponseToPlugin) {
317             m_pluginView->didReceiveResponse(loader->response());
318             m_hasSentResponseToPlugin = true;
319         }
320
321         if (!m_pluginView)
322             return;
323
324         m_pluginView->didReceiveData(data, length);
325     }
326 }
327
328 PassRefPtr<Widget> FrameLoaderClientBlackBerry::createPlugin(const IntSize& pluginSize,
329     HTMLPlugInElement* element, const KURL& url, const Vector<String>& paramNames,
330     const Vector<String>& paramValues, const String& mimeTypeIn, bool loadManually)
331 {
332     String mimeType(mimeTypeIn);
333     if (mimeType.isEmpty()) {
334         mimeType = MIMETypeRegistry::getMIMETypeForPath(url.path());
335         mimeType = WebSettings::getNormalizedMIMEType(mimeType);
336         if (mimeType != "application/x-shockwave-flash")
337             mimeType = mimeTypeIn;
338     }
339
340     if (mimeType == "application/x-shockwave-flash" || mimeType == "application/jnext-scriptable-plugin")
341         return PluginView::create(m_frame, pluginSize, element, url, paramNames, paramValues, mimeType, loadManually);
342
343     // If it's not the plugin type we support, try load directly from browser.
344     if (m_frame->loader() && m_frame->loader()->subframeLoader() && !url.isNull())
345         m_frame->loader()->subframeLoader()->requestFrame(element, url, String());
346
347     return 0;
348 }
349
350 void FrameLoaderClientBlackBerry::redirectDataToPlugin(Widget* pluginWidget)
351 {
352     ASSERT(!m_pluginView);
353     m_pluginView = static_cast<PluginView*>(pluginWidget);
354     m_hasSentResponseToPlugin = false;
355 }
356
357 void FrameLoaderClientBlackBerry::receivedData(const char* data, int length, const String& textEncoding)
358 {
359     if (!m_frame)
360         return;
361
362     if (m_cancelLoadOnNextData) {
363         m_frame->loader()->activeDocumentLoader()->stopLoading();
364         m_frame->loader()->documentLoader()->writer()->end();
365         m_cancelLoadOnNextData = false;
366         return;
367     }
368
369     // Set the encoding. This only needs to be done once, but it's harmless to do it again later.
370     String encoding = m_frame->loader()->documentLoader()->overrideEncoding();
371     bool userChosen = !encoding.isNull();
372     if (encoding.isNull())
373         encoding = textEncoding;
374     m_frame->loader()->documentLoader()->writer()->setEncoding(encoding, userChosen);
375     m_frame->loader()->documentLoader()->writer()->addData(data, length);
376 }
377
378 void FrameLoaderClientBlackBerry::finishedLoading(DocumentLoader* loader)
379 {
380     if (m_pluginView) {
381         m_pluginView->didFinishLoading();
382         m_pluginView = 0;
383         m_hasSentResponseToPlugin = false;
384     } else {
385         // Telling the frame we received some data and passing 0 as the data is our
386         // way to get work done that is normally done when the first bit of data is
387         // received, even for the case of a document with no data (like about:blank).
388         committedLoad(loader, 0, 0);
389     }
390 }
391
392 PassRefPtr<DocumentLoader> FrameLoaderClientBlackBerry::createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData)
393 {
394     // Make a copy of the request with the token from the original request for this frame
395     // (unless it already has a token, in which case the request came from the client).
396     ResourceRequest newRequest(request);
397     if (m_frame && m_frame->loader() && m_frame->loader()->documentLoader()) {
398         const ResourceRequest& originalRequest = m_frame->loader()->documentLoader()->originalRequest();
399         if (request.token().isNull() && !originalRequest.token().isNull())
400             newRequest.setToken(originalRequest.token());
401     }
402
403     // FIXME: This should probably be shared.
404     RefPtr<DocumentLoader> loader = DocumentLoader::create(newRequest, substituteData);
405     if (substituteData.isValid())
406         loader->setDeferMainResourceDataLoad(false);
407     return loader.release();
408 }
409
410 void FrameLoaderClientBlackBerry::frameLoaderDestroyed()
411 {
412     delete this;
413 }
414
415 void FrameLoaderClientBlackBerry::transitionToCommittedForNewPage()
416 {
417     m_cancelLoadOnNextData = false;
418
419     // In Frame::createView, Frame's FrameView object is set to 0 and recreated.
420     // This operation is not atomic, and an attempt to blit contents might happen
421     // in the backing store from another thread (see BackingStorePrivate::blitContents method),
422     // so we suspend and resume screen update to make sure we do not get a invalid FrameView
423     // state.
424     BackingStoreClient* backingStoreClientForFrame = m_webPagePrivate->backingStoreClientForFrame(m_frame);
425     if (backingStoreClientForFrame)
426         backingStoreClientForFrame->backingStore()->d->suspendScreenAndBackingStoreUpdates();
427
428     // We are navigating away from this document, so clean up any footprint we might have.
429     if (m_frame->document())
430         m_webPagePrivate->clearDocumentData(m_frame->document());
431
432     Color backgroundColor(m_webPagePrivate->m_webSettings->backgroundColor());
433
434     m_frame->createView(m_webPagePrivate->viewportSize(),      /* viewport */
435                         backgroundColor,                       /* background color */
436                         backgroundColor.hasAlpha(),            /* is transparent */
437                         m_webPagePrivate->actualVisibleSize(), /* fixed reported size */
438                         m_webPagePrivate->fixedLayoutSize(),   /* fixed layout size */
439                         m_webPagePrivate->useFixedLayout(),    /* use fixed layout */
440                         ScrollbarAlwaysOff,                    /* hor mode */
441                         true,                                  /* lock the mode */
442                         ScrollbarAlwaysOff,                    /* ver mode */
443                         true);                                 /* lock the mode */
444
445     if (backingStoreClientForFrame)
446         backingStoreClientForFrame->backingStore()->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
447     m_frame->view()->updateCanHaveScrollbars();
448
449     if (isMainFrame()) {
450         // Since the mainframe has a tiled backingstore request to receive all update
451         // rects instead of the default which just sends update rects for currently
452         // visible viewport.
453         m_frame->view()->setPaintsEntireContents(true);
454     }
455 }
456
457 String FrameLoaderClientBlackBerry::userAgent(const KURL&)
458 {
459     return m_webPagePrivate->m_webSettings->userAgentString();
460 }
461
462 bool FrameLoaderClientBlackBerry::canHandleRequest(const ResourceRequest&) const
463 {
464     // FIXME: Stub.
465     return true;
466 }
467
468 bool FrameLoaderClientBlackBerry::canShowMIMEType(const String& mimeTypeIn) const
469 {
470     // Get normalized type.
471     String mimeType = WebSettings::getNormalizedMIMEType(mimeTypeIn);
472
473     // FIXME: Seems no other port checks empty MIME type in this function. Should we do that?
474     return MIMETypeRegistry::isSupportedImageMIMEType(mimeType) || MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType)
475         || MIMETypeRegistry::isSupportedMediaMIMEType(mimeType) || WebSettings::isSupportedObjectMIMEType(mimeType)
476         || (mimeType == "application/x-shockwave-flash");
477 }
478
479 bool FrameLoaderClientBlackBerry::canShowMIMETypeAsHTML(const String&) const
480 {
481     // FIXME: Stub.
482     return true;
483 }
484
485 bool FrameLoaderClientBlackBerry::isMainFrame() const
486 {
487     return m_frame == m_webPagePrivate->m_mainFrame;
488 }
489
490 void FrameLoaderClientBlackBerry::dispatchDidStartProvisionalLoad()
491 {
492     if (isMainFrame())
493         m_webPagePrivate->setLoadState(WebPagePrivate::Provisional);
494
495     if (m_webPagePrivate->m_dumpRenderTree)
496         m_webPagePrivate->m_dumpRenderTree->didStartProvisionalLoadForFrame(m_frame);
497 }
498
499 void FrameLoaderClientBlackBerry::dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse& response)
500 {
501     if (m_webPagePrivate->m_dumpRenderTree)
502         m_webPagePrivate->m_dumpRenderTree->didReceiveResponseForFrame(m_frame, response);
503 }
504
505 void FrameLoaderClientBlackBerry::dispatchDidReceiveTitle(const StringWithDirection& title)
506 {
507     if (isMainFrame())
508         m_webPagePrivate->m_client->setPageTitle(title.string().characters(), title.string().length());
509
510     if (m_webPagePrivate->m_dumpRenderTree)
511         m_webPagePrivate->m_dumpRenderTree->didReceiveTitleForFrame(title.string(), m_frame);
512 }
513
514 void FrameLoaderClientBlackBerry::setTitle(const StringWithDirection& /*title*/, const KURL& /*url*/)
515 {
516     // Used by Apple WebKit to update the title of an existing history item.
517     // QtWebKit doesn't accomodate this on history items. If it ever does,
518     // it should be privateBrowsing-aware. For now, we are just passing
519     // globalhistory layout tests.
520     // FIXME: Use direction of title.
521     notImplemented();
522 }
523
524 void FrameLoaderClientBlackBerry::dispatchDidCommitLoad()
525 {
526     // FIXME: Do we need to find a replacement for m_frame->document()->setExtraLayoutDelay(250);?
527
528     if (isMainFrame()) {
529         m_webPagePrivate->setLoadState(WebPagePrivate::Committed);
530
531         String originalUrl = m_frame->loader()->documentLoader()->originalRequest().url().string();
532         String url = m_frame->loader()->documentLoader()->request().url().string();
533         String token = m_frame->loader()->documentLoader()->request().token();
534
535         // Notify the client that the load succeeded or failed (if it failed, this
536         // is actually committing the error page, which was set through
537         // SubstituteData in dispatchDidFailProvisionalLoad).
538         if (m_loadingErrorPage) {
539             m_loadingErrorPage = false;
540             m_webPagePrivate->m_client->notifyLoadFailedBeforeCommit(
541                 originalUrl.characters(), originalUrl.length(),
542                     url.characters(), url.length(), token.characters(), token.length());
543         } else {
544             m_webPagePrivate->m_client->notifyLoadCommitted(
545                 originalUrl.characters(), originalUrl.length(),
546                     url.characters(), url.length(), token.characters(), token.length());
547         }
548     }
549
550     if (m_webPagePrivate->m_dumpRenderTree)
551         m_webPagePrivate->m_dumpRenderTree->didCommitLoadForFrame(m_frame);
552 }
553
554 void FrameLoaderClientBlackBerry::dispatchDidHandleOnloadEvents()
555 {
556     m_webPagePrivate->m_client->notifyDocumentOnLoad();
557     if (m_webPagePrivate->m_dumpRenderTree)
558         m_webPagePrivate->m_dumpRenderTree->didHandleOnloadEventsForFrame(m_frame);
559 }
560
561 void FrameLoaderClientBlackBerry::dispatchDidFinishLoad()
562 {
563     didFinishOrFailLoading(ResourceError());
564
565     if (m_webPagePrivate->m_dumpRenderTree)
566         m_webPagePrivate->m_dumpRenderTree->didFinishLoadForFrame(m_frame);
567
568     if (!isMainFrame() || m_webPagePrivate->m_webSettings->isEmailMode()
569         || !m_frame->document() || !m_frame->document()->head())
570         return;
571
572     HTMLHeadElement* headElement = m_frame->document()->head();
573     // FIXME: Handle NOSCRIPT special case?
574
575     // Process document metadata.
576     RefPtr<NodeList> nodeList = headElement->getElementsByTagName(HTMLNames::metaTag.localName());
577     unsigned int size = nodeList->length();
578     ScopeArray<WebString> headers;
579
580     // This may allocate more space than needed since not all meta elements will be http-equiv.
581     headers.reset(new WebString[2 * size]);
582     unsigned headersLength = 0;
583
584     for (unsigned i = 0; i < size; ++i) {
585         HTMLMetaElement* metaElement = static_cast<HTMLMetaElement*>(nodeList->item(i));
586         if (WTF::equalIgnoringCase(metaElement->name(), "apple-mobile-web-app-capable")
587             && WTF::equalIgnoringCase(metaElement->content().stripWhiteSpace(), "yes"))
588             m_webPagePrivate->m_client->setWebAppCapable();
589         else {
590             String httpEquiv = metaElement->httpEquiv().stripWhiteSpace();
591             String content = metaElement->content().stripWhiteSpace();
592
593             if (!httpEquiv.isNull() && !content.isNull()) {
594                 headers[headersLength++] = httpEquiv;
595                 headers[headersLength++] = content;
596             }
597         }
598     }
599
600     if (headersLength > 0)
601         m_webPagePrivate->m_client->setMetaHeaders(headers, headersLength);
602
603     nodeList = headElement->getElementsByTagName(HTMLNames::linkTag.localName());
604     size = nodeList->length();
605
606     for (unsigned i = 0; i < size; ++i) {
607         HTMLLinkElement* linkElement = static_cast<HTMLLinkElement*>(nodeList->item(i));
608         String href = linkElement->href().string();
609         if (!href.isEmpty()) {
610             String title = linkElement->title();
611
612             if (WTF::equalIgnoringCase(linkElement->rel(), "apple-touch-icon"))
613                 m_webPagePrivate->m_client->setLargeIcon(href.latin1().data());
614             else if (WTF::equalIgnoringCase(linkElement->rel(), "search")) {
615                 if (WTF::equalIgnoringCase(linkElement->type(), "application/opensearchdescription+xml"))
616                     m_webPagePrivate->m_client->setSearchProviderDetails(title.utf8().data(), href.utf8().data());
617             } else if (WTF::equalIgnoringCase(linkElement->rel(), "alternate")
618                 && (WTF::equalIgnoringCase(linkElement->type(), "application/rss+xml")
619                 || WTF::equalIgnoringCase(linkElement->type(), "application/atom+xml")))
620                 m_webPagePrivate->m_client->setAlternateFeedDetails(title.utf8().data(), href.utf8().data());
621         }
622     }
623 }
624
625 void FrameLoaderClientBlackBerry::dispatchDidFinishDocumentLoad()
626 {
627     if (m_webPagePrivate->m_dumpRenderTree)
628         m_webPagePrivate->m_dumpRenderTree->didFinishDocumentLoadForFrame(m_frame);
629     notImplemented();
630 }
631
632 void FrameLoaderClientBlackBerry::dispatchDidFailLoad(const ResourceError& error)
633 {
634     didFinishOrFailLoading(error);
635     if (m_webPagePrivate->m_dumpRenderTree)
636         m_webPagePrivate->m_dumpRenderTree->didFailLoadForFrame(m_frame);
637 }
638
639 void FrameLoaderClientBlackBerry::didFinishOrFailLoading(const ResourceError& error)
640 {
641     // FIXME: Do we need to find a replacement for m_frame->document()->setExtraLayoutDelay(0);?
642
643     // If we have finished loading a page through history navigation, any
644     // attempt to go back to that page through an automatic redirect should be
645     // denied to avoid redirect loops. So save the history navigation urls to
646     // check later. (If this was not a history navigation,
647     // m_historyNavigationSourceURLs will be empty, and we should save that
648     // too.)
649     m_redirectURLsToSkipDueToHistoryNavigation.swap(m_historyNavigationSourceURLs);
650
651     // History navigation is finished so clear the history navigation url.
652     m_historyNavigationSourceURLs.clear();
653
654     if (isMainFrame()) {
655         m_loadError = error;
656         m_webPagePrivate->setLoadState(error.isNull() ? WebPagePrivate::Finished : WebPagePrivate::Failed);
657     }
658 }
659
660 void FrameLoaderClientBlackBerry::dispatchDidFailProvisionalLoad(const ResourceError& error)
661 {
662     if (isMainFrame()) {
663         m_loadError = error;
664         m_webPagePrivate->setLoadState(WebPagePrivate::Failed);
665
666         if (error.domain() == ResourceError::platformErrorDomain
667                 && (error.errorCode() == BlackBerry::Platform::FilterStream::StatusErrorAlreadyHandled)) {
668             // Error has already been displayed by client.
669             return;
670         }
671
672         if (error.domain().isEmpty() && !error.errorCode() && error.failingURL().isEmpty() && error.localizedDescription().isEmpty()) {
673             // Don't try to display empty errors returned from the unimplemented error functions in FrameLoaderClientBlackBerry - there's nothing to display anyway.
674             return;
675         }
676     }
677
678     if (m_webPagePrivate->m_dumpRenderTree)
679         m_webPagePrivate->m_dumpRenderTree->didFailProvisionalLoadForFrame(m_frame);
680
681     if (!isMainFrame())
682         return;
683
684     String errorPage = m_webPagePrivate->m_client->getErrorPage(error.errorCode()
685             , error.localizedDescription().isEmpty() ? "" : error.localizedDescription().utf8().data()
686             , error.failingURL().isEmpty() ? "" : error.failingURL().utf8().data());
687
688     // Make sure we're still in the provisionalLoad state - getErrorPage runs a
689     // nested event loop while it's waiting for client resources to load so
690     // there's a small window for the user to hit stop.
691     if (m_frame->loader()->provisionalDocumentLoader()) {
692         SubstituteData errorData(utf8Buffer(errorPage), "text/html", "utf-8", KURL(KURL(), error.failingURL()));
693
694         ResourceRequest originalRequest = m_frame->loader()->provisionalDocumentLoader()->originalRequest();
695
696         // Loading using SubstituteData will replace the original request with our
697         // error data. This must be done within dispatchDidFailProvisionalLoad,
698         // and do NOT call stopAllLoaders first, because the loader checks the
699         // provisionalDocumentLoader to decide the load type; if called any other
700         // way, the error page is added to the end of the history instead of
701         // replacing the failed load.
702         //
703         // If this comes from a back/forward navigation, we need to save the current viewstate
704         // to original historyitem, and prevent the restore of view state to the error page.
705         if (isBackForwardLoadType(m_frame->loader()->loadType())) {
706             m_frame->loader()->history()->saveScrollPositionAndViewStateToItem(m_frame->loader()->history()->currentItem());
707             ASSERT(m_frame->loader()->history()->provisionalItem());
708             m_frame->loader()->history()->provisionalItem()->viewState().shouldSaveViewState = false;
709         }
710         m_loadingErrorPage = true;
711         m_frame->loader()->load(originalRequest, errorData, false);
712     }
713 }
714
715 void FrameLoaderClientBlackBerry::dispatchWillSubmitForm(FramePolicyFunction function, PassRefPtr<FormState>)
716 {
717     // FIXME: Stub.
718     (m_frame->loader()->policyChecker()->*function)(PolicyUse);
719 }
720
721 PassRefPtr<Frame> FrameLoaderClientBlackBerry::createFrame(const KURL& url, const String& name
722     , HTMLFrameOwnerElement* ownerElement, const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
723 {
724     if (!m_webPagePrivate)
725         return 0;
726
727     if (m_childFrameCreationSuppressed)
728         return 0;
729
730     FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry();
731     RefPtr<Frame> childFrame = Frame::create(m_frame->page(), ownerElement, frameLoaderClient);
732     frameLoaderClient->setFrame(childFrame.get(), m_webPagePrivate);
733
734     // Initialize FrameView.
735     RefPtr<FrameView> frameView = FrameView::create(childFrame.get());
736     childFrame->setView(frameView.get());
737     if (!allowsScrolling)
738         frameView->setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff);
739     if (marginWidth != -1)
740         frameView->setMarginWidth(marginWidth);
741     if (marginHeight != -1)
742         frameView->setMarginHeight(marginHeight);
743
744     childFrame->tree()->setName(name);
745     m_frame->tree()->appendChild(childFrame);
746     childFrame->init();
747
748     if (!childFrame->tree()->parent())
749         return 0;
750
751     BackingStoreClient::create(childFrame.get(), m_frame, m_webPagePrivate->m_webPage);
752
753     m_frame->loader()->loadURLIntoChildFrame(url, referrer, childFrame.get());
754
755     if (!childFrame->tree()->parent())
756         return 0;
757
758     return childFrame.release();
759 }
760
761 void FrameLoaderClientBlackBerry::didTransferChildFrameToNewDocument(Page* /*oldPage*/)
762 {
763     Page* newPage = m_frame->page();
764     m_webPagePrivate = static_cast<ChromeClientBlackBerry*>(newPage->chrome()->client())->webPagePrivate();
765 }
766
767 void FrameLoaderClientBlackBerry::transferLoadingResourceFromPage(ResourceLoader*, const ResourceRequest&, Page*)
768 {
769     notImplemented();
770 }
771
772 ObjectContentType FrameLoaderClientBlackBerry::objectContentType(const KURL& url, const String& mimeTypeIn, bool shouldPreferPlugInsForImages)
773 {
774     String mimeType = mimeTypeIn;
775     if (mimeType.isEmpty())
776         mimeType = MIMETypeRegistry::getMIMETypeForPath(url.path());
777
778     // Get mapped type.
779     mimeType = WebSettings::getNormalizedMIMEType(mimeType);
780
781     ObjectContentType defaultType = FrameLoader::defaultObjectContentType(url, mimeType, shouldPreferPlugInsForImages);
782     if (defaultType != ObjectContentNone)
783         return defaultType;
784
785     if (WebSettings::isSupportedObjectMIMEType(mimeType))
786         return ObjectContentOtherPlugin;
787
788     return ObjectContentNone;
789 }
790
791 void FrameLoaderClientBlackBerry::dispatchWillClose()
792 {
793     m_webPagePrivate->frameUnloaded(m_frame);
794 }
795
796 void FrameLoaderClientBlackBerry::setMainDocumentError(DocumentLoader*, const ResourceError& error)
797 {
798     if (!m_pluginView)
799         return;
800
801     m_pluginView->didFail(error);
802     m_pluginView = 0;
803     m_hasSentResponseToPlugin = false;
804 }
805
806 void FrameLoaderClientBlackBerry::postProgressStartedNotification()
807 {
808     if (!isMainFrame())
809         return;
810
811     // New load started, so clear the error.
812     m_loadError = ResourceError();
813     m_sentReadyToRender = false;
814     m_webPagePrivate->m_client->notifyLoadStarted();
815 }
816
817 void FrameLoaderClientBlackBerry::postProgressEstimateChangedNotification()
818 {
819     if (!isMainFrame() || !m_frame->page())
820         return;
821
822     m_webPagePrivate->m_client->notifyLoadProgress(m_frame->page()->progress()->estimatedProgress() * 100);
823 }
824
825 void FrameLoaderClientBlackBerry::dispatchDidFirstVisuallyNonEmptyLayout()
826 {
827     if (!isMainFrame())
828         return;
829
830     BlackBerry::Platform::log(BlackBerry::Platform::LogLevelInfo, "dispatchDidFirstVisuallyNonEmptyLayout");
831
832     readyToRender(true);
833
834     // FIXME: We shouldn't be getting here if we are not in the Committed state but we are
835     // so we can not assert on that right now. But we only want to do this on load.
836     // RIM Bug #555
837     if (m_webPagePrivate->loadState() == WebPagePrivate::Committed) {
838         m_webPagePrivate->zoomToInitialScaleOnLoad(); // Set the proper zoom level first.
839         m_webPagePrivate->m_backingStore->d->clearVisibleZoom(); // Clear the visible zoom since we're explicitly rendering+blitting below.
840         m_webPagePrivate->m_backingStore->d->renderVisibleContents();
841     }
842
843     m_webPagePrivate->m_client->notifyFirstVisuallyNonEmptyLayout();
844 }
845
846 void FrameLoaderClientBlackBerry::postProgressFinishedNotification()
847 {
848     if (!isMainFrame())
849         return;
850
851     // Empty pages will never have called
852     // dispatchDidFirstVisuallyNonEmptyLayout, since they're visually empty, so
853     // we may need to call readyToRender now.
854     readyToRender(false);
855
856     // FIXME: Send up a real status code.
857     m_webPagePrivate->m_client->notifyLoadFinished(m_loadError.isNull() ? 0 : -1);
858
859     // Notify plugins that are waiting for the page to fully load before starting that
860     // the load has completed.
861     m_webPagePrivate->notifyPageOnLoad();
862 }
863
864 void FrameLoaderClientBlackBerry::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
865 {
866     if (world != mainThreadNormalWorld())
867         return;
868
869     // Provide the extension object first in case the client or others want to use it.
870     // FIXME: Conditionally attach extension object based on some flag or whether or not we
871     // are browser or something else.
872     attachExtensionObjectToFrame(m_frame, m_webPagePrivate->m_client);
873
874     m_webPagePrivate->m_client->notifyWindowObjectCleared();
875
876     if (m_webPagePrivate->m_dumpRenderTree) {
877         JSGlobalContextRef context = toGlobalRef(m_frame->script()->globalObject(mainThreadNormalWorld())->globalExec());
878         JSObjectRef windowObject = toRef(m_frame->script()->globalObject(mainThreadNormalWorld()));
879         ASSERT(windowObject);
880         m_webPagePrivate->m_dumpRenderTree->didClearWindowObjectInWorld(world, context, windowObject);
881     }
882 }
883
884 bool FrameLoaderClientBlackBerry::shouldGoToHistoryItem(HistoryItem*) const
885 {
886     return true;
887 }
888
889 bool FrameLoaderClientBlackBerry::shouldStopLoadingForHistoryItem(HistoryItem*) const
890 {
891     return true;
892 }
893
894 void FrameLoaderClientBlackBerry::invalidateBackForwardList() const
895 {
896     notifyBackForwardListChanged();
897 }
898
899 void FrameLoaderClientBlackBerry::notifyBackForwardListChanged() const
900 {
901     BackForwardListImpl* backForwardList = static_cast<BackForwardListImpl*>(m_webPagePrivate->m_page->backForward()->client());
902     ASSERT(backForwardList);
903
904     unsigned listSize = backForwardList->entries().size();
905     unsigned currentIndex = backForwardList->backListCount();
906     m_webPagePrivate->m_client->resetBackForwardList(listSize, currentIndex);
907 }
908
909 Frame* FrameLoaderClientBlackBerry::dispatchCreatePage(const NavigationAction& navigation)
910 {
911     WebPage* webPage = m_webPagePrivate->m_client->createWindow(0, 0, -1, -1, WebPageClient::FlagWindowDefault, navigation.url().string(), WebString());
912     if (!webPage)
913         return 0;
914
915     return webPage->d->m_page->mainFrame();
916 }
917
918 void FrameLoaderClientBlackBerry::detachedFromParent2()
919 {
920     BackingStoreClient* backingStoreClientForFrame = m_webPagePrivate->backingStoreClientForFrame(m_frame);
921     if (backingStoreClientForFrame) {
922         delete backingStoreClientForFrame;
923         backingStoreClientForFrame = 0;
924     }
925
926     if (m_frame->document())
927         m_webPagePrivate->clearDocumentData(m_frame->document());
928
929     m_webPagePrivate->frameUnloaded(m_frame);
930     m_webPagePrivate->m_client->notifyFrameDetached(m_frame);
931 }
932
933 void FrameLoaderClientBlackBerry::dispatchWillSendRequest(DocumentLoader* docLoader, long unsigned int, ResourceRequest& request, const ResourceResponse&)
934 {
935     // If the request is being loaded by the provisional document loader, then
936     // it is a new top level request which has not been commited.
937     bool isMainResourceLoad = docLoader && docLoader == docLoader->frameLoader()->provisionalDocumentLoader();
938
939     // Any processing which is done for all loads (both main and subresource) should go here.
940     BlackBerry::Platform::NetworkRequest platformRequest;
941     request.initializePlatformRequest(platformRequest, false /*isInitial*/);
942     m_webPagePrivate->m_client->populateCustomHeaders(platformRequest);
943     const BlackBerry::Platform::NetworkRequest::HeaderList& headerLists = platformRequest.getHeaderListRef();
944     for (BlackBerry::Platform::NetworkRequest::HeaderList::const_iterator it = headerLists.begin(); it != headerLists.end(); ++it) {
945         std::string headerString = it->first;
946         std::string headerValueString = it->second;
947         request.setHTTPHeaderField(String(headerString.c_str()), String(headerValueString.c_str()));
948     }
949     if (cookiesEnabled()) {
950         String cookiePairs = cookieManager().getCookie(request.url(), WithHttpOnlyCookies);
951         if (!cookiePairs.isEmpty()) {
952             // We only modify the WebCore request to make the cookies visible in inspector.
953             request.setHTTPHeaderField(String("Cookie"), cookiePairs);
954         }
955     }
956     if (!isMainResourceLoad) {
957         // Do nothing for now.
958         // Any processing which is done only for subresources should go here.
959         return;
960     }
961
962     // All processing beyond this point is done only for main resource loads.
963
964     if (m_clientRedirectIsPending && isMainFrame()) {
965         String originalUrl = m_frame->document()->url().string();
966         String finalUrl = request.url().string();
967
968         m_webPagePrivate->m_client->notifyClientRedirect(originalUrl.characters(), originalUrl.length(),
969             finalUrl.characters(), finalUrl.length());
970     }
971
972     // FIXME: Update the request type. See PR #119792.
973     if (docLoader->frameLoader()->isLoadingMainFrame())
974         request.setTargetType(ResourceRequest::TargetIsMainFrame);
975     else
976         request.setTargetType(ResourceRequest::TargetIsSubframe);
977
978     FrameLoader* loader = m_frame->loader();
979     ASSERT(loader);
980     if (isBackForwardLoadType(loader->loadType())) {
981         // Do not use the passed DocumentLoader because it is the loader that
982         // will be used for the new request (the DESTINATION of the history
983         // navigation - we want to use the current DocumentLoader to record the
984         // SOURCE).
985         DocumentLoader* docLoader = m_frame->loader()->documentLoader();
986         ASSERT(docLoader);
987         m_historyNavigationSourceURLs.add(docLoader->url());
988         m_historyNavigationSourceURLs.add(docLoader->originalURL());
989     }
990 }
991
992 void FrameLoaderClientBlackBerry::loadIconExternally(const String& originalPageUrl, const String& finalPageUrl, const String& iconUrl)
993 {
994     m_webPagePrivate->m_client->setIconForUrl(originalPageUrl.utf8().data(), finalPageUrl.utf8().data(), iconUrl.utf8().data());
995 }
996
997 void FrameLoaderClientBlackBerry::saveViewStateToItem(HistoryItem* item)
998 {
999     if (!isMainFrame())
1000         return;
1001
1002     ASSERT(item);
1003     HistoryItemViewState& viewState = item->viewState();
1004     if (viewState.shouldSaveViewState) {
1005         viewState.orientation = m_webPagePrivate->mainFrame()->orientation();
1006         viewState.isZoomToFitScale = m_webPagePrivate->currentScale() == m_webPagePrivate->zoomToFitScale();
1007         viewState.scale = m_webPagePrivate->currentScale();
1008         viewState.shouldReflowBlock = m_webPagePrivate->m_shouldReflowBlock;
1009     }
1010 }
1011
1012 void FrameLoaderClientBlackBerry::restoreViewState()
1013 {
1014     if (!isMainFrame())
1015         return;
1016
1017     HistoryItem* currentItem = m_frame->loader()->history()->currentItem();
1018     ASSERT(currentItem);
1019
1020     if (!currentItem)
1021         return;
1022
1023     // WebPagePrivate is messing up FrameView::wasScrolledByUser() by sending
1024     // scroll events that look like they were user generated all the time.
1025     //
1026     // Even if the user did not scroll, FrameView is gonna think they did.
1027     // So we use our own bookkeeping code to keep track of whether we were
1028     // actually scrolled by the user during load.
1029     //
1030     // If the user did scroll though, all are going to be in agreement about
1031     // that, and the worst thing that could happen is that
1032     // HistoryController::restoreScrollPositionAndViewState calls
1033     // setScrollPosition with the the same point, which is a NOOP.
1034     IntSize contentsSize = currentItem->contentsSize();
1035     IntPoint scrollPosition = currentItem->scrollPoint();
1036     if (m_webPagePrivate->m_userPerformedManualScroll)
1037         scrollPosition = m_webPagePrivate->scrollPosition();
1038
1039     // We need to reset this variable after the view state has been restored.
1040     m_webPagePrivate->m_didRestoreFromPageCache = false;
1041     HistoryItemViewState& viewState = currentItem->viewState();
1042
1043     // Also, try to keep the users zoom if any.
1044     double scale = viewState.scale;
1045     bool shouldReflowBlock = viewState.shouldReflowBlock;
1046     if (m_webPagePrivate->m_userPerformedManualZoom) {
1047         scale = m_webPagePrivate->currentScale();
1048         shouldReflowBlock = m_webPagePrivate->m_shouldReflowBlock;
1049     }
1050
1051     bool scrollChanged = scrollPosition != m_webPagePrivate->scrollPosition();
1052     bool scaleChanged = scale != m_webPagePrivate->currentScale();
1053     bool reflowChanged = shouldReflowBlock != m_webPagePrivate->m_shouldReflowBlock;
1054     bool orientationChanged = viewState.orientation % 180 != m_webPagePrivate->mainFrame()->orientation() % 180;
1055
1056     if (!scrollChanged && !scaleChanged && !reflowChanged && !orientationChanged)
1057         return;
1058
1059     // When rotate happens, only zoom when previous page was zoomToFitScale, otherwise keep old scale.
1060     if (orientationChanged && viewState.isZoomToFitScale)
1061         scale = BlackBerry::Platform::Graphics::Screen::primaryScreen()->width() * scale / static_cast<double>(BlackBerry::Platform::Graphics::Screen::primaryScreen()->height());
1062     m_webPagePrivate->m_backingStore->d->suspendScreenAndBackingStoreUpdates(); // don't flash checkerboard for the setScrollPosition call
1063     m_frame->view()->setContentsSizeFromHistory(contentsSize);
1064
1065     // Here we need to set scroll position what we asked for.
1066     // So we use ScrollView::setCanOverscroll(true).
1067     bool oldCanOverscroll = m_frame->view()->canOverScroll();
1068     m_frame->view()->setCanOverscroll(true);
1069     m_webPagePrivate->setScrollPosition(scrollPosition);
1070     m_frame->view()->setCanOverscroll(oldCanOverscroll);
1071
1072     m_webPagePrivate->m_shouldReflowBlock = viewState.shouldReflowBlock;
1073
1074     // Will restore updates to backingstore guaranteed!
1075     if (!m_webPagePrivate->zoomAboutPoint(scale, m_frame->view()->scrollPosition(), true /* enforceScaleClamping */, true /*forceRendering*/, true /*isRestoringZoomLevel*/)) {
1076         // If we're already at that scale, then we should still force rendering since
1077         // our scroll position changed.
1078         m_webPagePrivate->m_backingStore->d->renderVisibleContents();
1079
1080         // We need to notify the client of the scroll position and content size change(s) above even if we didn't scale.
1081         m_webPagePrivate->notifyTransformedContentsSizeChanged();
1082         m_webPagePrivate->notifyTransformedScrollChanged();
1083     }
1084 }
1085
1086 PolicyAction FrameLoaderClientBlackBerry::decidePolicyForExternalLoad(const ResourceRequest& request, bool isFragmentScroll)
1087 {
1088     const KURL& url = request.url();
1089     String pattern = m_webPagePrivate->findPatternStringForUrl(url);
1090     if (!pattern.isEmpty()) {
1091         m_webPagePrivate->m_client->handleStringPattern(pattern.characters(), pattern.length());
1092         return PolicyIgnore;
1093     }
1094
1095     if (m_webPagePrivate->m_webSettings->areLinksHandledExternally()
1096             && isMainFrame()
1097             && !request.mustHandleInternally()
1098             && !isFragmentScroll) {
1099         BlackBerry::Platform::NetworkRequest platformRequest;
1100         request.initializePlatformRequest(platformRequest);
1101         m_webPagePrivate->m_client->handleExternalLink(platformRequest, request.anchorText().characters(), request.anchorText().length(), m_clientRedirectIsPending);
1102         return PolicyIgnore;
1103     }
1104
1105     return PolicyUse;
1106 }
1107
1108 void FrameLoaderClientBlackBerry::willDeferLoading()
1109 {
1110     m_deferredJobsTimer->stop();
1111
1112     if (!isMainFrame())
1113         return;
1114
1115     m_webPagePrivate->willDeferLoading();
1116 }
1117
1118 void FrameLoaderClientBlackBerry::didResumeLoading()
1119 {
1120     if (!m_deferredManualScript.isNull())
1121         m_deferredJobsTimer->startOneShot(0);
1122
1123     if (!isMainFrame())
1124         return;
1125
1126     m_webPagePrivate->didResumeLoading();
1127 }
1128
1129 void FrameLoaderClientBlackBerry::setDeferredManualScript(const KURL& script)
1130 {
1131     ASSERT(!m_deferredJobsTimer->isActive());
1132     m_deferredManualScript = script;
1133 }
1134
1135 void FrameLoaderClientBlackBerry::deferredJobsTimerFired(Timer<FrameLoaderClientBlackBerry>*)
1136 {
1137     ASSERT(!m_frame->page()->defersLoading());
1138
1139     if (!m_deferredManualScript.isNull()) {
1140         // Executing the script will set deferred loading, which could trigger this timer again if a script is set. So clear the script first.
1141         KURL script = m_deferredManualScript;
1142         m_deferredManualScript = KURL();
1143
1144         m_frame->script()->executeIfJavaScriptURL(script);
1145     }
1146
1147     ASSERT(!m_frame->page()->defersLoading());
1148 }
1149
1150 void FrameLoaderClientBlackBerry::readyToRender(bool pageIsVisuallyNonEmpty)
1151 {
1152     // Only send the notification once.
1153     if (!m_sentReadyToRender) {
1154         m_webPagePrivate->m_client->notifyLoadReadyToRender(pageIsVisuallyNonEmpty);
1155         m_sentReadyToRender = true;
1156     }
1157 }
1158
1159 PassRefPtr<FrameNetworkingContext> FrameLoaderClientBlackBerry::createNetworkingContext()
1160 {
1161     return FrameNetworkingContextBlackBerry::create(m_frame);
1162 }
1163
1164 void FrameLoaderClientBlackBerry::authenticationChallenge(const String& realm, String& username, String& password)
1165 {
1166     WebString webPageUsername;
1167     WebString webPagePassword;
1168
1169     m_webPagePrivate->m_client->authenticationChallenge(realm.characters(), realm.length(), webPageUsername, webPagePassword);
1170
1171     username = webPageUsername;
1172     password = webPagePassword;
1173 }
1174
1175 void FrameLoaderClientBlackBerry::startDownload(const ResourceRequest& request, const String& /*suggestedName*/)
1176 {
1177     // FIXME: use the suggestedName?
1178     m_webPagePrivate->load(request.url().string().utf8().data(), 0, "GET", BlackBerry::Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, true, "");
1179 }
1180
1181 void FrameLoaderClientBlackBerry::download(ResourceHandle* handle, const ResourceRequest&, const ResourceRequest&, const ResourceResponse& r)
1182 {
1183     BlackBerry::Platform::FilterStream* stream = NetworkManager::instance()->streamForHandle(handle);
1184     ASSERT(stream);
1185
1186     m_webPagePrivate->m_client->downloadRequested(stream, r.suggestedFilename());
1187 }
1188
1189 void FrameLoaderClientBlackBerry::dispatchDidReceiveIcon()
1190 {
1191     String url = m_frame->document()->url().string();
1192     Image* img = iconDatabase().synchronousIconForPageURL(url, IntSize(10, 10));
1193     if (!img || !img->data())
1194         return;
1195
1196     NativeImageSkia* bitmap = img->nativeImageForCurrentFrame();
1197     if (!bitmap)
1198         return;
1199     bitmap->lockPixels();
1200     String iconUrl = iconDatabase().synchronousIconURLForPageURL(url);
1201     m_webPagePrivate->m_client->setFavicon(img->width(), img->height(), (unsigned char*)bitmap->getPixels(), iconUrl.utf8().data());
1202     bitmap->unlockPixels();
1203 }
1204
1205 bool FrameLoaderClientBlackBerry::canCachePage() const
1206 {
1207     // We won't cache pages containing video or audio.
1208     ASSERT(m_frame->document());
1209     RefPtr<NodeList> nodeList = m_frame->document()->getElementsByTagName(HTMLNames::videoTag.localName());
1210     if (nodeList.get()->length() > 0)
1211         return false;
1212     nodeList = m_frame->document()->getElementsByTagName(HTMLNames::audioTag.localName());
1213     if (nodeList.get()->length() > 0)
1214         return false;
1215
1216     // The multipart of "multipart/x-mixed-replace" only supports image, correct?
1217     // FIXME: Do we have a better place to handle this case?
1218     nodeList = m_frame->document()->getElementsByTagName(HTMLNames::imgTag.localName());
1219     for (unsigned i = 0; i < nodeList.get()->length(); ++i) {
1220         HTMLImageElement* node = static_cast<HTMLImageElement*>(nodeList.get()->item(i));
1221         CachedImage* cachedimage = node ? node->cachedImage() : 0;
1222         if (cachedimage && cachedimage->response().isMultipartPayload())
1223             return false;
1224     }
1225     return true;
1226 }
1227
1228 void FrameLoaderClientBlackBerry::didSaveToPageCache()
1229 {
1230     // When page goes into PageCache, clean up any possible
1231     // document data cache we might have.
1232     m_webPagePrivate->clearDocumentData(m_frame->document());
1233 }
1234
1235 void FrameLoaderClientBlackBerry::provisionalLoadStarted()
1236 {
1237     // We would like to hide the virtual keyboard before it navigates to another page
1238     // so that the scroll offset without keyboard shown will be saved in the history item.
1239     // Then when the user navigates back, it will scroll to the right position.
1240     if (isMainFrame())
1241         m_webPagePrivate->showVirtualKeyboard(false);
1242 }
1243
1244 // We don't need to provide the error message string, that will be handled in BrowserErrorPage according to the error code.
1245 ResourceError FrameLoaderClientBlackBerry::cannotShowURLError(const ResourceRequest& request)
1246 {
1247     // FIXME: Why are we not passing the domain to the ResourceError? See PR #119789.
1248     return ResourceError(String(), WebKitErrorCannotShowURL, request.url().string(), String());
1249 }
1250
1251 void FrameLoaderClientBlackBerry::didRestoreFromPageCache()
1252 {
1253     m_webPagePrivate->m_didRestoreFromPageCache = true;
1254 }
1255
1256 void FrameLoaderClientBlackBerry::dispatchWillUpdateApplicationCache(const ResourceRequest&)
1257 {
1258     ASSERT(isMainFrame());
1259     if (!isMainFrame())
1260         return;
1261
1262     m_webPagePrivate->m_client->notifyWillUpdateApplicationCache();
1263 }
1264
1265 void FrameLoaderClientBlackBerry::dispatchDidLoadFromApplicationCache(const ResourceRequest&)
1266 {
1267     ASSERT(isMainFrame());
1268     if (!isMainFrame())
1269         return;
1270
1271     m_webPagePrivate->m_client->notifyDidLoadFromApplicationCache();
1272 }
1273
1274 } // WebCore