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