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