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