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