d0d52b4782c6f69517b46d9e46daf8d8d66a5e34
[WebKit-https.git] / Source / WebKit / blackberry / Api / WebPage.cpp
1 /*
2  * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20 #include "WebPage.h"
21
22 #include "ApplicationCacheStorage.h"
23 #include "BackForwardController.h"
24 #include "BackForwardListImpl.h"
25 #include "BackingStoreClient.h"
26 #include "BackingStoreCompositingSurface.h"
27 #include "BackingStore_p.h"
28 #include "CString.h"
29 #include "CachedImage.h"
30 #include "Chrome.h"
31 #include "ChromeClientBlackBerry.h"
32 #include "ContextMenuClientBlackBerry.h"
33 #include "CookieManager.h"
34 #include "DOMSupport.h"
35 #include "Database.h"
36 #include "DatabaseSync.h"
37 #include "DatabaseTracker.h"
38 #include "DeviceMotionClientBlackBerry.h"
39 #include "DeviceOrientationClientBlackBerry.h"
40 #include "DragClientBlackBerry.h"
41 // FIXME: We should be using DumpRenderTreeClient, but I'm not sure where we should
42 // create the DRT_BB object. See PR #120355.
43 #if ENABLE_DRT
44 #include "DumpRenderTreeBlackBerry.h"
45 #endif
46 #include "EditorClientBlackBerry.h"
47 #include "FocusController.h"
48 #include "FrameLoaderClientBlackBerry.h"
49 #if ENABLE_DRT
50 #include "GeolocationClientMock.h"
51 #endif
52 #include "GeolocationControllerClientBlackBerry.h"
53 #include "GroupSettings.h"
54 #include "HTMLAreaElement.h"
55 #include "HTMLFrameOwnerElement.h"
56 #include "HTMLImageElement.h"
57 #include "HTMLInputElement.h"
58 #include "HTMLNames.h"
59 #include "HTMLParserIdioms.h"
60 #include "HTTPParsers.h"
61 #include "HistoryItem.h"
62 #include "IconDatabaseClientBlackBerry.h"
63 #include "InPageSearchManager.h"
64 #include "InRegionScrollableArea.h"
65 #include "InputHandler.h"
66 #include "InspectorBackendDispatcher.h"
67 #include "InspectorClientBlackBerry.h"
68 #include "InspectorController.h"
69 #include "JavaScriptDebuggerBlackBerry.h"
70 #include "LayerWebKitThread.h"
71 #include "NetworkManager.h"
72 #include "NodeRenderStyle.h"
73 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
74 #include "NotificationPresenterImpl.h"
75 #endif
76 #include "Page.h"
77 #include "PageCache.h"
78 #include "PageGroup.h"
79 #include "PlatformTouchEvent.h"
80 #include "PlatformWheelEvent.h"
81 #include "PluginDatabase.h"
82 #include "PluginView.h"
83 #include "RenderText.h"
84 #include "RenderThemeBlackBerry.h"
85 #include "RenderTreeAsText.h"
86 #include "RenderView.h"
87 #include "RenderWidget.h"
88 #include "ScriptSourceCode.h"
89 #include "ScriptValue.h"
90 #include "ScrollTypes.h"
91 #include "SelectionHandler.h"
92 #include "Settings.h"
93 #include "Storage.h"
94 #include "StorageNamespace.h"
95 #include "SurfacePool.h"
96 #include "Text.h"
97 #include "ThreadCheck.h"
98 #include "TouchEventHandler.h"
99 #include "TransformationMatrix.h"
100 #include "VisiblePosition.h"
101 #if ENABLE(WEBDOM)
102 #include "WebDOMDocument.h"
103 #endif
104 #include "WebPageClient.h"
105 #include "WebSocket.h"
106 #include "npapi.h"
107 #include "runtime_root.h"
108
109 #if ENABLE(VIDEO)
110 #include "HTMLMediaElement.h"
111 #include "MediaPlayer.h"
112 #include "MediaPlayerPrivateBlackBerry.h"
113 #endif
114
115 #if USE(SKIA)
116 #include "PlatformContextSkia.h"
117 #endif
118
119 #if USE(ACCELERATED_COMPOSITING)
120 #include "FrameLayers.h"
121 #include "WebPageCompositor.h"
122 #endif
123
124 #include <BlackBerryPlatformExecutableMessage.h>
125 #include <BlackBerryPlatformITPolicy.h>
126 #include <BlackBerryPlatformKeyboardEvent.h>
127 #include <BlackBerryPlatformMessageClient.h>
128 #include <BlackBerryPlatformMouseEvent.h>
129 #include <BlackBerryPlatformScreen.h>
130 #include <BlackBerryPlatformSettings.h>
131 #include <JavaScriptCore/APICast.h>
132 #include <JavaScriptCore/JSContextRef.h>
133 #include <SharedPointer.h>
134 #include <sys/keycodes.h>
135 #include <unicode/ustring.h> // platform ICU
136
137 #ifndef USER_PROCESSES
138 #include <memalloc.h>
139 #endif
140
141 #if ENABLE(ACCELERATED_2D_CANVAS)
142 #include "SharedGraphicsContext3D.h"
143 #include "GrContext.h"
144 #endif
145
146 #if ENABLE(REQUEST_ANIMATION_FRAME)
147 #include "PlatformScreen.h"
148 #endif
149
150 #define DEBUG_BLOCK_ZOOM 0
151 #define DEBUG_TOUCH_EVENTS 0
152 #define DEBUG_WEBPAGE_LOAD 0
153
154 using namespace std;
155 using namespace WebCore;
156
157 typedef const unsigned short* CUShortPtr;
158
159 namespace BlackBerry {
160 namespace WebKit {
161
162 static Vector<WebPage*>* visibleWebPages()
163 {
164     static Vector<WebPage*>* s_visibleWebPages = 0; // Initially, no web page is visible.
165     if (!s_visibleWebPages)
166         s_visibleWebPages = new Vector<WebPage*>;
167     return s_visibleWebPages;
168 }
169
170 const unsigned blockZoomMargin = 3; // Add 3 pixel margin on each side.
171 static int blockClickRadius = 0;
172 static double maximumBlockZoomScale = 3; // This scale can be clamped by the maximumScale set for the page.
173
174 const double manualScrollInterval = 0.1; // The time interval during which we associate user action with scrolling.
175
176 const double delayedZoomInterval = 0;
177
178 const IntSize minimumLayoutSize(10, 10); // Needs to be a small size, greater than 0, that we can grow the layout from.
179 const IntSize maximumLayoutSize(10000, 10000); // Used with viewport meta tag, but we can still grow from this of course.
180
181 const double minimumExpandingRatio = 0.15;
182
183 // Helper function to parse a URL and fill in missing parts.
184 static KURL parseUrl(const String& url)
185 {
186     String urlString(url);
187     KURL kurl = KURL(KURL(), urlString);
188     if (kurl.protocol().isEmpty()) {
189         urlString.insert("http://", 0);
190         kurl = KURL(KURL(), urlString);
191     }
192
193     return kurl;
194 }
195
196 // Helper functions to convert to and from WebCore types.
197 static inline WebCore::PlatformEvent::Type toWebCoreMouseEventType(const BlackBerry::Platform::MouseEvent::Type type)
198 {
199     switch (type) {
200     case BlackBerry::Platform::MouseEvent::MouseButtonDown:
201         return WebCore::PlatformEvent::MousePressed;
202     case Platform::MouseEvent::MouseButtonUp:
203         return WebCore::PlatformEvent::MouseReleased;
204     case Platform::MouseEvent::MouseMove:
205     default:
206         return WebCore::PlatformEvent::MouseMoved;
207     }
208 }
209
210 static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy)
211 {
212     switch (policy) {
213     case Platform::NetworkRequest::UseProtocolCachePolicy:
214         return UseProtocolCachePolicy;
215     case Platform::NetworkRequest::ReloadIgnoringCacheData:
216         return ReloadIgnoringCacheData;
217     case Platform::NetworkRequest::ReturnCacheDataElseLoad:
218         return ReturnCacheDataElseLoad;
219     case Platform::NetworkRequest::ReturnCacheDataDontLoad:
220         return ReturnCacheDataDontLoad;
221     default:
222         ASSERT_NOT_REACHED();
223         return UseProtocolCachePolicy;
224     }
225 }
226
227 #if ENABLE(EVENT_MODE_METATAGS)
228 static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode)
229 {
230     switch (mode) {
231     case ProcessedCursorEvents:
232         return Platform::ProcessedCursorEvents;
233     case NativeCursorEvents:
234         return Platform::NativeCursorEvents;
235     default:
236         ASSERT_NOT_REACHED();
237         return Platform::ProcessedCursorEvents;
238     }
239 }
240
241 static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode)
242 {
243     switch (mode) {
244     case ProcessedTouchEvents:
245         return Platform::ProcessedTouchEvents;
246     case NativeTouchEvents:
247         return Platform::NativeTouchEvents;
248     case PureTouchEventsWithMouseConversion:
249         return Platform::PureTouchEventsWithMouseConversion;
250     default:
251         ASSERT_NOT_REACHED();
252         return Platform::ProcessedTouchEvents;
253     }
254 }
255 #endif
256
257 static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id)
258 {
259     return reinterpret_cast<HistoryItem*>(id);
260 }
261
262 static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item)
263 {
264     return reinterpret_cast<WebPage::BackForwardId>(item);
265 }
266
267 WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
268     : m_webPage(webPage)
269     , m_client(client)
270     , m_page(0) // Initialized by init.
271     , m_mainFrame(0) // Initialized by init.
272     , m_currentContextNode(0)
273     , m_webSettings(0) // Initialized by init.
274     , m_visible(false)
275     , m_activationState(ActivationActive)
276     , m_shouldResetTilesWhenShown(false)
277     , m_userScalable(true)
278     , m_userPerformedManualZoom(false)
279     , m_userPerformedManualScroll(false)
280     , m_contentsSizeChanged(false)
281     , m_overflowExceedsContentsSize(false)
282     , m_resetVirtualViewportOnCommitted(true)
283     , m_shouldUseFixedDesktopMode(false)
284     , m_needTouchEvents(false)
285     , m_preventIdleDimmingCount(0)
286 #if ENABLE(TOUCH_EVENTS)
287     , m_preventDefaultOnTouchStart(false)
288 #endif
289     , m_nestedLayoutFinishedCount(0)
290     , m_actualVisibleWidth(rect.width())
291     , m_actualVisibleHeight(rect.height())
292     , m_virtualViewportWidth(0)
293     , m_virtualViewportHeight(0)
294     , m_defaultLayoutSize(minimumLayoutSize)
295     , m_didRestoreFromPageCache(false)
296     , m_viewMode(WebPagePrivate::Desktop) // Default to Desktop mode for PB.
297     , m_loadState(WebPagePrivate::None)
298     , m_transformationMatrix(new TransformationMatrix())
299     , m_backingStore(0) // Initialized by init.
300     , m_backingStoreClient(0) // Initialized by init.
301     , m_inPageSearchManager(new InPageSearchManager(this))
302     , m_inputHandler(new InputHandler(this))
303     , m_selectionHandler(new SelectionHandler(this))
304     , m_touchEventHandler(new TouchEventHandler(this))
305 #if ENABLE(EVENT_MODE_METATAGS)
306     , m_cursorEventMode(ProcessedCursorEvents)
307     , m_touchEventMode(ProcessedTouchEvents)
308 #endif
309     , m_currentCursor(Platform::CursorNone)
310     , m_dumpRenderTree(0) // Lazy initialization.
311     , m_initialScale(-1.0)
312     , m_minimumScale(-1.0)
313     , m_maximumScale(-1.0)
314     , m_blockZoomFinalScale(1.0)
315     , m_anchorInNodeRectRatio(-1, -1)
316     , m_currentBlockZoomNode(0)
317     , m_currentBlockZoomAdjustedNode(0)
318     , m_shouldReflowBlock(false)
319     , m_delayedZoomTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::zoomAboutPointTimerFired)))
320     , m_lastUserEventTimestamp(0.0)
321     , m_pluginMouseButtonPressed(false)
322     , m_pluginMayOpenNewTab(false)
323     , m_geolocationClient(0)
324     , m_inRegionScrollStartingNode(0)
325 #if USE(ACCELERATED_COMPOSITING)
326     , m_isAcceleratedCompositingActive(false)
327     , m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
328     , m_needsOneShotDrawingSynchronization(false)
329     , m_needsCommit(false)
330     , m_suspendRootLayerCommit(false)
331 #endif
332     , m_pendingOrientation(-1)
333     , m_fullscreenVideoNode(0)
334     , m_hasInRegionScrollableAreas(false)
335     , m_updateDelegatedOverlaysDispatched(false)
336 {
337 }
338
339 WebPage::WebPage(WebPageClient* client, const WebString& pageGroupName, const Platform::IntRect& rect)
340 {
341     globalInitialize();
342     d = new WebPagePrivate(this, client, rect);
343     d->init(pageGroupName);
344 }
345
346 WebPagePrivate::~WebPagePrivate()
347 {
348     // Hand the backingstore back to another owner if necessary.
349     m_webPage->setVisible(false);
350     if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage)
351         BackingStorePrivate::setCurrentBackingStoreOwner(0);
352
353     delete m_webSettings;
354     m_webSettings = 0;
355
356     delete m_backingStoreClient;
357     m_backingStoreClient = 0;
358     m_backingStore = 0;
359
360     delete m_page;
361     m_page = 0;
362
363     delete m_transformationMatrix;
364     m_transformationMatrix = 0;
365
366     delete m_inPageSearchManager;
367     m_inPageSearchManager = 0;
368
369     delete m_selectionHandler;
370     m_selectionHandler = 0;
371
372     delete m_inputHandler;
373     m_inputHandler = 0;
374
375     delete m_touchEventHandler;
376     m_touchEventHandler = 0;
377
378 #if ENABLE_DRT
379     delete m_dumpRenderTree;
380     m_dumpRenderTree = 0;
381 #endif
382 }
383
384 WebPage::~WebPage()
385 {
386     delete d;
387     d = 0;
388 }
389
390 Page* WebPagePrivate::core(const WebPage* webPage)
391 {
392     return webPage->d->m_page;
393 }
394
395 void WebPagePrivate::init(const WebString& pageGroupName)
396 {
397     ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this);
398     ContextMenuClientBlackBerry* contextMenuClient = 0;
399 #if ENABLE(CONTEXT_MENUS)
400     contextMenuClient = new ContextMenuClientBlackBerry();
401 #endif
402     EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this);
403     DragClientBlackBerry* dragClient = 0;
404 #if ENABLE(DRAG_SUPPORT)
405     dragClient = new DragClientBlackBerry();
406 #endif
407     InspectorClientBlackBerry* inspectorClient = 0;
408 #if ENABLE(INSPECTOR)
409     inspectorClient = new InspectorClientBlackBerry(this);
410 #endif
411
412     FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry();
413
414     Page::PageClients pageClients;
415     pageClients.chromeClient = chromeClient;
416     pageClients.contextMenuClient = contextMenuClient;
417     pageClients.editorClient = editorClient;
418     pageClients.dragClient = dragClient;
419     pageClients.inspectorClient = inspectorClient;
420
421     // Note the object will be destroyed when the page is destroyed.
422 #if ENABLE_DRT
423     if (getenv("drtRun"))
424         pageClients.geolocationClient = new GeolocationClientMock();
425     else
426 #endif
427         pageClients.geolocationClient = m_geolocationClient = new GeolocationControllerClientBlackBerry(this);
428 #else
429     pageClients.geolocationClient = m_geolocationClient;
430
431     m_page = new Page(pageClients);
432     WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientBlackBerry(this));
433     WebCore::provideDeviceMotionTo(m_page, new DeviceMotionClientBlackBerry(this));
434
435 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
436     WebCore::provideNotification(m_page, NotificationPresenterImpl::instance());
437 #endif
438
439 #if ENABLE_DRT
440     // In case running in DumpRenderTree mode set the controller to mock provider.
441     if (getenv("drtRun"))
442         static_cast<GeolocationClientMock*>(pageClients.geolocationClient)->setController(m_page->geolocationController());
443 #endif
444
445     m_page->setCustomHTMLTokenizerChunkSize(256);
446     m_page->setCustomHTMLTokenizerTimeDelay(0.3);
447
448     m_webSettings = WebSettings::createFromStandardSettings();
449
450     // FIXME: We explicitly call setDelegate() instead of passing ourself in createFromStandardSettings()
451     // so that we only get one didChangeSettings() callback when we set the page group name. This causes us
452     // to make a copy of the WebSettings since some WebSettings method make use of the page group name.
453     // Instead, we shouldn't be storing the page group name in WebSettings.
454     m_webSettings->setDelegate(this);
455     m_webSettings->setPageGroupName(pageGroupName);
456
457     RefPtr<Frame> newFrame = Frame::create(m_page, /* HTMLFrameOwnerElement* */ 0, frameLoaderClient);
458
459     m_mainFrame = newFrame.get();
460     frameLoaderClient->setFrame(m_mainFrame, this);
461     m_mainFrame->init();
462
463 #if ENABLE(WEBGL)
464     Platform::Settings* settings = Platform::Settings::get();
465     m_page->settings()->setWebGLEnabled(settings && settings->isWebGLSupported());
466 #endif
467 #if ENABLE(ACCELERATED_2D_CANVAS)
468     m_page->settings()->setCanvasUsesAcceleratedDrawing(true);
469     m_page->settings()->setAccelerated2dCanvasEnabled(true);
470 #endif
471 #if ENABLE(VIEWPORT_REFLOW)
472     m_page->settings()->setTextReflowEnabled(m_webSettings->textReflowMode() == WebSettings::TextReflowEnabled);
473 #endif
474
475     m_page->settings()->setUseHixie76WebSocketProtocol(false);
476     m_page->settings()->setInteractiveFormValidationEnabled(true);
477     m_page->settings()->setAllowUniversalAccessFromFileURLs(false);
478     m_page->settings()->setAllowFileAccessFromFileURLs(false);
479
480     m_backingStoreClient = BackingStoreClient::create(m_mainFrame, /* parent frame */ 0, m_webPage);
481     // The direct access to BackingStore is left here for convenience since it
482     // is owned by BackingStoreClient and then deleted by its destructor.
483     m_backingStore = m_backingStoreClient->backingStore();
484
485     m_page->settings()->setSpatialNavigationEnabled(m_webSettings->isSpatialNavigationEnabled());
486     blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(0).width())); // The clicked rectangle area should be a fixed unit of measurement.
487
488     m_page->settings()->setDelegateSelectionPaint(true);
489
490 #if ENABLE(REQUEST_ANIMATION_FRAME)
491     m_page->windowScreenDidChange((PlatformDisplayID)0);
492 #endif
493 }
494
495 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)
496 {
497     stopCurrentLoad();
498
499     String urlString(url);
500     if (urlString.startsWith("vs:", false)) {
501         urlString = urlString.substring(3);
502         m_mainFrame->setInViewSourceMode(true);
503     } else
504         m_mainFrame->setInViewSourceMode(false);
505
506     KURL kurl = parseUrl(urlString);
507     if (protocolIs(kurl, "javascript")) {
508         // Never run javascript while loading is deferred.
509         if (m_page->defersLoading()) {
510             FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(m_mainFrame->loader()->client());
511             frameLoaderClient->setDeferredManualScript(kurl);
512         } else
513             m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL);
514         return;
515     }
516
517     if (isInitial)
518         NetworkManager::instance()->setInitialURL(kurl);
519
520     ResourceRequest request(kurl, "" /* referrer */);
521     request.setToken(networkToken);
522     if (isInitial || mustHandleInternally)
523         request.setMustHandleInternally(true);
524     request.setHTTPMethod(method);
525     request.setCachePolicy(toWebCoreCachePolicy(cachePolicy));
526     if (overrideContentType)
527         request.setOverrideContentType(overrideContentType);
528
529     if (data)
530         request.setHTTPBody(FormData::create(data, dataLength));
531
532     for (unsigned i = 0; i + 1 < headersLength; i += 2)
533         request.addHTTPHeaderField(headers[i], headers[i + 1]);
534
535     if (forceDownload)
536         request.setForceDownload(true);
537
538     m_mainFrame->loader()->load(request, "" /* name */, false);
539 }
540
541 void WebPage::load(const char* url, const char* networkToken, bool isInitial)
542 {
543     d->load(url, networkToken, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, isInitial, false);
544 }
545
546 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)
547 {
548     d->load(url, networkToken, method, cachePolicy, data, dataLength, headers, headersLength, false, mustHandleInternally, false, "");
549 }
550
551 void WebPage::loadFile(const char* path, const char* overrideContentType)
552 {
553     std::string fileUrl(path);
554     if (!fileUrl.find("/"))
555         fileUrl.insert(0, "file://");
556     else if (fileUrl.find("file:///"))
557         return;
558
559     d->load(fileUrl.c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, false, overrideContentType);
560 }
561
562 void WebPage::download(const Platform::NetworkRequest& request)
563 {
564     d->load(request.getUrlRef().c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, true, "");
565 }
566
567 void WebPagePrivate::loadString(const char* string, const char* baseURL, const char* contentType, const char* failingURL)
568 {
569     KURL kurl = parseUrl(baseURL);
570     ResourceRequest request(kurl);
571     WTF::RefPtr<SharedBuffer> buffer
572         = SharedBuffer::create(string, strlen(string));
573     SubstituteData substituteData(buffer,
574                                   extractMIMETypeFromMediaType(contentType),
575                                   extractCharsetFromMediaType(contentType),
576                                   failingURL ? parseUrl(failingURL) : KURL());
577     m_mainFrame->loader()->load(request, substituteData, false);
578 }
579
580 void WebPage::loadString(const char* string, const char* baseURL, const char* mimeType, const char* failingURL)
581 {
582     d->loadString(string, baseURL, mimeType, failingURL);
583 }
584
585 bool WebPagePrivate::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
586 {
587     ScriptValue result = m_mainFrame->script()->executeScript(String::fromUTF8(script), false);
588     JSC::JSValue value = result.jsValue();
589     if (!value) {
590         returnType = JSException;
591         return false;
592     }
593
594     JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
595     JSGlobalContextRef context = toGlobalRef(exec);
596
597     JSType type = JSValueGetType(context, toRef(exec, value));
598
599     switch (type) {
600     case kJSTypeNull:
601         returnType = JSNull;
602         break;
603     case kJSTypeBoolean:
604         returnType = JSBoolean;
605         break;
606     case kJSTypeNumber:
607         returnType = JSNumber;
608         break;
609     case kJSTypeString:
610         returnType = JSString;
611         break;
612     case kJSTypeObject:
613         returnType = JSObject;
614         break;
615     case kJSTypeUndefined:
616     default:
617         returnType = JSUndefined;
618         break;
619     }
620
621     if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
622         String str = result.toString(exec);
623         returnValue = WebString(str.impl());
624     }
625
626     return true;
627 }
628
629 bool WebPage::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
630 {
631     return d->executeJavaScript(script, returnType, returnValue);
632 }
633
634 bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& sourceCode, JavaScriptDataType& returnType, WebString& returnValue)
635 {
636     if (!m_isolatedWorld)
637         m_isolatedWorld = m_mainFrame->script()->createWorld();
638
639     // Use evaluateInWorld to avoid canExecuteScripts check.
640     ScriptValue result = m_mainFrame->script()->evaluateInWorld(sourceCode, m_isolatedWorld.get());
641     JSC::JSValue value = result.jsValue();
642     if (!value) {
643         returnType = JSException;
644         return false;
645     }
646
647     JSC::ExecState* exec = m_mainFrame->script()->globalObject(m_isolatedWorld.get())->globalExec();
648     JSGlobalContextRef context = toGlobalRef(exec);
649
650     JSType type = JSValueGetType(context, toRef(exec, value));
651
652     switch (type) {
653     case kJSTypeNull:
654         returnType = JSNull;
655         break;
656     case kJSTypeBoolean:
657         returnType = JSBoolean;
658         break;
659     case kJSTypeNumber:
660         returnType = JSNumber;
661         break;
662     case kJSTypeString:
663         returnType = JSString;
664         break;
665     case kJSTypeObject:
666         returnType = JSObject;
667         break;
668     case kJSTypeUndefined:
669     default:
670         returnType = JSUndefined;
671         break;
672     }
673
674     if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
675         String str = result.toString(exec);
676         returnValue = WebString(str.impl());
677     }
678
679     return true;
680 }
681
682 bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, WebString& returnValue)
683 {
684     // On our platform wchar_t is unsigned int and UChar is unsigned short
685     // so we have to convert using ICU conversion function
686     int lengthCopied = 0;
687     UErrorCode error = U_ZERO_ERROR;
688     const int length = script.length() + 1 /*null termination char*/;
689     UChar data[length];
690
691     // FIXME: PR 138162 is giving U_INVALID_CHAR_FOUND error.
692     u_strFromUTF32(data, length, &lengthCopied, reinterpret_cast<const UChar32*>(script.c_str()), script.length(), &error);
693     BLACKBERRY_ASSERT(error == U_ZERO_ERROR);
694     if (error != U_ZERO_ERROR) {
695         Platform::logAlways(Platform::LogLevelCritical, "WebPage::executeJavaScriptInIsolatedWorld failed to convert UTF16 to JavaScript!");
696         return false;
697     }
698     String str = String(data, lengthCopied);
699     ScriptSourceCode sourceCode(str, KURL());
700     return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
701 }
702
703 bool WebPage::executeJavaScriptInIsolatedWorld(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
704 {
705     ScriptSourceCode sourceCode(String::fromUTF8(script), KURL());
706     return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
707 }
708
709 void WebPagePrivate::stopCurrentLoad()
710 {
711     // This function should contain all common code triggered by WebPage::load
712     // (which stops any load in progress before starting the new load) and
713     // WebPage::stoploading (the entry point for the client to stop the load
714     // explicitly). If it should only be done while stopping the load
715     // explicitly, it goes in WebPage::stopLoading, not here.
716     m_mainFrame->loader()->stopAllLoaders();
717
718     // Cancel any deferred script that hasn't been processed yet.
719     FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(m_mainFrame->loader()->client());
720     frameLoaderClient->setDeferredManualScript(KURL());
721 }
722
723 void WebPage::stopLoading()
724 {
725     d->stopCurrentLoad();
726 }
727
728 static void closeURLRecursively(Frame* frame)
729 {
730     // Do not create more frame please.
731     FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client());
732     frameLoaderClient->suppressChildFrameCreation();
733
734     frame->loader()->closeURL();
735
736     Vector<RefPtr<Frame>, 10> childFrames;
737
738     for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
739         childFrames.append(childFrame);
740
741     unsigned size = childFrames.size();
742     for (unsigned i = 0; i < size; i++)
743         closeURLRecursively(childFrames[i].get());
744 }
745
746 void WebPagePrivate::prepareToDestroy()
747 {
748     // Before the client starts tearing itself down, dispatch the unload event
749     // so it can take effect while all the client's state (e.g. scroll position)
750     // is still present.
751     closeURLRecursively(m_mainFrame);
752 }
753
754 void WebPage::prepareToDestroy()
755 {
756     d->prepareToDestroy();
757 }
758
759 void WebPagePrivate::setLoadState(LoadState state)
760 {
761     if (m_loadState == state)
762         return;
763
764     bool isFirstLoad = m_loadState == None;
765
766     // See RIM Bug #1068.
767     if (state == Finished && m_mainFrame && m_mainFrame->document())
768         m_mainFrame->document()->updateStyleIfNeeded();
769
770     m_loadState = state;
771
772 #if DEBUG_WEBPAGE_LOAD
773     Platform::log(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state);
774 #endif
775
776     switch (m_loadState) {
777     case Provisional:
778         if (isFirstLoad) {
779             // Paints the visible backingstore as white to prevent initial checkerboard on
780             // the first blit.
781             if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
782                 m_backingStore->d->blitVisibleContents();
783         }
784         break;
785     case Committed:
786         {
787             unscheduleZoomAboutPoint();
788
789 #if ENABLE(ACCELERATED_2D_CANVAS)
790             if (m_page->settings()->canvasUsesAcceleratedDrawing()) {
791                 // Free GPU resources as we're on a new page.
792                 // This will help us to free memory pressure.
793                 SharedGraphicsContext3D::get()->makeContextCurrent();
794                 GrContext* grContext = Platform::Graphics::getGrContext();
795                 grContext->freeGpuResources();
796             }
797 #endif
798
799 #if USE(ACCELERATED_COMPOSITING)
800             // FIXME: compositor may only be touched on the compositing thread.
801             // However, it's created/destroyed by a sync command so this is harmless.
802             if (m_compositor) {
803                 m_compositor->setLayoutRectForCompositing(IntRect());
804                 m_compositor->setContentsSizeForCompositing(IntSize());
805             }
806 #endif
807             m_previousContentsSize = IntSize();
808             m_backingStore->d->resetRenderQueue();
809             m_backingStore->d->resetTiles(true /* resetBackground */);
810             m_backingStore->d->setScrollingOrZooming(false, false /* shouldBlit */);
811             m_userPerformedManualZoom = false;
812             m_userPerformedManualScroll = false;
813             m_shouldUseFixedDesktopMode = false;
814             if (m_resetVirtualViewportOnCommitted) { // For DRT.
815                 m_virtualViewportWidth = 0;
816                 m_virtualViewportHeight = 0;
817             }
818             if (m_webSettings->viewportWidth() > 0) {
819                 m_virtualViewportWidth = m_webSettings->viewportWidth();
820                 m_virtualViewportHeight = m_defaultLayoutSize.height();
821             }
822             // Check if we have already process the meta viewport tag, this only happens on history navigation
823             if (!m_didRestoreFromPageCache) {
824                 m_viewportArguments = ViewportArguments();
825                 m_userScalable = m_webSettings->isUserScalable();
826                 resetScales();
827             } else {
828                 IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
829                 m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
830             }
831
832 #if ENABLE(EVENT_MODE_METATAGS)
833             didReceiveCursorEventMode(ProcessedCursorEvents);
834             didReceiveTouchEventMode(ProcessedTouchEvents);
835 #endif
836
837             // If it's a outmost SVG document, we use FixedDesktop mode, otherwise
838             // we default to Mobile mode. For example, using FixedDesktop mode to
839             // render http://www.croczilla.com/bits_and_pieces/svg/samples/tiger/tiger.svg
840             // is user-experience friendly.
841             if (m_page->mainFrame()->document()->isSVGDocument()) {
842                 setShouldUseFixedDesktopMode(true);
843                 setViewMode(FixedDesktop);
844             } else
845                 setViewMode(Mobile);
846
847             // Reset block zoom and reflow.
848             resetBlockZoom();
849 #if ENABLE(VIEWPORT_REFLOW)
850             toggleTextReflowIfEnabledForBlockZoomOnly();
851 #endif
852
853             // Notify InputHandler of state change.
854             m_inputHandler->enableInputMode(false);
855
856             // Set the scroll to origin here and notify the client since we'll be
857             // zooming below without any real contents yet thus the contents size
858             // we report to the client could make our current scroll position invalid.
859             setScrollPosition(IntPoint::zero());
860             notifyTransformedScrollChanged();
861
862             // Paints the visible backingstore as white. Note it is important we do
863             // this strictly after re-setting the scroll position to origin and resetting
864             // the scales otherwise the visible contents calculation is wrong and we
865             // can end up blitting artifacts instead. See: RIM Bug #401.
866             if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
867                 m_backingStore->d->blitVisibleContents();
868
869             zoomToInitialScaleOnLoad();
870
871             // Update cursor status.
872             updateCursor();
873
874 #if USE(ACCELERATED_COMPOSITING)
875             // Don't render compositing contents from previous page.
876             resetCompositingSurface();
877 #endif
878             break;
879         }
880     case Finished:
881     case Failed:
882         // Notify client of the initial zoom change.
883         m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
884         m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
885         break;
886     default:
887         break;
888     }
889 }
890
891 double WebPagePrivate::clampedScale(double scale) const
892 {
893     if (scale < minimumScale())
894         return minimumScale();
895     if (scale > maximumScale())
896         return maximumScale();
897     return scale;
898 }
899
900 bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale)
901 {
902     if (!m_mainFrame->view())
903         return false;
904
905     if (enforceScaleClamping)
906         scale = this->clampedScale(scale);
907
908     ASSERT(clampedScale);
909     *clampedScale = scale;
910
911     if (currentScale() == scale) {
912         // Make sure backingstore updates resume from pinch zoom in the case where the final zoom level doesn't change.
913         m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
914         m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
915         return false;
916     }
917
918     return true;
919 }
920
921 bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel)
922 {
923     if (!isRestoringZoomLevel) {
924         // Clear any existing block zoom.  (If we are restoring a saved zoom level on page load,
925         // there is guaranteed to be no existing block zoom and we don't want to clear m_shouldReflowBlock.)
926         resetBlockZoom();
927     }
928
929     // The reflow and block zoom stuff here needs to happen regardless of
930     // whether we shouldZoomAboutPoint.
931 #if ENABLE(VIEWPORT_REFLOW)
932     toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
933     if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view())
934         setNeedsLayout();
935 #endif
936
937     double scale;
938     if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
939         if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
940             m_currentPinchZoomNode = 0;
941             m_anchorInNodeRectRatio = FloatPoint(-1, -1);
942         }
943         return false;
944     }
945     TransformationMatrix zoom;
946     zoom.scale(scale);
947
948 #if DEBUG_WEBPAGE_LOAD
949     if (loadState() < Finished)
950         Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomAboutPoint scale %f anchor (%f, %f)", scale, anchor.x(), anchor.y());
951 #endif
952
953     // Our current scroll position in float.
954     FloatPoint scrollPosition = this->scrollPosition();
955
956     // Anchor offset from scroll position in float.
957     FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y());
958
959     // The horizontal scaling factor and vertical scaling factor should be equal
960     // to preserve aspect ratio of content.
961     ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22());
962
963     // Need to invert the previous transform to anchor the viewport.
964     double inverseScale = scale / m_transformationMatrix->m11();
965
966     // Actual zoom.
967     *m_transformationMatrix = zoom;
968
969     // Suspend all screen updates to the backingstore.
970     m_backingStore->d->suspendScreenAndBackingStoreUpdates();
971
972     updateViewportSize();
973
974     IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))),
975                                         max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale)))));
976
977     if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
978         // This is a hack for email which has reflow always turned on.
979         m_mainFrame->view()->setNeedsLayout();
980         requestLayoutIfNeeded();
981         if (m_currentPinchZoomNode)
982             newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale);
983          m_currentPinchZoomNode = 0;
984          m_anchorInNodeRectRatio = FloatPoint(-1, -1);
985     }
986
987     setScrollPosition(newScrollPosition);
988
989     notifyTransformChanged();
990
991     bool isLoading = this->isLoading();
992
993     // We need to invalidate all tiles both visible and non-visible if we're loading.
994     m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */);
995
996     m_client->resetBitmapZoomScale(m_transformationMatrix->m11());
997
998     bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering;
999     bool shouldClearVisibleZoom = isLoading && shouldRender;
1000
1001     if (shouldClearVisibleZoom) {
1002         // If we are loading and rendering then we need to clear the render queue's
1003         // visible zoom jobs as they will be irrelevant with the render below.
1004         m_backingStore->d->clearVisibleZoom();
1005     }
1006
1007     // Clear window to make sure there are no artifacts.
1008     if (shouldRender) {
1009         m_backingStore->d->clearWindow();
1010         // Resume all screen updates to the backingstore and render+blit visible contents to screen.
1011         m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
1012     } else {
1013         // Resume all screen updates to the backingstore but do not blit to the screen because we not rendering.
1014         m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1015     }
1016
1017     m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1018
1019     return true;
1020 }
1021
1022 IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale)
1023 {
1024     // Should only be invoked when text reflow is enabled.
1025     ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
1026
1027     int offsetY = 0;
1028     int offsetX = 0;
1029
1030     IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
1031
1032     if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) {
1033         offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y();
1034         if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0)
1035             offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale;
1036     }
1037
1038     IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get());
1039
1040     return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))),
1041                     max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale))));
1042 }
1043
1044 bool WebPagePrivate::scheduleZoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering)
1045 {
1046     double scale;
1047     if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1048         // We could be back to the right zoom level before the timer has
1049         // timed out, because of wiggling back and forth. Stop the timer.
1050         unscheduleZoomAboutPoint();
1051         return false;
1052     }
1053
1054     // For some reason, the bitmap zoom wants an anchor in backingstore coordinates!
1055     // this is different from zoomAboutPoint, which wants content coordinates.
1056     // See RIM Bug #641.
1057
1058     FloatPoint transformedAnchor = mapToTransformedFloatPoint(anchor);
1059     FloatPoint transformedScrollPosition = mapToTransformedFloatPoint(scrollPosition());
1060
1061     // Prohibit backingstore from updating the window overtop of the bitmap.
1062     m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1063
1064     // Need to invert the previous transform to anchor the viewport.
1065     double zoomFraction = scale / transformationMatrix()->m11();
1066
1067     // Anchor offset from scroll position in float.
1068     FloatPoint anchorOffset(transformedAnchor.x() - transformedScrollPosition.x(),
1069                             transformedAnchor.y() - transformedScrollPosition.y());
1070
1071     IntPoint srcPoint(
1072         static_cast<int>(roundf(transformedAnchor.x() - anchorOffset.x() / zoomFraction)),
1073         static_cast<int>(roundf(transformedAnchor.y() - anchorOffset.y() / zoomFraction)));
1074
1075     const IntRect viewportRect = IntRect(IntPoint::zero(), transformedViewportSize());
1076     const IntRect dstRect = viewportRect;
1077
1078     // This is the rect to pass as the actual source rect in the backingstore
1079     // for the transform given by zoom.
1080     IntRect srcRect(srcPoint.x(),
1081                     srcPoint.y(),
1082                     viewportRect.width() / zoomFraction,
1083                     viewportRect.height() / zoomFraction);
1084     m_backingStore->d->blitContents(dstRect, srcRect);
1085
1086     m_delayedZoomArguments.scale = scale;
1087     m_delayedZoomArguments.anchor = anchor;
1088     m_delayedZoomArguments.enforceScaleClamping = enforceScaleClamping;
1089     m_delayedZoomArguments.forceRendering = forceRendering;
1090     m_delayedZoomTimer->startOneShot(delayedZoomInterval);
1091
1092     return true;
1093 }
1094
1095 void WebPagePrivate::unscheduleZoomAboutPoint()
1096 {
1097     if (m_delayedZoomTimer->isActive())
1098         m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1099
1100     m_delayedZoomTimer->stop();
1101 }
1102
1103 void WebPagePrivate::zoomAboutPointTimerFired(Timer<WebPagePrivate>*)
1104 {
1105     zoomAboutPoint(m_delayedZoomArguments.scale, m_delayedZoomArguments.anchor, m_delayedZoomArguments.enforceScaleClamping, m_delayedZoomArguments.forceRendering);
1106 }
1107
1108 void WebPagePrivate::setNeedsLayout()
1109 {
1110     FrameView* view = m_mainFrame->view();
1111     ASSERT(view);
1112     view->setNeedsLayout();
1113 }
1114
1115 void WebPagePrivate::requestLayoutIfNeeded() const
1116 {
1117     FrameView* view = m_mainFrame->view();
1118     ASSERT(view);
1119     view->updateLayoutAndStyleIfNeededRecursive();
1120     ASSERT(!view->needsLayout());
1121 }
1122
1123 IntPoint WebPagePrivate::scrollPosition() const
1124 {
1125     return m_backingStoreClient->scrollPosition();
1126 }
1127
1128 IntPoint WebPagePrivate::maximumScrollPosition() const
1129 {
1130     return m_backingStoreClient->maximumScrollPosition();
1131 }
1132
1133 void WebPagePrivate::setScrollPosition(const IntPoint& pos)
1134 {
1135     m_backingStoreClient->setScrollPosition(pos);
1136 }
1137
1138 // Setting the scroll position is in transformed coordinates.
1139 void WebPage::setScrollPosition(const Platform::IntPoint& point)
1140 {
1141     if (d->transformedPointEqualsUntransformedPoint(point, d->scrollPosition()))
1142         return;
1143
1144     // If the user recently performed an event, this new scroll position
1145     // could possibly be a result of that. Or not, this is just a heuristic.
1146     if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
1147         d->m_userPerformedManualScroll = true;
1148
1149     d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1150     d->m_mainFrame->view()->setCanOverscroll(true);
1151     d->setScrollPosition(d->mapFromTransformed(point));
1152     d->m_mainFrame->view()->setCanOverscroll(false);
1153     d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1154 }
1155
1156 bool WebPagePrivate::shouldSendResizeEvent()
1157 {
1158     if (!m_mainFrame->document())
1159         return false;
1160
1161     // PR#96865 : Provide an option to always send resize events, regardless of the loading
1162     //            status. The scenario for this are Sapphire applications which tend to
1163     //            maintain an open GET request to the server. This open GET results in
1164     //            webkit thinking that content is still arriving when at the application
1165     //            level it is considered fully loaded.
1166     //
1167     //            NOTE: Care must be exercised in the use of this option, as it bypasses
1168     //                  the sanity provided in 'isLoadingInAPISense()' below.
1169     //
1170     static const bool unrestrictedResizeEvents = Platform::Settings::get()->unrestrictedResizeEvents();
1171     if (unrestrictedResizeEvents)
1172         return true;
1173
1174     // Don't send the resize event if the document is loading. Some pages automatically reload
1175     // when the window is resized; Safari on iPhone often resizes the window while setting up its
1176     // viewport. This obviously can cause problems.
1177     DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
1178     if (documentLoader && documentLoader->isLoadingInAPISense())
1179         return false;
1180
1181     return true;
1182 }
1183
1184 void WebPagePrivate::willDeferLoading()
1185 {
1186     m_client->willDeferLoading();
1187 }
1188
1189 void WebPagePrivate::didResumeLoading()
1190 {
1191     m_client->didResumeLoading();
1192 }
1193
1194 bool WebPagePrivate::scrollBy(int deltaX, int deltaY, bool scrollMainFrame)
1195 {
1196     IntSize delta(deltaX, deltaY);
1197     if (!scrollMainFrame) {
1198         // We need to work around the fact that ::map{To,From}Transformed do not
1199         // work well with negative values, like a negative width or height of an IntSize.
1200         IntSize copiedDelta(IntSize(abs(delta.width()), abs(delta.height())));
1201         IntSize untransformedCopiedDelta = mapFromTransformed(copiedDelta);
1202         delta = IntSize(
1203             delta.width() < 0 ? -untransformedCopiedDelta.width() : untransformedCopiedDelta.width(),
1204             delta.height() < 0 ? -untransformedCopiedDelta.height(): untransformedCopiedDelta.height());
1205
1206         if (m_inRegionScrollStartingNode) {
1207             if (scrollNodeRecursively(m_inRegionScrollStartingNode.get(), delta)) {
1208                 m_selectionHandler->selectionPositionChanged();
1209                 // FIXME: We have code in place to handle scrolling and clipping tap highlight
1210                 // on in-region scrolling. As soon as it is fast enough (i.e. we have it backed by
1211                 // a backing store), we can reliably make use of it in the real world.
1212                 // m_touchEventHandler->drawTapHighlight();
1213                 return true;
1214             }
1215         }
1216
1217         return false;
1218     }
1219
1220     setScrollPosition(scrollPosition() + delta);
1221     return true;
1222 }
1223
1224 bool WebPage::scrollBy(const Platform::IntSize& delta, bool scrollMainFrame)
1225 {
1226     d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1227     bool b = d->scrollBy(delta.width(), delta.height(), scrollMainFrame);
1228     d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1229     return b;
1230 }
1231
1232 void WebPagePrivate::notifyInRegionScrollStatusChanged(bool status)
1233 {
1234     if (!status && m_inRegionScrollStartingNode) {
1235         enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(m_inRegionScrollStartingNode.get());
1236         m_inRegionScrollStartingNode = 0;
1237     }
1238 }
1239
1240 void WebPage::notifyInRegionScrollStatusChanged(bool status)
1241 {
1242     d->notifyInRegionScrollStatusChanged(status);
1243 }
1244
1245 void WebPagePrivate::enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(Node* scrolledNode)
1246 {
1247     ASSERT(scrolledNode);
1248     if (scrolledNode->isDocumentNode()) {
1249         Frame* frame = static_cast<const Document*>(scrolledNode)->frame();
1250         ASSERT(frame);
1251         if (!frame)
1252             return;
1253         ASSERT(frame != m_mainFrame);
1254         FrameView* view = frame->view();
1255         if (!view)
1256             return;
1257
1258         // Steps:
1259         // #1 - Get frame rect in contents coords.
1260         // #2 - Get the clipped scrollview rect in contents coords.
1261         // #3 - Take transform into account for 1 and 2.
1262         // #4 - Subtract 2 from 1, so we know exactly which areas of the frame
1263         //      are offscreen, and need async repainting.
1264         FrameView* mainFrameView = m_mainFrame->view();
1265         ASSERT(mainFrameView);
1266         IntRect frameRect = view->frameRect();
1267         frameRect = frame->tree()->parent()->view()->contentsToWindow(frameRect);
1268         frameRect = mainFrameView->windowToContents(frameRect);
1269
1270         IntRect visibleWindowRect = getRecursiveVisibleWindowRect(view);
1271         IntRect visibleContentsRect = mainFrameView->windowToContents(visibleWindowRect);
1272
1273         IntRect transformedFrameRect = mapToTransformed(frameRect);
1274         IntRect transformedVisibleContentsRect = mapToTransformed(visibleContentsRect);
1275
1276         Platform::IntRectRegion offscreenRegionOfIframe
1277             = Platform::IntRectRegion::subtractRegions(Platform::IntRect(transformedFrameRect), Platform::IntRect(transformedVisibleContentsRect));
1278
1279         if (!offscreenRegionOfIframe.isEmpty())
1280             m_backingStore->d->m_renderQueue->addToQueue(RenderQueue::RegularRender, offscreenRegionOfIframe.rects());
1281     }
1282 }
1283
1284 void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
1285 {
1286     if (b != m_hasInRegionScrollableAreas)
1287         m_hasInRegionScrollableAreas = b;
1288 }
1289
1290 IntSize WebPagePrivate::viewportSize() const
1291 {
1292     return mapFromTransformed(transformedViewportSize());
1293 }
1294
1295 IntSize WebPagePrivate::actualVisibleSize() const
1296 {
1297     return mapFromTransformed(transformedActualVisibleSize());
1298 }
1299
1300 bool WebPagePrivate::hasVirtualViewport() const
1301 {
1302     return m_virtualViewportWidth && m_virtualViewportHeight;
1303 }
1304
1305 void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
1306 {
1307     ASSERT(m_mainFrame->view());
1308     if (setFixedReportedSize)
1309         m_mainFrame->view()->setFixedReportedSize(actualVisibleSize());
1310
1311     IntRect frameRect = IntRect(scrollPosition(), viewportSize());
1312     if (frameRect != m_mainFrame->view()->frameRect()) {
1313         m_mainFrame->view()->setFrameRect(frameRect);
1314         m_mainFrame->view()->adjustViewSize();
1315     }
1316
1317     // We're going to need to send a resize event to JavaScript because
1318     // innerWidth and innerHeight depend on fixed reported size.
1319     // This is how we support mobile pages where JavaScript resizes
1320     // the page in order to get around the fixed layout size, e.g.
1321     // google maps when it detects a mobile user agent.
1322     if (sendResizeEvent && shouldSendResizeEvent())
1323         m_mainFrame->eventHandler()->sendResizeEvent();
1324
1325     // When the actual visible size changes, we also
1326     // need to reposition fixed elements.
1327     m_mainFrame->view()->repaintFixedElementsAfterScrolling();
1328 }
1329
1330 FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
1331 {
1332     // The visible contents rect in float.
1333     FloatRect visibleContentsRect = this->visibleContentsRect();
1334
1335     // The center of the visible contents rect in float.
1336     return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
1337                       visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
1338 }
1339
1340 IntRect WebPagePrivate::visibleContentsRect() const
1341 {
1342     return m_backingStoreClient->visibleContentsRect();
1343 }
1344
1345 IntSize WebPagePrivate::contentsSize() const
1346 {
1347     if (!m_mainFrame->view())
1348         return IntSize();
1349
1350     return m_backingStoreClient->contentsSize();
1351 }
1352
1353 IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
1354 {
1355     if (!m_mainFrame->contentRenderer())
1356         return IntSize();
1357
1358     return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
1359 }
1360
1361 void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
1362 {
1363     if (m_previousContentsSize == contentsSize)
1364         return;
1365
1366     // This should only occur in the middle of layout so we set a flag here and
1367     // handle it at the end of the layout.
1368     m_contentsSizeChanged = true;
1369
1370 #if DEBUG_WEBPAGE_LOAD
1371     Platform::log(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %dx%d", contentsSize.width(), contentsSize.height());
1372 #endif
1373 }
1374
1375 void WebPagePrivate::layoutFinished()
1376 {
1377     if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
1378         return;
1379
1380     m_contentsSizeChanged = false; // Toggle to turn off notification again.
1381     m_overflowExceedsContentsSize = false;
1382
1383     if (contentsSize().isEmpty())
1384         return;
1385
1386     // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from
1387     // the middle of a layout, but the recursion is limited by detection code in
1388     // setViewMode() and mitigation code in fixedLayoutSize().
1389     if (didLayoutExceedMaximumIterations()) {
1390         notifyTransformedContentsSizeChanged();
1391         return;
1392     }
1393
1394     // Temporarily save the m_previousContentsSize here before updating it (in
1395     // notifyTransformedContentsSizeChanged()) so we can compare if our contents
1396     // shrunk afterwards.
1397     IntSize previousContentsSize = m_previousContentsSize;
1398
1399     m_nestedLayoutFinishedCount++;
1400
1401     if (loadState() == Committed)
1402         zoomToInitialScaleOnLoad();
1403     else if (loadState() != None)
1404         notifyTransformedContentsSizeChanged();
1405
1406     m_nestedLayoutFinishedCount--;
1407
1408     if (!m_nestedLayoutFinishedCount) {
1409         // When the contents shrinks, there is a risk that we
1410         // will be left at a scroll position that lies outside of the
1411         // contents rect. Since we allow overscrolling and neglect
1412         // to clamp overscroll in order to retain input focus (RIM Bug #414)
1413         // we need to clamp somewhere, and this is where we know the
1414         // contents size has changed.
1415
1416         if (contentsSize() != previousContentsSize) {
1417
1418             IntPoint newScrollPosition = scrollPosition();
1419
1420             if (contentsSize().height() < previousContentsSize.height()) {
1421                 IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
1422                 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
1423             }
1424
1425             if (contentsSize().width() < previousContentsSize.width()) {
1426                 IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
1427                 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
1428             }
1429
1430             if (newScrollPosition != scrollPosition()) {
1431                 setScrollPosition(newScrollPosition);
1432                 notifyTransformedScrollChanged();
1433             }
1434         }
1435     }
1436 }
1437
1438 void WebPagePrivate::zoomToInitialScaleOnLoad()
1439 {
1440 #if DEBUG_WEBPAGE_LOAD
1441     Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
1442 #endif
1443
1444     bool needsLayout = false;
1445
1446     // If the contents width exceeds the viewport width set to desktop mode.
1447     if (m_shouldUseFixedDesktopMode)
1448         needsLayout = setViewMode(FixedDesktop);
1449     else
1450         needsLayout = setViewMode(Desktop);
1451
1452     if (needsLayout) {
1453         // This can cause recursive layout...
1454         setNeedsLayout();
1455     }
1456
1457     if (contentsSize().isEmpty()) {
1458 #if DEBUG_WEBPAGE_LOAD
1459         Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
1460 #endif
1461         requestLayoutIfNeeded();
1462         m_client->resetBitmapZoomScale(currentScale());
1463         notifyTransformedContentsSizeChanged();
1464         return;
1465     }
1466
1467     bool performedZoom = false;
1468     bool shouldZoom = !m_userPerformedManualZoom;
1469
1470     // If this load should restore view state, don't zoom to initial scale
1471     // but instead let the HistoryItem's saved viewport reign supreme.
1472     if (m_mainFrame && m_mainFrame->loader() && m_mainFrame->loader()->shouldRestoreScrollPositionAndViewState())
1473         shouldZoom = false;
1474
1475     if (shouldZoom && loadState() == Committed) {
1476         // Preserve at top and at left position, to avoid scrolling
1477         // to a non top-left position for web page with viewport meta tag
1478         // that specifies an initial-scale that is zoomed in.
1479         FloatPoint anchor = centerOfVisibleContentsRect();
1480         if (!scrollPosition().x())
1481             anchor.setX(0);
1482         if (!scrollPosition().y())
1483             anchor.setY(0);
1484         performedZoom = zoomAboutPoint(initialScale(), anchor);
1485     }
1486
1487     // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout...
1488     requestLayoutIfNeeded();
1489
1490     if (!performedZoom) {
1491         // We only notify if we didn't perform zoom, because zoom will notify on
1492         // its own...
1493         m_client->resetBitmapZoomScale(currentScale());
1494         notifyTransformedContentsSizeChanged();
1495     }
1496 }
1497
1498 double WebPagePrivate::zoomToFitScale() const
1499 {
1500     // We must clamp the contents for this calculation so that we do not allow an
1501     // arbitrarily small zoomToFitScale much like we clamp the fixedLayoutSize()
1502     // so that we do not have arbitrarily large layout size.
1503     // If we have a specified viewport, we may need to be able to zoom out more.
1504     int contentWidth = std::min(contentsSize().width(), std::max(m_virtualViewportWidth, static_cast<int>(defaultMaxLayoutSize().width())));
1505
1506     // defaultMaxLayoutSize().width() is a safeguard for excessively large page layouts that
1507     // is too restrictive for image documents. In this case, the document width is sufficient.
1508     Document* doc = m_page->mainFrame()->document();
1509     if (doc && doc->isImageDocument())
1510        contentWidth = contentsSize().width();
1511
1512     // If we have a virtual viewport and its aspect ratio caused content to layout
1513     // wider than the default layout aspect ratio we need to zoom to fit the content height
1514     // in order to avoid showing a grey area below the web page.
1515     // Without virtual viewport we can never get into this situation.
1516     if (hasVirtualViewport()) {
1517         int contentHeight = std::min(contentsSize().height(), std::max(m_virtualViewportHeight, static_cast<int>(defaultMaxLayoutSize().height())));
1518
1519         // Aspect ratio check without division.
1520         if (contentWidth * m_defaultLayoutSize.height() > contentHeight * m_defaultLayoutSize.width())
1521             return contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
1522     }
1523
1524     return contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
1525 }
1526
1527 double WebPage::zoomToFitScale() const
1528 {
1529     return d->zoomToFitScale();
1530 }
1531
1532 double WebPagePrivate::initialScale() const
1533 {
1534     if (m_initialScale > 0.0)
1535         return m_initialScale;
1536
1537     if (m_webSettings->isZoomToFitOnLoad())
1538         return zoomToFitScale();
1539
1540     return 1.0;
1541 }
1542
1543 double WebPage::initialScale() const
1544 {
1545     return d->initialScale();
1546 }
1547
1548 void WebPage::initializeIconDataBase()
1549 {
1550     IconDatabaseClientBlackBerry::getInstance()->initIconDatabase(d->m_webSettings);
1551 }
1552
1553 bool WebPage::isUserScalable() const
1554 {
1555     return d->isUserScalable();
1556 }
1557
1558 double WebPage::currentScale() const
1559 {
1560     return d->currentScale();
1561 }
1562
1563 void WebPage::setInitialScale(double initialScale)
1564 {
1565     d->setInitialScale(initialScale);
1566 }
1567
1568 double WebPage::minimumScale() const
1569 {
1570     return d->minimumScale();
1571 }
1572
1573 void WebPage::setMinimumScale(double minimumScale)
1574 {
1575     d->setMinimumScale(minimumScale);
1576 }
1577
1578 void WebPage::setMaximumScale(double maximumScale)
1579 {
1580     d->setMaximumScale(maximumScale);
1581 }
1582
1583 double WebPagePrivate::maximumScale() const
1584 {
1585     if (m_maximumScale >= zoomToFitScale() && m_maximumScale >= m_minimumScale)
1586         return m_maximumScale;
1587
1588     return hasVirtualViewport() ? std::max<double>(zoomToFitScale(), 4.0) : 4.0;
1589 }
1590
1591 double WebPage::maximumScale() const
1592 {
1593     return d->maximumScale();
1594 }
1595
1596 void WebPagePrivate::resetScales()
1597 {
1598     TransformationMatrix identity;
1599     *m_transformationMatrix = identity;
1600     m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0;
1601     m_minimumScale = -1.0;
1602     m_maximumScale = -1.0;
1603
1604     // We have to let WebCore know about updated framerect now that we've
1605     // reset our scales. See: RIM Bug #401.
1606     updateViewportSize();
1607 }
1608
1609 IntPoint WebPagePrivate::transformedScrollPosition() const
1610 {
1611     return m_backingStoreClient->transformedScrollPosition();
1612 }
1613
1614 // Returned scroll position is in transformed coordinates.
1615 Platform::IntPoint WebPage::scrollPosition() const
1616 {
1617     return d->transformedScrollPosition();
1618 }
1619
1620 IntPoint WebPagePrivate::transformedMaximumScrollPosition() const
1621 {
1622     return m_backingStoreClient->transformedMaximumScrollPosition();
1623 }
1624
1625 IntSize WebPagePrivate::transformedActualVisibleSize() const
1626 {
1627     return IntSize(m_actualVisibleWidth, m_actualVisibleHeight);
1628 }
1629
1630 Platform::IntSize WebPage::viewportSize() const
1631 {
1632     return d->transformedActualVisibleSize();
1633 }
1634
1635 IntSize WebPagePrivate::transformedViewportSize() const
1636 {
1637     return Platform::Graphics::Screen::primaryScreen()->size();
1638 }
1639
1640 IntRect WebPagePrivate::transformedVisibleContentsRect() const
1641 {
1642     // Usually this would be mapToTransformed(visibleContentsRect()), but
1643     // that results in rounding errors because we already set the WebCore
1644     // viewport size from our original transformedViewportSize().
1645     // Instead, we only transform the scroll position and take the
1646     // viewport size as it is, which ensures that e.g. blitting operations
1647     // always cover the whole widget/screen.
1648     return IntRect(transformedScrollPosition(), transformedViewportSize());
1649 }
1650
1651 IntSize WebPagePrivate::transformedContentsSize() const
1652 {
1653     // mapToTransformed() functions use this method to crop their results,
1654     // so we can't make use of them here. While we want rounding inside page
1655     // boundaries to extend rectangles and round points, we need to crop the
1656     // contents size to the floored values so that we don't try to display
1657     // or report points that are not fully covered by the actual float-point
1658     // contents rectangle.
1659     const IntSize untransformedContentsSize = contentsSize();
1660     const FloatPoint transformedBottomRight = m_transformationMatrix->mapPoint(
1661         FloatPoint(untransformedContentsSize.width(), untransformedContentsSize.height()));
1662     return IntSize(floorf(transformedBottomRight.x()), floorf(transformedBottomRight.y()));
1663 }
1664
1665 IntPoint WebPagePrivate::mapFromContentsToViewport(const IntPoint& point) const
1666 {
1667     return m_backingStoreClient->mapFromContentsToViewport(point);
1668 }
1669
1670 IntPoint WebPagePrivate::mapFromViewportToContents(const IntPoint& point) const
1671 {
1672     return m_backingStoreClient->mapFromViewportToContents(point);
1673 }
1674
1675 IntRect WebPagePrivate::mapFromContentsToViewport(const IntRect& rect) const
1676 {
1677     return m_backingStoreClient->mapFromContentsToViewport(rect);
1678 }
1679
1680 IntRect WebPagePrivate::mapFromViewportToContents(const IntRect& rect) const
1681 {
1682     return m_backingStoreClient->mapFromViewportToContents(rect);
1683 }
1684
1685 IntPoint WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntPoint& point) const
1686 {
1687     return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(point);
1688 }
1689
1690 IntPoint WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntPoint& point) const
1691 {
1692     return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(point);
1693 }
1694
1695 IntRect WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntRect& rect) const
1696 {
1697     return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(rect);
1698 }
1699
1700 IntRect WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntRect& rect) const
1701 {
1702     return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(rect);
1703 }
1704
1705 // NOTE: PIXEL ROUNDING!
1706 // Accurate back-and-forth rounding is not possible with information loss
1707 // by integer points and sizes, so we always expand the resulting mapped
1708 // float rectangles to the nearest integer. For points, we always use
1709 // floor-rounding in mapToTransformed() so that we don't have to crop to
1710 // the (floor'd) transformed contents size.
1711 static inline IntPoint roundTransformedPoint(const FloatPoint &point)
1712 {
1713     // Maps by rounding half towards zero.
1714     return IntPoint(static_cast<int>(floorf(point.x())), static_cast<int>(floorf(point.y())));
1715 }
1716
1717 static inline IntPoint roundUntransformedPoint(const FloatPoint &point)
1718 {
1719     // Maps by rounding half away from zero.
1720     return IntPoint(static_cast<int>(ceilf(point.x())), static_cast<int>(ceilf(point.y())));
1721 }
1722
1723 IntPoint WebPagePrivate::mapToTransformed(const IntPoint& point) const
1724 {
1725     return roundTransformedPoint(m_transformationMatrix->mapPoint(FloatPoint(point)));
1726 }
1727
1728 FloatPoint WebPagePrivate::mapToTransformedFloatPoint(const FloatPoint& point) const
1729 {
1730     return m_transformationMatrix->mapPoint(point);
1731 }
1732
1733 IntPoint WebPagePrivate::mapFromTransformed(const IntPoint& point) const
1734 {
1735     return roundUntransformedPoint(m_transformationMatrix->inverse().mapPoint(FloatPoint(point)));
1736 }
1737
1738 FloatPoint WebPagePrivate::mapFromTransformedFloatPoint(const FloatPoint& point) const
1739 {
1740     return m_transformationMatrix->inverse().mapPoint(point);
1741 }
1742
1743 FloatRect WebPagePrivate::mapFromTransformedFloatRect(const FloatRect& rect) const
1744 {
1745     return m_transformationMatrix->inverse().mapRect(rect);
1746 }
1747
1748 IntSize WebPagePrivate::mapToTransformed(const IntSize& size) const
1749 {
1750     return mapToTransformed(IntRect(IntPoint::zero(), size)).size();
1751 }
1752
1753 IntSize WebPagePrivate::mapFromTransformed(const IntSize& size) const
1754 {
1755     return mapFromTransformed(IntRect(IntPoint::zero(), size)).size();
1756 }
1757
1758 IntRect WebPagePrivate::mapToTransformed(const IntRect& rect) const
1759 {
1760     return enclosingIntRect(m_transformationMatrix->mapRect(FloatRect(rect)));
1761 }
1762
1763 // Use this in conjunction with mapToTransformed(IntRect), in most cases.
1764 void WebPagePrivate::clipToTransformedContentsRect(IntRect& rect) const
1765 {
1766     rect.intersect(IntRect(IntPoint::zero(), transformedContentsSize()));
1767 }
1768
1769 IntRect WebPagePrivate::mapFromTransformed(const IntRect& rect) const
1770 {
1771     return enclosingIntRect(m_transformationMatrix->inverse().mapRect(FloatRect(rect)));
1772 }
1773
1774 bool WebPagePrivate::transformedPointEqualsUntransformedPoint(const IntPoint& transformedPoint, const IntPoint& untransformedPoint)
1775 {
1776     // Scaling down is always more accurate than scaling up.
1777     if (m_transformationMatrix->a() > 1.0)
1778         return transformedPoint == mapToTransformed(untransformedPoint);
1779
1780     return mapFromTransformed(transformedPoint) == untransformedPoint;
1781 }
1782
1783 void WebPagePrivate::notifyTransformChanged()
1784 {
1785     notifyTransformedContentsSizeChanged();
1786     notifyTransformedScrollChanged();
1787
1788     m_backingStore->d->transformChanged();
1789 }
1790
1791 void WebPagePrivate::notifyTransformedContentsSizeChanged()
1792 {
1793     // We mark here as the last reported content size we sent to the client.
1794     m_previousContentsSize = contentsSize();
1795
1796     const IntSize size = transformedContentsSize();
1797     m_backingStore->d->contentsSizeChanged(size);
1798     m_client->contentsSizeChanged(size);
1799     m_selectionHandler->selectionPositionChanged();
1800 }
1801
1802 void WebPagePrivate::notifyTransformedScrollChanged()
1803 {
1804     const IntPoint pos = transformedScrollPosition();
1805     m_backingStore->d->scrollChanged(pos);
1806     m_client->scrollChanged(pos);
1807 }
1808
1809 bool WebPagePrivate::setViewMode(ViewMode mode)
1810 {
1811     if (!m_mainFrame->view())
1812         return false;
1813
1814     m_viewMode = mode;
1815
1816     // If we're in the middle of a nested layout with a recursion count above
1817     // some maximum threshold, then our algorithm for finding the minimum content
1818     // width of a given page has become dependent on the visible width.
1819     //
1820     // We need to find some method to ensure that we don't experience excessive
1821     // and even infinite recursion. This can even happen with valid html. The
1822     // former can happen when we run into inline text with few candidates for line
1823     // break. The latter can happen for instance if the page has a negative margin
1824     // set against the right border. Note: this is valid by spec and can lead to
1825     // a situation where there is no value for which the content width will ensure
1826     // no horizontal scrollbar.
1827     // Example: LayoutTests/css1/box_properties/margin.html
1828     //
1829     // In order to address such situations when we detect a recursion above some
1830     // maximum threshold we snap our fixed layout size to a defined quantum increment.
1831     // Eventually, either the content width will be satisfied to ensure no horizontal
1832     // scrollbar or this increment will run into the maximum layout size and the
1833     // recursion will necessarily end.
1834     bool snapToIncrement = didLayoutExceedMaximumIterations();
1835
1836     IntSize currentSize = m_mainFrame->view()->fixedLayoutSize();
1837     IntSize newSize = fixedLayoutSize(snapToIncrement);
1838     if (currentSize == newSize)
1839         return false;
1840
1841     // FIXME: Temp solution. We'll get back to this.
1842     if (m_nestedLayoutFinishedCount) {
1843         double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width());
1844         double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height());
1845         if (widthChange < 0.05 && heightChange < 0.05)
1846             return false;
1847     }
1848
1849     m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
1850     m_mainFrame->view()->setFixedLayoutSize(newSize);
1851     return true; // Needs re-layout!
1852 }
1853
1854 void WebPagePrivate::setCursor(PlatformCursor handle)
1855 {
1856     if (m_currentCursor.type() != handle.type()) {
1857         m_currentCursor = handle;
1858         m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot().x(), handle.hotspot().y());
1859     }
1860 }
1861
1862 Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory()
1863 {
1864     return m_client->networkStreamFactory();
1865 }
1866
1867 Platform::Graphics::Window* WebPagePrivate::platformWindow() const
1868 {
1869     return m_client->window();
1870 }
1871
1872 void WebPagePrivate::setPreventsScreenDimming(bool keepAwake)
1873 {
1874     if (keepAwake) {
1875         if (!m_preventIdleDimmingCount)
1876             m_client->setPreventsScreenIdleDimming(true);
1877         m_preventIdleDimmingCount++;
1878     } else if (m_preventIdleDimmingCount > 0) {
1879         m_preventIdleDimmingCount--;
1880         if (!m_preventIdleDimmingCount)
1881             m_client->setPreventsScreenIdleDimming(false);
1882     } else
1883         ASSERT_NOT_REACHED(); // SetPreventsScreenIdleDimming(false) called too many times.
1884 }
1885
1886 void WebPagePrivate::showVirtualKeyboard(bool showKeyboard)
1887 {
1888     m_client->showVirtualKeyboard(showKeyboard);
1889 }
1890
1891 void WebPagePrivate::ensureContentVisible(bool centerInView)
1892 {
1893     m_inputHandler->ensureFocusElementVisible(centerInView);
1894 }
1895
1896 void WebPagePrivate::zoomToContentRect(const IntRect& rect)
1897 {
1898     // Don't scale if the user is not supposed to scale.
1899     if (!isUserScalable())
1900         return;
1901
1902     FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y());
1903     IntSize viewSize = viewportSize();
1904
1905     // Calculate the scale required to scale that dimension to fit.
1906     double scaleH = (double)viewSize.width() / (double)rect.width();
1907     double scaleV = (double)viewSize.height() / (double)rect.height();
1908
1909     // Choose the smaller scale factor so that all of the content is visible.
1910     zoomAboutPoint(min(scaleH, scaleV), anchor);
1911 }
1912
1913 void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister)
1914 {
1915     if (shouldRegister)
1916         m_pluginViews.add(plugin);
1917     else
1918         m_pluginViews.remove(plugin);
1919 }
1920
1921 #define FOR_EACH_PLUGINVIEW(pluginViews) \
1922     HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \
1923     HashSet<PluginView*>::const_iterator last = pluginViews.end(); \
1924     for (; it != last; ++it)
1925
1926 void WebPagePrivate::notifyPageOnLoad()
1927 {
1928     FOR_EACH_PLUGINVIEW(m_pluginViews)
1929         (*it)->handleOnLoadEvent();
1930 }
1931
1932 bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
1933 {
1934     return m_client->shouldPluginEnterFullScreen();
1935 }
1936
1937 void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
1938 {
1939     m_fullScreenPluginView = plugin;
1940     m_client->didPluginEnterFullScreen();
1941
1942     if (!m_client->window())
1943         return;
1944
1945     Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix);
1946     m_client->window()->setSensitivityFullscreenOverride(true);
1947 }
1948
1949 void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* windowUniquePrefix)
1950 {
1951     m_fullScreenPluginView = 0;
1952     m_client->didPluginExitFullScreen();
1953
1954     if (!m_client->window())
1955         return;
1956
1957     Platform::Graphics::Window::setTransparencyDiscardFilter(0);
1958     m_client->window()->setSensitivityFullscreenOverride(false);
1959 }
1960
1961 void WebPagePrivate::onPluginStartBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
1962 {
1963     m_client->onPluginStartBackgroundPlay();
1964 }
1965
1966 void WebPagePrivate::onPluginStopBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
1967 {
1968     m_client->onPluginStopBackgroundPlay();
1969 }
1970
1971 bool WebPagePrivate::lockOrientation(bool landscape)
1972 {
1973     return m_client->lockOrientation(landscape);
1974 }
1975
1976 void WebPagePrivate::unlockOrientation()
1977 {
1978     return m_client->unlockOrientation();
1979 }
1980
1981 int WebPagePrivate::orientation() const
1982 {
1983 #if ENABLE(ORIENTATION_EVENTS)
1984     return m_mainFrame->orientation();
1985 #else
1986 #error ORIENTATION_EVENTS must be defined.
1987 // Or a copy of the orientation value will have to be stored in these objects.
1988 #endif
1989 }
1990
1991 double WebPagePrivate::currentZoomFactor() const
1992 {
1993     return currentScale();
1994 }
1995
1996 int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype)
1997 {
1998     return m_client->showAlertDialog(atype);
1999 }
2000
2001 bool WebPagePrivate::isActive() const
2002 {
2003     return m_client->isActive();
2004 }
2005
2006 bool WebPagePrivate::useFixedLayout() const
2007 {
2008     return true;
2009 }
2010
2011 ActiveNodeContext WebPagePrivate::activeNodeContext(TargetDetectionStrategy strategy)
2012 {
2013     ActiveNodeContext context;
2014
2015     RefPtr<Node> node = contextNode(strategy);
2016     m_currentContextNode = node;
2017     if (!m_currentContextNode)
2018         return context;
2019
2020     requestLayoutIfNeeded();
2021
2022     bool nodeAllowSelectionOverride = false;
2023     if (Node* linkNode = node->enclosingLinkEventParentOrSelf()) {
2024         KURL href;
2025         if (linkNode->isLink() && linkNode->hasAttributes()) {
2026             if (Attribute* attribute = linkNode->attributes()->getAttributeItem(HTMLNames::hrefAttr))
2027                 href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
2028         }
2029
2030         String pattern = findPatternStringForUrl(href);
2031         if (!pattern.isEmpty())
2032             context.setPattern(pattern);
2033
2034         if (!href.string().isEmpty()) {
2035             context.setUrl(href.string());
2036
2037             // Links are non-selectable by default, but selection should be allowed
2038             // providing the page is selectable, use the parent to determine it.
2039             if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
2040                 nodeAllowSelectionOverride = true;
2041         }
2042     }
2043
2044     if (!nodeAllowSelectionOverride && !node->canStartSelection())
2045         context.resetFlag(ActiveNodeContext::IsSelectable);
2046
2047     if (node->isHTMLElement()) {
2048         HTMLImageElement* imageElement = 0;
2049         if (node->hasTagName(HTMLNames::imgTag))
2050             imageElement = static_cast<HTMLImageElement*>(node.get());
2051         else if (node->hasTagName(HTMLNames::areaTag))
2052             imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement();
2053         if (imageElement && imageElement->renderer()) {
2054             // FIXME: At the mean time, we only show "Save Image" when the image data is available.
2055             if (CachedResource* cachedResource = imageElement->cachedImage()) {
2056                 if (cachedResource->isLoaded() && cachedResource->data()) {
2057                     String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
2058                     context.setImageSrc(node->document()->completeURL(url).string());
2059                 }
2060             }
2061             String alt = imageElement->altText();
2062             if (!alt.isNull())
2063                 context.setImageAlt(alt);
2064         }
2065     }
2066
2067     if (node->isTextNode()) {
2068         Text* curText = static_cast<Text*>(node.get());
2069         if (!curText->wholeText().isEmpty())
2070             context.setText(curText->wholeText());
2071     }
2072
2073     if (node->isElementNode()) {
2074         Element* element = static_cast<Element*>(node->shadowAncestorNode());
2075         if (DOMSupport::isTextBasedContentEditableElement(element)) {
2076             context.setFlag(ActiveNodeContext::IsInput);
2077             if (element->hasTagName(HTMLNames::inputTag))
2078                 context.setFlag(ActiveNodeContext::IsSingleLine);
2079             if (DOMSupport::isPasswordElement(element))
2080                 context.setFlag(ActiveNodeContext::IsPassword);
2081
2082             String elementText(DOMSupport::inputElementText(element));
2083             if (!elementText.stripWhiteSpace().isEmpty())
2084                 context.setText(elementText);
2085         }
2086     }
2087
2088     if (node->isFocusable())
2089         context.setFlag(ActiveNodeContext::IsFocusable);
2090
2091     return context;
2092 }
2093
2094 ActiveNodeContext WebPage::activeNodeContext(TargetDetectionStrategy strategy) const
2095 {
2096     return d->activeNodeContext(strategy);
2097 }
2098
2099 void WebPagePrivate::updateCursor()
2100 {
2101     int buttonMask = 0;
2102     if (m_lastMouseEvent.button() == LeftButton)
2103         buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
2104     else if (m_lastMouseEvent.button() == MiddleButton)
2105         buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
2106     else if (m_lastMouseEvent.button() == RightButton)
2107         buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
2108
2109     BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask, mapToTransformed(m_lastMouseEvent.position()), mapToTransformed(m_lastMouseEvent.globalPos()), 0, 0);
2110     m_webPage->mouseEvent(event);
2111 }
2112
2113 IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
2114 {
2115     if (hasVirtualViewport())
2116         return IntSize(m_virtualViewportWidth, m_virtualViewportHeight);
2117
2118     const int defaultLayoutWidth = m_defaultLayoutSize.width();
2119     const int defaultLayoutHeight = m_defaultLayoutSize.height();
2120
2121     int minWidth = defaultLayoutWidth;
2122     int maxWidth = defaultMaxLayoutSize().width();
2123     int maxHeight = defaultMaxLayoutSize().height();
2124
2125     // If the load state is none then we haven't actually got anything yet, but we need to layout
2126     // the entire page so that the user sees the entire page (unrendered) instead of just part of it.
2127     if (m_loadState == None)
2128         return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2129
2130     if (m_viewMode == FixedDesktop) {
2131         int width  = maxWidth;
2132         // if the defaultLayoutHeight is at minimum, it probably was set as 0
2133         // and clamped, meaning it's effectively not set.  (Even if it happened
2134         // to be set exactly to the minimum, it's too small to be useful.)  So
2135         // ignore it.
2136         int height;
2137         if (defaultLayoutHeight <= minimumLayoutSize.height())
2138             height = maxHeight;
2139         else
2140             height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2141         return IntSize(width, height);
2142     }
2143
2144     if (m_viewMode == Desktop) {
2145         // If we detect an overflow larger than the contents size then use that instead since
2146         // it'll still be clamped by the maxWidth below...
2147         int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
2148
2149         if (snapToIncrement) {
2150             // Snap to increments of defaultLayoutWidth / 2.0.
2151             float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
2152             factor = ceilf(factor);
2153             width = (defaultLayoutWidth / 2.0) * factor;
2154         }
2155
2156         if (width < minWidth)
2157             width = minWidth;
2158         if (width > maxWidth)
2159             width = maxWidth;
2160         int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2161         return IntSize(width, height);
2162     }
2163
2164     if (m_webSettings->isZoomToFitOnLoad()) {
2165         // We need to clamp the layout width to the minimum of the layout
2166         // width or the content width. This is important under rotation for mobile
2167         // websites. We want the page to remain layouted at the same width which
2168         // it was loaded with, and instead change the zoom level to fit to screen.
2169         // The height is welcome to adapt to the height used in the new orientation,
2170         // otherwise we will get a grey bar below the web page.
2171         if (m_mainFrame->view() && !contentsSize().isEmpty())
2172             minWidth = contentsSize().width();
2173         else {
2174             // If there is no contents width, use the minimum of screen width
2175             // and layout width to shape the first layout to a contents width
2176             // that we could reasonably zoom to fit, in a manner that takes
2177             // orientation into account and still respects a small default
2178             // layout width.
2179 #if ENABLE(ORIENTATION_EVENTS)
2180             minWidth = m_mainFrame->orientation() % 180
2181                 ? Platform::Graphics::Screen::primaryScreen()->height()
2182                 : Platform::Graphics::Screen::primaryScreen()->width();
2183 #else
2184             minWidth = Platform::Graphics::Screen::primaryScreen()->width();
2185 #endif
2186         }
2187     }
2188
2189     return IntSize(std::min(minWidth, defaultLayoutWidth), defaultLayoutHeight);
2190 }
2191
2192 BackingStoreClient* WebPagePrivate::backingStoreClientForFrame(const Frame* frame) const
2193 {
2194     ASSERT(frame);
2195     BackingStoreClient* backingStoreClient = 0;
2196     if (m_backingStoreClientForFrameMap.contains(frame))
2197         backingStoreClient = m_backingStoreClientForFrameMap.get(frame);
2198     return backingStoreClient;
2199 }
2200
2201 void WebPagePrivate::addBackingStoreClientForFrame(const Frame* frame, BackingStoreClient* client)
2202 {
2203     ASSERT(frame);
2204     ASSERT(client);
2205     m_backingStoreClientForFrameMap.add(frame, client);
2206 }
2207
2208 void WebPagePrivate::removeBackingStoreClientForFrame(const Frame* frame)
2209 {
2210     ASSERT(frame);
2211     if (m_backingStoreClientForFrameMap.contains(frame))
2212         m_backingStoreClientForFrameMap.remove(frame);
2213 }
2214
2215
2216 void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
2217 {
2218     ASSERT(documentGoingAway);
2219     if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
2220         m_currentContextNode = 0;
2221
2222     if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
2223         m_currentPinchZoomNode = 0;
2224
2225     if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
2226         m_currentBlockZoomAdjustedNode = 0;
2227
2228     if (m_inRegionScrollStartingNode && m_inRegionScrollStartingNode->document() == documentGoingAway)
2229         m_inRegionScrollStartingNode = 0;
2230
2231     Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
2232     if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
2233         m_touchEventHandler->resetLastFatFingersResult();
2234
2235     // NOTE: m_fullscreenVideoNode, m_fullScreenPluginView and m_pluginViews
2236     // are cleared in other methods already.
2237 }
2238
2239 typedef bool (*PredicateFunction)(RenderLayer*);
2240 static bool isPositionedContainer(RenderLayer* layer)
2241 {
2242     RenderObject* o = layer->renderer();
2243     return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform();
2244 }
2245
2246 static bool isNonRenderViewFixedPositionedContainer(RenderLayer* layer)
2247 {
2248     RenderObject* o = layer->renderer();
2249     if (o->isRenderView())
2250         return false;
2251
2252     return o->isPositioned() && o->style()->position() == FixedPosition;
2253 }
2254
2255 static bool isFixedPositionedContainer(RenderLayer* layer)
2256 {
2257     RenderObject* o = layer->renderer();
2258     return o->isRenderView() || (o->isPositioned() && o->style()->position() == FixedPosition);
2259 }
2260
2261 static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
2262 {
2263     RenderLayer* curr = layer;
2264     while (curr && !predicate(curr))
2265         curr = curr->parent();
2266
2267     return curr;
2268 }
2269
2270 RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
2271 {
2272     return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
2273 }
2274
2275 RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
2276 {
2277     return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
2278 }
2279
2280 static inline Frame* frameForNode(Node* node)
2281 {
2282     Node* origNode = node;
2283     for (; node; node = node->parentNode()) {
2284         if (RenderObject* renderer = node->renderer()) {
2285             if (renderer->isRenderView()) {
2286                 if (FrameView* view = toRenderView(renderer)->frameView()) {
2287                     if (Frame* frame = view->frame())
2288                         return frame;
2289                 }
2290             }
2291             if (renderer->isWidget()) {
2292                 Widget* widget = toRenderWidget(renderer)->widget();
2293                 if (widget && widget->isFrameView()) {
2294                     if (Frame* frame = static_cast<FrameView*>(widget)->frame())
2295                         return frame;
2296                 }
2297             }
2298         }
2299     }
2300
2301     for (node = origNode; node; node = node->parentNode()) {
2302         if (Document* doc = node->document()) {
2303             if (Frame* frame = doc->frame())
2304                 return frame;
2305         }
2306     }
2307
2308     return 0;
2309 }
2310
2311 static IntRect getNodeWindowRect(Node* node)
2312 {
2313     if (Frame* frame = frameForNode(node)) {
2314         if (FrameView* view = frame->view())
2315             return view->contentsToWindow(node->getRect());
2316     }
2317     ASSERT_NOT_REACHED();
2318     return IntRect();
2319 }
2320
2321 IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
2322 {
2323     ASSERT(m_mainFrame);
2324
2325     // Don't call this function asking to not clip the main frame providing only
2326     // the main frame. All that can be returned is the content rect which
2327     // isn't what this function is for.
2328     if (noClipOfMainFrame && view == m_mainFrame->view()) {
2329         ASSERT_NOT_REACHED();
2330         return IntRect(IntPoint::zero(), view->contentsSize());
2331     }
2332
2333     IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect(false)));
2334     if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
2335         // Intersect with parent visible rect.
2336         visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
2337     }
2338     return visibleWindowRect;
2339 }
2340
2341 void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
2342 {
2343     ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
2344     ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
2345     ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
2346
2347     // First we clear the focus, since we want to focus either initial or the last
2348     // focusable element in the webpage (according to the TABINDEX), or simply clear
2349     // the focus.
2350     clearFocusNode();
2351
2352     switch (direction) {
2353     case FocusDirectionForward:
2354     case FocusDirectionBackward:
2355         m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
2356         break;
2357     case FocusDirectionNone:
2358         break;
2359     default:
2360         ASSERT_NOT_REACHED();
2361     }
2362 }
2363
2364 void WebPage::assignFocus(Platform::FocusDirection direction)
2365 {
2366     d->assignFocus(direction);
2367 }
2368
2369 Platform::IntRect WebPagePrivate::focusNodeRect()
2370 {
2371     Frame* frame = focusedOrMainFrame();
2372     if (!frame)
2373         return Platform::IntRect();
2374
2375     Document* doc = frame->document();
2376     FrameView* view = frame->view();
2377     if (!doc || !view || view->needsLayout())
2378         return Platform::IntRect();
2379
2380     IntRect focusRect = rectForNode(doc->focusedNode());
2381     focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
2382     focusRect = mapToTransformed(focusRect);
2383     clipToTransformedContentsRect(focusRect);
2384     return focusRect;
2385 }
2386
2387 PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
2388 {
2389     EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2390     const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
2391     bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
2392
2393     // Unpress the mouse button always.
2394     if (eventHandler->mousePressed())
2395         eventHandler->setMousePressed(false);
2396
2397     // Check if we're using LinkToLink and the user is not touching the screen.
2398     if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
2399         RefPtr<Node> node;
2400         node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
2401         if (node) {
2402             IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
2403             if (!visibleRect.intersects(getNodeWindowRect(node.get())))
2404                 return 0;
2405         }
2406         return node.release();
2407     }
2408
2409     // Check for text input.
2410     if (isTouching && lastFatFingersResult.isTextInput())
2411         return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
2412
2413     IntPoint contentPos;
2414     if (isTouching)
2415         contentPos = lastFatFingersResult.adjustedPosition();
2416     else
2417         contentPos = mapFromViewportToContents(m_lastMouseEvent.position());
2418
2419     if (strategy == RectBased) {
2420         FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
2421         return result.node(FatFingersResult::ShadowContentNotAllowed);
2422     }
2423
2424     HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos, false /*allowShadowContent*/);
2425     return result.innerNode();
2426 }
2427
2428 static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
2429 {
2430     // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709).
2431     double dx = static_cast<double>(p1.x() - p2.x());
2432     double dy = static_cast<double>(p1.y() - p2.y());
2433     return sqrt((dx * dx) + (dy * dy));
2434 }
2435
2436 Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& point)
2437 {
2438     IntPoint pt = mapFromTransformed(point);
2439     IntRect clickRect(pt.x() - blockClickRadius, pt.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
2440     Node* originalNode = nodeForZoomUnderPoint(point);
2441     if (!originalNode)
2442         return 0;
2443     Node* node = bestChildNodeForClickRect(originalNode, clickRect);
2444     return node ? adjustedBlockZoomNodeForZoomLimits(node) : adjustedBlockZoomNodeForZoomLimits(originalNode);
2445 }
2446
2447 Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
2448 {
2449     if (!parentNode)
2450         return 0;
2451
2452     int bestDistance = std::numeric_limits<int>::max();
2453
2454     Node* node = parentNode->firstChild();
2455     Node* bestNode = 0;
2456     for (; node; node = node->nextSibling()) {
2457         IntRect rect = rectForNode(node);
2458         if (!clickRect.intersects(rect))
2459             continue;
2460
2461         int distance = distanceBetweenPoints(rect.center(), clickRect.center());
2462         Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
2463         if (bestChildNode) {
2464             IntRect bestChildRect = rectForNode(bestChildNode);
2465             int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
2466             if (bestChildDistance < distance && bestChildDistance < bestDistance) {
2467                 bestNode = bestChildNode;
2468                 bestDistance = bestChildDistance;
2469             } else {
2470                 if (distance < bestDistance) {
2471                     bestNode = node;
2472                     bestDistance = distance;
2473                 }
2474             }
2475         } else {
2476             if (distance < bestDistance) {
2477                 bestNode = node;
2478                 bestDistance = distance;
2479             }
2480         }
2481     }
2482
2483     return bestNode;
2484 }
2485
2486 double WebPagePrivate::maxBlockZoomScale() const
2487 {
2488     return std::min(maximumBlockZoomScale, maximumScale());
2489 }
2490
2491 Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& point)
2492 {
2493     if (!m_mainFrame)
2494         return 0;
2495
2496     HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromTransformed(point), false);
2497
2498     Node* node = result.innerNonSharedNode();
2499
2500     if (!node)
2501         return 0;
2502
2503     RenderObject* renderer = node->renderer();
2504     while (!renderer) {
2505         node = node->parentNode();
2506         renderer = node->renderer();
2507     }
2508
2509     return node;
2510 }
2511
2512 Node* WebPagePrivate::adjustedBlockZoomNodeForZoomLimits(Node* node)
2513 {
2514     Node* initialNode = node;
2515     RenderObject* renderer = node->renderer();
2516     bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2517
2518     while (!renderer || !acceptableNodeSize) {
2519         node = node->parentNode();
2520
2521         if (!node)
2522             return initialNode;
2523
2524         renderer = node->renderer();
2525         acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2526     }
2527
2528     return node;
2529 }
2530
2531 bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
2532 {
2533     if (!n1 || !n2)
2534         return false;
2535
2536     return (n2 == n1) || n2->isDescendantOf(n1);
2537 }
2538
2539 double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
2540 {
2541     if (rect.isEmpty())
2542         return std::numeric_limits<double>::max();
2543
2544     ASSERT(rect.width() + margin);
2545
2546     double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
2547
2548     return newScale;
2549 }
2550
2551 IntRect WebPagePrivate::rectForNode(Node* node)
2552 {
2553     if (!node)
2554         return IntRect();
2555
2556     RenderObject* renderer = node->renderer();
2557
2558     if (!renderer)
2559         return IntRect();
2560
2561     // Return rect in un-transformed content coordinates.
2562     IntRect blockRect;
2563
2564     // FIXME: Ensure this works with iframes.
2565     if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
2566         RenderBlock* renderBlock = renderer->containingBlock();
2567         int xOffset = 0;
2568         int yOffset = 0;
2569         while (!renderBlock->isRoot()) {
2570             xOffset += renderBlock->x();
2571             yOffset += renderBlock->y();
2572             renderBlock = renderBlock->containingBlock();
2573         }
2574         const RenderText* renderText = toRenderText(renderer);
2575         IntRect linesBox = renderText->linesBoundingBox();
2576         blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height());
2577     } else
2578         blockRect = renderer->absoluteClippedOverflowRect();
2579
2580     if (renderer->isText()) {
2581         RenderBlock* rb = renderer->containingBlock();
2582
2583         // Inefficient? Way to find width when floats intersect a block.
2584         int blockWidth = 0;
2585         int lineCount = rb->lineCount();
2586         for (int i = 0; i < lineCount; i++)
2587             blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false));
2588
2589         blockRect.setWidth(blockWidth);
2590         blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
2591     }
2592
2593     // Strip off padding.
2594     if (renderer->style()->hasPadding()) {
2595         blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
2596         blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
2597         blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
2598         blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
2599     }
2600
2601     return blockRect;
2602 }
2603
2604 IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
2605 {
2606     ASSERT(frame);
2607
2608     // FIXME: This function can be called when page is being destroyed and JS triggers selection change.
2609     // We could break the call chain at upper levels, but I think it is better to check the frame pointer
2610     // here because the pointer is explicitly cleared in WebPage::destroy().
2611     if (!mainFrame())
2612         return IntPoint();
2613
2614     // Convert 0,0 in the frame's coordinate system to window coordinates to
2615     // get the frame's global position, and return this position in the main
2616     // frame's coordinates.  (So the main frame's coordinates will be 0,0.)
2617     return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
2618 }
2619
2620 IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
2621 {
2622     if (!node)
2623         return rect;
2624
2625     // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames.
2626     // FIXME: can we just use frameOffset instead of this big routine?
2627     const Node* tnode = node;
2628     IntRect adjustedRect = rect;
2629     do {
2630         Frame* frame = tnode->document()->frame();
2631         if (!frame)
2632             continue;
2633
2634         Node* ownerNode = static_cast<Node*>(frame->ownerElement());
2635         tnode = ownerNode;
2636         if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
2637             IntRect iFrameRect;
2638             do {
2639                 iFrameRect = rectForNode(ownerNode);
2640                 adjustedRect.move(iFrameRect.x(), iFrameRect.y());
2641                 adjustedRect.intersect(iFrameRect);
2642                 ownerNode = ownerNode->parentNode();
2643             } while (iFrameRect.isEmpty() && ownerNode);
2644         } else
2645             break;
2646     } while (tnode = tnode->parentNode());
2647
2648     return adjustedRect;
2649 }
2650
2651 IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
2652 {
2653     if (!node || contentsSize().isEmpty())
2654         return IntRect();
2655
2656     Node* tnode = node;
2657     m_currentBlockZoomAdjustedNode = tnode;
2658
2659     IntRect blockRect = rectForNode(tnode);
2660     IntRect originalRect = blockRect;
2661
2662     int originalArea = originalRect.width() * originalRect.height();
2663     int pageArea = contentsSize().width() * contentsSize().height();
2664     double blockToPageRatio = static_cast<double>(1 - originalArea / pageArea);
2665     double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
2666
2667     if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
2668         while (tnode = tnode->parentNode()) {
2669             ASSERT(tnode);
2670             IntRect tRect = rectForNode(tnode);
2671             int tempBlockArea = tRect.width() * tRect.height();
2672             // Don't expand the block if it will be too large relative to the content.
2673             if (static_cast<double>(1 - tempBlockArea / pageArea) < minimumExpandingRatio)
2674                 break;
2675             if (tRect.isEmpty())
2676                 continue; // No renderer.
2677             if (tempBlockArea < 1.1 * originalArea)
2678                 continue; // The size of this parent is very close to the child, no need to go to this parent.
2679             // Don't expand the block if the parent node size is already almost the size of actual visible size.
2680             IntSize actualSize = actualVisibleSize();
2681             if (static_cast<double>(1 - tRect.width() / actualSize.width()) < minimumExpandingRatio)
2682                 break;
2683             if (tempBlockArea < blockExpansionRatio * originalArea) {
2684                 blockRect = tRect;
2685                 m_currentBlockZoomAdjustedNode = tnode;
2686             } else
2687                 break;
2688         }
2689     }
2690
2691     blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
2692     blockRect = mapToTransformed(blockRect);
2693     clipToTransformedContentsRect(blockRect);
2694
2695 #if DEBUG_BLOCK_ZOOM
2696     // Re-paint the backingstore to screen to erase other annotations.
2697     m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::Blit);
2698
2699     // Render a black square over the calculated block and a gray square over the original block for visual inspection.
2700     originalRect = mapToTransformed(originalRect);
2701     clipToTransformedContentsRect(originalRect);
2702     IntRect renderRect = mapFromTransformedContentsToTransformedViewport(blockRect);
2703     IntRect originalRenderRect = mapFromTransformedContentsToTransformedViewport(originalRect);
2704     IntSize viewportSize = transformedViewportSize();
2705     renderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
2706     originalRenderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
2707     m_backingStore->d->clearWindow(renderRect, 0, 0, 0);
2708     m_backingStore->d->clearWindow(originalRenderRect, 120, 120, 120);
2709     m_backingStore->d->invalidateWindow(renderRect);
2710 #endif
2711
2712     return blockRect;
2713 }
2714
2715 // This function should not be called directly.
2716 // It is called after the animation ends (see above).
2717 void WebPagePrivate::zoomBlock()
2718 {
2719     if (!m_mainFrame)
2720         return;
2721
2722     IntPoint anchor(roundUntransformedPoint(mapFromTransformedFloatPoint(m_finalBlockPoint)));
2723     bool willUseTextReflow = false;
2724
2725 #if ENABLE(VIEWPORT_REFLOW)
2726     willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
2727     toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
2728     setNeedsLayout();
2729 #endif
2730
2731     TransformationMatrix zoom;
2732     zoom.scale(m_blockZoomFinalScale);
2733     *m_transformationMatrix = zoom;
2734     m_client->resetBitmapZoomScale(m_blockZoomFinalScale);
2735     m_backingStore->d->suspendScreenAndBackingStoreUpdates();
2736     updateViewportSize();
2737
2738 #if ENABLE(VIEWPORT_REFLOW)
2739     requestLayoutIfNeeded();
2740     if (willUseTextReflow && m_shouldReflowBlock) {
2741         IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
2742         reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
2743         reflowedRect.move(roundTransformedPoint(m_finalBlockPointReflowOffset).x(), roundTransformedPoint(m_finalBlockPointReflowOffset).y());
2744         RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
2745         IntPoint topLeftPoint(reflowedRect.location());
2746         if (renderer && renderer->isText()) {
2747             ETextAlign textAlign = renderer->style()->textAlign();
2748             IntPoint textAnchor;
2749             switch (textAlign) {
2750             case CENTER:
2751             case WEBKIT_CENTER:
2752                 textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
2753                 break;
2754             case LEFT:
2755             case WEBKIT_LEFT:
2756                 textAnchor = topLeftPoint;
2757                 break;
2758             case RIGHT:
2759             case WEBKIT_RIGHT:
2760                 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
2761                 break;
2762             case TAAUTO:
2763             case JUSTIFY:
2764             default:
2765                 if (renderer->style()->isLeftToRightDirection())
2766                     textAnchor = topLeftPoint;
2767                 else
2768                     textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
2769                 break;
2770             }
2771             setScrollPosition(textAnchor);
2772         } else {
2773             renderer->style()->isLeftToRightDirection()
2774                 ? setScrollPosition(topLeftPoint)
2775                 : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
2776         }
2777     } else if (willUseTextReflow) {
2778         IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
2779         finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
2780         setScrollPosition(IntPoint(0, finalRect.y() + m_finalBlockPointReflowOffset.y()));
2781         resetBlockZoom();
2782     }
2783 #endif
2784     if (!willUseTextReflow) {
2785         setScrollPosition(anchor);
2786         if (!m_shouldReflowBlock)
2787             resetBlockZoom();
2788     }
2789
2790     notifyTransformChanged();
2791     m_backingStore->d->clearWindow();
2792     m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
2793     m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
2794 }
2795
2796 void WebPage::blockZoomAnimationFinished()
2797 {
2798     d->zoomBlock();
2799 }
2800
2801 void WebPagePrivate::resetBlockZoom()
2802 {
2803     m_currentBlockZoomNode = 0;
2804     m_currentBlockZoomAdjustedNode = 0;
2805     m_shouldReflowBlock = false;
2806 }
2807
2808 void WebPage::destroyWebPageCompositor()
2809 {
2810 #if USE(ACCELERATED_COMPOSITING)
2811     // Destroy the layer renderer in a sync command before we destroy the backing store,
2812     // to flush any pending compositing messages on the compositing thread.
2813     // The backing store is indirectly deleted by the 'detachFromParent' call below.
2814     d->syncDestroyCompositorOnCompositingThread();
2815 #endif
2816 }
2817
2818 void WebPage::destroy()
2819 {
2820     // TODO: need to verify if this call needs to be made before calling
2821     // WebPage::destroyWebPageCompositor()
2822     d->m_backingStore->d->suspendScreenAndBackingStoreUpdates();
2823
2824     // Close the backforward list and release the cached pages.
2825     d->m_page->backForward()->close();
2826     pageCache()->releaseAutoreleasedPagesNow();
2827
2828     FrameLoader* loader = d->m_mainFrame->loader();
2829
2830     // Remove main frame's backing store client from the map
2831     // to prevent FrameLoaderClientBlackyBerry::detachFromParent2(),
2832     // which is called by loader->detachFromParent(), deleting it.
2833     // We will delete it in ~WebPagePrivate().
2834     // Reason: loader->detachFromParent() may ping back to backing store
2835     // indirectly through ChromeClientBlackBerry::invalidateContentsAndWindow().
2836     // see RIM PR #93256.
2837     d->removeBackingStoreClientForFrame(d->m_mainFrame);
2838
2839     // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion.
2840     d->m_mainFrame = 0;
2841     if (loader)
2842         loader->detachFromParent();
2843
2844     delete this;
2845 }
2846
2847 WebPageClient* WebPage::client() const
2848 {
2849     return d->m_client;
2850 }
2851
2852 int WebPage::backForwardListLength() const
2853 {
2854     return d->m_page->getHistoryLength();
2855 }
2856
2857 bool WebPage::canGoBackOrForward(int delta) const
2858 {
2859     return d->m_page->canGoBackOrForward(delta);
2860 }
2861
2862 bool WebPage::goBackOrForward(int delta)
2863 {
2864     if (d->m_page->canGoBackOrForward(delta)) {
2865         d->m_page->goBackOrForward(delta);
2866         return true;
2867     }
2868     return false;
2869 }
2870
2871 void WebPage::goToBackForwardEntry(BackForwardId id)
2872 {
2873     HistoryItem* item = historyItemFromBackForwardId(id);
2874     ASSERT(item);
2875     d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
2876 }
2877
2878 void WebPage::reload()
2879 {
2880     d->m_mainFrame->loader()->reload(/* bypassCache */ true);
2881 }
2882
2883 void WebPage::reloadFromCache()
2884 {
2885     d->m_mainFrame->loader()->reload(/* bypassCache */ false);
2886 }
2887
2888 WebSettings* WebPage::settings() const
2889 {
2890     return d->m_webSettings;
2891 }
2892
2893 bool WebPage::isVisible() const
2894 {
2895     return d->m_visible;
2896 }
2897
2898 #if ENABLE(PAGE_VISIBILITY_API)
2899 void WebPagePrivate::setPageVisibilityState()
2900 {
2901     static bool s_initialVisibilityState = true;
2902
2903     m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
2904     s_initialVisibilityState = false;
2905 }
2906 #endif
2907
2908 void WebPagePrivate::setVisible(bool visible)
2909 {
2910     m_visible = visible;
2911
2912 #if ENABLE(PAGE_VISIBILITY_API)
2913     setPageVisibilityState();
2914 #endif
2915 }
2916
2917 void WebPage::setVisible(bool visible)
2918 {
2919     if (d->m_visible == visible)
2920         return;
2921
2922     d->setVisible(visible);
2923
2924     if (!visible) {
2925         d->suspendBackingStore();
2926
2927         // Remove this WebPage from the visible pages list.
2928         size_t foundIndex = visibleWebPages()->find(this);
2929         if (foundIndex != WTF::notFound)
2930             visibleWebPages()->remove(foundIndex);
2931
2932         // Return the backing store to the last visible WebPage.
2933         if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
2934             visibleWebPages()->last()->d->resumeBackingStore();
2935
2936 #if USE(ACCELERATED_COMPOSITING)
2937         // Root layer commit is not necessary for invisible tabs.
2938         // And release layer resources can reduce memory consumption.
2939         d->suspendRootLayerCommit();
2940 #endif
2941         return;
2942     }
2943
2944 #if USE(ACCELERATED_COMPOSITING)
2945     d->resumeRootLayerCommit();
2946 #endif
2947
2948     // Push this WebPage to the top of the visible pages list.
2949     if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
2950         size_t foundIndex = visibleWebPages()->find(this);
2951         if (foundIndex != WTF::notFound)
2952             visibleWebPages()->remove(foundIndex);
2953     }
2954     visibleWebPages()->append(this);
2955
2956     if (BackingStorePrivate::currentBackingStoreOwner()
2957         && BackingStorePrivate::currentBackingStoreOwner() != this)
2958         BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
2959
2960     // resumeBackingStore will set the current owner to this webpage.
2961     // If we set the owner prematurely, then the tiles will not be reset.
2962     d->resumeBackingStore();
2963 }
2964
2965 void WebPagePrivate::selectionChanged(Frame* frame)
2966 {
2967     m_inputHandler->selectionChanged();
2968
2969     // FIXME: This is a hack!
2970     // To ensure the selection being changed has its frame 'focused', lets
2971     // set it as focused ourselves (PR #104724).
2972     m_page->focusController()->setFocusedFrame(frame);
2973 }
2974
2975 void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
2976 {
2977     // Track a dispatched message, we don't want to flood the webkit thread.
2978     // There can be as many as one more message enqued as needed but never less.
2979     if (dispatched)
2980         m_updateDelegatedOverlaysDispatched = false;
2981     else if (m_updateDelegatedOverlaysDispatched) {
2982         // Early return if there is message already pending on the webkit thread.
2983         return;
2984     }
2985
2986     if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
2987         // Must be called on the WebKit thread.
2988         if (m_selectionHandler->isSelectionActive())
2989             m_selectionHandler->selectionPositionChanged(true /* visualChangeOnly */);
2990
2991     } else if (m_selectionHandler->isSelectionActive()) {
2992         // Don't bother dispatching to webkit thread if selection and tap highlight are not active.
2993         m_updateDelegatedOverlaysDispatched = true;
2994         Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/));
2995     }
2996 }
2997
2998 void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle style)
2999 {
3000 }
3001
3002 bool WebPage::setBatchEditingActive(bool active)
3003 {
3004     return d->m_inputHandler->setBatchEditingActive(active);
3005 }
3006
3007 bool WebPage::setInputSelection(unsigned start, unsigned end)
3008 {
3009     return d->m_inputHandler->setSelection(start, end);
3010 }
3011
3012 int WebPage::inputCaretPosition() const
3013 {
3014     return d->m_inputHandler->caretPosition();
3015 }
3016
3017 void WebPage::popupListClosed(int size, bool* selecteds)
3018 {
3019     d->m_inputHandler->setPopupListIndexes(size, selecteds);
3020 }
3021
3022 void WebPage::popupListClosed(int index)
3023 {
3024     d->m_inputHandler->setPopupListIndex(index);
3025 }
3026
3027 void WebPage::setDateTimeInput(const WebString& value)
3028 {
3029     d->m_inputHandler->setInputValue(String(value.impl()));
3030 }
3031
3032 void WebPage::setColorInput(const WebString& value)
3033 {
3034     d->m_inputHandler->setInputValue(String(value.impl()));
3035 }
3036
3037 void WebPage::setVirtualViewportSize(int width, int height)
3038 {
3039     d->m_virtualViewportWidth = width;
3040     d->m_virtualViewportHeight = height;
3041 }
3042
3043 void WebPage::resetVirtualViewportOnCommitted(bool reset)
3044 {
3045     d->m_resetVirtualViewportOnCommitted = reset;
3046 }
3047
3048 IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments()
3049 {
3050     static ViewportArguments defaultViewportArguments;
3051     if (m_viewportArguments == defaultViewportArguments)
3052         return IntSize();
3053
3054     int desktopWidth = defaultMaxLayoutSize().width();
3055     int deviceWidth = Platform::Graphics::Screen::primaryScreen()->width();
3056     int deviceHeight = Platform::Graphics::Screen::primaryScreen()->height();
3057     FloatSize currentPPI = Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(-1);
3058     int deviceDPI = int(roundf((currentPPI.width() + currentPPI.height()) / 2));
3059     if (m_viewportArguments.targetDensityDpi == ViewportArguments::ValueAuto) {
3060         // Auto means 160dpi if we leave it alone. This looks terrible for pages wanting 1:1.
3061         // FIXME: This is insufficient for devices with high dpi, as they will render content unreadably small.
3062         m_viewportArguments.targetDensityDpi = deviceDPI;
3063     }
3064
3065     ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, deviceDPI, m_defaultLayoutSize);
3066     m_page->setDeviceScaleFactor(result.devicePixelRatio);
3067     return IntSize(result.layoutSize.width(), result.layoutSize.height());
3068 }
3069
3070 #if ENABLE(EVENT_MODE_METATAGS)
3071 void WebPagePrivate::didReceiveCursorEventMode(CursorEventMode mode)
3072 {
3073     if (mode != m_cursorEventMode)
3074         m_client->cursorEventModeChanged(toPlatformCursorEventMode(mode));
3075     m_cursorEventMode = mode;
3076 }
3077
3078 void WebPagePrivate::didReceiveTouchEventMode(TouchEventMode mode)
3079 {
3080     if (mode != m_touchEventMode)
3081         m_client->touchEventModeChanged(toPlatformTouchEventMode(mode));
3082     m_touchEventMode = mode;
3083 }
3084 #endif
3085
3086 void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments)
3087 {
3088     static ViewportArguments defaultViewportArguments;
3089     if (arguments == defaultViewportArguments)
3090         return;
3091
3092     m_viewportArguments = arguments;
3093
3094     // 0 width or height in viewport arguments makes no sense, and results in a very large initial scale.
3095     // In real world, a 0 width or height is usually caused by a syntax error in "content" field of viewport
3096     // meta tag, for example, using semicolon instead of comma as separator ("width=device-width; initial-scale=1.0").
3097     // We don't have a plan to tolerate the semicolon separator, but we can avoid applying 0 width/height.
3098     // I default it to ValueDeviceWidth rather than ValueAuto because in more cases the web site wants "device-width"
3099     // when they specify the viewport width.
3100     if (!m_viewportArguments.width)
3101         m_viewportArguments.width = ViewportArguments::ValueDeviceWidth;
3102     if (!m_viewportArguments.height)
3103         m_viewportArguments.height = ViewportArguments::ValueDeviceHeight;
3104
3105     setUserScalable(arguments.userScalable == ViewportArguments::ValueAuto ? true : arguments.userScalable);
3106     if (arguments.initialScale > 0)
3107         setInitialScale(arguments.initialScale);
3108     if (arguments.minimumScale > 0)
3109         setMinimumScale(arguments.minimumScale);
3110     if (arguments.maximumScale > 0)
3111         setMaximumScale(arguments.maximumScale);
3112
3113     IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
3114     m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
3115
3116     if (loadState() == WebKit::WebPagePrivate::Committed)
3117         zoomToInitialScaleOnLoad();
3118 }
3119
3120 void WebPagePrivate::onInputLocaleChanged(bool isRTL)
3121 {
3122     if (isRTL != m_webSettings->isWritingDirectionRTL()) {
3123         m_webSettings->setWritingDirectionRTL(isRTL);
3124         m_inputHandler->handleInputLocaleChanged(isRTL);
3125     }
3126 }
3127
3128 void WebPage::onInputLocaleChanged(bool isRTL)
3129 {
3130     d->onInputLocaleChanged(isRTL);
3131 }
3132
3133 void WebPagePrivate::suspendBackingStore()
3134 {
3135 #if USE(ACCELERATED_COMPOSITING)
3136     resetCompositingSurface();
3137 #endif
3138 }
3139
3140 void WebPagePrivate::resumeBackingStore()
3141 {
3142     ASSERT(m_webPage->isVisible());
3143
3144 #if USE(ACCELERATED_COMPOSITING)
3145     setNeedsOneShotDrawingSynchronization();
3146 #endif
3147
3148     bool directRendering = m_backingStore->d->shouldDirectRenderingToWindow();
3149     if (!m_backingStore->d->isActive()
3150         || shouldResetTilesWhenShown()
3151         || directRendering) {
3152         // We need to reset all tiles so that we do not show any tiles whose content may
3153         // have been replaced by another WebPage instance (i.e. another tab).
3154         BackingStorePrivate::setCurrentBackingStoreOwner(m_webPage);
3155         m_backingStore->d->orientationChanged(); // Updates tile geometry and creates visible tile buffer.
3156         m_backingStore->d->resetTiles(true /* resetBackground */);
3157         m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
3158         // This value may have changed, so we need to update it.
3159         directRendering = m_backingStore->d->shouldDirectRenderingToWindow();
3160         if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !directRendering)
3161             m_backingStore->d->blitVisibleContents();
3162     } else {
3163         // Rendering was disabled while we were hidden, so we need to update all tiles.
3164         m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
3165     }
3166
3167     setShouldResetTilesWhenShown(false);
3168 }
3169
3170 void WebPagePrivate::setScreenOrientation(int orientation)
3171 {
3172     FOR_EACH_PLUGINVIEW(m_pluginViews)
3173         (*it)->handleOrientationEvent(orientation);
3174
3175     m_pendingOrientation = -1;
3176
3177 #if ENABLE(ORIENTATION_EVENTS)
3178     if (m_mainFrame->orientation() == orientation)
3179         return;
3180     for (RefPtr<Frame> frame = m_mainFrame; frame; frame = frame->tree()->traverseNext())
3181         frame->sendOrientationChangeEvent(orientation);
3182 #endif
3183 }
3184
3185 void WebPage::setScreenOrientation(int orientation)
3186 {
3187     d->m_pendingOrientation = orientation;
3188 }
3189
3190 void WebPage::applyPendingOrientationIfNeeded()
3191 {
3192     if (d->m_pendingOrientation != -1)
3193         d->setScreenOrientation(d->m_pendingOrientation);
3194 }
3195
3196 void WebPagePrivate::screenRotated()
3197 {
3198     // This call will cause the client to reallocate the window buffer to new size,
3199     // which needs to be serialized with usage of the window buffer. Accomplish
3200     // this by sending a sync message to the compositing thread. All other usage of
3201     // the window buffer happens on the compositing thread.
3202     if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
3203         Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
3204             Platform::createMethodCallMessage(&WebPagePrivate::screenRotated, this));
3205         return;
3206     }
3207
3208     SurfacePool::globalSurfacePool()->notifyScreenRotated();
3209     m_client->notifyScreenRotated();
3210 }
3211
3212 void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize, bool ensureFocusElementVisible)
3213 {
3214     if (m_pendingOrientation == -1 && transformedActualVisibleSize == this->transformedActualVisibleSize())
3215         return;
3216
3217     // Suspend all screen updates to the backingstore to make sure no-one tries to blit
3218     // while the window surface and the BackingStore are out of sync.
3219     m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3220
3221     // The screen rotation is a major state transition that in this case is not properly
3222     // communicated to the backing store, since it does early return in most methods when
3223     // not visible.
3224     if (!m_visible || !m_backingStore->d->isActive())
3225         setShouldResetTilesWhenShown(true);
3226
3227     bool hasPendingOrientation = m_pendingOrientation != -1;
3228     if (hasPendingOrientation)
3229         screenRotated();
3230
3231     // The window buffers might have been recreated, cleared, moved, etc., so:
3232     m_backingStore->d->windowFrontBufferState()->clearBlittedRegion();
3233     m_backingStore->d->windowBackBufferState()->clearBlittedRegion();
3234
3235     IntSize viewportSizeBefore = actualVisibleSize();
3236     FloatPoint centerOfVisibleContentsRect = this->centerOfVisibleContentsRect();
3237     bool newVisibleRectContainsOldVisibleRect = (m_actualVisibleHeight <= transformedActualVisibleSize.height())
3238                                           && (m_actualVisibleWidth <= transformedActualVisibleSize.width());
3239
3240     bool atInitialScale = m_webPage->isAtInitialZoom();
3241     bool atTop = !scrollPosition().y();
3242     bool atLeft = !scrollPosition().x();
3243
3244     // We need to reorient the visibleTileRect because the following code
3245     // could cause BackingStore::transformChanged to be called, where it
3246     // is used.
3247     // It is only dependent on the transformedViewportSize which has been
3248     // updated by now.
3249     m_backingStore->d->createVisibleTileBuffer();
3250
3251     setDefaultLayoutSize(transformedActualVisibleSize);
3252
3253     // Recompute our virtual viewport.
3254     bool needsLayout = false;
3255     static ViewportArguments defaultViewportArguments;
3256     if (!(m_viewportArguments == defaultViewportArguments)) {
3257         // We may need to infer the width and height for the viewport with respect to the rotation.
3258         IntSize newVirtualViewport = recomputeVirtualViewportFromViewportArguments();
3259         ASSERT(!newVirtualViewport.isEmpty());
3260         m_webPage->setVirtualViewportSize(newVirtualViewport.width(), newVirtualViewport.height());
3261         m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
3262         m_mainFrame->view()->setFixedLayoutSize(fixedLayoutSize());
3263         needsLayout = true;
3264     }
3265
3266     // We switch this strictly after recomputing our virtual viewport as zoomToFitScale is dependent
3267     // upon these values and so is the virtual viewport recalculation.
3268     m_actualVisibleWidth = transformedActualVisibleSize.width();
3269     m_actualVisibleHeight = transformedActualVisibleSize.height();
3270
3271     IntSize viewportSizeAfter = actualVisibleSize();
3272
3273     IntPoint offset(roundf((viewportSizeBefore.width() - viewportSizeAfter.width()) / 2.0),
3274                     roundf((viewportSizeBefore.height() - viewportSizeAfter.height()) / 2.0));
3275
3276     // As a special case, if we were anchored to the top left position at
3277     // the beginning of the rotation then preserve that anchor.
3278     if (atTop)
3279         offset.setY(0);
3280     if (atLeft)
3281         offset.setX(0);
3282
3283     // If we're about to overscroll, cap the offset to valid content.
3284     IntPoint bottomRight(
3285         scrollPosition().x() + viewportSizeAfter.width(),
3286         scrollPosition().y() + viewportSizeAfter.height());
3287
3288     if (bottomRight.x() + offset.x() > contentsSize().width())
3289         offset.setX(contentsSize().width() - bottomRight.x());
3290     if (bottomRight.y() + offset.y() > contentsSize().height())
3291         offset.setY(contentsSize().height() - bottomRight.y());
3292     if (scrollPosition().x() + offset.x() < 0)
3293         offset.setX(-scrollPosition().x());
3294     if (scrollPosition().y() + offset.y() < 0)
3295         offset.setY(-scrollPosition().y());
3296
3297     // ...before scrolling, because the backing store will align its
3298     // tile matrix with the viewport as reported by the ScrollView.
3299     scrollBy(offset.x(), offset.y());
3300     notifyTransformedScrollChanged();
3301
3302     m_backingStore->d->orientationChanged();
3303     m_backingStore->d->actualVisibleSizeChanged(transformedActualVisibleSize);
3304
3305     // Update view mode only after we have updated the actual
3306     // visible size and reset the contents rect if necessary.
3307     if (setViewMode(viewMode()))
3308         needsLayout = true;
3309
3310     bool needsLayoutToFindContentSize = hasPendingOrientation;
3311
3312     // We need to update the viewport size of the WebCore::ScrollView...
3313     updateViewportSize(!needsLayoutToFindContentSize /* setFixedReportedSize */, false /* sendResizeEvent */);
3314     notifyTransformedContentsSizeChanged();
3315
3316     // If automatic zooming is disabled, prevent zooming below.
3317     if (!m_webSettings->isZoomToFitOnLoad()) {
3318         atInitialScale = false;
3319
3320         // Normally, if the contents size is smaller than the layout width,
3321         // we would zoom in. If zoom is disabled, we need to do something else,
3322         // or there will be artifacts due to non-rendered areas outside of the
3323         // contents size. If there is a virtual viewport, we are not allowed
3324         // to modify the fixed layout size, however.
3325         if (!hasVirtualViewport() && contentsSize().width() < m_defaultLayoutSize.width()) {
3326             m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
3327             m_mainFrame->view()->setFixedLayoutSize(m_defaultLayoutSize);
3328             needsLayout = true;
3329         }
3330     }
3331
3332     if (needsLayout)
3333         setNeedsLayout();
3334
3335     // Need to resume so that the backingstore will start recording the invalidated
3336     // rects from below.
3337     m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
3338
3339     // We might need to layout here to get a correct contentsSize so that zoomToFit
3340     // is calculated correctly.
3341     requestLayoutIfNeeded();
3342
3343     // As a special case if we were zoomed to the initial scale at the beginning
3344     // of the rotation then preserve that zoom level even when it is zoomToFit.
3345     double scale = atInitialScale ? initialScale() : currentScale();
3346
3347     // Do our own clamping.
3348     scale = clampedScale(scale);
3349
3350     if (needsLayoutToFindContentSize) {
3351         // Set the fixed reported size here so that innerWidth|innerHeight works
3352         // with this new scale.
3353         TransformationMatrix rotationMatrix;
3354         rotationMatrix.scale(scale);
3355         IntRect viewportRect = IntRect(IntPoint::zero(), transformedActualVisibleSize);
3356         IntRect actualVisibleRect = enclosingIntRect(rotationMatrix.inverse().mapRect(FloatRect(viewportRect)));
3357         m_mainFrame->view()->setFixedReportedSize(actualVisibleRect.size());
3358         m_mainFrame->view()->repaintFixedElementsAfterScrolling();
3359     }
3360
3361     // We're going to need to send a resize event to JavaScript because
3362     // innerWidth and innerHeight depend on fixed reported size.
3363     // This is how we support mobile pages where JavaScript resizes
3364     // the page in order to get around the fixed layout size, e.g.
3365     // google maps when it detects a mobile user agent.
3366     if (shouldSendResizeEvent())
3367         m_mainFrame->eventHandler()->sendResizeEvent();
3368
3369     // As a special case if we were anchored to the top left position at the beginning
3370     // of the rotation then preserve that anchor.
3371     FloatPoint anchor = centerOfVisibleContentsRect;
3372     if (atTop)
3373         anchor.setY(0);
3374     if (atLeft)
3375         anchor.setX(0);
3376
3377     // Try and zoom here with clamping on.
3378     if (m_backingStore->d->shouldDirectRenderingToWindow()) {
3379         bool success = zoomAboutPoint(scale, anchor, false /* enforceScaleClamping */, true /* forceRendering */);
3380         if (!success && ensureFocusElementVisible)
3381             ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3382     } else if (!scheduleZoomAboutPoint(scale, anchor, false /* enforceScaleClamping */, true /* forceRendering */)) {
3383         // Suspend all screen updates to the backingstore.
3384         m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3385
3386         // If the zoom failed, then we should still preserve the special case of scroll position.
3387         IntPoint scrollPosition = this->scrollPosition();
3388         if (atTop)
3389             scrollPosition.setY(0);
3390         if (atLeft)
3391             scrollPosition.setX(0);
3392         setScrollPosition(scrollPosition);
3393
3394         // These might have been altered even if we didn't zoom so notify the client.
3395         notifyTransformedContentsSizeChanged();
3396         notifyTransformedScrollChanged();
3397
3398         if (!needsLayout) {
3399             // The visible tiles for scroll must be up-to-date before we blit since we are not performing a layout.
3400             m_backingStore->d->updateTilesForScrollOrNotRenderedRegion();
3401         }
3402
3403         if (ensureFocusElementVisible)
3404             ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3405
3406         if (needsLayout) {
3407             m_backingStore->d->resetTiles(true);
3408             m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
3409         }
3410
3411         // If we need layout then render and blit, otherwise just blit as our viewport has changed.
3412         m_backingStore->d->resumeScreenAndBackingStoreUpdates(needsLayout ? BackingStore::RenderAndBlit : BackingStore::Blit);
3413     } else if (ensureFocusElementVisible)
3414         ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3415 }
3416
3417 void WebPage::setViewportSize(const Platform::IntSize& viewportSize, bool ensureFocusElementVisible)
3418 {
3419     d->setViewportSize(viewportSize, ensureFocusElementVisible);
3420 }
3421
3422 void WebPagePrivate::setDefaultLayoutSize(const IntSize& size)
3423 {
3424     IntSize screenSize = Platform::Graphics::Screen::primaryScreen()->size();
3425     ASSERT(size.width() <= screenSize.width() && size.height() <= screenSize.height());
3426     m_defaultLayoutSize = size.expandedTo(minimumLayoutSize).shrunkTo(screenSize);
3427 }
3428
3429 void WebPage::setDefaultLayoutSize(int width, int height)
3430 {
3431     IntSize size(width, height);
3432     if (size == d->m_defaultLayoutSize)
3433         return;
3434
3435     d->setDefaultLayoutSize(size);
3436     bool needsLayout = d->setViewMode(d->viewMode());
3437     if (needsLayout) {
3438         d->setNeedsLayout();
3439         if (!d->isLoading())
3440             d->requestLayoutIfNeeded();
3441     }
3442 }
3443
3444 bool WebPage::mouseEvent(const Platform::MouseEvent& mouseEvent, bool* wheelDeltaAccepted)
3445 {
3446     if (!d->m_mainFrame->view())
3447         return false;
3448
3449     PluginView* pluginView = d->m_fullScreenPluginView.get();
3450     if (pluginView)
3451         return d->dispatchMouseEventToFullScreenPlugin(pluginView, mouseEvent);
3452
3453     if (mouseEvent.type() == Platform::MouseEvent::MouseAborted) {
3454         d->m_mainFrame->eventHandler()->setMousePressed(false);
3455         return false;
3456     }
3457
3458     d->m_pluginMayOpenNewTab = true;
3459
3460     d->m_lastUserEventTimestamp = currentTime();
3461     int clickCount = (d->m_selectionHandler->isSelectionActive() || mouseEvent.type() != Platform::MouseEvent::MouseMove) ? 1 : 0;
3462
3463     // Set the button type.
3464     MouseButton buttonType = NoButton;
3465     if (mouseEvent.isLeftButton())
3466         buttonType = LeftButton;
3467     else if (mouseEvent.isRightButton())
3468         buttonType = RightButton;
3469     else if (mouseEvent.isMiddleButton())
3470         buttonType = MiddleButton;
3471
3472     // Create our event.
3473     PlatformMouseEvent platformMouseEvent(d->mapFromTransformed(mouseEvent.position()),
3474                                           d->mapFromTransformed(mouseEvent.screenPosition()),
3475                                           toWebCoreMouseEventType(mouseEvent.type()), clickCount, buttonType, PointingDevice);
3476     d->m_lastMouseEvent = platformMouseEvent;
3477     bool success = d->handleMouseEvent(platformMouseEvent);
3478
3479     if (mouseEvent.wheelTicks()) {
3480         PlatformWheelEvent wheelEvent(d->mapFromTransformed(mouseEvent.position()),
3481                                       d->mapFromTransformed(mouseEvent.screenPosition()),
3482                                       0, -mouseEvent.wheelDelta(),
3483                                       0, -mouseEvent.wheelTicks(),
3484                                       ScrollByPixelWheelEvent,
3485                                       false /* shiftKey */, false /* ctrlKey */,
3486                                       false /* altKey */, false /* metaKey */);
3487         if (wheelDeltaAccepted)
3488             *wheelDeltaAccepted = d->handleWheelEvent(wheelEvent);
3489     } else if (wheelDeltaAccepted)
3490         *wheelDeltaAccepted = false;
3491
3492     return success;
3493 }
3494
3495 bool WebPagePrivate::dispatchMouseEventToFullScreenPlugin(PluginView* plugin, const Platform::MouseEvent& event)
3496 {
3497     NPEvent npEvent;
3498     NPMouseEvent mouseEvent;
3499
3500     mouseEvent.x = event.screenPosition().x();
3501     mouseEvent.y = event.screenPosition().y();
3502
3503     switch (event.type()) {
3504     case Platform::MouseEvent::MouseButtonDown:
3505         mouseEvent.type = MOUSE_BUTTON_DOWN;
3506         m_pluginMouseButtonPressed = true;
3507         break;
3508     case Platform::MouseEvent::MouseButtonUp:
3509         mouseEvent.type = MOUSE_BUTTON_UP;
3510         m_pluginMouseButtonPressed = false;
3511         break;
3512     case Platform::MouseEvent::MouseMove:
3513         mouseEvent.type = MOUSE_MOTION;
3514         break;
3515     default:
3516         return false;
3517     }
3518
3519     mouseEvent.flags = 0;
3520     mouseEvent.button = m_pluginMouseButtonPressed;
3521
3522     npEvent.type = NP_MouseEvent;
3523     npEvent.data = &mouseEvent;
3524
3525     return plugin->dispatchFullScreenNPEvent(npEvent);
3526 }
3527
3528 bool WebPagePrivate::handleMouseEvent(PlatformMouseEvent& mouseEvent)
3529 {
3530     EventHandler* eventHandler = m_mainFrame->eventHandler();
3531
3532     if (mouseEvent.type() == WebCore::PlatformEvent::MouseMoved)
3533         return eventHandler->mouseMoved(mouseEvent);
3534
3535     if (mouseEvent.type() == WebCore::PlatformEvent::MouseScroll)
3536         return true;
3537
3538     Node* node = 0;
3539     if (mouseEvent.inputMethod() == TouchScreen) {
3540         const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
3541
3542         // Fat fingers can deal with shadow content.
3543         node = lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
3544     }
3545
3546     if (!node) {
3547         HitTestResult result = eventHandler->hitTestResultAtPoint(mapFromViewportToContents(mouseEvent.position()), false /*allowShadowContent*/);
3548         node = result.innerNode();
3549     }
3550
3551     if (mouseEvent.type() == WebCore::PlatformEvent::MousePressed) {
3552         if (m_inputHandler->willOpenPopupForNode(node)) {
3553             // Do not allow any human generated mouse or keyboard events to select <option>s in the list box
3554             // because we use a pop up dialog to handle the actual selections. This prevents options from
3555             // being selected prior to displaying the pop up dialog. The contents of the listbox are for
3556             // display only.
3557             //
3558             // FIXME: We explicitly do not forward this event to WebCore so as to preserve symmetry with
3559             // the MouseEventReleased handling (below). This has the side-effect that mousedown events
3560             // are not fired for human generated mouse press events. See RIM Bug #1579.
3561
3562             // We do focus <select>/<option> on mouse down so that a Focus event is fired and have the
3563             // element painted in its focus state on repaint.
3564             ASSERT(node->isElementNode());
3565             if (node->isElementNode()) {
3566                 Element* element = static_cast<Element*>(node);
3567                 element->focus();
3568             }
3569         } else
3570             eventHandler->handleMousePressEvent(mouseEvent);
3571     } else if (mouseEvent.type() == WebCore::PlatformEvent::MouseReleased) {
3572         // FIXME: For <select> and <options> elements, we explicitly do not forward this event to WebCore so
3573         // as to preserve symmetry with the MouseEventPressed handling (above). This has the side-effect that
3574         // mouseup events are not fired on such elements for human generated mouse release events. See RIM Bug #1579.
3575         if (!m_inputHandler->didNodeOpenPopup(node))
3576             eventHandler->handleMouseReleaseEvent(mouseEvent);
3577     }
3578
3579     return true;
3580 }
3581
3582 bool WebPagePrivate::handleWheelEvent(PlatformWheelEvent& wheelEvent)
3583 {
3584     return m_mainFrame->eventHandler()->handleWheelEvent(wheelEvent);
3585 }
3586
3587 bool WebPage::touchEvent(const Platform::TouchEvent& event)
3588 {
3589 #if DEBUG_TOUCH_EVENTS
3590     switch (event.m_type) {
3591     case Platform::TouchEvent::TouchEnd:
3592         Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent Touch End");
3593         break;
3594     case Platform::TouchEvent::TouchStart:
3595         Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent Touch Start");
3596         break;
3597     case Platform::TouchEvent::TouchMove:
3598         Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent Touch Move");
3599         break;
3600     case Platform::TouchEvent::TouchCancel:
3601         Platform::log(Platform::LogLevelCritical, "WebPage::touchCancel Touch Cancel");
3602         break;
3603     }
3604
3605     for (unsigned i = 0; i < event.m_points.size(); i++) {
3606         switch (event.m_points[i].m_state) {
3607         case Platform::TouchPoint::TouchPressed:
3608             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());
3609             break;
3610         case Platform::TouchPoint::TouchReleased:
3611             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());
3612             break;
3613         case Platform::TouchPoint::TouchMoved:
3614             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());
3615             break;
3616         case Platform::TouchPoint::TouchStationary:
3617             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());
3618             break;
3619         }
3620     }
3621 #endif
3622
3623 #if ENABLE(TOUCH_EVENTS)
3624     PluginView* pluginView = d->m_fullScreenPluginView.get();
3625     if (pluginView)
3626         return d->dispatchTouchEventToFullScreenPlugin(pluginView, event);
3627
3628     if (!d->m_mainFrame)
3629         return false;
3630
3631     Platform::TouchEvent tEvent = event;
3632     for (unsigned i = 0; i < event.m_points.size(); i++) {
3633         tEvent.m_points[i].m_pos = d->mapFromTransformed(tEvent.m_points[i].m_pos);
3634         tEvent.m_points[i].m_screenPos = d->mapFromTransformed(tEvent.m_points[i].m_screenPos);
3635     }
3636
3637     Platform::Gesture tapGesture;
3638     if (event.hasGesture(Platform::Gesture::SingleTap))
3639         d->m_pluginMayOpenNewTab = true;
3640     else if (tEvent.m_type == Platform::TouchEvent::TouchStart || tEvent.m_type == Platform::TouchEvent::TouchCancel)
3641         d->m_pluginMayOpenNewTab = false;
3642
3643     bool handled = false;
3644
3645     if (d->m_needTouchEvents && !event.hasGesture(Platform::Gesture::Injected))
3646         handled = d->m_mainFrame->eventHandler()->handleTouchEvent(PlatformTouchEvent(&tEvent));
3647
3648     // Unpress mouse if touch end is consumed by a JavaScript touch handler, otherwise the mouse state will remain pressed
3649     // which could either mess up the internal mouse state or start text selection on the next mouse move/down.
3650     if (tEvent.m_type == Platform::TouchEvent::TouchEnd && handled && d->m_mainFrame->eventHandler()->mousePressed())
3651         d->m_touchEventHandler->touchEventCancel();
3652
3653     if (d->m_preventDefaultOnTouchStart) {
3654         if (tEvent.m_type == Platform::TouchEvent::TouchEnd || tEvent.m_type == Platform::TouchEvent::TouchCancel)
3655             d->m_preventDefaultOnTouchStart = false;
3656         return true;
3657     }
3658
3659     if (handled) {
3660         if (tEvent.m_type == Platform::TouchEvent::TouchStart)
3661             d->m_preventDefaultOnTouchStart = true;
3662         return true;
3663     }
3664
3665     if (event.hasGesture(Platform::Gesture::TouchHold))
3666         d->m_touchEventHandler->touchHoldEvent();
3667 #endif
3668
3669     return false;
3670 }
3671
3672 void WebPagePrivate::setScrollOriginPoint(const Platform::IntPoint& point)
3673 {
3674     m_inRegionScrollStartingNode = 0;
3675
3676     if (!m_hasInRegionScrollableAreas)
3677         return;
3678
3679     m_client->notifyInRegionScrollingStartingPointChanged(inRegionScrollableAreasForPoint(point));
3680 }
3681
3682 void WebPage::setScrollOriginPoint(const Platform::IntPoint& point)
3683 {
3684     Platform::IntPoint untransformedPoint = d->mapFromTransformed(point);
3685     d->setScrollOriginPoint(untransformedPoint);
3686 }
3687
3688 bool WebPagePrivate::dispatchTouchEventToFullScreenPlugin(PluginView* plugin, const Platform::TouchEvent& event)
3689 {
3690     NPTouchEvent npTouchEvent;
3691
3692     if (event.hasGesture(Platform::Gesture::DoubleTap))
3693         npTouchEvent.type = TOUCH_EVENT_DOUBLETAP;
3694     else if (event.hasGesture(Platform::Gesture::TouchHold))
3695         npTouchEvent.type = TOUCH_EVENT_TOUCHHOLD;
3696     else {
3697         switch (event.m_type) {
3698         case Platform::TouchEvent::TouchStart:
3699             npTouchEvent.type = TOUCH_EVENT_START;
3700             break;
3701         case Platform::TouchEvent::TouchEnd:
3702             npTouchEvent.type = TOUCH_EVENT_END;
3703             break;
3704         case Platform::TouchEvent::TouchMove:
3705             npTouchEvent.type = TOUCH_EVENT_MOVE;
3706             break;
3707         case Platform::TouchEvent::TouchCancel:
3708             npTouchEvent.type = TOUCH_EVENT_CANCEL;
3709             break;
3710         default:
3711             return false;
3712         }
3713     }
3714
3715     npTouchEvent.points = 0;
3716     npTouchEvent.size = event.m_points.size();
3717     if (npTouchEvent.size) {
3718         npTouchEvent.points = new NPTouchPoint[npTouchEvent.size];
3719         for (int i = 0; i < npTouchEvent.size; i++) {
3720             npTouchEvent.points[i].touchId = event.m_points[i].m_id;
3721             npTouchEvent.points[i].clientX = event.m_points[i].m_screenPos.x();
3722             npTouchEvent.points[i].clientY = event.m_points[i].m_screenPos.y();
3723             npTouchEvent.points[i].screenX = event.m_points[i].m_screenPos.x();
3724             npTouchEvent.points[i].screenY = event.m_points[i].m_screenPos.y();
3725             npTouchEvent.points[i].pageX = event.m_points[i].m_pos.x();
3726             npTouchEvent.points[i].pageY = event.m_points[i].m_pos.y();
3727         }
3728     }
3729
3730     NPEvent npEvent;
3731     npEvent.type = NP_TouchEvent;
3732     npEvent.data = &npTouchEvent;
3733
3734     bool handled = plugin->dispatchFullScreenNPEvent(npEvent);
3735
3736     if (npTouchEvent.type == TOUCH_EVENT_DOUBLETAP && !handled) {
3737         // Send Touch Up if double tap not consumed.
3738         npTouchEvent.type = TOUCH_EVENT_END;
3739         npEvent.data = &npTouchEvent;
3740         handled = plugin->dispatchFullScreenNPEvent(npEvent);
3741     }
3742     delete[] npTouchEvent.points;
3743     return handled;
3744 }
3745
3746 bool WebPage::touchPointAsMouseEvent(const Platform::TouchPoint& point)
3747 {
3748     PluginView* pluginView = d->m_fullScreenPluginView.get();
3749     if (pluginView)
3750         return d->dispatchTouchPointAsMouseEventToFullScreenPlugin(pluginView, point);
3751
3752     d->m_lastUserEventTimestamp = currentTime();
3753
3754     Platform::TouchPoint tPoint = point;
3755     tPoint.m_pos = d->mapFromTransformed(tPoint.m_pos);
3756     tPoint.m_screenPos = d->mapFromTransformed(tPoint.m_screenPos);
3757
3758     return d->m_touchEventHandler->handleTouchPoint(tPoint);
3759 }
3760
3761 bool WebPagePrivate::dispatchTouchPointAsMouseEventToFullScreenPlugin(PluginView* pluginView, const Platform::TouchPoint& point)
3762 {
3763     NPEvent npEvent;
3764     NPMouseEvent mouse;
3765
3766     switch (point.m_state) {
3767     case Platform::TouchPoint::TouchPressed:
3768         mouse.type = MOUSE_BUTTON_DOWN;
3769         break;
3770     case Platform::TouchPoint::TouchReleased:
3771         mouse.type = MOUSE_BUTTON_UP;
3772         break;
3773     case Platform::TouchPoint::TouchMoved:
3774         mouse.type = MOUSE_MOTION;
3775         break;
3776     case Platform::TouchPoint::TouchStationary:
3777         return false;
3778     }
3779
3780     mouse.x = point.m_screenPos.x();
3781     mouse.y = point.m_screenPos.y();
3782     mouse.button = mouse.type != MOUSE_BUTTON_UP;
3783     mouse.flags = 0;
3784     npEvent.type = NP_MouseEvent;
3785     npEvent.data = &mouse;
3786
3787     return pluginView->dispatchFullScreenNPEvent(npEvent);
3788 }
3789
3790 void WebPage::touchEventCancel()
3791 {
3792     d->m_pluginMayOpenNewTab = false;
3793     d->m_touchEventHandler->touchEventCancel();
3794 }
3795
3796 void WebPage::touchEventCancelAndClearFocusedNode()
3797 {
3798     d->m_touchEventHandler->touchEventCancelAndClearFocusedNode();
3799 }
3800
3801 Frame* WebPagePrivate::focusedOrMainFrame() const
3802 {
3803     return m_page->focusController()->focusedOrMainFrame();
3804 }
3805
3806 void WebPagePrivate::clearFocusNode()
3807 {
3808     Frame* frame = focusedOrMainFrame();
3809     if (!frame)
3810         return;
3811     ASSERT(frame->document());
3812
3813     if (frame->document()->focusedNode())
3814         frame->page()->focusController()->setFocusedNode(0, frame);
3815 }
3816
3817 WebString WebPage::textEncoding()
3818 {
3819     Frame* frame = d->focusedOrMainFrame();
3820     if (!frame)
3821         return "";
3822
3823     Document* document = frame->document();
3824     if (!document)
3825         return "";
3826
3827     return document->loader()->writer()->encoding();
3828 }
3829
3830 WebString WebPage::forcedTextEncoding()
3831 {
3832     Frame* frame = d->focusedOrMainFrame();
3833     if (!frame)
3834         return "";
3835
3836     Document* document = frame->document();
3837     if (!document)
3838         return "";
3839
3840     return document->loader()->overrideEncoding();
3841 }
3842
3843 void WebPage::setForcedTextEncoding(const char* encoding)
3844 {
3845     if (encoding && d->focusedOrMainFrame() && d->focusedOrMainFrame()->loader() && d->focusedOrMainFrame()->loader())
3846         return d->focusedOrMainFrame()->loader()->reloadWithOverrideEncoding(encoding);
3847 }
3848
3849 bool WebPagePrivate::scrollNodeRecursively(Node* node, const IntSize& delta)
3850 {
3851     if (delta.isZero())
3852         return true;
3853
3854     if (!node)
3855         return false;
3856
3857     RenderObject* renderer = node->renderer();
3858     if (!renderer)
3859         return false;
3860
3861     FrameView* view = renderer->view()->frameView();
3862     if (!view)
3863         return false;
3864
3865     // Try scrolling the renderer.
3866     if (scrollRenderer(renderer, delta))
3867         return true;
3868
3869     // We've hit the page, don't scroll it and return false.
3870     if (view == m_mainFrame->view())
3871         return false;
3872
3873     // Try scrolling the FrameView.
3874     if (canScrollInnerFrame(view->frame())) {
3875         IntSize viewDelta = delta;
3876         IntPoint newViewOffset = view->scrollPosition();
3877         IntPoint maxViewOffset = view->maximumScrollPosition();
3878         adjustScrollDelta(maxViewOffset, newViewOffset, viewDelta);
3879
3880         if (!viewDelta.isZero()) {
3881             view->setCanBlitOnScroll(false);
3882
3883             BackingStoreClient* backingStoreClient = backingStoreClientForFrame(view->frame());
3884             if (backingStoreClient) {
3885                 backingStoreClient->setIsClientGeneratedScroll(true);
3886                 backingStoreClient->setIsScrollNotificationSuppressed(true);
3887             }
3888
3889             m_inRegionScrollStartingNode = view->frame()->document();
3890
3891             view->scrollBy(viewDelta);
3892
3893             if (backingStoreClient) {
3894                 backingStoreClient->setIsClientGeneratedScroll(false);
3895                 backingStoreClient->setIsScrollNotificationSuppressed(false);
3896             }
3897
3898             return true;
3899         }
3900     }
3901
3902     // Try scrolling the node of the enclosing frame.
3903     Frame* frame = node->document()->frame();
3904     if (frame) {
3905         Node* ownerNode = frame->ownerElement();
3906         if (scrollNodeRecursively(ownerNode, delta))
3907             return true;
3908     }
3909
3910     return false;
3911 }
3912
3913 void WebPagePrivate::adjustScrollDelta(const IntPoint& maxOffset, const IntPoint& currentOffset, IntSize& delta) const
3914 {
3915     if (currentOffset.x() + delta.width() > maxOffset.x())
3916         delta.setWidth(min(maxOffset.x() - currentOffset.x(), delta.width()));
3917
3918     if (currentOffset.x() + delta.width() < 0)
3919         delta.setWidth(max(-currentOffset.x(), delta.width()));
3920
3921     if (currentOffset.y() + delta.height() > maxOffset.y())
3922         delta.setHeight(min(maxOffset.y() - currentOffset.y(), delta.height()));
3923
3924     if (currentOffset.y() + delta.height() < 0)
3925         delta.setHeight(max(-currentOffset.y(), delta.height()));
3926 }
3927
3928 static Node* enclosingLayerNode(RenderLayer*);
3929
3930 bool WebPagePrivate::scrollRenderer(RenderObject* renderer, const IntSize& delta)
3931 {
3932     RenderLayer* layer = renderer->enclosingLayer();
3933     if (!layer)
3934         return false;
3935
3936     // Try to scroll layer.
3937     bool restrictedByLineClamp = false;
3938     if (renderer->parent())
3939         restrictedByLineClamp = !renderer->parent()->style()->lineClamp().isNone();
3940
3941     if (renderer->hasOverflowClip() && !restrictedByLineClamp) {
3942         IntSize layerDelta = delta;
3943         IntPoint maxOffset(layer->scrollWidth() - layer->renderBox()->clientWidth(), layer->scrollHeight() - layer->renderBox()->clientHeight());
3944         IntPoint currentOffset(layer->scrollXOffset(), layer->scrollYOffset());
3945         adjustScrollDelta(maxOffset, currentOffset, layerDelta);
3946         if (!layerDelta.isZero()) {
3947             m_inRegionScrollStartingNode = enclosingLayerNode(layer);
3948             IntPoint newOffset = currentOffset + layerDelta;
3949             layer->scrollToOffset(newOffset.x(), newOffset.y());
3950             renderer->repaint(true);
3951             return true;
3952         }
3953     }
3954
3955     while (layer = layer->parent()) {
3956         if (canScrollRenderBox(layer->renderBox()))
3957             return scrollRenderer(layer->renderBox(), delta);
3958     }
3959
3960     return false;
3961 }
3962
3963 static void handleScrolling(unsigned short character, WebPagePrivate* scroller)
3964 {
3965     const int scrollFactor = 20;
3966     int dx = 0, dy = 0;
3967     switch (character) {
3968     case KEYCODE_LEFT:
3969         dx = -scrollFactor;
3970         break;
3971     case KEYCODE_RIGHT:
3972         dx = scrollFactor;
3973         break;
3974     case KEYCODE_UP:
3975         dy = -scrollFactor;
3976         break;
3977     case KEYCODE_DOWN:
3978         dy = scrollFactor;
3979         break;
3980     case KEYCODE_PG_UP:
3981         ASSERT(scroller);
3982         dy = scrollFactor - scroller->actualVisibleSize().height();
3983         break;
3984     case KEYCODE_PG_DOWN:
3985         ASSERT(scroller);
3986         dy = scroller->actualVisibleSize().height() - scrollFactor;
3987         break;
3988     }
3989
3990     if (dx || dy) {
3991         // Don't use the scrollBy function because it triggers the scroll as originating from BlackBerry
3992         // but then it expects a separate invalidate which isn't sent in this case.
3993         ASSERT(scroller && scroller->m_mainFrame && scroller->m_mainFrame->view());
3994         IntPoint pos(scroller->scrollPosition() + IntSize(dx, dy));
3995
3996         // Prevent over scrolling for arrows and Page up/down.
3997         if (pos.x() < 0)
3998             pos.setX(0);
3999         if (pos.y() < 0)
4000             pos.setY(0);
4001         if (pos.x() + scroller->actualVisibleSize().width() > scroller->contentsSize().width())
4002             pos.setX(scroller->contentsSize().width() - scroller->actualVisibleSize().width());
4003         if (pos.y() + scroller->actualVisibleSize().height() > scroller->contentsSize().height())
4004             pos.setY(scroller->contentsSize().height() - scroller->actualVisibleSize().height());
4005
4006         scroller->m_mainFrame->view()->setScrollPosition(pos);
4007         scroller->m_client->scrollChanged(pos);
4008     }
4009 }
4010
4011 bool WebPage::keyEvent(const Platform::KeyboardEvent& keyboardEvent)
4012 {
4013     if (!d->m_mainFrame->view())
4014         return false;
4015
4016     ASSERT(d->m_page->focusController());
4017
4018     bool handled = d->m_inputHandler->handleKeyboardInput(keyboardEvent);
4019
4020     if (!handled && keyboardEvent.type() == Platform::KeyboardEvent::KeyDown && !d->m_inputHandler->isInputMode()) {
4021         IntPoint previousPos = d->scrollPosition();
4022         handleScrolling(keyboardEvent.character(), d);
4023         handled = previousPos != d->scrollPosition();
4024     }
4025
4026     return handled;
4027 }
4028
4029 bool WebPage::deleteTextRelativeToCursor(unsigned int leftOffset, unsigned int rightOffset)
4030 {
4031     return d->m_inputHandler->deleteTextRelativeToCursor(leftOffset, rightOffset);
4032 }
4033
4034 spannable_string_t* WebPage::selectedText(int32_t flags)
4035 {
4036     return d->m_inputHandler->selectedText(flags);
4037 }
4038
4039 spannable_string_t* WebPage::textBeforeCursor(int32_t length, int32_t flags)
4040 {
4041     return d->m_inputHandler->textBeforeCursor(length, flags);
4042 }
4043
4044 spannable_string_t* WebPage::textAfterCursor(int32_t length, int32_t flags)
4045 {
4046     return d->m_inputHandler->textAfterCursor(length, flags);
4047 }
4048
4049 extracted_text_t* WebPage::extractedTextRequest(extracted_text_request_t* request, int32_t flags)
4050 {
4051     return d->m_inputHandler->extractedTextRequest(request, flags);
4052 }
4053
4054 int32_t WebPage::setComposingRegion(int32_t start, int32_t end)
4055 {
4056     return d->m_inputHandler->setComposingRegion(start, end);
4057 }
4058
4059 int32_t WebPage::finishComposition()
4060 {
4061     return d->m_inputHandler->finishComposition();
4062 }
4063
4064 int32_t WebPage::setComposingText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
4065 {
4066     return d->m_inputHandler->setComposingText(spannableString, relativeCursorPosition);
4067 }
4068
4069 int32_t WebPage::commitText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
4070 {
4071     return d->m_inputHandler->commitText(spannableString, relativeCursorPosition);
4072 }
4073
4074 void WebPage::setSpellCheckingEnabled(bool enabled)
4075 {
4076     static_cast<EditorClientBlackBerry*>(d->m_page->editorClient())->enableSpellChecking(enabled);
4077 }
4078
4079 void WebPage::selectionCancelled()
4080 {