[BlackBerry] Upstream BlackBerry API web page related files
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Feb 2012 03:41:01 +0000 (03:41 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Feb 2012 03:41:01 +0000 (03:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=74380

Patch by Jacky Jiang <zhajiang@rim.com> on 2012-02-23
Reviewed by Antonio Gomes.

Initial upstream, no new tests.

* Api/WebPage.cpp: Added.
* Api/WebPage.h: Added.
* Api/WebPage_p.h: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108718 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/blackberry/Api/WebPage.cpp [new file with mode: 0644]
Source/WebKit/blackberry/Api/WebPage.h [new file with mode: 0644]
Source/WebKit/blackberry/Api/WebPage_p.h [new file with mode: 0644]
Source/WebKit/blackberry/ChangeLog

diff --git a/Source/WebKit/blackberry/Api/WebPage.cpp b/Source/WebKit/blackberry/Api/WebPage.cpp
new file mode 100644 (file)
index 0000000..490a88c
--- /dev/null
@@ -0,0 +1,5598 @@
+/*
+ * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+#include "WebPage.h"
+
+#include "ApplicationCacheStorage.h"
+#include "BackForwardController.h"
+#include "BackForwardListImpl.h"
+#include "BackingStoreClient.h"
+#include "BackingStoreCompositingSurface.h"
+#include "BackingStore_p.h"
+#include "CString.h"
+#include "CachedImage.h"
+#include "Chrome.h"
+#include "ChromeClientBlackBerry.h"
+#include "ContextMenuClientBlackBerry.h"
+#include "CookieManager.h"
+#include "DOMSupport.h"
+#include "Database.h"
+#include "DatabaseSync.h"
+#include "DatabaseTracker.h"
+#include "DeviceMotionClientBlackBerry.h"
+#include "DeviceOrientationClientBlackBerry.h"
+#include "DragClientBlackBerry.h"
+// FIXME: We should be using DumpRenderTreeClient, but I'm not sure where we should
+// create the DRT_BB object. See PR #120355.
+#if ENABLE_DRT
+#include "DumpRenderTreeBlackBerry.h"
+#endif
+#include "EditorClientBlackBerry.h"
+#include "FocusController.h"
+#include "FrameLoaderClientBlackBerry.h"
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+#if ENABLE_DRT
+#include "GeolocationClientMock.h"
+#endif
+#include "GeolocationControllerClientBlackBerry.h"
+#endif
+#include "GroupSettings.h"
+#include "HTMLAreaElement.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HTMLImageElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HTMLParserIdioms.h"
+#include "HTTPParsers.h"
+#include "HistoryItem.h"
+#include "IconDatabaseClientBlackBerry.h"
+#include "InPageSearchManager.h"
+#include "InRegionScrollableArea.h"
+#include "InputHandler.h"
+#include "InspectorBackendDispatcher.h"
+#include "InspectorClientBlackBerry.h"
+#include "InspectorController.h"
+#include "JavaScriptDebuggerBlackBerry.h"
+#include "LayerWebKitThread.h"
+#include "NetworkManager.h"
+#include "NodeRenderStyle.h"
+#include "Page.h"
+#include "PageCache.h"
+#include "PageGroup.h"
+#include "PlatformTouchEvent.h"
+#include "PlatformWheelEvent.h"
+#include "PluginDatabase.h"
+#include "PluginView.h"
+#include "RenderText.h"
+#include "RenderThemeBlackBerry.h"
+#include "RenderTreeAsText.h"
+#include "RenderView.h"
+#include "RenderWidget.h"
+#include "ScriptSourceCode.h"
+#include "ScriptValue.h"
+#include "ScrollTypes.h"
+#include "SelectionHandler.h"
+#include "Settings.h"
+#include "Storage.h"
+#include "StorageNamespace.h"
+#include "SurfacePool.h"
+#include "Text.h"
+#include "ThreadCheck.h"
+#include "TouchEventHandler.h"
+#include "TransformationMatrix.h"
+#include "VisiblePosition.h"
+#if ENABLE(WEBDOM)
+#include "WebDOMDocument.h"
+#endif
+#include "WebPageClient.h"
+#include "WebSocket.h"
+#include "npapi.h"
+#include "runtime_root.h"
+
+#if ENABLE(VIDEO)
+#include "HTMLMediaElement.h"
+#include "MediaPlayer.h"
+#include "MediaPlayerPrivateBlackBerry.h"
+#endif
+
+#if USE(SKIA)
+#include "PlatformContextSkia.h"
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "FrameLayers.h"
+#include "WebPageCompositor.h"
+#endif
+
+#include <BlackBerryPlatformExecutableMessage.h>
+#include <BlackBerryPlatformITPolicy.h>
+#include <BlackBerryPlatformKeyboardEvent.h>
+#include <BlackBerryPlatformMessageClient.h>
+#include <BlackBerryPlatformMouseEvent.h>
+#include <BlackBerryPlatformScreen.h>
+#include <BlackBerryPlatformSettings.h>
+#include <JavaScriptCore/APICast.h>
+#include <JavaScriptCore/JSContextRef.h>
+#include <SharedPointer.h>
+#include <sys/keycodes.h>
+#include <unicode/ustring.h> // platform ICU
+
+#ifndef USER_PROCESSES
+#include <memalloc.h>
+#endif
+
+#if ENABLE(SKIA_GPU_CANVAS)
+#include "BlackBerryPlatformGraphics.h"
+#include "GrContext.h"
+#endif
+
+#define DEBUG_BLOCK_ZOOM 0
+#define DEBUG_TOUCH_EVENTS 0
+#define DEBUG_WEBPAGE_LOAD 0
+
+using namespace std;
+using namespace WebCore;
+
+typedef const unsigned short* CUShortPtr;
+
+namespace BlackBerry {
+namespace WebKit {
+
+static Vector<WebPage*>* visibleWebPages()
+{
+    static Vector<WebPage*>* s_visibleWebPages = 0; // Initially, no web page is visible.
+    if (!s_visibleWebPages)
+        s_visibleWebPages = new Vector<WebPage*>;
+    return s_visibleWebPages;
+}
+
+const unsigned blockZoomMargin = 3; // Add 3 pixel margin on each side.
+static int blockClickRadius = 0;
+static double maximumBlockZoomScale = 3; // This scale can be clamped by the maximumScale set for the page.
+
+const double manualScrollInterval = 0.1; // The time interval during which we associate user action with scrolling.
+
+const double delayedZoomInterval = 0;
+
+const IntSize minimumLayoutSize(10, 10); // Needs to be a small size, greater than 0, that we can grow the layout from.
+const IntSize maximumLayoutSize(10000, 10000); // Used with viewport meta tag, but we can still grow from this of course.
+
+const double minimumExpandingRatio = 0.15;
+
+// Helper function to parse a URL and fill in missing parts.
+static KURL parseUrl(const String& url)
+{
+    String urlString(url);
+    KURL kurl = KURL(KURL(), urlString);
+    if (kurl.protocol().isEmpty()) {
+        urlString.insert("http://", 0);
+        kurl = KURL(KURL(), urlString);
+    }
+
+    return kurl;
+}
+
+// Helper functions to convert to and from WebCore types.
+static inline MouseEventType toWebCoreMouseEventType(const Platform::MouseEvent::Type type)
+{
+    switch (type) {
+    case Platform::MouseEvent::MouseButtonDown:
+        return MouseEventPressed;
+    case Platform::MouseEvent::MouseButtonUp:
+        return MouseEventReleased;
+    case Platform::MouseEvent::MouseMove:
+    default:
+        return MouseEventMoved;
+    }
+}
+
+static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy)
+{
+    switch (policy) {
+    case Platform::NetworkRequest::UseProtocolCachePolicy:
+        return UseProtocolCachePolicy;
+    case Platform::NetworkRequest::ReloadIgnoringCacheData:
+        return ReloadIgnoringCacheData;
+    case Platform::NetworkRequest::ReturnCacheDataElseLoad:
+        return ReturnCacheDataElseLoad;
+    case Platform::NetworkRequest::ReturnCacheDataDontLoad:
+        return ReturnCacheDataDontLoad;
+    default:
+        ASSERT_NOT_REACHED();
+        return UseProtocolCachePolicy;
+    }
+}
+
+#if ENABLE(EVENT_MODE_METATAGS)
+static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode)
+{
+    switch (mode) {
+    case ProcessedCursorEvents:
+        return Platform::ProcessedCursorEvents;
+    case NativeCursorEvents:
+        return Platform::NativeCursorEvents;
+    default:
+        ASSERT_NOT_REACHED();
+        return Platform::ProcessedCursorEvents;
+    }
+}
+
+static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode)
+{
+    switch (mode) {
+    case ProcessedTouchEvents:
+        return Platform::ProcessedTouchEvents;
+    case NativeTouchEvents:
+        return Platform::NativeTouchEvents;
+    case PureTouchEventsWithMouseConversion:
+        return Platform::PureTouchEventsWithMouseConversion;
+    default:
+        ASSERT_NOT_REACHED();
+        return Platform::ProcessedTouchEvents;
+    }
+}
+#endif
+
+static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id)
+{
+    return reinterpret_cast<HistoryItem*>(id);
+}
+
+static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item)
+{
+    return reinterpret_cast<WebPage::BackForwardId>(item);
+}
+
+WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
+    : m_webPage(webPage)
+    , m_client(client)
+    , m_page(0) // Initialized by init.
+    , m_mainFrame(0) // Initialized by init.
+    , m_currentContextNode(0)
+    , m_webSettings(0) // Initialized by init.
+    , m_visible(false)
+    , m_shouldResetTilesWhenShown(false)
+    , m_userScalable(true)
+    , m_userPerformedManualZoom(false)
+    , m_userPerformedManualScroll(false)
+    , m_contentsSizeChanged(false)
+    , m_overflowExceedsContentsSize(false)
+    , m_resetVirtualViewportOnCommitted(true)
+    , m_shouldUseFixedDesktopMode(false)
+    , m_needTouchEvents(false)
+    , m_preventIdleDimmingCount(0)
+#if ENABLE(TOUCH_EVENTS)
+    , m_preventDefaultOnTouchStart(false)
+#endif
+    , m_nestedLayoutFinishedCount(0)
+    , m_actualVisibleWidth(rect.width())
+    , m_actualVisibleHeight(rect.height())
+    , m_virtualViewportWidth(0)
+    , m_virtualViewportHeight(0)
+    , m_defaultLayoutSize(minimumLayoutSize)
+    , m_didRestoreFromPageCache(false)
+    , m_viewMode(WebPagePrivate::Desktop) // Default to Desktop mode for PB.
+    , m_loadState(WebPagePrivate::None)
+    , m_transformationMatrix(new TransformationMatrix())
+    , m_backingStore(0) // Initialized by init.
+    , m_backingStoreClient(0) // Initialized by init.
+    , m_inPageSearchManager(new InPageSearchManager(this))
+    , m_inputHandler(new InputHandler(this))
+    , m_selectionHandler(new SelectionHandler(this))
+    , m_touchEventHandler(new TouchEventHandler(this))
+#if ENABLE(EVENT_MODE_METATAGS)
+    , m_cursorEventMode(ProcessedCursorEvents)
+    , m_touchEventMode(ProcessedTouchEvents)
+#endif
+    , m_currentCursor(Platform::CursorNone)
+    , m_dumpRenderTree(0) // Lazy initialization.
+    , m_initialScale(-1.0)
+    , m_minimumScale(-1.0)
+    , m_maximumScale(-1.0)
+    , m_blockZoomFinalScale(1.0)
+    , m_anchorInNodeRectRatio(-1, -1)
+    , m_currentBlockZoomNode(0)
+    , m_currentBlockZoomAdjustedNode(0)
+    , m_shouldReflowBlock(false)
+    , m_delayedZoomTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::zoomAboutPointTimerFired)))
+    , m_lastUserEventTimestamp(0.0)
+    , m_pluginMouseButtonPressed(false)
+    , m_pluginMayOpenNewTab(false)
+    , m_geolocationClient(0)
+    , m_inRegionScrollStartingNode(0)
+#if USE(ACCELERATED_COMPOSITING)
+    , m_isAcceleratedCompositingActive(false)
+    , m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
+    , m_needsOneShotDrawingSynchronization(false)
+    , m_needsCommit(false)
+    , m_suspendRootLayerCommit(false)
+#endif
+    , m_pendingOrientation(-1)
+    , m_fullscreenVideoNode(0)
+    , m_hasInRegionScrollableAreas(false)
+    , m_updateDelegatedOverlaysDispatched(false)
+{
+}
+
+WebPagePrivate::~WebPagePrivate()
+{
+    // Hand the backingstore back to another owner if necessary.
+    m_webPage->setVisible(false);
+    if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage)
+        BackingStorePrivate::setCurrentBackingStoreOwner(0);
+
+    delete m_webSettings;
+    m_webSettings = 0;
+
+    delete m_backingStoreClient;
+    m_backingStoreClient = 0;
+    m_backingStore = 0;
+
+    delete m_page;
+    m_page = 0;
+
+    delete m_transformationMatrix;
+    m_transformationMatrix = 0;
+
+    delete m_inPageSearchManager;
+    m_inPageSearchManager = 0;
+
+    delete m_selectionHandler;
+    m_selectionHandler = 0;
+
+    delete m_inputHandler;
+    m_inputHandler = 0;
+
+    delete m_touchEventHandler;
+    m_touchEventHandler = 0;
+
+#if ENABLE_DRT
+    delete m_dumpRenderTree;
+    m_dumpRenderTree = 0;
+#endif
+}
+
+void WebPagePrivate::init(const WebString& pageGroupName)
+{
+    ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this);
+    ContextMenuClientBlackBerry* contextMenuClient = 0;
+#if ENABLE(CONTEXT_MENUS)
+    contextMenuClient = new ContextMenuClientBlackBerry();
+#endif
+    EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this);
+    DragClientBlackBerry* dragClient = 0;
+#if ENABLE(DRAG_SUPPORT)
+    dragClient = new DragClientBlackBerry();
+#endif
+    InspectorClientBlackBerry* inspectorClient = 0;
+#if ENABLE(INSPECTOR)
+    inspectorClient = new InspectorClientBlackBerry(this);
+#endif
+
+    FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry();
+
+    Page::PageClients pageClients;
+    pageClients.chromeClient = chromeClient;
+    pageClients.contextMenuClient = contextMenuClient;
+    pageClients.editorClient = editorClient;
+    pageClients.dragClient = dragClient;
+    pageClients.inspectorClient = inspectorClient;
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+    // Note the object will be destroyed when the page is destroyed.
+#if ENABLE_DRT
+    if (getenv("drtRun"))
+        pageClients.geolocationClient = new GeolocationClientMock();
+    else
+#endif
+        pageClients.geolocationClient = m_geolocationClient = new GeolocationControllerClientBlackBerry(this);
+#else
+    pageClients.geolocationClient = m_geolocationClient;
+#endif
+
+    pageClients.deviceMotionClient = new DeviceMotionClientBlackBerry(this);
+    pageClients.deviceOrientationClient = new DeviceOrientationClientBlackBerry(this);
+    m_page = new Page(pageClients);
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION) && ENABLE_DRT
+    // In case running in DumpRenderTree mode set the controller to mock provider.
+    if (getenv("drtRun"))
+        static_cast<GeolocationClientMock*>(pageClients.geolocationClient)->setController(m_page->geolocationController());
+#endif
+
+    m_page->setCustomHTMLTokenizerChunkSize(256);
+    m_page->setCustomHTMLTokenizerTimeDelay(0.3);
+
+    m_webSettings = WebSettings::createFromStandardSettings();
+
+    // FIXME: We explicitly call setDelegate() instead of passing ourself in createFromStandardSettings()
+    // so that we only get one didChangeSettings() callback when we set the page group name. This causes us
+    // to make a copy of the WebSettings since some WebSettings method make use of the page group name.
+    // Instead, we shouldn't be storing the page group name in WebSettings.
+    m_webSettings->setDelegate(this);
+    m_webSettings->setPageGroupName(pageGroupName);
+
+    RefPtr<Frame> newFrame = Frame::create(m_page, /* HTMLFrameOwnerElement* */ 0, frameLoaderClient);
+
+    m_mainFrame = newFrame.get();
+    frameLoaderClient->setFrame(m_mainFrame, this);
+    m_mainFrame->init();
+
+#if ENABLE(WEBGL)
+    Platform::Settings* settings = Platform::Settings::get();
+    m_page->settings()->setWebGLEnabled(settings && settings->isWebGLSupported());
+#endif
+#if ENABLE(SKIA_GPU_CANVAS)
+    m_page->settings()->setCanvasUsesAcceleratedDrawing(true);
+    m_page->settings()->setAccelerated2dCanvasEnabled(true);
+#endif
+#if ENABLE(VIEWPORT_REFLOW)
+    m_page->settings()->setTextReflowEnabled(m_webSettings->textReflowMode() == WebSettings::TextReflowEnabled);
+#endif
+
+    m_page->settings()->setUseHixie76WebSocketProtocol(false);
+    m_page->settings()->setInteractiveFormValidationEnabled(true);
+    m_page->settings()->setAllowUniversalAccessFromFileURLs(false);
+
+    m_backingStoreClient = BackingStoreClient::create(m_mainFrame, /* parent frame */ 0, m_webPage);
+    // The direct access to BackingStore is left here for convenience since it
+    // is owned by BackingStoreClient and then deleted by its destructor.
+    m_backingStore = m_backingStoreClient->backingStore();
+
+    m_page->settings()->setSpatialNavigationEnabled(m_webSettings->isSpatialNavigationEnabled());
+    blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::pixelsPerInch(0).width())); // The clicked rectangle area should be a fixed unit of measurement.
+
+    m_page->settings()->setDelegateSelectionPaint(true);
+}
+
+void WebPagePrivate::load(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool isInitial, bool mustHandleInternally, bool forceDownload, const char* overrideContentType)
+{
+    stopCurrentLoad();
+
+    String urlString(url);
+    if (urlString.startsWith("vs:", false)) {
+        urlString = urlString.substring(3);
+        m_mainFrame->setInViewSourceMode(true);
+    } else
+        m_mainFrame->setInViewSourceMode(false);
+
+    KURL kurl = parseUrl(urlString);
+    if (protocolIs(kurl, "javascript")) {
+        // Never run javascript while loading is deferred.
+        if (m_page->defersLoading()) {
+            FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(m_mainFrame->loader()->client());
+            frameLoaderClient->setDeferredManualScript(kurl);
+        } else
+            m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL);
+        return;
+    }
+
+    if (isInitial)
+        NetworkManager::instance()->setInitialURL(kurl);
+
+    ResourceRequest request(kurl, "" /* referrer */);
+    request.setToken(networkToken);
+    if (isInitial || mustHandleInternally)
+        request.setMustHandleInternally(true);
+    request.setHTTPMethod(method);
+    request.setCachePolicy(toWebCoreCachePolicy(cachePolicy));
+    if (overrideContentType)
+        request.setOverrideContentType(overrideContentType);
+
+    if (data)
+        request.setHTTPBody(FormData::create(data, dataLength));
+
+    for (unsigned i = 0; i + 1 < headersLength; i += 2)
+        request.addHTTPHeaderField(headers[i], headers[i + 1]);
+
+    if (forceDownload)
+        request.setForceDownload(true);
+
+    m_mainFrame->loader()->load(request, "" /* name */, false);
+}
+
+void WebPagePrivate::loadString(const char* string, const char* baseURL, const char* contentType, const char* failingURL)
+{
+    KURL kurl = parseUrl(baseURL);
+    ResourceRequest request(kurl);
+    WTF::RefPtr<SharedBuffer> buffer
+        = SharedBuffer::create(string, strlen(string));
+    SubstituteData substituteData(buffer,
+                                  extractMIMETypeFromMediaType(contentType),
+                                  extractCharsetFromMediaType(contentType),
+                                  failingURL ? parseUrl(failingURL) : KURL());
+    m_mainFrame->loader()->load(request, substituteData, false);
+}
+
+bool WebPagePrivate::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
+{
+    ScriptValue result = m_mainFrame->script()->executeScript(String::fromUTF8(script), false);
+    JSC::JSValue value = result.jsValue();
+    if (!value) {
+        returnType = JSException;
+        return false;
+    }
+
+    JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
+    JSGlobalContextRef context = toGlobalRef(exec);
+
+    JSType type = JSValueGetType(context, toRef(exec, value));
+
+    switch (type) {
+    case kJSTypeNull:
+        returnType = JSNull;
+        break;
+    case kJSTypeBoolean:
+        returnType = JSBoolean;
+        break;
+    case kJSTypeNumber:
+        returnType = JSNumber;
+        break;
+    case kJSTypeString:
+        returnType = JSString;
+        break;
+    case kJSTypeObject:
+        returnType = JSObject;
+        break;
+    case kJSTypeUndefined:
+    default:
+        returnType = JSUndefined;
+        break;
+    }
+
+    if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
+        String str = result.toString(exec);
+        returnValue = WebString(str.impl());
+    }
+
+    return true;
+}
+
+bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& sourceCode, JavaScriptDataType& returnType, WebString& returnValue)
+{
+    if (!m_isolatedWorld)
+        m_isolatedWorld = m_mainFrame->script()->createWorld();
+
+    // Use evaluateInWorld to avoid canExecuteScripts check.
+    ScriptValue result = m_mainFrame->script()->evaluateInWorld(sourceCode, m_isolatedWorld.get());
+    JSC::JSValue value = result.jsValue();
+    if (!value) {
+        returnType = JSException;
+        return false;
+    }
+
+    JSC::ExecState* exec = m_mainFrame->script()->globalObject(m_isolatedWorld.get())->globalExec();
+    JSGlobalContextRef context = toGlobalRef(exec);
+
+    JSType type = JSValueGetType(context, toRef(exec, value));
+
+    switch (type) {
+    case kJSTypeNull:
+        returnType = JSNull;
+        break;
+    case kJSTypeBoolean:
+        returnType = JSBoolean;
+        break;
+    case kJSTypeNumber:
+        returnType = JSNumber;
+        break;
+    case kJSTypeString:
+        returnType = JSString;
+        break;
+    case kJSTypeObject:
+        returnType = JSObject;
+        break;
+    case kJSTypeUndefined:
+    default:
+        returnType = JSUndefined;
+        break;
+    }
+
+    if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
+        String str = result.toString(exec);
+        returnValue = WebString(str.impl());
+    }
+
+    return true;
+}
+
+void WebPagePrivate::stopCurrentLoad()
+{
+    // This function should contain all common code triggered by WebPage::load
+    // (which stops any load in progress before starting the new load) and
+    // WebPage::stoploading (the entry point for the client to stop the load
+    // explicitly). If it should only be done while stopping the load
+    // explicitly, it goes in WebPage::stopLoading, not here.
+    m_mainFrame->loader()->stopAllLoaders();
+
+    // Cancel any deferred script that hasn't been processed yet.
+    FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(m_mainFrame->loader()->client());
+    frameLoaderClient->setDeferredManualScript(KURL());
+}
+
+static void closeURLRecursively(Frame* frame)
+{
+    // Do not create more frame please.
+    FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client());
+    frameLoaderClient->suppressChildFrameCreation();
+
+    frame->loader()->closeURL();
+
+    Vector<RefPtr<Frame>, 10> childFrames;
+
+    for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
+        childFrames.append(childFrame);
+
+    unsigned size = childFrames.size();
+    for (unsigned i = 0; i < size; i++)
+        closeURLRecursively(childFrames[i].get());
+}
+
+void WebPagePrivate::prepareToDestroy()
+{
+    // Before the client starts tearing itself down, dispatch the unload event
+    // so it can take effect while all the client's state (e.g. scroll position)
+    // is still present.
+    closeURLRecursively(m_mainFrame);
+}
+
+void WebPagePrivate::setLoadState(LoadState state)
+{
+    if (m_loadState == state)
+        return;
+
+    bool isFirstLoad = m_loadState == None;
+
+    // See RIM Bug #1068.
+    if (state == Finished && m_mainFrame && m_mainFrame->document())
+        m_mainFrame->document()->updateStyleIfNeeded();
+
+    m_loadState = state;
+
+#if DEBUG_WEBPAGE_LOAD
+    Platform::log(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state);
+#endif
+
+    switch (m_loadState) {
+    case Provisional:
+        if (isFirstLoad) {
+            // Paints the visible backingstore as white to prevent initial checkerboard on
+            // the first blit.
+            if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
+                m_backingStore->d->blitVisibleContents();
+        }
+        break;
+    case Committed:
+        {
+            unscheduleZoomAboutPoint();
+
+#if ENABLE(SKIA_GPU_CANVAS)
+            if (m_page->settings()->canvasUsesAcceleratedDrawing()) {
+                // Free GPU resources as we're on a new page.
+                // This will help us to free memory pressure.
+                Platform::Graphics::makeSharedResourceContextCurrent(Platform::Graphics::GLES2);
+                GrContext* grContext = Platform::Graphics::getGrContext();
+                grContext->freeGpuResources();
+            }
+#endif
+
+#if USE(ACCELERATED_COMPOSITING)
+            // FIXME: compositor may only be touched on the compositing thread.
+            // However, it's created/destroyed by a sync command so this is harmless.
+            if (m_compositor) {
+                m_compositor->setLayoutRectForCompositing(IntRect());
+                m_compositor->setContentsSizeForCompositing(IntSize());
+            }
+#endif
+            m_previousContentsSize = IntSize();
+            m_backingStore->d->resetRenderQueue();
+            m_backingStore->d->resetTiles(true /* resetBackground */);
+            m_backingStore->d->setScrollingOrZooming(false, false /* shouldBlit */);
+            m_userPerformedManualZoom = false;
+            m_userPerformedManualScroll = false;
+            m_shouldUseFixedDesktopMode = false;
+            if (m_resetVirtualViewportOnCommitted) { // For DRT.
+                m_virtualViewportWidth = 0;
+                m_virtualViewportHeight = 0;
+            }
+            if (m_webSettings->viewportWidth() > 0) {
+                m_virtualViewportWidth = m_webSettings->viewportWidth();
+                m_virtualViewportHeight = m_defaultLayoutSize.height();
+            }
+            // Check if we have already process the meta viewport tag, this only happens on history navigation
+            if (!m_didRestoreFromPageCache) {
+                m_viewportArguments = ViewportArguments();
+                m_userScalable = m_webSettings->isUserScalable();
+                resetScales();
+            } else {
+                IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
+                m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
+            }
+
+#if ENABLE(EVENT_MODE_METATAGS)
+            didReceiveCursorEventMode(ProcessedCursorEvents);
+            didReceiveTouchEventMode(ProcessedTouchEvents);
+#endif
+
+            // If it's a outmost SVG document, we use FixedDesktop mode, otherwise
+            // we default to Mobile mode. For example, using FixedDesktop mode to
+            // render http://www.croczilla.com/bits_and_pieces/svg/samples/tiger/tiger.svg
+            // is user-experience friendly.
+            if (m_page->mainFrame()->document()->isSVGDocument()) {
+                setShouldUseFixedDesktopMode(true);
+                setViewMode(FixedDesktop);
+            } else
+                setViewMode(Mobile);
+
+            // Reset block zoom and reflow.
+            resetBlockZoom();
+#if ENABLE(VIEWPORT_REFLOW)
+            toggleTextReflowIfEnabledForBlockZoomOnly();
+#endif
+
+            // Set the scroll to origin here and notify the client since we'll be
+            // zooming below without any real contents yet thus the contents size
+            // we report to the client could make our current scroll position invalid.
+            setScrollPosition(IntPoint::zero());
+            notifyTransformedScrollChanged();
+
+            // Paints the visible backingstore as white. Note it is important we do
+            // this strictly after re-setting the scroll position to origin and resetting
+            // the scales otherwise the visible contents calculation is wrong and we
+            // can end up blitting artifacts instead. See: RIM Bug #401.
+            if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
+                m_backingStore->d->blitVisibleContents();
+
+            zoomToInitialScaleOnLoad();
+
+            // Update cursor status.
+            updateCursor();
+
+#if USE(ACCELERATED_COMPOSITING)
+            // Don't render compositing contents from previous page.
+            resetCompositingSurface();
+#endif
+            break;
+        }
+    case Finished:
+    case Failed:
+        // Notify client of the initial zoom change.
+        m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
+        m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
+        break;
+    default:
+        break;
+    }
+}
+
+double WebPagePrivate::clampedScale(double scale) const
+{
+    if (scale < minimumScale())
+        return minimumScale();
+    if (scale > maximumScale())
+        return maximumScale();
+    return scale;
+}
+
+bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale)
+{
+    if (!m_mainFrame->view())
+        return false;
+
+    if (enforceScaleClamping)
+        scale = this->clampedScale(scale);
+
+    ASSERT(clampedScale);
+    *clampedScale = scale;
+
+    if (currentScale() == scale) {
+        // Make sure backingstore updates resume from pinch zoom in the case where the final zoom level doesn't change.
+        m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
+        m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
+        return false;
+    }
+
+    return true;
+}
+
+bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel)
+{
+    if (!isRestoringZoomLevel) {
+        // Clear any existing block zoom.  (If we are restoring a saved zoom level on page load,
+        // there is guaranteed to be no existing block zoom and we don't want to clear m_shouldReflowBlock.)
+        resetBlockZoom();
+    }
+
+    // The reflow and block zoom stuff here needs to happen regardless of
+    // whether we shouldZoomAboutPoint.
+#if ENABLE(VIEWPORT_REFLOW)
+    toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
+    if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view())
+        setNeedsLayout();
+#endif
+
+    double scale;
+    if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
+        if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
+            m_currentPinchZoomNode = 0;
+            m_anchorInNodeRectRatio = FloatPoint(-1, -1);
+        }
+        return false;
+    }
+    TransformationMatrix zoom;
+    zoom.scale(scale);
+
+#if DEBUG_WEBPAGE_LOAD
+    if (loadState() < Finished)
+        Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomAboutPoint scale %f anchor (%f, %f)", scale, anchor.x(), anchor.y());
+#endif
+
+    // Our current scroll position in float.
+    FloatPoint scrollPosition = this->scrollPosition();
+
+    // Anchor offset from scroll position in float.
+    FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y());
+
+    // The horizontal scaling factor and vertical scaling factor should be equal
+    // to preserve aspect ratio of content.
+    ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22());
+
+    // Need to invert the previous transform to anchor the viewport.
+    double inverseScale = scale / m_transformationMatrix->m11();
+
+    // Actual zoom.
+    *m_transformationMatrix = zoom;
+
+    // Suspend all screen updates to the backingstore.
+    m_backingStore->d->suspendScreenAndBackingStoreUpdates();
+
+    updateViewportSize();
+
+    IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))),
+                                        max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale)))));
+
+    if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
+        // This is a hack for email which has reflow always turned on.
+        m_mainFrame->view()->setNeedsLayout();
+        requestLayoutIfNeeded();
+        if (m_currentPinchZoomNode)
+            newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale);
+         m_currentPinchZoomNode = 0;
+         m_anchorInNodeRectRatio = FloatPoint(-1, -1);
+    }
+
+    setScrollPosition(newScrollPosition);
+
+    notifyTransformChanged();
+
+    bool isLoading = this->isLoading();
+
+    // We need to invalidate all tiles both visible and non-visible if we're loading.
+    m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */);
+
+    m_client->resetBitmapZoomScale(m_transformationMatrix->m11());
+
+    bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering;
+    bool shouldClearVisibleZoom = isLoading && shouldRender;
+
+    if (shouldClearVisibleZoom) {
+        // If we are loading and rendering then we need to clear the render queue's
+        // visible zoom jobs as they will be irrelevant with the render below.
+        m_backingStore->d->clearVisibleZoom();
+    }
+
+    // Clear window to make sure there are no artifacts.
+    if (shouldRender) {
+        m_backingStore->d->clearWindow();
+        // Resume all screen updates to the backingstore and render+blit visible contents to screen.
+        m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
+    } else {
+        // Resume all screen updates to the backingstore but do not blit to the screen because we not rendering.
+        m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
+    }
+
+    m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
+
+    return true;
+}
+
+IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale)
+{
+    // Should only be invoked when text reflow is enabled.
+    ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
+
+    int offsetY = 0;
+    int offsetX = 0;
+
+    IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
+
+    if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) {
+        offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y();
+        if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0)
+            offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale;
+    }
+
+    IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get());
+
+    return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))),
+                    max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale))));
+}
+
+bool WebPagePrivate::scheduleZoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering)
+{
+    double scale;
+    if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
+        // We could be back to the right zoom level before the timer has
+        // timed out, because of wiggling back and forth. Stop the timer.
+        unscheduleZoomAboutPoint();
+        return false;
+    }
+
+    // For some reason, the bitmap zoom wants an anchor in backingstore coordinates!
+    // this is different from zoomAboutPoint, which wants content coordinates.
+    // See RIM Bug #641.
+
+    FloatPoint transformedAnchor = mapToTransformedFloatPoint(anchor);
+    FloatPoint transformedScrollPosition = mapToTransformedFloatPoint(scrollPosition());
+
+    // Prohibit backingstore from updating the window overtop of the bitmap.
+    m_backingStore->d->suspendScreenAndBackingStoreUpdates();
+
+    // Need to invert the previous transform to anchor the viewport.
+    double zoomFraction = scale / transformationMatrix()->m11();
+
+    // Anchor offset from scroll position in float.
+    FloatPoint anchorOffset(transformedAnchor.x() - transformedScrollPosition.x(),
+                            transformedAnchor.y() - transformedScrollPosition.y());
+
+    IntPoint srcPoint(
+        static_cast<int>(roundf(transformedAnchor.x() - anchorOffset.x() / zoomFraction)),
+        static_cast<int>(roundf(transformedAnchor.y() - anchorOffset.y() / zoomFraction)));
+
+    const IntRect viewportRect = IntRect(IntPoint::zero(), transformedViewportSize());
+    const IntRect dstRect = viewportRect;
+
+    // This is the rect to pass as the actual source rect in the backingstore
+    // for the transform given by zoom.
+    IntRect srcRect(srcPoint.x(),
+                    srcPoint.y(),
+                    viewportRect.width() / zoomFraction,
+                    viewportRect.height() / zoomFraction);
+    m_backingStore->d->blitContents(dstRect, srcRect);
+
+    m_delayedZoomArguments.scale = scale;
+    m_delayedZoomArguments.anchor = anchor;
+    m_delayedZoomArguments.enforceScaleClamping = enforceScaleClamping;
+    m_delayedZoomArguments.forceRendering = forceRendering;
+    m_delayedZoomTimer->startOneShot(delayedZoomInterval);
+
+    return true;
+}
+
+void WebPagePrivate::unscheduleZoomAboutPoint()
+{
+    if (m_delayedZoomTimer->isActive())
+        m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
+
+    m_delayedZoomTimer->stop();
+}
+
+void WebPagePrivate::zoomAboutPointTimerFired(Timer<WebPagePrivate>*)
+{
+    zoomAboutPoint(m_delayedZoomArguments.scale, m_delayedZoomArguments.anchor, m_delayedZoomArguments.enforceScaleClamping, m_delayedZoomArguments.forceRendering);
+}
+
+void WebPagePrivate::setNeedsLayout()
+{
+    FrameView* view = m_mainFrame->view();
+    ASSERT(view);
+    view->setNeedsLayout();
+}
+
+void WebPagePrivate::requestLayoutIfNeeded() const
+{
+    FrameView* view = m_mainFrame->view();
+    ASSERT(view);
+    view->updateLayoutAndStyleIfNeededRecursive();
+    ASSERT(!view->needsLayout());
+}
+
+IntPoint WebPagePrivate::scrollPosition() const
+{
+    return m_backingStoreClient->scrollPosition();
+}
+
+IntPoint WebPagePrivate::maximumScrollPosition() const
+{
+    return m_backingStoreClient->maximumScrollPosition();
+}
+
+void WebPagePrivate::setScrollPosition(const IntPoint& pos)
+{
+    m_backingStoreClient->setScrollPosition(pos);
+}
+
+bool WebPagePrivate::shouldSendResizeEvent()
+{
+    if (!m_mainFrame->document())
+        return false;
+
+    // PR#96865 : Provide an option to always send resize events, regardless of the loading
+    //            status. The scenario for this are Sapphire applications which tend to
+    //            maintain an open GET request to the server. This open GET results in
+    //            webkit thinking that content is still arriving when at the application
+    //            level it is considered fully loaded.
+    //
+    //            NOTE: Care must be exercised in the use of this option, as it bypasses
+    //                  the sanity provided in 'isLoadingInAPISense()' below.
+    //
+    static const bool unrestrictedResizeEvents = Platform::Settings::get()->unrestrictedResizeEvents();
+    if (unrestrictedResizeEvents)
+        return true;
+
+    // Don't send the resize event if the document is loading. Some pages automatically reload
+    // when the window is resized; Safari on iPhone often resizes the window while setting up its
+    // viewport. This obviously can cause problems.
+    DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
+    if (documentLoader && documentLoader->isLoadingInAPISense())
+        return false;
+
+    return true;
+}
+
+void WebPagePrivate::willDeferLoading()
+{
+    m_client->willDeferLoading();
+}
+
+void WebPagePrivate::didResumeLoading()
+{
+    m_client->didResumeLoading();
+}
+
+bool WebPage::scrollBy(const Platform::IntSize& delta, bool scrollMainFrame)
+{
+    d->m_backingStoreClient->setIsClientGeneratedScroll(true);
+    bool b = d->scrollBy(delta.width(), delta.height(), scrollMainFrame);
+    d->m_backingStoreClient->setIsClientGeneratedScroll(false);
+    return b;
+}
+
+bool WebPagePrivate::scrollBy(int deltaX, int deltaY, bool scrollMainFrame)
+{
+    IntSize delta(deltaX, deltaY);
+    if (!scrollMainFrame) {
+        // We need to work around the fact that ::map{To,From}Transformed do not
+        // work well with negative values, like a negative width or height of an IntSize.
+        IntSize copiedDelta(IntSize(abs(delta.width()), abs(delta.height())));
+        IntSize untransformedCopiedDelta = mapFromTransformed(copiedDelta);
+        delta = IntSize(
+            delta.width() < 0 ? -untransformedCopiedDelta.width() : untransformedCopiedDelta.width(),
+            delta.height() < 0 ? -untransformedCopiedDelta.height(): untransformedCopiedDelta.height());
+
+        if (m_inRegionScrollStartingNode) {
+            if (scrollNodeRecursively(m_inRegionScrollStartingNode.get(), delta)) {
+                m_selectionHandler->selectionPositionChanged();
+                // FIXME: We have code in place to handle scrolling and clipping tap highlight
+                // on in-region scrolling. As soon as it is fast enough (i.e. we have it backed by
+                // a backing store), we can reliably make use of it in the real world.
+                // m_touchEventHandler->drawTapHighlight();
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    setScrollPosition(scrollPosition() + delta);
+    return true;
+}
+
+void WebPage::notifyInRegionScrollStatusChanged(bool status)
+{
+    d->notifyInRegionScrollStatusChanged(status);
+}
+
+void WebPagePrivate::notifyInRegionScrollStatusChanged(bool status)
+{
+    if (!status && m_inRegionScrollStartingNode) {
+        enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(m_inRegionScrollStartingNode.get());
+        m_inRegionScrollStartingNode = 0;
+    }
+}
+
+void WebPagePrivate::enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(Node* scrolledNode)
+{
+    ASSERT(scrolledNode);
+    if (scrolledNode->isDocumentNode()) {
+        Frame* frame = static_cast<const Document*>(scrolledNode)->frame();
+        ASSERT(frame);
+        if (!frame)
+            return;
+        ASSERT(frame != m_mainFrame);
+        FrameView* view = frame->view();
+        if (!view)
+            return;
+
+        // Steps:
+        // #1 - Get frame rect in contents coords.
+        // #2 - Get the clipped scrollview rect in contents coords.
+        // #3 - Take transform into account for 1 and 2.
+        // #4 - Subtract 2 from 1, so we know exactly which areas of the frame
+        //      are offscreen, and need async repainting.
+        FrameView* mainFrameView = m_mainFrame->view();
+        ASSERT(mainFrameView);
+        IntRect frameRect = view->frameRect();
+        frameRect = frame->tree()->parent()->view()->contentsToWindow(frameRect);
+        frameRect = mainFrameView->windowToContents(frameRect);
+
+        IntRect visibleWindowRect = getRecursiveVisibleWindowRect(view);
+        IntRect visibleContentsRect = mainFrameView->windowToContents(visibleWindowRect);
+
+        IntRect transformedFrameRect = mapToTransformed(frameRect);
+        IntRect transformedVisibleContentsRect = mapToTransformed(visibleContentsRect);
+
+        Platform::IntRectRegion offscreenRegionOfIframe
+            = Platform::IntRectRegion::subtractRegions(Platform::IntRect(transformedFrameRect), Platform::IntRect(transformedVisibleContentsRect));
+
+        if (!offscreenRegionOfIframe.isEmpty())
+            m_backingStore->d->m_renderQueue->addToQueue(RenderQueue::RegularRender, offscreenRegionOfIframe.rects());
+    }
+}
+
+void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
+{
+    if (b != m_hasInRegionScrollableAreas)
+        m_hasInRegionScrollableAreas = b;
+}
+
+IntSize WebPagePrivate::viewportSize() const
+{
+    return mapFromTransformed(transformedViewportSize());
+}
+
+IntSize WebPagePrivate::actualVisibleSize() const
+{
+    return mapFromTransformed(transformedActualVisibleSize());
+}
+
+bool WebPagePrivate::hasVirtualViewport() const
+{
+    return m_virtualViewportWidth && m_virtualViewportHeight;
+}
+
+void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
+{
+    ASSERT(m_mainFrame->view());
+    if (setFixedReportedSize)
+        m_mainFrame->view()->setFixedReportedSize(actualVisibleSize());
+
+    IntRect frameRect = IntRect(scrollPosition(), viewportSize());
+    if (frameRect != m_mainFrame->view()->frameRect()) {
+        m_mainFrame->view()->setFrameRect(frameRect);
+        m_mainFrame->view()->adjustViewSize();
+    }
+
+    // We're going to need to send a resize event to JavaScript because
+    // innerWidth and innerHeight depend on fixed reported size.
+    // This is how we support mobile pages where JavaScript resizes
+    // the page in order to get around the fixed layout size, e.g.
+    // google maps when it detects a mobile user agent.
+    if (sendResizeEvent && shouldSendResizeEvent())
+        m_mainFrame->eventHandler()->sendResizeEvent();
+
+    // When the actual visible size changes, we also
+    // need to reposition fixed elements.
+    m_mainFrame->view()->repaintFixedElementsAfterScrolling();
+}
+
+FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
+{
+    // The visible contents rect in float.
+    FloatRect visibleContentsRect = this->visibleContentsRect();
+
+    // The center of the visible contents rect in float.
+    return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
+                      visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
+}
+
+IntRect WebPagePrivate::visibleContentsRect() const
+{
+    return m_backingStoreClient->visibleContentsRect();
+}
+
+IntSize WebPagePrivate::contentsSize() const
+{
+    if (!m_mainFrame->view())
+        return IntSize();
+
+    return m_backingStoreClient->contentsSize();
+}
+
+IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
+{
+    if (!m_mainFrame->contentRenderer())
+        return IntSize();
+
+    return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
+}
+
+void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
+{
+    if (m_previousContentsSize == contentsSize)
+        return;
+
+    // This should only occur in the middle of layout so we set a flag here and
+    // handle it at the end of the layout.
+    m_contentsSizeChanged = true;
+
+#if DEBUG_WEBPAGE_LOAD
+    Platform::log(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %dx%d", contentsSize.width(), contentsSize.height());
+#endif
+}
+
+void WebPagePrivate::layoutFinished()
+{
+    if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
+        return;
+
+    m_contentsSizeChanged = false; // Toggle to turn off notification again.
+    m_overflowExceedsContentsSize = false;
+
+    if (contentsSize().isEmpty())
+        return;
+
+    // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from
+    // the middle of a layout, but the recursion is limited by detection code in
+    // setViewMode() and mitigation code in fixedLayoutSize().
+    if (didLayoutExceedMaximumIterations()) {
+        notifyTransformedContentsSizeChanged();
+        return;
+    }
+
+    // Temporarily save the m_previousContentsSize here before updating it (in
+    // notifyTransformedContentsSizeChanged()) so we can compare if our contents
+    // shrunk afterwards.
+    IntSize previousContentsSize = m_previousContentsSize;
+
+    m_nestedLayoutFinishedCount++;
+
+    if (loadState() == Committed)
+        zoomToInitialScaleOnLoad();
+    else if (loadState() != None)
+        notifyTransformedContentsSizeChanged();
+
+    m_nestedLayoutFinishedCount--;
+
+    if (!m_nestedLayoutFinishedCount) {
+        // When the contents shrinks, there is a risk that we
+        // will be left at a scroll position that lies outside of the
+        // contents rect. Since we allow overscrolling and neglect
+        // to clamp overscroll in order to retain input focus (RIM Bug #414)
+        // we need to clamp somewhere, and this is where we know the
+        // contents size has changed.
+
+        if (contentsSize() != previousContentsSize) {
+
+            IntPoint newScrollPosition = scrollPosition();
+
+            if (contentsSize().height() < previousContentsSize.height()) {
+                IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
+                newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
+            }
+
+            if (contentsSize().width() < previousContentsSize.width()) {
+                IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
+                newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
+            }
+
+            if (newScrollPosition != scrollPosition()) {
+                setScrollPosition(newScrollPosition);
+                notifyTransformedScrollChanged();
+            }
+        }
+    }
+}
+
+void WebPagePrivate::zoomToInitialScaleOnLoad()
+{
+#if DEBUG_WEBPAGE_LOAD
+    Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
+#endif
+
+    bool needsLayout = false;
+
+    // If the contents width exceeds the viewport width set to desktop mode.
+    if (m_shouldUseFixedDesktopMode)
+        needsLayout = setViewMode(FixedDesktop);
+    else
+        needsLayout = setViewMode(Desktop);
+
+    if (needsLayout) {
+        // This can cause recursive layout...
+        setNeedsLayout();
+    }
+
+    if (contentsSize().isEmpty()) {
+#if DEBUG_WEBPAGE_LOAD
+        Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
+#endif
+        requestLayoutIfNeeded();
+        m_client->resetBitmapZoomScale(currentScale());
+        notifyTransformedContentsSizeChanged();
+        return;
+    }
+
+    bool performedZoom = false;
+    bool shouldZoom = !m_userPerformedManualZoom;
+
+    // If this load should restore view state, don't zoom to initial scale
+    // but instead let the HistoryItem's saved viewport reign supreme.
+    if (m_mainFrame && m_mainFrame->loader() && m_mainFrame->loader()->shouldRestoreScrollPositionAndViewState())
+        shouldZoom = false;
+
+    if (shouldZoom && loadState() == Committed) {
+        // Preserve at top and at left position, to avoid scrolling
+        // to a non top-left position for web page with viewport meta tag
+        // that specifies an initial-scale that is zoomed in.
+        FloatPoint anchor = centerOfVisibleContentsRect();
+        if (!scrollPosition().x())
+            anchor.setX(0);
+        if (!scrollPosition().y())
+            anchor.setY(0);
+        performedZoom = zoomAboutPoint(initialScale(), anchor);
+    }
+
+    // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout...
+    requestLayoutIfNeeded();
+
+    if (!performedZoom) {
+        // We only notify if we didn't perform zoom, because zoom will notify on
+        // its own...
+        m_client->resetBitmapZoomScale(currentScale());
+        notifyTransformedContentsSizeChanged();
+    }
+}
+
+double WebPagePrivate::zoomToFitScale() const
+{
+    // We must clamp the contents for this calculation so that we do not allow an
+    // arbitrarily small zoomToFitScale much like we clamp the fixedLayoutSize()
+    // so that we do not have arbitrarily large layout size.
+    // If we have a specified viewport, we may need to be able to zoom out more.
+    int contentWidth = std::min(contentsSize().width(), std::max(m_virtualViewportWidth, static_cast<int>(defaultMaxLayoutSize().width())));
+
+    // defaultMaxLayoutSize().width() is a safeguard for excessively large page layouts that
+    // is too restrictive for image documents. In this case, the document width is sufficient.
+    Document* doc = m_page->mainFrame()->document();
+    if (doc && doc->isImageDocument())
+       contentWidth = contentsSize().width();
+
+    // If we have a virtual viewport and its aspect ratio caused content to layout
+    // wider than the default layout aspect ratio we need to zoom to fit the content height
+    // in order to avoid showing a grey area below the web page.
+    // Without virtual viewport we can never get into this situation.
+    if (hasVirtualViewport()) {
+        int contentHeight = std::min(contentsSize().height(), std::max(m_virtualViewportHeight, static_cast<int>(defaultMaxLayoutSize().height())));
+
+        // Aspect ratio check without division.
+        if (contentWidth * m_defaultLayoutSize.height() > contentHeight * m_defaultLayoutSize.width())
+            return contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
+    }
+
+    return contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
+}
+
+double WebPagePrivate::initialScale() const
+{
+    if (m_initialScale > 0.0)
+        return m_initialScale;
+
+    if (m_webSettings->isZoomToFitOnLoad())
+        return zoomToFitScale();
+
+    return 1.0;
+}
+
+void WebPage::initializeIconDataBase()
+{
+    IconDatabaseClientBlackBerry::getInstance()->initIconDatabase(d->m_webSettings);
+}
+
+bool WebPage::isUserScalable() const
+{
+    return d->isUserScalable();
+}
+
+double WebPage::currentScale() const
+{
+    return d->currentScale();
+}
+
+double WebPage::initialScale() const
+{
+    return d->initialScale();
+}
+
+double WebPage::zoomToFitScale() const
+{
+    return d->zoomToFitScale();
+}
+
+void WebPage::setInitialScale(double initialScale)
+{
+    d->setInitialScale(initialScale);
+}
+
+double WebPage::minimumScale() const
+{
+    return d->minimumScale();
+}
+
+void WebPage::setMinimumScale(double minimumScale)
+{
+    d->setMinimumScale(minimumScale);
+}
+
+double WebPage::maximumScale() const
+{
+    return d->maximumScale();
+}
+
+void WebPage::setMaximumScale(double maximumScale)
+{
+    d->setMaximumScale(maximumScale);
+}
+
+double WebPagePrivate::maximumScale() const
+{
+    if (m_maximumScale >= zoomToFitScale() && m_maximumScale >= m_minimumScale)
+        return m_maximumScale;
+
+    return hasVirtualViewport() ? std::max<double>(zoomToFitScale(), 4.0) : 4.0;
+}
+
+void WebPagePrivate::resetScales()
+{
+    TransformationMatrix identity;
+    *m_transformationMatrix = identity;
+    m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0;
+    m_minimumScale = -1.0;
+    m_maximumScale = -1.0;
+
+    // We have to let WebCore know about updated framerect now that we've
+    // reset our scales. See: RIM Bug #401.
+    updateViewportSize();
+}
+
+IntPoint WebPagePrivate::transformedScrollPosition() const
+{
+    return m_backingStoreClient->transformedScrollPosition();
+}
+
+IntPoint WebPagePrivate::transformedMaximumScrollPosition() const
+{
+    return m_backingStoreClient->transformedMaximumScrollPosition();
+}
+
+IntSize WebPagePrivate::transformedActualVisibleSize() const
+{
+    return IntSize(m_actualVisibleWidth, m_actualVisibleHeight);
+}
+
+IntSize WebPagePrivate::transformedViewportSize() const
+{
+    return Platform::Graphics::Screen::size();
+}
+
+IntRect WebPagePrivate::transformedVisibleContentsRect() const
+{
+    // Usually this would be mapToTransformed(visibleContentsRect()), but
+    // that results in rounding errors because we already set the WebCore
+    // viewport size from our original transformedViewportSize().
+    // Instead, we only transform the scroll position and take the
+    // viewport size as it is, which ensures that e.g. blitting operations
+    // always cover the whole widget/screen.
+    return IntRect(transformedScrollPosition(), transformedViewportSize());
+}
+
+IntSize WebPagePrivate::transformedContentsSize() const
+{
+    // mapToTransformed() functions use this method to crop their results,
+    // so we can't make use of them here. While we want rounding inside page
+    // boundaries to extend rectangles and round points, we need to crop the
+    // contents size to the floored values so that we don't try to display
+    // or report points that are not fully covered by the actual float-point
+    // contents rectangle.
+    const IntSize untransformedContentsSize = contentsSize();
+    const FloatPoint transformedBottomRight = m_transformationMatrix->mapPoint(
+        FloatPoint(untransformedContentsSize.width(), untransformedContentsSize.height()));
+    return IntSize(floorf(transformedBottomRight.x()), floorf(transformedBottomRight.y()));
+}
+
+IntPoint WebPagePrivate::mapFromContentsToViewport(const IntPoint& point) const
+{
+    return m_backingStoreClient->mapFromContentsToViewport(point);
+}
+
+IntPoint WebPagePrivate::mapFromViewportToContents(const IntPoint& point) const
+{
+    return m_backingStoreClient->mapFromViewportToContents(point);
+}
+
+IntRect WebPagePrivate::mapFromContentsToViewport(const IntRect& rect) const
+{
+    return m_backingStoreClient->mapFromContentsToViewport(rect);
+}
+
+IntRect WebPagePrivate::mapFromViewportToContents(const IntRect& rect) const
+{
+    return m_backingStoreClient->mapFromViewportToContents(rect);
+}
+
+IntPoint WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntPoint& point) const
+{
+    return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(point);
+}
+
+IntPoint WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntPoint& point) const
+{
+    return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(point);
+}
+
+IntRect WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntRect& rect) const
+{
+    return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(rect);
+}
+
+IntRect WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntRect& rect) const
+{
+    return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(rect);
+}
+
+// NOTE: PIXEL ROUNDING!
+// Accurate back-and-forth rounding is not possible with information loss
+// by integer points and sizes, so we always expand the resulting mapped
+// float rectangles to the nearest integer. For points, we always use
+// floor-rounding in mapToTransformed() so that we don't have to crop to
+// the (floor'd) transformed contents size.
+static inline IntPoint roundTransformedPoint(const FloatPoint &point)
+{
+    // Maps by rounding half towards zero.
+    return IntPoint(static_cast<int>(floorf(point.x())), static_cast<int>(floorf(point.y())));
+}
+
+static inline IntPoint roundUntransformedPoint(const FloatPoint &point)
+{
+    // Maps by rounding half away from zero.
+    return IntPoint(static_cast<int>(ceilf(point.x())), static_cast<int>(ceilf(point.y())));
+}
+
+IntPoint WebPagePrivate::mapToTransformed(const IntPoint& point) const
+{
+    return roundTransformedPoint(m_transformationMatrix->mapPoint(FloatPoint(point)));
+}
+
+FloatPoint WebPagePrivate::mapToTransformedFloatPoint(const FloatPoint& point) const
+{
+    return m_transformationMatrix->mapPoint(point);
+}
+
+IntPoint WebPagePrivate::mapFromTransformed(const IntPoint& point) const
+{
+    return roundUntransformedPoint(m_transformationMatrix->inverse().mapPoint(FloatPoint(point)));
+}
+
+FloatPoint WebPagePrivate::mapFromTransformedFloatPoint(const FloatPoint& point) const
+{
+    return m_transformationMatrix->inverse().mapPoint(point);
+}
+
+FloatRect WebPagePrivate::mapFromTransformedFloatRect(const FloatRect& rect) const
+{
+    return m_transformationMatrix->inverse().mapRect(rect);
+}
+
+IntSize WebPagePrivate::mapToTransformed(const IntSize& size) const
+{
+    return mapToTransformed(IntRect(IntPoint::zero(), size)).size();
+}
+
+IntSize WebPagePrivate::mapFromTransformed(const IntSize& size) const
+{
+    return mapFromTransformed(IntRect(IntPoint::zero(), size)).size();
+}
+
+IntRect WebPagePrivate::mapToTransformed(const IntRect& rect) const
+{
+    return enclosingIntRect(m_transformationMatrix->mapRect(FloatRect(rect)));
+}
+
+// Use this in conjunction with mapToTransformed(IntRect), in most cases.
+void WebPagePrivate::clipToTransformedContentsRect(IntRect& rect) const
+{
+    rect.intersect(IntRect(IntPoint::zero(), transformedContentsSize()));
+}
+
+IntRect WebPagePrivate::mapFromTransformed(const IntRect& rect) const
+{
+    return enclosingIntRect(m_transformationMatrix->inverse().mapRect(FloatRect(rect)));
+}
+
+bool WebPagePrivate::transformedPointEqualsUntransformedPoint(const IntPoint& transformedPoint, const IntPoint& untransformedPoint)
+{
+    // Scaling down is always more accurate than scaling up.
+    if (m_transformationMatrix->a() > 1.0)
+        return transformedPoint == mapToTransformed(untransformedPoint);
+
+    return mapFromTransformed(transformedPoint) == untransformedPoint;
+}
+
+void WebPagePrivate::notifyTransformChanged()
+{
+    notifyTransformedContentsSizeChanged();
+    notifyTransformedScrollChanged();
+
+    m_backingStore->d->transformChanged();
+}
+
+void WebPagePrivate::notifyTransformedContentsSizeChanged()
+{
+    // We mark here as the last reported content size we sent to the client.
+    m_previousContentsSize = contentsSize();
+
+    const IntSize size = transformedContentsSize();
+    m_backingStore->d->contentsSizeChanged(size);
+    m_client->contentsSizeChanged(size);
+    m_selectionHandler->selectionPositionChanged();
+}
+
+void WebPagePrivate::notifyTransformedScrollChanged()
+{
+    const IntPoint pos = transformedScrollPosition();
+    m_backingStore->d->scrollChanged(pos);
+    m_client->scrollChanged(pos);
+}
+
+bool WebPagePrivate::setViewMode(ViewMode mode)
+{
+    if (!m_mainFrame->view())
+        return false;
+
+    m_viewMode = mode;
+
+    // If we're in the middle of a nested layout with a recursion count above
+    // some maximum threshold, then our algorithm for finding the minimum content
+    // width of a given page has become dependent on the visible width.
+    //
+    // We need to find some method to ensure that we don't experience excessive
+    // and even infinite recursion. This can even happen with valid html. The
+    // former can happen when we run into inline text with few candidates for line
+    // break. The latter can happen for instance if the page has a negative margin
+    // set against the right border. Note: this is valid by spec and can lead to
+    // a situation where there is no value for which the content width will ensure
+    // no horizontal scrollbar.
+    // Example: LayoutTests/css1/box_properties/margin.html
+    //
+    // In order to address such situations when we detect a recursion above some
+    // maximum threshold we snap our fixed layout size to a defined quantum increment.
+    // Eventually, either the content width will be satisfied to ensure no horizontal
+    // scrollbar or this increment will run into the maximum layout size and the
+    // recursion will necessarily end.
+    bool snapToIncrement = didLayoutExceedMaximumIterations();
+
+    IntSize currentSize = m_mainFrame->view()->fixedLayoutSize();
+    IntSize newSize = fixedLayoutSize(snapToIncrement);
+    if (currentSize == newSize)
+        return false;
+
+    // FIXME: Temp solution. We'll get back to this.
+    if (m_nestedLayoutFinishedCount) {
+        double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width());
+        double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height());
+        if (widthChange < 0.05 && heightChange < 0.05)
+            return false;
+    }
+
+    m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
+    m_mainFrame->view()->setFixedLayoutSize(newSize);
+    return true; // Needs re-layout!
+}
+
+void WebPagePrivate::setCursor(PlatformCursorHandle handle)
+{
+    if (m_currentCursor.type() != handle.type()) {
+        m_currentCursor = handle;
+        m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot().x(), handle.hotspot().y());
+    }
+}
+
+Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory()
+{
+    return m_client->networkStreamFactory();
+}
+
+Platform::Graphics::Window* WebPagePrivate::platformWindow() const
+{
+    return m_client->window();
+}
+
+void WebPagePrivate::setPreventsScreenDimming(bool keepAwake)
+{
+    if (keepAwake) {
+        if (!m_preventIdleDimmingCount)
+            m_client->setPreventsScreenIdleDimming(true);
+        m_preventIdleDimmingCount++;
+    } else if (m_preventIdleDimmingCount > 0) {
+        m_preventIdleDimmingCount--;
+        if (!m_preventIdleDimmingCount)
+            m_client->setPreventsScreenIdleDimming(false);
+    } else
+        ASSERT_NOT_REACHED(); // SetPreventsScreenIdleDimming(false) called too many times.
+}
+
+void WebPagePrivate::showVirtualKeyboard(bool showKeyboard)
+{
+    m_client->showVirtualKeyboard(showKeyboard);
+}
+
+void WebPagePrivate::ensureContentVisible(bool centerInView)
+{
+    m_inputHandler->ensureFocusElementVisible(centerInView);
+}
+
+void WebPagePrivate::zoomToContentRect(const IntRect& rect)
+{
+    // Don't scale if the user is not supposed to scale.
+    if (!isUserScalable())
+        return;
+
+    FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y());
+    IntSize viewSize = viewportSize();
+
+    // Calculate the scale required to scale that dimension to fit.
+    double scaleH = (double)viewSize.width() / (double)rect.width();
+    double scaleV = (double)viewSize.height() / (double)rect.height();
+
+    // Choose the smaller scale factor so that all of the content is visible.
+    zoomAboutPoint(min(scaleH, scaleV), anchor);
+}
+
+void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister)
+{
+    if (shouldRegister)
+        m_pluginViews.add(plugin);
+    else
+        m_pluginViews.remove(plugin);
+}
+
+#define FOR_EACH_PLUGINVIEW(pluginViews) \
+    HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \
+    HashSet<PluginView*>::const_iterator last = pluginViews.end(); \
+    for (; it != last; ++it)
+
+void WebPagePrivate::notifyPageOnLoad()
+{
+    FOR_EACH_PLUGINVIEW(m_pluginViews)
+        (*it)->handleOnLoadEvent();
+}
+
+bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
+{
+    return m_client->shouldPluginEnterFullScreen();
+}
+
+void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
+{
+    m_fullScreenPluginView = plugin;
+    m_client->didPluginEnterFullScreen();
+    Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix);
+    m_client->window()->setSensitivityFullscreenOverride(true);
+}
+
+void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* windowUniquePrefix)
+{
+    m_fullScreenPluginView = 0;
+    m_client->didPluginExitFullScreen();
+    Platform::Graphics::Window::setTransparencyDiscardFilter(0);
+    m_client->window()->setSensitivityFullscreenOverride(false);
+}
+
+void WebPagePrivate::onPluginStartBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
+{
+    m_client->onPluginStartBackgroundPlay();
+}
+
+void WebPagePrivate::onPluginStopBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
+{
+    m_client->onPluginStopBackgroundPlay();
+}
+
+bool WebPagePrivate::lockOrientation(bool landscape)
+{
+    return m_client->lockOrientation(landscape);
+}
+
+void WebPagePrivate::unlockOrientation()
+{
+    return m_client->unlockOrientation();
+}
+
+int WebPagePrivate::orientation() const
+{
+#if ENABLE(ORIENTATION_EVENTS)
+    return m_mainFrame->orientation();
+#else
+#error ORIENTATION_EVENTS must be defined.
+// Or a copy of the orientation value will have to be stored in these objects.
+#endif
+}
+
+double WebPagePrivate::currentZoomFactor() const
+{
+    return currentScale();
+}
+
+int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype)
+{
+    return m_client->showAlertDialog(atype);
+}
+
+bool WebPagePrivate::isActive() const
+{
+    return m_client->isActive();
+}
+
+bool WebPagePrivate::useFixedLayout() const
+{
+    return true;
+}
+
+ActiveNodeContext WebPagePrivate::activeNodeContext(TargetDetectionStrategy strategy)
+{
+    ActiveNodeContext context;
+
+    RefPtr<Node> node = contextNode(strategy);
+    m_currentContextNode = node;
+    if (!m_currentContextNode)
+        return context;
+
+    requestLayoutIfNeeded();
+
+    bool nodeAllowSelectionOverride = false;
+    if (Node* linkNode = node->enclosingLinkEventParentOrSelf()) {
+        KURL href;
+        if (linkNode->isLink() && linkNode->hasAttributes()) {
+            if (Attribute* attribute = linkNode->attributes()->getAttributeItem(HTMLNames::hrefAttr))
+                href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
+        }
+
+        String pattern = findPatternStringForUrl(href);
+        if (!pattern.isEmpty())
+            context.setPattern(pattern);
+
+        if (!href.string().isEmpty()) {
+            context.setUrl(href.string());
+
+            // Links are non-selectable by default, but selection should be allowed
+            // providing the page is selectable, use the parent to determine it.
+            if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
+                nodeAllowSelectionOverride = true;
+        }
+    }
+
+    if (!nodeAllowSelectionOverride && !node->canStartSelection())
+        context.resetFlag(ActiveNodeContext::IsSelectable);
+
+    if (node->isHTMLElement()) {
+        HTMLImageElement* imageElement = 0;
+        if (node->hasTagName(HTMLNames::imgTag))
+            imageElement = static_cast<HTMLImageElement*>(node.get());
+        else if (node->hasTagName(HTMLNames::areaTag))
+            imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement();
+        if (imageElement && imageElement->renderer()) {
+            // FIXME: At the mean time, we only show "Save Image" when the image data is available.
+            if (CachedResource* cachedResource = imageElement->cachedImage()) {
+                if (cachedResource->isLoaded() && cachedResource->data()) {
+                    String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
+                    context.setImageSrc(node->document()->completeURL(url).string());
+                }
+            }
+            String alt = imageElement->altText();
+            if (!alt.isNull())
+                context.setImageAlt(alt);
+        }
+    }
+
+    if (node->isTextNode()) {
+        Text* curText = static_cast<Text*>(node.get());
+        if (!curText->wholeText().isEmpty())
+            context.setText(curText->wholeText());
+    }
+
+    if (node->isElementNode()) {
+        Element* element = static_cast<Element*>(node->shadowAncestorNode());
+        if (DOMSupport::isTextBasedContentEditableElement(element)) {
+            context.setFlag(ActiveNodeContext::IsInput);
+            if (element->hasTagName(HTMLNames::inputTag))
+                context.setFlag(ActiveNodeContext::IsSingleLine);
+            if (DOMSupport::isPasswordElement(element))
+                context.setFlag(ActiveNodeContext::IsPassword);
+
+            String elementText(DOMSupport::inputElementText(element));
+            if (!elementText.stripWhiteSpace().isEmpty())
+                context.setText(elementText);
+        }
+    }
+
+    if (node->isFocusable())
+        context.setFlag(ActiveNodeContext::IsFocusable);
+
+    return context;
+}
+
+void WebPagePrivate::updateCursor()
+{
+    int buttonMask = 0;
+    if (m_lastMouseEvent.button() == LeftButton)
+        buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
+    else if (m_lastMouseEvent.button() == MiddleButton)
+        buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
+    else if (m_lastMouseEvent.button() == RightButton)
+        buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
+
+    Platform::MouseEvent event(buttonMask, buttonMask, mapToTransformed(m_lastMouseEvent.pos()), mapToTransformed(m_lastMouseEvent.globalPos()), 0, 0);
+    m_webPage->mouseEvent(event);
+}
+
+IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
+{
+    if (hasVirtualViewport())
+        return IntSize(m_virtualViewportWidth, m_virtualViewportHeight);
+
+    const int defaultLayoutWidth = m_defaultLayoutSize.width();
+    const int defaultLayoutHeight = m_defaultLayoutSize.height();
+
+    int minWidth = defaultLayoutWidth;
+    int maxWidth = defaultMaxLayoutSize().width();
+    int maxHeight = defaultMaxLayoutSize().height();
+
+    // If the load state is none then we haven't actually got anything yet, but we need to layout
+    // the entire page so that the user sees the entire page (unrendered) instead of just part of it.
+    if (m_loadState == None)
+        return IntSize(defaultLayoutWidth, defaultLayoutHeight);
+
+    if (m_viewMode == FixedDesktop) {
+        int width  = maxWidth;
+        // if the defaultLayoutHeight is at minimum, it probably was set as 0
+        // and clamped, meaning it's effectively not set.  (Even if it happened
+        // to be set exactly to the minimum, it's too small to be useful.)  So
+        // ignore it.
+        int height;
+        if (defaultLayoutHeight <= minimumLayoutSize.height())
+            height = maxHeight;
+        else
+            height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
+        return IntSize(width, height);
+    }
+
+    if (m_viewMode == Desktop) {
+        // If we detect an overflow larger than the contents size then use that instead since
+        // it'll still be clamped by the maxWidth below...
+        int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
+
+        if (snapToIncrement) {
+            // Snap to increments of defaultLayoutWidth / 2.0.
+            float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
+            factor = ceilf(factor);
+            width = (defaultLayoutWidth / 2.0) * factor;
+        }
+
+        if (width < minWidth)
+            width = minWidth;
+        if (width > maxWidth)
+            width = maxWidth;
+        int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
+        return IntSize(width, height);
+    }
+
+    if (m_webSettings->isZoomToFitOnLoad()) {
+        // We need to clamp the layout width to the minimum of the layout
+        // width or the content width. This is important under rotation for mobile
+        // websites. We want the page to remain layouted at the same width which
+        // it was loaded with, and instead change the zoom level to fit to screen.
+        // The height is welcome to adapt to the height used in the new orientation,
+        // otherwise we will get a grey bar below the web page.
+        if (m_mainFrame->view() && !contentsSize().isEmpty())
+            minWidth = contentsSize().width();
+        else {
+            // If there is no contents width, use the minimum of screen width
+            // and layout width to shape the first layout to a contents width
+            // that we could reasonably zoom to fit, in a manner that takes
+            // orientation into account and still respects a small default
+            // layout width.
+#if ENABLE(ORIENTATION_EVENTS)
+            minWidth = m_mainFrame->orientation() % 180
+                ? Platform::Graphics::Screen::height()
+                : Platform::Graphics::Screen::width();
+#else
+            minWidth = Platform::Graphics::Screen::width();
+#endif
+        }
+    }
+
+    return IntSize(std::min(minWidth, defaultLayoutWidth), defaultLayoutHeight);
+}
+
+BackingStoreClient* WebPagePrivate::backingStoreClientForFrame(const Frame* frame) const
+{
+    ASSERT(frame);
+    BackingStoreClient* backingStoreClient = 0;
+    if (m_backingStoreClientForFrameMap.contains(frame))
+        backingStoreClient = m_backingStoreClientForFrameMap.get(frame);
+    return backingStoreClient;
+}
+
+void WebPagePrivate::addBackingStoreClientForFrame(const Frame* frame, BackingStoreClient* client)
+{
+    ASSERT(frame);
+    ASSERT(client);
+    m_backingStoreClientForFrameMap.add(frame, client);
+}
+
+void WebPagePrivate::removeBackingStoreClientForFrame(const Frame* frame)
+{
+    ASSERT(frame);
+    if (m_backingStoreClientForFrameMap.contains(frame))
+        m_backingStoreClientForFrameMap.remove(frame);
+}
+
+
+void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
+{
+    ASSERT(documentGoingAway);
+    if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
+        m_currentContextNode = 0;
+
+    if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
+        m_currentPinchZoomNode = 0;
+
+    if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
+        m_currentBlockZoomAdjustedNode = 0;
+
+    if (m_inRegionScrollStartingNode && m_inRegionScrollStartingNode->document() == documentGoingAway)
+        m_inRegionScrollStartingNode = 0;
+
+    Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
+    if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
+        m_touchEventHandler->resetLastFatFingersResult();
+
+    // NOTE: m_fullscreenVideoNode, m_fullScreenPluginView and m_pluginViews
+    // are cleared in other methods already.
+}
+
+typedef bool (*PredicateFunction)(RenderLayer*);
+static bool isPositionedContainer(RenderLayer* layer)
+{
+    RenderObject* o = layer->renderer();
+    return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform();
+}
+
+static bool isNonRenderViewFixedPositionedContainer(RenderLayer* layer)
+{
+    RenderObject* o = layer->renderer();
+    if (o->isRenderView())
+        return false;
+
+    return o->isPositioned() && o->style()->position() == FixedPosition;
+}
+
+static bool isFixedPositionedContainer(RenderLayer* layer)
+{
+    RenderObject* o = layer->renderer();
+    return o->isRenderView() || (o->isPositioned() && o->style()->position() == FixedPosition);
+}
+
+static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
+{
+    RenderLayer* curr = layer;
+    while (curr && !predicate(curr))
+        curr = curr->parent();
+
+    return curr;
+}
+
+RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
+{
+    return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
+}
+
+RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
+{
+    return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
+}
+
+static inline Frame* frameForNode(Node* node)
+{
+    Node* origNode = node;
+    for (; node; node = node->parentNode()) {
+        if (RenderObject* renderer = node->renderer()) {
+            if (renderer->isRenderView()) {
+                if (FrameView* view = toRenderView(renderer)->frameView()) {
+                    if (Frame* frame = view->frame())
+                        return frame;
+                }
+            }
+            if (renderer->isWidget()) {
+                Widget* widget = toRenderWidget(renderer)->widget();
+                if (widget && widget->isFrameView()) {
+                    if (Frame* frame = static_cast<FrameView*>(widget)->frame())
+                        return frame;
+                }
+            }
+        }
+    }
+
+    for (node = origNode; node; node = node->parentNode()) {
+        if (Document* doc = node->document()) {
+            if (Frame* frame = doc->frame())
+                return frame;
+        }
+    }
+
+    return 0;
+}
+
+static IntRect getNodeWindowRect(Node* node)
+{
+    if (Frame* frame = frameForNode(node)) {
+        if (FrameView* view = frame->view())
+            return view->contentsToWindow(node->getRect());
+    }
+    ASSERT_NOT_REACHED();
+    return IntRect();
+}
+
+IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
+{
+    ASSERT(m_mainFrame);
+
+    // Don't call this function asking to not clip the main frame providing only
+    // the main frame. All that can be returned is the content rect which
+    // isn't what this function is for.
+    if (noClipOfMainFrame && view == m_mainFrame->view()) {
+        ASSERT_NOT_REACHED();
+        return IntRect(IntPoint::zero(), view->contentsSize());
+    }
+
+    IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect(false)));
+    if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
+        // Intersect with parent visible rect.
+        visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
+    }
+    return visibleWindowRect;
+}
+
+void WebPage::assignFocus(Platform::FocusDirection direction)
+{
+    d->assignFocus(direction);
+}
+
+void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
+{
+    ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
+    ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
+    ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
+
+    // First we clear the focus, since we want to focus either initial or the last
+    // focusable element in the webpage (according to the TABINDEX), or simply clear
+    // the focus.
+    clearFocusNode();
+
+    switch (direction) {
+    case FocusDirectionForward:
+    case FocusDirectionBackward:
+        m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
+        break;
+    case FocusDirectionNone:
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+}
+
+Platform::IntRect WebPagePrivate::focusNodeRect()
+{
+    Frame* frame = focusedOrMainFrame();
+    if (!frame)
+        return Platform::IntRect();
+
+    Document* doc = frame->document();
+    FrameView* view = frame->view();
+    if (!doc || !view || view->needsLayout())
+        return Platform::IntRect();
+
+    IntRect focusRect = rectForNode(doc->focusedNode());
+    focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
+    focusRect = mapToTransformed(focusRect);
+    clipToTransformedContentsRect(focusRect);
+    return focusRect;
+}
+
+PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
+{
+    EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
+    const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
+    bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
+
+    // Unpress the mouse button always.
+    if (eventHandler->mousePressed())
+        eventHandler->setMousePressed(false);
+
+    // Check if we're using LinkToLink and the user is not touching the screen.
+    if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
+        RefPtr<Node> node;
+        node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
+        if (node) {
+            IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
+            if (!visibleRect.intersects(getNodeWindowRect(node.get())))
+                return 0;
+        }
+        return node.release();
+    }
+
+    // Check for text input.
+    if (isTouching && lastFatFingersResult.isTextInput())
+        return lastFatFingersResult.node(ShadowContentNotAllowed);
+
+    IntPoint contentPos;
+    if (isTouching)
+        contentPos = lastFatFingersResult.adjustedPosition();
+    else
+        contentPos = mapFromViewportToContents(m_lastMouseEvent.pos());
+
+    if (strategy == RectBased) {
+        FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
+        return result.node(ShadowContentNotAllowed);
+    }
+
+    HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos, false /*allowShadowContent*/);
+    return result.innerNode();
+}
+
+static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
+{
+    // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709).
+    double dx = static_cast<double>(p1.x() - p2.x());
+    double dy = static_cast<double>(p1.y() - p2.y());
+    return sqrt((dx * dx) + (dy * dy));
+}
+
+Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& point)
+{
+    IntPoint pt = mapFromTransformed(point);
+    IntRect clickRect(pt.x() - blockClickRadius, pt.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
+    Node* originalNode = nodeForZoomUnderPoint(point);
+    if (!originalNode)
+        return 0;
+    Node* node = bestChildNodeForClickRect(originalNode, clickRect);
+    return node ? adjustedBlockZoomNodeForZoomLimits(node) : adjustedBlockZoomNodeForZoomLimits(originalNode);
+}
+
+Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
+{
+    if (!parentNode)
+        return 0;
+
+    int bestDistance = std::numeric_limits<int>::max();
+
+    Node* node = parentNode->firstChild();
+    Node* bestNode = 0;
+    for (; node; node = node->nextSibling()) {
+        IntRect rect = rectForNode(node);
+        if (!clickRect.intersects(rect))
+            continue;
+
+        int distance = distanceBetweenPoints(rect.center(), clickRect.center());
+        Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
+        if (bestChildNode) {
+            IntRect bestChildRect = rectForNode(bestChildNode);
+            int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
+            if (bestChildDistance < distance && bestChildDistance < bestDistance) {
+                bestNode = bestChildNode;
+                bestDistance = bestChildDistance;
+            } else {
+                if (distance < bestDistance) {
+                    bestNode = node;
+                    bestDistance = distance;
+                }
+            }
+        } else {
+            if (distance < bestDistance) {
+                bestNode = node;
+                bestDistance = distance;
+            }
+        }
+    }
+
+    return bestNode;
+}
+
+double WebPagePrivate::maxBlockZoomScale() const
+{
+    return std::min(maximumBlockZoomScale, maximumScale());
+}
+
+Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& point)
+{
+    if (!m_mainFrame)
+        return 0;
+
+    HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromTransformed(point), false);
+
+    Node* node = result.innerNonSharedNode();
+
+    if (!node)
+        return 0;
+
+    RenderObject* renderer = node->renderer();
+    while (!renderer) {
+        node = node->parentNode();
+        renderer = node->renderer();
+    }
+
+    return node;
+}
+
+Node* WebPagePrivate::adjustedBlockZoomNodeForZoomLimits(Node* node)
+{
+    Node* initialNode = node;
+    RenderObject* renderer = node->renderer();
+    bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
+
+    while (!renderer || !acceptableNodeSize) {
+        node = node->parentNode();
+
+        if (!node)
+            return initialNode;
+
+        renderer = node->renderer();
+        acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
+    }
+
+    return node;
+}
+
+bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
+{
+    if (!n1 || !n2)
+        return false;
+
+    return (n2 == n1) || n2->isDescendantOf(n1);
+}
+
+double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
+{
+    if (rect.isEmpty())
+        return std::numeric_limits<double>::max();
+
+    ASSERT(rect.width() + margin);
+
+    double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
+
+    return newScale;
+}
+
+IntRect WebPagePrivate::rectForNode(Node* node)
+{
+    if (!node)
+        return IntRect();
+
+    RenderObject* renderer = node->renderer();
+
+    if (!renderer)
+        return IntRect();
+
+    // Return rect in un-transformed content coordinates.
+    IntRect blockRect;
+
+    // FIXME: Ensure this works with iframes.
+    if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
+        RenderBlock* renderBlock = renderer->containingBlock();
+        int xOffset = 0;
+        int yOffset = 0;
+        while (!renderBlock->isRoot()) {
+            xOffset += renderBlock->x();
+            yOffset += renderBlock->y();
+            renderBlock = renderBlock->containingBlock();
+        }
+        const RenderText* renderText = toRenderText(renderer);
+        IntRect linesBox = renderText->linesBoundingBox();
+        blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height());
+    } else
+        blockRect = renderer->absoluteClippedOverflowRect();
+
+    if (renderer->isText()) {
+        RenderBlock* rb = renderer->containingBlock();
+
+        // Inefficient? Way to find width when floats intersect a block.
+        int blockWidth = 0;
+        int lineCount = rb->lineCount();
+        for (int i = 0; i < lineCount; i++)
+            blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false));
+
+        blockRect.setWidth(blockWidth);
+        blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
+    }
+
+    // Strip off padding.
+    if (renderer->style()->hasPadding()) {
+        blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
+        blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
+        blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
+        blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
+    }
+
+    return blockRect;
+}
+
+IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
+{
+    ASSERT(frame);
+
+    // FIXME: This function can be called when page is being destroyed and JS triggers selection change.
+    // We could break the call chain at upper levels, but I think it is better to check the frame pointer
+    // here because the pointer is explicitly cleared in WebPage::destroy().
+    if (!mainFrame())
+        return IntPoint();
+
+    // Convert 0,0 in the frame's coordinate system to window coordinates to
+    // get the frame's global position, and return this position in the main
+    // frame's coordinates.  (So the main frame's coordinates will be 0,0.)
+    return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
+}
+
+IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
+{
+    if (!node)
+        return rect;
+
+    // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames.
+    // FIXME: can we just use frameOffset instead of this big routine?
+    const Node* tnode = node;
+    IntRect adjustedRect = rect;
+    do {
+        Frame* frame = tnode->document()->frame();
+        if (!frame)
+            continue;
+
+        Node* ownerNode = static_cast<Node*>(frame->ownerElement());
+        tnode = ownerNode;
+        if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
+            IntRect iFrameRect;
+            do {
+                iFrameRect = rectForNode(ownerNode);
+                adjustedRect.move(iFrameRect.x(), iFrameRect.y());
+                adjustedRect.intersect(iFrameRect);
+                ownerNode = ownerNode->parentNode();
+            } while (iFrameRect.isEmpty() && ownerNode);
+        } else
+            break;
+    } while (tnode = tnode->parentNode());
+
+    return adjustedRect;
+}
+
+IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
+{
+    if (!node || contentsSize().isEmpty())
+        return IntRect();
+
+    Node* tnode = node;
+    m_currentBlockZoomAdjustedNode = tnode;
+
+    IntRect blockRect = rectForNode(tnode);
+    IntRect originalRect = blockRect;
+
+    int originalArea = originalRect.width() * originalRect.height();
+    int pageArea = contentsSize().width() * contentsSize().height();
+    double blockToPageRatio = static_cast<double>(1 - originalArea / pageArea);
+    double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
+
+    if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
+        while (tnode = tnode->parentNode()) {
+            ASSERT(tnode);
+            IntRect tRect = rectForNode(tnode);
+            int tempBlockArea = tRect.width() * tRect.height();
+            // Don't expand the block if it will be too large relative to the content.
+            if (static_cast<double>(1 - tempBlockArea / pageArea) < minimumExpandingRatio)
+                break;
+            if (tRect.isEmpty())
+                continue; // No renderer.
+            if (tempBlockArea < 1.1 * originalArea)
+                continue; // The size of this parent is very close to the child, no need to go to this parent.
+            // Don't expand the block if the parent node size is already almost the size of actual visible size.
+            IntSize actualSize = actualVisibleSize();
+            if (static_cast<double>(1 - tRect.width() / actualSize.width()) < minimumExpandingRatio)
+                break;
+            if (tempBlockArea < blockExpansionRatio * originalArea) {
+                blockRect = tRect;
+                m_currentBlockZoomAdjustedNode = tnode;
+            } else
+                break;
+        }
+    }
+
+    blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
+    blockRect = mapToTransformed(blockRect);
+    clipToTransformedContentsRect(blockRect);
+
+#if DEBUG_BLOCK_ZOOM
+    // Re-paint the backingstore to screen to erase other annotations.
+    m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::Blit);
+
+    // Render a black square over the calculated block and a gray square over the original block for visual inspection.
+    originalRect = mapToTransformed(originalRect);
+    clipToTransformedContentsRect(originalRect);
+    IntRect renderRect = mapFromTransformedContentsToTransformedViewport(blockRect);
+    IntRect originalRenderRect = mapFromTransformedContentsToTransformedViewport(originalRect);
+    IntSize viewportSize = transformedViewportSize();
+    renderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
+    originalRenderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
+    m_backingStore->d->clearWindow(renderRect, 0, 0, 0);
+    m_backingStore->d->clearWindow(originalRenderRect, 120, 120, 120);
+    m_backingStore->d->invalidateWindow(renderRect);
+#endif
+
+    return blockRect;
+}
+
+void WebPage::blockZoomAnimationFinished()
+{
+    d->zoomBlock();
+}
+
+// This function should not be called directly.
+// It is called after the animation ends (see above).
+void WebPagePrivate::zoomBlock()
+{
+    if (!m_mainFrame)
+        return;
+
+    IntPoint anchor(roundUntransformedPoint(mapFromTransformedFloatPoint(m_finalBlockPoint)));
+    bool willUseTextReflow = false;
+
+#if ENABLE(VIEWPORT_REFLOW)
+    willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
+    toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
+    setNeedsLayout();
+#endif
+
+    TransformationMatrix zoom;
+    zoom.scale(m_blockZoomFinalScale);
+    *m_transformationMatrix = zoom;
+    m_client->resetBitmapZoomScale(m_blockZoomFinalScale);
+    m_backingStore->d->suspendScreenAndBackingStoreUpdates();
+    updateViewportSize();
+
+#if ENABLE(VIEWPORT_REFLOW)
+    requestLayoutIfNeeded();
+    if (willUseTextReflow && m_shouldReflowBlock) {
+        IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
+        reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
+        reflowedRect.move(roundTransformedPoint(m_finalBlockPointReflowOffset).x(), roundTransformedPoint(m_finalBlockPointReflowOffset).y());
+        RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
+        IntPoint topLeftPoint(reflowedRect.location());
+        if (renderer && renderer->isText()) {
+            ETextAlign textAlign = renderer->style()->textAlign();
+            IntPoint textAnchor;
+            switch (textAlign) {
+            case CENTER:
+            case WEBKIT_CENTER:
+                textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
+                break;
+            case LEFT:
+            case WEBKIT_LEFT:
+                textAnchor = topLeftPoint;
+                break;
+            case RIGHT:
+            case WEBKIT_RIGHT:
+                textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
+                break;
+            case TAAUTO:
+            case JUSTIFY:
+            default:
+                if (renderer->style()->isLeftToRightDirection())
+                    textAnchor = topLeftPoint;
+                else
+                    textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
+                break;
+            }
+            setScrollPosition(textAnchor);
+        } else {
+            renderer->style()->isLeftToRightDirection()
+                ? setScrollPosition(topLeftPoint)
+                : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
+        }
+    } else if (willUseTextReflow) {
+        IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
+        finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
+        setScrollPosition(IntPoint(0, finalRect.y() + m_finalBlockPointReflowOffset.y()));
+        resetBlockZoom();
+    }
+#endif
+    if (!willUseTextReflow) {
+        setScrollPosition(anchor);
+        if (!m_shouldReflowBlock)
+            resetBlockZoom();
+    }
+
+    notifyTransformChanged();
+    m_backingStore->d->clearWindow();
+    m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
+    m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
+}
+
+
+void WebPagePrivate::resetBlockZoom()
+{
+    m_currentBlockZoomNode = 0;
+    m_currentBlockZoomAdjustedNode = 0;
+    m_shouldReflowBlock = false;
+}
+
+WebPage::WebPage(WebPageClient* client, const WebString& pageGroupName, const Platform::IntRect& rect)
+{
+    globalInitialize();
+    d = new WebPagePrivate(this, client, rect);
+    d->init(pageGroupName);
+}
+
+void WebPage::destroyWebPageCompositor()
+{
+#if USE(ACCELERATED_COMPOSITING)
+    // Destroy the layer renderer in a sync command before we destroy the backing store,
+    // to flush any pending compositing messages on the compositing thread.
+    // The backing store is indirectly deleted by the 'detachFromParent' call below.
+    d->syncDestroyCompositorOnCompositingThread();
+#endif
+}
+
+void WebPage::destroy()
+{
+    // TODO: need to verify if this call needs to be made before calling
+    // WebPage::destroyWebPageCompositor()
+    d->m_backingStore->d->suspendScreenAndBackingStoreUpdates();
+
+    // Close the backforward list and release the cached pages.
+    d->m_page->backForward()->close();
+    pageCache()->releaseAutoreleasedPagesNow();
+
+    FrameLoader* loader = d->m_mainFrame->loader();
+
+    // Remove main frame's backing store client from the map
+    // to prevent FrameLoaderClientBlackyBerry::detachFromParent2(),
+    // which is called by loader->detachFromParent(), deleting it.
+    // We will delete it in ~WebPagePrivate().
+    // Reason: loader->detachFromParent() may ping back to backing store
+    // indirectly through ChromeClientBlackBerry::invalidateContentsAndWindow().
+    // see RIM PR #93256.
+    d->removeBackingStoreClientForFrame(d->m_mainFrame);
+
+    // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion.
+    d->m_mainFrame = 0;
+    if (loader)
+        loader->detachFromParent();
+
+    delete this;
+}
+
+WebPage::~WebPage()
+{
+    delete d;
+    d = 0;
+}
+
+WebPageClient* WebPage::client() const
+{
+    return d->m_client;
+}
+
+void WebPage::load(const char* url, const char* networkToken, bool isInitial)
+{
+    d->load(url, networkToken, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, isInitial, false);
+}
+
+void WebPage::loadExtended(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool mustHandleInternally)
+{
+    d->load(url, networkToken, method, cachePolicy, data, dataLength, headers, headersLength, false, mustHandleInternally, false, "");
+}
+
+void WebPage::loadFile(const char* path, const char* overrideContentType)
+{
+    std::string fileUrl(path);
+    if (!fileUrl.find("/"))
+        fileUrl.insert(0, "file://");
+    else if (fileUrl.find("file:///"))
+        return;
+
+    d->load(fileUrl.c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, false, overrideContentType);
+}
+
+void WebPage::loadString(const char* string, const char* baseURL, const char* mimeType, const char* failingURL)
+{
+    d->loadString(string, baseURL, mimeType, failingURL);
+}
+
+void WebPage::download(const Platform::NetworkRequest& request)
+{
+    d->load(request.getUrlRef().c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, true, "");
+}
+
+bool WebPage::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
+{
+    return d->executeJavaScript(script, returnType, returnValue);
+}
+
+bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, WebString& returnValue)
+{
+    // On our platform wchar_t is unsigned int and UChar is unsigned short
+    // so we have to convert using ICU conversion function
+    int lengthCopied = 0;
+    UErrorCode error = U_ZERO_ERROR;
+    const int length = script.length() + 1 /*null termination char*/;
+    UChar data[length];
+
+    // FIXME: PR 138162 is giving U_INVALID_CHAR_FOUND error.
+    u_strFromUTF32(data, length, &lengthCopied, reinterpret_cast<const UChar32*>(script.c_str()), script.length(), &error);
+    BLACKBERRY_ASSERT(error == U_ZERO_ERROR);
+    if (error != U_ZERO_ERROR) {
+        Platform::logAlways(Platform::LogLevelCritical, "WebPage::executeJavaScriptInIsolatedWorld failed to convert UTF16 to JavaScript!");
+        return false;
+    }
+    String str = String(data, lengthCopied);
+    ScriptSourceCode sourceCode(str, KURL());
+    return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
+}
+
+bool WebPage::executeJavaScriptInIsolatedWorld(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
+{
+    ScriptSourceCode sourceCode(String::fromUTF8(script), KURL());
+    return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
+}
+
+void WebPage::stopLoading()
+{
+    d->stopCurrentLoad();
+}
+
+void WebPage::prepareToDestroy()
+{
+    d->prepareToDestroy();
+}
+
+int WebPage::backForwardListLength() const
+{
+    return d->m_page->getHistoryLength();
+}
+
+bool WebPage::canGoBackOrForward(int delta) const
+{
+    return d->m_page->canGoBackOrForward(delta);
+}
+
+bool WebPage::goBackOrForward(int delta)
+{
+    if (d->m_page->canGoBackOrForward(delta)) {
+        d->m_page->goBackOrForward(delta);
+        return true;
+    }
+    return false;
+}
+
+void WebPage::goToBackForwardEntry(BackForwardId id)
+{
+    HistoryItem* item = historyItemFromBackForwardId(id);
+    ASSERT(item);
+    d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
+}
+
+void WebPage::reload()
+{
+    d->m_mainFrame->loader()->reload(/* bypassCache */ true);
+}
+
+void WebPage::reloadFromCache()
+{
+    d->m_mainFrame->loader()->reload(/* bypassCache */ false);
+}
+
+WebSettings* WebPage::settings() const
+{
+    return d->m_webSettings;
+}
+
+bool WebPage::isVisible() const
+{
+    return d->m_visible;
+}
+
+void WebPage::setVisible(bool visible)
+{
+    if (d->m_visible == visible)
+        return;
+
+    d->m_visible = visible;
+
+    if (!visible) {
+        d->suspendBackingStore();
+
+        // Remove this WebPage from the visible pages list.
+        size_t foundIndex = visibleWebPages()->find(this);
+        if (foundIndex != WTF::notFound)
+            visibleWebPages()->remove(foundIndex);
+
+        // Return the backing store to the last visible WebPage.
+        if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
+            visibleWebPages()->last()->d->resumeBackingStore();
+
+#if USE(ACCELERATED_COMPOSITING)
+        // Root layer commit is not necessary for invisible tabs.
+        // And release layer resources can reduce memory consumption.
+        d->suspendRootLayerCommit();
+#endif
+        return;
+    }
+
+#if USE(ACCELERATED_COMPOSITING)
+    d->resumeRootLayerCommit();
+#endif
+
+    // Push this WebPage to the top of the visible pages list.
+    if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
+        size_t foundIndex = visibleWebPages()->find(this);
+        if (foundIndex != WTF::notFound)
+            visibleWebPages()->remove(foundIndex);
+    }
+    visibleWebPages()->append(this);
+
+    if (BackingStorePrivate::currentBackingStoreOwner()
+        && BackingStorePrivate::currentBackingStoreOwner() != this)
+        BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
+
+    // resumeBackingStore will set the current owner to this webpage.
+    // If we set the owner prematurely, then the tiles will not be reset.
+    d->resumeBackingStore();
+}
+
+void WebPagePrivate::selectionChanged(Frame* frame)
+{
+    m_inputHandler->selectionChanged();
+
+    // FIXME: This is a hack!
+    // To ensure the selection being changed has its frame 'focused', lets
+    // set it as focused ourselves (PR #104724).
+    m_page->focusController()->setFocusedFrame(frame);
+}
+
+void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
+{
+    // Track a dispatched message, we don't want to flood the webkit thread.
+    // There can be as many as one more message enqued as needed but never less.
+    if (dispatched)
+        m_updateDelegatedOverlaysDispatched = false;
+    else if (m_updateDelegatedOverlaysDispatched) {
+        // Early return if there is message already pending on the webkit thread.
+        return;
+    }
+
+    if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
+        // Must be called on the WebKit thread.
+        if (m_selectionHandler->isSelectionActive())
+            m_selectionHandler->selectionPositionChanged(true /* visualChangeOnly */);
+
+    } else if (m_selectionHandler->isSelectionActive()) {
+        // Don't bother dispatching to webkit thread if selection and tap highlight are not active.
+        m_updateDelegatedOverlaysDispatched = true;
+        Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/));
+    }
+}
+
+void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle style)
+{
+}
+
+bool WebPage::setBatchEditingActive(bool active)
+{
+    return d->m_inputHandler->setBatchEditingActive(active);
+}
+
+bool WebPage::setInputSelection(unsigned start, unsigned end)
+{
+    return d->m_inputHandler->setSelection(start, end);
+}
+
+int WebPage::inputCaretPosition() const
+{
+    return d->m_inputHandler->caretPosition();
+}
+
+void WebPage::popupListClosed(int size, bool* selecteds)
+{
+    d->m_inputHandler->setPopupListIndexes(size, selecteds);
+}
+
+void WebPage::popupListClosed(int index)
+{
+    d->m_inputHandler->setPopupListIndex(index);
+}
+
+void WebPage::setDateTimeInput(const WebString& value)
+{
+    d->m_inputHandler->setInputValue(String(value.impl()));
+}
+
+void WebPage::setColorInput(const WebString& value)
+{
+    d->m_inputHandler->setInputValue(String(value.impl()));
+}
+
+ActiveNodeContext WebPage::activeNodeContext(TargetDetectionStrategy strategy) const
+{
+    return d->activeNodeContext(strategy);
+}
+
+void WebPage::setVirtualViewportSize(int width, int height)
+{
+    d->m_virtualViewportWidth = width;
+    d->m_virtualViewportHeight = height;
+}
+
+void WebPage::resetVirtualViewportOnCommitted(bool reset)
+{
+    d->m_resetVirtualViewportOnCommitted = reset;
+}
+
+IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments()
+{
+    static ViewportArguments defaultViewportArguments;
+    if (m_viewportArguments == defaultViewportArguments)
+        return IntSize();
+
+    int desktopWidth = defaultMaxLayoutSize().width();
+    int deviceWidth = Platform::Graphics::Screen::width();
+    int deviceHeight = Platform::Graphics::Screen::height();
+    FloatSize currentPPI = Platform::Graphics::Screen::pixelsPerInch(-1);
+    int deviceDPI = int(roundf((currentPPI.width() + currentPPI.height()) / 2));
+    if (m_viewportArguments.targetDensityDpi == ViewportArguments::ValueAuto) {
+        // Auto means 160dpi if we leave it alone. This looks terrible for pages wanting 1:1.
+        // FIXME: This is insufficient for devices with high dpi, as they will render content unreadably small.
+        m_viewportArguments.targetDensityDpi = deviceDPI;
+    }
+
+    ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, deviceDPI, m_defaultLayoutSize);
+    return IntSize(result.layoutSize.width(), result.layoutSize.height());
+}
+
+#if ENABLE(EVENT_MODE_METATAGS)
+void WebPagePrivate::didReceiveCursorEventMode(CursorEventMode mode)
+{
+    if (mode != m_cursorEventMode)
+        m_client->cursorEventModeChanged(toPlatformCursorEventMode(mode));
+    m_cursorEventMode = mode;
+}
+
+void WebPagePrivate::didReceiveTouchEventMode(TouchEventMode mode)
+{
+    if (mode != m_touchEventMode)
+        m_client->touchEventModeChanged(toPlatformTouchEventMode(mode));
+    m_touchEventMode = mode;
+}
+#endif
+
+void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments)
+{
+    static ViewportArguments defaultViewportArguments;
+    if (arguments == defaultViewportArguments)
+        return;
+
+    m_viewportArguments = arguments;
+
+    // 0 width or height in viewport arguments makes no sense, and results in a very large initial scale.
+    // In real world, a 0 width or height is usually caused by a syntax error in "content" field of viewport
+    // meta tag, for example, using semicolon instead of comma as separator ("width=device-width; initial-scale=1.0").
+    // We don't have a plan to tolerate the semicolon separator, but we can avoid applying 0 width/height.
+    // I default it to ValueDeviceWidth rather than ValueAuto because in more cases the web site wants "device-width"
+    // when they specify the viewport width.
+    if (!m_viewportArguments.width)
+        m_viewportArguments.width = ViewportArguments::ValueDeviceWidth;
+    if (!m_viewportArguments.height)
+        m_viewportArguments.height = ViewportArguments::ValueDeviceHeight;
+
+    setUserScalable(arguments.userScalable == ViewportArguments::ValueAuto ? true : arguments.userScalable);
+    if (arguments.initialScale > 0)
+        setInitialScale(arguments.initialScale);
+    if (arguments.minimumScale > 0)
+        setMinimumScale(arguments.minimumScale);
+    if (arguments.maximumScale > 0)
+        setMaximumScale(arguments.maximumScale);
+
+    IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
+    m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
+
+    if (loadState() == WebKit::WebPagePrivate::Committed)
+        zoomToInitialScaleOnLoad();
+}
+
+void WebPagePrivate::onInputLocaleChanged(bool isRTL)
+{
+    if (isRTL != m_webSettings->isWritingDirectionRTL()) {
+        m_webSettings->setWritingDirectionRTL(isRTL);
+        m_inputHandler->handleInputLocaleChanged(isRTL);
+    }
+}
+
+void WebPage::setScreenOrientation(int orientation)
+{
+    d->m_pendingOrientation = orientation;
+}
+
+void WebPage::applyPendingOrientationIfNeeded()
+{
+    if (d->m_pendingOrientation != -1)
+        d->setScreenOrientation(d->m_pendingOrientation);
+}
+
+void WebPagePrivate::suspendBackingStore()
+{
+#if USE(ACCELERATED_COMPOSITING)
+    resetCompositingSurface();
+#endif
+}
+
+void WebPagePrivate::resumeBackingStore()
+{
+    ASSERT(m_webPage->isVisible());
+
+#if USE(ACCELERATED_COMPOSITING)
+    setNeedsOneShotDrawingSynchronization();
+#endif
+
+    bool directRendering = m_backingStore->d->shouldDirectRenderingToWindow();
+    if (!m_backingStore->d->isActive()
+        || shouldResetTilesWhenShown()
+        || directRendering) {
+        // We need to reset all tiles so that we do not show any tiles whose content may
+        // have been replaced by another WebPage instance (i.e. another tab).
+        BackingStorePrivate::setCurrentBackingStoreOwner(m_webPage);
+        m_backingStore->d->orientationChanged(); // Updates tile geometry and creates visible tile buffer.
+        m_backingStore->d->resetTiles(true /* resetBackground */);
+        m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
+        // This value may have changed, so we need to update it.
+        directRendering = m_backingStore->d->shouldDirectRenderingToWindow();
+        if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !directRendering)
+            m_backingStore->d->blitVisibleContents();
+    } else {
+        // Rendering was disabled while we were hidden, so we need to update all tiles.
+        m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
+    }
+
+    setShouldResetTilesWhenShown(false);
+}
+
+void WebPagePrivate::setScreenOrientation(int orientation)
+{
+    FOR_EACH_PLUGINVIEW(m_pluginViews)
+        (*it)->handleOrientationEvent(orientation);
+
+    m_pendingOrientation = -1;
+
+#if ENABLE(ORIENTATION_EVENTS)
+    if (m_mainFrame->orientation() == orientation)
+        return;
+    for (RefPtr<Frame> frame = m_mainFrame; frame; frame = frame->tree()->traverseNext())
+        frame->sendOrientationChangeEvent(orientation);
+#endif
+}
+
+Platform::IntSize WebPage::viewportSize() const
+{
+    return d->transformedActualVisibleSize();
+}
+
+void WebPage::setViewportSize(const Platform::IntSize& viewportSize, bool ensureFocusElementVisible)
+{
+    d->setViewportSize(viewportSize, ensureFocusElementVisible);
+}
+
+void WebPagePrivate::screenRotated()
+{
+    // This call will cause the client to reallocate the window buffer to new size,
+    // which needs to be serialized with usage of the window buffer. Accomplish
+    // this by sending a sync message to the compositing thread. All other usage of
+    // the window buffer happens on the compositing thread.
+    if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
+        Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
+            Platform::createMethodCallMessage(&WebPagePrivate::screenRotated, this));
+        return;
+    }
+
+    SurfacePool::globalSurfacePool()->notifyScreenRotated();
+    m_client->notifyScreenRotated();
+}
+
+void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize, bool ensureFocusElementVisible)
+{
+    if (m_pendingOrientation == -1 && transformedActualVisibleSize == this->transformedActualVisibleSize())
+        return;
+
+    // Suspend all screen updates to the backingstore to make sure no-one tries to blit
+    // while the window surface and the BackingStore are out of sync.
+    m_backingStore->d->suspendScreenAndBackingStoreUpdates();
+
+    // The screen rotation is a major state transition that in this case is not properly
+    // communicated to the backing store, since it does early return in most methods when
+    // not visible.
+    if (!m_visible || !m_backingStore->d->isActive())
+        setShouldResetTilesWhenShown(true);
+
+    bool hasPendingOrientation = m_pendingOrientation != -1;
+    if (hasPendingOrientation)
+        screenRotated();
+
+    // The window buffers might have been recreated, cleared, moved, etc., so:
+    m_backingStore->d->windowFrontBufferState()->clearBlittedRegion();
+    m_backingStore->d->windowBackBufferState()->clearBlittedRegion();
+
+    IntSize viewportSizeBefore = actualVisibleSize();
+    FloatPoint centerOfVisibleContentsRect = this->centerOfVisibleContentsRect();
+    bool newVisibleRectContainsOldVisibleRect = (m_actualVisibleHeight <= transformedActualVisibleSize.height())
+                                          && (m_actualVisibleWidth <= transformedActualVisibleSize.width());
+
+    bool atInitialScale = currentScale() == initialScale();
+    bool atTop = !scrollPosition().y();
+    bool atLeft = !scrollPosition().x();
+
+    // We need to reorient the visibleTileRect because the following code
+    // could cause BackingStore::transformChanged to be called, where it
+    // is used.
+    // It is only dependent on the transformedViewportSize which has been
+    // updated by now.
+    m_backingStore->d->createVisibleTileBuffer();
+
+    setDefaultLayoutSize(transformedActualVisibleSize);
+
+    // Recompute our virtual viewport.
+    bool needsLayout = false;
+    static ViewportArguments defaultViewportArguments;
+    if (!(m_viewportArguments == defaultViewportArguments)) {
+        // We may need to infer the width and height for the viewport with respect to the rotation.
+        IntSize newVirtualViewport = recomputeVirtualViewportFromViewportArguments();
+        ASSERT(!newVirtualViewport.isEmpty());
+        m_webPage->setVirtualViewportSize(newVirtualViewport.width(), newVirtualViewport.height());
+        m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
+        m_mainFrame->view()->setFixedLayoutSize(fixedLayoutSize());
+        needsLayout = true;
+    }
+
+    // We switch this strictly after recomputing our virtual viewport as zoomToFitScale is dependent
+    // upon these values and so is the virtual viewport recalculation.
+    m_actualVisibleWidth = transformedActualVisibleSize.width();
+    m_actualVisibleHeight = transformedActualVisibleSize.height();
+
+    IntSize viewportSizeAfter = actualVisibleSize();
+
+    IntPoint offset(roundf((viewportSizeBefore.width() - viewportSizeAfter.width()) / 2.0),
+                    roundf((viewportSizeBefore.height() - viewportSizeAfter.height()) / 2.0));
+
+    // As a special case, if we were anchored to the top left position at
+    // the beginning of the rotation then preserve that anchor.
+    if (atTop)
+        offset.setY(0);
+    if (atLeft)
+        offset.setX(0);
+
+    // If we're about to overscroll, cap the offset to valid content.
+    IntPoint bottomRight(
+        scrollPosition().x() + viewportSizeAfter.width(),
+        scrollPosition().y() + viewportSizeAfter.height());
+
+    if (bottomRight.x() + offset.x() > contentsSize().width())
+        offset.setX(contentsSize().width() - bottomRight.x());
+    if (bottomRight.y() + offset.y() > contentsSize().height())
+        offset.setY(contentsSize().height() - bottomRight.y());
+    if (scrollPosition().x() + offset.x() < 0)
+        offset.setX(-scrollPosition().x());
+    if (scrollPosition().y() + offset.y() < 0)
+        offset.setY(-scrollPosition().y());
+
+    // ...before scrolling, because the backing store will align its
+    // tile matrix with the viewport as reported by the ScrollView.
+    scrollBy(offset.x(), offset.y());
+    notifyTransformedScrollChanged();
+
+    m_backingStore->d->orientationChanged();
+    m_backingStore->d->actualVisibleSizeChanged(transformedActualVisibleSize);
+
+    // Update view mode only after we have updated the actual
+    // visible size and reset the contents rect if necessary.
+    if (setViewMode(viewMode()))
+        needsLayout = true;
+
+    // We need to update the viewport size of the WebCore::ScrollView...
+    updateViewportSize(!hasPendingOrientation /* setFixedReportedSize */, false /* sendResizeEvent */);
+    notifyTransformedContentsSizeChanged();
+
+    // If automatic zooming is disabled, prevent zooming below.
+    if (!m_webSettings->isZoomToFitOnLoad()) {
+        atInitialScale = false;
+
+        // Normally, if the contents size is smaller than the layout width,
+        // we would zoom in. If zoom is disabled, we need to do something else,
+        // or there will be artifacts due to non-rendered areas outside of the
+        // contents size. If there is a virtual viewport, we are not allowed
+        // to modify the fixed layout size, however.
+        if (!hasVirtualViewport() && contentsSize().width() < m_defaultLayoutSize.width()) {
+            m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
+            m_mainFrame->view()->setFixedLayoutSize(m_defaultLayoutSize);
+            needsLayout = true;
+        }
+    }
+
+    if (needsLayout)
+        setNeedsLayout();
+
+    // Need to resume so that the backingstore will start recording the invalidated
+    // rects from below.
+    m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
+
+    // We might need to layout here to get a correct contentsSize so that zoomToFit
+    // is calculated correctly.
+    requestLayoutIfNeeded();
+
+    // As a special case if we were zoomed to the initial scale at the beginning
+    // of the rotation then preserve that zoom level even when it is zoomToFit.
+    double scale = atInitialScale ? initialScale() : currentScale();
+
+    // Do our own clamping.
+    scale = clampedScale(scale);
+
+    if (hasPendingOrientation) {
+        // Set the fixed reported size here so that innerWidth|innerHeight works
+        // with this new scale.
+        TransformationMatrix rotationMatrix;
+        rotationMatrix.scale(scale);
+        IntRect viewportRect = IntRect(IntPoint::zero(), transformedActualVisibleSize);
+        IntRect actualVisibleRect = enclosingIntRect(rotationMatrix.inverse().mapRect(FloatRect(viewportRect)));
+        m_mainFrame->view()->setFixedReportedSize(actualVisibleRect.size());
+    }
+
+    // We're going to need to send a resize event to JavaScript because
+    // innerWidth and innerHeight depend on fixed reported size.
+    // This is how we support mobile pages where JavaScript resizes
+    // the page in order to get around the fixed layout size, e.g.
+    // google maps when it detects a mobile user agent.
+    if (shouldSendResizeEvent())
+        m_mainFrame->eventHandler()->sendResizeEvent();
+
+    // As a special case if we were anchored to the top left position at the beginning
+    // of the rotation then preserve that anchor.
+    FloatPoint anchor = centerOfVisibleContentsRect;
+    if (atTop)
+        anchor.setY(0);
+    if (atLeft)
+        anchor.setX(0);
+
+    // Try and zoom here with clamping on.
+    if (m_backingStore->d->shouldDirectRenderingToWindow()) {
+        bool success = zoomAboutPoint(scale, anchor, false /* enforceScaleClamping */, true /* forceRendering */);
+        if (!success && ensureFocusElementVisible)
+            ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
+    } else if (!scheduleZoomAboutPoint(scale, anchor, false /* enforceScaleClamping */, true /* forceRendering */)) {
+        // Suspend all screen updates to the backingstore.
+        m_backingStore->d->suspendScreenAndBackingStoreUpdates();
+
+        // If the zoom failed, then we should still preserve the special case of scroll position.
+        IntPoint scrollPosition = this->scrollPosition();
+        if (atTop)
+            scrollPosition.setY(0);
+        if (atLeft)
+            scrollPosition.setX(0);
+        setScrollPosition(scrollPosition);
+
+        // These might have been altered even if we didn't zoom so notify the client.
+        notifyTransformedContentsSizeChanged();
+        notifyTransformedScrollChanged();
+
+        if (!needsLayout) {
+            // The visible tiles for scroll must be up-to-date before we blit since we are not performing a layout.
+            m_backingStore->d->updateTilesForScrollOrNotRenderedRegion();
+        }
+
+        if (ensureFocusElementVisible)
+            ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
+
+        if (needsLayout) {
+            m_backingStore->d->resetTiles(true);
+            m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
+        }
+
+        // If we need layout then render and blit, otherwise just blit as our viewport has changed.
+        m_backingStore->d->resumeScreenAndBackingStoreUpdates(needsLayout ? BackingStore::RenderAndBlit : BackingStore::Blit);
+    } else if (ensureFocusElementVisible)
+        ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
+}
+
+void WebPage::setDefaultLayoutSize(int width, int height)
+{
+    IntSize size(width, height);
+    d->setDefaultLayoutSize(size);
+}
+
+void WebPagePrivate::setDefaultLayoutSize(const IntSize& size)
+{
+    if (size == m_defaultLayoutSize)
+        return;
+
+    IntSize screenSize = Platform::Graphics::Screen::size();
+    ASSERT(size.width() <= screenSize.width() && size.height() <= screenSize.height());
+    m_defaultLayoutSize = size.expandedTo(minimumLayoutSize).shrunkTo(screenSize);
+
+    bool needsLayout = setViewMode(viewMode());
+    if (needsLayout) {
+        setNeedsLayout();
+        if (!isLoading())
+            requestLayoutIfNeeded();
+    }
+}
+
+bool WebPage::mouseEvent(const Platform::MouseEvent& mouseEvent, bool* wheelDeltaAccepted)
+{
+    if (!d->m_mainFrame->view())
+        return false;
+
+    PluginView* pluginView = d->m_fullScreenPluginView.get();
+    if (pluginView)
+        return d->dispatchMouseEventToFullScreenPlugin(pluginView, mouseEvent);
+
+    if (mouseEvent.type() == Platform::MouseEvent::MouseAborted) {
+        d->m_mainFrame->eventHandler()->setMousePressed(false);
+        return false;
+    }
+
+    d->m_pluginMayOpenNewTab = true;
+
+    d->m_lastUserEventTimestamp = currentTime();
+    int clickCount = (d->m_selectionHandler->isSelectionActive() || mouseEvent.type() != Platform::MouseEvent::MouseMove) ? 1 : 0;
+
+    // Set the button type.
+    MouseButton buttonType = NoButton;
+    if (mouseEvent.isLeftButton())
+        buttonType = LeftButton;
+    else if (mouseEvent.isRightButton())
+        buttonType = RightButton;
+    else if (mouseEvent.isMiddleButton())
+        buttonType = MiddleButton;
+
+    // Create our event.
+    PlatformMouseEvent platformMouseEvent(d->mapFromTransformed(mouseEvent.position()),
+                                          d->mapFromTransformed(mouseEvent.screenPosition()),
+                                          toWebCoreMouseEventType(mouseEvent.type()), clickCount, buttonType, PointingDevice);
+    d->m_lastMouseEvent = platformMouseEvent;
+    bool success = d->handleMouseEvent(platformMouseEvent);
+
+    if (mouseEvent.wheelTicks()) {
+        PlatformWheelEvent wheelEvent(d->mapFromTransformed(mouseEvent.position()),
+                                      d->mapFromTransformed(mouseEvent.screenPosition()),
+                                      0, -mouseEvent.wheelDelta(),
+                                      0, -mouseEvent.wheelTicks(),
+                                      ScrollByPixelWheelEvent,
+                                      false /* shiftKey */, false /* ctrlKey */,
+                                      false /* altKey */, false /* metaKey */);
+        if (wheelDeltaAccepted)
+            *wheelDeltaAccepted = d->handleWheelEvent(wheelEvent);
+    } else if (wheelDeltaAccepted)
+        *wheelDeltaAccepted = false;
+
+    return success;
+}
+
+bool WebPagePrivate::dispatchMouseEventToFullScreenPlugin(PluginView* plugin, const Platform::MouseEvent& event)
+{
+    NPEvent npEvent;
+    NPMouseEvent mouseEvent;
+
+    mouseEvent.x = event.screenPosition().x();
+    mouseEvent.y = event.screenPosition().y();
+
+    switch (event.type()) {
+    case Platform::MouseEvent::MouseButtonDown:
+        mouseEvent.type = MOUSE_BUTTON_DOWN;
+        m_pluginMouseButtonPressed = true;
+        break;
+    case Platform::MouseEvent::MouseButtonUp:
+        mouseEvent.type = MOUSE_BUTTON_UP;
+        m_pluginMouseButtonPressed = false;
+        break;
+    case Platform::MouseEvent::MouseMove:
+        mouseEvent.type = MOUSE_MOTION;
+        break;
+    default:
+        return false;
+    }
+
+    mouseEvent.flags = 0;
+    mouseEvent.button = m_pluginMouseButtonPressed;
+
+    npEvent.type = NP_MouseEvent;
+    npEvent.data = &mouseEvent;
+
+    return plugin->dispatchFullScreenNPEvent(npEvent);
+}
+
+bool WebPagePrivate::handleMouseEvent(PlatformMouseEvent& mouseEvent)
+{
+    EventHandler* eventHandler = m_mainFrame->eventHandler();
+
+    if (mouseEvent.eventType() == MouseEventMoved)
+        return eventHandler->mouseMoved(mouseEvent);
+
+    if (mouseEvent.eventType() == MouseEventScroll)
+        return true;
+
+    Node* node = 0;
+    if (mouseEvent.inputMethod() == TouchScreen) {
+        const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
+
+        // Fat fingers can deal with shadow content.
+        node = lastFatFingersResult.node(ShadowContentNotAllowed);
+    }
+
+    if (!node) {
+        HitTestResult result = eventHandler->hitTestResultAtPoint(mapFromViewportToContents(mouseEvent.pos()), false /*allowShadowContent*/);
+        node = result.innerNode();
+    }
+
+    if (mouseEvent.eventType() == MouseEventPressed) {
+        if (m_inputHandler->willOpenPopupForNode(node)) {
+            // Do not allow any human generated mouse or keyboard events to select <option>s in the list box
+            // because we use a pop up dialog to handle the actual selections. This prevents options from
+            // being selected prior to displaying the pop up dialog. The contents of the listbox are for
+            // display only.
+            //
+            // FIXME: We explicitly do not forward this event to WebCore so as to preserve symmetry with
+            // the MouseEventReleased handling (below). This has the side-effect that mousedown events
+            // are not fired for human generated mouse press events. See RIM Bug #1579.
+
+            // We do focus <select>/<option> on mouse down so that a Focus event is fired and have the
+            // element painted in its focus state on repaint.
+            ASSERT(node->isElementNode());
+            if (node->isElementNode()) {
+                Element* element = static_cast<Element*>(node);
+                element->focus();
+            }
+        } else
+            eventHandler->handleMousePressEvent(mouseEvent);
+    } else if (mouseEvent.eventType() == MouseEventReleased) {
+        // FIXME: For <select> and <options> elements, we explicitly do not forward this event to WebCore so
+        // as to preserve symmetry with the MouseEventPressed handling (above). This has the side-effect that
+        // mouseup events are not fired on such elements for human generated mouse release events. See RIM Bug #1579.
+        if (!m_inputHandler->didNodeOpenPopup(node))
+            eventHandler->handleMouseReleaseEvent(mouseEvent);
+    }
+
+    return true;
+}
+
+bool WebPagePrivate::handleWheelEvent(PlatformWheelEvent& wheelEvent)
+{
+    return m_mainFrame->eventHandler()->handleWheelEvent(wheelEvent);
+}
+
+bool WebPage::touchEvent(const Platform::TouchEvent& event)
+{
+#if DEBUG_TOUCH_EVENTS
+    switch (event.m_type) {
+    case Platform::TouchEvent::TouchEnd:
+        Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent Touch End");
+        break;
+    case Platform::TouchEvent::TouchStart:
+        Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent Touch Start");
+        break;
+    case Platform::TouchEvent::TouchMove:
+        Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent Touch Move");
+        break;
+    case Platform::TouchEvent::TouchCancel:
+        Platform::log(Platform::LogLevelCritical, "WebPage::touchCancel Touch Cancel");
+        break;
+    }
+
+    for (unsigned i = 0; i < event.m_points.size(); i++) {
+        switch (event.m_points[i].m_state) {
+        case Platform::TouchPoint::TouchPressed:
+            Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent %d Touch Pressed (%d, %d)", event.m_points[i].m_id, event.m_points[i].m_pos.x(), event.m_points[i].m_pos.y());
+            break;
+        case Platform::TouchPoint::TouchReleased:
+            Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent %d Touch Released (%d, %d)", event.m_points[i].m_id, event.m_points[i].m_pos.x(), event.m_points[i].m_pos.y());
+            break;
+        case Platform::TouchPoint::TouchMoved:
+            Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent %d Touch Moved (%d, %d)", event.m_points[i].m_id, event.m_points[i].m_pos.x(), event.m_points[i].m_pos.y());
+            break;
+        case Platform::TouchPoint::TouchStationary:
+            Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent %d Touch Stationary (%d, %d)", event.m_points[i].m_id, event.m_points[i].m_pos.x(), event.m_points[i].m_pos.y());
+            break;
+        }
+    }
+#endif
+
+#if ENABLE(TOUCH_EVENTS)
+    PluginView* pluginView = d->m_fullScreenPluginView.get();
+    if (pluginView)
+        return d->dispatchTouchEventToFullScreenPlugin(pluginView, event);
+
+    if (!d->m_mainFrame)
+        return false;
+
+    Platform::TouchEvent tEvent = event;
+    for (unsigned i = 0; i < event.m_points.size(); i++) {
+        tEvent.m_points[i].m_pos = d->mapFromTransformed(tEvent.m_points[i].m_pos);
+        tEvent.m_points[i].m_screenPos = d->mapFromTransformed(tEvent.m_points[i].m_screenPos);
+    }
+
+    Platform::Gesture tapGesture;
+    if (event.hasGesture(Platform::Gesture::SingleTap))
+        d->m_pluginMayOpenNewTab = true;
+    else if (tEvent.m_type == Platform::TouchEvent::TouchStart || tEvent.m_type == Platform::TouchEvent::TouchCancel)
+        d->m_pluginMayOpenNewTab = false;
+
+    bool handled = false;
+
+    if (d->m_needTouchEvents && !event.hasGesture(Platform::Gesture::Injected))
+        handled = d->m_mainFrame->eventHandler()->handleTouchEvent(PlatformTouchEvent(&tEvent));
+
+    // Unpress mouse if touch end is consumed by a JavaScript touch handler, otherwise the mouse state will remain pressed
+    // which could either mess up the internal mouse state or start text selection on the next mouse move/down.
+    if (tEvent.m_type == Platform::TouchEvent::TouchEnd && handled && d->m_mainFrame->eventHandler()->mousePressed())
+        d->m_touchEventHandler->touchEventCancel();
+
+    if (d->m_preventDefaultOnTouchStart) {
+        if (tEvent.m_type == Platform::TouchEvent::TouchEnd || tEvent.m_type == Platform::TouchEvent::TouchCancel)
+            d->m_preventDefaultOnTouchStart = false;
+        return true;
+    }
+
+    if (handled) {
+        if (tEvent.m_type == Platform::TouchEvent::TouchStart)
+            d->m_preventDefaultOnTouchStart = true;
+        return true;
+    }
+
+    if (event.hasGesture(Platform::Gesture::TouchHold))
+        d->m_touchEventHandler->touchHoldEvent();
+#endif
+
+    return false;
+}
+
+void WebPage::setScrollOriginPoint(const Platform::IntPoint& point)
+{
+    Platform::IntPoint untransformedPoint = d->mapFromTransformed(point);
+    d->setScrollOriginPoint(untransformedPoint);
+}
+
+void WebPagePrivate::setScrollOriginPoint(const Platform::IntPoint& point)
+{
+    m_inRegionScrollStartingNode = 0;
+
+    if (!m_hasInRegionScrollableAreas)
+        return;
+
+    m_client->notifyInRegionScrollingStartingPointChanged(inRegionScrollableAreasForPoint(point));
+}
+
+bool WebPagePrivate::dispatchTouchEventToFullScreenPlugin(PluginView* plugin, const Platform::TouchEvent& event)
+{
+    NPTouchEvent npTouchEvent;
+
+    if (event.hasGesture(Platform::Gesture::DoubleTap))
+        npTouchEvent.type = TOUCH_EVENT_DOUBLETAP;
+    else if (event.hasGesture(Platform::Gesture::TouchHold))
+        npTouchEvent.type = TOUCH_EVENT_TOUCHHOLD;
+    else {
+        switch (event.m_type) {
+        case Platform::TouchEvent::TouchStart:
+            npTouchEvent.type = TOUCH_EVENT_START;
+            break;
+        case Platform::TouchEvent::TouchEnd:
+            npTouchEvent.type = TOUCH_EVENT_END;
+            break;
+        case Platform::TouchEvent::TouchMove:
+            npTouchEvent.type = TOUCH_EVENT_MOVE;
+            break;
+        case Platform::TouchEvent::TouchCancel:
+            npTouchEvent.type = TOUCH_EVENT_CANCEL;
+            break;
+        default:
+            return false;
+        }
+    }
+
+    npTouchEvent.points = 0;
+    npTouchEvent.size = event.m_points.size();
+    if (npTouchEvent.size) {
+        npTouchEvent.points = new NPTouchPoint[npTouchEvent.size];
+        for (int i = 0; i < npTouchEvent.size; i++) {
+            npTouchEvent.points[i].touchId = event.m_points[i].m_id;
+            npTouchEvent.points[i].clientX = event.m_points[i].m_screenPos.x();
+            npTouchEvent.points[i].clientY = event.m_points[i].m_screenPos.y();
+            npTouchEvent.points[i].screenX = event.m_points[i].m_screenPos.x();
+            npTouchEvent.points[i].screenY = event.m_points[i].m_screenPos.y();
+            npTouchEvent.points[i].pageX = event.m_points[i].m_pos.x();
+            npTouchEvent.points[i].pageY = event.m_points[i].m_pos.y();
+        }
+    }
+
+    NPEvent npEvent;
+    npEvent.type = NP_TouchEvent;
+    npEvent.data = &npTouchEvent;
+
+    bool handled = plugin->dispatchFullScreenNPEvent(npEvent);
+
+    if (npTouchEvent.type == TOUCH_EVENT_DOUBLETAP && !handled) {
+        // Send Touch Up if double tap not consumed.
+        npTouchEvent.type = TOUCH_EVENT_END;
+        npEvent.data = &npTouchEvent;
+        handled = plugin->dispatchFullScreenNPEvent(npEvent);
+    }
+    delete[] npTouchEvent.points;
+    return handled;
+}
+
+bool WebPage::touchPointAsMouseEvent(const Platform::TouchPoint& point)
+{
+    PluginView* pluginView = d->m_fullScreenPluginView.get();
+    if (pluginView)
+        return d->dispatchTouchPointAsMouseEventToFullScreenPlugin(pluginView, point);
+
+    d->m_lastUserEventTimestamp = currentTime();
+
+    Platform::TouchPoint tPoint = point;
+    tPoint.m_pos = d->mapFromTransformed(tPoint.m_pos);
+    tPoint.m_screenPos = d->mapFromTransformed(tPoint.m_screenPos);
+
+    return d->m_touchEventHandler->handleTouchPoint(tPoint);
+}
+
+bool WebPagePrivate::dispatchTouchPointAsMouseEventToFullScreenPlugin(PluginView* pluginView, const Platform::TouchPoint& point)
+{
+    NPEvent npEvent;
+    NPMouseEvent mouse;
+
+    switch (point.m_state) {
+    case Platform::TouchPoint::TouchPressed:
+        mouse.type = MOUSE_BUTTON_DOWN;
+        break;
+    case Platform::TouchPoint::TouchReleased:
+        mouse.type = MOUSE_BUTTON_UP;
+        break;
+    case Platform::TouchPoint::TouchMoved:
+        mouse.type = MOUSE_MOTION;
+        break;
+    case Platform::TouchPoint::TouchStationary:
+        return false;
+    }
+
+    mouse.x = point.m_screenPos.x();
+    mouse.y = point.m_screenPos.y();
+    mouse.button = mouse.type != MOUSE_BUTTON_UP;
+    mouse.flags = 0;
+    npEvent.type = NP_MouseEvent;
+    npEvent.data = &mouse;
+
+    return pluginView->dispatchFullScreenNPEvent(npEvent);
+}
+
+void WebPage::touchEventCancel()
+{
+    d->m_pluginMayOpenNewTab = false;
+    d->m_touchEventHandler->touchEventCancel();
+}
+
+void WebPage::touchEventCancelAndClearFocusedNode()
+{
+    d->m_touchEventHandler->touchEventCancelAndClearFocusedNode();
+}
+
+Frame* WebPagePrivate::focusedOrMainFrame() const
+{
+    return m_page->focusController()->focusedOrMainFrame();
+}
+
+void WebPagePrivate::clearFocusNode()
+{
+    Frame* frame = focusedOrMainFrame();
+    if (!frame)
+        return;
+    ASSERT(frame->document());
+
+    if (frame->document()->focusedNode())
+        frame->page()->focusController()->setFocusedNode(0, frame);
+}
+
+bool WebPagePrivate::scrollNodeRecursively(Node* node, const IntSize& delta)
+{
+    if (delta.isZero())
+        return true;
+
+    if (!node)
+        return false;
+
+    RenderObject* renderer = node->renderer();
+    if (!renderer)
+        return false;
+
+    FrameView* view = renderer->view()->frameView();
+    if (!view)
+        return false;
+
+    // Try scrolling the renderer.
+    if (scrollRenderer(renderer, delta))
+        return true;
+
+    // We've hit the page, don't scroll it and return false.
+    if (view == m_mainFrame->view())
+        return false;
+
+    // Try scrolling the FrameView.
+    if (canScrollInnerFrame(view->frame())) {
+        IntSize viewDelta = delta;
+        IntPoint newViewOffset = view->scrollPosition();
+        IntPoint maxViewOffset = view->maximumScrollPosition();
+        adjustScrollDelta(maxViewOffset, newViewOffset, viewDelta);
+
+        if (!viewDelta.isZero()) {
+            view->setCanBlitOnScroll(false);
+
+            BackingStoreClient* backingStoreClient = backingStoreClientForFrame(view->frame());
+            if (backingStoreClient) {
+                backingStoreClient->setIsClientGeneratedScroll(true);
+                backingStoreClient->setIsScrollNotificationSuppressed(true);
+            }
+
+            m_inRegionScrollStartingNode = view->frame()->document();
+
+            view->scrollBy(viewDelta);
+
+            if (backingStoreClient) {
+                backingStoreClient->setIsClientGeneratedScroll(false);
+                backingStoreClient->setIsScrollNotificationSuppressed(false);
+            }
+
+            return true;
+        }
+    }
+
+    // Try scrolling the node of the enclosing frame.
+    Frame* frame = node->document()->frame();
+    if (frame) {
+        Node* ownerNode = frame->ownerElement();
+        if (scrollNodeRecursively(ownerNode, delta))
+            return true;
+    }
+
+    return false;
+}
+
+void WebPagePrivate::adjustScrollDelta(const IntPoint& maxOffset, const IntPoint& currentOffset, IntSize& delta) const
+{
+    if (currentOffset.x() + delta.width() > maxOffset.x())
+        delta.setWidth(min(maxOffset.x() - currentOffset.x(), delta.width()));
+
+    if (currentOffset.x() + delta.width() < 0)
+        delta.setWidth(max(-currentOffset.x(), delta.width()));
+
+    if (currentOffset.y() + delta.height() > maxOffset.y())
+        delta.setHeight(min(maxOffset.y() - currentOffset.y(), delta.height()));
+
+    if (currentOffset.y() + delta.height() < 0)
+        delta.setHeight(max(-currentOffset.y(), delta.height()));
+}
+
+static Node* enclosingLayerNode(RenderLayer*);
+
+bool WebPagePrivate::scrollRenderer(RenderObject* renderer, const IntSize& delta)
+{
+    RenderLayer* layer = renderer->enclosingLayer();
+    if (!layer)
+        return false;
+
+    // Try to scroll layer.
+    bool restrictedByLineClamp = false;
+    if (renderer->parent())
+        restrictedByLineClamp = !renderer->parent()->style()->lineClamp().isNone();
+
+    if (renderer->hasOverflowClip() && !restrictedByLineClamp) {
+        IntSize layerDelta = delta;
+        IntPoint maxOffset(layer->scrollWidth() - layer->renderBox()->clientWidth(), layer->scrollHeight() - layer->renderBox()->clientHeight());
+        IntPoint currentOffset(layer->scrollXOffset(), layer->scrollYOffset());
+        adjustScrollDelta(maxOffset, currentOffset, layerDelta);
+        if (!layerDelta.isZero()) {
+            m_inRegionScrollStartingNode = enclosingLayerNode(layer);
+            IntPoint newOffset = currentOffset + layerDelta;
+            layer->scrollToOffset(newOffset.x(), newOffset.y());
+            renderer->repaint(true);
+            return true;
+        }
+    }
+
+    while (layer = layer->parent()) {
+        if (canScrollRenderBox(layer->renderBox()))
+            return scrollRenderer(layer->renderBox(), delta);
+    }
+
+    return false;
+}
+
+static void handleScrolling(unsigned short character, WebPagePrivate* scroller)
+{
+    const int scrollFactor = 20;
+    int dx = 0, dy = 0;
+    switch (character) {
+    case KEYCODE_LEFT:
+        dx = -scrollFactor;
+        break;
+    case KEYCODE_RIGHT:
+        dx = scrollFactor;
+        break;
+    case KEYCODE_UP:
+        dy = -scrollFactor;
+        break;
+    case KEYCODE_DOWN:
+        dy = scrollFactor;
+        break;
+    case KEYCODE_PG_UP:
+        ASSERT(scroller);
+        dy = scrollFactor - scroller->actualVisibleSize().height();
+        break;
+    case KEYCODE_PG_DOWN:
+        ASSERT(scroller);
+        dy = scroller->actualVisibleSize().height() - scrollFactor;
+        break;
+    }
+
+    if (dx || dy) {
+        // Don't use the scrollBy function because it triggers the scroll as originating from BlackBerry
+        // but then it expects a separate invalidate which isn't sent in this case.
+        ASSERT(scroller && scroller->m_mainFrame && scroller->m_mainFrame->view());
+        IntPoint pos(scroller->scrollPosition() + IntSize(dx, dy));
+
+        // Prevent over scrolling for arrows and Page up/down.
+        if (pos.x() < 0)
+            pos.setX(0);
+        if (pos.y() < 0)
+            pos.setY(0);
+        if (pos.x() + scroller->actualVisibleSize().width() > scroller->contentsSize().width())
+            pos.setX(scroller->contentsSize().width() - scroller->actualVisibleSize().width());
+        if (pos.y() + scroller->actualVisibleSize().height() > scroller->contentsSize().height())
+            pos.setY(scroller->contentsSize().height() - scroller->actualVisibleSize().height());
+
+        scroller->m_mainFrame->view()->setScrollPosition(pos);
+        scroller->m_client->scrollChanged(pos);
+    }
+}
+
+bool WebPage::keyEvent(const Platform::KeyboardEvent& keyboardEvent)
+{
+    if (!d->m_mainFrame->view())
+        return false;
+
+    ASSERT(d->m_page->focusController());
+
+    bool handled = d->m_inputHandler->handleKeyboardInput(keyboardEvent);
+
+    if (!handled && keyboardEvent.type() == Platform::KeyboardEvent::KeyDown && !d->m_inputHandler->isInputMode()) {
+        IntPoint previousPos = d->scrollPosition();
+        handleScrolling(keyboardEvent.character(), d);
+        handled = previousPos != d->scrollPosition();
+    }
+
+    return handled;
+}
+
+bool WebPage::deleteTextRelativeToCursor(unsigned int leftOffset, unsigned int rightOffset)
+{
+    return d->m_inputHandler->deleteTextRelativeToCursor(leftOffset, rightOffset);
+}
+
+spannable_string_t* WebPage::selectedText(int32_t flags)
+{
+    return d->m_inputHandler->selectedText(flags);
+}
+
+spannable_string_t* WebPage::textBeforeCursor(int32_t length, int32_t flags)
+{
+    return d->m_inputHandler->textBeforeCursor(length, flags);
+}
+
+spannable_string_t* WebPage::textAfterCursor(int32_t length, int32_t flags)
+{
+    return d->m_inputHandler->textAfterCursor(length, flags);
+}
+
+extracted_text_t* WebPage::extractedTextRequest(extracted_text_request_t* request, int32_t flags)
+{
+    return d->m_inputHandler->extractedTextRequest(request, flags);
+}
+
+int32_t WebPage::setComposingRegion(int32_t start, int32_t end)
+{
+    return d->m_inputHandler->setComposingRegion(start, end);
+}
+
+int32_t WebPage::finishComposition()
+{
+    return d->m_inputHandler->finishComposition();
+}
+
+int32_t WebPage::setComposingText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
+{
+    return d->m_inputHandler->setComposingText(spannableString, relativeCursorPosition);
+}
+
+int32_t WebPage::commitText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
+{
+    return d->m_inputHandler->commitText(spannableString, relativeCursorPosition);
+}
+
+void WebPage::spellCheckingEnabled(bool enabled)
+{
+    static_cast<EditorClientBlackBerry*>(d->m_page->editorClient())->enableSpellChecking(enabled);
+}
+
+void WebPage::selectionCancelled()
+{
+    d->m_selectionHandler->cancelSelection();
+}
+
+bool WebPage::selectionContains(const Platform::IntPoint& point)
+{
+    return d->m_selectionHandler->selectionContains(d->mapFromTransformed(point));
+}
+
+WebString WebPage::title() const
+{
+    if (d->m_mainFrame->document())
+        return d->m_mainFrame->loader()->documentLoader()->title().string();
+    return WebString();
+}
+
+WebString WebPage::selectedText() const
+{
+    return d->m_selectionHandler->selectedText();
+}
+
+WebString WebPage::cutSelectedText()
+{
+    WebString selectedText = d->m_selectionHandler->selectedText();
+    if (!selectedText.isEmpty())
+        d->m_inputHandler->deleteSelection();
+    return selectedText;
+}
+
+void WebPage::insertText(const WebString& string)
+{
+    d->m_inputHandler->insertText(string);
+}
+
+void WebPage::clearCurrentInputField()
+{
+    d->m_inputHandler->clearField();
+}
+
+void WebPage::cut()
+{
+    d->m_inputHandler->cut();
+}
+
+void WebPage::copy()
+{
+    d->m_inputHandler->copy();
+}
+
+void WebPage::paste()
+{
+    d->m_inputHandler->paste();
+}
+
+void WebPage::setSelection(const Platform::IntPoint& startPoint, const Platform::IntPoint& endPoint)
+{
+    // Transform this events coordinates to webkit content coordinates.
+    // FIXME: Don't transform the sentinel, because it may be transformed to a floating number
+    // which could be rounded to 0 or other numbers. This workaround should be removed after
+    // the error of roundUntransformedPoint() is fixed.
+    bool invalidPoint = IntPoint(startPoint) == DOMSupport::InvalidPoint;
+    IntPoint start = invalidPoint ? DOMSupport::InvalidPoint : d->mapFromTransformed(startPoint);
+    invalidPoint = IntPoint(endPoint) == DOMSupport::InvalidPoint;
+    IntPoint end = invalidPoint ? DOMSupport::InvalidPoint : d->mapFromTransformed(endPoint);
+
+    d->m_selectionHandler->setSelection(start, end);
+}
+
+void WebPage::setCaretPosition(const Platform::IntPoint& position)
+{
+    // Handled by selection handler as it's point based.
+    // Transform this events coordinates to webkit content coordinates.
+    d->m_selectionHandler->setCaretPosition(d->mapFromTransformed(position));
+}
+
+void WebPage::selectAtPoint(const Platform::IntPoint& location)
+{
+    // Transform this events coordinates to webkit content coordinates if it
+    // is not the sentinel value.
+    IntPoint selectionLocation =
+            IntPoint(location) == DOMSupport::InvalidPoint ?
+            DOMSupport::InvalidPoint :
+            d->mapFromTransformed(location);
+
+    d->m_selectionHandler->selectAtPoint(selectionLocation);
+}
+
+// Returned scroll position is in transformed coordinates.
+Platform::IntPoint WebPage::scrollPosition() const
+{
+    return d->transformedScrollPosition();
+}
+
+// Setting the scroll position is in transformed coordinates.
+void WebPage::setScrollPosition(const Platform::IntPoint& point)
+{
+    if (d->transformedPointEqualsUntransformedPoint(point, d->scrollPosition()))
+        return;
+
+    // If the user recently performed an event, this new scroll position
+    // could possibly be a result of that. Or not, this is just a heuristic.
+    if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
+        d->m_userPerformedManualScroll = true;
+
+    d->m_backingStoreClient->setIsClientGeneratedScroll(true);
+    d->m_mainFrame->view()->setCanOverscroll(true);
+    d->setScrollPosition(d->mapFromTransformed(point));
+    d->m_mainFrame->view()->setCanOverscroll(false);
+    d->m_backingStoreClient->setIsClientGeneratedScroll(false);
+}
+
+WebString WebPage::textEncoding()
+{
+    Frame* frame = d->focusedOrMainFrame();
+    if (!frame)
+        return "";
+
+    Document* document = frame->document();
+    if (!document)
+        return "";
+
+    return document->loader()->writer()->encoding();
+}
+
+WebString WebPage::forcedTextEncoding()
+{
+    Frame* frame = d->focusedOrMainFrame();
+    if (!frame)
+        return "";
+
+    Document* document = frame->document();
+    if (!document)
+        return "";
+
+    return document->loader()->overrideEncoding();
+}
+
+void WebPage::setForcedTextEncoding(const char* encoding)
+{
+    if (encoding && d->focusedOrMainFrame() && d->focusedOrMainFrame()->loader() && d->focusedOrMainFrame()->loader())
+        return d->focusedOrMainFrame()->loader()->reloadWithOverrideEncoding(encoding);
+}
+
+// FIXME: Move to DOMSupport.
+bool WebPagePrivate::canScrollInnerFrame(Frame* frame) const
+{
+    if (!frame || !frame->view())
+        return false;
+
+    // Not having an owner element means that we are on the mainframe.
+    if (!frame->ownerElement())
+        return false;
+
+    ASSERT(frame != m_mainFrame);
+
+    IntSize visibleSize = frame->view()->visibleContentRect().size();
+    IntSize contentsSize = frame->view()->contentsSize();
+
+    bool canBeScrolled = contentsSize.height() > visibleSize.height() || contentsSize.width() > visibleSize.width();
+
+    // Lets also consider the 'overflow-{x,y} property set directly to the {i}frame tag.
+    return canBeScrolled && (frame->ownerElement()->scrollingMode() != ScrollbarAlwaysOff);
+}
+
+// The RenderBox::canbeScrolledAndHasScrollableArea method returns true for the
+// following scenario, for example:
+// (1) a div that has a vertical overflow but no horizontal overflow
+//     with overflow-y: hidden and overflow-x: auto set.
+// The version below fixes it.
+// FIXME: Fix RenderBox::canBeScrolledAndHasScrollableArea method instead.
+bool WebPagePrivate::canScrollRenderBox(RenderBox* box)
+{
+    if (!box || !box->hasOverflowClip())
+        return false;
+
+    if (box->scrollsOverflowX() && (box->scrollWidth() != box->clientWidth())
+        || box->scrollsOverflowY() && (box->scrollHeight() != box->clientHeight()))
+        return true;
+
+    Node* node = box->node();
+    return node && (node->rendererIsEditable() || node->isDocumentNode());
+}
+
+static RenderLayer* parentLayer(RenderLayer* layer)
+{
+    ASSERT(layer);
+
+    if (layer->parent())
+        return layer->parent();
+
+    RenderObject* renderer = layer->renderer();
+    if (renderer->document() && renderer->document()->ownerElement() && renderer->document()->ownerElement()->renderer())
+        return renderer->document()->ownerElement()->renderer()->enclosingLayer();
+
+    return 0;
+}
+
+// FIXME: Make RenderLayer::enclosingElement public so this one can be removed.
+static Node* enclosingLayerNode(RenderLayer* layer)
+{
+    for (RenderObject* r = layer->renderer(); r; r = r->parent()) {
+        if (Node* e = r->node())
+            return e;
+    }
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
+static void pushBackInRegionScrollable(std::vector<Platform::ScrollViewBase>& vector, InRegionScrollableArea scroller, WebPagePrivate* webPage)
+{
+    ASSERT(webPage);
+    ASSERT(!scroller.isNull());
+
+    scroller.setCanPropagateScrollingToEnclosingScrollable(!isNonRenderViewFixedPositionedContainer(scroller.layer()));
+    vector.push_back(scroller);
+    if (vector.size() == 1) {
+        // FIXME: Use RenderLayer::renderBox()->node() instead?
+        webPage->m_inRegionScrollStartingNode = enclosingLayerNode(scroller.layer());
+    }
+}
+
+std::vector<Platform::ScrollViewBase> WebPagePrivate::inRegionScrollableAreasForPoint(const Platform::IntPoint& point)
+{
+    std::vector<Platform::ScrollViewBase> validReturn;
+    std::vector<Platform::ScrollViewBase> emptyReturn;
+
+    HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromViewportToContents(point), false /*allowShadowContent*/);
+    Node* node = result.innerNonSharedNode();
+    if (!node)
+        return emptyReturn;
+
+    RenderObject* renderer = node->renderer();
+    // FIXME: Validate with elements with visibility:hidden.
+    if (!renderer)
+        return emptyReturn;
+
+    RenderLayer* layer = renderer->enclosingLayer();
+
+    do {
+        RenderObject* renderer = layer->renderer();
+
+        if (renderer->isRenderView()) {
+            if (RenderView* renderView = toRenderView(renderer)) {
+                FrameView* view = renderView->frameView();
+                if (!view)
+                    return emptyReturn;
+
+                if (canScrollInnerFrame(view->frame())) {
+                    pushBackInRegionScrollable(validReturn, InRegionScrollableArea(this, layer), this);
+                    continue;
+                }
+            }
+        } else if (canScrollRenderBox(layer->renderBox())) {
+            pushBackInRegionScrollable(validReturn, InRegionScrollableArea(this, layer), this);
+            continue;
+        }
+
+        // If we run into a fix positioned layer, set the last scrollable in-region object
+        // as not able to propagate scroll to its parent scrollable.
+        if (isNonRenderViewFixedPositionedContainer(layer) && validReturn.size()) {
+            Platform::ScrollViewBase& end = validReturn.back();
+            end.setCanPropagateScrollingToEnclosingScrollable(false);
+        }
+
+    } while (layer = parentLayer(layer));
+
+    if (validReturn.empty())
+        return emptyReturn;
+
+    return validReturn;
+}
+
+BackingStore* WebPage::backingStore() const
+{
+    return d->m_backingStore;
+}
+
+bool WebPage::zoomToFit()
+{
+    if (d->contentsSize().isEmpty() || !d->isUserScalable())
+        return false;
+
+    d->m_userPerformedManualZoom = true;
+
+    // TODO: We may need to use (0,0) as the anchor point when textReflow is enabled.
+    // IF the minimum font size is ginormous, we may still want the scroll position to be 0,0.
+    return d->zoomAboutPoint(d->zoomToFitScale(), d->centerOfVisibleContentsRect());
+}
+
+void WebPagePrivate::setTextReflowAnchorPoint(const Platform::IntPoint& focalPoint)
+{
+    // Should only be invoked when text reflow is enabled.
+    ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
+
+    m_currentPinchZoomNode = bestNodeForZoomUnderPoint(focalPoint);
+    if (!m_currentPinchZoomNode)
+        return;
+
+    IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
+    m_anchorInNodeRectRatio.set(static_cast<float>(mapFromTransformed(focalPoint).x() - nodeRect.x()) / nodeRect.width(),
+                                static_cast<float>(mapFromTransformed(focalPoint).y() - nodeRect.y()) / nodeRect.height());
+}
+
+bool WebPage::pinchZoomAboutPoint(double scale, int x, int y)
+{
+    IntPoint anchor(x, y);
+    d->m_userPerformedManualZoom = true;
+    d->m_userPerformedManualScroll = true;
+
+    if (d->m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
+        d->setTextReflowAnchorPoint(anchor);
+        // Theoretically, d->nodeForZoomUnderPoint(anchor) can return null.
+        if (!d->m_currentPinchZoomNode)
+            return false;
+    }
+
+    return d->zoomAboutPoint(scale, d->mapFromTransformed(anchor));
+}
+
+#if ENABLE(VIEWPORT_REFLOW)
+void WebPagePrivate::toggleTextReflowIfEnabledForBlockZoomOnly(bool shouldEnableTextReflow)
+{
+    if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabledOnlyForBlockZoom)
+        m_page->settings()->setTextReflowEnabled(shouldEnableTextReflow);
+}
+#endif
+
+bool WebPage::blockZoom(int x, int y)
+{
+    if (!d->m_mainFrame->view() || !d->isUserScalable())
+        return false;
+
+    Node* node = d->bestNodeForZoomUnderPoint(IntPoint(x, y));
+    if (!node)
+        return false;
+
+    IntRect nodeRect = d->rectForNode(node);
+    IntRect blockRect;
+    bool endOfBlockZoomMode = d->compareNodesForBlockZoom(d->m_currentBlockZoomAdjustedNode.get(), node);
+    const double oldScale = d->m_transformationMatrix->m11();
+    double newScale = 0;
+    const double margin = endOfBlockZoomMode ? 0 : blockZoomMargin * 2 * oldScale;
+    bool isFirstZoom = false;
+
+    if (endOfBlockZoomMode) {
+        // End of block zoom mode
+        IntRect rect = d->blockZoomRectForNode(node);
+        blockRect = IntRect(0, rect.y(), d->transformedContentsSize().width(), d->transformedContentsSize().height() - rect.y());
+        d->m_shouldReflowBlock = false;
+    } else {
+        // Start/continue block zoom mode
+        Node* tempBlockZoomAdjustedNode = d->m_currentBlockZoomAdjustedNode.get();
+        blockRect = d->blockZoomRectForNode(node);
+
+        // Don't use a block if it is too close to the size of the actual contents.
+        // We allow this for images only so that they can be zoomed tight to the screen.
+        if (!node->hasTagName(HTMLNames::imgTag)) {
+            IntRect tRect = d->mapFromTransformed(blockRect);
+            int blockArea = tRect.width() * tRect.height();
+            int pageArea = d->contentsSize().width() * d->contentsSize().height();
+            double blockToPageRatio = static_cast<double>(1 - blockArea / pageArea);
+            if (blockToPageRatio < minimumExpandingRatio) {
+                // Restore old adjust node because zoom was canceled.
+                d->m_currentBlockZoomAdjustedNode = tempBlockZoomAdjustedNode;
+                return false;
+            }
+        }
+
+        if (blockRect.isEmpty() || !blockRect.width() || !blockRect.height())
+            return false;
+
+        if (!d->m_currentBlockZoomNode.get())
+            isFirstZoom = true;
+
+        d->m_currentBlockZoomNode = node;
+        d->m_shouldReflowBlock = true;
+    }
+
+    newScale = std::min(d->newScaleForBlockZoomRect(blockRect, oldScale, margin), d->maxBlockZoomScale());
+    newScale = std::max(newScale, minimumScale());
+
+#if DEBUG_BLOCK_ZOOM
+    // Render the double tap point for visual reference.
+    IntRect renderRect(x, y, 1, 1);
+    renderRect = d->mapFromTransformedContentsToTransformedViewport(renderRect);
+    IntSize viewportSize = d->transformedViewportSize();
+    renderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
+    d->m_backingStore->d->clearWindow(renderRect, 0, 0, 0);
+    d->m_backingStore->d->invalidateWindow(renderRect);
+
+    // Uncomment this to return in order to see the blocks being selected.
+    // d->m_client->zoomChanged(isMinZoomed(), isMaxZoomed(), isAtInitialZoom(), currentZoomLevel());
+    // return true;
+#endif
+
+#if ENABLE(VIEWPORT_REFLOW)
+    // If reflowing, adjust the reflow-width of text node to make sure the font is a reasonable size.
+    if (d->m_currentBlockZoomNode && d->m_shouldReflowBlock && settings()->textReflowMode() != WebSettings::TextReflowDisabled) {
+        RenderObject* renderer = d->m_currentBlockZoomNode->renderer();
+        if (renderer && renderer->isText()) {
+            double newFontSize = renderer->style()->fontSize() * newScale;
+            if (newFontSize < d->m_webSettings->defaultFontSize()) {
+                newScale = std::min(static_cast<double>(d->m_webSettings->defaultFontSize()) / renderer->style()->fontSize(), d->maxBlockZoomScale());
+                newScale = std::max(newScale, minimumScale());
+            }
+            blockRect.setWidth(oldScale * static_cast<double>(d->transformedActualVisibleSize().width()) / newScale);
+            // Re-calculate the scale here to take in to account the margin.
+            newScale = std::min(d->newScaleForBlockZoomRect(blockRect, oldScale, margin), d->maxBlockZoomScale());
+            newScale = std::max(newScale, minimumScale()); // Still, it's not allowed to be smaller than minimum scale.
+        }
+    }
+#endif
+
+    // Align the zoomed block in the screen.
+    double newBlockHeight = d->mapFromTransformed(blockRect).height();
+    double newBlockWidth = d->mapFromTransformed(blockRect).width();
+    double scaledViewportWidth = static_cast<double>(d->actualVisibleSize().width()) * oldScale / newScale;
+    double scaledViewportHeight = static_cast<double>(d->actualVisibleSize().height()) * oldScale / newScale;
+    double dx = std::max(0.0, (scaledViewportWidth - newBlockWidth) / 2.0);
+    double dy = std::max(0.0, (scaledViewportHeight - newBlockHeight) / 2.0);
+
+    RenderObject* renderer = d->m_currentBlockZoomAdjustedNode->renderer();
+    FloatPoint anchor;
+    FloatPoint topLeftPoint(d->mapFromTransformed(blockRect).location());
+    if (renderer && renderer->isText()) {
+        ETextAlign textAlign = renderer->style()->textAlign();
+        switch (textAlign) {
+        case CENTER:
+        case WEBKIT_CENTER:
+            anchor = FloatPoint(nodeRect.x() + (nodeRect.width() - scaledViewportWidth) / 2, topLeftPoint.y());
+            break;
+        case LEFT:
+        case WEBKIT_LEFT:
+            anchor = topLeftPoint;
+            break;
+        case RIGHT:
+        case WEBKIT_RIGHT:
+            anchor = FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y());
+            break;
+        case TAAUTO:
+        case JUSTIFY:
+        default:
+            if (renderer->style()->isLeftToRightDirection())
+                anchor = topLeftPoint;
+            else
+                anchor = FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y());
+            break;
+        }
+    } else
+        anchor = renderer->style()->isLeftToRightDirection() ? topLeftPoint : FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y());
+
+    if (newBlockHeight <= scaledViewportHeight) {
+        // The block fits in the viewport so center it.
+        d->m_finalBlockPoint = FloatPoint(anchor.x() - dx, anchor.y() - dy);
+    } else {
+        // The block is longer than the viewport so top align it and add 3 pixel margin.
+        d->m_finalBlockPoint = FloatPoint(anchor.x() - dx, anchor.y() - 3);
+    }
+
+#if ENABLE(VIEWPORT_REFLOW)
+    // We don't know how long the reflowed block will be so we position it at the top of the screen with a small margin.
+    if (settings()->textReflowMode() != WebSettings::TextReflowDisabled) {
+        d->m_finalBlockPoint = FloatPoint(anchor.x() - dx, anchor.y() - 3);
+        d->m_finalBlockPointReflowOffset = FloatPoint(-dx, -3);
+    }
+#endif
+
+    // Make sure that the original node rect is visible in the screen after the zoom. This is necessary because the identified block rect might
+    // not be the same as the original node rect, and it could force the original node rect off the screen.
+    FloatRect br(anchor, FloatSize(scaledViewportWidth, scaledViewportHeight));
+    IntPoint clickPoint = d->mapFromTransformed(IntPoint(x, y));
+    if (!br.contains(clickPoint)) {
+        d->m_finalBlockPointReflowOffset.move(0, (clickPoint.y() - scaledViewportHeight / 2) - d->m_finalBlockPoint.y());
+        d->m_finalBlockPoint = FloatPoint(d->m_finalBlockPoint.x(), clickPoint.y() - scaledViewportHeight / 2);
+    }
+
+    // Clamp the finalBlockPoint to not cause any overflow scrolling.
+    if (d->m_finalBlockPoint.x() < 0) {
+        d->m_finalBlockPoint.setX(0);
+        d->m_finalBlockPointReflowOffset.setX(0);
+    } else if (d->m_finalBlockPoint.x() + scaledViewportWidth > d->contentsSize().width()) {
+        d->m_finalBlockPoint.setX(d->contentsSize().width() - scaledViewportWidth);
+        d->m_finalBlockPointReflowOffset.setX(0);
+    }
+
+    if (d->m_finalBlockPoint.y() < 0) {
+        d->m_finalBlockPoint.setY(0);
+        d->m_finalBlockPointReflowOffset.setY(0);
+    } else if (d->m_finalBlockPoint.y() + scaledViewportHeight > d->contentsSize().height()) {
+        d->m_finalBlockPoint.setY(d->contentsSize().height() - scaledViewportHeight);
+        d->m_finalBlockPointReflowOffset.setY(0);
+    }
+
+    d->m_finalBlockPoint = d->mapToTransformedFloatPoint(d->m_finalBlockPoint);
+
+    // Don't block zoom if the user is zooming and the new scale is only marginally different from the
+    // oldScale with only a marginal change in scroll position. Ignore scroll difference in the special case
+    // that the zoom level is the minimumScale.
+    if (!endOfBlockZoomMode && abs(newScale - oldScale) / oldScale < minimumExpandingRatio) {
+        const double minimumDisplacement = minimumExpandingRatio * d->transformedActualVisibleSize().width();
+        if (oldScale == d->minimumScale() || (distanceBetweenPoints(roundTransformedPoint(d->mapToTransformed(d->scrollPosition())), roundTransformedPoint(d->m_finalBlockPoint)) < minimumDisplacement && abs(newScale - oldScale) / oldScale < 0.10)) {
+            if (isFirstZoom) {
+                d->resetBlockZoom();
+                return false;
+            }
+            // Zoom out of block zoom.
+            blockZoom(x, y);
+            return true;
+        }
+    }
+
+    d->m_blockZoomFinalScale = newScale;
+
+    // We set this here to make sure we don't try to re-render the page at a different zoom level during loading.
+    d->m_userPerformedManualZoom = true;
+    d->m_userPerformedManualScroll = true;
+    d->m_client->animateBlockZoom(d->m_finalBlockPoint, d->m_blockZoomFinalScale);
+
+    return true;
+}
+
+bool WebPage::isMaxZoomed() const
+{
+    return (d->currentScale() == d->maximumScale()) || !d->isUserScalable();
+}
+
+bool WebPage::isMinZoomed() const
+{
+    return (d->currentScale() == d->minimumScale()) || !d->isUserScalable();
+}
+
+bool WebPage::isAtInitialZoom() const
+{
+    return (d->currentScale() == d->initialScale()) || !d->isUserScalable();
+}
+
+bool WebPagePrivate::shouldZoomOnEscape() const
+{
+    if (!isUserScalable())
+        return false;
+
+    // If the initial scale is not reachable, don't try to zoom.
+    if (initialScale() < minimumScale() || initialScale() > maximumScale())
+        return false;
+
+    // Don't ever zoom in when we press escape.
+    if (initialScale() >= currentScale())
+        return false;
+
+    return currentScale() != initialScale();
+}
+
+void WebPage::zoomToInitialScale()
+{
+    if (!d->isUserScalable())
+        return;
+
+    d->zoomAboutPoint(d->initialScale(), d->centerOfVisibleContentsRect());
+}
+
+bool WebPage::zoomToOneOne()
+{
+    if (!d->isUserScalable())
+        return false;
+
+    double scale = 1;
+    return d->zoomAboutPoint(scale, d->centerOfVisibleContentsRect());
+}
+
+Platform::IntRect WebPage::focusNodeRect()
+{
+    return d->focusNodeRect();
+}
+
+void WebPage::setFocused(bool focused)
+{
+    FocusController* focusController = d->m_page->focusController();
+    focusController->setActive(focused);
+    if (focused) {
+        Frame* frame = focusController->focusedFrame();
+        if (!frame)
+            focusController->setFocusedFrame(d->m_mainFrame);
+    }
+    focusController->setFocused(focused);
+}
+
+bool WebPage::findNextString(const char* text, bool forward)
+{
+    return d->m_inPageSearchManager->findNextString(String::fromUTF8(text), forward);
+}
+
+void WebPage::runLayoutTests()
+{
+#if ENABLE_DRT
+    // FIXME: do we need API to toggle this?
+    d->m_page->settings()->setDeveloperExtrasEnabled(true);
+
+    if (!d->m_dumpRenderTree)
+        d->m_dumpRenderTree = new DumpRenderTree(this);
+    d->m_dumpRenderTree->runTests();
+#endif
+}
+
+bool WebPage::enableScriptDebugger()
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        return true;
+
+    d->m_scriptDebugger = adoptPtr(new JavaScriptDebuggerBlackBerry(this->d));
+
+    return !!d->m_scriptDebugger;
+#endif
+}
+
+bool WebPage::disableScriptDebugger()
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (!d->m_scriptDebugger)
+        return true;
+
+    d->m_scriptDebugger.clear();
+    return true;
+#endif
+}
+
+void WebPage::addBreakpoint(const unsigned short* url, unsigned urlLength, int lineNumber, const unsigned short* condition, unsigned conditionLength)
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        d->m_scriptDebugger->addBreakpoint(url, urlLength, lineNumber, condition, conditionLength);
+#endif
+}
+
+void WebPage::updateBreakpoint(const unsigned short* url, unsigned urlLength, int lineNumber, const unsigned short* condition, unsigned conditionLength)
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        d->m_scriptDebugger->updateBreakpoint(url, urlLength, lineNumber, condition, conditionLength);
+#endif
+}
+
+void WebPage::removeBreakpoint(const unsigned short* url, unsigned urlLength, int lineNumber)
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        d->m_scriptDebugger->removeBreakpoint(url, urlLength, lineNumber);
+#endif
+}
+
+bool WebPage::pauseOnExceptions()
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    return d->m_scriptDebugger ? d->m_scriptDebugger->pauseOnExceptions() : false;
+#endif
+}
+
+void WebPage::setPauseOnExceptions(bool pause)
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        d->m_scriptDebugger->setPauseOnExceptions(pause);
+#endif
+}
+
+void WebPage::pauseInDebugger()
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        d->m_scriptDebugger->pauseInDebugger();
+#endif
+}
+
+void WebPage::resumeDebugger()
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        d->m_scriptDebugger->resumeDebugger();
+#endif
+}
+
+void WebPage::stepOverStatementInDebugger()
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        d->m_scriptDebugger->stepOverStatementInDebugger();
+#endif
+}
+
+void WebPage::stepIntoStatementInDebugger()
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        d->m_scriptDebugger->stepIntoStatementInDebugger();
+#endif
+}
+
+void WebPage::stepOutOfFunctionInDebugger()
+{
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    if (d->m_scriptDebugger)
+        d->m_scriptDebugger->stepOutOfFunctionInDebugger();
+#endif
+}
+
+unsigned WebPage::timeoutForJavaScriptExecution() const
+{
+    return Settings::timeoutForJavaScriptExecution(d->m_page->groupName());
+}
+
+void WebPage::setTimeoutForJavaScriptExecution(unsigned ms)
+{
+    Settings::setTimeoutForJavaScriptExecution(d->m_page->groupName(), ms);
+
+    Document* doc = d->m_page->mainFrame()->document();
+    if (!doc)
+        return;
+
+    doc->globalData()->timeoutChecker.setTimeoutInterval(ms);
+}
+
+JSContextRef WebPage::scriptContext() const
+{
+    if (!d->m_mainFrame)
+        return 0;
+
+    JSC::Bindings::RootObject *root = d->m_mainFrame->script()->bindingRootObject();
+    if (!root)
+        return 0;
+
+    JSC::ExecState *exec = root->globalObject()->globalExec();
+    return toRef(exec);
+}
+
+JSValueRef WebPage::windowObject() const
+{
+    return toRef(d->m_mainFrame->script()->globalObject(mainThreadNormalWorld()));
+}
+
+// Serialize only the members of HistoryItem which are needed by the client,
+// and copy them into a SharedArray. Also include the HistoryItem pointer which
+// will be used by the client as an opaque reference to identify the item.
+void WebPage::getBackForwardList(SharedArray<BackForwardEntry>& result, unsigned int& resultSize) const
+{
+    HistoryItemVector entries = static_cast<BackForwardListImpl*>(d->m_page->backForward()->client())->entries();
+    resultSize = entries.size();
+    result.reset(new BackForwardEntry[resultSize]);
+
+    for (unsigned i = 0; i < resultSize; ++i) {
+        RefPtr<HistoryItem> entry = entries[i];
+        BackForwardEntry& resultEntry = result[i];
+        resultEntry.url = entry->urlString();
+        resultEntry.originalUrl = entry->originalURLString();
+        resultEntry.title = entry->title();
+        resultEntry.networkToken = entry->viewState().networkToken;
+        resultEntry.lastVisitWasHTTPNonGet = entry->lastVisitWasHTTPNonGet();
+        resultEntry.id = backForwardIdFromHistoryItem(entry.get());
+
+        // Make sure the HistoryItem is not disposed while the result list is still being used, to make sure the pointer is not reused
+        // will be balanced by deref in releaseBackForwardEntry.
+        entry->ref();
+    }
+}
+
+void WebPage::releaseBackForwardEntry(BackForwardId id) const
+{
+    HistoryItem* item = historyItemFromBackForwardId(id);
+    ASSERT(item);
+    item->deref();
+}
+
+void WebPage::clearBrowsingData()
+{
+    clearMemoryCaches();
+    clearAppCache(d->m_page->groupName());
+    clearLocalStorage();
+    clearCookieCache();
+    clearHistory();
+    clearPluginSiteData();
+}
+
+void WebPage::clearHistory()
+{
+    // Don't clear the back-forward list as we might like to keep it.
+}
+
+void WebPage::clearCookies()
+{
+    clearCookieCache();
+}
+
+void WebPage::clearLocalStorage()
+{
+    BlackBerry::WebKit::clearLocalStorage(d->m_page->groupName());
+    clearDatabase(d->m_page->groupName());
+}
+
+void WebPage::clearCache()
+{
+    clearMemoryCaches();
+    clearAppCache(d->m_page->groupName());
+}
+
+void WebPage::clearBackForwardList(bool keepCurrentPage) const
+{
+    BackForwardListImpl* backForwardList = static_cast<BackForwardListImpl*>(d->m_page->backForward()->client());
+    RefPtr<HistoryItem> currentItem = backForwardList->currentItem();
+    while (!backForwardList->entries().isEmpty())
+        backForwardList->removeItem(backForwardList->entries().last().get());
+    if (keepCurrentPage)
+        backForwardList->addItem(currentItem);
+}
+
+bool WebPage::isEnableLocalAccessToAllCookies() const
+{
+    return cookieManager().canLocalAccessAllCookies();
+}
+
+void WebPage::setEnableLocalAccessToAllCookies(bool enabled)
+{
+    cookieManager().setCanLocalAccessAllCookies(enabled);
+}
+
+void WebPage::addVisitedLink(const unsigned short* url, unsigned int length)
+{
+    ASSERT(d->m_page);
+    d->m_page->group().addVisitedLink(url, length);
+}
+
+#if ENABLE(WEBDOM)
+WebDOMDocument WebPage::document() const
+{
+    if (!d->m_mainFrame)
+        return WebDOMDocument();
+    return WebDOMDocument(d->m_mainFrame->document());
+}
+
+WebDOMNode WebPage::nodeAtPoint(int x, int y)
+{
+    HitTestResult result = d->m_mainFrame->eventHandler()->hitTestResultAtPoint(d->mapFromTransformed(IntPoint(x, y)), false);
+    Node* node = result.innerNonSharedNode();
+    return WebDOMNode(node);
+}
+
+bool WebPage::getNodeRect(const WebDOMNode& node, Platform::IntRect& result)
+{
+    Node* nodeImpl = node.impl();
+    if (nodeImpl && nodeImpl->renderer()) {
+        result = nodeImpl->getRect();
+        return true;
+    }
+
+    return false;
+}
+
+bool WebPage::setNodeFocus(const WebDOMNode& node, bool on)
+{
+    Node* nodeImpl = node.impl();
+
+    if (nodeImpl && nodeImpl->isFocusable()) {
+        Document* doc = nodeImpl->document();
+        if (Page* page = doc->page()) {
+            // Modify if focusing on node or turning off focused node.
+            if (on) {
+                page->focusController()->setFocusedNode(nodeImpl, doc->frame());
+                if (nodeImpl->isElementNode())
+                    static_cast<Element*>(nodeImpl)->updateFocusAppearance(true);
+                d->m_inputHandler->didNodeOpenPopup(nodeImpl);
+            } else if (doc->focusedNode() == nodeImpl) // && !on
+                page->focusController()->setFocusedNode(0, doc->frame());
+
+            return true;
+        }
+    }
+    return false;
+}
+
+bool WebPage::setNodeHovered(const WebDOMNode& node, bool on)
+{
+    if (Node* nodeImpl = node.impl()) {
+        nodeImpl->setHovered(on);
+        return true;
+    }
+    return false;
+}
+
+bool WebPage::nodeHasHover(const WebDOMNode& node)
+{
+    if (Node* nodeImpl = node.impl()) {
+        if (RenderStyle* style = nodeImpl->renderStyle())
+            return style->affectedByHoverRules();
+    }
+    return false;
+}
+#endif
+
+String WebPagePrivate::findPatternStringForUrl(const KURL& url) const
+{
+    if ((m_webSettings->shouldHandlePatternUrls() && protocolIs(url, "pattern"))
+            || protocolIs(url, "tel")
+            || protocolIs(url, "wtai")
+            || protocolIs(url, "cti")
+            || protocolIs(url, "mailto")
+            || protocolIs(url, "sms")
+            || protocolIs(url, "pin")) {
+        return url;
+    }
+    return String();
+}
+
+bool WebPage::defersLoading() const
+{
+    return d->m_page->defersLoading();
+}
+
+bool WebPage::willFireTimer()
+{
+    if (d->isLoading())
+        return true;
+
+    return d->m_backingStore->d->willFireTimer();
+}
+
+void WebPage::notifyPagePause()
+{
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews)
+        (*it)->handlePauseEvent();
+}
+
+void WebPage::notifyPageResume()
+{
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews)
+        (*it)->handleResumeEvent();
+}
+
+void WebPage::notifyPageBackground()
+{
+#if USE(ACCELERATED_COMPOSITING)
+    d->suspendRootLayerCommit();
+#endif
+
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews)
+        (*it)->handleBackgroundEvent();
+}
+
+void WebPage::notifyPageForeground()
+{
+#if USE(ACCELERATED_COMPOSITING)
+    d->resumeRootLayerCommit();
+#endif
+
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews)
+        (*it)->handleForegroundEvent();
+}
+
+void WebPage::notifyPageFullScreenAllowed()
+{
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews)
+        (*it)->handleFullScreenAllowedEvent();
+}
+
+void WebPage::notifyPageFullScreenExit()
+{
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews)
+        (*it)->handleFullScreenExitEvent();
+}
+
+void WebPage::notifyDeviceIdleStateChange(bool enterIdle)
+{
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews)
+        (*it)->handleIdleEvent(enterIdle);
+}
+
+void WebPage::notifyAppActivationStateChange(ActivationStateType activationState)
+{
+#if ENABLE(VIDEO)
+    MediaPlayerPrivate::notifyAppActivatedEvent(activationState == ActivationActive);
+#endif
+
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews) {
+        switch (activationState) {
+        case ActivationActive:
+            (*it)->handleAppActivatedEvent();
+            break;
+        case ActivationInactive:
+            (*it)->handleAppDeactivatedEvent();
+            break;
+        case ActivationStandby:
+            (*it)->handleAppStandbyEvent();
+            break;
+        default: // FIXME: Get rid of the default to force a compiler error instead of using a runtime error. See PR #121109.
+            ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+}
+
+void WebPage::notifySwipeEvent()
+{
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews)
+       (*it)->handleSwipeEvent();
+}
+
+void WebPage::notifyScreenPowerStateChanged(bool powered)
+{
+    FOR_EACH_PLUGINVIEW(d->m_pluginViews)
+       (*it)->handleScreenPowerEvent(powered);
+}
+
+void WebPage::notifyFullScreenVideoExited(bool done)
+{
+    UNUSED_PARAM(done);
+#if ENABLE(VIDEO)
+    if (HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(d->m_fullscreenVideoNode.get()))
+        mediaElement->exitFullscreen();
+#endif
+}
+
+void WebPage::clearPluginSiteData()
+{
+    PluginDatabase* database = PluginDatabase::installedPlugins(true);
+
+    if (!database)
+        return;
+
+    Vector<PluginPackage*> plugins = database->plugins();
+
+    Vector<PluginPackage*>::const_iterator end = plugins.end();
+    for (Vector<PluginPackage*>::const_iterator it = plugins.begin(); it != end; ++it)
+        (*it)->clearSiteData(String());
+}
+
+void WebPage::onInputLocaleChanged(bool isRTL)
+{
+    d->onInputLocaleChanged(isRTL);
+}
+
+void WebPage::onNetworkAvailabilityChanged(bool available)
+{
+    updateOnlineStatus(available);
+}
+
+void WebPage::onCertificateStoreLocationSet(const WebString& caPath)
+{
+#if ENABLE(VIDEO)
+    MediaPlayerPrivate::setCertificatePath(caPath);
+#endif
+}
+
+void WebPage::enableWebInspector()
+{
+    d->m_page->inspectorController()->connectFrontend();
+    d->m_page->settings()->setDeveloperExtrasEnabled(true);
+}
+
+void WebPage::disableWebInspector()
+{
+    d->m_page->inspectorController()->disconnectFrontend();
+    d->m_page->settings()->setDeveloperExtrasEnabled(false);
+}
+
+void WebPage::enablePasswordEcho()
+{
+    d->m_page->settings()->setPasswordEchoEnabled(true);
+}
+
+void WebPage::disablePasswordEcho()
+{
+    d->m_page->settings()->setPasswordEchoEnabled(false);
+}
+
+void WebPage::dispatchInspectorMessage(const char* message, int length)
+{
+    String stringMessage(message, length);
+    d->m_page->inspectorController()->dispatchMessageFromFrontend(stringMessage);
+}
+
+Frame* WebPage::mainFrame() const
+{
+    return d->m_mainFrame;
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+void WebPagePrivate::drawLayersOnCommit()
+{
+    if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
+        // This method will only be called when the layer appearance changed due to
+        // animations. And only if we don't need a one shot drawing sync.
+        ASSERT(!needsOneShotDrawingSynchronization());
+
+        if (!m_webPage->isVisible() || !m_backingStore->d->isActive())
+            return;
+
+        m_backingStore->d->willDrawLayersOnCommit();
+
+        Platform::userInterfaceThreadMessageClient()->dispatchMessage(
+            Platform::createMethodCallMessage(&WebPagePrivate::drawLayersOnCommit, this));
+        return;
+    }
+
+    if (m_client->window()->windowUsage() == Platform::Graphics::Window::GLES2Usage) {
+        m_backingStore->d->blitVisibleContents();
+        return; // blitVisibleContents() includes drawSubLayers() in this case.
+    }
+
+    if (!drawSubLayers())
+        return;
+
+    // If we use the compositing surface, we need to re-blit the
+    // backingstore and blend the compositing surface on top of that
+    // in order to get the newly drawn layers on screen.
+    if (!SurfacePool::globalSurfacePool()->compositingSurface())
+        return;
+
+    // If there are no visible layers, return early.
+    if (lastCompositingResults().isEmpty() && lastCompositingResults().wasEmpty)
+        return;
+
+    if (m_backingStore->d->shouldDirectRenderingToWindow())
+        return;
+
+    m_backingStore->d->blitVisibleContents();
+}
+
+bool WebPagePrivate::drawSubLayers(const IntRect& dstRect, const FloatRect& contents)
+{
+    ASSERT(Platform::userInterfaceThreadMessageClient()->isCurrentThread());
+    if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread())
+        return false;
+
+    if (m_compositor) {
+        m_compositor->setCompositingOntoMainWindow(
+            m_client->window()->windowUsage() == Platform::Graphics::Window::GLES2Usage);
+        return m_compositor->drawLayers(dstRect, contents);
+    }
+
+    return false;
+}
+
+bool WebPagePrivate::drawSubLayers()
+{
+    ASSERT(Platform::userInterfaceThreadMessageClient()->isCurrentThread());
+    if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread())
+        return false;
+
+    return m_backingStore->d->drawSubLayers();
+}
+
+void WebPagePrivate::scheduleRootLayerCommit()
+{
+    if (!m_frameLayers || !m_frameLayers->hasLayer())
+        return;
+
+    m_needsCommit = true;
+    if (!m_rootLayerCommitTimer->isActive())
+        m_rootLayerCommitTimer->startOneShot(0);
+}
+
+static bool needsLayoutRecursive(FrameView* view)
+{
+    if (view->needsLayout())
+        return true;
+
+    bool subframesNeedsLayout = false;
+    const HashSet<RefPtr<Widget> >* viewChildren = view->children();
+    HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
+    for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end && !subframesNeedsLayout; ++current) {
+        Widget* widget = (*current).get();
+        if (widget->isFrameView())
+            subframesNeedsLayout |= needsLayoutRecursive(static_cast<FrameView*>(widget));
+    }
+
+    return subframesNeedsLayout;
+}
+
+LayerRenderingResults WebPagePrivate::lastCompositingResults() const
+{
+    if (m_compositor)
+        return m_compositor->lastCompositingResults();
+    return LayerRenderingResults();
+}
+
+void WebPagePrivate::commitRootLayer(const IntRect& layoutRectForCompositing,
+                                     const IntSize& contentsSizeForCompositing)
+{
+    if (!m_frameLayers || !m_compositor)
+        return;
+
+    m_compositor->setLayoutRectForCompositing(layoutRectForCompositing);
+    m_compositor->setContentsSizeForCompositing(contentsSizeForCompositing);
+    m_compositor->commit(m_frameLayers->rootLayer());
+}
+
+bool WebPagePrivate::commitRootLayerIfNeeded()
+{
+    if (m_suspendRootLayerCommit)
+        return false;
+
+    if (!m_needsCommit)
+        return false;
+
+    if (!m_frameLayers || !m_frameLayers->hasLayer())
+        return false;
+
+    FrameView* view = m_mainFrame->view();
+    if (!view)
+        return false;
+
+    // If we sync compositing layers when a layout is pending, we may cause painting of compositing
+    // layer content to occur before layout has happened, which will cause paintContents() to bail.
+    if (needsLayoutRecursive(view)) {
+        // In case of one shot drawing synchronization, you
+        // should first layoutIfNeeded, render, then commit and draw the layers.
+        ASSERT(!needsOneShotDrawingSynchronization());
+        return false;
+    }
+
+    m_needsCommit = false;
+    // We get here either due to the commit timer, which would have called
+    // render if a one shot sync was needed. Or we get called from render
+    // before the timer times out, which means we are doing a one shot anyway.
+    m_needsOneShotDrawingSynchronization = false;
+
+    if (m_rootLayerCommitTimer->isActive())
+        m_rootLayerCommitTimer->stop();
+
+    m_frameLayers->commitOnWebKitThread(currentScale());
+    updateDelegatedOverlays();
+
+    // Stash the visible content rect according to webkit thread
+    // This is the rectangle used to layout fixed positioned elements,
+    // and that's what the layer renderer wants.
+    IntRect layoutRectForCompositing(scrollPosition(), actualVisibleSize());
+    IntSize contentsSizeForCompositing = contentsSize();
+
+    // Commit changes made to the layers synchronously with the compositing thread.
+    Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
+        Platform::createMethodCallMessage(
+            &WebPagePrivate::commitRootLayer,
+            this,
+            layoutRectForCompositing,
+            contentsSizeForCompositing));
+
+    return true;
+}
+
+void WebPagePrivate::rootLayerCommitTimerFired(Timer<WebPagePrivate>*)
+{
+    if (m_suspendRootLayerCommit)
+        return;
+
+    // The commit timer may have fired just before the layout timer, or for some
+    // other reason we need layout. It's not allowed to commit when a layout is
+    // pending, becaues a commit can cause parts of the web page to be rendered
+    // to texture.
+    // The layout can also turn of compositing altogether, so we need to be prepared
+    // to handle a one shot drawing synchronization after the layout.
+    requestLayoutIfNeeded();
+
+    bool isSingleTargetWindow = SurfacePool::globalSurfacePool()->compositingSurface()
+        || m_client->window()->windowUsage() == Platform::Graphics::Window::GLES2Usage;
+
+    // If we are doing direct rendering and have a single rendering target,
+    // committing is equivalent to a one shot drawing synchronization.
+    // We need to re-render the web page, re-render the layers, and
+    // then blit them on top of the re-rendered web page.
+    if (isSingleTargetWindow && m_backingStore->d->shouldDirectRenderingToWindow())
+        setNeedsOneShotDrawingSynchronization();
+
+    if (needsOneShotDrawingSynchronization()) {
+        const IntRect windowRect = IntRect(IntPoint::zero(), viewportSize());
+        m_backingStore->d->repaint(windowRect, true /*contentChanged*/, true /*immediate*/);
+        return;
+    }
+
+    // If the web page needs layout, the commit will fail.
+    // No need to draw the layers if nothing changed.
+    if (commitRootLayerIfNeeded())
+        drawLayersOnCommit();
+}
+
+void WebPagePrivate::setIsAcceleratedCompositingActive(bool active)
+{
+    // Backing store can be null here because it happens during teardown.
+    if (m_isAcceleratedCompositingActive == active || !m_backingStore)
+        return;
+
+    m_isAcceleratedCompositingActive = active;
+
+    if (!active) {
+        m_compositor.clear();
+        resetCompositingSurface();
+        return;
+    }
+
+    if (!m_compositor) {
+        m_compositor = adoptPtr(new WebPageCompositor(this));
+        m_isAcceleratedCompositingActive = m_compositor->hardwareCompositing();
+        if (!m_isAcceleratedCompositingActive)
+            m_compositor.clear();
+    }
+}
+
+void WebPagePrivate::resetCompositingSurface()
+{
+    if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
+        Platform::userInterfaceThreadMessageClient()->dispatchMessage(
+            Platform::createMethodCallMessage(
+                &WebPagePrivate::resetCompositingSurface, this));
+        return;
+    }
+
+    if (m_compositor)
+        m_compositor->setLastCompositingResults(LayerRenderingResults());
+}
+
+void WebPagePrivate::setRootLayerWebKitThread(Frame* frame, LayerWebKitThread* layer)
+{
+    // This method updates the FrameLayers based on input from WebCore.
+    // FrameLayers keeps track of the layer proxies attached to frames.
+    // We will have to compute a new root layer and update the compositor.
+    if (!layer && !m_frameLayers)
+        return;
+
+    if (!layer) {
+         ASSERT(m_frameLayers);
+         m_frameLayers->removeLayerByFrame(frame);
+         if (!m_frameLayers->hasLayer())
+             m_frameLayers.clear();
+    } else {
+        if (!m_frameLayers)
+            m_frameLayers = adoptPtr(new FrameLayers(this));
+
+        if (!m_frameLayers->containsLayerForFrame(frame))
+            m_frameLayers->addLayer(frame, layer);
+
+        ASSERT(m_frameLayers);
+    }
+
+    LayerCompositingThread* rootLayerCompositingThread = 0;
+    if (m_frameLayers && m_frameLayers->rootLayer())
+        rootLayerCompositingThread = m_frameLayers->rootLayer()->layerCompositingThread();
+
+    setRootLayerCompositingThread(rootLayerCompositingThread);
+}
+
+void WebPagePrivate::setRootLayerCompositingThread(LayerCompositingThread* layer)
+{
+    if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
+        Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
+            Platform::createMethodCallMessage(&WebPagePrivate::setRootLayerCompositingThread, this, layer));
+        return;
+    }
+
+    // Depending on whether we have a root layer or not,
+    // this method will turn on or off accelerated compositing.
+    if (!layer) {
+         // Don't ASSERT(m_compositor) here because we may be called in
+         // the process of destruction of WebPage where we have already
+         // called syncDestroyCompositorOnCompositingThread() to destroy
+         // the compositor.
+         setIsAcceleratedCompositingActive(false);
+         return;
+    }
+
+    if (!m_compositor)
+        setIsAcceleratedCompositingActive(true);
+
+    // Don't ASSERT(m_compositor) here because setIsAcceleratedCompositingActive(true)
+    // may not turn accelerated compositing on since m_backingStore is 0.
+    if (m_compositor)
+        m_compositor->setRootLayer(layer);
+}
+
+void WebPagePrivate::destroyCompositor()
+{
+     m_compositor.clear();
+}
+
+void WebPagePrivate::syncDestroyCompositorOnCompositingThread()
+{
+    if (!m_compositor)
+        return;
+
+    Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
+        Platform::createMethodCallMessage(
+            &WebPagePrivate::destroyCompositor, this));
+}
+
+void WebPagePrivate::destroyLayerResources()
+{
+     m_compositor->releaseLayerResources();
+}
+
+void WebPagePrivate::suspendRootLayerCommit()
+{
+    if (m_suspendRootLayerCommit)
+        return;
+
+    m_suspendRootLayerCommit = true;
+
+    if (!m_frameLayers || !m_frameLayers->hasLayer() || !m_compositor)
+        return;
+
+    Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
+        Platform::createMethodCallMessage(&WebPagePrivate::destroyLayerResources, this));
+}
+
+void WebPagePrivate::resumeRootLayerCommit()
+{
+    if (!m_suspendRootLayerCommit)
+        return;
+
+    m_suspendRootLayerCommit = false;
+    m_needsCommit = true;
+
+    // Recreate layer resources if needed.
+    commitRootLayerIfNeeded();
+}
+
+bool WebPagePrivate::needsOneShotDrawingSynchronization()
+{
+    return m_needsOneShotDrawingSynchronization;
+}
+
+void WebPagePrivate::setNeedsOneShotDrawingSynchronization()
+{
+    // This means we have to commit layers on next render, or render on the next commit,
+    // whichever happens first.
+    m_needsCommit = true;
+    m_needsOneShotDrawingSynchronization = true;
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+void WebPagePrivate::enterFullscreenForNode(Node* node)
+{
+#if ENABLE(VIDEO)
+    if (!node || !node->hasTagName(HTMLNames::videoTag))
+        return;
+
+    MediaPlayer* player = static_cast<HTMLMediaElement*>(node)->player();
+    if (!player)
+        return;
+
+    MediaPlayerPrivate* mmrPlayer = static_cast<MediaPlayerPrivate*>(player->implementation());
+    if (!mmrPlayer)
+        return;
+
+    Platform::Graphics::Window* window = mmrPlayer->windowGet();
+    if (!window)
+        return;
+
+    unsigned x, y, width, height;
+    mmrPlayer->windowPositionGet(x, y, width, height);
+
+    const char* contextName = mmrPlayer->mmrContextNameGet();
+    if (!contextName)
+        return;
+
+    mmrPlayer->setFullscreenWebPageClient(m_client);
+    m_fullscreenVideoNode = node;
+    m_client->fullscreenStart(contextName, window, x, y, width, height);
+#endif
+}
+
+void WebPagePrivate::exitFullscreenForNode(Node* node)
+{
+#if ENABLE(VIDEO)
+    if (m_fullscreenVideoNode.get()) {
+        m_client->fullscreenStop();
+        m_fullscreenVideoNode = 0;
+    }
+
+    if (!node || !node->hasTagName(HTMLNames::videoTag))
+        return;
+
+    MediaPlayer* player = static_cast<HTMLMediaElement*>(node)->player();
+    if (!player)
+        return;
+
+    MediaPlayerPrivate* mmrPlayer = static_cast<MediaPlayerPrivate*>(player->implementation());
+    if (!mmrPlayer)
+        return;
+
+    // Fullscreen mode is being turned off, so MediaPlayerPrivate no longer needs the pointer.
+    mmrPlayer->setFullscreenWebPageClient(0);
+#endif
+}
+
+void WebPagePrivate::didChangeSettings(WebSettings* webSettings)
+{
+    Settings* coreSettings = m_page->settings();
+    m_page->setGroupName(webSettings->pageGroupName());
+    coreSettings->setXSSAuditorEnabled(webSettings->xssAuditorEnabled());
+    coreSettings->setLoadsImagesAutomatically(webSettings->loadsImagesAutomatically());
+    coreSettings->setShouldDrawBorderWhileLoadingImages(webSettings->shouldDrawBorderWhileLoadingImages());
+    coreSettings->setScriptEnabled(webSettings->isJavaScriptEnabled());
+    coreSettings->setPrivateBrowsingEnabled(webSettings->isPrivateBrowsingEnabled());
+    coreSettings->setDefaultFixedFontSize(webSettings->defaultFixedFontSize());
+    coreSettings->setDefaultFontSize(webSettings->defaultFontSize());
+    coreSettings->setMinimumFontSize(webSettings->minimumFontSize());
+    coreSettings->setSerifFontFamily(webSettings->serifFontFamily().impl());
+    coreSettings->setFixedFontFamily(webSettings->fixedFontFamily().impl());
+    coreSettings->setSansSerifFontFamily(webSettings->sansSerifFontFamily().impl());
+    coreSettings->setStandardFontFamily(webSettings->standardFontFamily().impl());
+    coreSettings->setJavaScriptCanOpenWindowsAutomatically(webSettings->canJavaScriptOpenWindowsAutomatically());
+    coreSettings->setAllowScriptsToCloseWindows(webSettings->canJavaScriptOpenWindowsAutomatically()); // Why are we using the same value as setJavaScriptCanOpenWindowsAutomatically()?
+    coreSettings->setPluginsEnabled(webSettings->arePluginsEnabled());
+    coreSettings->setDefaultTextEncodingName(webSettings->defaultTextEncodingName().impl());
+    coreSettings->setDownloadableBinaryFontsEnabled(webSettings->downloadableBinaryFontsEnabled());
+    coreSettings->setSpatialNavigationEnabled(m_webSettings->isSpatialNavigationEnabled());
+
+    // UserScalable should be reset by new settings.
+    setUserScalable(webSettings->isUserScalable());
+
+    WebString stylesheetURL = webSettings->userStyleSheetString();
+    if (stylesheetURL.isEmpty())
+        stylesheetURL = webSettings->userStyleSheetLocation();
+    if (!stylesheetURL.isEmpty())
+        coreSettings->setUserStyleSheetLocation(KURL(KURL(), stylesheetURL));
+
+    coreSettings->setFirstScheduledLayoutDelay(webSettings->firstScheduledLayoutDelay());
+    coreSettings->setUseCache(webSettings->useWebKitCache());
+
+#if ENABLE(SQL_DATABASE)
+    // DatabaseTracker can only be initialized for once, so it doesn't
+    // make sense to change database path after DatabaseTracker has
+    // already been initialized.
+    static bool dbinit = false;
+    if (!dbinit && !webSettings->databasePath().isEmpty()) {
+        dbinit = true;
+        DatabaseTracker::initializeTracker(webSettings->databasePath());
+    }
+
+    // The directory of cacheStorage for one page group can only be initialized once.
+    static bool acinit = false;
+    if (!acinit && !webSettings->appCachePath().isEmpty()) {
+        acinit = true;
+        cacheStorage().setCacheDirectory(webSettings->appCachePath());
+    }
+
+    coreSettings->setLocalStorageDatabasePath(webSettings->localStoragePath());
+    Database::setIsAvailable(webSettings->isDatabasesEnabled());
+    DatabaseSync::setIsAvailable(webSettings->isDatabasesEnabled());
+
+    coreSettings->setLocalStorageEnabled(webSettings->isLocalStorageEnabled());
+    coreSettings->setOfflineWebApplicationCacheEnabled(webSettings->isAppCacheEnabled());
+
+    m_page->group().groupSettings()->setLocalStorageQuotaBytes(webSettings->localStorageQuota());
+    coreSettings->setUsesPageCache(webSettings->maximumPagesInCache());
+    coreSettings->setFrameFlatteningEnabled(webSettings->isFrameFlatteningEnabled());
+#endif
+
+#if ENABLE(WEB_SOCKETS)
+    WebSocket::setIsAvailable(webSettings->areWebSocketsEnabled());
+#endif
+
+#if ENABLE(VIEWPORT_REFLOW)
+    coreSettings->setTextReflowEnabled(webSettings->textReflowMode() == WebSettings::TextReflowEnabled);
+#endif
+
+    // FIXME: We don't want HTMLTokenizer to yield for anything other than email case because
+    // call to currentTime() is too expensive on our platform. See RIM Bug #746.
+    coreSettings->setShouldUseFirstScheduledLayoutDelay(webSettings->isEmailMode());
+    coreSettings->setProcessHTTPEquiv(!webSettings->isEmailMode());
+
+    coreSettings->setShouldUseCrossOriginProtocolCheck(!webSettings->allowCrossSiteRequests());
+
+    cookieManager().setPrivateMode(webSettings->isPrivateBrowsingEnabled());
+
+    if (m_mainFrame && m_mainFrame->view()) {
+        Color backgroundColor(webSettings->backgroundColor());
+        m_mainFrame->view()->updateBackgroundRecursively(backgroundColor, backgroundColor.hasAlpha());
+    }
+}
+
+IntSize WebPagePrivate::defaultMaxLayoutSize()
+{
+    static IntSize size;
+    if (size.isEmpty())
+        size = IntSize(std::max(1024, Platform::Graphics::Screen::landscapeWidth()),
+                       std::max(768, Platform::Graphics::Screen::landscapeHeight()));
+
+    return size;
+}
+
+WebString WebPage::textHasAttribute(const WebString& query) const
+{
+    if (Document* doc = d->m_page->focusController()->focusedOrMainFrame()->document())
+        return doc->queryCommandValue(query);
+
+    return "";
+}
+
+void WebPage::setJavaScriptCanAccessClipboard(bool enabled)
+{
+    d->m_page->settings()->setJavaScriptCanAccessClipboard(enabled);
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+void WebPagePrivate::blitVisibleContents()
+{
+    if (m_backingStore->d->shouldDirectRenderingToWindow())
+        return;
+
+    m_backingStore->d->blitVisibleContents();
+}
+#endif
+
+void WebPage::setWebGLEnabled(bool enabled)
+{
+    if (!Platform::ITPolicy::isWebGLEnabled()) {
+        d->m_page->settings()->setWebGLEnabled(false);
+        return;
+    }
+    d->m_page->settings()->setWebGLEnabled(enabled);
+}
+
+bool WebPage::isWebGLEnabled() const
+{
+    return d->m_page->settings()->webGLEnabled();
+}
+
+void WebPagePrivate::setNeedTouchEvents(bool value)
+{
+    m_needTouchEvents = value;
+}
+
+}
+}
diff --git a/Source/WebKit/blackberry/Api/WebPage.h b/Source/WebKit/blackberry/Api/WebPage.h
new file mode 100644 (file)
index 0000000..489f453
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef WebPage_h
+#define WebPage_h
+
+#include "ActiveNodeContext.h"
+#include "BlackBerryGlobal.h"
+#include <BlackBerryPlatformGuardedPointer.h>
+#include <BlackBerryPlatformInputEvents.h>
+#include <imf/input_data.h>
+#include <network/NetworkRequest.h>
+
+struct OpaqueJSContext;
+typedef const struct OpaqueJSContext* JSContextRef;
+
+struct OpaqueJSValue;
+typedef const struct OpaqueJSValue* JSValueRef;
+
+namespace WebCore {
+class ChromeClientBlackBerry;
+class EditorClientBlackBerry;
+class Element;
+class Frame;
+class FrameLoaderClientBlackBerry;
+class GeolocationControllerClientBlackBerry;
+class IconDatabaseClientBlackBerry;
+class InspectorClientBlackBerry;
+class JavaScriptDebuggerBlackBerry;
+class Node;
+class RenderObject;
+class VisibleSelection;
+}
+
+class WebDOMDocument;
+class WebDOMNode;
+template<typename T> class SharedArray;
+
+namespace BlackBerry {
+namespace Platform {
+class IntPoint;
+class IntRect;
+class IntSize;
+class KeyboardEvent;
+class MouseEvent;
+class TouchEvent;
+class TouchPoint;
+}
+
+namespace WebKit {
+
+class BackingStore;
+class BackingStoreClient;
+class BackingStorePrivate;
+class DumpRenderTreeClient;
+class RenderQueue;
+class WebPageClient;
+class WebPageGroupLoadDeferrer;
+class WebPagePrivate;
+class WebSettings;
+
+enum JavaScriptDataType { JSUndefined = 0, JSNull, JSBoolean, JSNumber, JSString, JSObject, JSException, JSDataTypeMax };
+
+enum ActivationStateType { ActivationActive, ActivationInactive, ActivationStandby };
+
+enum TargetDetectionStrategy {PointBased, RectBased};
+
+class BLACKBERRY_EXPORT WebPage : public Platform::GuardedPointerBase {
+public:
+    WebPage(WebPageClient*, const WebString& pageGroupName, const Platform::IntRect&);
+    void destroy();
+
+    WebPageClient* client() const;
+
+    void load(const char* url, const char* networkToken, bool isInitial = false);
+
+    void loadExtended(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy = Platform::NetworkRequest::UseProtocolCachePolicy, const char* data = 0, size_t dataLength = 0, const char* const* headers = 0, size_t headersLength = 0, bool mustHandleInternally = false);
+
+    void loadFile(const char* path, const char* overrideContentType = "");
+
+    void loadString(const char* string, const char* baseURL, const char* contentType = "text/html", const char* failingURL = 0);
+
+    void download(const Platform::NetworkRequest&);
+
+    bool executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue);
+
+    // This will execute the script even if in-page JavaScript is disabled.
+    bool executeJavaScriptInIsolatedWorld(const char* script, JavaScriptDataType& returnType, WebString& returnValue);
+
+    // Takes a UTF16 encoded script that is used explicitly by the pattern matching code
+    bool executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, WebString& returnValue);
+
+    void initializeIconDataBase();
+
+    void stopLoading();
+
+    // This will force any unload handlers to run.
+    void prepareToDestroy();
+
+    void reload();
+    void reloadFromCache();
+
+    WebSettings* settings() const;
+
+    void setVisible(bool);
+    bool isVisible() const;
+
+    void setScreenOrientation(int);
+    void applyPendingOrientationIfNeeded();
+
+    Platform::IntSize viewportSize() const;
+    void setViewportSize(const Platform::IntSize& viewportSize, bool ensureFocusElementVisible = true);
+
+    void resetVirtualViewportOnCommitted(bool reset);
+    void setVirtualViewportSize(int width, int height);
+
+    // Used for default layout size unless overridden by web content or by other APIs.
+    void setDefaultLayoutSize(int width, int height);
+
+    bool mouseEvent(const Platform::MouseEvent&, bool* wheelDeltaAccepted = 0);
+
+    // Handles native javascript touch events.
+    bool touchEvent(const Platform::TouchEvent&);
+
+    // For conversion to mouse events.
+    void touchEventCancel();
+    void touchEventCancelAndClearFocusedNode();
+    bool touchPointAsMouseEvent(const Platform::TouchPoint&);
+
+    // Returns true if the key stroke was handled by WebKit.
+    bool keyEvent(const Platform::KeyboardEvent&);
+
+    WebString title() const;
+    WebString selectedText() const;
+    WebString cutSelectedText();
+    void insertText(const WebString&);
+    void clearCurrentInputField();
+
+    void cut();
+    void copy();
+    void paste();
+
+    // Text encoding.
+    WebString textEncoding();
+    WebString forcedTextEncoding();
+    void setForcedTextEncoding(const char*);
+
+    // Scroll position returned is in transformed coordinates.
+    Platform::IntPoint scrollPosition() const;
+    // Scroll position provided should be in transformed coordinates.
+    void setScrollPosition(const Platform::IntPoint&);
+    bool scrollBy(const Platform::IntSize&, bool scrollMainFrame = true);
+    void notifyInRegionScrollStatusChanged(bool status);
+    void setScrollOriginPoint(const Platform::IntPoint&);
+
+    BackingStore* backingStore() const;
+
+    bool zoomToFit();
+    bool zoomToOneOne();
+    void zoomToInitialScale();
+    bool blockZoom(int x, int y);
+    void blockZoomAnimationFinished();
+    bool isAtInitialZoom() const;
+    bool isMaxZoomed() const;
+    bool isMinZoomed() const;
+    bool pinchZoomAboutPoint(double scale, int x, int y);
+
+    bool isUserScalable() const;
+    double currentScale() const;
+    double initialScale() const;
+    double zoomToFitScale() const;
+    void setInitialScale(double);
+    double minimumScale() const;
+    void setMinimumScale(double);
+    double maximumScale() const;
+    void setMaximumScale(double);
+
+    void assignFocus(Platform::FocusDirection);
+
+    Platform::IntRect focusNodeRect();
+
+    void setFocused(bool);
+
+    void clearBrowsingData();
+    void clearHistory();
+    void clearCookies();
+    void clearCache();
+    void clearLocalStorage();
+
+    void runLayoutTests();
+
+     // Finds and selects the next utf8 string that is a case sensitive
+     // match in the web page. It will wrap the web page if it reaches
+     // the end. An empty string will result in no match and no selection.
+     // Returns true if the string matched and false if not.
+    bool findNextString(const char*, bool forward = true);
+
+    // JavaScriptDebugger interface.
+    bool enableScriptDebugger();
+    bool disableScriptDebugger();
+
+    JSContextRef scriptContext() const;
+    JSValueRef windowObject() const;
+
+    void addBreakpoint(const unsigned short* url, unsigned urlLength, int lineNumber, const unsigned short* condition, unsigned conditionLength);
+    void updateBreakpoint(const unsigned short* url, unsigned urlLength, int lineNumber, const unsigned short* condition, unsigned conditionLength);
+    void removeBreakpoint(const unsigned short* url, unsigned urlLength, int lineNumber);
+
+    bool pauseOnExceptions();
+    void setPauseOnExceptions(bool);
+
+    void pauseInDebugger();
+    void resumeDebugger();
+
+    void stepOverStatementInDebugger();
+    void stepIntoStatementInDebugger();
+    void stepOutOfFunctionInDebugger();
+
+    unsigned timeoutForJavaScriptExecution() const;
+    void setTimeoutForJavaScriptExecution(unsigned ms);
+
+    void setCaretHighlightStyle(Platform::CaretHighlightStyle);
+
+    // IMF functions.
+    bool setBatchEditingActive(bool);
+    bool setInputSelection(unsigned start, unsigned end);
+    int inputCaretPosition() const;
+    bool deleteTextRelativeToCursor(unsigned leftOffset, unsigned rightOffset);
+    spannable_string_t* selectedText(int32_t flags);
+    spannable_string_t* textBeforeCursor(int32_t length, int32_t flags);
+    spannable_string_t* textAfterCursor(int32_t length, int32_t flags);
+    extracted_text_t* extractedTextRequest(extracted_text_request_t*, int32_t flags);
+    int32_t setComposingRegion(int32_t start, int32_t end);
+    int32_t finishComposition();
+    int32_t setComposingText(spannable_string_t*, int32_t relativeCursorPosition);
+    int32_t commitText(spannable_string_t*, int32_t relativeCursorPosition);
+
+    void spellCheckingEnabled(bool);
+
+    void setSelection(const Platform::IntPoint& startPoint, const Platform::IntPoint& endPoint);
+    void setCaretPosition(const Platform::IntPoint&);
+    void selectAtPoint(const Platform::IntPoint&);
+    void selectionCancelled();
+    bool selectionContains(const Platform::IntPoint&);
+
+    void popupListClosed(int size, bool* selecteds);
+    void popupListClosed(int index);
+    void setDateTimeInput(const WebString& value);
+    void setColorInput(const WebString& value);
+
+    void onInputLocaleChanged(bool isRTL);
+    static void onNetworkAvailabilityChanged(bool available);
+    static void onCertificateStoreLocationSet(const WebString& caPath);
+
+    WebString textHasAttribute(const WebString& query) const;
+
+    ActiveNodeContext activeNodeContext(TargetDetectionStrategy) const;
+
+    typedef intptr_t BackForwardId;
+    struct BackForwardEntry {
+        WebString url;
+        WebString originalUrl;
+        WebString title;
+        WebString networkToken;
+        BackForwardId id;
+        bool lastVisitWasHTTPNonGet;
+    };
+
+    bool canGoBackOrForward(int delta) const;
+    // Returns false if there is no page for the given delta (eg.
+    // attempt to go back with -1 when on the first page).
+    bool goBackOrForward(int delta);
+    void goToBackForwardEntry(BackForwardId);
+
+    int backForwardListLength() const;
+    void getBackForwardList(SharedArray<BackForwardEntry>& result, unsigned& resultLength) const;
+    void releaseBackForwardEntry(BackForwardId) const;
+    void clearBackForwardList(bool keepCurrentPage) const;
+
+    void addVisitedLink(const unsigned short* url, unsigned length);
+
+#if defined(ENABLE_WEBDOM) && ENABLE_WEBDOM
+    WebDOMDocument document() const;
+    WebDOMNode nodeAtPoint(int x, int y);
+    bool getNodeRect(const WebDOMNode&, Platform::IntRect& result);
+    bool setNodeFocus(const WebDOMNode&, bool on);
+    bool setNodeHovered(const WebDOMNode&, bool on);
+    bool nodeHasHover(const WebDOMNode&);
+#endif
+
+    bool defersLoading() const;
+
+    bool willFireTimer();
+
+    bool isEnableLocalAccessToAllCookies() const;
+    void setEnableLocalAccessToAllCookies(bool);
+
+    void enableWebInspector();
+    void disableWebInspector();
+    void enablePasswordEcho();
+    void disablePasswordEcho();
+    void dispatchInspectorMessage(const char* message, int length);
+    WebCore::Frame* mainFrame() const;
+
+    // FIXME: Needs API review on this header. See PR #120402.
+    void notifyPagePause();
+    void notifyPageResume();
+    void notifyPageBackground();
+    void notifyPageForeground();
+    void notifyPageFullScreenAllowed();
+    void notifyPageFullScreenExit();
+    void notifyDeviceIdleStateChange(bool enterIdle);
+    void notifyAppActivationStateChange(ActivationStateType);
+    void notifySwipeEvent();
+    void notifyScreenPowerStateChanged(bool powered);
+    void notifyFullScreenVideoExited(bool done);
+    void clearPluginSiteData();
+    void setJavaScriptCanAccessClipboard(bool);
+    bool isWebGLEnabled() const;
+    void setWebGLEnabled(bool);
+
+    void destroyWebPageCompositor();
+
+private:
+    ~WebPage();
+
+    friend class WebKit::BackingStore;
+    friend class WebKit::BackingStoreClient;
+    friend class WebKit::BackingStorePrivate;
+    friend class WebKit::RenderQueue;
+    friend class WebKit::WebPageGroupLoadDeferrer;
+    friend class WebCore::ChromeClientBlackBerry;
+    friend class WebCore::FrameLoaderClientBlackBerry;
+    WebPagePrivate* d;
+};
+}
+}
+
+#endif // WebPage_h
diff --git a/Source/WebKit/blackberry/Api/WebPage_p.h b/Source/WebKit/blackberry/Api/WebPage_p.h
new file mode 100644 (file)
index 0000000..e0238b6
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef WebPage_p_h
+#define WebPage_p_h
+
+#include "ChromeClient.h"
+#if USE(ACCELERATED_COMPOSITING)
+#include "LayerRenderer.h"
+#endif
+#include "PageClientBlackBerry.h"
+#include "PlatformMouseEvent.h"
+#include "ScriptSourceCode.h"
+#include "Timer.h"
+#include "ViewportArguments.h"
+#include "WebPage.h"
+#include "WebSettings.h"
+
+#include <BlackBerryPlatformMessage.h>
+
+namespace WebCore {
+class DOMWrapperWorld;
+class Document;
+class Frame;
+class FrameView;
+class GeolocationControllerClientBlackBerry;
+class JavaScriptDebuggerBlackBerry;
+class KURL;
+class Node;
+class Page;
+class PluginView;
+class RenderLayer;
+class RenderObject;
+class ScrollView;
+class TransformationMatrix;
+template<typename T> class Timer;
+}
+
+namespace BlackBerry {
+namespace WebKit {
+
+class BackingStore;
+class BackingStoreClient;
+class BackingStoreTile;
+class DumpRenderTreeClient;
+class InPageSearchManager;
+class InputHandler;
+class InRegionScrollableArea;
+class SelectionHandler;
+class TouchEventHandler;
+class WebPageClient;
+
+#if USE(ACCELERATED_COMPOSITING)
+class FrameLayers;
+class WebPageCompositor;
+#endif
+
+// In the client code, there is screen size and viewport.
+// In WebPagePrivate, the screen size is called the transformedViewportSize,
+// the viewport position is called the transformedScrollPosition,
+// and the viewport size is called the transformedActualVisibleSize.
+class WebPagePrivate : public PageClientBlackBerry, public WebSettingsDelegate, public Platform::GuardedPointerBase {
+public:
+    enum ViewMode { Mobile, Desktop, FixedDesktop };
+    enum LoadState { None /* on instantiation of page */, Provisional, Committed, Finished, Failed };
+
+    WebPagePrivate(WebPage*, WebPageClient*, const WebCore::IntRect&);
+    virtual ~WebPagePrivate();
+
+    void init(const WebString& pageGroupName);
+    bool handleMouseEvent(WebCore::PlatformMouseEvent&);
+    bool handleWheelEvent(WebCore::PlatformWheelEvent&);
+
+    void load(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool isInitial, bool mustHandleInternally = false, bool forceDownload = false, const char* overrideContentType = "");
+    void loadString(const char* string, const char* baseURL, const char* mimeType, const char* failingURL = 0);
+    bool executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue);
+    bool executeJavaScriptInIsolatedWorld(const WebCore::ScriptSourceCode&, JavaScriptDataType& returnType, WebString& returnValue);
+
+    void stopCurrentLoad();
+    void prepareToDestroy();
+
+    LoadState loadState() const { return m_loadState; }
+    bool isLoading() const { return m_loadState == WebPagePrivate::Provisional || m_loadState == WebPagePrivate::Committed; }
+
+    // Called from within WebKit via FrameLoaderClientBlackBerry.
+    void setLoadState(LoadState);
+
+    // Clamp the scale.
+    double clampedScale(double scale) const;
+
+    // Determine if we should zoom, clamping the scale parameter if required.
+    bool shouldZoomAboutPoint(double scale, const WebCore::FloatPoint& anchor, bool enforeScaleClamping, double* clampedScale);
+
+    // Scale the page to the given scale and anchor about the point which is specified in untransformed content coordinates.
+    bool zoomAboutPoint(double scale, const WebCore::FloatPoint& anchor, bool enforceScaleClamping = true, bool forceRendering = false, bool isRestoringZoomLevel = false);
+    bool scheduleZoomAboutPoint(double scale, const WebCore::FloatPoint& anchor, bool enforceScaleClamping = true, bool forceRendering = false);
+    void unscheduleZoomAboutPoint();
+    WebCore::IntPoint calculateReflowedScrollPosition(const WebCore::FloatPoint& anchorOffset, double inverseScale);
+    void setTextReflowAnchorPoint(const Platform::IntPoint& focalPoint);
+
+    void schedulePinchZoomAboutPoint(double scale, const WebCore::IntPoint& anchor);
+
+    // Perform actual zoom for block zoom.
+    void zoomBlock();
+
+    // Called by the backing store as well as the method below.
+    void requestLayoutIfNeeded() const;
+    void setNeedsLayout();
+
+    WebCore::IntPoint scrollPosition() const;
+    WebCore::IntPoint maximumScrollPosition() const;
+    void setScrollPosition(const WebCore::IntPoint&);
+    bool scrollBy(int deltaX, int deltaY, bool scrollMainFrame = true);
+
+    void enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(WebCore::Node*);
+    std::vector<Platform::ScrollViewBase> inRegionScrollableAreasForPoint(const Platform::IntPoint&);
+    void notifyInRegionScrollStatusChanged(bool status);
+    void setScrollOriginPoint(const Platform::IntPoint&);
+    void setHasInRegionScrollableAreas(bool);
+
+    // The actual visible size as reported by the client, but in WebKit coordinates.
+    WebCore::IntSize actualVisibleSize() const;
+
+    // The viewport size is the same as the client's window size, but in webkit coordinates.
+    WebCore::IntSize viewportSize() const;
+
+    // Modifies the zoomToFit algorithm logic to construct a scale such that the viewportSize above is equal to this size.
+    bool hasVirtualViewport() const;
+    bool isUserScalable() const { return m_userScalable; }
+    void setUserScalable(bool userScalable) { m_userScalable = userScalable; }
+
+    // Sets default layout size without doing layout or marking as needing layout.
+    void setDefaultLayoutSize(const WebCore::IntSize&);
+
+    // Updates WebCore when the viewportSize() or actualVisibleSize() change.
+    void updateViewportSize(bool setFixedReportedSize = true, bool sendResizeEvent = true);
+
+    WebCore::FloatPoint centerOfVisibleContentsRect() const;
+    WebCore::IntRect visibleContentsRect() const;
+    WebCore::IntSize contentsSize() const;
+    WebCore::IntSize absoluteVisibleOverflowSize() const;
+
+    // Virtual functions inherited from PageClientBlackBerry.
+    virtual void setCursor(WebCore::PlatformCursorHandle);
+    virtual Platform::NetworkStreamFactory* networkStreamFactory();
+    virtual Platform::Graphics::Window* platformWindow() const;
+    virtual void setPreventsScreenDimming(bool preventDimming);
+    virtual void showVirtualKeyboard(bool showKeyboard);
+    virtual void ensureContentVisible(bool centerInView = true);
+    virtual void zoomToContentRect(const WebCore::IntRect&);
+    virtual void registerPlugin(WebCore::PluginView*, bool);
+    virtual void notifyPageOnLoad();
+    virtual bool shouldPluginEnterFullScreen(WebCore::PluginView*, const char*);
+    virtual void didPluginEnterFullScreen(WebCore::PluginView*, const char*);
+    virtual void didPluginExitFullScreen(WebCore::PluginView*, const char*);
+    virtual void onPluginStartBackgroundPlay(WebCore::PluginView*, const char*);
+    virtual void onPluginStopBackgroundPlay(WebCore::PluginView*, const char*);
+    virtual bool lockOrientation(bool landscape);
+    virtual void unlockOrientation();
+    virtual int orientation() const;
+    virtual double currentZoomFactor() const;
+    virtual int showAlertDialog(WebPageClient::AlertType atype);
+    virtual bool isActive() const;
+
+    // Called from within WebKit via ChromeClientBlackBerry.
+    void enterFullscreenForNode(WebCore::Node*);
+    void exitFullscreenForNode(WebCore::Node*);
+    void contentsSizeChanged(const WebCore::IntSize&);
+    void overflowExceedsContentsSize() { m_overflowExceedsContentsSize = true; }
+    void layoutFinished();
+    void setNeedTouchEvents(bool);
+
+    // Called according to our heuristic or from setLoadState depending on whether we have a virtual viewport.
+    void zoomToInitialScaleOnLoad();
+
+    // Various scale factors.
+    double currentScale() const { return m_transformationMatrix->m11(); }
+    double zoomToFitScale() const;
+    double initialScale() const;
+    void setInitialScale(double scale) { m_initialScale = scale; }
+    double minimumScale() const
+    {
+        return (m_minimumScale > zoomToFitScale() && m_minimumScale <= maximumScale()) ? m_minimumScale : zoomToFitScale();
+    }
+
+    void setMinimumScale(double scale) { m_minimumScale = scale; }
+    double maximumScale() const;
+    void setMaximumScale(double scale) { m_maximumScale = scale; }
+    void resetScales();
+
+    // Note: to make this reflow width transform invariant just use
+    // transformedActualVisibleSize() here instead!
+    int reflowWidth() const { return actualVisibleSize().width(); }
+
+    // These methods give the real geometry of the device given the currently set transform.
+    WebCore::IntPoint transformedScrollPosition() const;
+    WebCore::IntPoint transformedMaximumScrollPosition() const;
+    WebCore::IntSize transformedActualVisibleSize() const;
+    WebCore::IntSize transformedViewportSize() const;
+    WebCore::IntRect transformedVisibleContentsRect() const;
+    WebCore::IntSize transformedContentsSize() const;
+
+    // Generic conversions of points, rects, relative to and from contents and viewport.
+    WebCore::IntPoint mapFromContentsToViewport(const WebCore::IntPoint&) const;
+    WebCore::IntPoint mapFromViewportToContents(const WebCore::IntPoint&) const;
+    WebCore::IntRect mapFromContentsToViewport(const WebCore::IntRect&) const;
+    WebCore::IntRect mapFromViewportToContents(const WebCore::IntRect&) const;
+
+    // Generic conversions of points, rects, relative to and from transformed contents and transformed viewport.
+    WebCore::IntPoint mapFromTransformedContentsToTransformedViewport(const WebCore::IntPoint&) const;
+    WebCore::IntPoint mapFromTransformedViewportToTransformedContents(const WebCore::IntPoint&) const;
+    WebCore::IntRect mapFromTransformedContentsToTransformedViewport(const WebCore::IntRect&) const;
+    WebCore::IntRect mapFromTransformedViewportToTransformedContents(const WebCore::IntRect&) const;
+
+    // Generic conversions of points, rects, and sizes to and from transformed coordinates.
+    WebCore::IntPoint mapToTransformed(const WebCore::IntPoint&) const;
+    WebCore::FloatPoint mapToTransformedFloatPoint(const WebCore::FloatPoint&) const;
+    WebCore::IntPoint mapFromTransformed(const WebCore::IntPoint&) const;
+    WebCore::FloatPoint mapFromTransformedFloatPoint(const WebCore::FloatPoint&) const;
+    WebCore::FloatRect mapFromTransformedFloatRect(const WebCore::FloatRect&) const;
+    WebCore::IntSize mapToTransformed(const WebCore::IntSize&) const;
+    WebCore::IntSize mapFromTransformed(const WebCore::IntSize&) const;
+    WebCore::IntRect mapToTransformed(const WebCore::IntRect&) const;
+    void clipToTransformedContentsRect(WebCore::IntRect&) const;
+    WebCore::IntRect mapFromTransformed(const WebCore::IntRect&) const;
+    bool transformedPointEqualsUntransformedPoint(const WebCore::IntPoint& transformedPoint, const WebCore::IntPoint& untransformedPoint);
+
+    // Notification methods that deliver changes to the real geometry of the device as specified above.
+    void notifyTransformChanged();
+    void notifyTransformedContentsSizeChanged();
+    void notifyTransformedScrollChanged();
+
+    void assignFocus(Platform::FocusDirection);
+    Platform::IntRect focusNodeRect();
+    WebCore::IntRect getRecursiveVisibleWindowRect(WebCore::ScrollView*, bool noClipOfMainFrame = false);
+
+    WebCore::IntPoint frameOffset(const WebCore::Frame*) const;
+
+    WebCore::Node* bestNodeForZoomUnderPoint(const WebCore::IntPoint&);
+    WebCore::Node* bestChildNodeForClickRect(WebCore::Node* parentNode, const WebCore::IntRect& clickRect);
+    WebCore::Node* nodeForZoomUnderPoint(const WebCore::IntPoint&);
+    WebCore::Node* adjustedBlockZoomNodeForZoomLimits(WebCore::Node*);
+    WebCore::IntRect rectForNode(WebCore::Node*);
+    WebCore::IntRect blockZoomRectForNode(WebCore::Node*);
+    WebCore::IntRect adjustRectOffsetForFrameOffset(const WebCore::IntRect&, const WebCore::Node*);
+    bool compareNodesForBlockZoom(WebCore::Node* n1, WebCore::Node* n2);
+    double newScaleForBlockZoomRect(const WebCore::IntRect&, double oldScale, double margin);
+    double maxBlockZoomScale() const;
+
+    // Plugin Methods.
+    void notifyPluginRectChanged(int id, const WebCore::IntRect& rectChanged);
+
+    // Context Methods.
+    ActiveNodeContext activeNodeContext(TargetDetectionStrategy);
+    PassRefPtr<WebCore::Node> contextNode(TargetDetectionStrategy);
+
+#if ENABLE(VIEWPORT_REFLOW)
+    void toggleTextReflowIfEnabledForBlockZoomOnly(bool shouldEnableTextReflow = false);
+#endif
+
+    void selectionChanged(WebCore::Frame*);
+
+    void updateDelegatedOverlays(bool dispatched = false);
+
+    void updateCursor();
+
+    void onInputLocaleChanged(bool isRTL);
+
+    ViewMode viewMode() const { return m_viewMode; }
+    bool setViewMode(ViewMode); // Returns true if the change requires re-layout.
+
+    void setShouldUseFixedDesktopMode(bool b) { m_shouldUseFixedDesktopMode = b; }
+
+    bool useFixedLayout() const;
+    WebCore::IntSize fixedLayoutSize(bool snapToIncrement = false) const;
+
+    // ZoomToFitOnLoad can lead to a large recursion depth in FrameView::layout() as we attempt
+    // to determine the zoom scale factor so as to have the content of the page fit within the
+    // area of the frame. From observation, we can bail out after a recursion depth of 10 and
+    // still have reasonable results.
+    bool didLayoutExceedMaximumIterations() const { return m_nestedLayoutFinishedCount > 10; }
+
+    void clearFocusNode();
+    WebCore::Frame* focusedOrMainFrame() const;
+    WebCore::Frame* mainFrame() const { return m_mainFrame; }
+
+    bool scrollNodeRecursively(WebCore::Node* originalNode, const WebCore::IntSize& delta);
+    bool scrollRenderer(WebCore::RenderObject* renderer, const WebCore::IntSize& delta);
+    void adjustScrollDelta(const WebCore::IntPoint& maxOffset, const WebCore::IntPoint& currentOffset, WebCore::IntSize& delta) const;
+
+    bool canScrollRenderBox(WebCore::RenderBox*);
+    bool canScrollInnerFrame(WebCore::Frame*) const;
+
+#if ENABLE(EVENT_MODE_METATAGS)
+    void didReceiveCursorEventMode(WebCore::CursorEventMode);
+    void didReceiveTouchEventMode(WebCore::TouchEventMode);
+#endif
+
+    void dispatchViewportPropertiesDidChange(const WebCore::ViewportArguments&);
+    WebCore::IntSize recomputeVirtualViewportFromViewportArguments();
+
+    void resetBlockZoom();
+
+    void zoomAboutPointTimerFired(WebCore::Timer<WebPagePrivate>*);
+    bool shouldSendResizeEvent();
+    void scrollEventTimerFired(WebCore::Timer<WebPagePrivate>*);
+    void resizeEventTimerFired(WebCore::Timer<WebPagePrivate>*);
+
+    // If this url should be handled as a pattern, returns the pattern
+    // otherwise, returns an empty string.
+    String findPatternStringForUrl(const WebCore::KURL&) const;
+
+    void suspendBackingStore();
+    void resumeBackingStore();
+
+    void setShouldResetTilesWhenShown(bool flag) { m_shouldResetTilesWhenShown = flag; }
+    bool shouldResetTilesWhenShown() const { return m_shouldResetTilesWhenShown; }
+
+    void setScreenOrientation(int);
+
+    // Scroll and/or zoom so that the WebPage fits the new actual
+    // visible size.
+    void setViewportSize(const WebCore::IntSize& transformedActualVisibleSize, bool ensureFocusElementVisible);
+    void screenRotated(); // Helper method for setViewportSize().
+
+    void scheduleDeferrableTimer(WebCore::Timer<WebPagePrivate>*, double timeOut);
+    void unscheduleAllDeferrableTimers();
+    void willDeferLoading();
+    void didResumeLoading();
+
+    // Returns true if the escape key handler should zoom.
+    bool shouldZoomOnEscape() const;
+
+    WebCore::TransformationMatrix* transformationMatrix() const
+    {
+        return m_transformationMatrix;
+    }
+
+#if USE(ACCELERATED_COMPOSITING)
+    // WebKit thread.
+    bool needsOneShotDrawingSynchronization();
+    void rootLayerCommitTimerFired(WebCore::Timer<WebPagePrivate>*);
+    bool commitRootLayerIfNeeded();
+    WebCore::LayerRenderingResults lastCompositingResults() const;
+
+    // WebKit thread, plumbed through from ChromeClientBlackBerry.
+    void setRootLayerWebKitThread(WebCore::Frame*, WebCore::LayerWebKitThread*);
+    void setNeedsOneShotDrawingSynchronization();
+    void scheduleRootLayerCommit();
+
+    // Thread safe.
+    void resetCompositingSurface();
+    void drawLayersOnCommit(); // Including backing store blit.
+    bool drawSubLayers(const WebCore::IntRect& dstRect, const WebCore::FloatRect& contents);
+    bool drawSubLayers(); // Draw them at last known position.
+
+    // Compositing thread.
+    void setRootLayerCompositingThread(WebCore::LayerCompositingThread*);
+    void commitRootLayer(const WebCore::IntRect&, const WebCore::IntSize&);
+    void setIsAcceleratedCompositingActive(bool);
+    void destroyCompositor();
+    void syncDestroyCompositorOnCompositingThread();
+    void destroyLayerResources();
+    void suspendRootLayerCommit();
+    void resumeRootLayerCommit();
+    void blitVisibleContents();
+#endif
+
+    bool dispatchTouchEventToFullScreenPlugin(WebCore::PluginView*, const Platform::TouchEvent&);
+    bool dispatchTouchPointAsMouseEventToFullScreenPlugin(WebCore::PluginView*, const Platform::TouchPoint&);
+    bool dispatchMouseEventToFullScreenPlugin(WebCore::PluginView*, const Platform::MouseEvent&);
+
+    BackingStoreClient* backingStoreClientForFrame(const WebCore::Frame*) const;
+    void addBackingStoreClientForFrame(const WebCore::Frame*, BackingStoreClient*);
+    void removeBackingStoreClientForFrame(const WebCore::Frame*);
+
+    // Clean up any document related data we might be holding.
+    void clearDocumentData(const WebCore::Document*);
+
+    static WebCore::RenderLayer* enclosingPositionedAncestorOrSelfIfPositioned(WebCore::RenderLayer*);
+    static WebCore::RenderLayer* enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(WebCore::RenderLayer*);
+
+    static WebCore::IntSize defaultMaxLayoutSize();
+
+    WebPage* m_webPage;
+    WebPageClient* m_client;
+    WebCore::Page* m_page;
+    WebCore::Frame* m_mainFrame;
+    RefPtr<WebCore::Node> m_currentContextNode;
+    WebSettings* m_webSettings;
+
+#if ENABLE(JAVASCRIPT_DEBUGGER)
+    OwnPtr<WebCore::JavaScriptDebuggerBlackBerry> m_scriptDebugger;
+#endif
+
+    bool m_visible;
+    bool m_shouldResetTilesWhenShown;
+    bool m_userScalable;
+    bool m_userPerformedManualZoom;
+    bool m_userPerformedManualScroll;
+    bool m_contentsSizeChanged;
+    bool m_overflowExceedsContentsSize;
+    bool m_resetVirtualViewportOnCommitted;
+    bool m_shouldUseFixedDesktopMode;
+    bool m_needTouchEvents;
+    int m_preventIdleDimmingCount;
+
+#if ENABLE(TOUCH_EVENTS)
+    bool m_preventDefaultOnTouchStart;
+#endif
+    unsigned m_nestedLayoutFinishedCount;
+    WebCore::IntSize m_previousContentsSize;
+    int m_actualVisibleWidth;
+    int m_actualVisibleHeight;
+    int m_virtualViewportWidth;
+    int m_virtualViewportHeight;
+    WebCore::IntSize m_defaultLayoutSize;
+    WebCore::ViewportArguments m_viewportArguments; // We keep this around since we may need to re-evaluate the arguments on rotation.
+    bool m_didRestoreFromPageCache;
+    ViewMode m_viewMode;
+    LoadState m_loadState;
+    WebCore::TransformationMatrix* m_transformationMatrix;
+    BackingStore* m_backingStore;
+    BackingStoreClient* m_backingStoreClient;
+    InPageSearchManager* m_inPageSearchManager;
+    InputHandler* m_inputHandler;
+    SelectionHandler* m_selectionHandler;
+    TouchEventHandler* m_touchEventHandler;
+
+#if ENABLE(EVENT_MODE_METATAGS)
+    WebCore::CursorEventMode m_cursorEventMode;
+    WebCore::TouchEventMode m_touchEventMode;
+#endif
+
+    Platform::BlackBerryCursor m_currentCursor;
+
+    DumpRenderTreeClient* m_dumpRenderTree;
+
+    double m_initialScale;
+    double m_minimumScale;
+    double m_maximumScale;
+
+    // Block zoom animation data.
+    WebCore::FloatPoint m_finalBlockPoint;
+    WebCore::FloatPoint m_finalBlockPointReflowOffset;
+    double m_blockZoomFinalScale;
+    RefPtr<WebCore::Node> m_currentPinchZoomNode;
+    WebCore::FloatPoint m_anchorInNodeRectRatio;
+    RefPtr<WebCore::Node> m_currentBlockZoomNode;
+    RefPtr<WebCore::Node> m_currentBlockZoomAdjustedNode;
+    bool m_shouldReflowBlock;
+
+    // Delayed zoomAboutPoint.
+    OwnPtr<WebCore::Timer<WebPagePrivate> > m_delayedZoomTimer;
+    struct {
+        double scale;
+        WebCore::FloatPoint anchor;
+        bool enforceScaleClamping;
+        bool forceRendering;
+    } m_delayedZoomArguments;
+
+    double m_lastUserEventTimestamp; // Used to detect user scrolling.
+
+    WebCore::PlatformMouseEvent m_lastMouseEvent;
+    bool m_pluginMouseButtonPressed; // Used to track mouse button for full screen plugins.
+    bool m_pluginMayOpenNewTab;
+
+    WebCore::GeolocationControllerClientBlackBerry* m_geolocationClient;
+
+    HashSet<WebCore::PluginView*> m_pluginViews;
+
+    RefPtr<WebCore::Node> m_inRegionScrollStartingNode;
+
+#if USE(ACCELERATED_COMPOSITING)
+    bool m_isAcceleratedCompositingActive;
+    OwnPtr<FrameLayers> m_frameLayers; // WebKit thread only.
+    OwnPtr<WebPageCompositor> m_compositor; // Compositing thread only.
+    OwnPtr<WebCore::Timer<WebPagePrivate> > m_rootLayerCommitTimer;
+    bool m_needsOneShotDrawingSynchronization;
+    bool m_needsCommit;
+    bool m_suspendRootLayerCommit;
+#endif
+
+    int m_pendingOrientation;
+
+    RefPtr<WebCore::Node> m_fullscreenVideoNode;
+    RefPtr<WebCore::PluginView> m_fullScreenPluginView;
+
+    typedef HashMap<const WebCore::Frame*, BackingStoreClient*> BackingStoreClientForFrameMap;
+    BackingStoreClientForFrameMap m_backingStoreClientForFrameMap;
+
+    // WebSettingsDelegate methods.
+    virtual void didChangeSettings(WebSettings*);
+
+    RefPtr<WebCore::DOMWrapperWorld> m_isolatedWorld;
+    bool m_hasInRegionScrollableAreas;
+    bool m_updateDelegatedOverlaysDispatched;
+};
+}
+}
+
+#endif // WebPage_p_h
index 1a74338..00891b2 100644 (file)
@@ -1,3 +1,16 @@
+2012-02-23  Jacky Jiang  <zhajiang@rim.com>
+
+        [BlackBerry] Upstream BlackBerry API web page related files
+        https://bugs.webkit.org/show_bug.cgi?id=74380
+
+        Reviewed by Antonio Gomes.
+
+        Initial upstream, no new tests.
+
+        * Api/WebPage.cpp: Added.
+        * Api/WebPage.h: Added.
+        * Api/WebPage_p.h: Added.
+
 2012-02-23  Leo Yang  <leo.yang@torchmobile.com.cn>
 
         [BlackBerry] Remove unused ChromeClientBlackBerry::platformCompositingWindow(), platformWindow() and WebPageClient::compositingWindow()