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