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