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