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