[BlackBerry] Animation & UI lag when rendering
[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 "AutofillManager.h"
24 #include "BackForwardController.h"
25 #include "BackForwardListImpl.h"
26 #include "BackingStoreClient.h"
27 #include "BackingStoreCompositingSurface.h"
28 #include "BackingStore_p.h"
29 #if ENABLE(BATTERY_STATUS)
30 #include "BatteryClientBlackBerry.h"
31 #endif
32 #include "CString.h"
33 #include "CachedImage.h"
34 #include "Chrome.h"
35 #include "ChromeClientBlackBerry.h"
36 #include "ContextMenuClientBlackBerry.h"
37 #include "CookieManager.h"
38 #include "CredentialManager.h"
39 #include "CredentialStorage.h"
40 #include "CredentialTransformData.h"
41 #include "DOMSupport.h"
42 #include "Database.h"
43 #include "DatabaseSync.h"
44 #include "DatabaseTracker.h"
45 #include "DefaultTapHighlight.h"
46 #include "DeviceMotionClientBlackBerry.h"
47 #include "DeviceOrientationClientBlackBerry.h"
48 #include "DragClientBlackBerry.h"
49 // FIXME: We should be using DumpRenderTreeClient, but I'm not sure where we should
50 // create the DRT_BB object. See PR #120355.
51 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
52 #include "DumpRenderTreeBlackBerry.h"
53 #endif
54 #include "EditorClientBlackBerry.h"
55 #include "FocusController.h"
56 #include "FrameLoaderClientBlackBerry.h"
57 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
58 #include "GeolocationClientMock.h"
59 #endif
60 #include "GeolocationControllerClientBlackBerry.h"
61 #include "GroupSettings.h"
62 #include "HTMLAreaElement.h"
63 #include "HTMLFrameOwnerElement.h"
64 #include "HTMLImageElement.h"
65 #include "HTMLInputElement.h"
66 #include "HTMLMediaElement.h"
67 #include "HTMLNames.h"
68 #include "HTMLParserIdioms.h"
69 #include "HTTPParsers.h"
70 #include "HistoryItem.h"
71 #include "IconDatabaseClientBlackBerry.h"
72 #include "InPageSearchManager.h"
73 #include "InRegionScrollableArea.h"
74 #include "InRegionScroller_p.h"
75 #include "InputHandler.h"
76 #include "InspectorBackendDispatcher.h"
77 #include "InspectorClientBlackBerry.h"
78 #include "InspectorController.h"
79 #include "InspectorOverlay.h"
80 #include "JavaScriptDebuggerBlackBerry.h"
81 #include "JavaScriptVariant_p.h"
82 #include "LayerWebKitThread.h"
83 #include "NetworkManager.h"
84 #include "NodeRenderStyle.h"
85 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
86 #include "NotificationPresenterImpl.h"
87 #endif
88 #include "Page.h"
89 #include "PageCache.h"
90 #include "PageGroup.h"
91 #include "PagePopupBlackBerry.h"
92 #include "PlatformTouchEvent.h"
93 #include "PlatformWheelEvent.h"
94 #include "PluginDatabase.h"
95 #include "PluginView.h"
96 #include "RenderLayerBacking.h"
97 #include "RenderLayerCompositor.h"
98 #if ENABLE(FULLSCREEN_API)
99 #include "RenderFullScreen.h"
100 #endif
101 #include "RenderText.h"
102 #include "RenderThemeBlackBerry.h"
103 #include "RenderTreeAsText.h"
104 #include "RenderView.h"
105 #include "RenderWidget.h"
106 #include "ScriptSourceCode.h"
107 #include "ScriptValue.h"
108 #include "ScrollTypes.h"
109 #include "SecurityPolicy.h"
110 #include "SelectionHandler.h"
111 #include "SelectionOverlay.h"
112 #include "Settings.h"
113 #include "Storage.h"
114 #include "StorageNamespace.h"
115 #include "SurfacePool.h"
116 #include "Text.h"
117 #include "ThreadCheck.h"
118 #include "TouchEventHandler.h"
119 #include "TransformationMatrix.h"
120 #if ENABLE(MEDIA_STREAM)
121 #include "UserMediaClientImpl.h"
122 #endif
123 #if ENABLE(VIBRATION)
124 #include "VibrationClientBlackBerry.h"
125 #endif
126 #include "VisiblePosition.h"
127 #if ENABLE(WEBDOM)
128 #include "WebDOMDocument.h"
129 #endif
130 #include "WebKitVersion.h"
131 #include "WebOverlay.h"
132 #include "WebOverlay_p.h"
133 #include "WebPageClient.h"
134 #include "WebSocket.h"
135 #include "WebViewportArguments.h"
136 #include "npapi.h"
137 #include "runtime_root.h"
138
139 #if ENABLE(VIDEO)
140 #include "MediaPlayer.h"
141 #include "MediaPlayerPrivateBlackBerry.h"
142 #endif
143
144 #if USE(SKIA)
145 #include "PlatformContextSkia.h"
146 #endif
147
148 #if USE(ACCELERATED_COMPOSITING)
149 #include "FrameLayers.h"
150 #include "WebPageCompositorClient.h"
151 #include "WebPageCompositor_p.h"
152 #endif
153
154 #include <BlackBerryPlatformDeviceInfo.h>
155 #include <BlackBerryPlatformExecutableMessage.h>
156 #include <BlackBerryPlatformITPolicy.h>
157 #include <BlackBerryPlatformKeyboardEvent.h>
158 #include <BlackBerryPlatformMessageClient.h>
159 #include <BlackBerryPlatformMouseEvent.h>
160 #include <BlackBerryPlatformScreen.h>
161 #include <BlackBerryPlatformSettings.h>
162 #include <JavaScriptCore/APICast.h>
163 #include <JavaScriptCore/JSContextRef.h>
164 #include <JavaScriptCore/JSStringRef.h>
165 #include <SharedPointer.h>
166 #include <sys/keycodes.h>
167 #include <unicode/ustring.h> // platform ICU
168
169 #ifndef USER_PROCESSES
170 #include <memalloc.h>
171 #endif
172
173 #if ENABLE(ACCELERATED_2D_CANVAS)
174 #include "GrContext.h"
175 #include "SharedGraphicsContext3D.h"
176 #endif
177
178 #if ENABLE(REQUEST_ANIMATION_FRAME)
179 #include "PlatformScreen.h"
180 #endif
181
182 #define DEBUG_BLOCK_ZOOM 0
183 #define DEBUG_TOUCH_EVENTS 0
184 #define DEBUG_WEBPAGE_LOAD 0
185 #define DEBUG_AC_COMMIT 0
186
187 using namespace std;
188 using namespace WebCore;
189
190 typedef const unsigned short* CUShortPtr;
191
192 namespace BlackBerry {
193 namespace WebKit {
194
195 static Vector<WebPage*>* visibleWebPages()
196 {
197     static Vector<WebPage*>* s_visibleWebPages = 0; // Initially, no web page is visible.
198     if (!s_visibleWebPages)
199         s_visibleWebPages = new Vector<WebPage*>;
200     return s_visibleWebPages;
201 }
202
203 const unsigned blockZoomMargin = 3; // Add 3 pixel margin on each side.
204 static int blockClickRadius = 0;
205 static double maximumBlockZoomScale = 3; // This scale can be clamped by the maximumScale set for the page.
206
207 const double manualScrollInterval = 0.1; // The time interval during which we associate user action with scrolling.
208
209 const double delayedZoomInterval = 0;
210
211 const IntSize minimumLayoutSize(10, 10); // Needs to be a small size, greater than 0, that we can grow the layout from.
212
213 const double minimumExpandingRatio = 0.15;
214
215 const double minimumZoomToFitScale = 0.25;
216
217 // Helper function to parse a URL and fill in missing parts.
218 static KURL parseUrl(const String& url)
219 {
220     String urlString(url);
221     KURL kurl = KURL(KURL(), urlString);
222     if (kurl.protocol().isEmpty()) {
223         urlString.insert("http://", 0);
224         kurl = KURL(KURL(), urlString);
225     }
226
227     return kurl;
228 }
229
230 // Helper functions to convert to and from WebCore types.
231 static inline WebCore::PlatformEvent::Type toWebCoreMouseEventType(const BlackBerry::Platform::MouseEvent::Type type)
232 {
233     switch (type) {
234     case BlackBerry::Platform::MouseEvent::MouseButtonDown:
235         return WebCore::PlatformEvent::MousePressed;
236     case Platform::MouseEvent::MouseButtonUp:
237         return WebCore::PlatformEvent::MouseReleased;
238     case Platform::MouseEvent::MouseMove:
239     default:
240         return WebCore::PlatformEvent::MouseMoved;
241     }
242 }
243
244 static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy)
245 {
246     switch (policy) {
247     case Platform::NetworkRequest::UseProtocolCachePolicy:
248         return UseProtocolCachePolicy;
249     case Platform::NetworkRequest::ReloadIgnoringCacheData:
250         return ReloadIgnoringCacheData;
251     case Platform::NetworkRequest::ReturnCacheDataElseLoad:
252         return ReturnCacheDataElseLoad;
253     case Platform::NetworkRequest::ReturnCacheDataDontLoad:
254         return ReturnCacheDataDontLoad;
255     default:
256         ASSERT_NOT_REACHED();
257         return UseProtocolCachePolicy;
258     }
259 }
260
261 #if ENABLE(EVENT_MODE_METATAGS)
262 static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode)
263 {
264     switch (mode) {
265     case ProcessedCursorEvents:
266         return Platform::ProcessedCursorEvents;
267     case NativeCursorEvents:
268         return Platform::NativeCursorEvents;
269     default:
270         ASSERT_NOT_REACHED();
271         return Platform::ProcessedCursorEvents;
272     }
273 }
274
275 static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode)
276 {
277     switch (mode) {
278     case ProcessedTouchEvents:
279         return Platform::ProcessedTouchEvents;
280     case NativeTouchEvents:
281         return Platform::NativeTouchEvents;
282     case PureTouchEventsWithMouseConversion:
283         return Platform::PureTouchEventsWithMouseConversion;
284     default:
285         ASSERT_NOT_REACHED();
286         return Platform::ProcessedTouchEvents;
287     }
288 }
289 #endif
290
291 static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id)
292 {
293     return reinterpret_cast<HistoryItem*>(id);
294 }
295
296 static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item)
297 {
298     return reinterpret_cast<WebPage::BackForwardId>(item);
299 }
300
301 void WebPage::setUserViewportArguments(const WebViewportArguments& viewportArguments)
302 {
303     d->m_userViewportArguments = *(viewportArguments.d);
304 }
305
306 void WebPage::resetUserViewportArguments()
307 {
308     d->m_userViewportArguments = ViewportArguments();
309 }
310
311 template <bool WebPagePrivate::* isActive>
312 class DeferredTask: public WebPagePrivate::DeferredTaskBase {
313 public:
314     static void finishOrCancel(WebPagePrivate* webPagePrivate)
315     {
316         webPagePrivate->*isActive = false;
317     }
318 protected:
319     DeferredTask(WebPagePrivate* webPagePrivate)
320         : DeferredTaskBase(webPagePrivate, isActive)
321     {
322     }
323     typedef DeferredTask<isActive> DeferredTaskType;
324 };
325
326 void WebPage::autofillTextField(const string& item)
327 {
328     if (!d->m_webSettings->isFormAutofillEnabled())
329         return;
330
331     d->m_autofillManager->autofillTextField(item.c_str());
332 }
333
334 void WebPage::enableQnxJavaScriptObject(bool enabled)
335 {
336     d->m_enableQnxJavaScriptObject = enabled;
337 }
338
339 WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
340     : m_webPage(webPage)
341     , m_client(client)
342     , m_inspectorClient(0)
343     , m_page(0) // Initialized by init.
344     , m_mainFrame(0) // Initialized by init.
345     , m_currentContextNode(0)
346     , m_webSettings(0) // Initialized by init.
347     , m_visible(false)
348     , m_activationState(ActivationActive)
349     , m_shouldResetTilesWhenShown(false)
350     , m_shouldZoomToInitialScaleAfterLoadFinished(false)
351     , m_userScalable(true)
352     , m_userPerformedManualZoom(false)
353     , m_userPerformedManualScroll(false)
354     , m_contentsSizeChanged(false)
355     , m_overflowExceedsContentsSize(false)
356     , m_resetVirtualViewportOnCommitted(true)
357     , m_shouldUseFixedDesktopMode(false)
358     , m_needTouchEvents(false)
359     , m_preventIdleDimmingCount(0)
360 #if ENABLE(TOUCH_EVENTS)
361     , m_preventDefaultOnTouchStart(false)
362 #endif
363     , m_nestedLayoutFinishedCount(0)
364     , m_actualVisibleWidth(rect.width())
365     , m_actualVisibleHeight(rect.height())
366     , m_virtualViewportWidth(0)
367     , m_virtualViewportHeight(0)
368     , m_defaultLayoutSize(minimumLayoutSize)
369     , m_didRestoreFromPageCache(false)
370     , m_viewMode(WebPagePrivate::Desktop) // Default to Desktop mode for PB.
371     , m_loadState(WebPagePrivate::None)
372     , m_transformationMatrix(new TransformationMatrix())
373     , m_backingStore(0) // Initialized by init.
374     , m_backingStoreClient(0) // Initialized by init.
375     , m_inPageSearchManager(new InPageSearchManager(this))
376     , m_inputHandler(new InputHandler(this))
377     , m_selectionHandler(new SelectionHandler(this))
378     , m_touchEventHandler(new TouchEventHandler(this))
379 #if ENABLE(EVENT_MODE_METATAGS)
380     , m_cursorEventMode(ProcessedCursorEvents)
381     , m_touchEventMode(ProcessedTouchEvents)
382 #endif
383 #if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
384     , m_scaleBeforeFullScreen(-1.0)
385     , m_xScrollOffsetBeforeFullScreen(-1)
386 #endif
387     , m_currentCursor(Platform::CursorNone)
388     , m_dumpRenderTree(0) // Lazy initialization.
389     , m_initialScale(-1.0)
390     , m_minimumScale(-1.0)
391     , m_maximumScale(-1.0)
392     , m_blockZoomFinalScale(1.0)
393     , m_anchorInNodeRectRatio(-1, -1)
394     , m_currentBlockZoomNode(0)
395     , m_currentBlockZoomAdjustedNode(0)
396     , m_shouldReflowBlock(false)
397     , m_delayedZoomTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::zoomAboutPointTimerFired)))
398     , m_lastUserEventTimestamp(0.0)
399     , m_pluginMouseButtonPressed(false)
400     , m_pluginMayOpenNewTab(false)
401 #if USE(ACCELERATED_COMPOSITING)
402     , m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
403     , m_needsOneShotDrawingSynchronization(false)
404     , m_needsCommit(false)
405     , m_suspendRootLayerCommit(false)
406 #endif
407     , m_hasPendingSurfaceSizeChange(false)
408     , m_pendingOrientation(-1)
409     , m_fullscreenVideoNode(0)
410     , m_hasInRegionScrollableAreas(false)
411     , m_updateDelegatedOverlaysDispatched(false)
412     , m_enableQnxJavaScriptObject(true)
413     , m_deferredTasksTimer(this, &WebPagePrivate::deferredTasksTimerFired)
414     , m_selectPopup(0)
415     , m_autofillManager(AutofillManager::create(this))
416 {
417     static bool isInitialized = false;
418     if (!isInitialized) {
419         isInitialized = true;
420         BlackBerry::Platform::DeviceInfo::instance();
421         defaultUserAgent();
422     }
423 }
424
425 WebPage::WebPage(WebPageClient* client, const WebString& pageGroupName, const Platform::IntRect& rect)
426 {
427     globalInitialize();
428     d = new WebPagePrivate(this, client, rect);
429     d->init(pageGroupName);
430 }
431
432 WebPagePrivate::~WebPagePrivate()
433 {
434     // Hand the backingstore back to another owner if necessary.
435     m_webPage->setVisible(false);
436     if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage)
437         BackingStorePrivate::setCurrentBackingStoreOwner(0);
438
439     delete m_webSettings;
440     m_webSettings = 0;
441
442     delete m_backingStoreClient;
443     m_backingStoreClient = 0;
444     m_backingStore = 0;
445
446     delete m_page;
447     m_page = 0;
448
449     delete m_transformationMatrix;
450     m_transformationMatrix = 0;
451
452     delete m_inPageSearchManager;
453     m_inPageSearchManager = 0;
454
455     delete m_selectionHandler;
456     m_selectionHandler = 0;
457
458     delete m_inputHandler;
459     m_inputHandler = 0;
460
461     delete m_touchEventHandler;
462     m_touchEventHandler = 0;
463
464 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
465     delete m_dumpRenderTree;
466     m_dumpRenderTree = 0;
467 #endif
468
469 #if USE(ACCELERATED_COMPOSITING)
470     deleteGuardedObject(m_selectionOverlay);
471     m_selectionOverlay = 0;
472 #endif
473 }
474
475 WebPage::~WebPage()
476 {
477     deleteGuardedObject(d);
478     d = 0;
479 }
480
481 Page* WebPagePrivate::core(const WebPage* webPage)
482 {
483     return webPage->d->m_page;
484 }
485
486 void WebPagePrivate::init(const WebString& pageGroupName)
487 {
488     ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this);
489     ContextMenuClientBlackBerry* contextMenuClient = 0;
490 #if ENABLE(CONTEXT_MENUS)
491     contextMenuClient = new ContextMenuClientBlackBerry();
492 #endif
493     EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this);
494     DragClientBlackBerry* dragClient = 0;
495 #if ENABLE(DRAG_SUPPORT)
496     dragClient = new DragClientBlackBerry();
497 #endif
498 #if ENABLE(INSPECTOR)
499     m_inspectorClient = new InspectorClientBlackBerry(this);
500 #endif
501
502     FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry();
503
504     Page::PageClients pageClients;
505     pageClients.chromeClient = chromeClient;
506     pageClients.contextMenuClient = contextMenuClient;
507     pageClients.editorClient = editorClient;
508     pageClients.dragClient = dragClient;
509     pageClients.inspectorClient = m_inspectorClient;
510
511     m_page = new Page(pageClients);
512 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
513     if (getenv("drtRun")) {
514         // In case running in DumpRenderTree mode set the controller to mock provider.
515         GeolocationClientMock* mock = new GeolocationClientMock();
516         WebCore::provideGeolocationTo(m_page, mock);
517         mock->setController(WebCore::GeolocationController::from(m_page));
518     } else
519 #else
520         WebCore::provideGeolocationTo(m_page, new GeolocationControllerClientBlackBerry(this));
521 #endif
522     WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientBlackBerry(this));
523     WebCore::provideDeviceMotionTo(m_page, new DeviceMotionClientBlackBerry(this));
524 #if ENABLE(VIBRATION)
525     WebCore::provideVibrationTo(m_page, new VibrationClientBlackBerry());
526 #endif
527
528 #if ENABLE(BATTERY_STATUS)
529     WebCore::provideBatteryTo(m_page, new WebCore::BatteryClientBlackBerry(this));
530 #endif
531
532 #if ENABLE(MEDIA_STREAM)
533     WebCore::provideUserMediaTo(m_page, new UserMediaClientImpl(m_webPage));
534 #endif
535
536 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
537     WebCore::provideNotification(m_page, NotificationPresenterImpl::instance());
538 #endif
539
540     m_page->setCustomHTMLTokenizerChunkSize(256);
541     m_page->setCustomHTMLTokenizerTimeDelay(0.3);
542
543     m_webSettings = WebSettings::createFromStandardSettings();
544     m_webSettings->setUserAgentString(defaultUserAgent());
545     m_page->setDeviceScaleFactor(m_webSettings->devicePixelRatio());
546
547 #if USE(ACCELERATED_COMPOSITING)
548     m_tapHighlight = DefaultTapHighlight::create(this);
549     m_selectionOverlay = SelectionOverlay::create(this);
550     m_page->settings()->setAcceleratedCompositingForFixedPositionEnabled(true);
551 #endif
552
553     // FIXME: We explicitly call setDelegate() instead of passing ourself in createFromStandardSettings()
554     // so that we only get one didChangeSettings() callback when we set the page group name. This causes us
555     // to make a copy of the WebSettings since some WebSettings method make use of the page group name.
556     // Instead, we shouldn't be storing the page group name in WebSettings.
557     m_webSettings->setPageGroupName(pageGroupName);
558     m_webSettings->setDelegate(this);
559     didChangeSettings(m_webSettings);
560
561     RefPtr<Frame> newFrame = Frame::create(m_page, /* HTMLFrameOwnerElement* */ 0, frameLoaderClient);
562
563     m_mainFrame = newFrame.get();
564     frameLoaderClient->setFrame(m_mainFrame, this);
565     m_mainFrame->init();
566
567     m_inRegionScroller = adoptPtr(new InRegionScroller(this));
568
569 #if ENABLE(WEBGL)
570     Platform::Settings* settings = Platform::Settings::instance();
571     m_page->settings()->setWebGLEnabled(settings && settings->isWebGLSupported());
572 #endif
573 #if ENABLE(ACCELERATED_2D_CANVAS)
574     m_page->settings()->setCanvasUsesAcceleratedDrawing(true);
575     m_page->settings()->setAccelerated2dCanvasEnabled(true);
576 #endif
577
578     m_page->settings()->setInteractiveFormValidationEnabled(true);
579     m_page->settings()->setAllowUniversalAccessFromFileURLs(false);
580     m_page->settings()->setAllowFileAccessFromFileURLs(false);
581
582     m_backingStoreClient = BackingStoreClient::create(m_mainFrame, /* parent frame */ 0, m_webPage);
583     // The direct access to BackingStore is left here for convenience since it
584     // is owned by BackingStoreClient and then deleted by its destructor.
585     m_backingStore = m_backingStoreClient->backingStore();
586
587     blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(0).width())); // The clicked rectangle area should be a fixed unit of measurement.
588
589     m_page->settings()->setDelegateSelectionPaint(true);
590
591 #if ENABLE(REQUEST_ANIMATION_FRAME)
592     m_page->windowScreenDidChange((PlatformDisplayID)0);
593 #endif
594
595 #if ENABLE(WEB_TIMING)
596     m_page->settings()->setMemoryInfoEnabled(true);
597 #endif
598
599 #if USE(ACCELERATED_COMPOSITING)
600     // The compositor will be needed for overlay rendering, so create it
601     // unconditionally. It will allocate OpenGL objects lazily, so this incurs
602     // no overhead in the unlikely case where the compositor is not needed.
603     Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
604             createMethodCallMessage(&WebPagePrivate::createCompositor, this));
605 #endif
606     m_page->settings()->setDNSPrefetchingEnabled(true);
607 }
608
609 class DeferredTaskLoadManualScript: public DeferredTask<&WebPagePrivate::m_wouldLoadManualScript> {
610 public:
611     explicit DeferredTaskLoadManualScript(WebPagePrivate* webPagePrivate, const KURL& url)
612         : DeferredTaskType(webPagePrivate)
613     {
614         webPagePrivate->m_cachedManualScript = url;
615     }
616 private:
617     virtual void performInternal(WebPagePrivate* webPagePrivate)
618     {
619         webPagePrivate->m_mainFrame->script()->executeIfJavaScriptURL(webPagePrivate->m_cachedManualScript, DoNotReplaceDocumentIfJavaScriptURL);
620     }
621 };
622
623 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, const char* suggestedSaveName)
624 {
625     stopCurrentLoad();
626     DeferredTaskLoadManualScript::finishOrCancel(this);
627
628     String urlString(url);
629     if (urlString.startsWith("vs:", false)) {
630         urlString = urlString.substring(3);
631         m_mainFrame->setInViewSourceMode(true);
632     } else
633         m_mainFrame->setInViewSourceMode(false);
634
635     KURL kurl = parseUrl(urlString);
636     if (protocolIs(kurl, "javascript")) {
637         // Never run javascript while loading is deferred.
638         if (m_page->defersLoading())
639             m_deferredTasks.append(adoptPtr(new DeferredTaskLoadManualScript(this, kurl)));
640         else
641             m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL);
642         return;
643     }
644
645     if (isInitial)
646         NetworkManager::instance()->setInitialURL(kurl);
647
648     ResourceRequest request(kurl);
649     request.setToken(networkToken);
650     if (isInitial || mustHandleInternally)
651         request.setMustHandleInternally(true);
652     request.setHTTPMethod(method);
653     request.setCachePolicy(toWebCoreCachePolicy(cachePolicy));
654     if (overrideContentType)
655         request.setOverrideContentType(overrideContentType);
656
657     if (data)
658         request.setHTTPBody(FormData::create(data, dataLength));
659
660     for (unsigned i = 0; i + 1 < headersLength; i += 2)
661         request.addHTTPHeaderField(headers[i], headers[i + 1]);
662
663     if (forceDownload)
664         request.setForceDownload(true);
665
666     request.setSuggestedSaveName(suggestedSaveName);
667
668     m_mainFrame->loader()->load(request, "" /* name */, false);
669 }
670
671 void WebPage::load(const char* url, const char* networkToken, bool isInitial)
672 {
673     d->load(url, networkToken, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, isInitial, false);
674 }
675
676 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)
677 {
678     d->load(url, networkToken, method, cachePolicy, data, dataLength, headers, headersLength, false, mustHandleInternally, false, "");
679 }
680
681 void WebPage::loadFile(const char* path, const char* overrideContentType)
682 {
683     std::string fileUrl(path);
684     if (!fileUrl.find("/"))
685         fileUrl.insert(0, "file://");
686     else if (fileUrl.find("file:///"))
687         return;
688
689     d->load(fileUrl.c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, false, overrideContentType);
690 }
691
692 void WebPage::download(const Platform::NetworkRequest& request)
693 {
694     vector<const char*> headers;
695     Platform::NetworkRequest::HeaderList& list = request.getHeaderListRef();
696     for (unsigned i = 0; i < list.size(); i++) {
697         headers.push_back(list[i].first.c_str());
698         headers.push_back(list[i].second.c_str());
699     }
700     d->load(request.getUrlRef().c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, headers.empty() ? 0 : &headers[0], headers.size(), false, false, true, "", request.getSuggestedSaveName().c_str());
701 }
702
703 void WebPagePrivate::loadString(const char* string, const char* baseURL, const char* contentType, const char* failingURL)
704 {
705     KURL kurl = parseUrl(baseURL);
706     ResourceRequest request(kurl);
707     WTF::RefPtr<SharedBuffer> buffer
708         = SharedBuffer::create(string, strlen(string));
709     SubstituteData substituteData(buffer,
710                                   extractMIMETypeFromMediaType(contentType),
711                                   extractCharsetFromMediaType(contentType),
712                                   failingURL ? parseUrl(failingURL) : KURL());
713     m_mainFrame->loader()->load(request, substituteData, false);
714 }
715
716 void WebPage::loadString(const char* string, const char* baseURL, const char* mimeType, const char* failingURL)
717 {
718     d->loadString(string, baseURL, mimeType, failingURL);
719 }
720
721 bool WebPagePrivate::executeJavaScript(const char* scriptUTF8, JavaScriptDataType& returnType, WebString& returnValue)
722 {
723     String script = String::fromUTF8(scriptUTF8);
724
725     if (script.isNull()) {
726         returnType = JSException;
727         return false;
728     }
729
730     if (script.isEmpty()) {
731         returnType = JSUndefined;
732         return true;
733     }
734
735     ScriptValue result = m_mainFrame->script()->executeScript(script, false);
736     JSC::JSValue value = result.jsValue();
737     if (!value) {
738         returnType = JSException;
739         return false;
740     }
741
742     JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
743     JSGlobalContextRef context = toGlobalRef(exec);
744
745     JSType type = JSValueGetType(context, toRef(exec, value));
746
747     switch (type) {
748     case kJSTypeNull:
749         returnType = JSNull;
750         break;
751     case kJSTypeBoolean:
752         returnType = JSBoolean;
753         break;
754     case kJSTypeNumber:
755         returnType = JSNumber;
756         break;
757     case kJSTypeString:
758         returnType = JSString;
759         break;
760     case kJSTypeObject:
761         returnType = JSObject;
762         break;
763     case kJSTypeUndefined:
764     default:
765         returnType = JSUndefined;
766         break;
767     }
768
769     if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
770         String str = result.toString(exec);
771         returnValue = WebString(str.impl());
772     }
773
774     return true;
775 }
776
777 bool WebPage::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
778 {
779     return d->executeJavaScript(script, returnType, returnValue);
780 }
781
782 bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& sourceCode, JavaScriptDataType& returnType, WebString& returnValue)
783 {
784     if (!m_isolatedWorld)
785         m_isolatedWorld = m_mainFrame->script()->createWorld();
786
787     // Use evaluateInWorld to avoid canExecuteScripts check.
788     ScriptValue result = m_mainFrame->script()->evaluateInWorld(sourceCode, m_isolatedWorld.get());
789     JSC::JSValue value = result.jsValue();
790     if (!value) {
791         returnType = JSException;
792         return false;
793     }
794
795     JSC::ExecState* exec = m_mainFrame->script()->globalObject(m_isolatedWorld.get())->globalExec();
796     JSGlobalContextRef context = toGlobalRef(exec);
797
798     JSType type = JSValueGetType(context, toRef(exec, value));
799
800     switch (type) {
801     case kJSTypeNull:
802         returnType = JSNull;
803         break;
804     case kJSTypeBoolean:
805         returnType = JSBoolean;
806         break;
807     case kJSTypeNumber:
808         returnType = JSNumber;
809         break;
810     case kJSTypeString:
811         returnType = JSString;
812         break;
813     case kJSTypeObject:
814         returnType = JSObject;
815         break;
816     case kJSTypeUndefined:
817     default:
818         returnType = JSUndefined;
819         break;
820     }
821
822     if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
823         String str = result.toString(exec);
824         returnValue = WebString(str.impl());
825     }
826
827     return true;
828 }
829
830 bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, WebString& returnValue)
831 {
832     // On our platform wchar_t is unsigned int and UChar is unsigned short
833     // so we have to convert using ICU conversion function
834     int lengthCopied = 0;
835     UErrorCode error = U_ZERO_ERROR;
836     const int length = script.length() + 1 /*null termination char*/;
837     UChar data[length];
838
839     // FIXME: PR 138162 is giving U_INVALID_CHAR_FOUND error.
840     u_strFromUTF32(data, length, &lengthCopied, reinterpret_cast<const UChar32*>(script.c_str()), script.length(), &error);
841     BLACKBERRY_ASSERT(error == U_ZERO_ERROR);
842     if (error != U_ZERO_ERROR) {
843         Platform::logAlways(Platform::LogLevelCritical, "WebPage::executeJavaScriptInIsolatedWorld failed to convert UTF16 to JavaScript!");
844         return false;
845     }
846     String str = String(data, lengthCopied);
847     ScriptSourceCode sourceCode(str, KURL());
848     return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
849 }
850
851 bool WebPage::executeJavaScriptInIsolatedWorld(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
852 {
853     ScriptSourceCode sourceCode(String::fromUTF8(script), KURL());
854     return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
855 }
856
857 void WebPage::executeJavaScriptFunction(const std::vector<std::string> &function, const std::vector<JavaScriptVariant> &args, JavaScriptVariant& returnValue)
858 {
859     if (!d->m_mainFrame) {
860         returnValue.setType(JavaScriptVariant::Exception);
861         return;
862     }
863
864     JSC::Bindings::RootObject* root = d->m_mainFrame->script()->bindingRootObject();
865     if (!root) {
866         returnValue.setType(JavaScriptVariant::Exception);
867         return;
868     }
869
870     JSC::ExecState* exec = root->globalObject()->globalExec();
871     JSGlobalContextRef ctx = toGlobalRef(exec);
872
873     WTF::Vector<JSValueRef> argListRef(args.size());
874     for (unsigned i = 0; i < args.size(); ++i)
875         argListRef[i] = BlackBerryJavaScriptVariantToJSValueRef(ctx, args[i]);
876
877     JSValueRef windowObjectValue = windowObject();
878     JSObjectRef obj = JSValueToObject(ctx, windowObjectValue, 0);
879     JSObjectRef thisObject = obj;
880     for (unsigned i = 0; i < function.size(); ++i) {
881         JSStringRef str = JSStringCreateWithUTF8CString(function[i].c_str());
882         thisObject = obj;
883         obj = JSValueToObject(ctx, JSObjectGetProperty(ctx, obj, str, 0), 0);
884         JSStringRelease(str);
885         if (!obj)
886             break;
887     }
888
889     JSObjectRef functionObject = obj;
890     JSValueRef result = 0;
891     if (functionObject && thisObject)
892         result = JSObjectCallAsFunction(ctx, functionObject, thisObject, args.size(), argListRef.data(), 0);
893
894     if (!result) {
895         returnValue.setType(JavaScriptVariant::Exception);
896         return;
897     }
898
899     returnValue = JSValueRefToBlackBerryJavaScriptVariant(ctx, result);
900 }
901
902 void WebPagePrivate::stopCurrentLoad()
903 {
904     // This function should contain all common code triggered by WebPage::load
905     // (which stops any load in progress before starting the new load) and
906     // WebPage::stoploading (the entry point for the client to stop the load
907     // explicitly). If it should only be done while stopping the load
908     // explicitly, it goes in WebPage::stopLoading, not here.
909     m_mainFrame->loader()->stopAllLoaders();
910
911     // Cancel any deferred script that hasn't been processed yet.
912     DeferredTaskLoadManualScript::finishOrCancel(this);
913 }
914
915 void WebPage::stopLoading()
916 {
917     d->stopCurrentLoad();
918 }
919
920 static void closeURLRecursively(Frame* frame)
921 {
922     // Do not create more frame please.
923     FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client());
924     frameLoaderClient->suppressChildFrameCreation();
925
926     frame->loader()->closeURL();
927
928     Vector<RefPtr<Frame>, 10> childFrames;
929
930     for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
931         childFrames.append(childFrame);
932
933     unsigned size = childFrames.size();
934     for (unsigned i = 0; i < size; i++)
935         closeURLRecursively(childFrames[i].get());
936 }
937
938 void WebPagePrivate::prepareToDestroy()
939 {
940     // Before the client starts tearing itself down, dispatch the unload event
941     // so it can take effect while all the client's state (e.g. scroll position)
942     // is still present.
943     closeURLRecursively(m_mainFrame);
944 }
945
946 void WebPage::prepareToDestroy()
947 {
948     d->prepareToDestroy();
949 }
950
951 bool WebPage::dispatchBeforeUnloadEvent()
952 {
953     return d->m_page->mainFrame()->loader()->shouldClose();
954 }
955
956 static void enableCrossSiteXHRRecursively(Frame* frame)
957 {
958     frame->document()->securityOrigin()->grantUniversalAccess();
959
960     Vector<RefPtr<Frame>, 10> childFrames;
961     for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
962         childFrames.append(childFrame);
963
964     unsigned size = childFrames.size();
965     for (unsigned i = 0; i < size; i++)
966         enableCrossSiteXHRRecursively(childFrames[i].get());
967 }
968
969 void WebPagePrivate::enableCrossSiteXHR()
970 {
971     enableCrossSiteXHRRecursively(m_mainFrame);
972 }
973
974 void WebPage::enableCrossSiteXHR()
975 {
976     d->enableCrossSiteXHR();
977 }
978
979 void WebPagePrivate::addOriginAccessWhitelistEntry(const char* sourceOrigin, const char* destinationOrigin, bool allowDestinationSubdomains)
980 {
981     RefPtr<SecurityOrigin> source = SecurityOrigin::createFromString(sourceOrigin);
982     if (source->isUnique())
983         return;
984
985     KURL destination(KURL(), destinationOrigin);
986     SecurityPolicy::addOriginAccessWhitelistEntry(*source, destination.protocol(), destination.host(), allowDestinationSubdomains);
987 }
988
989 void WebPage::addOriginAccessWhitelistEntry(const char* sourceOrigin, const char* destinationOrigin, bool allowDestinationSubdomains)
990 {
991     d->addOriginAccessWhitelistEntry(sourceOrigin, destinationOrigin, allowDestinationSubdomains);
992 }
993
994 void WebPagePrivate::removeOriginAccessWhitelistEntry(const char* sourceOrigin, const char* destinationOrigin, bool allowDestinationSubdomains)
995 {
996     RefPtr<SecurityOrigin> source = SecurityOrigin::createFromString(sourceOrigin);
997     if (source->isUnique())
998         return;
999
1000     KURL destination(KURL(), destinationOrigin);
1001     SecurityPolicy::removeOriginAccessWhitelistEntry(*source, destination.protocol(), destination.host(), allowDestinationSubdomains);
1002 }
1003
1004 void WebPage::removeOriginAccessWhitelistEntry(const char* sourceOrigin, const char* destinationOrigin, bool allowDestinationSubdomains)
1005 {
1006     d->removeOriginAccessWhitelistEntry(sourceOrigin, destinationOrigin, allowDestinationSubdomains);
1007 }
1008
1009 void WebPagePrivate::setLoadState(LoadState state)
1010 {
1011     if (m_loadState == state)
1012         return;
1013
1014     bool isFirstLoad = m_loadState == None;
1015
1016     // See RIM Bug #1068.
1017     if (state == Finished && m_mainFrame && m_mainFrame->document())
1018         m_mainFrame->document()->updateStyleIfNeeded();
1019
1020     m_loadState = state;
1021
1022 #if DEBUG_WEBPAGE_LOAD
1023     Platform::log(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state);
1024 #endif
1025
1026     switch (m_loadState) {
1027     case Provisional:
1028         if (isFirstLoad) {
1029             // Paints the visible backingstore as white to prevent initial checkerboard on
1030             // the first blit.
1031             if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
1032                 m_backingStore->d->blitVisibleContents();
1033         }
1034         break;
1035     case Committed:
1036         {
1037             unscheduleZoomAboutPoint();
1038
1039 #if ENABLE(ACCELERATED_2D_CANVAS)
1040             if (m_page->settings()->canvasUsesAcceleratedDrawing()) {
1041                 // Free GPU resources as we're on a new page.
1042                 // This will help us to free memory pressure.
1043                 SharedGraphicsContext3D::get()->makeContextCurrent();
1044                 GrContext* grContext = Platform::Graphics::getGrContext();
1045                 grContext->freeGpuResources();
1046             }
1047 #endif
1048
1049 #if USE(ACCELERATED_COMPOSITING)
1050             releaseLayerResources();
1051 #endif
1052
1053             // Suspend screen update to avoid ui thread blitting while resetting backingstore.
1054             m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1055
1056             m_previousContentsSize = IntSize();
1057             m_backingStore->d->resetRenderQueue();
1058             m_backingStore->d->resetTiles(true /* resetBackground */);
1059             m_backingStore->d->setScrollingOrZooming(false, false /* shouldBlit */);
1060             m_shouldZoomToInitialScaleAfterLoadFinished = false;
1061             m_userPerformedManualZoom = false;
1062             m_userPerformedManualScroll = false;
1063             m_shouldUseFixedDesktopMode = false;
1064             if (m_resetVirtualViewportOnCommitted) { // For DRT.
1065                 m_virtualViewportWidth = 0;
1066                 m_virtualViewportHeight = 0;
1067             }
1068             if (m_webSettings->viewportWidth() > 0) {
1069                 m_virtualViewportWidth = m_webSettings->viewportWidth();
1070                 m_virtualViewportHeight = m_defaultLayoutSize.height();
1071             }
1072             // Check if we have already process the meta viewport tag, this only happens on history navigation.
1073             // For back/forward history navigation, we should only keep these previous values if the document
1074             // has the meta viewport tag when the state is Committed in setLoadState.
1075             static ViewportArguments defaultViewportArguments;
1076             bool documentHasViewportArguments = false;
1077             if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->viewportArguments() != defaultViewportArguments)
1078                 documentHasViewportArguments = true;
1079             if (!(m_didRestoreFromPageCache && documentHasViewportArguments)) {
1080                 m_viewportArguments = ViewportArguments();
1081                 m_userScalable = m_webSettings->isUserScalable();
1082                 resetScales();
1083
1084                 // At the moment we commit a new load, set the viewport arguments
1085                 // to any fallback values. If there is a meta viewport in the
1086                 // content it will overwrite the fallback arguments soon.
1087                 dispatchViewportPropertiesDidChange(m_userViewportArguments);
1088             } else {
1089                 IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
1090                 m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
1091             }
1092
1093 #if ENABLE(EVENT_MODE_METATAGS)
1094             didReceiveCursorEventMode(ProcessedCursorEvents);
1095             didReceiveTouchEventMode(ProcessedTouchEvents);
1096 #endif
1097
1098             // Reset block zoom and reflow.
1099             resetBlockZoom();
1100 #if ENABLE(VIEWPORT_REFLOW)
1101             toggleTextReflowIfEnabledForBlockZoomOnly();
1102 #endif
1103
1104             // Notify InputHandler of state change.
1105             m_inputHandler->setInputModeEnabled(false);
1106
1107             // Set the scroll to origin here and notify the client since we'll be
1108             // zooming below without any real contents yet thus the contents size
1109             // we report to the client could make our current scroll position invalid.
1110             setScrollPosition(IntPoint::zero());
1111             notifyTransformedScrollChanged();
1112
1113             m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1114
1115             // Paints the visible backingstore as white. Note it is important we do
1116             // this strictly after re-setting the scroll position to origin and resetting
1117             // the scales otherwise the visible contents calculation is wrong and we
1118             // can end up blitting artifacts instead. See: RIM Bug #401.
1119             if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
1120                 m_backingStore->d->blitVisibleContents();
1121
1122             zoomToInitialScaleOnLoad();
1123
1124             // Update cursor status.
1125             updateCursor();
1126
1127 #if USE(ACCELERATED_COMPOSITING)
1128             // Don't render compositing contents from previous page.
1129             resetCompositingSurface();
1130 #endif
1131             break;
1132         }
1133     case Finished:
1134     case Failed:
1135         // Notify client of the initial zoom change.
1136         m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1137         m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
1138         break;
1139     default:
1140         break;
1141     }
1142 }
1143
1144 double WebPagePrivate::clampedScale(double scale) const
1145 {
1146     if (scale < minimumScale())
1147         return minimumScale();
1148     if (scale > maximumScale())
1149         return maximumScale();
1150     return scale;
1151 }
1152
1153 bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale)
1154 {
1155     if (!m_mainFrame->view())
1156         return false;
1157
1158     if (enforceScaleClamping)
1159         scale = this->clampedScale(scale);
1160
1161     ASSERT(clampedScale);
1162     *clampedScale = scale;
1163
1164     if (currentScale() == scale) {
1165         m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1166         return false;
1167     }
1168
1169     return true;
1170 }
1171
1172 bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel)
1173 {
1174     if (!isRestoringZoomLevel) {
1175         // Clear any existing block zoom.  (If we are restoring a saved zoom level on page load,
1176         // there is guaranteed to be no existing block zoom and we don't want to clear m_shouldReflowBlock.)
1177         resetBlockZoom();
1178     }
1179
1180     // The reflow and block zoom stuff here needs to happen regardless of
1181     // whether we shouldZoomAboutPoint.
1182 #if ENABLE(VIEWPORT_REFLOW)
1183     toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
1184     if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view())
1185         setNeedsLayout();
1186 #endif
1187
1188     double scale;
1189     if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1190         if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1191             m_currentPinchZoomNode = 0;
1192             m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1193         }
1194         return false;
1195     }
1196     TransformationMatrix zoom;
1197     zoom.scale(scale);
1198
1199 #if DEBUG_WEBPAGE_LOAD
1200     if (loadState() < Finished)
1201         Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomAboutPoint scale %f anchor (%f, %f)", scale, anchor.x(), anchor.y());
1202 #endif
1203
1204     // Our current scroll position in float.
1205     FloatPoint scrollPosition = this->scrollPosition();
1206
1207     // Anchor offset from scroll position in float.
1208     FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y());
1209
1210     // The horizontal scaling factor and vertical scaling factor should be equal
1211     // to preserve aspect ratio of content.
1212     ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22());
1213
1214     // Need to invert the previous transform to anchor the viewport.
1215     double inverseScale = scale / m_transformationMatrix->m11();
1216
1217     // Actual zoom.
1218     *m_transformationMatrix = zoom;
1219
1220     // Suspend all screen updates to the backingstore.
1221     m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1222
1223     updateViewportSize();
1224
1225     IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))),
1226                                         max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale)))));
1227
1228     if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1229         // This is a hack for email which has reflow always turned on.
1230         m_mainFrame->view()->setNeedsLayout();
1231         requestLayoutIfNeeded();
1232         if (m_currentPinchZoomNode)
1233             newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale);
1234          m_currentPinchZoomNode = 0;
1235          m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1236     }
1237
1238     setScrollPosition(newScrollPosition);
1239
1240     notifyTransformChanged();
1241
1242     bool isLoading = this->isLoading();
1243
1244     // We need to invalidate all tiles both visible and non-visible if we're loading.
1245     m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */);
1246
1247     m_client->resetBitmapZoomScale(m_transformationMatrix->m11());
1248
1249     bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering;
1250     bool shouldClearVisibleZoom = isLoading && shouldRender;
1251
1252     if (shouldClearVisibleZoom) {
1253         // If we are loading and rendering then we need to clear the render queue's
1254         // visible zoom jobs as they will be irrelevant with the render below.
1255         m_backingStore->d->clearVisibleZoom();
1256     }
1257
1258     // Clear window to make sure there are no artifacts.
1259     if (shouldRender) {
1260         // Resume all screen updates to the backingstore and render+blit visible contents to screen.
1261         m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
1262     } else {
1263         // Resume all screen updates to the backingstore but do not blit to the screen because we not rendering.
1264         m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1265     }
1266
1267     m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1268
1269     return true;
1270 }
1271
1272 IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale)
1273 {
1274     // Should only be invoked when text reflow is enabled.
1275     ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
1276
1277     int offsetY = 0;
1278     int offsetX = 0;
1279
1280     IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
1281
1282     if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) {
1283         offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y();
1284         if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0)
1285             offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale;
1286     }
1287
1288     IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get());
1289
1290     return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))),
1291                     max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale))));
1292 }
1293
1294 bool WebPagePrivate::scheduleZoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering)
1295 {
1296     double scale;
1297     if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1298         // We could be back to the right zoom level before the timer has
1299         // timed out, because of wiggling back and forth. Stop the timer.
1300         unscheduleZoomAboutPoint();
1301         return false;
1302     }
1303
1304     // For some reason, the bitmap zoom wants an anchor in backingstore coordinates!
1305     // this is different from zoomAboutPoint, which wants content coordinates.
1306     // See RIM Bug #641.
1307
1308     FloatPoint transformedAnchor = mapToTransformedFloatPoint(anchor);
1309     FloatPoint transformedScrollPosition = mapToTransformedFloatPoint(scrollPosition());
1310
1311     // Prohibit backingstore from updating the window overtop of the bitmap.
1312     m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1313
1314     // Need to invert the previous transform to anchor the viewport.
1315     double zoomFraction = scale / transformationMatrix()->m11();
1316
1317     // Anchor offset from scroll position in float.
1318     FloatPoint anchorOffset(transformedAnchor.x() - transformedScrollPosition.x(),
1319                             transformedAnchor.y() - transformedScrollPosition.y());
1320
1321     IntPoint srcPoint(
1322         static_cast<int>(roundf(transformedAnchor.x() - anchorOffset.x() / zoomFraction)),
1323         static_cast<int>(roundf(transformedAnchor.y() - anchorOffset.y() / zoomFraction)));
1324
1325     const IntRect viewportRect = IntRect(IntPoint::zero(), transformedViewportSize());
1326     const IntRect dstRect = viewportRect;
1327
1328     // This is the rect to pass as the actual source rect in the backingstore
1329     // for the transform given by zoom.
1330     IntRect srcRect(srcPoint.x(),
1331                     srcPoint.y(),
1332                     viewportRect.width() / zoomFraction,
1333                     viewportRect.height() / zoomFraction);
1334     m_backingStore->d->blitContents(dstRect, srcRect);
1335
1336     m_delayedZoomArguments.scale = scale;
1337     m_delayedZoomArguments.anchor = anchor;
1338     m_delayedZoomArguments.enforceScaleClamping = enforceScaleClamping;
1339     m_delayedZoomArguments.forceRendering = forceRendering;
1340     m_delayedZoomTimer->startOneShot(delayedZoomInterval);
1341
1342     return true;
1343 }
1344
1345 void WebPagePrivate::unscheduleZoomAboutPoint()
1346 {
1347     if (m_delayedZoomTimer->isActive())
1348         m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1349
1350     m_delayedZoomTimer->stop();
1351 }
1352
1353 void WebPagePrivate::zoomAboutPointTimerFired(Timer<WebPagePrivate>*)
1354 {
1355     zoomAboutPoint(m_delayedZoomArguments.scale, m_delayedZoomArguments.anchor, m_delayedZoomArguments.enforceScaleClamping, m_delayedZoomArguments.forceRendering);
1356     m_backingStore->d->resumeScreenAndBackingStoreUpdates(m_delayedZoomArguments.forceRendering ? BackingStore::RenderAndBlit : BackingStore::None);
1357 }
1358
1359 void WebPagePrivate::setNeedsLayout()
1360 {
1361     FrameView* view = m_mainFrame->view();
1362     ASSERT(view);
1363     view->setNeedsLayout();
1364 }
1365
1366 void WebPagePrivate::requestLayoutIfNeeded() const
1367 {
1368     FrameView* view = m_mainFrame->view();
1369     ASSERT(view);
1370     view->updateLayoutAndStyleIfNeededRecursive();
1371     ASSERT(!view->needsLayout());
1372 }
1373
1374 IntPoint WebPagePrivate::scrollPosition() const
1375 {
1376     return m_backingStoreClient->scrollPosition();
1377 }
1378
1379 IntPoint WebPagePrivate::maximumScrollPosition() const
1380 {
1381     return m_backingStoreClient->maximumScrollPosition();
1382 }
1383
1384 void WebPagePrivate::setScrollPosition(const IntPoint& pos)
1385 {
1386     m_backingStoreClient->setScrollPosition(pos);
1387 }
1388
1389 // Setting the scroll position is in transformed coordinates.
1390 void WebPage::setScrollPosition(const Platform::IntPoint& point)
1391 {
1392     if (d->transformedPointEqualsUntransformedPoint(point, d->scrollPosition()))
1393         return;
1394
1395     // If the user recently performed an event, this new scroll position
1396     // could possibly be a result of that. Or not, this is just a heuristic.
1397     if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
1398         d->m_userPerformedManualScroll = true;
1399
1400     d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1401
1402     // UI thread can call BackingStorePrivate::setScrollingOrZooming(false) before WebKit thread calls WebPage::setScrollPosition(),
1403     // in which case it will set ScrollableArea::m_constrainsScrollingToContentEdge to true earlier.
1404     // We can cache ScrollableArea::m_constrainsScrollingToContentEdge and always set it to false before we set scroll position in
1405     // WebKit thread to avoid scroll position clamping during scrolling, and restore it to what it was after that.
1406     bool constrainsScrollingToContentEdge = d->m_mainFrame->view()->constrainsScrollingToContentEdge();
1407     d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(false);
1408     d->setScrollPosition(d->mapFromTransformed(point));
1409     d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge);
1410
1411     d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1412 }
1413
1414 bool WebPagePrivate::shouldSendResizeEvent()
1415 {
1416     if (!m_mainFrame->document())
1417         return false;
1418
1419     // PR#96865 : Provide an option to always send resize events, regardless of the loading
1420     //            status. The scenario for this are Sapphire applications which tend to
1421     //            maintain an open GET request to the server. This open GET results in
1422     //            webkit thinking that content is still arriving when at the application
1423     //            level it is considered fully loaded.
1424     //
1425     //            NOTE: Care must be exercised in the use of this option, as it bypasses
1426     //                  the sanity provided in 'isLoadingInAPISense()' below.
1427     //
1428     static const bool unrestrictedResizeEvents = Platform::Settings::instance()->unrestrictedResizeEvents();
1429     if (unrestrictedResizeEvents)
1430         return true;
1431
1432     // Don't send the resize event if the document is loading. Some pages automatically reload
1433     // when the window is resized; Safari on iPhone often resizes the window while setting up its
1434     // viewport. This obviously can cause problems.
1435     DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
1436     if (documentLoader && documentLoader->isLoadingInAPISense())
1437         return false;
1438
1439     return true;
1440 }
1441
1442 void WebPagePrivate::willDeferLoading()
1443 {
1444     m_deferredTasksTimer.stop();
1445     m_client->willDeferLoading();
1446 }
1447
1448 void WebPagePrivate::didResumeLoading()
1449 {
1450     if (!m_deferredTasks.isEmpty())
1451         m_deferredTasksTimer.startOneShot(0);
1452     m_client->didResumeLoading();
1453 }
1454
1455 void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*)
1456 {
1457     ASSERT(!m_deferredTasks.isEmpty());
1458     if (!m_deferredTasks.isEmpty())
1459         return;
1460
1461     OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release();
1462     m_deferredTasks.remove(0);
1463
1464     if (!m_deferredTasks.isEmpty())
1465         m_deferredTasksTimer.startOneShot(0);
1466
1467     task->perform(this);
1468 }
1469
1470 void WebPagePrivate::scrollBy(int deltaX, int deltaY)
1471 {
1472     IntSize delta(deltaX, deltaY);
1473     setScrollPosition(scrollPosition() + delta);
1474 }
1475
1476 void WebPage::scrollBy(const Platform::IntSize& delta)
1477 {
1478     d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1479     d->scrollBy(delta.width(), delta.height());
1480     d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1481 }
1482
1483 void WebPagePrivate::notifyInRegionScrollStopped()
1484 {
1485     if (m_inRegionScroller->d->hasNode()) {
1486         enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(m_inRegionScroller->d->node());
1487         m_inRegionScroller->d->reset();
1488     }
1489 }
1490
1491 void WebPage::notifyInRegionScrollStopped()
1492 {
1493     d->notifyInRegionScrollStopped();
1494 }
1495
1496 void WebPagePrivate::enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(Node* scrolledNode)
1497 {
1498     ASSERT(scrolledNode);
1499     if (scrolledNode->isDocumentNode()) {
1500         Frame* frame = static_cast<const Document*>(scrolledNode)->frame();
1501         ASSERT(frame);
1502         if (!frame)
1503             return;
1504         ASSERT(frame != m_mainFrame);
1505         FrameView* view = frame->view();
1506         if (!view)
1507             return;
1508
1509         // Steps:
1510         // #1 - Get frame rect in contents coords.
1511         // #2 - Get the clipped scrollview rect in contents coords.
1512         // #3 - Take transform into account for 1 and 2.
1513         // #4 - Subtract 2 from 1, so we know exactly which areas of the frame
1514         //      are offscreen, and need async repainting.
1515         FrameView* mainFrameView = m_mainFrame->view();
1516         ASSERT(mainFrameView);
1517         IntRect frameRect = view->frameRect();
1518         frameRect = frame->tree()->parent()->view()->contentsToWindow(frameRect);
1519         frameRect = mainFrameView->windowToContents(frameRect);
1520
1521         IntRect visibleWindowRect = getRecursiveVisibleWindowRect(view);
1522         IntRect visibleContentsRect = mainFrameView->windowToContents(visibleWindowRect);
1523
1524         IntRect transformedFrameRect = mapToTransformed(frameRect);
1525         IntRect transformedVisibleContentsRect = mapToTransformed(visibleContentsRect);
1526
1527         Platform::IntRectRegion offscreenRegionOfIframe
1528             = Platform::IntRectRegion::subtractRegions(Platform::IntRect(transformedFrameRect), Platform::IntRect(transformedVisibleContentsRect));
1529
1530         if (!offscreenRegionOfIframe.isEmpty())
1531             m_backingStore->d->m_renderQueue->addToQueue(RenderQueue::RegularRender, offscreenRegionOfIframe.rects());
1532     }
1533 }
1534
1535 void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
1536 {
1537     if (b != m_hasInRegionScrollableAreas)
1538         m_hasInRegionScrollableAreas = b;
1539 }
1540
1541 IntSize WebPagePrivate::viewportSize() const
1542 {
1543     return mapFromTransformed(transformedViewportSize());
1544 }
1545
1546 IntSize WebPagePrivate::actualVisibleSize() const
1547 {
1548     return mapFromTransformed(transformedActualVisibleSize());
1549 }
1550
1551 bool WebPagePrivate::hasVirtualViewport() const
1552 {
1553     return m_virtualViewportWidth && m_virtualViewportHeight;
1554 }
1555
1556 void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
1557 {
1558     // This checks to make sure we're not calling updateViewportSize
1559     // during WebPagePrivate::init().
1560     if (!m_backingStore)
1561         return;
1562     ASSERT(m_mainFrame->view());
1563     if (setFixedReportedSize)
1564         m_mainFrame->view()->setFixedReportedSize(actualVisibleSize());
1565
1566     IntRect frameRect = IntRect(scrollPosition(), viewportSize());
1567     if (frameRect != m_mainFrame->view()->frameRect()) {
1568         m_mainFrame->view()->setFrameRect(frameRect);
1569         m_mainFrame->view()->adjustViewSize();
1570
1571 #if ENABLE(FULLSCREEN_API)
1572         // If we are in fullscreen video mode, and we change the FrameView::viewportRect,
1573         // we need to adjust the media container to the new size.
1574         if (m_fullscreenVideoNode) {
1575             Document* document = m_fullscreenVideoNode->document();
1576             ASSERT(document);
1577             ASSERT(document->fullScreenRenderer());
1578
1579             int width = m_mainFrame->view()->visibleContentRect().size().width();
1580             document->fullScreenRenderer()->style()->setWidth(Length(width, Fixed));
1581         }
1582 #endif
1583     }
1584
1585     // We're going to need to send a resize event to JavaScript because
1586     // innerWidth and innerHeight depend on fixed reported size.
1587     // This is how we support mobile pages where JavaScript resizes
1588     // the page in order to get around the fixed layout size, e.g.
1589     // google maps when it detects a mobile user agent.
1590     if (sendResizeEvent && shouldSendResizeEvent())
1591         m_mainFrame->eventHandler()->sendResizeEvent();
1592
1593     // When the actual visible size changes, we also
1594     // need to reposition fixed elements.
1595     m_mainFrame->view()->repaintFixedElementsAfterScrolling();
1596 }
1597
1598 FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
1599 {
1600     // The visible contents rect in float.
1601     FloatRect visibleContentsRect = this->visibleContentsRect();
1602
1603     // The center of the visible contents rect in float.
1604     return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
1605                       visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
1606 }
1607
1608 IntRect WebPagePrivate::visibleContentsRect() const
1609 {
1610     return m_backingStoreClient->visibleContentsRect();
1611 }
1612
1613 IntSize WebPagePrivate::contentsSize() const
1614 {
1615     if (!m_mainFrame->view())
1616         return IntSize();
1617
1618     return m_backingStoreClient->contentsSize();
1619 }
1620
1621 IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
1622 {
1623     if (!m_mainFrame->contentRenderer())
1624         return IntSize();
1625
1626     return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
1627 }
1628
1629 void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
1630 {
1631     if (m_previousContentsSize == contentsSize)
1632         return;
1633
1634     // This should only occur in the middle of layout so we set a flag here and
1635     // handle it at the end of the layout.
1636     m_contentsSizeChanged = true;
1637
1638 #if DEBUG_WEBPAGE_LOAD
1639     Platform::log(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %dx%d", contentsSize.width(), contentsSize.height());
1640 #endif
1641 }
1642
1643 void WebPagePrivate::layoutFinished()
1644 {
1645     if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
1646         return;
1647
1648     m_contentsSizeChanged = false; // Toggle to turn off notification again.
1649     m_overflowExceedsContentsSize = false;
1650
1651     if (contentsSize().isEmpty())
1652         return;
1653
1654     // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from
1655     // the middle of a layout, but the recursion is limited by detection code in
1656     // setViewMode() and mitigation code in fixedLayoutSize().
1657     if (didLayoutExceedMaximumIterations()) {
1658         notifyTransformedContentsSizeChanged();
1659         return;
1660     }
1661
1662     // Temporarily save the m_previousContentsSize here before updating it (in
1663     // notifyTransformedContentsSizeChanged()) so we can compare if our contents
1664     // shrunk afterwards.
1665     IntSize previousContentsSize = m_previousContentsSize;
1666
1667     m_nestedLayoutFinishedCount++;
1668
1669     if (shouldZoomToInitialScaleOnLoad()) {
1670         zoomToInitialScaleOnLoad();
1671         m_shouldZoomToInitialScaleAfterLoadFinished = false;
1672     } else if (loadState() != None)
1673         notifyTransformedContentsSizeChanged();
1674
1675     m_nestedLayoutFinishedCount--;
1676
1677     if (!m_nestedLayoutFinishedCount) {
1678         // When the contents shrinks, there is a risk that we
1679         // will be left at a scroll position that lies outside of the
1680         // contents rect. Since we allow overscrolling and neglect
1681         // to clamp overscroll in order to retain input focus (RIM Bug #414)
1682         // we need to clamp somewhere, and this is where we know the
1683         // contents size has changed.
1684
1685         if (contentsSize() != previousContentsSize) {
1686
1687             IntPoint newScrollPosition = scrollPosition();
1688
1689             if (contentsSize().height() < previousContentsSize.height()) {
1690                 IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
1691                 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
1692             }
1693
1694             if (contentsSize().width() < previousContentsSize.width()) {
1695                 IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
1696                 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
1697             }
1698
1699             if (newScrollPosition != scrollPosition()) {
1700                 setScrollPosition(newScrollPosition);
1701                 notifyTransformedScrollChanged();
1702             }
1703         }
1704     }
1705 }
1706
1707 void WebPagePrivate::zoomToInitialScaleOnLoad()
1708 {
1709 #if DEBUG_WEBPAGE_LOAD
1710     Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
1711 #endif
1712
1713     bool needsLayout = false;
1714
1715     // If the contents width exceeds the viewport width set to desktop mode.
1716     if (m_shouldUseFixedDesktopMode)
1717         needsLayout = setViewMode(FixedDesktop);
1718     else
1719         needsLayout = setViewMode(Desktop);
1720
1721     if (needsLayout) {
1722         // This can cause recursive layout...
1723         setNeedsLayout();
1724     }
1725
1726     if (contentsSize().isEmpty()) {
1727 #if DEBUG_WEBPAGE_LOAD
1728         Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
1729 #endif
1730         requestLayoutIfNeeded();
1731         m_client->resetBitmapZoomScale(currentScale());
1732         notifyTransformedContentsSizeChanged();
1733         return;
1734     }
1735
1736     bool performedZoom = false;
1737     bool shouldZoom = !m_userPerformedManualZoom;
1738
1739     // If this is a back/forward type navigation, don't zoom to initial scale
1740     // but instead let the HistoryItem's saved viewport reign supreme.
1741     if (m_mainFrame && m_mainFrame->loader() && isBackForwardLoadType(m_mainFrame->loader()->loadType()))
1742         shouldZoom = false;
1743
1744     if (shouldZoom && shouldZoomToInitialScaleOnLoad()) {
1745         // Preserve at top and at left position, to avoid scrolling
1746         // to a non top-left position for web page with viewport meta tag
1747         // that specifies an initial-scale that is zoomed in.
1748         FloatPoint anchor = centerOfVisibleContentsRect();
1749         if (!scrollPosition().x())
1750             anchor.setX(0);
1751         if (!scrollPosition().y())
1752             anchor.setY(0);
1753         performedZoom = zoomAboutPoint(initialScale(), anchor);
1754     }
1755
1756     // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout...
1757     requestLayoutIfNeeded();
1758
1759     if (!performedZoom) {
1760         // We only notify if we didn't perform zoom, because zoom will notify on
1761         // its own...
1762         m_client->resetBitmapZoomScale(currentScale());
1763         notifyTransformedContentsSizeChanged();
1764     }
1765 }
1766
1767 double WebPagePrivate::zoomToFitScale() const
1768 {
1769     int contentWidth = contentsSize().width();
1770     int contentHeight = contentsSize().height();
1771     double zoomToFitScale = contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
1772     if (contentHeight * zoomToFitScale < static_cast<double>(m_defaultLayoutSize.height()))
1773         zoomToFitScale = contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
1774
1775     return std::max(zoomToFitScale, minimumZoomToFitScale);
1776 }
1777
1778 double WebPage::zoomToFitScale() const
1779 {
1780     return d->zoomToFitScale();
1781 }
1782
1783 double WebPagePrivate::initialScale() const
1784 {
1785     if (m_initialScale > 0.0)
1786         return m_initialScale;
1787
1788     if (m_webSettings->isZoomToFitOnLoad())
1789         return zoomToFitScale();
1790
1791     return 1.0;
1792 }
1793
1794 double WebPage::initialScale() const
1795 {
1796     return d->initialScale();
1797 }
1798
1799 void WebPage::initializeIconDataBase()
1800 {
1801     IconDatabaseClientBlackBerry::getInstance()->initIconDatabase(d->m_webSettings);
1802 }
1803
1804 bool WebPage::isUserScalable() const
1805 {
1806     return d->isUserScalable();
1807 }
1808
1809 void WebPage::setUserScalable(bool userScalable)
1810 {
1811     d->setUserScalable(userScalable);
1812 }
1813
1814 double WebPage::currentScale() const
1815 {
1816     return d->currentScale();
1817 }
1818
1819 void WebPage::setInitialScale(double initialScale)
1820 {
1821     d->setInitialScale(initialScale);
1822 }
1823
1824 double WebPage::minimumScale() const
1825 {
1826     return d->minimumScale();
1827 }
1828
1829 void WebPage::setMinimumScale(double minimumScale)
1830 {
1831     d->setMinimumScale(minimumScale);
1832 }
1833
1834 void WebPage::setMaximumScale(double maximumScale)
1835 {
1836     d->setMaximumScale(maximumScale);
1837 }
1838
1839 double WebPagePrivate::maximumScale() const
1840 {
1841     if (m_maximumScale >= zoomToFitScale() && m_maximumScale >= m_minimumScale)
1842         return m_maximumScale;
1843
1844     return hasVirtualViewport() ? std::max<double>(zoomToFitScale(), 4.0) : 4.0;
1845 }
1846
1847 double WebPage::maximumScale() const
1848 {
1849     return d->maximumScale();
1850 }
1851
1852 void WebPagePrivate::resetScales()
1853 {
1854     TransformationMatrix identity;
1855     *m_transformationMatrix = identity;
1856     m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0;
1857     m_minimumScale = -1.0;
1858     m_maximumScale = -1.0;
1859
1860     // We have to let WebCore know about updated framerect now that we've
1861     // reset our scales. See: RIM Bug #401.
1862     updateViewportSize();
1863 }
1864
1865 IntPoint WebPagePrivate::transformedScrollPosition() const
1866 {
1867     return m_backingStoreClient->transformedScrollPosition();
1868 }
1869
1870 // Returned scroll position is in transformed coordinates.
1871 Platform::IntPoint WebPage::scrollPosition() const
1872 {
1873     return d->transformedScrollPosition();
1874 }
1875
1876 IntPoint WebPagePrivate::transformedMaximumScrollPosition() const
1877 {
1878     return m_backingStoreClient->transformedMaximumScrollPosition();
1879 }
1880
1881 IntSize WebPagePrivate::transformedActualVisibleSize() const
1882 {
1883     return IntSize(m_actualVisibleWidth, m_actualVisibleHeight);
1884 }
1885
1886 Platform::IntSize WebPage::viewportSize() const
1887 {
1888     return d->transformedActualVisibleSize();
1889 }
1890
1891 IntSize WebPagePrivate::transformedViewportSize() const
1892 {
1893     return Platform::Graphics::Screen::primaryScreen()->size();
1894 }
1895
1896 IntRect WebPagePrivate::transformedVisibleContentsRect() const
1897 {
1898     // Usually this would be mapToTransformed(visibleContentsRect()), but
1899     // that results in rounding errors because we already set the WebCore
1900     // viewport size from our original transformedViewportSize().
1901     // Instead, we only transform the scroll position and take the
1902     // viewport size as it is, which ensures that e.g. blitting operations
1903     // always cover the whole widget/screen.
1904     return IntRect(transformedScrollPosition(), transformedViewportSize());
1905 }
1906
1907 IntSize WebPagePrivate::transformedContentsSize() const
1908 {
1909     // mapToTransformed() functions use this method to crop their results,
1910     // so we can't make use of them here. While we want rounding inside page
1911     // boundaries to extend rectangles and round points, we need to crop the
1912     // contents size to the floored values so that we don't try to display
1913     // or report points that are not fully covered by the actual float-point
1914     // contents rectangle.
1915     const IntSize untransformedContentsSize = contentsSize();
1916     const FloatPoint transformedBottomRight = m_transformationMatrix->mapPoint(
1917         FloatPoint(untransformedContentsSize.width(), untransformedContentsSize.height()));
1918     return IntSize(floorf(transformedBottomRight.x()), floorf(transformedBottomRight.y()));
1919 }
1920
1921 IntPoint WebPagePrivate::mapFromContentsToViewport(const IntPoint& point) const
1922 {
1923     return m_backingStoreClient->mapFromContentsToViewport(point);
1924 }
1925
1926 IntPoint WebPagePrivate::mapFromViewportToContents(const IntPoint& point) const
1927 {
1928     return m_backingStoreClient->mapFromViewportToContents(point);
1929 }
1930
1931 IntRect WebPagePrivate::mapFromContentsToViewport(const IntRect& rect) const
1932 {
1933     return m_backingStoreClient->mapFromContentsToViewport(rect);
1934 }
1935
1936 IntRect WebPagePrivate::mapFromViewportToContents(const IntRect& rect) const
1937 {
1938     return m_backingStoreClient->mapFromViewportToContents(rect);
1939 }
1940
1941 IntPoint WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntPoint& point) const
1942 {
1943     return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(point);
1944 }
1945
1946 IntPoint WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntPoint& point) const
1947 {
1948     return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(point);
1949 }
1950
1951 IntRect WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntRect& rect) const
1952 {
1953     return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(rect);
1954 }
1955
1956 IntRect WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntRect& rect) const
1957 {
1958     return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(rect);
1959 }
1960
1961 // NOTE: PIXEL ROUNDING!
1962 // Accurate back-and-forth rounding is not possible with information loss
1963 // by integer points and sizes, so we always expand the resulting mapped
1964 // float rectangles to the nearest integer. For points, we always use
1965 // floor-rounding in mapToTransformed() so that we don't have to crop to
1966 // the (floor'd) transformed contents size.
1967 static inline IntPoint roundTransformedPoint(const FloatPoint &point)
1968 {
1969     // Maps by rounding half towards zero.
1970     return IntPoint(static_cast<int>(floorf(point.x())), static_cast<int>(floorf(point.y())));
1971 }
1972
1973 static inline IntPoint roundUntransformedPoint(const FloatPoint &point)
1974 {
1975     // Maps by rounding half away from zero.
1976     return IntPoint(static_cast<int>(ceilf(point.x())), static_cast<int>(ceilf(point.y())));
1977 }
1978
1979 IntPoint WebPagePrivate::mapToTransformed(const IntPoint& point) const
1980 {
1981     return roundTransformedPoint(m_transformationMatrix->mapPoint(FloatPoint(point)));
1982 }
1983
1984 FloatPoint WebPagePrivate::mapToTransformedFloatPoint(const FloatPoint& point) const
1985 {
1986     return m_transformationMatrix->mapPoint(point);
1987 }
1988
1989 IntPoint WebPagePrivate::mapFromTransformed(const IntPoint& point) const
1990 {
1991     return roundUntransformedPoint(m_transformationMatrix->inverse().mapPoint(FloatPoint(point)));
1992 }
1993
1994 FloatPoint WebPagePrivate::mapFromTransformedFloatPoint(const FloatPoint& point) const
1995 {
1996     return m_transformationMatrix->inverse().mapPoint(point);
1997 }
1998
1999 FloatRect WebPagePrivate::mapFromTransformedFloatRect(const FloatRect& rect) const
2000 {
2001     return m_transformationMatrix->inverse().mapRect(rect);
2002 }
2003
2004 IntSize WebPagePrivate::mapToTransformed(const IntSize& size) const
2005 {
2006     return mapToTransformed(IntRect(IntPoint::zero(), size)).size();
2007 }
2008
2009 IntSize WebPagePrivate::mapFromTransformed(const IntSize& size) const
2010 {
2011     return mapFromTransformed(IntRect(IntPoint::zero(), size)).size();
2012 }
2013
2014 IntRect WebPagePrivate::mapToTransformed(const IntRect& rect) const
2015 {
2016     return enclosingIntRect(m_transformationMatrix->mapRect(FloatRect(rect)));
2017 }
2018
2019 // Use this in conjunction with mapToTransformed(IntRect), in most cases.
2020 void WebPagePrivate::clipToTransformedContentsRect(IntRect& rect) const
2021 {
2022     rect.intersect(IntRect(IntPoint::zero(), transformedContentsSize()));
2023 }
2024
2025 IntRect WebPagePrivate::mapFromTransformed(const IntRect& rect) const
2026 {
2027     return enclosingIntRect(m_transformationMatrix->inverse().mapRect(FloatRect(rect)));
2028 }
2029
2030 bool WebPagePrivate::transformedPointEqualsUntransformedPoint(const IntPoint& transformedPoint, const IntPoint& untransformedPoint)
2031 {
2032     // Scaling down is always more accurate than scaling up.
2033     if (m_transformationMatrix->a() > 1.0)
2034         return transformedPoint == mapToTransformed(untransformedPoint);
2035
2036     return mapFromTransformed(transformedPoint) == untransformedPoint;
2037 }
2038
2039 void WebPagePrivate::notifyTransformChanged()
2040 {
2041     notifyTransformedContentsSizeChanged();
2042     notifyTransformedScrollChanged();
2043
2044     m_backingStore->d->transformChanged();
2045 }
2046
2047 void WebPagePrivate::notifyTransformedContentsSizeChanged()
2048 {
2049     // We mark here as the last reported content size we sent to the client.
2050     m_previousContentsSize = contentsSize();
2051
2052     const IntSize size = transformedContentsSize();
2053     m_backingStore->d->contentsSizeChanged(size);
2054     m_client->contentsSizeChanged(size);
2055 }
2056
2057 void WebPagePrivate::notifyTransformedScrollChanged()
2058 {
2059     const IntPoint pos = transformedScrollPosition();
2060     m_backingStore->d->scrollChanged(pos);
2061     m_client->scrollChanged(pos);
2062 }
2063
2064 bool WebPagePrivate::setViewMode(ViewMode mode)
2065 {
2066     if (!m_mainFrame->view())
2067         return false;
2068
2069     m_viewMode = mode;
2070
2071     // If we're in the middle of a nested layout with a recursion count above
2072     // some maximum threshold, then our algorithm for finding the minimum content
2073     // width of a given page has become dependent on the visible width.
2074     //
2075     // We need to find some method to ensure that we don't experience excessive
2076     // and even infinite recursion. This can even happen with valid html. The
2077     // former can happen when we run into inline text with few candidates for line
2078     // break. The latter can happen for instance if the page has a negative margin
2079     // set against the right border. Note: this is valid by spec and can lead to
2080     // a situation where there is no value for which the content width will ensure
2081     // no horizontal scrollbar.
2082     // Example: LayoutTests/css1/box_properties/margin.html
2083     //
2084     // In order to address such situations when we detect a recursion above some
2085     // maximum threshold we snap our fixed layout size to a defined quantum increment.
2086     // Eventually, either the content width will be satisfied to ensure no horizontal
2087     // scrollbar or this increment will run into the maximum layout size and the
2088     // recursion will necessarily end.
2089     bool snapToIncrement = didLayoutExceedMaximumIterations();
2090
2091     IntSize currentSize = m_mainFrame->view()->fixedLayoutSize();
2092     IntSize newSize = fixedLayoutSize(snapToIncrement);
2093     if (currentSize == newSize)
2094         return false;
2095
2096     // FIXME: Temp solution. We'll get back to this.
2097     if (m_nestedLayoutFinishedCount) {
2098         double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width());
2099         double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height());
2100         if (widthChange < 0.05 && heightChange < 0.05)
2101             return false;
2102     }
2103
2104     m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
2105     m_mainFrame->view()->setFixedLayoutSize(newSize);
2106     return true; // Needs re-layout!
2107 }
2108
2109 void WebPagePrivate::setCursor(PlatformCursor handle)
2110 {
2111     if (m_currentCursor.type() != handle.type()) {
2112         m_currentCursor = handle;
2113         m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot().x(), handle.hotspot().y());
2114     }
2115 }
2116
2117 Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory()
2118 {
2119     return m_client->networkStreamFactory();
2120 }
2121
2122 Platform::Graphics::Window* WebPagePrivate::platformWindow() const
2123 {
2124     return m_client->window();
2125 }
2126
2127 void WebPagePrivate::setPreventsScreenDimming(bool keepAwake)
2128 {
2129     if (keepAwake) {
2130         if (!m_preventIdleDimmingCount)
2131             m_client->setPreventsScreenIdleDimming(true);
2132         m_preventIdleDimmingCount++;
2133     } else if (m_preventIdleDimmingCount > 0) {
2134         m_preventIdleDimmingCount--;
2135         if (!m_preventIdleDimmingCount)
2136             m_client->setPreventsScreenIdleDimming(false);
2137     } else
2138         ASSERT_NOT_REACHED(); // SetPreventsScreenIdleDimming(false) called too many times.
2139 }
2140
2141 void WebPagePrivate::showVirtualKeyboard(bool showKeyboard)
2142 {
2143     m_client->showVirtualKeyboard(showKeyboard);
2144 }
2145
2146 void WebPagePrivate::ensureContentVisible(bool centerInView)
2147 {
2148     m_inputHandler->ensureFocusElementVisible(centerInView);
2149 }
2150
2151 void WebPagePrivate::zoomToContentRect(const IntRect& rect)
2152 {
2153     // Don't scale if the user is not supposed to scale.
2154     if (!isUserScalable())
2155         return;
2156
2157     FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y());
2158     IntSize viewSize = viewportSize();
2159
2160     // Calculate the scale required to scale that dimension to fit.
2161     double scaleH = (double)viewSize.width() / (double)rect.width();
2162     double scaleV = (double)viewSize.height() / (double)rect.height();
2163
2164     // Choose the smaller scale factor so that all of the content is visible.
2165     zoomAboutPoint(min(scaleH, scaleV), anchor);
2166 }
2167
2168 void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister)
2169 {
2170     if (shouldRegister)
2171         m_pluginViews.add(plugin);
2172     else
2173         m_pluginViews.remove(plugin);
2174 }
2175
2176 #define FOR_EACH_PLUGINVIEW(pluginViews) \
2177     HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \
2178     HashSet<PluginView*>::const_iterator last = pluginViews.end(); \
2179     for (; it != last; ++it)
2180
2181 void WebPagePrivate::notifyPageOnLoad()
2182 {
2183     FOR_EACH_PLUGINVIEW(m_pluginViews)
2184         (*it)->handleOnLoadEvent();
2185 }
2186
2187 bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2188 {
2189     return m_client->shouldPluginEnterFullScreen();
2190 }
2191
2192 void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2193 {
2194     m_fullScreenPluginView = plugin;
2195     m_client->didPluginEnterFullScreen();
2196
2197     if (!m_client->window())
2198         return;
2199
2200     Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix);
2201     m_client->window()->setSensitivityFullscreenOverride(true);
2202 }
2203
2204 void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2205 {
2206     m_fullScreenPluginView = 0;
2207     m_client->didPluginExitFullScreen();
2208
2209     if (!m_client->window())
2210         return;
2211
2212     Platform::Graphics::Window::setTransparencyDiscardFilter(0);
2213     m_client->window()->setSensitivityFullscreenOverride(false);
2214 }
2215
2216 void WebPagePrivate::onPluginStartBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
2217 {
2218     m_client->onPluginStartBackgroundPlay();
2219 }
2220
2221 void WebPagePrivate::onPluginStopBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
2222 {
2223     m_client->onPluginStopBackgroundPlay();
2224 }
2225
2226 bool WebPagePrivate::lockOrientation(bool landscape)
2227 {
2228     return m_client->lockOrientation(landscape);
2229 }
2230
2231 void WebPagePrivate::unlockOrientation()
2232 {
2233     return m_client->unlockOrientation();
2234 }
2235
2236 int WebPagePrivate::orientation() const
2237 {
2238 #if ENABLE(ORIENTATION_EVENTS)
2239     return m_mainFrame->orientation();
2240 #else
2241 #error ORIENTATION_EVENTS must be defined.
2242 // Or a copy of the orientation value will have to be stored in these objects.
2243 #endif
2244 }
2245
2246 double WebPagePrivate::currentZoomFactor() const
2247 {
2248     return currentScale();
2249 }
2250
2251 int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype)
2252 {
2253     return m_client->showAlertDialog(atype);
2254 }
2255
2256 bool WebPagePrivate::isActive() const
2257 {
2258     return m_client->isActive();
2259 }
2260
2261 bool WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSpace& protectionSpace, Credential& inputCredential)
2262 {
2263     WebString username;
2264     WebString password;
2265
2266 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
2267     if (m_dumpRenderTree)
2268         return m_dumpRenderTree->didReceiveAuthenticationChallenge(inputCredential);
2269 #endif
2270
2271 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2272     if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled())
2273         credentialManager().autofillAuthenticationChallenge(protectionSpace, username, password);
2274 #endif
2275
2276     bool isConfirmed = m_client->authenticationChallenge(protectionSpace.realm().characters(), protectionSpace.realm().length(), username, password);
2277
2278 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2279     Credential credential(username, password, CredentialPersistencePermanent);
2280     if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled() && isConfirmed)
2281         credentialManager().saveCredentialIfConfirmed(this, CredentialTransformData(url, protectionSpace, credential));
2282 #else
2283     Credential credential(username, password, CredentialPersistenceNone);
2284 #endif
2285     inputCredential = credential;
2286     return isConfirmed;
2287 }
2288
2289 PageClientBlackBerry::SaveCredentialType WebPagePrivate::notifyShouldSaveCredential(bool isNew)
2290 {
2291     return static_cast<PageClientBlackBerry::SaveCredentialType>(m_client->notifyShouldSaveCredential(isNew));
2292 }
2293
2294 void WebPagePrivate::syncProxyCredential(const WebCore::Credential& credential)
2295 {
2296     m_client->syncProxyCredential(credential.user().utf8().data(), credential.password().utf8().data());
2297 }
2298
2299 void WebPagePrivate::notifyPopupAutofillDialog(const Vector<String>& candidates, const WebCore::IntRect& screenRect)
2300 {
2301     vector<string> textItems;
2302     for (size_t i = 0; i < candidates.size(); i++)
2303         textItems.push_back(candidates[i].utf8().data());
2304     m_client->notifyPopupAutofillDialog(textItems, screenRect);
2305 }
2306
2307 void WebPagePrivate::notifyDismissAutofillDialog()
2308 {
2309     m_client->notifyDismissAutofillDialog();
2310 }
2311
2312 bool WebPagePrivate::useFixedLayout() const
2313 {
2314     return true;
2315 }
2316
2317 Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy)
2318 {
2319     Platform::WebContext context;
2320
2321     RefPtr<Node> node = contextNode(strategy);
2322     m_currentContextNode = node;
2323     if (!m_currentContextNode)
2324         return context;
2325
2326     // Send an onContextMenu event to the current context ndoe and get the result. Since we've already figured out
2327     // which node we want, we can send it directly to the node and not do a hit test. The onContextMenu event doesn't require
2328     // mouse positions so we just set the position at (0,0)
2329     PlatformMouseEvent mouseEvent(IntPoint(), IntPoint(), PlatformEvent::MouseMoved, 0, NoButton, TouchScreen);
2330     if (m_currentContextNode->dispatchMouseEvent(mouseEvent, eventNames().contextmenuEvent, 0)) {
2331         context.setFlag(Platform::WebContext::IsOnContextMenuPrevented);
2332         return context;
2333     }
2334
2335     // Unpress the mouse button if we're actually getting context.
2336     EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2337     if (eventHandler->mousePressed())
2338         eventHandler->setMousePressed(false);
2339
2340     requestLayoutIfNeeded();
2341
2342     bool nodeAllowSelectionOverride = false;
2343     if (Node* linkNode = node->enclosingLinkEventParentOrSelf()) {
2344         KURL href;
2345         if (linkNode->isLink() && linkNode->hasAttributes()) {
2346             if (Attribute* attribute = static_cast<Element*>(linkNode)->getAttributeItem(HTMLNames::hrefAttr))
2347                 href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
2348         }
2349
2350         String pattern = findPatternStringForUrl(href);
2351         if (!pattern.isEmpty())
2352             context.setPattern(pattern.utf8().data());
2353
2354         if (!href.string().isEmpty()) {
2355             context.setUrl(href.string().utf8().data());
2356
2357             // Links are non-selectable by default, but selection should be allowed
2358             // providing the page is selectable, use the parent to determine it.
2359             if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
2360                 nodeAllowSelectionOverride = true;
2361         }
2362     }
2363
2364     if (node->isHTMLElement()) {
2365         HTMLImageElement* imageElement = 0;
2366         HTMLMediaElement* mediaElement = 0;
2367
2368         if (node->hasTagName(HTMLNames::imgTag))
2369             imageElement = static_cast<HTMLImageElement*>(node.get());
2370         else if (node->hasTagName(HTMLNames::areaTag))
2371             imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement();
2372
2373         if (static_cast<HTMLElement*>(node.get())->isMediaElement())
2374             mediaElement = static_cast<HTMLMediaElement*>(node.get());
2375
2376         if (imageElement && imageElement->renderer()) {
2377             context.setFlag(Platform::WebContext::IsImage);
2378             // FIXME: At the mean time, we only show "Save Image" when the image data is available.
2379             if (CachedResource* cachedResource = imageElement->cachedImage()) {
2380                 if (cachedResource->isLoaded() && cachedResource->data()) {
2381                     String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
2382                     context.setSrc(node->document()->completeURL(url).string().utf8().data());
2383                 }
2384             }
2385             String alt = imageElement->altText();
2386             if (!alt.isNull())
2387                 context.setAlt(alt.utf8().data());
2388         }
2389
2390         if (mediaElement) {
2391             if (mediaElement->hasAudio())
2392                 context.setFlag(Platform::WebContext::IsAudio);
2393             if (mediaElement->hasVideo())
2394                 context.setFlag(Platform::WebContext::IsVideo);
2395
2396             String src = stripLeadingAndTrailingHTMLSpaces(mediaElement->getAttribute(HTMLNames::srcAttr).string());
2397             context.setSrc(node->document()->completeURL(src).string().utf8().data());
2398         }
2399     }
2400
2401     if (node->isTextNode()) {
2402         Text* curText = toText(node.get());
2403         if (!curText->wholeText().isEmpty())
2404             context.setText(curText->wholeText().utf8().data());
2405     }
2406
2407     bool canStartSelection = node->canStartSelection();
2408
2409     if (node->isElementNode()) {
2410         Element* element = static_cast<Element*>(node->shadowAncestorNode());
2411         if (DOMSupport::isTextBasedContentEditableElement(element)) {
2412             if (!canStartSelection) {
2413                 // Input fields host node is by spec non-editable unless the field itself has content editable enabled.
2414                 // Enable selection if the shadow tree for the input field is selectable.
2415                 Node* nodeUnderFinger = m_touchEventHandler->lastFatFingersResult().isValid() ? m_touchEventHandler->lastFatFingersResult().node(FatFingersResult::ShadowContentAllowed) : 0;
2416                 if (nodeUnderFinger)
2417                     canStartSelection = nodeUnderFinger->canStartSelection();
2418             }
2419             context.setFlag(Platform::WebContext::IsInput);
2420             if (element->hasTagName(HTMLNames::inputTag))
2421                 context.setFlag(Platform::WebContext::IsSingleLine);
2422             if (DOMSupport::isPasswordElement(element))
2423                 context.setFlag(Platform::WebContext::IsPassword);
2424
2425             String elementText(DOMSupport::inputElementText(element));
2426             if (!elementText.stripWhiteSpace().isEmpty())
2427                 context.setText(elementText.utf8().data());
2428         }
2429     }
2430
2431     if (!nodeAllowSelectionOverride && !canStartSelection)
2432         context.resetFlag(Platform::WebContext::IsSelectable);
2433
2434     if (node->isFocusable())
2435         context.setFlag(Platform::WebContext::IsFocusable);
2436
2437     return context;
2438 }
2439
2440 Platform::WebContext WebPage::webContext(TargetDetectionStrategy strategy) const
2441 {
2442     return d->webContext(strategy);
2443 }
2444
2445 void WebPagePrivate::updateCursor()
2446 {
2447     int buttonMask = 0;
2448     if (m_lastMouseEvent.button() == LeftButton)
2449         buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
2450     else if (m_lastMouseEvent.button() == MiddleButton)
2451         buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
2452     else if (m_lastMouseEvent.button() == RightButton)
2453         buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
2454
2455     BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask, mapToTransformed(m_lastMouseEvent.position()), mapToTransformed(m_lastMouseEvent.globalPosition()), 0, 0);
2456     m_webPage->mouseEvent(event);
2457 }
2458
2459 IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
2460 {
2461     if (hasVirtualViewport())
2462         return IntSize(m_virtualViewportWidth, m_virtualViewportHeight);
2463
2464     const int defaultLayoutWidth = m_defaultLayoutSize.width();
2465     const int defaultLayoutHeight = m_defaultLayoutSize.height();
2466
2467     int minWidth = defaultLayoutWidth;
2468     int maxWidth = DEFAULT_MAX_LAYOUT_WIDTH;
2469     int maxHeight = DEFAULT_MAX_LAYOUT_HEIGHT;
2470
2471     // If the load state is none then we haven't actually got anything yet, but we need to layout
2472     // the entire page so that the user sees the entire page (unrendered) instead of just part of it.
2473     if (m_loadState == None)
2474         return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2475
2476     if (m_viewMode == FixedDesktop) {
2477         int width  = maxWidth;
2478         // if the defaultLayoutHeight is at minimum, it probably was set as 0
2479         // and clamped, meaning it's effectively not set.  (Even if it happened
2480         // to be set exactly to the minimum, it's too small to be useful.)  So
2481         // ignore it.
2482         int height;
2483         if (defaultLayoutHeight <= minimumLayoutSize.height())
2484             height = maxHeight;
2485         else
2486             height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2487         return IntSize(width, height);
2488     }
2489
2490     if (m_viewMode == Desktop) {
2491         // If we detect an overflow larger than the contents size then use that instead since
2492         // it'll still be clamped by the maxWidth below...
2493         int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
2494         if (m_pendingOrientation != -1 && !m_nestedLayoutFinishedCount)
2495             width = 0;
2496
2497         if (snapToIncrement) {
2498             // Snap to increments of defaultLayoutWidth / 2.0.
2499             float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
2500             factor = ceilf(factor);
2501             width = (defaultLayoutWidth / 2.0) * factor;
2502         }
2503
2504         if (width < minWidth)
2505             width = minWidth;
2506         if (width > maxWidth)
2507             width = maxWidth;
2508         int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2509         return IntSize(width, height);
2510     }
2511
2512     ASSERT_NOT_REACHED();
2513     return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2514 }
2515
2516 BackingStoreClient* WebPagePrivate::backingStoreClientForFrame(const Frame* frame) const
2517 {
2518     ASSERT(frame);
2519     BackingStoreClient* backingStoreClient = 0;
2520     if (m_backingStoreClientForFrameMap.contains(frame))
2521         backingStoreClient = m_backingStoreClientForFrameMap.get(frame);
2522     return backingStoreClient;
2523 }
2524
2525 void WebPagePrivate::addBackingStoreClientForFrame(const Frame* frame, BackingStoreClient* client)
2526 {
2527     ASSERT(frame);
2528     ASSERT(client);
2529     m_backingStoreClientForFrameMap.add(frame, client);
2530 }
2531
2532 void WebPagePrivate::removeBackingStoreClientForFrame(const Frame* frame)
2533 {
2534     ASSERT(frame);
2535     if (m_backingStoreClientForFrameMap.contains(frame))
2536         m_backingStoreClientForFrameMap.remove(frame);
2537 }
2538
2539
2540 void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
2541 {
2542     ASSERT(documentGoingAway);
2543     if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
2544         m_currentContextNode = 0;
2545
2546     if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
2547         m_currentPinchZoomNode = 0;
2548
2549     if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
2550         m_currentBlockZoomAdjustedNode = 0;
2551
2552     if (m_inRegionScroller->d->hasNode() && m_inRegionScroller->d->node()->document() == documentGoingAway)
2553         m_inRegionScroller->d->reset();
2554
2555     if (documentGoingAway->frame())
2556         m_inputHandler->frameUnloaded(documentGoingAway->frame());
2557
2558     Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
2559     if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
2560         m_touchEventHandler->resetLastFatFingersResult();
2561
2562     // NOTE: m_fullscreenVideoNode, m_fullScreenPluginView and m_pluginViews
2563     // are cleared in other methods already.
2564 }
2565
2566 typedef bool (*PredicateFunction)(RenderLayer*);
2567 static bool isPositionedContainer(RenderLayer* layer)
2568 {
2569     RenderObject* o = layer->renderer();
2570     return o->isRenderView() || o->isOutOfFlowPositioned() || o->isRelPositioned() || layer->hasTransform();
2571 }
2572
2573 static bool isFixedPositionedContainer(RenderLayer* layer)
2574 {
2575     RenderObject* o = layer->renderer();
2576     return o->isRenderView() || (o->isOutOfFlowPositioned() && o->style()->position() == FixedPosition);
2577 }
2578
2579 static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
2580 {
2581     RenderLayer* curr = layer;
2582     while (curr && !predicate(curr))
2583         curr = curr->parent();
2584
2585     return curr;
2586 }
2587
2588 RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
2589 {
2590     return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
2591 }
2592
2593 RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
2594 {
2595     return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
2596 }
2597
2598 static inline Frame* frameForNode(Node* node)
2599 {
2600     Node* origNode = node;
2601     for (; node; node = node->parentNode()) {
2602         if (RenderObject* renderer = node->renderer()) {
2603             if (renderer->isRenderView()) {
2604                 if (FrameView* view = toRenderView(renderer)->frameView()) {
2605                     if (Frame* frame = view->frame())
2606                         return frame;
2607                 }
2608             }
2609             if (renderer->isWidget()) {
2610                 Widget* widget = toRenderWidget(renderer)->widget();
2611                 if (widget && widget->isFrameView()) {
2612                     if (Frame* frame = static_cast<FrameView*>(widget)->frame())
2613                         return frame;
2614                 }
2615             }
2616         }
2617     }
2618
2619     for (node = origNode; node; node = node->parentNode()) {
2620         if (Document* doc = node->document()) {
2621             if (Frame* frame = doc->frame())
2622                 return frame;
2623         }
2624     }
2625
2626     return 0;
2627 }
2628
2629 static IntRect getNodeWindowRect(Node* node)
2630 {
2631     if (Frame* frame = frameForNode(node)) {
2632         if (FrameView* view = frame->view())
2633             return view->contentsToWindow(node->getRect());
2634     }
2635     ASSERT_NOT_REACHED();
2636     return IntRect();
2637 }
2638
2639 IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
2640 {
2641     ASSERT(m_mainFrame);
2642
2643     // Don't call this function asking to not clip the main frame providing only
2644     // the main frame. All that can be returned is the content rect which
2645     // isn't what this function is for.
2646     if (noClipOfMainFrame && view == m_mainFrame->view()) {
2647         ASSERT_NOT_REACHED();
2648         return IntRect(IntPoint::zero(), view->contentsSize());
2649     }
2650
2651     IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect(false)));
2652     if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
2653         // Intersect with parent visible rect.
2654         visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
2655     }
2656     return visibleWindowRect;
2657 }
2658
2659 void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
2660 {
2661     ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
2662     ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
2663     ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
2664
2665     // First we clear the focus, since we want to focus either initial or the last
2666     // focusable element in the webpage (according to the TABINDEX), or simply clear
2667     // the focus.
2668     clearFocusNode();
2669
2670     switch (direction) {
2671     case FocusDirectionForward:
2672     case FocusDirectionBackward:
2673         m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
2674         break;
2675     case FocusDirectionNone:
2676         break;
2677     default:
2678         ASSERT_NOT_REACHED();
2679     }
2680 }
2681
2682 void WebPage::assignFocus(Platform::FocusDirection direction)
2683 {
2684     if (d->m_page->defersLoading())
2685        return;
2686     d->assignFocus(direction);
2687 }
2688
2689 Platform::IntRect WebPagePrivate::focusNodeRect()
2690 {
2691     Frame* frame = focusedOrMainFrame();
2692     if (!frame)
2693         return Platform::IntRect();
2694
2695     Document* doc = frame->document();
2696     FrameView* view = frame->view();
2697     if (!doc || !view || view->needsLayout())
2698         return Platform::IntRect();
2699
2700     IntRect focusRect = rectForNode(doc->focusedNode());
2701     focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
2702     focusRect = mapToTransformed(focusRect);
2703     clipToTransformedContentsRect(focusRect);
2704     return focusRect;
2705 }
2706
2707 PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
2708 {
2709     EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2710     const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
2711     bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
2712
2713     // Check if we're using LinkToLink and the user is not touching the screen.
2714     if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
2715         RefPtr<Node> node;
2716         node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
2717         if (node) {
2718             IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
2719             if (!visibleRect.intersects(getNodeWindowRect(node.get())))
2720                 return 0;
2721         }
2722         return node.release();
2723     }
2724
2725     // Check for text input.
2726     if (isTouching && lastFatFingersResult.isTextInput())
2727         return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
2728
2729     IntPoint contentPos;
2730     if (isTouching)
2731         contentPos = lastFatFingersResult.adjustedPosition();
2732     else
2733         contentPos = mapFromViewportToContents(m_lastMouseEvent.position());
2734
2735     if (strategy == RectBased) {
2736         FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
2737         return result.node(FatFingersResult::ShadowContentNotAllowed);
2738     }
2739
2740     HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos, false /*allowShadowContent*/);
2741     return result.innerNode();
2742 }
2743
2744 static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
2745 {
2746     // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709).
2747     double dx = static_cast<double>(p1.x() - p2.x());
2748     double dy = static_cast<double>(p1.y() - p2.y());
2749     return sqrt((dx * dx) + (dy * dy));
2750 }
2751
2752 Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& point)
2753 {
2754     IntPoint pt = mapFromTransformed(point);
2755     IntRect clickRect(pt.x() - blockClickRadius, pt.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
2756     Node* originalNode = nodeForZoomUnderPoint(point);
2757     if (!originalNode)
2758         return 0;
2759     Node* node = bestChildNodeForClickRect(originalNode, clickRect);
2760     return node ? adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(node) : adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(originalNode);
2761 }
2762
2763 Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
2764 {
2765     if (!parentNode)
2766         return 0;
2767
2768     int bestDistance = std::numeric_limits<int>::max();
2769
2770     Node* node = parentNode->firstChild();
2771     Node* bestNode = 0;
2772     for (; node; node = node->nextSibling()) {
2773         IntRect rect = rectForNode(node);
2774         if (!clickRect.intersects(rect))
2775             continue;
2776
2777         int distance = distanceBetweenPoints(rect.center(), clickRect.center());
2778         Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
2779         if (bestChildNode) {
2780             IntRect bestChildRect = rectForNode(bestChildNode);
2781             int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
2782             if (bestChildDistance < distance && bestChildDistance < bestDistance) {
2783                 bestNode = bestChildNode;
2784                 bestDistance = bestChildDistance;
2785             } else {
2786                 if (distance < bestDistance) {
2787                     bestNode = node;
2788                     bestDistance = distance;
2789                 }
2790             }
2791         } else {
2792             if (distance < bestDistance) {
2793                 bestNode = node;
2794                 bestDistance = distance;
2795             }
2796         }
2797     }
2798
2799     return bestNode;
2800 }
2801
2802 double WebPagePrivate::maxBlockZoomScale() const
2803 {
2804     return std::min(maximumBlockZoomScale, maximumScale());
2805 }
2806
2807 Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& point)
2808 {
2809     if (!m_mainFrame)
2810         return 0;
2811
2812     HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromTransformed(point), false);
2813
2814     Node* node = result.innerNonSharedNode();
2815
2816     if (!node)
2817         return 0;
2818
2819     RenderObject* renderer = node->renderer();
2820     while (!renderer) {
2821         node = node->parentNode();
2822         renderer = node->renderer();
2823     }
2824
2825     return node;
2826 }
2827
2828 Node* WebPagePrivate::adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(Node* node)
2829 {
2830     Node* initialNode = node;
2831     RenderObject* renderer = node->renderer();
2832     bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2833     IntSize actualVisibleSize = this->actualVisibleSize();
2834
2835     while (!renderer || !acceptableNodeSize) {
2836         node = node->parentNode();
2837         IntRect nodeRect = rectForNode(node);
2838
2839         // Don't choose a node if the width of the node size is very close to the width of the actual visible size,
2840         // as block zoom can do nothing on such kind of node.
2841         if (!node || static_cast<double>(actualVisibleSize.width() - nodeRect.width()) / actualVisibleSize.width() < minimumExpandingRatio)
2842             return initialNode;
2843
2844         renderer = node->renderer();
2845         acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2846     }
2847
2848     return node;
2849 }
2850
2851 bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
2852 {
2853     if (!n1 || !n2)
2854         return false;
2855
2856     return (n2 == n1) || n2->isDescendantOf(n1);
2857 }
2858
2859 double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
2860 {
2861     if (rect.isEmpty())
2862         return std::numeric_limits<double>::max();
2863
2864     ASSERT(rect.width() + margin);
2865
2866     double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
2867
2868     return newScale;
2869 }
2870
2871 IntRect WebPagePrivate::rectForNode(Node* node)
2872 {
2873     if (!node)
2874         return IntRect();
2875
2876     RenderObject* renderer = node->renderer();
2877
2878     if (!renderer)
2879         return IntRect();
2880
2881     // Return rect in un-transformed content coordinates.
2882     IntRect blockRect;
2883
2884     // FIXME: Ensure this works with iframes.
2885     if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
2886         RenderBlock* renderBlock = renderer->containingBlock();
2887         int xOffset = 0;
2888         int yOffset = 0;
2889         while (!renderBlock->isRoot()) {
2890             xOffset += renderBlock->x();
2891             yOffset += renderBlock->y();
2892             renderBlock = renderBlock->containingBlock();
2893         }
2894         const RenderText* renderText = toRenderText(renderer);
2895         IntRect linesBox = renderText->linesBoundingBox();
2896         blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height());
2897     } else
2898         blockRect = renderer->absoluteClippedOverflowRect();
2899
2900     if (renderer->isText()) {
2901         RenderBlock* rb = renderer->containingBlock();
2902
2903         // Inefficient? Way to find width when floats intersect a block.
2904         int blockWidth = 0;
2905         int lineCount = rb->lineCount();
2906         for (int i = 0; i < lineCount; i++)
2907             blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false));
2908
2909         blockRect.setWidth(blockWidth);
2910         blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
2911     }
2912
2913     // Strip off padding.
2914     if (renderer->style()->hasPadding()) {
2915         blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
2916         blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
2917         blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
2918         blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
2919     }
2920
2921     return blockRect;
2922 }
2923
2924 IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
2925 {
2926     ASSERT(frame);
2927
2928     // FIXME: This function can be called when page is being destroyed and JS triggers selection change.
2929     // We could break the call chain at upper levels, but I think it is better to check the frame pointer
2930     // here because the pointer is explicitly cleared in WebPage::destroy().
2931     if (!mainFrame())
2932         return IntPoint();
2933
2934     // Convert 0,0 in the frame's coordinate system to window coordinates to
2935     // get the frame's global position, and return this position in the main
2936     // frame's coordinates.  (So the main frame's coordinates will be 0,0.)
2937     return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
2938 }
2939
2940 IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
2941 {
2942     if (!node)
2943         return rect;
2944
2945     // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames.
2946     // FIXME: can we just use frameOffset instead of this big routine?
2947     const Node* tnode = node;
2948     IntRect adjustedRect = rect;
2949     do {
2950         Frame* frame = tnode->document()->frame();
2951         if (!frame)
2952             continue;
2953
2954         Node* ownerNode = static_cast<Node*>(frame->ownerElement());
2955         tnode = ownerNode;
2956         if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
2957             IntRect iFrameRect;
2958             do {
2959                 iFrameRect = rectForNode(ownerNode);
2960                 adjustedRect.move(iFrameRect.x(), iFrameRect.y());
2961                 adjustedRect.intersect(iFrameRect);
2962                 ownerNode = ownerNode->parentNode();
2963             } while (iFrameRect.isEmpty() && ownerNode);
2964         } else
2965             break;
2966     } while (tnode = tnode->parentNode());
2967
2968     return adjustedRect;
2969 }
2970
2971 IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
2972 {
2973     if (!node || contentsSize().isEmpty())
2974         return IntRect();
2975
2976     Node* tnode = node;
2977     m_currentBlockZoomAdjustedNode = tnode;
2978
2979     IntRect blockRect = rectForNode(tnode);
2980     IntRect originalRect = blockRect;
2981
2982     int originalArea = originalRect.width() * originalRect.height();
2983     int pageArea = contentsSize().width() * contentsSize().height();
2984     double blockToPageRatio = static_cast<double>(pageArea - originalArea) / pageArea;
2985     double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
2986
2987     if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
2988         while (tnode = tnode->parentNode()) {
2989             ASSERT(tnode);
2990             IntRect tRect = rectForNode(tnode);
2991             int tempBlockArea = tRect.width() * tRect.height();
2992             // Don't expand the block if it will be too large relative to the content.
2993             if (static_cast<double>(pageArea - tempBlockArea) / pageArea < minimumExpandingRatio)
2994                 break;
2995             if (tRect.isEmpty())
2996                 continue; // No renderer.
2997             if (tempBlockArea < 1.1 * originalArea)
2998                 continue; // The size of this parent is very close to the child, no need to go to this parent.
2999             // Don't expand the block if the parent node size is already almost the size of actual visible size.
3000             IntSize actualSize = actualVisibleSize();
3001             if (static_cast<double>(actualSize.width() - tRect.width()) / actualSize.width() < minimumExpandingRatio)
3002                 break;
3003             if (tempBlockArea < blockExpansionRatio * originalArea) {
3004                 blockRect = tRect;
3005                 m_currentBlockZoomAdjustedNode = tnode;
3006             } else
3007                 break;
3008         }
3009     }
3010
3011     blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
3012     blockRect = mapToTransformed(blockRect);
3013     clipToTransformedContentsRect(blockRect);
3014
3015 #if DEBUG_BLOCK_ZOOM
3016     if (!m_backingStore->d->isSuspended()) {
3017         // Re-paint the backingstore to screen to erase other annotations.
3018         if (m_backingStore->d->shouldDirectRenderingToWindow())
3019             m_backingStore->d->renderVisibleContents();
3020         else
3021             m_backingStore->d->blitVisibleContents();
3022
3023         // Render a black square over the calculated block and a gray square over the original block for visual inspection.
3024         originalRect = mapToTransformed(originalRect);
3025         clipToTransformedContentsRect(originalRect);
3026         IntRect renderRect = mapFromTransformedContentsToTransformedViewport(blockRect);
3027         IntRect originalRenderRect = mapFromTransformedContentsToTransformedViewport(originalRect);
3028         IntSize viewportSize = transformedViewportSize();
3029         renderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
3030         originalRenderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
3031         m_backingStore->d->clearWindow(renderRect, 0, 0, 0);
3032         m_backingStore->d->clearWindow(originalRenderRect, 120, 120, 120);
3033         m_backingStore->d->invalidateWindow(renderRect);
3034     }
3035 #endif
3036
3037     return blockRect;
3038 }
3039
3040 // This function should not be called directly.
3041 // It is called after the animation ends (see above).
3042 void WebPagePrivate::zoomBlock()
3043 {
3044     if (!m_mainFrame)
3045         return;
3046
3047     IntPoint anchor(roundUntransformedPoint(mapFromTransformedFloatPoint(m_finalBlockPoint)));
3048     bool willUseTextReflow = false;
3049
3050 #if ENABLE(VIEWPORT_REFLOW)
3051     willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
3052     toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
3053     setNeedsLayout();
3054 #endif
3055
3056     TransformationMatrix zoom;
3057     zoom.scale(m_blockZoomFinalScale);
3058     *m_transformationMatrix = zoom;
3059     m_client->resetBitmapZoomScale(m_blockZoomFinalScale);
3060     m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3061     updateViewportSize();
3062
3063 #if ENABLE(VIEWPORT_REFLOW)
3064     requestLayoutIfNeeded();
3065     if (willUseTextReflow && m_shouldReflowBlock) {
3066         IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
3067         reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
3068         reflowedRect.move(roundTransformedPoint(m_finalBlockPointReflowOffset).x(), roundTransformedPoint(m_finalBlockPointReflowOffset).y());
3069         RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
3070         IntPoint topLeftPoint(reflowedRect.location());
3071         if (renderer && renderer->isText()) {
3072             ETextAlign textAlign = renderer->style()->textAlign();
3073             IntPoint textAnchor;
3074             switch (textAlign) {
3075             case CENTER:
3076             case WEBKIT_CENTER:
3077                 textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
3078                 break;
3079             case LEFT:
3080             case WEBKIT_LEFT:
3081                 textAnchor = topLeftPoint;
3082                 break;
3083             case RIGHT:
3084             case WEBKIT_RIGHT:
3085                 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
3086                 break;
3087             case TAAUTO:
3088             case JUSTIFY:
3089             default:
3090                 if (renderer->style()->isLeftToRightDirection())
3091                     textAnchor = topLeftPoint;
3092                 else
3093                     textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
3094                 break;
3095             }
3096             setScrollPosition(textAnchor);
3097         } else {
3098             renderer->style()->isLeftToRightDirection()
3099                 ? setScrollPosition(topLeftPoint)
3100                 : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
3101         }
3102     } else if (willUseTextReflow) {
3103         IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
3104         finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
3105         setScrollPosition(IntPoint(0, finalRect.y() + m_finalBlockPointReflowOffset.y()));
3106         resetBlockZoom();
3107     }
3108 #endif
3109     if (!willUseTextReflow) {
3110         setScrollPosition(anchor);
3111         if (!m_shouldReflowBlock)
3112             resetBlockZoom();
3113     }
3114
3115     notifyTransformChanged();
3116     m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
3117     m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
3118 }
3119
3120 void WebPage::blockZoomAnimationFinished()
3121 {
3122     d->zoomBlock();
3123 }
3124
3125 void WebPage::resetBlockZoom()
3126 {
3127     d->resetBlockZoom();
3128 }
3129
3130 void WebPagePrivate::resetBlockZoom()
3131 {
3132     m_currentBlockZoomNode = 0;
3133     m_currentBlockZoomAdjustedNode = 0;
3134     m_shouldReflowBlock = false;
3135 }
3136
3137 void WebPage::destroyWebPageCompositor()
3138 {
3139 #if USE(ACCELERATED_COMPOSITING)
3140     // Destroy the layer renderer in a sync command before we destroy the backing store,
3141     // to flush any pending compositing messages on the compositing thread.
3142     // The backing store is indirectly deleted by the 'detachFromParent' call below.
3143     d->syncDestroyCompositorOnCompositingThread();
3144 #endif
3145 }
3146
3147 void WebPage::destroy()
3148 {
3149     // TODO: need to verify if this call needs to be made before calling
3150     // WebPage::destroyWebPageCompositor()
3151     d->m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3152
3153     // Close the backforward list and release the cached pages.
3154     d->m_page->backForward()->close();
3155     pageCache()->releaseAutoreleasedPagesNow();
3156
3157     FrameLoader* loader = d->m_mainFrame->loader();
3158
3159     // Remove main frame's backing store client from the map
3160     // to prevent FrameLoaderClientBlackyBerry::detachFromParent2(),
3161     // which is called by loader->detachFromParent(), deleting it.
3162     // We will delete it in ~WebPagePrivate().
3163     // Reason: loader->detachFromParent() may ping back to backing store
3164     // indirectly through ChromeClientBlackBerry::invalidateContentsAndWindow().
3165     // see RIM PR #93256.
3166     d->removeBackingStoreClientForFrame(d->m_mainFrame);
3167
3168     // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion.
3169     d->m_mainFrame = 0;
3170     if (loader)
3171         loader->detachFromParent();
3172
3173     deleteGuardedObject(this);
3174 }
3175
3176 WebPageClient* WebPage::client() const
3177 {
3178     return d->m_client;
3179 }
3180
3181 int WebPage::backForwardListLength() const
3182 {
3183     return d->m_page->getHistoryLength();
3184 }
3185
3186 bool WebPage::canGoBackOrForward(int delta) const
3187 {
3188     return d->m_page->canGoBackOrForward(delta);
3189 }
3190
3191 bool WebPage::goBackOrForward(int delta)
3192 {
3193     if (d->m_page->canGoBackOrForward(delta)) {
3194         d->m_page->goBackOrForward(delta);
3195         return true;
3196     }
3197     return false;
3198 }
3199
3200 void WebPage::goToBackForwardEntry(BackForwardId id)
3201 {
3202     HistoryItem* item = historyItemFromBackForwardId(id);
3203     ASSERT(item);
3204     d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
3205 }
3206
3207 void WebPage::reload()
3208 {
3209     d->m_mainFrame->loader()->reload(/* bypassCache */ true);
3210 }
3211
3212 void WebPage::reloadFromCache()
3213 {
3214     d->m_mainFrame->loader()->reload(/* bypassCache */ false);
3215 }
3216
3217 WebSettings* WebPage::settings() const
3218 {
3219     return d->m_webSettings;
3220 }
3221
3222 bool WebPage::isVisible() const
3223 {
3224     return d->m_visible;
3225 }
3226
3227 #if ENABLE(PAGE_VISIBILITY_API)
3228 class DeferredTaskSetPageVisibilityState: public DeferredTask<&WebPagePrivate::m_wouldSetPageVisibilityState> {
3229 public:
3230     explicit DeferredTaskSetPageVisibilityState(WebPagePrivate* webPagePrivate)
3231         : DeferredTaskType(webPagePrivate)
3232     {
3233     }
3234 private:
3235     virtual void performInternal(WebPagePrivate* webPagePrivate)
3236     {
3237         webPagePrivate->setPageVisibilityState();
3238     }
3239 };
3240
3241 void WebPagePrivate::setPageVisibilityState()
3242 {
3243     if (m_page->defersLoading())
3244         m_deferredTasks.append(adoptPtr(new DeferredTaskSetPageVisibilityState(this)));
3245     else {
3246         DeferredTaskSetPageVisibilityState::finishOrCancel(this);
3247
3248         static bool s_initialVisibilityState = true;
3249
3250         m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
3251         s_initialVisibilityState = false;
3252     }
3253 }
3254 #endif
3255
3256 void WebPagePrivate::setVisible(bool visible)
3257 {
3258     m_visible = visible;
3259
3260 #if ENABLE(PAGE_VISIBILITY_API)
3261     setPageVisibilityState();
3262 #endif
3263 }
3264
3265 void WebPage::setVisible(bool visible)
3266 {
3267     if (d->m_visible == visible)
3268         return;
3269
3270     d->setVisible(visible);
3271
3272     if (!visible) {
3273         d->suspendBackingStore();
3274
3275         // Remove this WebPage from the visible pages list.
3276         size_t foundIndex = visibleWebPages()->find(this);
3277         if (foundIndex != WTF::notFound)
3278             visibleWebPages()->remove(foundIndex);
3279
3280         // Return the backing store to the last visible WebPage.
3281         if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
3282             visibleWebPages()->last()->d->resumeBackingStore();
3283
3284 #if USE(ACCELERATED_COMPOSITING)
3285         // Root layer commit is not necessary for invisible tabs.
3286         // And release layer resources can reduce memory consumption.
3287         d->suspendRootLayerCommit();
3288 #endif
3289
3290         return;
3291     }
3292
3293 #if USE(ACCELERATED_COMPOSITING)
3294     d->resumeRootLayerCommit();
3295 #endif
3296
3297     // Push this WebPage to the top of the visible pages list.
3298     if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
3299         size_t foundIndex = visibleWebPages()->find(this);
3300         if (foundIndex != WTF::notFound)
3301             visibleWebPages()->remove(foundIndex);
3302     }
3303     visibleWebPages()->append(this);
3304
3305     if (BackingStorePrivate::currentBackingStoreOwner()
3306         && BackingStorePrivate::currentBackingStoreOwner() != this)
3307         BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
3308
3309     // resumeBackingStore will set the current owner to this webpage.
3310     // If we set the owner prematurely, then the tiles will not be reset.
3311     d->resumeBackingStore();
3312 }
3313
3314 void WebPagePrivate::selectionChanged(Frame* frame)
3315 {
3316     m_inputHandler->selectionChanged();
3317
3318     // FIXME: This is a hack!
3319     // To ensure the selection being changed has its frame 'focused', lets
3320     // set it as focused ourselves (PR #104724).
3321     m_page->focusController()->setFocusedFrame(frame);
3322 }
3323
3324 void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
3325 {
3326     // Track a dispatched message, we don't want to flood the webkit thread.
3327     // There can be as many as one more message enqued as needed but never less.
3328     if (dispatched)
3329         m_updateDelegatedOverlaysDispatched = false;
3330     else if (m_updateDelegatedOverlaysDispatched) {
3331         // Early return if there is message already pending on the webkit thread.
3332         return;
3333     }
3334
3335     if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
3336         // Must be called on the WebKit thread.
3337         if (m_selectionHandler->isSelectionActive())
3338             m_selectionHandler->selectionPositionChanged();
3339         if (m_inspectorOverlay)
3340             m_inspectorOverlay->update();
3341
3342     } else if (m_selectionHandler->isSelectionActive()) {
3343         // Don't bother dispatching to webkit thread if selection and tap highlight are not active.
3344         m_updateDelegatedOverlaysDispatched = true;
3345         Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/));
3346     }
3347 }
3348
3349 void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle style)
3350 {
3351 }
3352
3353 bool WebPage::setBatchEditingActive(bool active)
3354 {
3355     return d->m_inputHandler->setBatchEditingActive(active);
3356 }
3357
3358 bool WebPage::setInputSelection(unsigned start, unsigned end)
3359 {
3360     if (d->m_page->defersLoading())
3361         return false;
3362     return d->m_inputHandler->setSelection(start, end);
3363 }
3364
3365 int WebPage::inputCaretPosition() const
3366 {
3367     return d->m_inputHandler->caretPosition();
3368 }
3369
3370 class DeferredTaskPopupListSelectMultiple: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectMultiple> {
3371 public:
3372     DeferredTaskPopupListSelectMultiple(WebPagePrivate* webPagePrivate, int size, const bool* selecteds) 
3373         : DeferredTaskType(webPagePrivate)
3374     {
3375         webPagePrivate->m_cachedPopupListSelecteds.append(selecteds, size);
3376     }
3377 private:
3378     virtual void performInternal(WebPagePrivate* webPagePrivate)
3379     {
3380         webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelecteds.size(), webPagePrivate->m_cachedPopupListSelecteds.data());
3381     }
3382 };
3383
3384 class DeferredTaskPopupListSelectSingle: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectSingle> {
3385 public:
3386     explicit DeferredTaskPopupListSelectSingle(WebPagePrivate* webPagePrivate, int index)
3387         : DeferredTaskType(webPagePrivate)
3388     {
3389         webPagePrivate->m_cachedPopupListSelectedIndex = index;
3390     }
3391 private:
3392     virtual void performInternal(WebPagePrivate* webPagePrivate)
3393     {
3394         webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelectedIndex);
3395     }
3396 };
3397
3398 void WebPage::popupListClosed(int size, const bool* selecteds)
3399 {
3400     DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3401     if (d->m_page->defersLoading()) {
3402         d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectMultiple(d, size, selecteds)));
3403         return;
3404     }
3405     DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3406     d->m_inputHandler->setPopupListIndexes(size, selecteds);
3407 }
3408
3409 void WebPage::popupListClosed(int index)
3410 {
3411     DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3412     if (d->m_page->defersLoading()) {
3413         d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectSingle(d, index)));
3414         return;
3415     }
3416     DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3417     d->m_inputHandler->setPopupListIndex(index);
3418 }
3419
3420 class DeferredTaskSetDateTimeInput: public DeferredTask<&WebPagePrivate::m_wouldSetDateTimeInput> {
3421 public:
3422     explicit DeferredTaskSetDateTimeInput(WebPagePrivate* webPagePrivate, WebString value)
3423         : DeferredTaskType(webPagePrivate)
3424     {
3425         webPagePrivate->m_cachedDateTimeInput = value;
3426     }
3427 private:
3428     virtual void performInternal(WebPagePrivate* webPagePrivate)
3429     {
3430         webPagePrivate->m_webPage->setDateTimeInput(webPagePrivate->m_cachedDateTimeInput);
3431     }
3432 };
3433
3434 void WebPage::setDateTimeInput(const WebString& value)
3435 {
3436     if (d->m_page->defersLoading()) {
3437         d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetDateTimeInput(d, value)));
3438         return;
3439     }
3440     DeferredTaskSetDateTimeInput::finishOrCancel(d);
3441     d->m_inputHandler->setInputValue(String(value.impl()));
3442 }
3443
3444 class DeferredTaskSetColorInput: public DeferredTask<&WebPagePrivate::m_wouldSetColorInput> {
3445 public:
3446     explicit DeferredTaskSetColorInput(WebPagePrivate* webPagePrivate, WebString value)
3447         : DeferredTaskType(webPagePrivate)
3448     {
3449         webPagePrivate->m_cachedColorInput = value;
3450     }
3451 private:
3452     virtual void performInternal(WebPagePrivate* webPagePrivate)
3453     {
3454         webPagePrivate->m_webPage->setColorInput(webPagePrivate->m_cachedColorInput);
3455     }
3456 };
3457
3458 void WebPage::setColorInput(const WebString& value)
3459 {
3460     if (d->m_page->defersLoading()) {
3461         d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetColorInput(d, value)));
3462         return;
3463     }
3464     DeferredTaskSetColorInput::finishOrCancel(d);
3465     d->m_inputHandler->setInputValue(String(value.impl()));
3466 }
3467
3468 void WebPage::setVirtualViewportSize(int width, int height)
3469 {
3470     d->m_virtualViewportWidth = width;
3471     d->m_virtualViewportHeight = height;
3472 }
3473
3474 void WebPage::resetVirtualViewportOnCommitted(bool reset)
3475 {
3476     d->m_resetVirtualViewportOnCommitted = reset;
3477 }
3478
3479 IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments()
3480 {
3481     static const ViewportArguments defaultViewportArguments;
3482     if (m_viewportArguments == defaultViewportArguments)
3483         return IntSize();
3484
3485     int desktopWidth = DEFAULT_MAX_LAYOUT_WIDTH;
3486     int deviceWidth = Platform::Graphics::Screen::primaryScreen()->width();
3487     int deviceHeight = Platform::Graphics::Screen::primaryScreen()->height();
3488     ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, m_webSettings->devicePixelRatio(), m_defaultLayoutSize);
3489
3490     setUserScalable(m_webSettings->isUserScalable() && result.userScalable);
3491     if (result.initialScale > 0)
3492         setInitialScale(result.initialScale * result.devicePixelRatio);
3493     if (result.minimumScale > 0)
3494         setMinimumScale(result.minimumScale * result.devicePixelRatio);
3495     if (result.maximumScale > 0)
3496         setMaximumScale(result.maximumScale * result.devicePixelRatio);
3497
3498     return IntSize(result.layoutSize.width(), result.layoutSize.height());
3499 }
3500
3501 #if ENABLE(EVENT_MODE_METATAGS)
3502 void WebPagePrivate::didReceiveCursorEventMode(CursorEventMode mode)
3503 {
3504     if (mode != m_cursorEventMode)
3505         m_client->cursorEventModeChanged(toPlatformCursorEventMode(mode));
3506     m_cursorEventMode = mode;
3507 }
3508
3509 void WebPagePrivate::didReceiveTouchEventMode(TouchEventMode mode)
3510 {
3511     if (mode != m_touchEventMode)
3512         m_client->touchEventModeChanged(toPlatformTouchEventMode(mode));
3513     m_touchEventMode = mode;
3514 }
3515 #endif
3516