a400f150b878e6126c65ae171ea96610c8937676
[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         m_mainFrame->view()->setNeedsLayout();
1250         requestLayoutIfNeeded();
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::requestLayoutIfNeeded() const
1318 {
1319     FrameView* view = m_mainFrame->view();
1320     ASSERT(view);
1321     view->updateLayoutAndStyleIfNeededRecursive();
1322     ASSERT(!view->needsLayout());
1323 }
1324
1325 IntPoint WebPagePrivate::scrollPosition() const
1326 {
1327     if (!m_backingStoreClient)
1328         return IntPoint();
1329
1330     return m_backingStoreClient->scrollPosition();
1331 }
1332
1333 IntPoint WebPagePrivate::maximumScrollPosition() const
1334 {
1335     if (!m_backingStoreClient)
1336         return IntPoint();
1337
1338     return m_backingStoreClient->maximumScrollPosition();
1339 }
1340
1341 void WebPagePrivate::setScrollPosition(const IntPoint& pos)
1342 {
1343     ASSERT(m_backingStoreClient);
1344     m_backingStoreClient->setScrollPosition(pos);
1345 }
1346
1347 // Setting the scroll position is in transformed coordinates.
1348 void WebPage::setDocumentScrollPosition(const Platform::IntPoint& documentScrollPosition)
1349 {
1350     WebCore::IntPoint scrollPosition = documentScrollPosition;
1351     if (scrollPosition == d->scrollPosition())
1352         return;
1353
1354     // If the user recently performed an event, this new scroll position
1355     // could possibly be a result of that. Or not, this is just a heuristic.
1356     if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
1357         d->m_userPerformedManualScroll = true;
1358
1359     d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1360
1361     // UI thread can call BackingStorePrivate::setScrollingOrZooming(false) before WebKit thread calls WebPage::setScrollPosition(),
1362     // in which case it will set ScrollableArea::m_constrainsScrollingToContentEdge to true earlier.
1363     // We can cache ScrollableArea::m_constrainsScrollingToContentEdge and always set it to false before we set scroll position in
1364     // WebKit thread to avoid scroll position clamping during scrolling, and restore it to what it was after that.
1365     bool constrainsScrollingToContentEdge = d->m_mainFrame->view()->constrainsScrollingToContentEdge();
1366     d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(false);
1367     d->setScrollPosition(scrollPosition);
1368     d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge);
1369
1370     d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1371 }
1372
1373 bool WebPagePrivate::shouldSendResizeEvent()
1374 {
1375     if (!m_mainFrame || !m_mainFrame->document())
1376         return false;
1377
1378     // PR#96865 : Provide an option to always send resize events, regardless of the loading
1379     //            status. The scenario for this are Sapphire applications which tend to
1380     //            maintain an open GET request to the server. This open GET results in
1381     //            webkit thinking that content is still arriving when at the application
1382     //            level it is considered fully loaded.
1383     //
1384     //            NOTE: Care must be exercised in the use of this option, as it bypasses
1385     //                  the sanity provided in 'isLoadingInAPISense()' below.
1386     //
1387     static const bool unrestrictedResizeEvents = Platform::Settings::instance()->unrestrictedResizeEvents();
1388     if (unrestrictedResizeEvents)
1389         return true;
1390
1391     // Don't send the resize event if the document is loading. Some pages automatically reload
1392     // when the window is resized; Safari on iPhone often resizes the window while setting up its
1393     // viewport. This obviously can cause problems.
1394     DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
1395     if (documentLoader && documentLoader->isLoadingInAPISense())
1396         return false;
1397
1398     return true;
1399 }
1400
1401 void WebPagePrivate::willDeferLoading()
1402 {
1403     m_deferredTasksTimer.stop();
1404     m_client->willDeferLoading();
1405 }
1406
1407 void WebPagePrivate::didResumeLoading()
1408 {
1409     if (!m_deferredTasks.isEmpty())
1410         m_deferredTasksTimer.startOneShot(0);
1411     m_client->didResumeLoading();
1412 }
1413
1414 void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*)
1415 {
1416     ASSERT(!m_deferredTasks.isEmpty());
1417     if (m_deferredTasks.isEmpty())
1418         return;
1419
1420     OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release();
1421     m_deferredTasks.remove(0);
1422
1423     if (!m_deferredTasks.isEmpty())
1424         m_deferredTasksTimer.startOneShot(0);
1425
1426     task->perform(this);
1427 }
1428
1429 void WebPagePrivate::notifyInRegionScrollStopped()
1430 {
1431     if (m_inRegionScroller->d->isActive())
1432         m_inRegionScroller->d->reset();
1433 }
1434
1435 void WebPage::notifyInRegionScrollStopped()
1436 {
1437     d->notifyInRegionScrollStopped();
1438 }
1439
1440 void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
1441 {
1442     if (b != m_hasInRegionScrollableAreas)
1443         m_hasInRegionScrollableAreas = b;
1444 }
1445
1446 IntSize WebPagePrivate::viewportSize() const
1447 {
1448     return m_webkitThreadViewportAccessor->roundToDocumentFromPixelContents(Platform::IntRect(Platform::IntPoint::zero(), transformedViewportSize())).size();
1449 }
1450
1451 IntSize WebPagePrivate::actualVisibleSize() const
1452 {
1453     return m_webkitThreadViewportAccessor->documentViewportSize();
1454 }
1455
1456 bool WebPagePrivate::hasVirtualViewport() const
1457 {
1458     return !m_virtualViewportSize.isEmpty();
1459 }
1460
1461 void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
1462 {
1463     // This checks to make sure we're not calling updateViewportSize
1464     // during WebPagePrivate::init().
1465     if (!m_backingStore)
1466         return;
1467     ASSERT(m_mainFrame->view());
1468     IntSize visibleSize = actualVisibleSize();
1469     if (setFixedReportedSize)
1470         m_mainFrame->view()->setFixedReportedSize(visibleSize);
1471
1472     IntRect frameRect = IntRect(scrollPosition(), visibleSize);
1473     if (frameRect != m_mainFrame->view()->frameRect()) {
1474         m_mainFrame->view()->setFrameRect(frameRect);
1475         m_mainFrame->view()->adjustViewSize();
1476
1477 #if ENABLE(FULLSCREEN_API)
1478         adjustFullScreenElementDimensionsIfNeeded();
1479 #endif
1480     }
1481
1482     // We're going to need to send a resize event to JavaScript because
1483     // innerWidth and innerHeight depend on fixed reported size.
1484     // This is how we support mobile pages where JavaScript resizes
1485     // the page in order to get around the fixed layout size, e.g.
1486     // google maps when it detects a mobile user agent.
1487     if (sendResizeEvent && shouldSendResizeEvent())
1488         m_mainFrame->eventHandler()->sendResizeEvent();
1489
1490     // When the actual visible size changes, we also
1491     // need to reposition fixed elements.
1492     m_mainFrame->view()->repaintFixedElementsAfterScrolling();
1493 }
1494
1495 FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
1496 {
1497     // The visible contents rect in float.
1498     FloatRect visibleContentsRect = this->visibleContentsRect();
1499
1500     // The center of the visible contents rect in float.
1501     return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
1502         visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
1503 }
1504
1505 IntRect WebPagePrivate::visibleContentsRect() const
1506 {
1507     return m_backingStoreClient->visibleContentsRect();
1508 }
1509
1510 IntSize WebPagePrivate::contentsSize() const
1511 {
1512     if (!m_mainFrame || !m_mainFrame->view())
1513         return IntSize();
1514
1515     return m_backingStoreClient->contentsSize();
1516 }
1517
1518 IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
1519 {
1520     if (!m_mainFrame || !m_mainFrame->contentRenderer())
1521         return IntSize();
1522
1523     return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
1524 }
1525
1526 void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
1527 {
1528     if (m_previousContentsSize == contentsSize)
1529         return;
1530
1531     // This should only occur in the middle of layout so we set a flag here and
1532     // handle it at the end of the layout.
1533     m_contentsSizeChanged = true;
1534
1535 #if DEBUG_WEBPAGE_LOAD
1536     Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %s", Platform::IntSize(contentsSize).toString().c_str());
1537 #endif
1538 }
1539
1540 void WebPagePrivate::overflowExceedsContentsSize()
1541 {
1542     m_overflowExceedsContentsSize = true;
1543     if (absoluteVisibleOverflowSize().width() < DEFAULT_MAX_LAYOUT_WIDTH && !hasVirtualViewport()) {
1544         if (setViewMode(viewMode())) {
1545             setNeedsLayout();
1546             requestLayoutIfNeeded();
1547         }
1548     }
1549 }
1550
1551 void WebPagePrivate::layoutFinished()
1552 {
1553     // If a layout change has occurred, we need to invalidate any current spellcheck requests and trigger a new run.
1554     m_inputHandler->stopPendingSpellCheckRequests(true /* isRestartRequired */);
1555
1556     if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
1557         return;
1558
1559     m_contentsSizeChanged = false; // Toggle to turn off notification again.
1560     m_overflowExceedsContentsSize = false;
1561
1562     if (contentsSize().isEmpty())
1563         return;
1564
1565     // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from
1566     // the middle of a layout, but the recursion is limited by detection code in
1567     // setViewMode() and mitigation code in fixedLayoutSize().
1568     if (didLayoutExceedMaximumIterations()) {
1569         notifyTransformedContentsSizeChanged();
1570         return;
1571     }
1572
1573     // Temporarily save the m_previousContentsSize here before updating it (in
1574     // notifyTransformedContentsSizeChanged()) so we can compare if our contents
1575     // shrunk afterwards.
1576     IntSize previousContentsSize = m_previousContentsSize;
1577
1578     m_nestedLayoutFinishedCount++;
1579
1580     if (shouldZoomToInitialScaleOnLoad()) {
1581         zoomToInitialScaleOnLoad();
1582         m_shouldZoomToInitialScaleAfterLoadFinished = false;
1583     } else if (loadState() != None)
1584         notifyTransformedContentsSizeChanged();
1585
1586     m_nestedLayoutFinishedCount--;
1587
1588     if (!m_nestedLayoutFinishedCount) {
1589         // When the contents shrinks, there is a risk that we
1590         // will be left at a scroll position that lies outside of the
1591         // contents rect. Since we allow overscrolling and neglect
1592         // to clamp overscroll in order to retain input focus (RIM Bug #414)
1593         // we need to clamp somewhere, and this is where we know the
1594         // contents size has changed.
1595
1596         if (contentsSize() != previousContentsSize) {
1597
1598             IntPoint newScrollPosition = scrollPosition();
1599
1600             if (contentsSize().height() < previousContentsSize.height()) {
1601                 IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
1602                 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
1603             }
1604
1605             if (contentsSize().width() < previousContentsSize.width()) {
1606                 IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
1607                 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
1608             }
1609
1610             if (newScrollPosition != scrollPosition()) {
1611                 setScrollPosition(newScrollPosition);
1612                 notifyTransformedScrollChanged();
1613             }
1614
1615             const Platform::IntSize pixelContentsSize = m_webkitThreadViewportAccessor->pixelContentsSize();
1616
1617             // If the content size is too small, zoom it to fit the viewport.
1618             if ((loadState() == Finished || loadState() == Committed) && (pixelContentsSize.width() < m_actualVisibleWidth || pixelContentsSize.height() < m_actualVisibleHeight))
1619                 zoomAboutPoint(initialScale(), newScrollPosition);
1620         }
1621     }
1622 }
1623
1624 void WebPagePrivate::zoomToInitialScaleOnLoad()
1625 {
1626 #if DEBUG_WEBPAGE_LOAD
1627     Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
1628 #endif
1629
1630     bool needsLayout = false;
1631
1632     // If the contents width exceeds the viewport width set to desktop mode.
1633     if (m_shouldUseFixedDesktopMode)
1634         needsLayout = setViewMode(FixedDesktop);
1635     else
1636         needsLayout = setViewMode(Desktop);
1637
1638     if (needsLayout) {
1639         // This can cause recursive layout...
1640         setNeedsLayout();
1641     }
1642
1643     if (contentsSize().isEmpty()) {
1644 #if DEBUG_WEBPAGE_LOAD
1645         Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
1646 #endif
1647         requestLayoutIfNeeded();
1648         notifyTransformedContentsSizeChanged();
1649         return;
1650     }
1651
1652     bool performedZoom = false;
1653     bool shouldZoom = !m_userPerformedManualZoom;
1654
1655     // If this is a back/forward type navigation, don't zoom to initial scale
1656     // but instead let the HistoryItem's saved viewport reign supreme.
1657     if (m_mainFrame && m_mainFrame->loader() && isBackForwardLoadType(m_mainFrame->loader()->loadType()))
1658         shouldZoom = false;
1659
1660     if (shouldZoom && shouldZoomToInitialScaleOnLoad()) {
1661         // Preserve at top and at left position, to avoid scrolling
1662         // to a non top-left position for web page with viewport meta tag
1663         // that specifies an initial-scale that is zoomed in.
1664         FloatPoint anchor = centerOfVisibleContentsRect();
1665         if (!scrollPosition().x())
1666             anchor.setX(0);
1667         if (!scrollPosition().y())
1668             anchor.setY(0);
1669         performedZoom = zoomAboutPoint(initialScale(), anchor);
1670     }
1671
1672     // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout...
1673     requestLayoutIfNeeded();
1674
1675     if (!performedZoom) {
1676         // We only notify if we didn't perform zoom, because zoom will notify on
1677         // its own...
1678         notifyTransformedContentsSizeChanged();
1679     }
1680 }
1681
1682 double WebPagePrivate::zoomToFitScale() const
1683 {
1684     int contentWidth = contentsSize().width();
1685
1686     // For image document, zoom to fit the screen based on the actual image width
1687     // instead of the contents width within a maximum scale .
1688     Document* doc = m_page->mainFrame()->document();
1689     bool isImageDocument = doc && doc->isImageDocument();
1690     if (isImageDocument)
1691         contentWidth = static_cast<ImageDocument*>(doc)->imageSize().width();
1692
1693     double zoomToFitScale = contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
1694     int contentHeight = contentsSize().height();
1695     if (contentHeight * zoomToFitScale < static_cast<double>(m_defaultLayoutSize.height()))
1696         zoomToFitScale = contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
1697     zoomToFitScale = std::max(zoomToFitScale, minimumZoomToFitScale);
1698
1699     if (!isImageDocument)
1700         return zoomToFitScale;
1701
1702     return std::min(zoomToFitScale, maximumImageDocumentZoomToFitScale);
1703 }
1704
1705 bool WebPagePrivate::respectViewport() const
1706 {
1707     return m_forceRespectViewportArguments || contentsSize().width() <= m_virtualViewportSize.width() + 1;
1708 }
1709
1710 double WebPagePrivate::initialScale() const
1711 {
1712
1713     if (m_initialScale > 0.0 && respectViewport())
1714         return m_initialScale;
1715
1716     if (m_webSettings->isZoomToFitOnLoad())
1717         return zoomToFitScale();
1718
1719     return 1.0;
1720 }
1721
1722 double WebPage::initialScale() const
1723 {
1724     return d->initialScale();
1725 }
1726
1727 void WebPage::initializeIconDataBase()
1728 {
1729     IconDatabaseClientBlackBerry::instance()->initIconDatabase(d->m_webSettings);
1730 }
1731
1732 bool WebPage::isUserScalable() const
1733 {
1734     return d->isUserScalable();
1735 }
1736
1737 void WebPage::setUserScalable(bool userScalable)
1738 {
1739     d->setUserScalable(userScalable);
1740 }
1741
1742 double WebPage::currentScale() const
1743 {
1744     return d->currentScale();
1745 }
1746
1747 void WebPage::setInitialScale(double initialScale)
1748 {
1749     d->setInitialScale(initialScale);
1750 }
1751
1752 double WebPage::minimumScale() const
1753 {
1754     return d->minimumScale();
1755 }
1756
1757 void WebPage::setMinimumScale(double minimumScale)
1758 {
1759     d->setMinimumScale(minimumScale);
1760 }
1761
1762 void WebPage::setMaximumScale(double maximumScale)
1763 {
1764     d->setMaximumScale(maximumScale);
1765 }
1766
1767 double WebPagePrivate::maximumScale() const
1768 {
1769     double zoomToFitScale = this->zoomToFitScale();
1770     if (m_maximumScale >= m_minimumScale && respectViewport())
1771         return std::max(zoomToFitScale, m_maximumScale);
1772
1773     return hasVirtualViewport() ? std::max<double>(zoomToFitScale, 4.0) : 4.0;
1774 }
1775
1776 double WebPage::maximumScale() const
1777 {
1778     return d->maximumScale();
1779 }
1780
1781 void WebPagePrivate::resetScales()
1782 {
1783     TransformationMatrix identity;
1784     *m_transformationMatrix = identity;
1785     m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0;
1786     m_minimumScale = -1.0;
1787     m_maximumScale = -1.0;
1788     m_client->scaleChanged();
1789
1790     // We have to let WebCore know about updated framerect now that we've
1791     // reset our scales. See: RIM Bug #401.
1792     updateViewportSize();
1793 }
1794
1795 IntPoint WebPagePrivate::transformedScrollPosition() const
1796 {
1797     return m_backingStoreClient->transformedScrollPosition();
1798 }
1799
1800 IntPoint WebPagePrivate::transformedMaximumScrollPosition() const
1801 {
1802     return m_backingStoreClient->transformedMaximumScrollPosition();
1803 }
1804
1805 IntSize WebPagePrivate::transformedActualVisibleSize() const
1806 {
1807     return IntSize(m_actualVisibleWidth, m_actualVisibleHeight);
1808 }
1809
1810 Platform::ViewportAccessor* WebPage::webkitThreadViewportAccessor() const
1811 {
1812     return d->m_webkitThreadViewportAccessor;
1813 }
1814
1815 Platform::IntSize WebPage::viewportSize() const
1816 {
1817     return d->transformedActualVisibleSize();
1818 }
1819
1820 IntSize WebPagePrivate::transformedViewportSize() const
1821 {
1822     return BlackBerry::Platform::Settings::instance()->applicationSize();
1823 }
1824
1825 void WebPagePrivate::notifyTransformChanged()
1826 {
1827     notifyTransformedContentsSizeChanged();
1828     notifyTransformedScrollChanged();
1829
1830     m_backingStore->d->transformChanged();
1831 }
1832
1833 void WebPagePrivate::notifyTransformedContentsSizeChanged()
1834 {
1835     // We mark here as the last reported content size we sent to the client.
1836     m_previousContentsSize = contentsSize();
1837
1838     const IntSize size = m_webkitThreadViewportAccessor->pixelContentsSize();
1839     m_backingStore->d->contentsSizeChanged(size);
1840     m_client->contentsSizeChanged();
1841 }
1842
1843 void WebPagePrivate::notifyTransformedScrollChanged()
1844 {
1845     const IntPoint pos = transformedScrollPosition();
1846     m_backingStore->d->scrollChanged(pos);
1847     m_client->scrollChanged();
1848
1849 #if ENABLE(FULLSCREEN_API)
1850     adjustFullScreenElementDimensionsIfNeeded();
1851 #endif
1852 }
1853
1854 bool WebPagePrivate::setViewMode(ViewMode mode)
1855 {
1856     if (!m_mainFrame || !m_mainFrame->view())
1857         return false;
1858
1859     m_viewMode = mode;
1860
1861     // If we're in the middle of a nested layout with a recursion count above
1862     // some maximum threshold, then our algorithm for finding the minimum content
1863     // width of a given page has become dependent on the visible width.
1864     //
1865     // We need to find some method to ensure that we don't experience excessive
1866     // and even infinite recursion. This can even happen with valid html. The
1867     // former can happen when we run into inline text with few candidates for line
1868     // break. The latter can happen for instance if the page has a negative margin
1869     // set against the right border. Note: this is valid by spec and can lead to
1870     // a situation where there is no value for which the content width will ensure
1871     // no horizontal scrollbar.
1872     // Example: LayoutTests/css1/box_properties/margin.html
1873     //
1874     // In order to address such situations when we detect a recursion above some
1875     // maximum threshold we snap our fixed layout size to a defined quantum increment.
1876     // Eventually, either the content width will be satisfied to ensure no horizontal
1877     // scrollbar or this increment will run into the maximum layout size and the
1878     // recursion will necessarily end.
1879     bool snapToIncrement = didLayoutExceedMaximumIterations();
1880
1881     IntSize currentSize = m_mainFrame->view()->fixedLayoutSize();
1882     IntSize newSize = fixedLayoutSize(snapToIncrement);
1883     if (currentSize == newSize)
1884         return false;
1885
1886     // FIXME: Temp solution. We'll get back to this.
1887     if (m_nestedLayoutFinishedCount) {
1888         double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width());
1889         double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height());
1890         if (widthChange < 0.05 && heightChange < 0.05)
1891             return false;
1892     }
1893
1894     m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
1895     m_mainFrame->view()->setFixedLayoutSize(newSize);
1896     return true; // Needs re-layout!
1897 }
1898
1899 int WebPagePrivate::playerID() const
1900 {
1901     return m_client ? m_client->getInstanceId() : 0;
1902 }
1903
1904 void WebPagePrivate::setCursor(PlatformCursor handle)
1905 {
1906     if (m_currentCursor.type() != handle.type()) {
1907         m_currentCursor = handle;
1908         m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot());
1909     }
1910 }
1911
1912 Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory()
1913 {
1914     return m_client->networkStreamFactory();
1915 }
1916
1917 Platform::Graphics::Window* WebPagePrivate::platformWindow() const
1918 {
1919     return m_client->window();
1920 }
1921
1922 void WebPagePrivate::setPreventsScreenDimming(bool keepAwake)
1923 {
1924     if (keepAwake) {
1925         if (!m_preventIdleDimmingCount)
1926             m_client->setPreventsScreenIdleDimming(true);
1927         m_preventIdleDimmingCount++;
1928     } else if (m_preventIdleDimmingCount > 0) {
1929         m_preventIdleDimmingCount--;
1930         if (!m_preventIdleDimmingCount)
1931             m_client->setPreventsScreenIdleDimming(false);
1932     } else
1933         ASSERT_NOT_REACHED(); // SetPreventsScreenIdleDimming(false) called too many times.
1934 }
1935
1936 void WebPagePrivate::showVirtualKeyboard(bool showKeyboard)
1937 {
1938     m_client->showVirtualKeyboard(showKeyboard);
1939 }
1940
1941 void WebPagePrivate::ensureContentVisible(bool centerInView)
1942 {
1943     m_inputHandler->ensureFocusElementVisible(centerInView);
1944 }
1945
1946 void WebPagePrivate::zoomToContentRect(const IntRect& rect)
1947 {
1948     // Don't scale if the user is not supposed to scale.
1949     if (!isUserScalable())
1950         return;
1951
1952     FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y());
1953     IntSize viewSize = viewportSize();
1954
1955     // Calculate the scale required to scale that dimension to fit.
1956     double scaleH = (double)viewSize.width() / (double)rect.width();
1957     double scaleV = (double)viewSize.height() / (double)rect.height();
1958
1959     // Choose the smaller scale factor so that all of the content is visible.
1960     zoomAboutPoint(min(scaleH, scaleV), anchor);
1961 }
1962
1963 void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister)
1964 {
1965     if (shouldRegister)
1966         m_pluginViews.add(plugin);
1967     else
1968         m_pluginViews.remove(plugin);
1969 }
1970
1971 #define FOR_EACH_PLUGINVIEW(pluginViews) \
1972     HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \
1973     HashSet<PluginView*>::const_iterator last = pluginViews.end(); \
1974     for (; it != last; ++it)
1975
1976 void WebPagePrivate::notifyPageOnLoad()
1977 {
1978     FOR_EACH_PLUGINVIEW(m_pluginViews)
1979         (*it)->handleOnLoadEvent();
1980 }
1981
1982 bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView*, const char*)
1983 {
1984     return m_client->shouldPluginEnterFullScreen();
1985 }
1986
1987 void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
1988 {
1989     m_fullScreenPluginView = plugin;
1990     m_client->didPluginEnterFullScreen();
1991
1992     if (!m_client->window())
1993         return;
1994
1995     Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix);
1996     m_client->window()->setSensitivityFullscreenOverride(true);
1997 }
1998
1999 void WebPagePrivate::didPluginExitFullScreen(PluginView*, const char*)
2000 {
2001     m_fullScreenPluginView = 0;
2002     m_client->didPluginExitFullScreen();
2003
2004     if (!m_client->window())
2005         return;
2006
2007     Platform::Graphics::Window::setTransparencyDiscardFilter(0);
2008     m_client->window()->setSensitivityFullscreenOverride(false);
2009 }
2010
2011 void WebPagePrivate::onPluginStartBackgroundPlay(PluginView*, const char*)
2012 {
2013     m_client->onPluginStartBackgroundPlay();
2014 }
2015
2016 void WebPagePrivate::onPluginStopBackgroundPlay(PluginView*, const char*)
2017 {
2018     m_client->onPluginStopBackgroundPlay();
2019 }
2020
2021 bool WebPagePrivate::lockOrientation(bool landscape)
2022 {
2023     return m_client->lockOrientation(landscape);
2024 }
2025
2026 void WebPagePrivate::unlockOrientation()
2027 {
2028     return m_client->unlockOrientation();
2029 }
2030
2031 int WebPagePrivate::orientation() const
2032 {
2033 #if ENABLE(ORIENTATION_EVENTS)
2034     return m_mainFrame->orientation();
2035 #else
2036 #error ORIENTATION_EVENTS must be defined.
2037 // Or a copy of the orientation value will have to be stored in these objects.
2038 #endif
2039 }
2040
2041 double WebPagePrivate::currentZoomFactor() const
2042 {
2043     return currentScale();
2044 }
2045
2046 int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype)
2047 {
2048     return m_client->showAlertDialog(atype);
2049 }
2050
2051 bool WebPagePrivate::isActive() const
2052 {
2053     return m_client->isActive();
2054 }
2055
2056 void WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSpace& protectionSpace, const Credential& inputCredential)
2057 {
2058     AuthenticationChallengeManager* authmgr = AuthenticationChallengeManager::instance();
2059     BlackBerry::Platform::String username;
2060     BlackBerry::Platform::String password;
2061     BlackBerry::Platform::String requestURL(url.string());
2062
2063 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
2064     if (m_dumpRenderTree) {
2065         Credential credential(inputCredential, inputCredential.persistence());
2066         if (m_dumpRenderTree->didReceiveAuthenticationChallenge(credential))
2067             authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeSuccess, credential);
2068         else
2069             authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeCancelled, inputCredential);
2070         return;
2071     }
2072 #endif
2073
2074 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2075     if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled())
2076         credentialManager().autofillAuthenticationChallenge(protectionSpace, username, password);
2077 #endif
2078
2079     bool isConfirmed = m_client->authenticationChallenge(protectionSpace.realm().characters(), protectionSpace.realm().length(), username, password, requestURL, protectionSpace.isProxy());
2080
2081 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2082     Credential credential(username, password, CredentialPersistencePermanent);
2083     if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled() && isConfirmed)
2084         credentialManager().saveCredentialIfConfirmed(this, CredentialTransformData(protectionSpace, credential));
2085 #else
2086     Credential credential(username, password, CredentialPersistenceNone);
2087 #endif
2088
2089     if (isConfirmed)
2090         authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeSuccess, credential);
2091     else
2092         authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeCancelled, inputCredential);
2093 }
2094
2095 PageClientBlackBerry::SaveCredentialType WebPagePrivate::notifyShouldSaveCredential(bool isNew)
2096 {
2097     return static_cast<PageClientBlackBerry::SaveCredentialType>(m_client->notifyShouldSaveCredential(isNew));
2098 }
2099
2100 void WebPagePrivate::syncProxyCredential(const WebCore::Credential& credential)
2101 {
2102     m_client->syncProxyCredential(credential.user(), credential.password());
2103 }
2104
2105 void WebPagePrivate::notifyPopupAutofillDialog(const Vector<String>& candidates)
2106 {
2107     vector<BlackBerry::Platform::String> textItems;
2108     for (size_t i = 0; i < candidates.size(); i++)
2109         textItems.push_back(candidates[i]);
2110     m_client->notifyPopupAutofillDialog(textItems);
2111 }
2112
2113 void WebPagePrivate::notifyDismissAutofillDialog()
2114 {
2115     m_client->notifyDismissAutofillDialog();
2116 }
2117
2118 bool WebPagePrivate::useFixedLayout() const
2119 {
2120     return true;
2121 }
2122
2123 Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy)
2124 {
2125     Platform::WebContext context;
2126
2127     RefPtr<Node> node = contextNode(strategy);
2128     m_currentContextNode = node;
2129     if (!m_currentContextNode)
2130         return context;
2131
2132     // Send an onContextMenu event to the current context ndoe and get the result. Since we've already figured out
2133     // which node we want, we can send it directly to the node and not do a hit test. The onContextMenu event doesn't require
2134     // mouse positions so we just set the position at (0,0)
2135     PlatformMouseEvent mouseEvent(IntPoint(), IntPoint(), PlatformEvent::MouseMoved, 0, NoButton, false, false, false, TouchScreen);
2136     if (!m_currentContextNode->dispatchMouseEvent(mouseEvent, eventNames().contextmenuEvent, 0)) {
2137         context.setFlag(Platform::WebContext::IsOnContextMenuPrevented);
2138         return context;
2139     }
2140
2141     requestLayoutIfNeeded();
2142
2143     bool nodeAllowSelectionOverride = false;
2144     Node* linkNode = node->enclosingLinkEventParentOrSelf();
2145     // 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.
2146     if ((node == linkNode) || (node->isTextNode() && linkNode)) {
2147         KURL href;
2148         if (linkNode->isLink() && linkNode->hasAttributes()) {
2149             if (const Attribute* attribute = toElement(linkNode)->getAttributeItem(HTMLNames::hrefAttr))
2150                 href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
2151         }
2152
2153         String pattern = findPatternStringForUrl(href);
2154         if (!pattern.isEmpty())
2155             context.setPattern(pattern);
2156
2157         if (!href.string().isEmpty()) {
2158             context.setUrl(href.string());
2159
2160             // Links are non-selectable by default, but selection should be allowed
2161             // providing the page is selectable, use the parent to determine it.
2162             if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
2163                 nodeAllowSelectionOverride = true;
2164         }
2165     }
2166
2167     if (node->isHTMLElement()) {
2168         HTMLImageElement* imageElement = 0;
2169         HTMLMediaElement* mediaElement = 0;
2170
2171         if (node->hasTagName(HTMLNames::imgTag))
2172             imageElement = static_cast<HTMLImageElement*>(node.get());
2173         else if (node->hasTagName(HTMLNames::areaTag))
2174             imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement();
2175
2176         if (static_cast<HTMLElement*>(node.get())->isMediaElement())
2177             mediaElement = static_cast<HTMLMediaElement*>(node.get());
2178
2179         if (imageElement && imageElement->renderer()) {
2180             context.setFlag(Platform::WebContext::IsImage);
2181             // FIXME: At the mean time, we only show "Save Image" when the image data is available.
2182             if (CachedImage* cachedImage = imageElement->cachedImage()) {
2183                 if (cachedImage->isLoaded() && cachedImage->resourceBuffer()) {
2184                     String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
2185                     context.setSrc(node->document()->completeURL(url).string());
2186
2187                     String mimeType = cachedImage->response().mimeType();
2188                     if (mimeType.isEmpty()) {
2189                         StringBuilder builder;
2190                         String extension = cachedImage->image()->filenameExtension();
2191                         builder.append("image/");
2192                         if (extension.isEmpty())
2193                             builder.append("unknown");
2194                         else if (extension == "jpg")
2195                             builder.append("jpeg");
2196                         else
2197                             builder.append(extension);
2198                         mimeType = builder.toString();
2199                     }
2200                     context.setMimeType(mimeType);
2201                 }
2202             }
2203             String alt = imageElement->altText();
2204             if (!alt.isNull())
2205                 context.setAlt(alt);
2206         }
2207
2208         if (mediaElement) {
2209             if (mediaElement->hasAudio())
2210                 context.setFlag(Platform::WebContext::IsAudio);
2211             if (mediaElement->hasVideo())
2212                 context.setFlag(Platform::WebContext::IsVideo);
2213
2214             String src = stripLeadingAndTrailingHTMLSpaces(mediaElement->getAttribute(HTMLNames::srcAttr).string());
2215             context.setSrc(node->document()->completeURL(src).string());
2216         }
2217     }
2218
2219     if (node->isTextNode()) {
2220         Text* curText = toText(node.get());
2221         if (!curText->wholeText().isEmpty())
2222             context.setText(curText->wholeText());
2223     }
2224
2225     bool canStartSelection = node->canStartSelection();
2226
2227     if (node->isElementNode()) {
2228         Element* element = toElement(node->deprecatedShadowAncestorNode());
2229
2230         if (DOMSupport::isTextBasedContentEditableElement(element)) {
2231             if (!canStartSelection) {
2232                 // Input fields host node is by spec non-editable unless the field itself has content editable enabled.
2233                 // Enable selection if the shadow tree for the input field is selectable.
2234                 Node* nodeUnderFinger = m_touchEventHandler->lastFatFingersResult().isValid() ? m_touchEventHandler->lastFatFingersResult().node(FatFingersResult::ShadowContentAllowed) : 0;
2235                 if (nodeUnderFinger)
2236                     canStartSelection = nodeUnderFinger->canStartSelection();
2237             }
2238             context.setFlag(Platform::WebContext::IsInput);
2239             if (element->hasTagName(HTMLNames::inputTag))
2240                 context.setFlag(Platform::WebContext::IsSingleLine);
2241             if (DOMSupport::isPasswordElement(element))
2242                 context.setFlag(Platform::WebContext::IsPassword);
2243
2244             String elementText(DOMSupport::inputElementText(element));
2245             if (!elementText.stripWhiteSpace().isEmpty())
2246                 context.setText(elementText);
2247             else if (!node->focused() && m_touchEventHandler->lastFatFingersResult().isValid() && strategy == RectBased) {
2248                 // 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.
2249                 m_touchEventHandler->sendClickAtFatFingersPoint();
2250             }
2251         }
2252     }
2253
2254     if (!nodeAllowSelectionOverride && !canStartSelection)
2255         context.resetFlag(Platform::WebContext::IsSelectable);
2256
2257     if (node->isFocusable())
2258         context.setFlag(Platform::WebContext::IsFocusable);
2259
2260     // Walk up the node tree looking for our custom webworks context attribute.
2261     while (node) {
2262         if (node->isElementNode()) {
2263             Element* element = toElement(node->deprecatedShadowAncestorNode());
2264             String webWorksContext(DOMSupport::webWorksContext(element));
2265             if (!webWorksContext.stripWhiteSpace().isEmpty()) {
2266                 context.setFlag(Platform::WebContext::IsWebWorksContext);
2267                 context.setWebWorksContext(webWorksContext);
2268                 break;
2269             }
2270         }
2271         node = node->parentNode();
2272     }
2273
2274     return context;
2275 }
2276
2277 Platform::WebContext WebPage::webContext(TargetDetectionStrategy strategy) const
2278 {
2279     return d->webContext(strategy);
2280 }
2281
2282 void WebPagePrivate::updateCursor()
2283 {
2284     int buttonMask = 0;
2285     if (m_lastMouseEvent.button() == LeftButton)
2286         buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
2287     else if (m_lastMouseEvent.button() == MiddleButton)
2288         buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
2289     else if (m_lastMouseEvent.button() == RightButton)
2290         buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
2291
2292     unsigned modifiers = m_lastMouseEvent.shiftKey() ? 0 : KEYMOD_SHIFT |
2293         m_lastMouseEvent.ctrlKey() ? 0 : KEYMOD_CTRL |
2294         m_lastMouseEvent.altKey() ? 0 : KEYMOD_ALT;
2295
2296     const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor;
2297
2298     BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask,
2299         viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatPoint(m_lastMouseEvent.position())),
2300         viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatPoint(m_lastMouseEvent.globalPosition())),
2301         0, modifiers, 0);
2302
2303     // 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.
2304     event.populateDocumentPosition(m_lastMouseEvent.position(), viewportAccessor->documentContentsFromViewport(m_lastMouseEvent.position()));
2305
2306     m_webPage->mouseEvent(event);
2307 }
2308
2309 IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
2310 {
2311     if (hasVirtualViewport())
2312         return m_virtualViewportSize;
2313
2314     const int defaultLayoutWidth = m_defaultLayoutSize.width();
2315     const int defaultLayoutHeight = m_defaultLayoutSize.height();
2316
2317     int minWidth = defaultLayoutWidth;
2318     int maxWidth = DEFAULT_MAX_LAYOUT_WIDTH;
2319     int maxHeight = DEFAULT_MAX_LAYOUT_HEIGHT;
2320
2321     // If the load state is none then we haven't actually got anything yet, but we need to layout
2322     // the entire page so that the user sees the entire page (unrendered) instead of just part of it.
2323     // If the load state is Provisional, it is possible that absoluteVisibleOverflowSize() and
2324     // contentsSize() are based on the old page and cause inconsistent fixedLayoutSize, so layout the
2325     // new page based on the defaultLayoutSize as well.
2326     if (m_loadState == None || m_loadState == Provisional)
2327         return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2328
2329     if (m_viewMode == FixedDesktop) {
2330         int width  = maxWidth;
2331         // if the defaultLayoutHeight is at minimum, it probably was set as 0
2332         // and clamped, meaning it's effectively not set.  (Even if it happened
2333         // to be set exactly to the minimum, it's too small to be useful.)  So
2334         // ignore it.
2335         int height;
2336         if (defaultLayoutHeight <= minimumLayoutSize.height())
2337             height = maxHeight;
2338         else
2339             height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2340         return IntSize(width, height);
2341     }
2342
2343     if (m_viewMode == Desktop) {
2344         // If we detect an overflow larger than the contents size then use that instead since
2345         // it'll still be clamped by the maxWidth below...
2346         int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
2347         if (m_pendingOrientation != -1 && !m_nestedLayoutFinishedCount && !m_overflowExceedsContentsSize)
2348             width = 0;
2349
2350         if (snapToIncrement) {
2351             // Snap to increments of defaultLayoutWidth / 2.0.
2352             float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
2353             factor = ceilf(factor);
2354             width = (defaultLayoutWidth / 2.0) * factor;
2355         }
2356
2357         if (width < minWidth)
2358             width = minWidth;
2359         if (width > maxWidth)
2360             width = maxWidth;
2361         int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2362         return IntSize(width, height);
2363     }
2364
2365     ASSERT_NOT_REACHED();
2366     return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2367 }
2368
2369 BackingStoreClient* WebPagePrivate::backingStoreClient() const
2370 {
2371     return m_backingStoreClient;
2372 }
2373
2374 void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
2375 {
2376     ASSERT(documentGoingAway);
2377     if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
2378         m_currentContextNode = 0;
2379
2380     if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
2381         m_currentPinchZoomNode = 0;
2382
2383     if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
2384         m_currentBlockZoomAdjustedNode = 0;
2385
2386     if (m_inRegionScroller->d->isActive())
2387         m_inRegionScroller->d->clearDocumentData(documentGoingAway);
2388
2389     if (documentGoingAway->frame())
2390         m_inputHandler->frameUnloaded(documentGoingAway->frame());
2391
2392     Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
2393     if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
2394         m_touchEventHandler->resetLastFatFingersResult();
2395
2396     // NOTE: m_fullscreenNode, m_fullScreenPluginView and m_pluginViews
2397     // are cleared in other methods already.
2398 }
2399
2400 typedef bool (*PredicateFunction)(RenderLayer*);
2401 static bool isPositionedContainer(RenderLayer* layer)
2402 {
2403     RenderObject* o = layer->renderer();
2404     return o->isRenderView() || o->isOutOfFlowPositioned() || o->isRelPositioned() || layer->hasTransform();
2405 }
2406
2407 static bool isFixedPositionedContainer(RenderLayer* layer)
2408 {
2409     RenderObject* o = layer->renderer();
2410     return o->isRenderView() || (o->isOutOfFlowPositioned() && o->style()->position() == FixedPosition);
2411 }
2412
2413 static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
2414 {
2415     RenderLayer* curr = layer;
2416     while (curr && !predicate(curr))
2417         curr = curr->parent();
2418
2419     return curr;
2420 }
2421
2422 RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
2423 {
2424     return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
2425 }
2426
2427 RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
2428 {
2429     return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
2430 }
2431
2432 static inline Frame* frameForNode(Node* node)
2433 {
2434     Node* origNode = node;
2435     for (; node; node = node->parentNode()) {
2436         if (RenderObject* renderer = node->renderer()) {
2437             if (renderer->isRenderView()) {
2438                 if (FrameView* view = toRenderView(renderer)->frameView()) {
2439                     if (Frame* frame = view->frame())
2440                         return frame;
2441                 }
2442             }
2443             if (renderer->isWidget()) {
2444                 Widget* widget = toRenderWidget(renderer)->widget();
2445                 if (widget && widget->isFrameView()) {
2446                     if (Frame* frame = toFrameView(widget)->frame())
2447                         return frame;
2448                 }
2449             }
2450         }
2451     }
2452
2453     for (node = origNode; node; node = node->parentNode()) {
2454         if (Document* doc = node->document()) {
2455             if (Frame* frame = doc->frame())
2456                 return frame;
2457         }
2458     }
2459
2460     return 0;
2461 }
2462
2463 static IntRect getNodeWindowRect(Node* node)
2464 {
2465     if (Frame* frame = frameForNode(node)) {
2466         if (FrameView* view = frame->view())
2467             return view->contentsToWindow(node->getRect());
2468     }
2469     ASSERT_NOT_REACHED();
2470     return IntRect();
2471 }
2472
2473 IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
2474 {
2475     ASSERT(m_mainFrame);
2476
2477     // Don't call this function asking to not clip the main frame providing only
2478     // the main frame. All that can be returned is the content rect which
2479     // isn't what this function is for.
2480     if (noClipOfMainFrame && view == m_mainFrame->view()) {
2481         ASSERT_NOT_REACHED();
2482         return IntRect(IntPoint::zero(), view->contentsSize());
2483     }
2484
2485     IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect()));
2486     if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
2487         // Intersect with parent visible rect.
2488         visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
2489     }
2490     return visibleWindowRect;
2491 }
2492
2493 void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
2494 {
2495     ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
2496     ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
2497     ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
2498
2499     // First we clear the focus, since we want to focus either initial or the last
2500     // focusable element in the webpage (according to the TABINDEX), or simply clear
2501     // the focus.
2502     clearFocusNode();
2503
2504     switch (direction) {
2505     case FocusDirectionForward:
2506     case FocusDirectionBackward:
2507         m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
2508         break;
2509     case FocusDirectionNone:
2510         break;
2511     default:
2512         ASSERT_NOT_REACHED();
2513     }
2514 }
2515
2516 void WebPage::assignFocus(Platform::FocusDirection direction)
2517 {
2518     if (d->m_page->defersLoading())
2519         return;
2520     d->assignFocus(direction);
2521 }
2522
2523 void WebPage::focusNextField()
2524 {
2525     d->m_inputHandler->focusNextField();
2526 }
2527
2528 void WebPage::focusPreviousField()
2529 {
2530     d->m_inputHandler->focusPreviousField();
2531 }
2532
2533 void WebPage::submitForm()
2534 {
2535     d->m_inputHandler->submitForm();
2536 }
2537
2538 Platform::IntRect WebPagePrivate::focusNodeRect()
2539 {
2540     Frame* frame = focusedOrMainFrame();
2541     if (!frame)
2542         return Platform::IntRect();
2543
2544     Document* doc = frame->document();
2545     FrameView* view = frame->view();
2546     if (!doc || !view || view->needsLayout())
2547         return Platform::IntRect();
2548
2549     const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor;
2550
2551     IntRect focusRect = rectForNode(doc->focusedNode());
2552     focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
2553     focusRect = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatRect(focusRect));
2554     focusRect.intersect(viewportAccessor->pixelContentsRect());
2555     return focusRect;
2556 }
2557
2558 PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
2559 {
2560     EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2561     const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
2562     bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
2563
2564     // Check if we're using LinkToLink and the user is not touching the screen.
2565     if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
2566         RefPtr<Node> node;
2567         node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
2568         if (node) {
2569             IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
2570             if (!visibleRect.intersects(getNodeWindowRect(node.get())))
2571                 return 0;
2572         }
2573         return node.release();
2574     }
2575
2576     // Check for text input.
2577     if (isTouching && lastFatFingersResult.isTextInput())
2578         return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
2579
2580     if (strategy == RectBased) {
2581         FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
2582         return result.node(FatFingersResult::ShadowContentNotAllowed);
2583     }
2584     if (strategy == FocusBased)
2585         return m_inputHandler->currentFocusElement();
2586
2587     IntPoint contentPos;
2588     if (isTouching)
2589         contentPos = lastFatFingersResult.adjustedPosition();
2590     else
2591         contentPos = m_webkitThreadViewportAccessor->documentContentsFromViewport(m_lastMouseEvent.position());
2592
2593     HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos);
2594     return result.innerNode();
2595 }
2596
2597 static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
2598 {
2599     // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709).
2600     double dx = static_cast<double>(p1.x() - p2.x());
2601     double dy = static_cast<double>(p1.y() - p2.y());
2602     return sqrt((dx * dx) + (dy * dy));
2603 }
2604
2605 Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& documentPoint)
2606 {
2607     IntRect clickRect(documentPoint.x() - blockClickRadius, documentPoint.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
2608     Node* originalNode = nodeForZoomUnderPoint(documentPoint);
2609     if (!originalNode)
2610         return 0;
2611     Node* node = bestChildNodeForClickRect(originalNode, clickRect);
2612     return node ? adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(node) : adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(originalNode);
2613 }
2614
2615 Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
2616 {
2617     if (!parentNode)
2618         return 0;
2619
2620     int bestDistance = std::numeric_limits<int>::max();
2621
2622     Node* node = parentNode->firstChild();
2623     Node* bestNode = 0;
2624     for (; node; node = node->nextSibling()) {
2625         IntRect rect = rectForNode(node);
2626         if (!clickRect.intersects(rect))
2627             continue;
2628
2629         int distance = distanceBetweenPoints(rect.center(), clickRect.center());
2630         Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
2631         if (bestChildNode) {
2632             IntRect bestChildRect = rectForNode(bestChildNode);
2633             int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
2634             if (bestChildDistance < distance && bestChildDistance < bestDistance) {
2635                 bestNode = bestChildNode;
2636                 bestDistance = bestChildDistance;
2637             } else {
2638                 if (distance < bestDistance) {
2639                     bestNode = node;
2640                     bestDistance = distance;
2641                 }
2642             }
2643         } else {
2644             if (distance < bestDistance) {
2645                 bestNode = node;
2646                 bestDistance = distance;
2647             }
2648         }
2649     }
2650
2651     return bestNode;
2652 }
2653
2654 double WebPagePrivate::maxBlockZoomScale() const
2655 {
2656     return std::min(maximumBlockZoomScale, maximumScale());
2657 }
2658
2659 Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& documentPoint)
2660 {
2661     if (!m_mainFrame)
2662         return 0;
2663
2664     HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(documentPoint);
2665
2666     Node* node = result.innerNonSharedNode();
2667
2668     if (!node)
2669         return 0;
2670
2671     RenderObject* renderer = node->renderer();
2672     while (!renderer) {
2673         node = node->parentNode();
2674         renderer = node->renderer();
2675     }
2676
2677     return node;
2678 }
2679
2680 Node* WebPagePrivate::adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(Node* node)
2681 {
2682     Node* initialNode = node;
2683     RenderObject* renderer = node->renderer();
2684     bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2685     IntSize actualVisibleSize = this->actualVisibleSize();
2686
2687     while (!renderer || !acceptableNodeSize) {
2688         node = node->parentNode();
2689         IntRect nodeRect = rectForNode(node);
2690
2691         // Don't choose a node if the width of the node size is very close to the width of the actual visible size,
2692         // as block zoom can do nothing on such kind of node.
2693         if (!node || static_cast<double>(actualVisibleSize.width() - nodeRect.width()) / actualVisibleSize.width() < minimumExpandingRatio)
2694             return initialNode;
2695
2696         renderer = node->renderer();
2697         acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2698     }
2699
2700     return node;
2701 }
2702
2703 bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
2704 {
2705     if (!n1 || !n2)
2706         return false;
2707
2708     return (n2 == n1) || n2->isDescendantOf(n1);
2709 }
2710
2711 double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
2712 {
2713     if (rect.isEmpty())
2714         return std::numeric_limits<double>::max();
2715
2716     ASSERT(rect.width() + margin);
2717
2718     double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
2719
2720     return newScale;
2721 }
2722
2723 IntRect WebPagePrivate::rectForNode(Node* node)
2724 {
2725     if (!node)
2726         return IntRect();
2727
2728     RenderObject* renderer = node->renderer();
2729
2730     if (!renderer)
2731         return IntRect();
2732
2733     // Return rect in un-transformed content coordinates.
2734     IntRect blockRect;
2735
2736     // FIXME: Ensure this works with iframes.
2737     if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
2738         RenderBlock* renderBlock = renderer->containingBlock();
2739         int xOffset = 0;
2740         int yOffset = 0;
2741         while (!renderBlock->isRoot()) {
2742             xOffset += renderBlock->x().toInt();
2743             yOffset += renderBlock->y().toInt();
2744             renderBlock = renderBlock->containingBlock();
2745         }
2746         const RenderText* renderText = toRenderText(renderer);
2747         IntRect linesBox = renderText->linesBoundingBox();
2748         blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height());
2749     } else
2750         blockRect = IntRect(renderer->absoluteClippedOverflowRect());
2751
2752     if (renderer->isText()) {
2753         RenderBlock* rb = renderer->containingBlock();
2754
2755         // Inefficient? Way to find width when floats intersect a block.
2756         int blockWidth = 0;
2757         int lineCount = rb->lineCount();
2758         for (int i = 0; i < lineCount; i++)
2759             blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false).toInt());
2760
2761         blockRect.setWidth(blockWidth);
2762         blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
2763     }
2764
2765     // Strip off padding.
2766     if (renderer->style()->hasPadding()) {
2767         blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
2768         blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
2769         blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
2770         blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
2771     }
2772
2773     return blockRect;
2774 }
2775
2776 IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
2777 {
2778     ASSERT(frame);
2779
2780     // FIXME: This function can be called when page is being destroyed and JS triggers selection change.
2781     // We could break the call chain at upper levels, but I think it is better to check the frame pointer
2782     // here because the pointer is explicitly cleared in WebPage::destroy().
2783     if (!mainFrame())
2784         return IntPoint();
2785
2786     // Convert 0,0 in the frame's coordinate system to window coordinates to
2787     // get the frame's global position, and return this position in the main
2788     // frame's coordinates.  (So the main frame's coordinates will be 0,0.)
2789     return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
2790 }
2791
2792 IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
2793 {
2794     if (!node)
2795         return rect;
2796
2797     // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames.
2798     // FIXME: can we just use frameOffset instead of this big routine?
2799     const Node* tnode = node;
2800     IntRect adjustedRect = rect;
2801     do {
2802         Frame* frame = tnode->document()->frame();
2803         if (!frame)
2804             continue;
2805
2806         Node* ownerNode = static_cast<Node*>(frame->ownerElement());
2807         tnode = ownerNode;
2808         if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
2809             IntRect iFrameRect;
2810             do {
2811                 iFrameRect = rectForNode(ownerNode);
2812                 adjustedRect.move(iFrameRect.x(), iFrameRect.y());
2813                 adjustedRect.intersect(iFrameRect);
2814                 ownerNode = ownerNode->parentNode();
2815             } while (iFrameRect.isEmpty() && ownerNode);
2816         } else
2817             break;
2818     } while ((tnode = tnode->parentNode()));
2819
2820     return adjustedRect;
2821 }
2822
2823 IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
2824 {
2825     if (!node || contentsSize().isEmpty())
2826         return IntRect();
2827
2828     Node* tnode = node;
2829     m_currentBlockZoomAdjustedNode = tnode;
2830
2831     IntRect blockRect = rectForNode(tnode);
2832     IntRect originalRect = blockRect;
2833
2834     int originalArea = originalRect.width() * originalRect.height();
2835     int pageArea = contentsSize().width() * contentsSize().height();
2836     double blockToPageRatio = static_cast<double>(pageArea - originalArea) / pageArea;
2837     double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
2838
2839     if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
2840         while ((tnode = tnode->parentNode())) {
2841             ASSERT(tnode);
2842             IntRect tRect = rectForNode(tnode);
2843             int tempBlockArea = tRect.width() * tRect.height();
2844             // Don't expand the block if it will be too large relative to the content.
2845             if (static_cast<double>(pageArea - tempBlockArea) / pageArea < minimumExpandingRatio)
2846                 break;
2847             if (tRect.isEmpty())
2848                 continue; // No renderer.
2849             if (tempBlockArea < 1.1 * originalArea)
2850                 continue; // The size of this parent is very close to the child, no need to go to this parent.
2851             // Don't expand the block if the parent node size is already almost the size of actual visible size.
2852             IntSize actualSize = actualVisibleSize();
2853             if (static_cast<double>(actualSize.width() - tRect.width()) / actualSize.width() < minimumExpandingRatio)
2854                 break;
2855             if (tempBlockArea < blockExpansionRatio * originalArea) {
2856                 blockRect = tRect;
2857                 m_currentBlockZoomAdjustedNode = tnode;
2858             } else
2859                 break;
2860         }
2861     }
2862
2863     const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor;
2864
2865     blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
2866     blockRect = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatRect(blockRect));
2867     blockRect.intersect(viewportAccessor->pixelContentsRect());
2868
2869     return blockRect;
2870 }
2871
2872 // This function should not be called directly.
2873 // It is called after the animation ends (see above).
2874 void WebPagePrivate::zoomAnimationFinished(double finalAnimationScale, const WebCore::FloatPoint& finalAnimationDocumentScrollPosition, bool shouldConstrainScrollingToContentEdge)
2875 {
2876     if (!m_mainFrame)
2877         return;
2878
2879     const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor;
2880
2881     IntPoint anchor(viewportAccessor->roundedDocumentContents(finalAnimationDocumentScrollPosition));
2882     bool willUseTextReflow = false;
2883
2884 #if ENABLE(VIEWPORT_REFLOW)
2885     willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
2886     toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
2887     setNeedsLayout();
2888 #endif
2889
2890     TransformationMatrix zoom;
2891     zoom.scale(finalAnimationScale);
2892     *m_transformationMatrix = zoom;
2893     // FIXME: Do we really need to suspend/resume both backingstore and screen here?
2894     m_backingStore->d->suspendBackingStoreUpdates();
2895     m_backingStore->d->suspendScreenUpdates();
2896     updateViewportSize();
2897
2898     FrameView* mainFrameView = m_mainFrame->view();
2899     bool constrainsScrollingToContentEdge = true;
2900     if (mainFrameView) {
2901         constrainsScrollingToContentEdge = mainFrameView->constrainsScrollingToContentEdge();
2902         mainFrameView->setConstrainsScrollingToContentEdge(shouldConstrainScrollingToContentEdge);
2903     }
2904
2905 #if ENABLE(VIEWPORT_REFLOW)
2906     requestLayoutIfNeeded();
2907     if (willUseTextReflow && m_shouldReflowBlock) {
2908         Platform::IntPoint roundedReflowOffset(
2909             std::floorf(m_finalAnimationDocumentScrollPositionReflowOffset.x()),
2910             std::floorf(m_finalAnimationDocumentScrollPositionReflowOffset.y()));
2911
2912         IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
2913         reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
2914         reflowedRect.move(roundedReflowOffset.x(), roundedReflowOffset.y());
2915
2916         RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
2917         IntPoint topLeftPoint(reflowedRect.location());
2918         if (renderer && renderer->isText()) {
2919             ETextAlign textAlign = renderer->style()->textAlign();
2920             IntPoint textAnchor;
2921             switch (textAlign) {
2922             case CENTER:
2923             case WEBKIT_CENTER:
2924                 textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
2925                 break;
2926             case LEFT:
2927             case WEBKIT_LEFT:
2928                 textAnchor = topLeftPoint;
2929                 break;
2930             case RIGHT:
2931             case WEBKIT_RIGHT:
2932                 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
2933                 break;
2934             case TASTART:
2935             case JUSTIFY:
2936             default:
2937                 if (renderer->style()->isLeftToRightDirection())
2938                     textAnchor = topLeftPoint;
2939                 else
2940                     textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
2941                 break;
2942             }
2943             setScrollPosition(textAnchor);
2944         } else {
2945             renderer->style()->isLeftToRightDirection()
2946                 ? setScrollPosition(topLeftPoint)
2947                 : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
2948         }
2949     } else if (willUseTextReflow) {
2950         IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
2951         finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
2952         setScrollPosition(IntPoint(0, finalRect.y() + m_finalAnimationDocumentScrollPositionReflowOffset.y()));
2953         resetBlockZoom();
2954     }
2955 #endif
2956     if (!willUseTextReflow) {
2957         setScrollPosition(anchor);
2958         if (!m_shouldReflowBlock)
2959             resetBlockZoom();
2960     }
2961
2962     notifyTransformChanged();
2963     m_client->scaleChanged();
2964
2965     if (mainFrameView)
2966         mainFrameView->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge);
2967
2968     // FIXME: Do we really need to suspend/resume both backingstore and screen here?
2969     m_backingStore->d->resumeBackingStoreUpdates();
2970     m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit);
2971 }
2972
2973 void WebPage::zoomAnimationFinished(double finalScale, const Platform::FloatPoint& finalDocumentScrollPosition, bool shouldConstrainScrollingToContentEdge)
2974 {
2975     d->zoomAnimationFinished(finalScale, finalDocumentScrollPosition, shouldConstrainScrollingToContentEdge);
2976 }
2977
2978 void WebPage::resetBlockZoom()
2979 {
2980     d->resetBlockZoom();
2981 }
2982
2983 void WebPagePrivate::resetBlockZoom()
2984 {
2985     m_currentBlockZoomNode = 0;
2986     m_currentBlockZoomAdjustedNode = 0;
2987     m_shouldReflowBlock = false;
2988 }
2989
2990 void WebPage::destroyWebPageCompositor()
2991 {
2992 #if USE(ACCELERATED_COMPOSITING)
2993     // Destroy the layer renderer in a sync command before we destroy the backing store,
2994     // to flush any pending compositing messages on the compositing thread.
2995     // The backing store is indirectly deleted by the 'detachFromParent' call below.
2996     d->syncDestroyCompositorOnCompositingThread();
2997 #endif
2998 }
2999
3000 void WebPage::destroy()
3001 {
3002     // TODO: need to verify if this call needs to be made before calling
3003     // Close the Inspector to resume the JS engine if it's paused.
3004     disableWebInspector();
3005
3006     // WebPage::destroyWebPageCompositor()
3007     // FIXME: Do we really need to suspend/resume both backingstore and screen here?
3008     d->m_backingStore->d->suspendBackingStoreUpdates();
3009     d->m_backingStore->d->suspendScreenUpdates();
3010
3011     // Close the backforward list and release the cached pages.
3012     d->m_page->backForward()->close();
3013
3014     FrameLoader* loader = d->m_mainFrame->loader();
3015
3016     // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion.
3017     d->m_mainFrame = 0;
3018     if (loader)
3019         loader->detachFromParent();
3020
3021     deleteGuardedObject(this);
3022 }
3023
3024 WebPageClient* WebPage::client() const
3025 {
3026     return d->m_client;
3027 }
3028
3029 int WebPage::backForwardListLength() const
3030 {
3031     return d->m_page->getHistoryLength();
3032 }
3033
3034 bool WebPage::canGoBackOrForward(int delta) const
3035 {
3036     return d->m_page->canGoBackOrForward(delta);
3037 }
3038
3039 bool WebPage::goBackOrForward(int delta)
3040 {
3041     if (d->m_page->canGoBackOrForward(delta)) {
3042         d->m_userPerformedManualZoom = false;
3043         d->m_userPerformedManualScroll = false;
3044         d->m_backingStore->d->suspendScreenUpdates();
3045         d->m_page->goBackOrForward(delta);
3046         d->m_backingStore->d->resumeScreenUpdates(BackingStore::None);
3047         return true;
3048     }
3049     return false;
3050 }
3051
3052 void WebPage::goToBackForwardEntry(BackForwardId id)
3053 {
3054     HistoryItem* item = historyItemFromBackForwardId(id);
3055     ASSERT(item);
3056     d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
3057 }
3058
3059 void WebPage::reload()
3060 {
3061     d->m_mainFrame->loader()->reload(/* bypassCache */ true);
3062 }
3063
3064 void WebPage::reloadFromCache()
3065 {
3066     d->m_mainFrame->loader()->reload(/* bypassCache */ false);
3067 }
3068
3069 WebSettings* WebPage::settings() const
3070 {
3071     return d->m_webSettings;
3072 }
3073
3074 WebCookieJar* WebPage::cookieJar() const
3075 {
3076     if (!d->m_cookieJar)
3077         d->m_cookieJar = new WebCookieJar();
3078
3079     return d->m_cookieJar;
3080 }
3081
3082 bool WebPage::isLoading() const
3083 {
3084     return d->isLoading();
3085 }
3086
3087 bool WebPage::isVisible() const
3088 {
3089     return d->m_visible;
3090 }
3091
3092 #if ENABLE(PAGE_VISIBILITY_API)
3093 class DeferredTaskSetPageVisibilityState: public DeferredTask<&WebPagePrivate::m_wouldSetPageVisibilityState> {
3094 public:
3095     explicit DeferredTaskSetPageVisibilityState(WebPagePrivate* webPagePrivate)
3096         : DeferredTaskType(webPagePrivate)
3097     {
3098     }
3099 private:
3100     virtual void performInternal(WebPagePrivate* webPagePrivate)
3101     {
3102         webPagePrivate->setPageVisibilityState();
3103     }
3104 };
3105
3106 void WebPagePrivate::setPageVisibilityState()
3107 {
3108     if (m_page->defersLoading())
3109         m_deferredTasks.append(adoptPtr(new DeferredTaskSetPageVisibilityState(this)));
3110     else {
3111         DeferredTaskSetPageVisibilityState::finishOrCancel(this);
3112
3113         static bool s_initialVisibilityState = true;
3114
3115         m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
3116         s_initialVisibilityState = false;
3117     }
3118 }
3119 #endif
3120
3121 void WebPagePrivate::setVisible(bool visible)
3122 {
3123     if (visible != m_visible) {
3124         if (visible) {
3125             if (m_mainFrame)
3126                 m_mainFrame->animation()->resumeAnimations();
3127             if (m_page->scriptedAnimationsSuspended())
3128                 m_page->resumeScriptedAnimations();
3129         } else {
3130             if (m_mainFrame)
3131                 m_mainFrame->animation()->suspendAnimations();
3132             if (!m_page->scriptedAnimationsSuspended())
3133                 m_page->suspendScriptedAnimations();
3134
3135             if (m_webPage->hasOpenedPopup())
3136                 m_page->chrome()->client()->closePagePopup(0);
3137         }
3138
3139         m_visible = visible;
3140         m_backingStore->d->updateSuspendScreenUpdateState();
3141     }
3142
3143 #if ENABLE(PAGE_VISIBILITY_API)
3144     setPageVisibilityState();
3145 #endif
3146 }
3147
3148 void WebPage::setVisible(bool visible)
3149 {
3150     if (d->m_visible == visible)
3151         return;
3152
3153     d->setVisible(visible);
3154     AuthenticationChallengeManager::instance()->pageVisibilityChanged(d, visible);
3155
3156     if (!visible) {
3157         d->suspendBackingStore();
3158
3159         // Remove this WebPage from the visible pages list.
3160         size_t foundIndex = visibleWebPages()->find(this);
3161         if (foundIndex != WTF::notFound)
3162             visibleWebPages()->remove(foundIndex);
3163
3164         // Return the backing store to the last visible WebPage.
3165         if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
3166             visibleWebPages()->last()->d->resumeBackingStore();
3167
3168 #if USE(ACCELERATED_COMPOSITING)
3169         // Root layer commit is not necessary for invisible tabs.
3170         // And release layer resources can reduce memory consumption.
3171         d->suspendRootLayerCommit();
3172 #endif
3173
3174         return;
3175     }
3176
3177 #if USE(ACCELERATED_COMPOSITING)
3178     d->resumeRootLayerCommit();
3179 #endif
3180
3181     // We want to become visible but not get backing store ownership.
3182     if (d->m_backingStore->d->isOpenGLCompositing() && !d->m_webSettings->isBackingStoreEnabled()) {
3183         d->setCompositorDrawsRootLayer(true);
3184 #if USE(ACCELERATED_COMPOSITING)
3185         d->setNeedsOneShotDrawingSynchronization();
3186 #endif
3187         d->setShouldResetTilesWhenShown(true);
3188         return;
3189     }
3190
3191     // Push this WebPage to the top of the visible pages list.
3192     if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
3193         size_t foundIndex = visibleWebPages()->find(this);
3194         if (foundIndex != WTF::notFound)
3195             visibleWebPages()->remove(foundIndex);
3196     }
3197     visibleWebPages()->append(this);
3198
3199     if (BackingStorePrivate::currentBackingStoreOwner()
3200         && BackingStorePrivate::currentBackingStoreOwner() != this)
3201         BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
3202
3203     // resumeBackingStore will set the current owner to this webpage.
3204     // If we set the owner prematurely, then the tiles will not be reset.
3205     d->resumeBackingStore();
3206 }
3207
3208 void WebPagePrivate::selectionChanged(Frame* frame)
3209 {
3210     m_inputHandler->selectionChanged();
3211
3212     // FIXME: This is a hack!
3213     // To ensure the selection being changed has its frame 'focused', lets
3214     // set it as focused ourselves (PR #104724).
3215     m_page->focusController()->setFocusedFrame(frame);
3216 }
3217
3218 void WebPagePrivate::updateSelectionScrollView(const Node* node)
3219 {
3220     m_inRegionScroller->d->updateSelectionScrollView(node);
3221 }
3222
3223 void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
3224 {
3225     // Track a dispatched message, we don't want to flood the webkit thread.
3226     // There can be as many as one more message enqued as needed but never less.
3227     if (dispatched)
3228         m_updateDelegatedOverlaysDispatched = false;
3229     else if (m_updateDelegatedOverlaysDispatched) {
3230         // Early return if there is message already pending on the webkit thread.
3231         return;
3232     }
3233
3234     if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
3235         // Must be called on the WebKit thread.
3236         if (m_selectionHandler->isSelectionActive())
3237             m_selectionHandler->selectionPositionChanged();
3238         if (m_inspectorOverlay)
3239             m_inspectorOverlay->update();
3240
3241     } else if (m_selectionHandler->isSelectionActive()) {
3242         // Don't bother dispatching to webkit thread if selection and tap highlight are not active.
3243         m_updateDelegatedOverlaysDispatched = true;
3244         Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/));
3245     }
3246 }
3247
3248 void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle)
3249 {
3250 }
3251
3252 bool WebPage::setBatchEditingActive(bool active)
3253 {
3254     return d->m_inputHandler->setBatchEditingActive(active);
3255 }
3256
3257 bool WebPage::setInputSelection(unsigned start, unsigned end)
3258 {
3259     if (d->m_page->defersLoading())
3260         return false;
3261     return d->m_inputHandler->setSelection(start, end);
3262 }
3263
3264 int WebPage::inputCaretPosition() const
3265 {
3266     return d->m_inputHandler->caretPosition();
3267 }
3268
3269 class DeferredTaskPopupListSelectMultiple: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectMultiple> {
3270 public:
3271     DeferredTaskPopupListSelectMultiple(WebPagePrivate* webPagePrivate, int size, const bool* selecteds)
3272         : DeferredTaskType(webPagePrivate)
3273     {
3274         webPagePrivate->m_cachedPopupListSelecteds.append(selecteds, size);
3275     }
3276 private:
3277     virtual void performInternal(WebPagePrivate* webPagePrivate)
3278     {
3279         webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelecteds.size(), webPagePrivate->m_cachedPopupListSelecteds.data());
3280     }
3281 };
3282
3283 class DeferredTaskPopupListSelectSingle: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectSingle> {
3284 public:
3285     explicit DeferredTaskPopupListSelectSingle(WebPagePrivate* webPagePrivate, int index)
3286         : DeferredTaskType(webPagePrivate)
3287     {
3288         webPagePrivate->m_cachedPopupListSelectedIndex = index;
3289     }
3290 private:
3291     virtual void performInternal(WebPagePrivate* webPagePrivate)
3292     {
3293         webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelectedIndex);
3294     }
3295 };
3296
3297 void WebPage::popupListClosed(int size, const bool* selecteds)
3298 {
3299     DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3300     if (d->m_page->defersLoading()) {
3301         d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectMultiple(d, size, selecteds)));
3302         return;
3303     }
3304     DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3305     d->m_inputHandler->setPopupListIndexes(size, selecteds);
3306 }
3307
3308 void WebPage::popupListClosed(int index)
3309 {
3310     DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3311     if (d->m_page->defersLoading()) {
3312         d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectSingle(d, index)));
3313         return;
3314     }
3315     DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3316     d->m_inputHandler->setPopupListIndex(index);
3317 }
3318
3319 class DeferredTaskSetDateTimeInput: public DeferredTask<&WebPagePrivate::m_wouldSetDateTimeInput> {
3320 public:
3321     explicit DeferredTaskSetDateTimeInput(WebPagePrivate* webPagePrivate, BlackBerry::Platform::String value)
3322         : DeferredTaskType(webPagePrivate)
3323     {
3324         webPagePrivate->m_cachedDateTimeInput = value;
3325     }
3326 private:
3327     virtual void performInternal(WebPagePrivate* webPagePrivate)
3328     {
3329         webPagePrivate->m_webPage->setDateTimeInput(webPagePrivate->m_cachedDateTimeInput);
3330     }
3331 };
3332
3333 void WebPage::setDateTimeInput(const BlackBerry::Platform::String& value)
3334 {
3335     if (d->m_page->defersLoading()) {
3336         d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetDateTimeInput(d, value)));
3337         return;
3338     }
3339     DeferredTaskSetDateTimeInput::finishOrCancel(d);
3340     d->m_inputHandler->setInputValue(value);
3341 }
3342
3343 class DeferredTaskSetColorInput: public DeferredTask<&WebPagePrivate::m_wouldSetColorInput> {
3344 public:
3345     explicit DeferredTaskSetColorInput(WebPagePrivate* webPagePrivate, BlackBerry::Platform::String value)
3346         : DeferredTaskType(webPagePrivate)
3347     {
3348         webPagePrivate->m_cachedColorInput = value;
3349     }
3350 private:
3351     virtual void performInternal(WebPagePrivate* webPagePrivate)
3352     {
3353         webPagePrivate->m_webPage->setColorInput(webPagePrivate->m_cachedColorInput);
3354     }
3355 };
3356
3357 void WebPage::setColorInput(const BlackBerry::Platform::String& value)
3358 {
3359     if (d->m_page->defersLoading()) {
3360         d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetColorInput(d, value)));
3361         return;
3362     }
3363     DeferredTaskSetColorInput::finishOrCancel(d);
3364     d->m_inputHandler->setInputValue(value);
3365 }
3366
3367 void WebPage::setVirtualViewportSize(const Platform::IntSize& size)
3368 {
3369     d->m_virtualViewportSize = WebCore::IntSize(size);
3370 }
3371
3372 void WebPage::resetVirtualViewportOnCommitted(bool reset)
3373 {
3374     d->m_resetVirtualViewportOnCommitted = reset;
3375 }
3376
3377 Platform::IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments()
3378 {
3379     static const ViewportArguments defaultViewportArguments;
3380     if (m_viewportArguments == defaultViewportArguments)
3381         return IntSize();
3382
3383     int desktopWidth = DEFAULT_MAX_LAYOUT_WIDTH;
3384     int deviceWidth = Platform::Graphics::Screen::primaryScreen()->width();
3385     int deviceHeight = Platform::Graphics::Screen::primaryScreen()->height();
3386     float devicePixelRatio = m_webSettings->devicePixelRatio();
3387     ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, devicePixelRatio, m_defaultLayoutSize);
3388     m_page->setDeviceScaleFactor(devicePixelRatio);
3389
3390     setUserScalable(m_webSettings->isUserScalable() && result.userScalable);
3391     if (result.initialScale > 0)
3392         setInitialScale(result.initialScale * devicePixelRatio);
3393     if (result.minimumScale > 0)
3394         setMinimumScale(result.minimumScale * devicePixelRatio);
3395     if (result.maximumScale > 0)
3396         setMaximumScale(result.maximumScale * devicePixelRatio);
3397
3398     return Platform::IntSize(result.layoutSize.width(), result.layoutSize.height());
3399 }
3400
3401 #if ENABLE(EVENT_MODE_METATAGS)
3402 void WebPagePrivate::didReceiveCursorEventMode(CursorEventMode mode)
3403 {
3404     if (mode != m_cursorEventMode)
3405         m_client->cursorEventModeChanged(toPlatformCursorEventMode(mode));
3406     m_cursorEventMode = mode;
3407 }
3408
3409 void WebPagePrivate::didReceiveTouchEventMode(TouchEventMode mode)
3410 {
3411     if (mode != m_touchEventMode)
3412         m_client->touchEventModeChanged(toPlatformTouchEventMode(mode));
3413     m_touchEventMode = mode;
3414 }
3415 #endif
3416
3417 void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments)
3418 {
3419     if (arguments == m_viewportArguments)
3420         return;
3421
3422     // If the caller is trying to reset to default arguments, use the user supplied ones instead.
3423     static const ViewportArguments defaultViewportArguments;
3424     if (arguments == defaultViewportArguments) {
3425         m_viewportArguments = m_userViewportArguments;
3426         m_forceRespectViewportArguments = m_userViewportArguments != defaultViewportArguments;
3427     } else
3428         m_viewportArguments = arguments;
3429
3430     // 0 width or height in viewport arguments makes no sense, and results in a very large initial scale.
3431     // In real world, a 0 width or height is usually caused by a syntax error in "content" field of viewport
3432     // meta tag, for example, using semicolon instead of comma as separator ("width=device-width; initial-scale=1.0").
3433     // We don't have a plan to tolerate the semicolon separator, but we can avoid applying 0 width/height.
3434     // I default it to ValueDeviceWidth rather than ValueAuto because in more cases the web site wants "device-width"
3435     // when they specify the viewport width.
3436     if (!m_viewportArguments.width)
3437         m_viewportArguments.width = ViewportArguments::ValueDeviceWidth;
3438     if (!m_viewportArguments.height)
3439         m_viewportArguments.height = ViewportArguments::ValueDeviceHeight;
3440
3441     Platform::IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
3442     m_webPage->setVirtualViewportSize(virtualViewport);
3443
3444     // Reset m_userPerformedManualZoom and enable m_shouldZoomToInitialScaleAfterLoadFinished so that we can relayout
3445     // the page and zoom it to fit the screen when we dynamically change the meta viewport after the load is finished.
3446     bool isLoadFinished = loadState() == Finished;
3447     if (isLoadFinished) {
3448         m_userPerformedManualZoom = false;
3449         setShouldZoomToInitialScaleAfterLoadFinished(true);
3450     }
3451     if (loadState() == Committed || isLoadFinished)
3452         zoomToInitialScaleOnLoad();
3453 }
3454
3455 void WebPagePrivate::suspendBackingStore()
3456 {
3457 #if USE(ACCELERATED_COMPOSITING)
3458     if (m_backingStore->d->isOpenGLCompositing()) {
3459         // A visible web page's backing store can be suspended when another web
3460         // page is taking over the backing store.
3461         if (m_visible)
3462             setCompositorDrawsRootLayer(true);
3463
3464         return;
3465     }
3466 #endif
3467 }
3468
3469 void WebPagePrivate::resumeBackingStore()
3470 {
3471     ASSERT(m_webPage->isVisible());
3472
3473     if (!m_backingStore->d->isActive() || shouldResetTilesWhenShown()) {
3474         BackingStorePrivate::setCurrentBackingStoreOwner(m_webPage);
3475
3476         // If we're OpenGL compositing, switching to accel comp drawing of the root layer
3477         // is a good substitute for backingstore blitting.
3478         if (m_backingStore->d->isOpenGLCompositing())
3479             setCompositorDrawsRootLayer(!m_backingStore->d->isActive());
3480
3481         m_backingStore->d->orientationChanged(); // Updates tile geometry and creates visible tile buffer.
3482         m_backingStore->d->resetTiles();
3483         m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
3484
3485 #if USE(ACCELERATED_COMPOSITING)
3486         setNeedsOneShotDrawingSynchronization();
3487 #endif
3488
3489         m_backingStore->d->renderAndBlitVisibleContentsImmediately();
3490     } else {
3491         if (m_backingStore->d->isOpenGLCompositing())
3492             setCompositorDrawsRootLayer(false);
3493
3494         // Rendering was disabled while we were hidden, so we need to update all tiles.
3495         m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
3496 #if USE(ACCELERATED_COMPOSITING)
3497         setNeedsOneShotDrawingSynchronization();
3498 #endif
3499     }
3500
3501     setShouldResetTilesWhenShown(false);
3502 }
3503
3504 void WebPagePrivate::setScreenOrientation(int orientation)
3505 {
3506     FOR_EACH_PLUGINVIEW(m_pluginViews)
3507         (*it)->handleOrientationEvent(orientation);
3508
3509     m_pendingOrientation = -1;
3510
3511 #if ENABLE(ORIENTATION_EVENTS)
3512     if (m_mainFrame->orientation() == orientation)
3513         return;
3514     for (RefPtr<Frame> frame = m_mainFrame; frame; frame = frame->tree()->traverseNext())
3515         frame->sendOrientationChangeEvent(orientation);
3516 #endif
3517 }
3518
3519 void WebPage::setScreenOrientation(int orientation)
3520 {
3521     d->m_pendingOrientation = orientation;
3522 }
3523
3524 void WebPage::applyPendingOrientationIfNeeded()
3525 {
3526     if (d->m_pendingOrientation != -1)
3527         d->setScreenOrientation(d->m_pendingOrientation);
3528
3529     // After rotation, we should redraw the dialog box instead of just moving it since rotation dismisses all dialogs.
3530     d->m_inputHandler->redrawSpellCheckDialogIfRequired(false /* shouldMoveDialog */);
3531 }
3532
3533 bool WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize, const IntSize& defaultLayoutSize, bool ensureFocusElementVisible)
3534 {
3535     if (m_pendingOrientation == -1 && transformedActualVisibleSize == this->transformedActualVisibleSize())
3536         return false;
3537
3538     // Suspend all screen updates to the backingstore to make sure no-one tries to blit
3539     // while the window surface and the BackingStore are out of sync.
3540     BackingStore::ResumeUpdateOperation screenResumeOperation = BackingStore::Blit;
3541     m_backingStore->d->suspendScreenUpdates();
3542     m_backingStore->d->suspendBackingStoreUpdates();
3543
3544     // The screen rotation is a major state transition that in this case is not properly
3545     // communicated to the backing store, since it does early return in most methods when
3546     // not visible.
3547     if (!m_visible || !m_backingStore->d->isActive())
3548         setShouldResetTilesWhenShown(true);
3549
3550     bool hasPendingOrientation = m_pendingOrientation != -1;
3551
3552     IntSize viewportSizeBefore = actualVisibleSize();
3553     FloatPoint centerOfVisibleContentsRect = this->centerOfVisibleContentsRect();
3554     bool newVisibleRectContainsOldVisibleRect = (m_actualVisibleHeight <= transformedActualVisibleSize.height())
3555         && (m_actualVisibleWidth <= transformedActualVisibleSize.width());
3556
3557     bool atInitialScale = m_webPage->isAtInitialZoom();
3558     bool atTop = !scrollPosition().y();
3559     bool atLeft = !scrollPosition().x();
3560
3561     setDefaultLayoutSize(defaultLayoutSize);
3562
3563     // Recompute our virtual viewport.
3564     bool needsLayout = false;
3565     Platform::IntSize newVirtualViewport = recomputeVirtualViewportFromViewportArguments();
3566     if (!newVirtualViewport.isEmpty()) {
3567         m_webPage->setVirtualViewportSize(newVirtualViewport);
3568         m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
3569         m_mainFrame->view()->setFixedLayoutSize(fixedLayoutSize());
3570         needsLayout = true;
3571     }
3572
3573     // We switch this strictly after recomputing our virtual viewport as zoomToFitScale is dependent
3574     // upon these values and so is the virtual viewport recalculation.
3575     m_actualVisibleWidth = transformedActualVisibleSize.width();
3576     m_actualVisibleHeight = transformedActualVisibleSize.height();
3577
3578     IntSize viewportSizeAfter = actualVisibleSize();
3579
3580     IntSize offset;
3581     if (hasPendingOrientation && !m_fullscreenNode) {
3582         offset = IntSize(roundf((viewportSizeBefore.width() - viewportSizeAfter.width()) / 2.0),
3583             roundf((viewportSizeBefore.height() - viewportSizeAfter.height()) / 2.0));
3584     }
3585
3586     // As a special case, if we were anchored to the top left position at
3587     // the beginning of the rotation then preserve that anchor.
3588     if (atTop)
3589         offset.setHeight(0);
3590     if (atLeft)
3591         offset.setWidth(0);
3592
3593     // If we're about to overscroll, cap the offset to valid content.
3594     IntPoint bottomRight(
3595         scrollPosition().x() + viewportSizeAfter.width(),
3596         scrollPosition().y() + viewportSizeAfter.height());
3597
3598     if (bottomRight.x() + offset.width() > contentsSize().width())
3599         offset.setWidth(contentsSize().width() - bottomRight.x());
3600     if (bottomRight.y() + offset.height() > contentsSize().height())
3601         offset.setHeight(contentsSize().height() - bottomRight.y());
3602     if (scrollPosition().x() + offset.width() < 0)
3603         offset.setWidth(-scrollPosition().x());
3604     if (scrollPosition().y() + offset.height() < 0)
3605         offset.setHeight(-scrollPosition().y());
3606
3607     // ...before scrolling, because the backing store will align its
3608     // tile matrix with the viewport as reported by the ScrollView.
3609     setScrollPosition(scrollPosition() + offset);
3610     notifyTransformedScrollChanged();
3611
3612     m_backingStore->d->orientationChanged();
3613     m_backingStore->d->actualVisibleSizeChanged(transformedActualVisibleSize);
3614
3615     // Update view mode only after we have updated the actual
3616     // visible size and reset the contents rect if necessary.
3617     if (setViewMode(viewMode()))
3618         needsLayout = true;
3619
3620     bool needsLayoutToFindContentSize = hasPendingOrientation;
3621
3622     // We need to update the viewport size of the WebCore::ScrollView...
3623     updateViewportSize(!needsLayoutToFindContentSize /* setFixedReportedSize */, false /* sendResizeEvent */);
3624     notifyTransformedContentsSizeChanged();
3625
3626     // If automatic zooming is disabled, prevent zooming below.
3627     if (!m_webSettings->isZoomToFitOnLoad()) {
3628         atInitialScale = false;
3629
3630         // Normally, if the contents size is smaller than the layout width,
3631         // we would zoom in. If zoom is disabled, we need to do something else,
3632         // or there will be artifacts due to non-rendered areas outside of the
3633         // contents size. If there is a virtual viewport, we are not allowed
3634         // to modify the fixed layout size, however.
3635         if (!hasVirtualViewport() && contentsSize().width() < m_defaultLayoutSize.width()) {
3636             m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
3637             m_mainFrame->view()->setFixedLayoutSize(m_defaultLayoutSize);
3638             needsLayout = true;
3639         }
3640     }
3641
3642     // Need to resume so that the backingstore will start recording the invalidated
3643     // rects from below.
3644     m_backingStore->d->resumeBackingStoreUpdates();
3645
3646     // We might need to layout here to get a correct contentsSize so that zoomToFit
3647     // is calculated correctly.
3648     bool stillNeedsLayout = needsLayout;
3649     while (stillNeedsLayout) {
3650         setNeedsLayout();
3651         requestLayoutIfNeeded();
3652         stillNeedsLayout = false;
3653
3654         // Emulate the zoomToFitWidthOnLoad algorithm if we're rotating.
3655         ++m_nestedLayoutFinishedCount;
3656         if (needsLayoutToFindContentSize) {
3657             if (setViewMode(viewMode()))
3658                 stillNeedsLayout = true;
3659         }
3660     }
3661     m_nestedLayoutFinishedCount = 0;
3662
3663     // As a special case if we were zoomed to the initial scale at the beginning
3664     // of the rotation then preserve that zoom level even when it is zoomToFit.
3665     double scale = atInitialScale ? initialScale() : currentScale();
3666
3667     // Do our own clamping.
3668     scale = clampedScale(scale);
3669
3670     if (needsLayoutToFindContentSize) {
3671         // Set the fixed reported size here so that innerWidth|innerHeight works
3672         // with this new scale.
3673         TransformationMatrix rotationMatrix;
3674         rotationMatrix.scale(scale);
3675         IntRect viewportRect = IntRect(IntPoint::zero(), transformedActualVisibleSize);
3676         IntRect actualVisibleRect = enclosingIntRect(rotationMatrix.inverse().mapRect(FloatRect(viewportRect)));
3677         m_mainFrame->view()->setFixedReportedSize(actualVisibleRect.size());
3678         m_mainFrame->view()->repaintFixedElementsAfterScrolling();
3679         requestLayoutIfNeeded();
3680         m_mainFrame->view()->updateFixedElementsAfterScrolling();
3681     }
3682
3683     // We're going to need to send a resize event to JavaScript because
3684     // innerWidth and innerHeight depend on fixed reported size.
3685     // This is how we support mobile pages where JavaScript resizes
3686     // the page in order to get around the fixed layout size, e.g.
3687     // google maps when it detects a mobile user agent.
3688     if (shouldSendResizeEvent())
3689         m_mainFrame->eventHandler()->sendResizeEvent();
3690
3691     // As a special case if we were anchored to the top left position at the beginning
3692     // of the rotation then preserve that anchor.
3693     FloatPoint anchor = centerOfVisibleContentsRect;
3694     if (atTop)
3695         anchor.setY(0);
3696     if (atLeft)
3697         anchor.setX(0);
3698
3699     // Try and zoom here with clamping on.
3700     // FIXME: Determine why the above comment says "clamping on", yet we
3701     //   don't set enforceScaleClamping to true.
3702     if (zoomAboutPoint(scale, anchor, false /*enforceScaleClamping*/, true /*forceRendering*/)) {
3703         if (ensureFocusElementVisible)
3704             ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3705     } else {
3706         // Suspend all updates to the backingstore.
3707         m_backingStore->d->suspendBackingStoreUpdates();
3708
3709         // If the zoom failed, then we should still preserve the special case of scroll position.
3710         IntPoint scrollPosition = this->scrollPosition();
3711         if (atTop)
3712             scrollPosition.setY(0);
3713         if (atLeft)
3714             scrollPosition.setX(0);
3715         setScrollPosition(scrollPosition);
3716
3717         // These might have been altered even if we didn't zoom so notify the client.
3718         notifyTransformedContentsSizeChanged();
3719         notifyTransformedScrollChanged();
3720
3721         if (!needsLayout) {
3722             // The visible tiles for scroll must be up-to-date before we blit since we are not performing a layout.
3723             m_backingStore->d->updateTilesForScrollOrNotRenderedRegion();
3724         }
3725
3726         if (ensureFocusElementVisible)
3727             ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3728
3729         if (needsLayout) {
3730             m_backingStore->d->resetTiles();
3731             m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
3732             screenResumeOperation = BackingStore::RenderAndBlit;
3733         }
3734
3735         // If we need layout then render and blit, otherwise just blit as our viewport has changed.
3736         m_backingStore->d->resumeBackingStoreUpdates();
3737     }
3738
3739 #if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
3740     // When leaving fullscreen mode, restore the scale and scroll position if needed.
3741     // We also need to make sure the scale and scroll position won't cause over scale or over scroll.
3742     if (m_scaleBeforeFullScreen > 0 && !m_fullscreenNode) {
3743         // Restore the scale when leaving fullscreen. We can't use TransformationMatrix::scale(double) here,
3744         // as it will multiply the scale rather than set the scale.
3745         // FIXME: We can refactor this into setCurrentScale(double) if it is useful in the future.
3746         if (m_orientationBeforeFullScreen % 180 != orientation() % 180) { // Orientation changed
3747             if (m_actualVisibleWidth > contentsSize().width() * m_scaleBeforeFullScreen) {
3748                 // Cached scale need to be adjusted after rotation.
3749                 m_scaleBeforeFullScreen = double(m_actualVisibleWidth) / contentsSize().width();
3750             }
3751             if (m_scaleBeforeFullScreen * contentsSize().height() < m_actualVisibleHeight) {
3752                 // Use zoom to fit height scale in order to cover the screen height.
3753                 m_scaleBeforeFullScreen = double(m_actualVisibleHeight) / contentsSize().height();
3754             }
3755
3756             if (m_actualVisibleWidth > m_scaleBeforeFullScreen * (contentsSize().width() - m_scrollPositionBeforeFullScreen.x())) {
3757                 // Cached scroll position over scrolls horizontally after rotation.
3758                 m_scrollPositionBeforeFullScreen.setX(contentsSize().width() - m_actualVisibleWidth / m_scaleBeforeFullScreen);
3759             }
3760             if (m_actualVisibleHeight > m_scaleBeforeFullScreen * (contentsSize().height() - m_scrollPositionBeforeFullScreen.y())) {
3761                 // Cached scroll position over scrolls vertically after rotation.
3762                 m_scrollPositionBeforeFullScreen.setY(contentsSize().height() - m_actualVisibleHeight / m_scaleBeforeFullScreen);
3763             }
3764         }
3765
3766         m_transformationMatrix->setM11(m_scaleBeforeFullScreen);
3767         m_transformationMatrix->setM22(m_scaleBeforeFullScreen);
3768         m_scaleBeforeFullScreen = -1.0;
3769
3770         setScrollPosition(m_scrollPositionBeforeFullScreen);
3771         notifyTransformChanged();
3772         m_client->scaleChanged();
3773     }
3774 #endif
3775
3776     m_backingStore->d->resumeScreenUpdates(screenResumeOperation);
3777     m_inputHandler->redrawSpellCheckDialogIfRequired();
3778
3779     return true;
3780 }
3781
3782 void WebPage::setViewportSize(const Platform::IntSize& viewportSize, const Platform::IntSize& defaultLayoutSize, bool ensureFocusElementVisible)
3783 {
3784     if (!d->setViewportSize(viewportSize, defaultLayoutSize, ensureFocusElementVisible)) {
3785         // If the viewport didn't change, try to apply only the new default layout size.
3786         setDefaultLayoutSize(defaultLayoutSize);
3787     }
3788 }
3789
3790 void WebPagePrivate::setDefaultLayoutSize(const IntSize& size)
3791 {
3792     IntSize screenSize = Platform::Settings::instance()->applicationSize();
3793     ASSERT(size.width() <= screenSize.width() && size.height() <= screenSize.height());
3794     m_defaultLayoutSize = size.expandedTo(minimumLayoutSize).shrunkTo(screenSize);
3795 }
3796
3797 Platform::IntSize WebPage::defaultLayoutSize() const
3798 {
3799     return d->m_defaultLayoutSize;
3800 }
3801
3802 void WebPage::setDefaultLayoutSize(const Platform::IntSize& platformSize)
3803 {
3804     bool needsLayout = false;
3805     WebCore::IntSize size = platformSize;
3806     if (size == d->m_defaultLayoutSize)
3807         return;
3808
3809     d->setDefaultLayoutSize(size);
3810
3811     // The default layout size affects interpretation of any viewport arguments present.
3812     Platform::IntSize virtualViewportSize = d->recomputeVirtualViewportFromViewportArguments();
3813     if (!virtualViewportSize.isEmpty()) {
3814         setVirtualViewportSize(virtualViewportSize);
3815         needsLayout = true;
3816     }
3817
3818     if (d->setViewMode(d->viewMode()))
3819         needsLayout = true;
3820
3821     if (needsLayout) {
3822         d->setNeedsLayout();
3823         if (!d->isLoading())
3824             d->requestLayoutIfNeeded();
3825     }
3826 }
3827
3828 bool WebPage::mouseEvent(const Platform::MouseEvent& mouseEvent, bool* wheelDeltaAccepted)
3829 {
3830     if (!d->m_mainFrame->view())
3831         return false;
3832
3833     if (d->m_page->defersLoading())
3834         return false;
3835
3836     PluginView* pluginView = d->m_fullScreenPluginView.get();
3837     if (pluginView)
3838         return d->dispatchMouseEventToFullScreenPlugin(pluginView, mouseEvent);
3839
3840     if (mouseEvent.type() == Platform::MouseEvent::MouseAborted) {
3841         d->m_mainFrame->eventHandler()->setMousePressed(false);
3842         return false;
3843     }
3844
3845     d->m_pluginMayOpenNewTab = true;
3846
3847     d->m_lastUserEventTimestamp = currentTime();
3848     int clickCount = (d->m_selectionHandler->isSelectionActive() || mouseEvent.type() != Platform::MouseEvent::MouseMove) ? 1 : 0;
3849
3850     // Set the button type.
3851     MouseButton buttonType = NoButton;
3852     if (mouseEvent.isLeftButton())
3853         buttonType = LeftButton;
3854     else if (mouseEvent.isRightButton())
3855         buttonType = RightButton;
3856     else if (mouseEvent.isMiddleButton())
3857         buttonType = MiddleButton;
3858
3859     // Create our event.
3860     PlatformMouseEvent platformMouseEvent(mouseEvent.documentViewportPosition(), mouseEvent.screenPosition(),
3861         toWebCoreMouseEventType(mouseEvent.type()), clickCount, buttonType,
3862         mouseEvent.shiftActive(), mouseEvent.ctrlActive(), mouseEvent.altActive(), PointingDevice);
3863     d->m_lastMouseEvent = platformMouseEvent;
3864     bool success = d->handleMouseEvent(platformMouseEvent);
3865
3866     if (mouseEvent.wheelTicks()) {
3867         PlatformWheelEvent wheelEvent(mouseEvent.documentViewportPosition(), mouseEvent.screenPosition(),
3868             0, -mouseEvent.wheelDelta(),
3869             0, -mouseEvent.wheelTicks(),
3870             ScrollByPixelWheelEvent,
3871             mouseEvent.shiftActive(), mouseEvent.ctrlActive(),
3872             mouseEvent.altActive(), false /* metaKey */);
3873         if (wheelDeltaAccepted)
3874             *wheelDeltaAccepted = d->handleWheelEvent(wheelEvent);
3875     } else if (wheelDeltaAccepted)
3876         *wheelDeltaAccepted = false;
3877
3878     return success;
3879 }
3880
3881 bool WebPagePrivate::dispatchMouseEventToFullScreenPlugin(PluginView* plugin, const Platform::MouseEvent& event)
3882 {
3883     NPEvent npEvent;
3884     NPMouseEvent mouseEvent;
3885
3886     mouseEvent.x = event.screenPosition().x();
3887     mouseEvent.y = event.screenPosition().y();
3888
3889     switch (event.type()) {
3890     case Platform::MouseEvent::MouseButtonDown:
3891         mouseEvent.type = MOUSE_BUTTON_DOWN;
3892         m_pluginMouseButtonPressed = true;
3893         break;
3894     case Platform::MouseEvent::MouseButtonUp:
3895         mouseEvent.type = MOUSE_BUTTON_UP;
3896         m_pluginMouseButtonPressed = false;
3897         break;
3898     case Platform::MouseEvent::MouseMove:
3899         mouseEvent.type = MOUSE_MOTION;
3900         break;
3901     default:
3902         return false;
3903     }
3904
3905     mouseEvent.flags = 0;
3906     mouseEvent.button = m_pluginMouseButtonPressed;
3907
3908     npEvent.type = NP_MouseEvent;
3909     npEvent.data = &mouseEvent;
3910
3911     return plugin->dispatchFullScreenNPEvent(npEvent);
3912 }
3913
3914 bool WebPagePrivate::handleMouseEvent(PlatformMouseEvent& mouseEvent)
3915 {
3916     EventHandler* eventHandler = m_mainFrame->eventHandler();
3917
3918     if (mouseEvent.type() == WebCore::PlatformEvent::MouseMoved)
3919         return eventHandler->mouseMoved(mouseEvent);
3920
3921     if (mouseEvent.type() == WebCore::PlatformEvent::MouseScroll)
3922         return true;
3923
3924     Node* node = 0;
3925     if (mouseEvent.inputMethod() == TouchScreen) {
3926         const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
3927
3928         // Fat fingers can deal with shadow content.
3929         node = lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
3930
3931         // Save mouse event state for later. This allows us to know why some responses have occurred, namely selection changes.
3932         m_touchEventHandler->m_userTriggeredTouchPressOnTextInput = mouseEvent.type() == WebCore::PlatformEvent::MousePressed && lastFatFingersResult.isTextInput();
3933     }
3934
3935     if (!node) {
3936         IntPoint documentContentsPoint = m_webkitThreadViewportAccessor->documentContentsFromViewport(mouseEvent.position());
3937         HitTestResult result = eventHandler->hitTestResultAtPoint(documentContentsPoint);
3938         node = result.innerNode();
3939     }
3940
3941     if (mouseEvent.type() == WebCore::PlatformEvent::MousePressed) {
3942         m_inputHandler->setInputModeEnabled();
3943         if (m_inputHandler->willOpenPopupForNode(node)) {
3944             // Do not allow any human generated mouse or keyboard events to select <option>s in the list box
3945             // because we use a pop up dialog to handle the actual selections. This prevents options from
3946             // being selected prior to displaying the pop up dialog. The contents of the listbox are for
3947             // display only.
3948             //
3949             // FIXME: We explicitly do not forward this event to WebCore so as to preserve symmetry with
3950             // the MouseEventReleased handling (below). This has the side-effect that mousedown events
3951             // are not fired for human generated mouse press events. See RIM Bug #1579.
3952
3953             // We do focus <select>/<option> on mouse down so that a Focus event is fired and have the
3954             // element painted in its focus state on repaint.
3955             ASSERT_WITH_SECURITY_IMPLICATION(node->isElementNode());
3956             if (node->isElementNode()) {
3957                 Element* element = toElement(node);
3958                 element->focus();
3959             }
3960         } else
3961             eventHandler->handleMousePressEvent(mouseEvent);
3962     } else if (mouseEvent.type() == WebCore::PlatformEvent::MouseReleased) {
3963         // FIXME: For <select> and <options> elements, we explicitly do not forward this event to WebCore so
3964         // as to preserve symmetry with the MouseEventPressed handling (above). This has the side-effect that
3965         // mouseup events are not fired on such elements for human generated mouse release events. See RIM Bug #1579.
3966         if (!m_inputHandler->didNodeOpenPopup(node))
3967             eventHandler->handleMouseReleaseEvent(mouseEvent);
3968     }
3969
3970     return true;
3971 }
3972
3973 bool WebPagePrivate::handleWheelEvent(PlatformWheelEvent& wheelEvent)
3974 {
3975     return m_mainFrame->eventHandler()->handleWheelEvent(wheelEvent);
3976 }
3977
3978 bool WebPage::touchEvent(const Platform::TouchEvent& event)
3979 {
3980 #if DEBUG_TOUCH_EVENTS
3981     Platform::logAlways(Platform::LogLevelCritical, "%s", event.toString().c_str());
3982 #endif
3983
3984 #if ENABLE(TOUCH_EVENTS)
3985     if (!d->m_mainFrame)
3986         return false;
3987
3988     if (d->m_page->defersLoading())
3989         return false;
3990
3991     if (d->m_inputHandler)
3992         d->m_inputHandler->setInputModeEnabled();
3993
3994     PluginView* pluginView = d->m_fullScreenPluginView.get();
3995     if (pluginView)
3996         return d->dispatchTouchEventToFullScreenPlugin(pluginView, event);
3997
3998     Platform::TouchEvent tEvent = event;
3999     if (event.isSingleTap())
4000         d->m_pluginMayOpenNewTab = true;
4001     else if (tEvent.m_type == Platform::TouchEvent::TouchStart || tEvent.m_type == Platform::TouchEvent::TouchCancel)
4002         d->m_pluginMayOpenNewTab = false;
4003
4004     if (tEvent.m_type == Platform::TouchEvent::TouchStart) {
4005         d->clearCachedHitTestResult();
4006         d->m_touchEventHandler->doFatFingers(tEvent.m_points[0]);
4007
4008         // Draw tap highlight as soon as possible if we can
4009         Element* elementUnderFatFinger = d->m_touchEventHandler->lastFatFingersResult().nodeAsElementIfApplicable();
4010         if (elementUnderFatFinger)
4011             d->m_touchEventHandler->drawTapHighlight();
4012     }
4013
4014     if (event.isTouchHold())
4015         d->m_touchEventHandler->handleTouchHold();
4016
4017     bool handled = false;
4018
4019     if (event.m_type != Platform::TouchEvent::TouchInjected)
4020         handled = d->m_mainFrame->eventHandler()->handleTouchEvent(PlatformTouchEvent(&tEvent));
4021
4022     if (d->m_preventDefaultOnTouchStart) {
4023         if (tEvent.m_type == Platform::TouchEvent::TouchEnd || tEvent.m_type == Platform::TouchEvent::TouchCancel)
4024             d->m_preventDefaultOnTouchStart = false;
4025         return true;
4026     }
4027
4028     if (handled) {
4029         if (tEvent.m_type == Platform::TouchEvent::TouchStart)
4030             d->m_preventDefaultOnTouchStart = true;
4031         return true;
4032     }
4033 #endif
4034
4035     return false;
4036 }
4037
4038 void WebPagePrivate::setScrollOriginPoint(const Platform::IntPoint& documentScrollOrigin)
4039 {
4040     m_inRegionScroller->d->reset();
4041
4042     if (!m_hasInRegionScrollableAreas)
4043         return;
4044
4045     postponeDocumentStyleRecalc();
4046     m_inRegionScroller->d->calculateInRegionScrollableAreasForPoint(documentScrollOrigin);
4047     if (!m_inRegionScroller->d->activeInRegionScrollableAreas().empty())
4048         m_client->notifyInRegionScrollableAreasChanged(m_inRegionScroller->d->activeInRegionScrollableAreas());
4049     resumeDocumentStyleRecalc();
4050 }
4051
4052 void WebPage::setDocumentScrollOriginPoint(const Platform::IntPoint& documentScrollOrigin)
4053 {
4054     d->setScrollOriginPoint(documentScrollOrigin);
4055 }
4056
4057 void WebPage::touchPointAsMouseEvent(const Platform::TouchPoint& point, unsigned modifiers)
4058 {
4059     if (d->m_page->defersLoading())
4060         return;
4061
4062     if (d->m_fullScreenPluginView.get())
4063         return;
4064
4065     d->m_lastUserEventTimestamp = currentTime();
4066
4067     d->m_touchEventHandler->handleTouchPoint(point, modifiers);
4068 }
4069
4070 void WebPage::playSoundIfAnchorIsTarget() const
4071 {
4072     d->m_touchEventHandler->playSoundIfAnchorIsTarget();
4073 }
4074
4075 bool WebPagePrivate::dispatchTouchEventToFullScreenPlugin(PluginView* plugin, const Platform::TouchEvent& event)
4076 {
4077     // Always convert touch events to mouse events.
4078     // Don't send actual touch events because no one has ever implemented them in flash.
4079     if (!event.neverHadMultiTouch())
4080         return false;
4081
4082     if (event.isDoubleTap() || event.isTouchHold() || event.m_type == Platform::TouchEvent::TouchCancel) {
4083         NPTouchEvent npTouchEvent;
4084
4085         if (event.isDoubleTap())
4086             npTouchEvent.type = TOUCH_EVENT_DOUBLETAP;
4087         else if (event.isTouchHold())
4088             npTouchEvent.type = TOUCH_EVENT_TOUCHHOLD;
4089         else if (event.m_type == Platform::TouchEvent::TouchCancel)
40