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