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