[BlackBerry] Crash due to an assert in FrameView::doDeferredRepaints
[WebKit-https.git] / Source / WebKit / blackberry / Api / WebPage.cpp
1 /*
2  * Copyright (C) 2009, 2010, 2011, 2012, 2013 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20 #include "WebPage.h"
21
22 #include "APIShims.h"
23 #include "ApplicationCacheStorage.h"
24 #include "AuthenticationChallengeManager.h"
25 #include "AutofillManager.h"
26 #include "BackForwardController.h"
27 #include "BackForwardListBlackBerry.h"
28 #include "BackingStoreClient.h"
29 #include "BackingStore_p.h"
30 #if ENABLE(BATTERY_STATUS)
31 #include "BatteryClientBlackBerry.h"
32 #endif
33 #include "CachedImage.h"
34 #include "Chrome.h"
35 #include "ChromeClientBlackBerry.h"
36 #include "ContextMenuClientBlackBerry.h"
37 #include "CookieManager.h"
38 #include "CredentialManager.h"
39 #include "CredentialStorage.h"
40 #include "CredentialTransformData.h"
41 #include "DOMSupport.h"
42 #include "DatabaseManager.h"
43 #include "DefaultTapHighlight.h"
44 #include "DeviceMotionClientBlackBerry.h"
45 #include "DeviceOrientationClientBlackBerry.h"
46 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
47 #include "DeviceOrientationClientMock.h"
48 #endif
49 #include "DragClientBlackBerry.h"
50 // FIXME: We should be using DumpRenderTreeClient, but I'm not sure where we should
51 // create the DRT_BB object. See PR #120355.
52 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
53 #include "DumpRenderTreeBlackBerry.h"
54 #endif
55 #include "EditorClientBlackBerry.h"
56 #include "FocusController.h"
57 #include "Frame.h"
58 #include "FrameLoadRequest.h"
59 #include "FrameLoaderClientBlackBerry.h"
60 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
61 #include "GeolocationClientMock.h"
62 #endif
63 #include "GeolocationClientBlackBerry.h"
64 #include "GroupSettings.h"
65 #include "HTMLAreaElement.h"
66 #include "HTMLFrameOwnerElement.h"
67 #include "HTMLImageElement.h"
68 #include "HTMLInputElement.h"
69 #include "HTMLMediaElement.h"
70 #include "HTMLNames.h"
71 #include "HTMLParserIdioms.h"
72 #include "HTTPParsers.h"
73 #include "HistoryItem.h"
74 #include "IconDatabaseClientBlackBerry.h"
75 #include "ImageDocument.h"
76 #include "InPageSearchManager.h"
77 #include "InRegionScrollableArea.h"
78 #include "InRegionScroller_p.h"
79 #include "InputHandler.h"
80 #include "InspectorBackendDispatcher.h"
81 #include "InspectorClientBlackBerry.h"
82 #include "InspectorController.h"
83 #include "InspectorInstrumentation.h"
84 #include "InspectorOverlay.h"
85 #include "JavaScriptVariant_p.h"
86 #include "LayerWebKitThread.h"
87 #include "LocalFileSystem.h"
88 #if ENABLE(NETWORK_INFO)
89 #include "NetworkInfoClientBlackBerry.h"
90 #endif
91 #include "NetworkManager.h"
92 #include "NodeRenderStyle.h"
93 #include "NodeTraversal.h"
94 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
95 #include "NavigatorContentUtilsClientBlackBerry.h"
96 #endif
97 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
98 #include "NotificationClientBlackBerry.h"
99 #endif
100 #include "Page.h"
101 #include "PageCache.h"
102 #include "PageGroup.h"
103 #include "PagePopupBlackBerry.h"
104 #include "PlatformTouchEvent.h"
105 #include "PlatformWheelEvent.h"
106 #include "PluginDatabase.h"
107 #include "PluginView.h"
108 #include "RenderLayerBacking.h"
109 #include "RenderLayerCompositor.h"
110 #if ENABLE(FULLSCREEN_API)
111 #include "RenderFullScreen.h"
112 #endif
113 #include "RenderText.h"
114 #include "RenderThemeBlackBerry.h"
115 #include "RenderTreeAsText.h"
116 #include "RenderView.h"
117 #include "RenderWidget.h"
118 #include "ScriptController.h"
119 #include "ScriptSourceCode.h"
120 #include "ScriptValue.h"
121 #include "ScrollTypes.h"
122 #include "SecurityPolicy.h"
123 #include "SelectionHandler.h"
124 #include "SelectionOverlay.h"
125 #include "Settings.h"
126 #include "Storage.h"
127 #include "StorageNamespace.h"
128 #include "SurfacePool.h"
129 #include "Text.h"
130 #include "ThreadCheck.h"
131 #include "TouchEventHandler.h"
132 #include "TransformationMatrix.h"
133 #if ENABLE(MEDIA_STREAM)
134 #include "UserMediaClientImpl.h"
135 #endif
136 #if ENABLE(VIBRATION)
137 #include "VibrationClientBlackBerry.h"
138 #endif
139 #include "VisiblePosition.h"
140 #include "WebCookieJar.h"
141 #if ENABLE(WEBDOM)
142 #include "WebDOMDocument.h"
143 #endif
144 #include "WebKitThreadViewportAccessor.h"
145 #include "WebKitVersion.h"
146 #include "WebOverlay.h"
147 #include "WebOverlay_p.h"
148 #include "WebPageClient.h"
149 #include "WebSocket.h"
150 #include "WebViewportArguments.h"
151 #include "npapi.h"
152 #include "runtime_root.h"
153
154 #if ENABLE(VIDEO)
155 #include "MediaPlayer.h"
156 #include "MediaPlayerPrivateBlackBerry.h"
157 #endif
158
159 #if USE(ACCELERATED_COMPOSITING)
160 #include "FrameLayers.h"
161 #include "WebPageCompositorClient.h"
162 #include "WebPageCompositor_p.h"
163 #endif
164
165 #include <BlackBerryPlatformDeviceInfo.h>
166 #include <BlackBerryPlatformExecutableMessage.h>
167 #include <BlackBerryPlatformKeyboardEvent.h>
168 #include <BlackBerryPlatformMessageClient.h>
169 #include <BlackBerryPlatformMouseEvent.h>
170 #include <BlackBerryPlatformScreen.h>
171 #include <BlackBerryPlatformSettings.h>
172 #include <BlackBerryPlatformWebFileSystem.h>
173 #include <JavaScriptCore/APICast.h>
174 #include <JavaScriptCore/JSContextRef.h>
175 #include <JavaScriptCore/JSStringRef.h>
176 #include <SharedPointer.h>
177 #include <cmath>
178 #include <sys/keycodes.h>
179 #include <unicode/ustring.h> // platform ICU
180
181 #include <wtf/text/CString.h>
182
183 #ifndef USER_PROCESSES
184 #include <memalloc.h>
185 #endif
186
187 #if ENABLE(ACCELERATED_2D_CANVAS)
188 #include "GrContext.h"
189 #include "SharedGraphicsContext3D.h"
190 #endif
191
192 #if ENABLE(REQUEST_ANIMATION_FRAME)
193 #include "PlatformScreen.h"
194 #endif
195
196 #define DEBUG_TOUCH_EVENTS 0
197 #define DEBUG_WEBPAGE_LOAD 0
198 #define DEBUG_AC_COMMIT 0
199
200 using namespace std;
201 using namespace WebCore;
202
203 typedef const unsigned short* CUShortPtr;
204
205 namespace BlackBerry {
206 namespace WebKit {
207
208 static Vector<WebPage*>* visibleWebPages()
209 {
210     static Vector<WebPage*>* s_visibleWebPages = 0; // Initially, no web page is visible.
211     if (!s_visibleWebPages)
212         s_visibleWebPages = new Vector<WebPage*>;
213     return s_visibleWebPages;
214 }
215
216 const unsigned blockZoomMargin = 3; // Add 3 pixel margin on each side.
217 static int blockClickRadius = 0;
218 static double maximumBlockZoomScale = 3; // This scale can be clamped by the maximumScale set for the page.
219
220 const double manualScrollInterval = 0.1; // The time interval during which we associate user action with scrolling.
221
222 const IntSize minimumLayoutSize(10, 10); // Needs to be a small size, greater than 0, that we can grow the layout from.
223
224 const double minimumExpandingRatio = 0.15;
225
226 const double minimumZoomToFitScale = 0.25;
227 const double maximumImageDocumentZoomToFitScale = 2;
228
229 // Helper function to parse a URL and fill in missing parts.
230 static KURL parseUrl(const String& url)
231 {
232     String urlString(url);
233     KURL kurl = KURL(KURL(), urlString);
234     if (kurl.protocol().isEmpty()) {
235         urlString.insert("http://", 0);
236         kurl = KURL(KURL(), urlString);
237     }
238
239     return kurl;
240 }
241
242 // Helper functions to convert to and from WebCore types.
243 static inline WebCore::PlatformEvent::Type toWebCoreMouseEventType(const BlackBerry::Platform::MouseEvent::Type type)
244 {
245     switch (type) {
246     case BlackBerry::Platform::MouseEvent::MouseButtonDown:
247         return WebCore::PlatformEvent::MousePressed;
248     case Platform::MouseEvent::MouseButtonUp:
249         return WebCore::PlatformEvent::MouseReleased;
250     case Platform::MouseEvent::MouseMove:
251     default:
252         return WebCore::PlatformEvent::MouseMoved;
253     }
254 }
255
256 static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy)
257 {
258     switch (policy) {
259     case Platform::NetworkRequest::UseProtocolCachePolicy:
260         return UseProtocolCachePolicy;
261     case Platform::NetworkRequest::ReloadIgnoringCacheData:
262         return ReloadIgnoringCacheData;
263     case Platform::NetworkRequest::ReturnCacheDataElseLoad:
264         return ReturnCacheDataElseLoad;
265     case Platform::NetworkRequest::ReturnCacheDataDontLoad:
266         return ReturnCacheDataDontLoad;
267     default:
268         ASSERT_NOT_REACHED();
269         return UseProtocolCachePolicy;
270     }
271 }
272
273 #if ENABLE(EVENT_MODE_METATAGS)
274 static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode)
275 {
276     switch (mode) {
277     case ProcessedCursorEvents:
278         return Platform::ProcessedCursorEvents;
279     case NativeCursorEvents:
280         return Platform::NativeCursorEvents;
281     default:
282         ASSERT_NOT_REACHED();
283         return Platform::ProcessedCursorEvents;
284     }
285 }
286
287 static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode)
288 {
289     switch (mode) {
290     case ProcessedTouchEvents:
291         return Platform::ProcessedTouchEvents;
292     case NativeTouchEvents:
293         return Platform::NativeTouchEvents;
294     case PureTouchEventsWithMouseConversion:
295         return Platform::PureTouchEventsWithMouseConversion;
296     default:
297         ASSERT_NOT_REACHED();
298         return Platform::ProcessedTouchEvents;
299     }
300 }
301 #endif
302
303 static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id)
304 {
305     return reinterpret_cast<HistoryItem*>(id);
306 }
307
308 static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item)
309 {
310     return reinterpret_cast<WebPage::BackForwardId>(item);
311 }
312
313 void WebPage::setUserViewportArguments(const WebViewportArguments& viewportArguments)
314 {
315     d->m_userViewportArguments = *(viewportArguments.d);
316 }
317
318 void WebPage::resetUserViewportArguments()
319 {
320     d->m_userViewportArguments = ViewportArguments();
321 }
322
323 template <bool WebPagePrivate::* isActive>
324 class DeferredTask: public WebPagePrivate::DeferredTaskBase {
325 public:
326     static void finishOrCancel(WebPagePrivate* webPagePrivate)
327     {
328         webPagePrivate->*isActive = false;
329     }
330 protected:
331     DeferredTask(WebPagePrivate* webPagePrivate)
332         : DeferredTaskBase(webPagePrivate, isActive)
333     {
334     }
335     typedef DeferredTask<isActive> DeferredTaskType;
336 };
337
338 void WebPage::autofillTextField(const BlackBerry::Platform::String& item)
339 {
340     if (!d->m_webSettings->isFormAutofillEnabled())
341         return;
342
343     d->m_autofillManager->autofillTextField(item);
344 }
345
346 BlackBerry::Platform::String WebPage::renderTreeAsText()
347 {
348     return externalRepresentation(d->m_mainFrame);
349 }
350
351 WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
352     : m_webPage(webPage)
353     , m_client(client)
354     , m_inspectorClient(0)
355     , m_page(0) // Initialized by init.
356     , m_mainFrame(0) // Initialized by init.
357     , m_currentContextNode(0)
358     , m_webSettings(0) // Initialized by init.
359     , m_cookieJar(0)
360     , m_visible(false)
361     , m_activationState(ActivationActive)
362     , m_shouldResetTilesWhenShown(false)
363     , m_shouldZoomToInitialScaleAfterLoadFinished(false)
364     , m_userScalable(true)
365     , m_userPerformedManualZoom(false)
366     , m_userPerformedManualScroll(false)
367     , m_contentsSizeChanged(false)
368     , m_overflowExceedsContentsSize(false)
369     , m_resetVirtualViewportOnCommitted(true)
370     , m_shouldUseFixedDesktopMode(false)
371     , m_inspectorEnabled(false)
372     , m_preventIdleDimmingCount(0)
373 #if ENABLE(TOUCH_EVENTS)
374     , m_preventDefaultOnTouchStart(false)
375 #endif
376     , m_nestedLayoutFinishedCount(0)
377     , m_actualVisibleWidth(rect.width())
378     , m_actualVisibleHeight(rect.height())
379     , m_defaultLayoutSize(minimumLayoutSize)
380     , m_didRestoreFromPageCache(false)
381     , m_viewMode(WebPagePrivate::Desktop) // Default to Desktop mode for PB.
382     , m_loadState(WebPagePrivate::None)
383     , m_transformationMatrix(new TransformationMatrix())
384     , m_backingStore(0) // Initialized by init.
385     , m_backingStoreClient(0) // Initialized by init.
386     , m_webkitThreadViewportAccessor(new WebKitThreadViewportAccessor(this))
387     , m_inPageSearchManager(new InPageSearchManager(this))
388     , m_inputHandler(new InputHandler(this))
389     , m_selectionHandler(new SelectionHandler(this))
390     , m_touchEventHandler(new TouchEventHandler(this))
391     , m_proximityDetector(new ProximityDetector(this))
392 #if ENABLE(EVENT_MODE_METATAGS)
393     , m_cursorEventMode(ProcessedCursorEvents)
394     , m_touchEventMode(ProcessedTouchEvents)
395 #endif
396 #if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
397     , m_scaleBeforeFullScreen(-1.0)
398 #endif
399     , m_currentCursor(Platform::CursorNone)
400     , m_dumpRenderTree(0) // Lazy initialization.
401     , m_initialScale(-1.0)
402     , m_minimumScale(-1.0)
403     , m_maximumScale(-1.0)
404     , m_forceRespectViewportArguments(false)
405     , m_anchorInNodeRectRatio(-1, -1)
406     , m_currentBlockZoomNode(0)
407     , m_currentBlockZoomAdjustedNode(0)
408     , m_shouldReflowBlock(false)
409     , m_lastUserEventTimestamp(0.0)
410     , m_pluginMouseButtonPressed(false)
411     , m_pluginMayOpenNewTab(false)
412 #if USE(ACCELERATED_COMPOSITING)
413     , m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
414     , m_needsOneShotDrawingSynchronization(false)
415     , m_needsCommit(false)
416     , m_suspendRootLayerCommit(false)
417 #endif
418     , m_pendingOrientation(-1)
419     , m_fullscreenNode(0)
420     , m_hasInRegionScrollableAreas(false)
421     , m_updateDelegatedOverlaysDispatched(false)
422     , m_deferredTasksTimer(this, &WebPagePrivate::deferredTasksTimerFired)
423     , m_selectPopup(0)
424     , m_autofillManager(AutofillManager::create(this))
425     , m_documentStyleRecalcPostponed(false)
426     , m_documentChildNeedsStyleRecalc(false)
427 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
428     , m_notificationManager(this)
429 #endif
430     , m_didStartAnimations(false)
431     , m_animationStartTime(0)
432 {
433     static bool isInitialized = false;
434     if (!isInitialized) {
435         isInitialized = true;
436         BlackBerry::Platform::DeviceInfo::instance();
437         defaultUserAgent();
438     }
439
440     AuthenticationChallengeManager::instance()->pageCreated(this);
441     clearCachedHitTestResult();
442 }
443
444 WebPage::WebPage(WebPageClient* client, const BlackBerry::Platform::String& pageGroupName, const Platform::IntRect& rect)
445 {
446     globalInitialize();
447     d = new WebPagePrivate(this, client, rect);
448     d->init(pageGroupName);
449 }
450
451 WebPagePrivate::~WebPagePrivate()
452 {
453     // Hand the backingstore back to another owner if necessary.
454     m_webPage->setVisible(false);
455     if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage)
456         BackingStorePrivate::setCurrentBackingStoreOwner(0);
457
458     delete m_webSettings;
459     m_webSettings = 0;
460
461     delete m_cookieJar;
462     m_cookieJar = 0;
463
464     delete m_webkitThreadViewportAccessor;
465     m_webkitThreadViewportAccessor = 0;
466
467     delete m_backingStoreClient;
468     m_backingStoreClient = 0;
469     m_backingStore = 0;
470
471     delete m_page;
472     m_page = 0;
473
474     delete m_transformationMatrix;
475     m_transformationMatrix = 0;
476
477     delete m_inPageSearchManager;
478     m_inPageSearchManager = 0;
479
480     delete m_selectionHandler;
481     m_selectionHandler = 0;
482
483     delete m_inputHandler;
484     m_inputHandler = 0;
485
486     delete m_touchEventHandler;
487     m_touchEventHandler = 0;
488
489     delete m_proximityDetector;
490     m_proximityDetector = 0;
491
492 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
493     BlackBerry::Platform::deleteGuardedObject(static_cast<DumpRenderTree*>(m_dumpRenderTree));
494     m_dumpRenderTree = 0;
495 #endif
496
497     AuthenticationChallengeManager::instance()->pageDeleted(this);
498 }
499
500 WebPage::~WebPage()
501 {
502     deleteGuardedObject(d);
503     d = 0;
504 }
505
506 Page* WebPagePrivate::core(const WebPage* webPage)
507 {
508     return webPage->d->m_page;
509 }
510
511 void WebPagePrivate::init(const BlackBerry::Platform::String& pageGroupName)
512 {
513     m_webSettings = WebSettings::createFromStandardSettings();
514     m_webSettings->setUserAgentString(defaultUserAgent());
515
516     ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this);
517 #if ENABLE(CONTEXT_MENUS)
518     ContextMenuClientBlackBerry* contextMenuClient = 0;
519     contextMenuClient = new ContextMenuClientBlackBerry();
520 #endif
521     EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this);
522     DragClientBlackBerry* dragClient = 0;
523 #if ENABLE(DRAG_SUPPORT)
524     dragClient = new DragClientBlackBerry();
525 #endif
526 #if ENABLE(INSPECTOR)
527     m_inspectorClient = new InspectorClientBlackBerry(this);
528 #endif
529
530     FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry();
531
532     Page::PageClients pageClients;
533     pageClients.chromeClient = chromeClient;
534 #if ENABLE(CONTEXT_MENUS)
535     pageClients.contextMenuClient = contextMenuClient;
536 #endif
537     pageClients.editorClient = editorClient;
538     pageClients.dragClient = dragClient;
539     pageClients.inspectorClient = m_inspectorClient;
540     pageClients.backForwardClient = BackForwardListBlackBerry::create(this);
541
542     m_page = new Page(pageClients);
543 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
544     if (isRunningDrt()) {
545         // In case running in DumpRenderTree mode set the controller to mock provider.
546         GeolocationClientMock* mock = new GeolocationClientMock();
547         WebCore::provideGeolocationTo(m_page, mock);
548         mock->setController(WebCore::GeolocationController::from(m_page));
549     } else
550 #endif
551         WebCore::provideGeolocationTo(m_page, new GeolocationClientBlackBerry(this));
552 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
553     if (getenv("drtRun"))
554         WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientMock);
555     else
556 #endif
557         WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientBlackBerry(this));
558
559     WebCore::provideDeviceMotionTo(m_page, new DeviceMotionClientBlackBerry(this));
560 #if ENABLE(VIBRATION)
561     WebCore::provideVibrationTo(m_page, new VibrationClientBlackBerry());
562 #endif
563
564 #if ENABLE(BATTERY_STATUS)
565     WebCore::provideBatteryTo(m_page, new WebCore::BatteryClientBlackBerry(this));
566 #endif
567
568 #if ENABLE(MEDIA_STREAM)
569     WebCore::provideUserMediaTo(m_page, new UserMediaClientImpl(m_webPage));
570 #endif
571
572 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
573     WebCore::provideNotification(m_page, new NotificationClientBlackBerry(this));
574 #endif
575
576 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
577     m_navigatorContentUtilsClient = adoptPtr(new NavigatorContentUtilsClientBlackBerry(this));
578     WebCore::provideNavigatorContentUtilsTo(m_page, m_navigatorContentUtilsClient.get());
579 #endif
580
581 #if ENABLE(NETWORK_INFO)
582     WebCore::provideNetworkInfoTo(m_page, new WebCore::NetworkInfoClientBlackBerry(this));
583 #endif
584
585     m_page->setDeviceScaleFactor(m_webSettings->devicePixelRatio());
586
587     m_page->addLayoutMilestones(DidFirstVisuallyNonEmptyLayout);
588
589 #if USE(ACCELERATED_COMPOSITING)
590     m_tapHighlight = DefaultTapHighlight::create(this);
591     m_selectionHighlight = DefaultTapHighlight::create(this);
592     m_selectionOverlay = SelectionOverlay::create(this);
593     m_page->settings()->setAcceleratedCompositingForFixedPositionEnabled(true);
594 #endif
595
596     // FIXME: We explicitly call setDelegate() instead of passing ourself in createFromStandardSettings()
597     // so that we only get one didChangeSettings() callback when we set the page group name. This causes us
598     // to make a copy of the WebSettings since some WebSettings method make use of the page group name.
599     // Instead, we shouldn't be storing the page group name in WebSettings.
600     m_webSettings->setPageGroupName(pageGroupName);
601     m_webSettings->setDelegate(this);
602     didChangeSettings(m_webSettings);
603
604     RefPtr<Frame> newFrame = Frame::create(m_page, /* HTMLFrameOwnerElement* */ 0, frameLoaderClient);
605
606     m_mainFrame = newFrame.get();
607     frameLoaderClient->setFrame(m_mainFrame, this);
608     m_mainFrame->init();
609
610     m_inRegionScroller = adoptPtr(new InRegionScroller(this));
611
612 #if ENABLE(WEBGL)
613     m_page->settings()->setWebGLEnabled(true);
614 #endif
615 #if ENABLE(ACCELERATED_2D_CANVAS)
616     m_page->settings()->setCanvasUsesAcceleratedDrawing(true);
617     m_page->settings()->setAccelerated2dCanvasEnabled(true);
618 #endif
619
620     m_page->settings()->setInteractiveFormValidationEnabled(true);
621     m_page->settings()->setAllowUniversalAccessFromFileURLs(false);
622     m_page->settings()->setAllowFileAccessFromFileURLs(false);
623     m_page->settings()->setFixedPositionCreatesStackingContext(true);
624     m_page->settings()->setWantsBalancedSetDefersLoadingBehavior(true);
625
626     m_backingStoreClient = BackingStoreClient::create(m_mainFrame, /* parent frame */ 0, m_webPage);
627     // The direct access to BackingStore is left here for convenience since it
628     // is owned by BackingStoreClient and then deleted by its destructor.
629     m_backingStore = m_backingStoreClient->backingStore();
630
631     blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(0).width())); // The clicked rectangle area should be a fixed unit of measurement.
632
633     m_page->settings()->setDelegateSelectionPaint(true);
634
635 #if ENABLE(REQUEST_ANIMATION_FRAME)
636     m_page->windowScreenDidChange((PlatformDisplayID)0);
637 #endif
638
639 #if ENABLE(WEB_TIMING)
640     m_page->settings()->setMemoryInfoEnabled(true);
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 ENABLE(ACCELERATED_2D_CANVAS)
1056             if (m_page->settings()->canvasUsesAcceleratedDrawing()) {
1057                 // Free GPU resources as we're on a new page.
1058                 // This will help us to free memory pressure.
1059                 SharedGraphicsContext3D::get()->makeContextCurrent();
1060                 GrContext* grContext = Platform::Graphics::getGrContext();
1061                 grContext->freeGpuResources();
1062             }
1063 #endif
1064
1065 #if USE(ACCELERATED_COMPOSITING)
1066             releaseLayerResources();
1067 #endif
1068
1069             // Suspend screen update to avoid ui thread blitting while resetting backingstore.
1070             // FIXME: Do we really need to suspend/resume both backingstore and screen here?
1071             m_backingStore->d->suspendBackingStoreUpdates();
1072             m_backingStore->d->suspendScreenUpdates();
1073
1074             m_previousContentsSize = IntSize();
1075             m_backingStore->d->resetRenderQueue();
1076             m_backingStore->d->resetTiles();
1077             m_backingStore->d->setScrollingOrZooming(false, false /* shouldBlit */);
1078             m_shouldZoomToInitialScaleAfterLoadFinished = false;
1079             m_userPerformedManualZoom = false;
1080             m_userPerformedManualScroll = false;
1081             m_shouldUseFixedDesktopMode = false;
1082             m_forceRespectViewportArguments = false;
1083             if (m_resetVirtualViewportOnCommitted) // For DRT.
1084                 m_virtualViewportSize = IntSize();
1085             if (m_webSettings->viewportWidth() > 0)
1086                 m_virtualViewportSize = IntSize(m_webSettings->viewportWidth(), m_defaultLayoutSize.height());
1087
1088             // Check if we have already process the meta viewport tag, this only happens on history navigation.
1089             // For back/forward history navigation, we should only keep these previous values if the document
1090             // has the meta viewport tag when the state is Committed in setLoadState.
1091             static ViewportArguments defaultViewportArguments;
1092             bool documentHasViewportArguments = false;
1093             if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->viewportArguments() != defaultViewportArguments)
1094                 documentHasViewportArguments = true;
1095             if (!(m_didRestoreFromPageCache && documentHasViewportArguments)) {
1096                 m_viewportArguments = ViewportArguments();
1097                 m_userScalable = m_webSettings->isUserScalable();
1098                 resetScales();
1099
1100                 // At the moment we commit a new load, set the viewport arguments
1101                 // to any fallback values. If there is a meta viewport in the
1102                 // content it will overwrite the fallback arguments soon.
1103                 dispatchViewportPropertiesDidChange(m_userViewportArguments);
1104                 if (m_userViewportArguments != defaultViewportArguments)
1105                     m_forceRespectViewportArguments = true;
1106             } else {
1107                 Platform::IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
1108                 m_webPage->setVirtualViewportSize(virtualViewport);
1109             }
1110
1111             if (m_shouldUseFixedDesktopMode)
1112                 setViewMode(FixedDesktop);
1113             else
1114                 setViewMode(Desktop);
1115
1116 #if ENABLE(EVENT_MODE_METATAGS)
1117             didReceiveCursorEventMode(ProcessedCursorEvents);
1118             didReceiveTouchEventMode(ProcessedTouchEvents);
1119 #endif
1120
1121             // Reset block zoom and reflow.
1122             resetBlockZoom();
1123 #if ENABLE(VIEWPORT_REFLOW)
1124             toggleTextReflowIfEnabledForBlockZoomOnly();
1125 #endif
1126
1127             // Notify InputHandler of state change.
1128             m_inputHandler->setInputModeEnabled(false);
1129
1130             // Set the scroll to origin here and notify the client since we'll be
1131             // zooming below without any real contents yet thus the contents size
1132             // we report to the client could make our current scroll position invalid.
1133             setScrollPosition(IntPoint::zero());
1134             notifyTransformedScrollChanged();
1135
1136             // FIXME: Do we really need to suspend/resume both backingstore and screen here?
1137             m_backingStore->d->resumeBackingStoreUpdates();
1138             // Paints the visible backingstore as white. Note it is important we do
1139             // this strictly after re-setting the scroll position to origin and resetting
1140             // the scales otherwise the visible contents calculation is wrong and we
1141             // can end up blitting artifacts instead. See: RIM Bug #401.
1142             m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit);
1143
1144             // Update cursor status.
1145             updateCursor();
1146
1147             break;
1148         }
1149     case Finished:
1150     case Failed:
1151         // Notify client of the initial zoom change.
1152         m_client->scaleChanged();
1153         m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
1154         break;
1155     default:
1156         break;
1157     }
1158 }
1159
1160 double WebPagePrivate::clampedScale(double scale) const
1161 {
1162     if (scale < minimumScale())
1163         return minimumScale();
1164     if (scale > maximumScale())
1165         return maximumScale();
1166     return scale;
1167 }
1168
1169 bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale)
1170 {
1171     if (!m_mainFrame || !m_mainFrame->view())
1172         return false;
1173
1174     if (enforceScaleClamping)
1175         scale = this->clampedScale(scale);
1176
1177     ASSERT(clampedScale);
1178     *clampedScale = scale;
1179
1180     if (currentScale() == scale)
1181         return false;
1182
1183     return true;
1184 }
1185
1186 bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel)
1187 {
1188     if (!isRestoringZoomLevel) {
1189         // Clear any existing block zoom.  (If we are restoring a saved zoom level on page load,
1190         // there is guaranteed to be no existing block zoom and we don't want to clear m_shouldReflowBlock.)
1191         resetBlockZoom();
1192     }
1193
1194     // The reflow and block zoom stuff here needs to happen regardless of
1195     // whether we shouldZoomAboutPoint.
1196 #if ENABLE(VIEWPORT_REFLOW)
1197     toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
1198     if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view())
1199         setNeedsLayout();
1200 #endif
1201
1202     double scale;
1203     if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1204         if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1205             m_currentPinchZoomNode = 0;
1206             m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1207         }
1208         return false;
1209     }
1210     TransformationMatrix zoom;
1211     zoom.scale(scale);
1212
1213 #if DEBUG_WEBPAGE_LOAD
1214     if (loadState() < Finished) {
1215         Platform::logAlways(Platform::LogLevelInfo,
1216             "WebPagePrivate::zoomAboutPoint scale %f anchor %s",
1217             scale, Platform::FloatPoint(anchor).toString().c_str());
1218     }
1219 #endif
1220
1221     // Our current scroll position in float.
1222     FloatPoint scrollPosition = this->scrollPosition();
1223
1224     // Anchor offset from scroll position in float.
1225     FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y());
1226
1227     // The horizontal scaling factor and vertical scaling factor should be equal
1228     // to preserve aspect ratio of content.
1229     ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22());
1230
1231     // Need to invert the previous transform to anchor the viewport.
1232     double inverseScale = scale / m_transformationMatrix->m11();
1233
1234     // Actual zoom.
1235     *m_transformationMatrix = zoom;
1236
1237     // Suspend all screen updates to the backingstore.
1238     // FIXME: Do we really need to suspend/resume both backingstore and screen here?
1239     m_backingStore->d->suspendBackingStoreUpdates();
1240     m_backingStore->d->suspendScreenUpdates();
1241
1242     updateViewportSize();
1243
1244     IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))),
1245         max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale)))));
1246
1247     if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1248         // This is a hack for email which has reflow always turned on.
1249         setNeedsLayout();
1250         layoutIfNeeded();
1251         if (m_currentPinchZoomNode)
1252             newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale);
1253         m_currentPinchZoomNode = 0;
1254         m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1255     }
1256
1257     setScrollPosition(newScrollPosition);
1258
1259     notifyTransformChanged();
1260
1261     bool isLoading = this->isLoading();
1262
1263     // We need to invalidate all tiles both visible and non-visible if we're loading.
1264     m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */);
1265
1266     bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering;
1267
1268     m_client->scaleChanged();
1269
1270     if (m_pendingOrientation != -1)
1271         m_client->updateInteractionViews();
1272
1273     // FIXME: Do we really need to suspend/resume both backingstore and screen here?
1274     m_backingStore->d->resumeBackingStoreUpdates();
1275
1276     // Clear window to make sure there are no artifacts.
1277     if (shouldRender) {
1278         // Resume all screen updates to the backingstore and render+blit visible contents to screen.
1279         m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit);
1280     } else {
1281         // Resume all screen updates to the backingstore but do not blit to the screen because we not rendering.
1282         m_backingStore->d->resumeScreenUpdates(BackingStore::None);
1283     }
1284
1285     return true;
1286 }
1287
1288 IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale)
1289 {
1290     // Should only be invoked when text reflow is enabled.
1291     ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
1292
1293     int offsetY = 0;
1294     int offsetX = 0;
1295
1296     IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
1297
1298     if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) {
1299         offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y();
1300         if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0)
1301             offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale;
1302     }
1303
1304     IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get());
1305
1306     return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))),
1307         max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale))));
1308 }
1309
1310 void WebPagePrivate::setNeedsLayout()
1311 {
1312     FrameView* view = m_mainFrame->view();
1313     ASSERT(view);
1314     view->setNeedsLayout();
1315 }
1316
1317 void WebPagePrivate::updateLayoutAndStyleIfNeededRecursive() const
1318 {
1319     FrameView* view = m_mainFrame->view();
1320     ASSERT(view);
1321     view->updateLayoutAndStyleIfNeededRecursive();
1322     ASSERT(!view->needsLayout());
1323 }
1324
1325 void WebPagePrivate::layoutIfNeeded() const
1326 {
1327     FrameView* view = m_mainFrame->view();
1328     ASSERT(view);
1329     if (view->needsLayout())
1330         view->layout();
1331 }
1332
1333 IntPoint WebPagePrivate::scrollPosition() const
1334 {
1335     if (!m_backingStoreClient)
1336         return IntPoint();
1337
1338     return m_backingStoreClient->scrollPosition();
1339 }
1340
1341 IntPoint WebPagePrivate::maximumScrollPosition() const
1342 {
1343     if (!m_backingStoreClient)
1344         return IntPoint();
1345
1346     return m_backingStoreClient->maximumScrollPosition();
1347 }
1348
1349 void WebPagePrivate::setScrollPosition(const IntPoint& pos)
1350 {
1351     ASSERT(m_backingStoreClient);
1352     m_backingStoreClient->setScrollPosition(pos);
1353 }
1354
1355 // Setting the scroll position is in transformed coordinates.
1356 void WebPage::setDocumentScrollPosition(const Platform::IntPoint& documentScrollPosition)
1357 {
1358     WebCore::IntPoint scrollPosition = documentScrollPosition;
1359     if (scrollPosition == d->scrollPosition())
1360         return;
1361
1362     // If the user recently performed an event, this new scroll position
1363     // could possibly be a result of that. Or not, this is just a heuristic.
1364     if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
1365         d->m_userPerformedManualScroll = true;
1366
1367     d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1368
1369     // UI thread can call BackingStorePrivate::setScrollingOrZooming(false) before WebKit thread calls WebPage::setScrollPosition(),
1370     // in which case it will set ScrollableArea::m_constrainsScrollingToContentEdge to true earlier.
1371     // We can cache ScrollableArea::m_constrainsScrollingToContentEdge and always set it to false before we set scroll position in
1372     // WebKit thread to avoid scroll position clamping during scrolling, and restore it to what it was after that.
1373     bool constrainsScrollingToContentEdge = d->m_mainFrame->view()->constrainsScrollingToContentEdge();
1374     d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(false);
1375     d->setScrollPosition(scrollPosition);
1376     d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge);
1377
1378     d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1379 }
1380
1381 bool WebPagePrivate::shouldSendResizeEvent()
1382 {
1383     if (!m_mainFrame || !m_mainFrame->document())
1384         return false;
1385
1386     // PR#96865 : Provide an option to always send resize events, regardless of the loading
1387     //            status. The scenario for this are Sapphire applications which tend to
1388     //            maintain an open GET request to the server. This open GET results in
1389     //            webkit thinking that content is still arriving when at the application
1390     //            level it is considered fully loaded.
1391     //
1392     //            NOTE: Care must be exercised in the use of this option, as it bypasses
1393     //                  the sanity provided in 'isLoadingInAPISense()' below.
1394     //
1395     static const bool unrestrictedResizeEvents = Platform::Settings::instance()->unrestrictedResizeEvents();
1396     if (unrestrictedResizeEvents)
1397         return true;
1398
1399     // Don't send the resize event if the document is loading. Some pages automatically reload
1400     // when the window is resized; Safari on iPhone often resizes the window while setting up its
1401     // viewport. This obviously can cause problems.
1402     DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
1403     if (documentLoader && documentLoader->isLoadingInAPISense())
1404         return false;
1405
1406     return true;
1407 }
1408
1409 void WebPagePrivate::willDeferLoading()
1410 {
1411     m_deferredTasksTimer.stop();
1412     m_client->willDeferLoading();
1413 }
1414
1415 void WebPagePrivate::didResumeLoading()
1416 {
1417     if (!m_deferredTasks.isEmpty())
1418         m_deferredTasksTimer.startOneShot(0);
1419     m_client->didResumeLoading();
1420 }
1421
1422 void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*)
1423 {
1424     ASSERT(!m_deferredTasks.isEmpty());
1425     if (m_deferredTasks.isEmpty())
1426         return;
1427
1428     OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release();
1429     m_deferredTasks.remove(0);
1430
1431     if (!m_deferredTasks.isEmpty())
1432         m_deferredTasksTimer.startOneShot(0);
1433
1434     task->perform(this);
1435 }
1436
1437 void WebPagePrivate::notifyInRegionScrollStopped()
1438 {
1439     if (m_inRegionScroller->d->isActive())
1440         m_inRegionScroller->d->reset();
1441 }
1442
1443 void WebPage::notifyInRegionScrollStopped()
1444 {
1445     d->notifyInRegionScrollStopped();
1446 }
1447
1448 void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
1449 {
1450     if (b != m_hasInRegionScrollableAreas)
1451         m_hasInRegionScrollableAreas = b;
1452 }
1453
1454 IntSize WebPagePrivate::viewportSize() const
1455 {
1456     return m_webkitThreadViewportAccessor->roundToDocumentFromPixelContents(Platform::IntRect(Platform::IntPoint::zero(), transformedViewportSize())).size();
1457 }
1458
1459 IntSize WebPagePrivate::actualVisibleSize() const
1460 {
1461     return m_webkitThreadViewportAccessor->documentViewportSize();
1462 }
1463
1464 bool WebPagePrivate::hasVirtualViewport() const
1465 {
1466     return !m_virtualViewportSize.isEmpty();
1467 }
1468
1469 void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
1470 {
1471     // This checks to make sure we're not calling updateViewportSize
1472     // during WebPagePrivate::init().
1473     if (!m_backingStore)
1474         return;
1475     ASSERT(m_mainFrame->view());
1476     IntSize visibleSize = actualVisibleSize();
1477     if (setFixedReportedSize)
1478         m_mainFrame->view()->setFixedReportedSize(visibleSize);
1479
1480     IntRect frameRect = IntRect(scrollPosition(), visibleSize);
1481     if (frameRect != m_mainFrame->view()->frameRect()) {
1482         m_mainFrame->view()->setFrameRect(frameRect);
1483         m_mainFrame->view()->adjustViewSize();
1484
1485 #if ENABLE(FULLSCREEN_API)
1486         adjustFullScreenElementDimensionsIfNeeded();
1487 #endif
1488     }
1489
1490     // We're going to need to send a resize event to JavaScript because
1491     // innerWidth and innerHeight depend on fixed reported size.
1492     // This is how we support mobile pages where JavaScript resizes
1493     // the page in order to get around the fixed layout size, e.g.
1494     // google maps when it detects a mobile user agent.
1495     if (sendResizeEvent && shouldSendResizeEvent())
1496         m_mainFrame->eventHandler()->sendResizeEvent();
1497
1498     // When the actual visible size changes, we also
1499     // need to reposition fixed elements.
1500     m_mainFrame->view()->repaintFixedElementsAfterScrolling();
1501 }
1502
1503 FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
1504 {
1505     // The visible contents rect in float.
1506     FloatRect visibleContentsRect = this->visibleContentsRect();
1507
1508     // The center of the visible contents rect in float.
1509     return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
1510         visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
1511 }
1512
1513 IntRect WebPagePrivate::visibleContentsRect() const
1514 {
1515     return m_backingStoreClient->visibleContentsRect();
1516 }
1517
1518 IntSize WebPagePrivate::contentsSize() const
1519 {
1520     if (!m_mainFrame || !m_mainFrame->view())
1521         return IntSize();
1522
1523     return m_backingStoreClient->contentsSize();
1524 }
1525
1526 IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
1527 {
1528     if (!m_mainFrame || !m_mainFrame->contentRenderer())
1529         return IntSize();
1530
1531     return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
1532 }
1533
1534 void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
1535 {
1536     if (m_previousContentsSize == contentsSize)
1537         return;
1538
1539     // This should only occur in the middle of layout so we set a flag here and
1540     // handle it at the end of the layout.
1541     m_contentsSizeChanged = true;
1542
1543 #if DEBUG_WEBPAGE_LOAD
1544     Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %s", Platform::IntSize(contentsSize).toString().c_str());
1545 #endif
1546 }
1547
1548 void WebPagePrivate::overflowExceedsContentsSize()
1549 {
1550     m_overflowExceedsContentsSize = true;
1551     if (absoluteVisibleOverflowSize().width() < DEFAULT_MAX_LAYOUT_WIDTH && !hasVirtualViewport()) {
1552         if (setViewMode(viewMode())) {
1553             setNeedsLayout();
1554             layoutIfNeeded();
1555         }
1556     }
1557 }
1558
1559 void WebPagePrivate::layoutFinished()
1560 {
1561     // If a layout change has occurred, we need to invalidate any current spellcheck requests and trigger a new run.
1562     m_inputHandler->stopPendingSpellCheckRequests(true /* isRestartRequired */);
1563
1564     if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
1565         return;
1566
1567     m_contentsSizeChanged = false; // Toggle to turn off notification again.
1568     m_overflowExceedsContentsSize = false;
1569
1570     if (contentsSize().isEmpty())
1571         return;
1572
1573     // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from
1574     // the middle of a layout, but the recursion is limited by detection code in
1575     // setViewMode() and mitigation code in fixedLayoutSize().
1576     if (didLayoutExceedMaximumIterations()) {
1577         notifyTransformedContentsSizeChanged();
1578         return;
1579     }
1580
1581     // Temporarily save the m_previousContentsSize here before updating it (in
1582     // notifyTransformedContentsSizeChanged()) so we can compare if our contents
1583     // shrunk afterwards.
1584     IntSize previousContentsSize = m_previousContentsSize;
1585
1586     m_nestedLayoutFinishedCount++;
1587
1588     if (shouldZoomToInitialScaleOnLoad()) {
1589         zoomToInitialScaleOnLoad();
1590         m_shouldZoomToInitialScaleAfterLoadFinished = false;
1591     } else if (loadState() != None)
1592         notifyTransformedContentsSizeChanged();
1593
1594     m_nestedLayoutFinishedCount--;
1595
1596     if (!m_nestedLayoutFinishedCount) {
1597         // When the contents shrinks, there is a risk that we
1598         // will be left at a scroll position that lies outside of the
1599         // contents rect. Since we allow overscrolling and neglect
1600         // to clamp overscroll in order to retain input focus (RIM Bug #414)
1601         // we need to clamp somewhere, and this is where we know the
1602         // contents size has changed.
1603
1604         if (contentsSize() != previousContentsSize) {
1605
1606             IntPoint newScrollPosition = scrollPosition();
1607
1608             if (contentsSize().height() < previousContentsSize.height()) {
1609                 IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
1610                 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
1611             }
1612
1613             if (contentsSize().width() < previousContentsSize.width()) {
1614                 IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
1615                 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
1616             }
1617
1618             if (newScrollPosition != scrollPosition()) {
1619                 setScrollPosition(newScrollPosition);
1620                 notifyTransformedScrollChanged();
1621             }
1622
1623             const Platform::IntSize pixelContentsSize = m_webkitThreadViewportAccessor->pixelContentsSize();
1624
1625             // If the content size is too small, zoom it to fit the viewport.
1626             if ((loadState() == Finished || loadState() == Committed) && (pixelContentsSize.width() < m_actualVisibleWidth || pixelContentsSize.height() < m_actualVisibleHeight))
1627                 zoomAboutPoint(initialScale(), newScrollPosition);
1628         }
1629     }
1630 }
1631
1632 void WebPagePrivate::zoomToInitialScaleOnLoad()
1633 {
1634 #if DEBUG_WEBPAGE_LOAD
1635     Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
1636 #endif
1637
1638     bool needsLayout = false;
1639
1640     // If the contents width exceeds the viewport width set to desktop mode.
1641     if (m_shouldUseFixedDesktopMode)
1642         needsLayout = setViewMode(FixedDesktop);
1643     else
1644         needsLayout = setViewMode(Desktop);
1645
1646     if (needsLayout) {
1647         // This can cause recursive layout...
1648         setNeedsLayout();
1649     }
1650
1651     if (contentsSize().isEmpty()) {
1652 #if DEBUG_WEBPAGE_LOAD
1653         Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
1654 #endif
1655         layoutIfNeeded();
1656         notifyTransformedContentsSizeChanged();
1657         return;
1658     }
1659
1660     bool performedZoom = false;
1661     bool shouldZoom = !m_userPerformedManualZoom;
1662
1663     // If this is a back/forward type navigation, don't zoom to initial scale
1664     // but instead let the HistoryItem's saved viewport reign supreme.
1665     if (m_mainFrame && m_mainFrame->loader() && isBackForwardLoadType(m_mainFrame->loader()->loadType()))
1666         shouldZoom = false;
1667
1668     if (shouldZoom && shouldZoomToInitialScaleOnLoad()) {
1669         // Preserve at top and at left position, to avoid scrolling
1670         // to a non top-left position for web page with viewport meta tag
1671         // that specifies an initial-scale that is zoomed in.
1672         FloatPoint anchor = centerOfVisibleContentsRect();
1673         if (!scrollPosition().x())
1674             anchor.setX(0);
1675         if (!scrollPosition().y())
1676             anchor.setY(0);
1677         performedZoom = zoomAboutPoint(initialScale(), anchor);
1678     }
1679
1680     // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout...
1681     layoutIfNeeded();
1682
1683     if (!performedZoom) {
1684         // We only notify if we didn't perform zoom, because zoom will notify on
1685         // its own...
1686         notifyTransformedContentsSizeChanged();
1687     }
1688 }
1689
1690 double WebPagePrivate::zoomToFitScale() const
1691 {
1692     int contentWidth = contentsSize().width();
1693
1694     // For image document, zoom to fit the screen based on the actual image width
1695     // instead of the contents width within a maximum scale .
1696     Document* doc = m_page->mainFrame()->document();
1697     bool isImageDocument = doc && doc->isImageDocument();
1698     if (isImageDocument)
1699         contentWidth = static_cast<ImageDocument*>(doc)->imageSize().width();
1700
1701     double zoomToFitScale = contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
1702     int contentHeight = contentsSize().height();
1703     if (contentHeight * zoomToFitScale < static_cast<double>(m_defaultLayoutSize.height()))
1704         zoomToFitScale = contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
1705     zoomToFitScale = std::max(zoomToFitScale, minimumZoomToFitScale);
1706
1707     if (!isImageDocument)
1708         return zoomToFitScale;
1709
1710     return std::min(zoomToFitScale, maximumImageDocumentZoomToFitScale);
1711 }
1712
1713 bool WebPagePrivate::respectViewport() const
1714 {
1715     return m_forceRespectViewportArguments || contentsSize().width() <= m_virtualViewportSize.width() + 1;
1716 }
1717
1718 double WebPagePrivate::initialScale() const
1719 {
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, 4.0) : 4.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     Node* linkNode = node->enclosingLinkEventParentOrSelf();
2153     // 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.
2154     if ((node == linkNode) || (node->isTextNode() && linkNode)) {
2155         KURL href;
2156         if (linkNode->isLink() && linkNode->hasAttributes()) {
2157             if (const Attribute* attribute = toElement(linkNode)->getAttributeItem(HTMLNames::hrefAttr))
2158                 href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
2159         }
2160
2161         String pattern = findPatternStringForUrl(href);
2162         if (!pattern.isEmpty())
2163             context.setPattern(pattern);
2164
2165         if (!href.string().isEmpty()) {
2166             context.setUrl(href.string());
2167
2168             // Links are non-selectable by default, but selection should be allowed
2169             // providing the page is selectable, use the parent to determine it.
2170             if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
2171                 nodeAllowSelectionOverride = true;
2172         }
2173     }
2174
2175     if (node->isHTMLElement()) {
2176         HTMLImageElement* imageElement = 0;
2177         HTMLMediaElement* mediaElement = 0;
2178
2179         if (node->hasTagName(HTMLNames::imgTag))
2180             imageElement = static_cast<HTMLImageElement*>(node.get());
2181         else if (node->hasTagName(HTMLNames::areaTag))
2182             imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement();
2183
2184         if (static_cast<HTMLElement*>(node.get())->isMediaElement())
2185             mediaElement = static_cast<HTMLMediaElement*>(node.get());
2186
2187         if (imageElement && imageElement->renderer()) {
2188             context.setFlag(Platform::WebContext::IsImage);
2189             // FIXME: At the mean time, we only show "Save Image" when the image data is available.
2190             if (CachedImage* cachedImage = imageElement->cachedImage()) {
2191                 if (cachedImage->isLoaded() && cachedImage->resourceBuffer()) {
2192                     String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
2193                     context.setSrc(node->document()->completeURL(url).string());
2194
2195                     String mimeType = cachedImage->response().mimeType();
2196                     if (mimeType.isEmpty()) {
2197                         StringBuilder builder;
2198                         String extension = cachedImage->image()->filenameExtension();
2199                         builder.append("image/");
2200                         if (extension.isEmpty())
2201                             builder.append("unknown");
2202                         else if (extension == "jpg")
2203                             builder.append("jpeg");
2204                         else
2205                             builder.append(extension);
2206                         mimeType = builder.toString();
2207                     }
2208                     context.setMimeType(mimeType);
2209                 }
2210             }
2211             String alt = imageElement->altText();
2212             if (!alt.isNull())
2213                 context.setAlt(alt);
2214         }
2215
2216         if (mediaElement) {
2217             if (mediaElement->hasAudio())
2218                 context.setFlag(Platform::WebContext::IsAudio);
2219             if (mediaElement->hasVideo())
2220                 context.setFlag(Platform::WebContext::IsVideo);
2221
2222             String src = stripLeadingAndTrailingHTMLSpaces(mediaElement->getAttribute(HTMLNames::srcAttr).string());
2223             context.setSrc(node->document()->completeURL(src).string());
2224         }
2225     }
2226
2227     if (node->isTextNode()) {
2228         Text* curText = toText(node.get());
2229         if (!curText->wholeText().isEmpty())
2230             context.setText(curText->wholeText());
2231     }
2232
2233     bool canStartSelection = node->canStartSelection();
2234
2235     if (node->isElementNode()) {
2236         Element* element = toElement(node->deprecatedShadowAncestorNode());
2237
2238         if (DOMSupport::isTextBasedContentEditableElement(element)) {
2239             if (!canStartSelection) {
2240                 // Input fields host node is by spec non-editable unless the field itself has content editable enabled.
2241                 // Enable selection if the shadow tree for the input field is selectable.
2242                 Node* nodeUnderFinger = m_touchEventHandler->lastFatFingersResult().isValid() ? m_touchEventHandler->lastFatFingersResult().node(FatFingersResult::ShadowContentAllowed) : 0;
2243                 if (nodeUnderFinger)
2244                     canStartSelection = nodeUnderFinger->canStartSelection();
2245             }
2246             context.setFlag(Platform::WebContext::IsInput);
2247             if (element->hasTagName(HTMLNames::inputTag))
2248                 context.setFlag(Platform::WebContext::IsSingleLine);
2249             if (DOMSupport::isPasswordElement(element))
2250                 context.setFlag(Platform::WebContext::IsPassword);
2251
2252             String elementText(DOMSupport::inputElementText(element));
2253             if (!elementText.stripWhiteSpace().isEmpty())
2254                 context.setText(elementText);
2255             else if (!node->focused() && m_touchEventHandler->lastFatFingersResult().isValid() && strategy == RectBased) {
2256                 // 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.
2257                 m_touchEventHandler->sendClickAtFatFingersPoint();
2258             }
2259         }
2260     }
2261
2262     if (!nodeAllowSelectionOverride && !canStartSelection)
2263         context.resetFlag(Platform::WebContext::IsSelectable);
2264
2265     if (node->isFocusable())
2266         context.setFlag(Platform::WebContext::IsFocusable);
2267
2268     // Walk up the node tree looking for our custom webworks context attribute.
2269     while (node) {
2270         if (node->isElementNode()) {
2271             Element* element = toElement(node->deprecatedShadowAncestorNode());
2272             String webWorksContext(DOMSupport::webWorksContext(element));
2273             if (!webWorksContext.stripWhiteSpace().isEmpty()) {
2274                 context.setFlag(Platform::WebContext::IsWebWorksContext);
2275                 context.setWebWorksContext(webWorksContext);
2276                 break;
2277             }
2278         }
2279         node = node->parentNode();
2280     }
2281
2282     return context;
2283 }
2284
2285 Platform::WebContext WebPage::webContext(TargetDetectionStrategy strategy) const
2286 {
2287     return d->webContext(strategy);
2288 }
2289
2290 void WebPagePrivate::updateCursor()
2291 {
2292     int buttonMask = 0;
2293     if (m_lastMouseEvent.button() == LeftButton)
2294         buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
2295     else if (m_lastMouseEvent.button() == MiddleButton)
2296         buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
2297     else if (m_lastMouseEvent.button() == RightButton)
2298         buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
2299
2300     unsigned modifiers = m_lastMouseEvent.shiftKey() ? 0 : KEYMOD_SHIFT |
2301         m_lastMouseEvent.ctrlKey() ? 0 : KEYMOD_CTRL |
2302         m_lastMouseEvent.altKey() ? 0 : KEYMOD_ALT;
2303
2304     const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor;
2305
2306     BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask,
2307         viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatPoint(m_lastMouseEvent.position())),
2308         viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatPoint(m_lastMouseEvent.globalPosition())),
2309         0, modifiers, 0);
2310
2311     // 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.
2312     event.populateDocumentPosition(m_lastMouseEvent.position(), viewportAccessor->documentContentsFromViewport(m_lastMouseEvent.position()));
2313
2314     m_webPage->mouseEvent(event);
2315 }
2316
2317 IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
2318 {
2319     if (hasVirtualViewport())
2320         return m_virtualViewportSize;
2321
2322     const int defaultLayoutWidth = m_defaultLayoutSize.width();
2323     const int defaultLayoutHeight = m_defaultLayoutSize.height();
2324
2325     int minWidth = defaultLayoutWidth;
2326     int maxWidth = DEFAULT_MAX_LAYOUT_WIDTH;
2327     int maxHeight = DEFAULT_MAX_LAYOUT_HEIGHT;
2328
2329     // If the load state is none then we haven't actually got anything yet, but we need to layout
2330     // the entire page so that the user sees the entire page (unrendered) instead of just part of it.
2331     // If the load state is Provisional, it is possible that absoluteVisibleOverflowSize() and
2332     // contentsSize() are based on the old page and cause inconsistent fixedLayoutSize, so layout the
2333     // new page based on the defaultLayoutSize as well.
2334     if (m_loadState == None || m_loadState == Provisional)
2335         return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2336
2337     if (m_viewMode == FixedDesktop) {
2338         int width  = maxWidth;
2339         // if the defaultLayoutHeight is at minimum, it probably was set as 0
2340         // and clamped, meaning it's effectively not set.  (Even if it happened
2341         // to be set exactly to the minimum, it's too small to be useful.)  So
2342         // ignore it.
2343         int height;
2344         if (defaultLayoutHeight <= minimumLayoutSize.height())
2345             height = maxHeight;
2346         else
2347             height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2348         return IntSize(width, height);
2349     }
2350
2351     if (m_viewMode == Desktop) {
2352         // If we detect an overflow larger than the contents size then use that instead since
2353         // it'll still be clamped by the maxWidth below...
2354         int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
2355         if (m_pendingOrientation != -1 && !m_nestedLayoutFinishedCount && !m_overflowExceedsContentsSize)
2356             width = 0;
2357
2358         if (snapToIncrement) {
2359             // Snap to increments of defaultLayoutWidth / 2.0.
2360             float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
2361             factor = ceilf(factor);
2362             width = (defaultLayoutWidth / 2.0) * factor;
2363         }
2364
2365         if (width < minWidth)
2366             width = minWidth;
2367         if (width > maxWidth)
2368             width = maxWidth;
2369         int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2370         return IntSize(width, height);
2371     }
2372
2373     ASSERT_NOT_REACHED();
2374     return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2375 }
2376
2377 BackingStoreClient* WebPagePrivate::backingStoreClient() const
2378 {
2379     return m_backingStoreClient;
2380 }
2381
2382 void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
2383 {
2384     ASSERT(documentGoingAway);
2385     if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
2386         m_currentContextNode = 0;
2387
2388     if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
2389         m_currentPinchZoomNode = 0;
2390
2391     if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
2392         m_currentBlockZoomAdjustedNode = 0;
2393
2394     if (m_inRegionScroller->d->isActive())
2395         m_inRegionScroller->d->clearDocumentData(documentGoingAway);
2396
2397     if (documentGoingAway->frame())
2398         m_inputHandler->frameUnloaded(documentGoingAway->frame());
2399
2400     Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
2401     if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
2402         m_touchEventHandler->resetLastFatFingersResult();
2403
2404     // NOTE: m_fullscreenNode, m_fullScreenPluginView and m_pluginViews
2405     // are cleared in other methods already.
2406 }
2407
2408 typedef bool (*PredicateFunction)(RenderLayer*);
2409 static bool isPositionedContainer(RenderLayer* layer)
2410 {
2411     RenderObject* o = layer->renderer();
2412     return o->isRenderView() || o->isOutOfFlowPositioned() || o->isRelPositioned() || layer->hasTransform();
2413 }
2414
2415 static bool isFixedPositionedContainer(RenderLayer* layer)
2416 {
2417     RenderObject* o = layer->renderer();
2418     return o->isRenderView() || (o->isOutOfFlowPositioned() && o->style()->position() == FixedPosition);
2419 }
2420
2421 static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
2422 {
2423     RenderLayer* curr = layer;
2424     while (curr && !predicate(curr))
2425         curr = curr->parent();
2426
2427     return curr;
2428 }
2429
2430 RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
2431 {
2432     return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
2433 }
2434
2435 RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
2436 {
2437     return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
2438 }
2439
2440 static inline Frame* frameForNode(Node* node)
2441 {
2442     Node* origNode = node;
2443     for (; node; node = node->parentNode()) {
2444         if (RenderObject* renderer = node->renderer()) {
2445             if (renderer->isRenderView()) {
2446                 if (FrameView* view = toRenderView(renderer)->frameView()) {
2447                     if (Frame* frame = view->frame())
2448                         return frame;
2449                 }
2450             }
2451             if (renderer->isWidget()) {
2452                 Widget* widget = toRenderWidget(renderer)->widget();
2453                 if (widget && widget->isFrameView()) {
2454                     if (Frame* frame = toFrameView(widget)->frame())
2455                         return frame;
2456                 }
2457             }
2458         }
2459     }
2460
2461     for (node = origNode; node; node = node->parentNode()) {
2462         if (Document* doc = node->document()) {
2463             if (Frame* frame = doc->frame())
2464                 return frame;
2465         }
2466     }
2467
2468     return 0;
2469 }
2470
2471 static IntRect getNodeWindowRect(Node* node)
2472 {
2473     if (Frame* frame = frameForNode(node)) {
2474         if (FrameView* view = frame->view())
2475             return view->contentsToWindow(node->getRect());
2476     }
2477     ASSERT_NOT_REACHED();
2478     return IntRect();
2479 }
2480
2481 IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
2482 {
2483     ASSERT(m_mainFrame);
2484
2485     // Don't call this function asking to not clip the main frame providing only
2486     // the main frame. All that can be returned is the content rect which
2487     // isn't what this function is for.
2488     if (noClipOfMainFrame && view == m_mainFrame->view()) {
2489         ASSERT_NOT_REACHED();
2490         return IntRect(IntPoint::zero(), view->contentsSize());
2491     }
2492
2493     IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect()));
2494     if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
2495         // Intersect with parent visible rect.
2496         visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
2497     }
2498     return visibleWindowRect;
2499 }
2500
2501 void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
2502 {
2503     ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
2504     ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
2505     ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
2506
2507     // First we clear the focus, since we want to focus either initial or the last
2508     // focusable element in the webpage (according to the TABINDEX), or simply clear
2509     // the focus.
2510     clearFocusNode();
2511
2512     switch (direction) {
2513     case FocusDirectionForward:
2514     case FocusDirectionBackward:
2515         m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
2516         break;
2517     case FocusDirectionNone:
2518         break;
2519     default:
2520         ASSERT_NOT_REACHED();
2521     }
2522 }
2523
2524 void WebPage::assignFocus(Platform::FocusDirection direction)
2525 {
2526     if (d->m_page->defersLoading())
2527         return;
2528     d->assignFocus(direction);
2529 }
2530
2531 void WebPage::focusNextField()
2532 {
2533     d->m_inputHandler->focusNextField();
2534 }
2535
2536 void WebPage::focusPreviousField()
2537 {
2538     d->m_inputHandler->focusPreviousField();
2539 }
2540
2541 void WebPage::submitForm()
2542 {
2543     d->m_inputHandler->submitForm();
2544 }
2545
2546 Platform::IntRect WebPagePrivate::focusNodeRect()
2547 {
2548     Frame* frame = focusedOrMainFrame();
2549     if (!frame)
2550         return Platform::IntRect();
2551
2552     Document* doc = frame->document();
2553     FrameView* view = frame->view();
2554     if (!doc || !view || view->needsLayout())
2555         return Platform::IntRect();
2556
2557     const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor;
2558
2559     IntRect focusRect = rectForNode(doc->focusedNode());
2560     focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
2561     focusRect = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatRect(focusRect));
2562     focusRect.intersect(viewportAccessor->pixelContentsRect());
2563     return focusRect;
2564 }
2565
2566 PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
2567 {
2568     EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2569     const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
2570     bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
2571
2572     // Check if we're using LinkToLink and the user is not touching the screen.
2573     if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
2574         RefPtr<Node> node;
2575         node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
2576         if (node) {
2577             IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
2578             if (!visibleRect.intersects(getNodeWindowRect(node.get())))
2579                 return 0;
2580         }
2581         return node.release();
2582     }
2583
2584     // Check for text input.
2585     if (isTouching && lastFatFingersResult.isTextInput())
2586         return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
2587
2588     if (strategy == RectBased) {
2589         FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
2590         return result.node(FatFingersResult::ShadowContentNotAllowed);
2591     }
2592     if (strategy == FocusBased)
2593         return m_inputHandler->currentFocusElement();
2594
2595     IntPoint contentPos;
2596     if (isTouching)
2597         contentPos = lastFatFingersResult.adjustedPosition();
2598     else
2599         contentPos = m_webkitThreadViewportAccessor->documentContentsFromViewport(m_lastMouseEvent.position());
2600
2601     HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos);
2602     return result.innerNode();
2603 }
2604
2605 static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
2606 {
2607     // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709).
2608     double dx = static_cast<double>(p1.x() - p2.x());
2609     double dy = static_cast<double>(p1.y() - p2.y());
2610     return sqrt((dx * dx) + (dy * dy));
2611 }
2612
2613 Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& documentPoint)
2614 {
2615     IntRect clickRect(documentPoint.x() - blockClickRadius, documentPoint.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
2616     Node* originalNode = nodeForZoomUnderPoint(documentPoint);
2617     if (!originalNode)
2618         return 0;
2619     Node* node = bestChildNodeForClickRect(originalNode, clickRect);
2620     return node ? adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(node) : adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(originalNode);
2621 }
2622
2623 Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
2624 {
2625     if (!parentNode)
2626         return 0;
2627
2628     int bestDistance = std::numeric_limits<int>::max();
2629
2630     Node* node = parentNode->firstChild();
2631     Node* bestNode = 0;
2632     for (; node; node = node->nextSibling()) {
2633         IntRect rect = rectForNode(node);
2634         if (!clickRect.intersects(rect))
2635             continue;
2636
2637         int distance = distanceBetweenPoints(rect.center(), clickRect.center());
2638         Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
2639         if (bestChildNode) {
2640             IntRect bestChildRect = rectForNode(bestChildNode);
2641             int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
2642             if (bestChildDistance < distance && bestChildDistance < bestDistance) {
2643                 bestNode = bestChildNode;
2644                 bestDistance = bestChildDistance;
2645             } else {
2646                 if (distance < bestDistance) {
2647                     bestNode = node;
2648                     bestDistance = distance;
2649                 }
2650             }
2651         } else {
2652             if (distance < bestDistance) {
2653                 bestNode = node;
2654                 bestDistance = distance;
2655             }
2656         }
2657     }
2658
2659     return bestNode;
2660 }
2661
2662 double WebPagePrivate::maxBlockZoomScale() const
2663 {
2664     return std::min(maximumBlockZoomScale, maximumScale());
2665 }
2666
2667 Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& documentPoint)
2668 {
2669     if (!m_mainFrame)
2670         return 0;
2671
2672     HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(documentPoint);
2673
2674     Node* node = result.innerNonSharedNode();
2675
2676     if (!node)
2677         return 0;
2678
2679     RenderObject* renderer = node->renderer();
2680     while (!renderer) {
2681         node = node->parentNode();
2682         renderer = node->renderer();
2683     }
2684
2685     return node;
2686 }
2687
2688 Node* WebPagePrivate::adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(Node* node)
2689 {
2690     Node* initialNode = node;
2691     RenderObject* renderer = node->renderer();
2692     bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2693     IntSize actualVisibleSize = this->actualVisibleSize();
2694
2695     while (!renderer || !acceptableNodeSize) {
2696         node = node->parentNode();
2697         IntRect nodeRect = rectForNode(node);
2698
2699         // Don't choose a node if the width of the node size is very close to the width of the actual visible size,
2700         // as block zoom can do nothing on such kind of node.
2701         if (!node || static_cast<double>(actualVisibleSize.width() - nodeRect.width()) / actualVisibleSize.width() < minimumExpandingRatio)
2702             return initialNode;
2703
2704         renderer = node->renderer();
2705         acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2706     }
2707
2708     return node;
2709 }
2710
2711 bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
2712 {
2713     if (!n1 || !n2)
2714         return false;
2715
2716     return (n2 == n1) || n2->isDescendantOf(n1);
2717 }
2718
2719 double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
2720 {
2721     if (rect.isEmpty())
2722         return std::numeric_limits<double>::max();
2723
2724     ASSERT(rect.width() + margin);
2725
2726     double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
2727
2728     return newScale;
2729 }
2730
2731 IntRect WebPagePrivate::rectForNode(Node* node)
2732 {
2733     if (!node)
2734         return IntRect();
2735
2736     RenderObject* renderer = node->renderer();
2737
2738     if (!renderer)
2739         return IntRect();
2740
2741     // Return rect in un-transformed content coordinates.
2742     IntRect blockRect;
2743
2744     // FIXME: Ensure this works with iframes.
2745     if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
2746         RenderBlock* renderBlock = renderer->containingBlock();
2747         int xOffset = 0;
2748         int yOffset = 0;
2749         while (!renderBlock->isRoot()) {
2750             xOffset += renderBlock->x().toInt();
2751             yOffset += renderBlock->y().toInt();
2752             renderBlock = renderBlock->containingBlock();
2753         }
2754         const RenderText* renderText = toRenderText(renderer);
2755         IntRect linesBox = renderText->linesBoundingBox();
2756         blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height());
2757     } else
2758         blockRect = IntRect(renderer->absoluteClippedOverflowRect());
2759
2760     if (renderer->isText()) {
2761         RenderBlock* rb = renderer->containingBlock();
2762
2763         // Inefficient? Way to find width when floats intersect a block.
2764         int blockWidth = 0;
2765         int lineCount = rb->lineCount();
2766         for (int i = 0; i < lineCount; i++)
2767             blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false).toInt());
2768
2769         blockRect.setWidth(blockWidth);
2770         blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
2771     }
2772
2773     // Strip off padding.
2774     if (renderer->style()->hasPadding()) {
2775         blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
2776         blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
2777         blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
2778         blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
2779     }
2780
2781     return blockRect;
2782 }
2783
2784 IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
2785 {
2786     ASSERT(frame);
2787
2788     // FIXME: This function can be called when page is being destroyed and JS triggers selection change.
2789     // We could break the call chain at upper levels, but I think it is better to check the frame pointer
2790     // here because the pointer is explicitly cleared in WebPage::destroy().
2791     if (!mainFrame())
2792         return IntPoint();
2793
2794     // Convert 0,0 in the frame's coordinate system to window coordinates to
2795     // get the frame's global position, and return this position in the main
2796     // frame's coordinates.  (So the main frame's coordinates will be 0,0.)
2797     return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
2798 }
2799
2800 IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
2801 {
2802     if (!node)
2803         return rect;
2804
2805     // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames.
2806     // FIXME: can we just use frameOffset instead of this big routine?
2807     const Node* tnode = node;
2808     IntRect adjustedRect = rect;
2809     do {
2810         Frame* frame = tnode->document()->frame();
2811         if (!frame)
2812             continue;
2813
2814         Node* ownerNode = static_cast<Node*>(frame->ownerElement());
2815         tnode = ownerNode;
2816         if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
2817             IntRect iFrameRect;
2818             do {
2819                 iFrameRect = rectForNode(ownerNode);
2820                 adjustedRect.move(iFrameRect.x(), iFrameRect.y());
2821                 adjustedRect.intersect(iFrameRect);
2822                 ownerNode = ownerNode->parentNode();
2823             } while (iFrameRect.isEmpty() && ownerNode);
2824         } else
2825             break;
2826     } while ((tnode = tnode->parentNode()));
2827
2828     return adjustedRect;
2829 }
2830
2831 IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
2832 {
2833     if (!node || contentsSize().isEmpty())
2834         return IntRect();
2835
2836     Node* tnode = node;
2837     m_currentBlockZoomAdjustedNode = tnode;
2838
2839     IntRect blockRect = rectForNode(tnode);
2840     IntRect originalRect = blockRect;
2841
2842     int originalArea = originalRect.width() * originalRect.height();
2843     int pageArea = contentsSize().width() * contentsSize().height();
2844     double blockToPageRatio = static_cast<double>(pageArea - originalArea) / pageArea;
2845     double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
2846
2847     if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
2848         while ((tnode = tnode->parentNode())) {
2849             ASSERT(tnode);
2850             IntRect tRect = rectForNode(tnode);
2851             int tempBlockArea = tRect.width() * tRect.height();
2852             // Don't expand the block if it will be too large relative to the content.
2853             if (static_cast<double>(pageArea - tempBlockArea) / pageArea < minimumExpandingRatio)
2854                 break;
2855             if (tRect.isEmpty())
2856                 continue; // No renderer.
2857             if (tempBlockArea < 1.1 * originalArea)
2858                 continue; // The size of this parent is very close to the child, no need to go to this parent.
2859             // Don't expand the block if the parent node size is already almost the size of actual visible size.
2860             IntSize actualSize = actualVisibleSize();
2861             if (static_cast<double>(actualSize.width() - tRect.width()) / actualSize.width() < minimumExpandingRatio)
2862                 break;
2863             if (tempBlockArea < blockExpansionRatio * originalArea) {
2864                 blockRect = tRect;
2865                 m_currentBlockZoomAdjustedNode = tnode;
2866             } else
2867                 break;
2868         }
2869     }
2870
2871     const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor;
2872
2873     blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
2874     blockRect = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatRect(blockRect));
2875     blockRect.intersect(viewportAccessor->pixelContentsRect());
2876
2877     return blockRect;
2878 }
2879
2880 // This function should not be called directly.
2881 // It is called after the animation ends (see above).
2882 void WebPagePrivate::zoomAnimationFinished(double finalAnimationScale, const WebCore::FloatPoint& finalAnimationDocumentScrollPosition, bool shouldConstrainScrollingToContentEdge)
2883 {
2884     if (!m_mainFrame)
2885         return;
2886
2887     const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor;
2888
2889     IntPoint anchor(viewportAccessor->roundedDocumentContents(finalAnimationDocumentScrollPosition));
2890     bool willUseTextReflow = false;
2891
2892 #if ENABLE(VIEWPORT_REFLOW)
2893     willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
2894     toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
2895     setNeedsLayout();
2896 #endif
2897
2898     TransformationMatrix zoom;
2899     zoom.scale(finalAnimationScale);
2900     *m_transformationMatrix = zoom;
2901     // FIXME: Do we really need to suspend/resume both backingstore and screen here?
2902     m_backingStore->d->suspendBackingStoreUpdates();
2903     m_backingStore->d->suspendScreenUpdates();
2904     updateViewportSize();
2905
2906     FrameView* mainFrameView = m_mainFrame->view();
2907     bool constrainsScrollingToContentEdge = true;
2908     if (mainFrameView) {
2909         constrainsScrollingToContentEdge = mainFrameView->constrainsScrollingToContentEdge();
2910         mainFrameView->setConstrainsScrollingToContentEdge(shouldConstrainScrollingToContentEdge);
2911     }
2912
2913 #if ENABLE(VIEWPORT_REFLOW)
2914     layoutIfNeeded();
2915     if (willUseTextReflow && m_shouldReflowBlock) {
2916         Platform::IntPoint roundedReflowOffset(
2917             std::floorf(m_finalAnimationDocumentScrollPositionReflowOffset.x()),
2918             std::floorf(m_finalAnimationDocumentScrollPositionReflowOffset.y()));
2919
2920         IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
2921         reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
2922         reflowedRect.move(roundedReflowOffset.x(), roundedReflowOffset.y());
2923
2924         RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
2925         IntPoint topLeftPoint(reflowedRect.location());
2926         if (renderer && renderer->isText()) {
2927             ETextAlign textAlign = renderer->style()->textAlign();
2928             IntPoint textAnchor;
2929             switch (textAlign) {
2930             case CENTER:
2931             case WEBKIT_CENTER:
2932                 textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
2933                 break;
2934             case LEFT:
2935             case WEBKIT_LEFT:
2936                 textAnchor = topLeftPoint;
2937                 break;
2938             case RIGHT:
2939             case WEBKIT_RIGHT:
2940                 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
2941                 break;
2942             case TASTART:
2943             case JUSTIFY:
2944             default:
2945                 if (renderer->style()->isLeftToRightDirection())
2946                     textAnchor = topLeftPoint;
2947                 else
2948                     textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
2949                 break;
2950             }
2951             setScrollPosition(textAnchor);
2952         } else {
2953             renderer->style()->isLeftToRightDirection()
2954                 ? setScrollPosition(topLeftPoint)
2955                 : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
2956         }
2957     } else if (willUseTextReflow) {
2958         IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
2959         finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
2960         setScrollPosition(IntPoint(0, finalRect.y() + m_finalAnimationDocumentScrollPositionReflowOffset.y()));
2961         resetBlockZoom();
2962     }
2963 #endif
2964     if (!willUseTextReflow) {
2965         setScrollPosition(anchor);
2966         if (!m_shouldReflowBlock)
2967             resetBlockZoom();
2968     }
2969
2970     notifyTransformChanged();
2971     m_client->scaleChanged();
2972
2973     if (mainFrameView)
2974         mainFrameView->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge);
2975
2976     // FIXME: Do we really need to suspend/resume both backingstore and screen here?
2977     m_backingStore->d->resumeBackingStoreUpdates();
2978     m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit);
2979 }
2980
2981 void WebPage::zoomAnimationFinished(double finalScale, const Platform::FloatPoint& finalDocumentScrollPosition, bool shouldConstrainScrollingToContentEdge)
2982 {
2983     d->zoomAnimationFinished(finalScale, finalDocumentScrollPosition, shouldConstrainScrollingToContentEdge);
2984 }
2985
2986 void WebPage::resetBlockZoom()
2987 {
2988     d->resetBlockZoom();
2989 }
2990
2991 void WebPagePrivate::resetBlockZoom()
2992 {
2993     m_currentBlockZoomNode = 0;
2994     m_currentBlockZoomAdjustedNode = 0;
2995     m_shouldReflowBlock = false;
2996 }
2997
2998 void WebPage::destroyWebPageCompositor()
2999 {
3000 #if USE(ACCELERATED_COMPOSITING)
3001     // Destroy the layer renderer in a sync command before we destroy the backing store,
3002     // to flush any pending compositing messages on the compositing thread.
3003     // The backing store is indirectly deleted by the 'detachFromParent' call below.
3004     d->syncDestroyCompositorOnCompositingThread();
3005 #endif
3006 }
3007
3008 void WebPage::destroy()
3009 {
3010     // TODO: need to verify if this call needs to be made before calling
3011     // Close the Inspector to resume the JS engine if it's paused.
3012     disableWebInspector();
3013
3014     // WebPage::destroyWebPageCompositor()
3015     // FIXME: Do we really need to suspend/resume both backingstore and screen here?
3016     d->m_backingStore->d->suspendBackingStoreUpdates();
3017     d->m_backingStore->d->suspendScreenUpdates();
3018
3019     // Close the backforward list and release the cached pages.
3020     d->m_page->backForward()->close();
3021
3022     FrameLoader* loader = d->m_mainFrame->loader();
3023
3024     // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion.
3025     d->m_mainFrame = 0;
3026     if (loader)
3027         loader->detachFromParent();
3028
3029     deleteGuardedObject(this);
3030 }
3031
3032 WebPageClient* WebPage::client() const
3033 {
3034     return d->m_client;
3035 }
3036
3037 int WebPage::backForwardListLength() const
3038 {
3039     return d->m_page->getHistoryLength();
3040 }
3041
3042 bool WebPage::canGoBackOrForward(int delta) const
3043 {
3044     return d->m_page->canGoBackOrForward(delta);
3045 }
3046
3047 bool WebPage::goBackOrForward(int delta)
3048 {
3049     if (d->m_page->canGoBackOrForward(delta)) {
3050         d->m_userPerformedManualZoom = false;
3051         d->m_userPerformedManualScroll = false;
3052         d->m_backingStore->d->suspendScreenUpdates();
3053         d->m_page->goBackOrForward(delta);
3054         d->m_backingStore->d->resumeScreenUpdates(BackingStore::None);
3055         return true;
3056     }
3057     return false;
3058 }
3059
3060 void WebPage::goToBackForwardEntry(BackForwardId id)
3061 {
3062     HistoryItem* item = historyItemFromBackForwardId(id);
3063     ASSERT(item);
3064     d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
3065 }
3066
3067 void WebPage::reload()
3068 {
3069     d->m_mainFrame->loader()->reload(/* bypassCache */ true);
3070 }
3071
3072 void WebPage::reloadFromCache()
3073 {
3074     d->m_mainFrame->loader()->reload(/* bypassCache */ false);
3075 }
3076
3077 WebSettings* WebPage::settings() const
3078 {
3079     return d->m_webSettings;
3080 }
3081
3082 WebCookieJar* WebPage::cookieJar() const
3083 {
3084     if (!d->m_cookieJar)
3085         d->m_cookieJar = new WebCookieJar();
3086
3087     return d->m_cookieJar;
3088 }
3089
3090 bool WebPage::isLoading() const
3091 {
3092     return d->isLoading();
3093 }
3094
3095 bool WebPage::isVisible() const
3096 {
3097     return d->m_visible;
3098 }
3099
3100 #if ENABLE(PAGE_VISIBILITY_API)
3101 class DeferredTaskSetPageVisibilityState: public DeferredTask<&WebPagePrivate::m_wouldSetPageVisibilityState> {
3102 public:
3103     explicit DeferredTaskSetPageVisibilityState(WebPagePrivate* webPagePrivate)
3104         : DeferredTaskType(webPagePrivate)
3105     {
3106     }
3107 private:
3108     virtual void performInternal(WebPagePrivate* webPagePrivate)
3109     {
3110         webPagePrivate->setPageVisibilityState();
3111     }
3112 };
3113
3114 void WebPagePrivate::setPageVisibilityState()
3115 {
3116     if (m_page->defersLoading())
3117         m_deferredTasks.append(adoptPtr(new DeferredTaskSetPageVisibilityState(this)));
3118     else {
3119         DeferredTaskSetPageVisibilityState::finishOrCancel(this);
3120
3121         static bool s_initialVisibilityState = true;
3122
3123         m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
3124         s_initialVisibilityState = false;
3125     }
3126 }
3127 #endif
3128
3129 void WebPagePrivate::setVisible(bool visible)
3130 {
3131     if (visible != m_visible) {
3132         if (visible) {
3133             if (m_mainFrame)
3134                 m_mainFrame->animation()->resumeAnimations();
3135             if (m_page->scriptedAnimationsSuspended())
3136                 m_page->resumeScriptedAnimations();
3137         } else {
3138             if (m_mainFrame)
3139                 m_mainFrame->animation()->suspendAnimations();
3140             if (!m_page->scriptedAnimationsSuspended())
3141                 m_page->suspendScriptedAnimations();
3142
3143             if (m_webPage->hasOpenedPopup())
3144                 m_page->chrome()->client()->closePagePopup(0);
3145         }
3146
3147         m_visible = visible;
3148         m_backingStore->d->updateSuspendScreenUpdateState();
3149     }
3150
3151 #if ENABLE(PAGE_VISIBILITY_API)
3152     setPageVisibilityState();
3153 #endif
3154 }
3155
3156 void WebPage::setVisible(bool visible)
3157 {
3158     if (d->m_visible == visible)
3159         return;
3160
3161     d->setVisible(visible);
3162     AuthenticationChallengeManager::instance()->pageVisibilityChanged(d, visible);
3163
3164     if (!visible) {
3165         d->suspendBackingStore();
3166
3167         // Remove this WebPage from the visible pages list.
3168         size_t foundIndex = visibleWebPages()->find(this);
3169         if (foundIndex != WTF::notFound)
3170             visibleWebPages()->remove(foundIndex);
3171
3172         // Return the backing store to the last visible WebPage.
3173         if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
3174             visibleWebPages()->last()->d->resumeBackingStore();
3175
3176 #if USE(ACCELERATED_COMPOSITING)
3177         // Root layer commit is not necessary for invisible tabs.
3178         // And release layer resources can reduce memory consumption.
3179         d->suspendRootLayerCommit();
3180 #endif
3181
3182         return;
3183     }
3184
3185 #if USE(ACCELERATED_COMPOSITING)
3186     d->resumeRootLayerCommit();
3187 #endif
3188
3189     // We want to become visible but not get backing store ownership.
3190     if (d->m_backingStore->d->isOpenGLCompositing() && !d->m_webSettings->isBackingStoreEnabled()) {
3191         d->setCompositorDrawsRootLayer(true);
3192 #if USE(ACCELERATED_COMPOSITING)
3193         d->setNeedsOneShotDrawingSynchronization();
3194 #endif
3195         d->setShouldResetTilesWhenShown(true);
3196         return;
3197     }
3198
3199     // Push this WebPage to the top of the visible pages list.
3200     if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
3201         size_t foundIndex = visibleWebPages()->find(this);
3202         if (foundIndex != WTF::notFound)
3203             visibleWebPages()->remove(foundIndex);
3204     }
3205     visibleWebPages()->append(this);
3206
3207     if (BackingStorePrivate::currentBackingStoreOwner()
3208         && BackingStorePrivate::currentBackingStoreOwner() != this)
3209         BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
3210
3211     // resumeBackingStore will set the current owner to this webpage.
3212     // If we set the owner prematurely, then the tiles will not be reset.
3213     d->resumeBackingStore();
3214 }
3215
3216 void WebPagePrivate::selectionChanged(Frame* frame)
3217 {
3218     m_inputHandler->selectionChanged();
3219
3220     // FIXME: This is a hack!
3221     // To ensure the selection being changed has its frame 'focused', lets
3222     // set it as focused ourselves (PR #104724).
3223     m_page->focusController()->setFocusedFrame(frame);
3224 }
3225
3226 void WebPagePrivate::updateSelectionScrollView(const Node* node)
3227 {
3228     m_inRegionScroller->d->updateSelectionScrollView(node);
3229 }
3230
3231 void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
3232 {
3233     // Track a dispatched message, we don't want to flood the webkit thread.
3234     // There can be as many as one more message enqued as needed but never less.
3235     if (dispatched)
3236         m_updateDelegatedOverlaysDispatched = false;
3237     else if (m_updateDelegatedOverlaysDispatched) {
3238         // Early return if there is message already pending on the webkit thread.
3239         return;
3240     }
3241
3242     if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
3243         // Must be called on the WebKit thread.
3244         if (m_selectionHandler->isSelectionActive())
3245             m_selectionHandler->selectionPositionChanged();
3246         if (m_inspectorOverlay)
3247             m_inspectorOverlay->update();
3248
3249     } else if (m_selectionHandler->isSelectionActive()) {
3250         // Don't bother dispatching to webkit thread if selection and tap highlight are not active.
3251         m_updateDelegatedOverlaysDispatched = true;
3252         Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/));
3253     }
3254 }
3255
3256 void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle)
3257 {
3258 }
3259
3260 bool WebPage::setBatchEditingActive(bool active)
3261 {
3262     return d->m_inputHandler->setBatchEditingActive(active);
3263 }
3264
3265 bool WebPage::setInputSelection(unsigned start, unsigned end)
3266 {
3267     if (d->m_page->defersLoading())
3268         return false;
3269     return d->m_inputHandler->setSelection(start, end);
3270 }
3271
3272 int WebPage::inputCaretPosition() const
3273 {
3274     return d->m_inputHandler->caretPosition();
3275 }
3276
3277 class DeferredTaskPopupListSelectMultiple: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectMultiple> {
3278 public:
3279     DeferredTaskPopupListSelectMultiple(WebPagePrivate* webPagePrivate, int size, const bool* selecteds)
3280         : DeferredTaskType(webPagePrivate)
3281     {
3282         webPagePrivate->m_cachedPopupListSelecteds.append(selecteds, size);
3283     }
3284 private:
3285     virtual void performInternal(WebPagePrivate* webPagePrivate)
3286     {
3287         webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelecteds.size(), webPagePrivate->m_cachedPopupListSelecteds.data());
3288     }
3289 };
3290
3291 class DeferredTaskPopupListSelectSingle: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectSingle> {
3292 public:
3293     explicit DeferredTaskPopupListSelectSingle(WebPagePrivate* webPagePrivate, int index)
3294         : DeferredTaskType(webPagePrivate)
3295     {
3296         webPagePrivate->m_cachedPopupListSelectedIndex = index;
3297     }
3298 private:
3299     virtual void performInternal(WebPagePrivate* webPagePrivate)
3300     {
3301         webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelectedIndex);
3302     }
3303 };
3304
3305 void WebPage::popupListClosed(int size, const bool* selecteds)
3306 {
3307     DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3308     if (d->m_page->defersLoading()) {
3309         d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectMultiple(d, size, selecteds)));
3310         return;
3311     }
3312     DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3313     d->m_inputHandler->setPopupListIndexes(size, selecteds);
3314 }
3315
3316 void WebPage::popupListClosed(int index)
3317 {
3318     DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3319     if (d->m_page->defersLoading()) {
3320         d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectSingle(d, index)));
3321         return;
3322     }
3323     DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3324     d->m_inputHandler->setPopupListIndex(index);
3325 }
3326
3327 class DeferredTaskSetDateTimeInput: public DeferredTask<&WebPagePrivate::m_wouldSetDateTimeInput> {
3328 public:
3329     explicit DeferredTaskSetDateTimeInput(WebPagePrivate* webPagePrivate, BlackBerry::Platform::String value)
3330         : DeferredTaskType(webPagePrivate)
3331     {
3332         webPagePrivate->m_cachedDateTimeInput = value;
3333     }
3334 private:
3335     virtual void performInternal(WebPagePrivate* webPagePrivate)
3336     {
3337         webPagePrivate->m_webPage->setDateTimeInput(webPagePrivate->m_cachedDateTimeInput);
3338     }
3339 };
3340
3341 void WebPage::setDateTimeInput(const BlackBerry::Platform::String& value)
3342 {
3343     if (d->m_page->defersLoading()) {
3344         d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetDateTimeInput(d, value)));
3345         return;
3346     }
3347     DeferredTaskSetDateTimeInput::finishOrCancel(d);
3348     d->m_inputHandler->setInputValue(value);
3349 }
3350
3351 class DeferredTaskSetColorInput: public DeferredTask<&WebPagePrivate::m_wouldSetColorInput> {
3352 public:
3353     explicit DeferredTaskSetColorInput(WebPagePrivate* webPagePrivate, BlackBerry::Platform::String value)
3354         : DeferredTaskType(webPagePrivate)
3355     {
3356         webPagePrivate->m_cachedColorInput = value;
3357     }
3358 private:
3359     virtual void performInternal(WebPagePrivate* webPagePrivate)
3360     {
3361         webPagePrivate->m_webPage->setColorInput(webPagePrivate->m_cachedColorInput);
3362     }
3363 };
3364
3365 void WebPage::setColorInput(const BlackBerry::Platform::String& value)
3366 {
3367     if (d->m_page->defersLoading()) {
3368         d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetColorInput(d, value)));
3369         return;
3370     }
3371     DeferredTaskSetColorInput::finishOrCancel(d);
3372     d->m_inputHandler->setInputValue(value);
3373 }
3374
3375 void WebPage::setVirtualViewportSize(const Platform::IntSize& size)
3376 {
3377     d->m_virtualViewportSize = WebCore::IntSize(size);
3378 }
3379
3380 void WebPage::resetVirtualViewportOnCommitted(bool reset)
3381 {
3382     d->m_resetVirtualViewportOnCommitted = reset;
3383 }
3384
3385 Platform::IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments()
3386 {
3387     static const ViewportArguments defaultViewportArguments;
3388     if (m_viewportArguments == defaultViewportArguments)
3389         return IntSize();
3390
3391     int desktopWidth = DEFAULT_MAX_LAYOUT_WIDTH;
3392     int deviceWidth = Platform::Graphics::Screen::primaryScreen()->width();
3393     int deviceHeight = Platform::Graphics::Screen::primaryScreen()->height();
3394     float devicePixelRatio = m_webSettings->devicePixelRatio();
3395     ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, devicePixelRatio, m_defaultLayoutSize);
3396     m_page->setDeviceScaleFactor(devicePixelRatio);
3397
3398     setUserScalable(m_webSettings->isUserScalable() && result.userScalable);
3399     if (result.initialScale > 0)
3400         setInitialScale(result.initialScale * devicePixelRatio);
3401     if (result.minimumScale > 0)
3402         setMinimumScale(result.minimumScale * devicePixelRatio);
3403     if (result.maximumScale > 0)
3404         setMaximumScale(result.maximumScale * devicePixelRatio);
3405
3406     return Platform::IntSize(result.layoutSize.width(), result.layoutSize.height());
3407 }
3408
3409 #if ENABLE(EVENT_MODE_METATAGS)
3410 void WebPagePrivate::didReceiveCursorEventMode(CursorEventMode mode)
3411 {
3412     if (mode != m_cursorEventMode)
3413         m_client->cursorEventModeChanged(toPlatformCursorEventMode(mode));
3414     m_cursorEventMode = mode;
3415 }
3416
3417 void WebPagePrivate::didReceiveTouchEventMode(TouchEventMode mode)
3418 {
3419     if (mode != m_touchEventMode)
3420         m_client->touchEventModeChanged(toPlatformTouchEventMode(mode));
3421     m_touchEventMode = mode;
3422 }
3423 #endif
3424
3425 void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments)
3426 {
3427     if (arguments == m_viewportArguments)
3428         return;
3429
3430     // If the caller is trying to reset to default arguments, use the user supplied ones instead.
3431     static const ViewportArguments defaultViewportArguments;
3432     if (arguments == defaultViewportArguments) {
3433         m_viewportArguments = m_userViewportArguments;
3434         m_forceRespectViewportArguments = m_userViewportArguments != defaultViewportArguments;
3435     } else
3436         m_viewportArguments = arguments;
3437
3438     // 0 width or height in viewport arguments makes no sense, and results in a very large initial scale.
3439     // In real world, a 0 width or height is usually caused by a syntax error in "content" field of viewport
3440     // meta tag, for example, using semicolon instead of comma as separator ("width=device-width; initial-scale=1.0").
3441     // We don't have a plan to tolerate the semicolon separator, but we can avoid applying 0 width/height.
3442     // I default it to ValueDeviceWidth rather than ValueAuto because in more cases the web site wants "device-width"
3443     // when they specify the viewport width.
3444     if (!m_viewportArguments.width)
3445         m_viewportArguments.width = ViewportArguments::ValueDeviceWidth;
3446     if (!m_viewportArguments.height)
3447         m_viewportArguments.height = ViewportArguments::ValueDeviceHeight;
3448
3449     Platform::IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
3450     m_webPage->setVirtualViewportSize(virtualViewport);
3451
3452     // Reset m_userPerformedManualZoom and enable m_shouldZoomToInitialScaleAfterLoadFinished so that we can relayout
3453     // the page and zoom it to fit the screen when we dynamically change the meta viewport after the load is finished.
3454     bool isLoadFinished = loadState() == Finished;
3455     if (isLoadFinished) {
3456         m_userPerformedManualZoom = false;
3457         setShouldZoomToInitialScaleAfterLoadFinished(true);
3458     }
3459     if (loadState() == Committed || isLoadFinished)
3460         zoomToInitialScaleOnLoad();
3461 }
3462
3463 void WebPagePrivate::suspendBackingStore()
3464 {
3465 #if USE(ACCELERATED_COMPOSITING)
3466     if (m_backingStore->d->isOpenGLCompositing()) {
3467         // A visible web page's backing store can be suspended when another web
3468         // page is taking over the backing store.
3469         if (m_visible)
3470             setCompositorDrawsRootLayer(true);
3471
3472         return;
3473     }
3474 #endif
3475 }
3476
3477 void WebPagePrivate::resumeBackingStore()
3478 {
3479     ASSERT(m_webPage->isVisible());
3480
3481     if (!m_backingStore->d->isActive() || shouldResetTilesWhenShown()) {
3482         BackingStorePrivate::setCurrentBackingStoreOwner(m_webPage);
3483
3484         // If we're OpenGL compositing, switching to accel comp drawing of the root layer
3485         // is a good substitute for backingstore blitting.
3486         if (m_backingStore->d->isOpenGLCompositing())
3487             setCompositorDrawsRootLayer(!m_backingStore->d->isActive());
3488
3489         m_backingStore->d->orientationChanged(); // Updates tile geometry and creates visible tile buffer.
3490         m_backingStore->d->resetTiles();
3491         m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
3492
3493 #if USE(ACCELERATED_COMPOSITING)
3494         setNeedsOneShotDrawingSynchronization();
3495 #endif
3496
3497         m_backingStore->d->renderAndBlitVisibleContentsImmediately();
3498     } else {
3499         if (m_backingStore->d->isOpenGLCompositing())
3500             setCompositorDrawsRootLayer(false);
3501
3502         // Rendering was disabled while we were hidden, so we need to update all tiles.
3503         m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
3504 #if USE(ACCELERATED_COMPOSITING)
3505         setNeedsOneShotDrawingSynchronization();
3506 #endif
3507     }