2 * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
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.
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.
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
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"
29 #include "CachedImage.h"
31 #include "ChromeClientBlackBerry.h"
32 #include "ContextMenuClientBlackBerry.h"
33 #include "CookieManager.h"
34 #include "CredentialManager.h"
35 #include "CredentialTransformData.h"
36 #include "DOMSupport.h"
38 #include "DatabaseSync.h"
39 #include "DatabaseTracker.h"
40 #include "DeviceMotionClientBlackBerry.h"
41 #include "DeviceOrientationClientBlackBerry.h"
42 #include "DragClientBlackBerry.h"
43 // FIXME: We should be using DumpRenderTreeClient, but I'm not sure where we should
44 // create the DRT_BB object. See PR #120355.
46 #include "DumpRenderTreeBlackBerry.h"
48 #include "EditorClientBlackBerry.h"
49 #include "FocusController.h"
50 #include "FrameLoaderClientBlackBerry.h"
52 #include "GeolocationClientMock.h"
54 #include "GeolocationControllerClientBlackBerry.h"
55 #include "GroupSettings.h"
56 #include "HTMLAreaElement.h"
57 #include "HTMLFrameOwnerElement.h"
58 #include "HTMLImageElement.h"
59 #include "HTMLInputElement.h"
60 #include "HTMLMediaElement.h"
61 #include "HTMLNames.h"
62 #include "HTMLParserIdioms.h"
63 #include "HTTPParsers.h"
64 #include "HistoryItem.h"
65 #include "IconDatabaseClientBlackBerry.h"
66 #include "InPageSearchManager.h"
67 #include "InRegionScrollableArea.h"
68 #include "InputHandler.h"
69 #include "InspectorBackendDispatcher.h"
70 #include "InspectorClientBlackBerry.h"
71 #include "InspectorController.h"
72 #include "JavaScriptDebuggerBlackBerry.h"
73 #include "LayerWebKitThread.h"
74 #include "NetworkManager.h"
75 #include "NodeRenderStyle.h"
76 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
77 #include "NotificationPresenterImpl.h"
80 #include "PageCache.h"
81 #include "PageGroup.h"
82 #include "PlatformTouchEvent.h"
83 #include "PlatformWheelEvent.h"
84 #include "PluginDatabase.h"
85 #include "PluginView.h"
86 #include "RenderText.h"
87 #include "RenderThemeBlackBerry.h"
88 #include "RenderTreeAsText.h"
89 #include "RenderView.h"
90 #include "RenderWidget.h"
91 #include "ScriptSourceCode.h"
92 #include "ScriptValue.h"
93 #include "ScrollTypes.h"
94 #include "SelectionHandler.h"
97 #include "StorageNamespace.h"
98 #include "SurfacePool.h"
100 #include "ThreadCheck.h"
101 #include "TouchEventHandler.h"
102 #include "TransformationMatrix.h"
103 #include "VisiblePosition.h"
105 #include "WebDOMDocument.h"
107 #include "WebKitVersion.h"
108 #include "WebPageClient.h"
109 #include "WebSocket.h"
111 #include "runtime_root.h"
114 #include "HTMLMediaElement.h"
115 #include "MediaPlayer.h"
116 #include "MediaPlayerPrivateBlackBerry.h"
120 #include "PlatformContextSkia.h"
123 #if USE(ACCELERATED_COMPOSITING)
124 #include "FrameLayers.h"
125 #include "WebPageCompositor_p.h"
128 #include <BlackBerryPlatformDeviceInfo.h>
129 #include <BlackBerryPlatformExecutableMessage.h>
130 #include <BlackBerryPlatformITPolicy.h>
131 #include <BlackBerryPlatformKeyboardEvent.h>
132 #include <BlackBerryPlatformMessageClient.h>
133 #include <BlackBerryPlatformMouseEvent.h>
134 #include <BlackBerryPlatformScreen.h>
135 #include <BlackBerryPlatformSettings.h>
136 #include <JavaScriptCore/APICast.h>
137 #include <JavaScriptCore/JSContextRef.h>
138 #include <SharedPointer.h>
139 #include <sys/keycodes.h>
140 #include <unicode/ustring.h> // platform ICU
142 #ifndef USER_PROCESSES
143 #include <memalloc.h>
146 #if ENABLE(ACCELERATED_2D_CANVAS)
147 #include "SharedGraphicsContext3D.h"
148 #include "GrContext.h"
151 #if ENABLE(REQUEST_ANIMATION_FRAME)
152 #include "PlatformScreen.h"
155 #define DEBUG_BLOCK_ZOOM 0
156 #define DEBUG_TOUCH_EVENTS 0
157 #define DEBUG_WEBPAGE_LOAD 0
160 using namespace WebCore;
162 typedef const unsigned short* CUShortPtr;
164 namespace BlackBerry {
167 static Vector<WebPage*>* visibleWebPages()
169 static Vector<WebPage*>* s_visibleWebPages = 0; // Initially, no web page is visible.
170 if (!s_visibleWebPages)
171 s_visibleWebPages = new Vector<WebPage*>;
172 return s_visibleWebPages;
175 const unsigned blockZoomMargin = 3; // Add 3 pixel margin on each side.
176 static int blockClickRadius = 0;
177 static double maximumBlockZoomScale = 3; // This scale can be clamped by the maximumScale set for the page.
179 const double manualScrollInterval = 0.1; // The time interval during which we associate user action with scrolling.
181 const double delayedZoomInterval = 0;
183 const IntSize minimumLayoutSize(10, 10); // Needs to be a small size, greater than 0, that we can grow the layout from.
184 const IntSize maximumLayoutSize(10000, 10000); // Used with viewport meta tag, but we can still grow from this of course.
186 const double minimumExpandingRatio = 0.15;
188 // Helper function to parse a URL and fill in missing parts.
189 static KURL parseUrl(const String& url)
191 String urlString(url);
192 KURL kurl = KURL(KURL(), urlString);
193 if (kurl.protocol().isEmpty()) {
194 urlString.insert("http://", 0);
195 kurl = KURL(KURL(), urlString);
201 // Helper functions to convert to and from WebCore types.
202 static inline WebCore::PlatformEvent::Type toWebCoreMouseEventType(const BlackBerry::Platform::MouseEvent::Type type)
205 case BlackBerry::Platform::MouseEvent::MouseButtonDown:
206 return WebCore::PlatformEvent::MousePressed;
207 case Platform::MouseEvent::MouseButtonUp:
208 return WebCore::PlatformEvent::MouseReleased;
209 case Platform::MouseEvent::MouseMove:
211 return WebCore::PlatformEvent::MouseMoved;
215 static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy)
218 case Platform::NetworkRequest::UseProtocolCachePolicy:
219 return UseProtocolCachePolicy;
220 case Platform::NetworkRequest::ReloadIgnoringCacheData:
221 return ReloadIgnoringCacheData;
222 case Platform::NetworkRequest::ReturnCacheDataElseLoad:
223 return ReturnCacheDataElseLoad;
224 case Platform::NetworkRequest::ReturnCacheDataDontLoad:
225 return ReturnCacheDataDontLoad;
227 ASSERT_NOT_REACHED();
228 return UseProtocolCachePolicy;
232 #if ENABLE(EVENT_MODE_METATAGS)
233 static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode)
236 case ProcessedCursorEvents:
237 return Platform::ProcessedCursorEvents;
238 case NativeCursorEvents:
239 return Platform::NativeCursorEvents;
241 ASSERT_NOT_REACHED();
242 return Platform::ProcessedCursorEvents;
246 static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode)
249 case ProcessedTouchEvents:
250 return Platform::ProcessedTouchEvents;
251 case NativeTouchEvents:
252 return Platform::NativeTouchEvents;
253 case PureTouchEventsWithMouseConversion:
254 return Platform::PureTouchEventsWithMouseConversion;
256 ASSERT_NOT_REACHED();
257 return Platform::ProcessedTouchEvents;
262 static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id)
264 return reinterpret_cast<HistoryItem*>(id);
267 static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item)
269 return reinterpret_cast<WebPage::BackForwardId>(item);
272 WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
275 , m_page(0) // Initialized by init.
276 , m_mainFrame(0) // Initialized by init.
277 , m_currentContextNode(0)
278 , m_webSettings(0) // Initialized by init.
280 , m_activationState(ActivationActive)
281 , m_shouldResetTilesWhenShown(false)
282 , m_userScalable(true)
283 , m_userPerformedManualZoom(false)
284 , m_userPerformedManualScroll(false)
285 , m_contentsSizeChanged(false)
286 , m_overflowExceedsContentsSize(false)
287 , m_resetVirtualViewportOnCommitted(true)
288 , m_shouldUseFixedDesktopMode(false)
289 , m_needTouchEvents(false)
290 , m_preventIdleDimmingCount(0)
291 #if ENABLE(TOUCH_EVENTS)
292 , m_preventDefaultOnTouchStart(false)
294 , m_nestedLayoutFinishedCount(0)
295 , m_actualVisibleWidth(rect.width())
296 , m_actualVisibleHeight(rect.height())
297 , m_virtualViewportWidth(0)
298 , m_virtualViewportHeight(0)
299 , m_defaultLayoutSize(minimumLayoutSize)
300 , m_didRestoreFromPageCache(false)
301 , m_viewMode(WebPagePrivate::Desktop) // Default to Desktop mode for PB.
302 , m_loadState(WebPagePrivate::None)
303 , m_transformationMatrix(new TransformationMatrix())
304 , m_backingStore(0) // Initialized by init.
305 , m_backingStoreClient(0) // Initialized by init.
306 , m_inPageSearchManager(new InPageSearchManager(this))
307 , m_inputHandler(new InputHandler(this))
308 , m_selectionHandler(new SelectionHandler(this))
309 , m_touchEventHandler(new TouchEventHandler(this))
310 #if ENABLE(EVENT_MODE_METATAGS)
311 , m_cursorEventMode(ProcessedCursorEvents)
312 , m_touchEventMode(ProcessedTouchEvents)
314 , m_currentCursor(Platform::CursorNone)
315 , m_dumpRenderTree(0) // Lazy initialization.
316 , m_initialScale(-1.0)
317 , m_minimumScale(-1.0)
318 , m_maximumScale(-1.0)
319 , m_blockZoomFinalScale(1.0)
320 , m_anchorInNodeRectRatio(-1, -1)
321 , m_currentBlockZoomNode(0)
322 , m_currentBlockZoomAdjustedNode(0)
323 , m_shouldReflowBlock(false)
324 , m_delayedZoomTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::zoomAboutPointTimerFired)))
325 , m_lastUserEventTimestamp(0.0)
326 , m_pluginMouseButtonPressed(false)
327 , m_pluginMayOpenNewTab(false)
328 , m_inRegionScrollStartingNode(0)
329 #if USE(ACCELERATED_COMPOSITING)
330 , m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
331 , m_needsOneShotDrawingSynchronization(false)
332 , m_needsCommit(false)
333 , m_suspendRootLayerCommit(false)
335 , m_pendingOrientation(-1)
336 , m_fullscreenVideoNode(0)
337 , m_hasInRegionScrollableAreas(false)
338 , m_updateDelegatedOverlaysDispatched(false)
340 static bool isInitialized = false;
341 if (!isInitialized) {
342 isInitialized = true;
343 BlackBerry::Platform::DeviceInfo::instance();
348 WebPage::WebPage(WebPageClient* client, const WebString& pageGroupName, const Platform::IntRect& rect)
351 d = new WebPagePrivate(this, client, rect);
352 d->init(pageGroupName);
355 WebPagePrivate::~WebPagePrivate()
357 // Hand the backingstore back to another owner if necessary.
358 m_webPage->setVisible(false);
359 if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage)
360 BackingStorePrivate::setCurrentBackingStoreOwner(0);
362 delete m_webSettings;
365 delete m_backingStoreClient;
366 m_backingStoreClient = 0;
372 delete m_transformationMatrix;
373 m_transformationMatrix = 0;
375 delete m_inPageSearchManager;
376 m_inPageSearchManager = 0;
378 delete m_selectionHandler;
379 m_selectionHandler = 0;
381 delete m_inputHandler;
384 delete m_touchEventHandler;
385 m_touchEventHandler = 0;
388 delete m_dumpRenderTree;
389 m_dumpRenderTree = 0;
399 Page* WebPagePrivate::core(const WebPage* webPage)
401 return webPage->d->m_page;
404 void WebPagePrivate::init(const WebString& pageGroupName)
406 ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this);
407 ContextMenuClientBlackBerry* contextMenuClient = 0;
408 #if ENABLE(CONTEXT_MENUS)
409 contextMenuClient = new ContextMenuClientBlackBerry();
411 EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this);
412 DragClientBlackBerry* dragClient = 0;
413 #if ENABLE(DRAG_SUPPORT)
414 dragClient = new DragClientBlackBerry();
416 InspectorClientBlackBerry* inspectorClient = 0;
417 #if ENABLE(INSPECTOR)
418 inspectorClient = new InspectorClientBlackBerry(this);
421 FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry();
423 Page::PageClients pageClients;
424 pageClients.chromeClient = chromeClient;
425 pageClients.contextMenuClient = contextMenuClient;
426 pageClients.editorClient = editorClient;
427 pageClients.dragClient = dragClient;
428 pageClients.inspectorClient = inspectorClient;
430 m_page = new Page(pageClients);
432 if (getenv("drtRun")) {
433 // In case running in DumpRenderTree mode set the controller to mock provider.
434 GeolocationClientMock* mock = new GeolocationClientMock();
435 WebCore::provideGeolocationTo(m_page, mock);
436 mock->setController(WebCore::GeolocationController::from(m_page));
439 WebCore::provideGeolocationTo(m_page, new GeolocationControllerClientBlackBerry(this));
441 WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientBlackBerry(this));
442 WebCore::provideDeviceMotionTo(m_page, new DeviceMotionClientBlackBerry(this));
444 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
445 WebCore::provideNotification(m_page, NotificationPresenterImpl::instance());
448 m_page->setCustomHTMLTokenizerChunkSize(256);
449 m_page->setCustomHTMLTokenizerTimeDelay(0.3);
451 m_webSettings = WebSettings::createFromStandardSettings();
452 m_webSettings->setUserAgentString(defaultUserAgent());
454 // FIXME: We explicitly call setDelegate() instead of passing ourself in createFromStandardSettings()
455 // so that we only get one didChangeSettings() callback when we set the page group name. This causes us
456 // to make a copy of the WebSettings since some WebSettings method make use of the page group name.
457 // Instead, we shouldn't be storing the page group name in WebSettings.
458 m_webSettings->setDelegate(this);
459 m_webSettings->setPageGroupName(pageGroupName);
461 RefPtr<Frame> newFrame = Frame::create(m_page, /* HTMLFrameOwnerElement* */ 0, frameLoaderClient);
463 m_mainFrame = newFrame.get();
464 frameLoaderClient->setFrame(m_mainFrame, this);
468 Platform::Settings* settings = Platform::Settings::get();
469 m_page->settings()->setWebGLEnabled(settings && settings->isWebGLSupported());
471 #if ENABLE(ACCELERATED_2D_CANVAS)
472 m_page->settings()->setCanvasUsesAcceleratedDrawing(true);
473 m_page->settings()->setAccelerated2dCanvasEnabled(true);
475 #if ENABLE(VIEWPORT_REFLOW)
476 m_page->settings()->setTextReflowEnabled(m_webSettings->textReflowMode() == WebSettings::TextReflowEnabled);
479 m_page->settings()->setUseHixie76WebSocketProtocol(false);
480 m_page->settings()->setInteractiveFormValidationEnabled(true);
481 m_page->settings()->setAllowUniversalAccessFromFileURLs(false);
482 m_page->settings()->setAllowFileAccessFromFileURLs(false);
484 m_backingStoreClient = BackingStoreClient::create(m_mainFrame, /* parent frame */ 0, m_webPage);
485 // The direct access to BackingStore is left here for convenience since it
486 // is owned by BackingStoreClient and then deleted by its destructor.
487 m_backingStore = m_backingStoreClient->backingStore();
489 m_page->settings()->setSpatialNavigationEnabled(m_webSettings->isSpatialNavigationEnabled());
490 blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(0).width())); // The clicked rectangle area should be a fixed unit of measurement.
492 m_page->settings()->setDelegateSelectionPaint(true);
494 #if ENABLE(REQUEST_ANIMATION_FRAME)
495 m_page->windowScreenDidChange((PlatformDisplayID)0);
498 #if ENABLE(WEB_TIMING)
499 m_page->settings()->setMemoryInfoEnabled(true);
503 void WebPagePrivate::load(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool isInitial, bool mustHandleInternally, bool forceDownload, const char* overrideContentType)
507 String urlString(url);
508 if (urlString.startsWith("vs:", false)) {
509 urlString = urlString.substring(3);
510 m_mainFrame->setInViewSourceMode(true);
512 m_mainFrame->setInViewSourceMode(false);
514 KURL kurl = parseUrl(urlString);
515 if (protocolIs(kurl, "javascript")) {
516 // Never run javascript while loading is deferred.
517 if (m_page->defersLoading()) {
518 FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(m_mainFrame->loader()->client());
519 frameLoaderClient->setDeferredManualScript(kurl);
521 m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL);
526 NetworkManager::instance()->setInitialURL(kurl);
528 ResourceRequest request(kurl, "" /* referrer */);
529 request.setToken(networkToken);
530 if (isInitial || mustHandleInternally)
531 request.setMustHandleInternally(true);
532 request.setHTTPMethod(method);
533 request.setCachePolicy(toWebCoreCachePolicy(cachePolicy));
534 if (overrideContentType)
535 request.setOverrideContentType(overrideContentType);
538 request.setHTTPBody(FormData::create(data, dataLength));
540 for (unsigned i = 0; i + 1 < headersLength; i += 2)
541 request.addHTTPHeaderField(headers[i], headers[i + 1]);
544 request.setForceDownload(true);
546 m_mainFrame->loader()->load(request, "" /* name */, false);
549 void WebPage::load(const char* url, const char* networkToken, bool isInitial)
551 d->load(url, networkToken, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, isInitial, false);
554 void WebPage::loadExtended(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool mustHandleInternally)
556 d->load(url, networkToken, method, cachePolicy, data, dataLength, headers, headersLength, false, mustHandleInternally, false, "");
559 void WebPage::loadFile(const char* path, const char* overrideContentType)
561 std::string fileUrl(path);
562 if (!fileUrl.find("/"))
563 fileUrl.insert(0, "file://");
564 else if (fileUrl.find("file:///"))
567 d->load(fileUrl.c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, false, overrideContentType);
570 void WebPage::download(const Platform::NetworkRequest& request)
572 d->load(request.getUrlRef().c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, true, "");
575 void WebPagePrivate::loadString(const char* string, const char* baseURL, const char* contentType, const char* failingURL)
577 KURL kurl = parseUrl(baseURL);
578 ResourceRequest request(kurl);
579 WTF::RefPtr<SharedBuffer> buffer
580 = SharedBuffer::create(string, strlen(string));
581 SubstituteData substituteData(buffer,
582 extractMIMETypeFromMediaType(contentType),
583 extractCharsetFromMediaType(contentType),
584 failingURL ? parseUrl(failingURL) : KURL());
585 m_mainFrame->loader()->load(request, substituteData, false);
588 void WebPage::loadString(const char* string, const char* baseURL, const char* mimeType, const char* failingURL)
590 d->loadString(string, baseURL, mimeType, failingURL);
593 bool WebPagePrivate::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
595 ScriptValue result = m_mainFrame->script()->executeScript(String::fromUTF8(script), false);
596 JSC::JSValue value = result.jsValue();
598 returnType = JSException;
602 JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
603 JSGlobalContextRef context = toGlobalRef(exec);
605 JSType type = JSValueGetType(context, toRef(exec, value));
612 returnType = JSBoolean;
615 returnType = JSNumber;
618 returnType = JSString;
621 returnType = JSObject;
623 case kJSTypeUndefined:
625 returnType = JSUndefined;
629 if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
630 String str = result.toString(exec);
631 returnValue = WebString(str.impl());
637 bool WebPage::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
639 return d->executeJavaScript(script, returnType, returnValue);
642 bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& sourceCode, JavaScriptDataType& returnType, WebString& returnValue)
644 if (!m_isolatedWorld)
645 m_isolatedWorld = m_mainFrame->script()->createWorld();
647 // Use evaluateInWorld to avoid canExecuteScripts check.
648 ScriptValue result = m_mainFrame->script()->evaluateInWorld(sourceCode, m_isolatedWorld.get());
649 JSC::JSValue value = result.jsValue();
651 returnType = JSException;
655 JSC::ExecState* exec = m_mainFrame->script()->globalObject(m_isolatedWorld.get())->globalExec();
656 JSGlobalContextRef context = toGlobalRef(exec);
658 JSType type = JSValueGetType(context, toRef(exec, value));
665 returnType = JSBoolean;
668 returnType = JSNumber;
671 returnType = JSString;
674 returnType = JSObject;
676 case kJSTypeUndefined:
678 returnType = JSUndefined;
682 if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
683 String str = result.toString(exec);
684 returnValue = WebString(str.impl());
690 bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, WebString& returnValue)
692 // On our platform wchar_t is unsigned int and UChar is unsigned short
693 // so we have to convert using ICU conversion function
694 int lengthCopied = 0;
695 UErrorCode error = U_ZERO_ERROR;
696 const int length = script.length() + 1 /*null termination char*/;
699 // FIXME: PR 138162 is giving U_INVALID_CHAR_FOUND error.
700 u_strFromUTF32(data, length, &lengthCopied, reinterpret_cast<const UChar32*>(script.c_str()), script.length(), &error);
701 BLACKBERRY_ASSERT(error == U_ZERO_ERROR);
702 if (error != U_ZERO_ERROR) {
703 Platform::logAlways(Platform::LogLevelCritical, "WebPage::executeJavaScriptInIsolatedWorld failed to convert UTF16 to JavaScript!");
706 String str = String(data, lengthCopied);
707 ScriptSourceCode sourceCode(str, KURL());
708 return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
711 bool WebPage::executeJavaScriptInIsolatedWorld(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
713 ScriptSourceCode sourceCode(String::fromUTF8(script), KURL());
714 return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
717 void WebPagePrivate::stopCurrentLoad()
719 // This function should contain all common code triggered by WebPage::load
720 // (which stops any load in progress before starting the new load) and
721 // WebPage::stoploading (the entry point for the client to stop the load
722 // explicitly). If it should only be done while stopping the load
723 // explicitly, it goes in WebPage::stopLoading, not here.
724 m_mainFrame->loader()->stopAllLoaders();
726 // Cancel any deferred script that hasn't been processed yet.
727 FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(m_mainFrame->loader()->client());
728 frameLoaderClient->setDeferredManualScript(KURL());
731 void WebPage::stopLoading()
733 d->stopCurrentLoad();
736 static void closeURLRecursively(Frame* frame)
738 // Do not create more frame please.
739 FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client());
740 frameLoaderClient->suppressChildFrameCreation();
742 frame->loader()->closeURL();
744 Vector<RefPtr<Frame>, 10> childFrames;
746 for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
747 childFrames.append(childFrame);
749 unsigned size = childFrames.size();
750 for (unsigned i = 0; i < size; i++)
751 closeURLRecursively(childFrames[i].get());
754 void WebPagePrivate::prepareToDestroy()
756 // Before the client starts tearing itself down, dispatch the unload event
757 // so it can take effect while all the client's state (e.g. scroll position)
759 closeURLRecursively(m_mainFrame);
762 void WebPage::prepareToDestroy()
764 d->prepareToDestroy();
767 void WebPagePrivate::setLoadState(LoadState state)
769 if (m_loadState == state)
772 bool isFirstLoad = m_loadState == None;
774 // See RIM Bug #1068.
775 if (state == Finished && m_mainFrame && m_mainFrame->document())
776 m_mainFrame->document()->updateStyleIfNeeded();
780 #if DEBUG_WEBPAGE_LOAD
781 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state);
784 switch (m_loadState) {
787 // Paints the visible backingstore as white to prevent initial checkerboard on
789 if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
790 m_backingStore->d->blitVisibleContents();
795 unscheduleZoomAboutPoint();
797 #if ENABLE(ACCELERATED_2D_CANVAS)
798 if (m_page->settings()->canvasUsesAcceleratedDrawing()) {
799 // Free GPU resources as we're on a new page.
800 // This will help us to free memory pressure.
801 SharedGraphicsContext3D::get()->makeContextCurrent();
802 GrContext* grContext = Platform::Graphics::getGrContext();
803 grContext->freeGpuResources();
807 #if USE(ACCELERATED_COMPOSITING)
808 // FIXME: compositor may only be touched on the compositing thread.
809 // However, it's created/destroyed by a sync command so this is harmless.
811 m_compositor->setLayoutRectForCompositing(IntRect());
812 m_compositor->setContentsSizeForCompositing(IntSize());
815 m_previousContentsSize = IntSize();
816 m_backingStore->d->resetRenderQueue();
817 m_backingStore->d->resetTiles(true /* resetBackground */);
818 m_backingStore->d->setScrollingOrZooming(false, false /* shouldBlit */);
819 m_userPerformedManualZoom = false;
820 m_userPerformedManualScroll = false;
821 m_shouldUseFixedDesktopMode = false;
822 if (m_resetVirtualViewportOnCommitted) { // For DRT.
823 m_virtualViewportWidth = 0;
824 m_virtualViewportHeight = 0;
826 if (m_webSettings->viewportWidth() > 0) {
827 m_virtualViewportWidth = m_webSettings->viewportWidth();
828 m_virtualViewportHeight = m_defaultLayoutSize.height();
830 // Check if we have already process the meta viewport tag, this only happens on history navigation
831 if (!m_didRestoreFromPageCache) {
832 m_viewportArguments = ViewportArguments();
833 m_userScalable = m_webSettings->isUserScalable();
836 IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
837 m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
840 #if ENABLE(EVENT_MODE_METATAGS)
841 didReceiveCursorEventMode(ProcessedCursorEvents);
842 didReceiveTouchEventMode(ProcessedTouchEvents);
845 // If it's a outmost SVG document, we use FixedDesktop mode, otherwise
846 // we default to Mobile mode. For example, using FixedDesktop mode to
847 // render http://www.croczilla.com/bits_and_pieces/svg/samples/tiger/tiger.svg
848 // is user-experience friendly.
849 if (m_page->mainFrame()->document()->isSVGDocument()) {
850 setShouldUseFixedDesktopMode(true);
851 setViewMode(FixedDesktop);
855 // Reset block zoom and reflow.
857 #if ENABLE(VIEWPORT_REFLOW)
858 toggleTextReflowIfEnabledForBlockZoomOnly();
861 // Notify InputHandler of state change.
862 m_inputHandler->enableInputMode(false);
864 // Set the scroll to origin here and notify the client since we'll be
865 // zooming below without any real contents yet thus the contents size
866 // we report to the client could make our current scroll position invalid.
867 setScrollPosition(IntPoint::zero());
868 notifyTransformedScrollChanged();
870 // Paints the visible backingstore as white. Note it is important we do
871 // this strictly after re-setting the scroll position to origin and resetting
872 // the scales otherwise the visible contents calculation is wrong and we
873 // can end up blitting artifacts instead. See: RIM Bug #401.
874 if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
875 m_backingStore->d->blitVisibleContents();
877 zoomToInitialScaleOnLoad();
879 // Update cursor status.
882 #if USE(ACCELERATED_COMPOSITING)
883 // Don't render compositing contents from previous page.
884 resetCompositingSurface();
890 // Notify client of the initial zoom change.
891 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
892 m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
899 double WebPagePrivate::clampedScale(double scale) const
901 if (scale < minimumScale())
902 return minimumScale();
903 if (scale > maximumScale())
904 return maximumScale();
908 bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale)
910 if (!m_mainFrame->view())
913 if (enforceScaleClamping)
914 scale = this->clampedScale(scale);
916 ASSERT(clampedScale);
917 *clampedScale = scale;
919 if (currentScale() == scale) {
920 // Make sure backingstore updates resume from pinch zoom in the case where the final zoom level doesn't change.
921 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
922 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
929 bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel)
931 if (!isRestoringZoomLevel) {
932 // Clear any existing block zoom. (If we are restoring a saved zoom level on page load,
933 // there is guaranteed to be no existing block zoom and we don't want to clear m_shouldReflowBlock.)
937 // The reflow and block zoom stuff here needs to happen regardless of
938 // whether we shouldZoomAboutPoint.
939 #if ENABLE(VIEWPORT_REFLOW)
940 toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
941 if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view())
946 if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
947 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
948 m_currentPinchZoomNode = 0;
949 m_anchorInNodeRectRatio = FloatPoint(-1, -1);
953 TransformationMatrix zoom;
956 #if DEBUG_WEBPAGE_LOAD
957 if (loadState() < Finished)
958 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomAboutPoint scale %f anchor (%f, %f)", scale, anchor.x(), anchor.y());
961 // Our current scroll position in float.
962 FloatPoint scrollPosition = this->scrollPosition();
964 // Anchor offset from scroll position in float.
965 FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y());
967 // The horizontal scaling factor and vertical scaling factor should be equal
968 // to preserve aspect ratio of content.
969 ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22());
971 // Need to invert the previous transform to anchor the viewport.
972 double inverseScale = scale / m_transformationMatrix->m11();
975 *m_transformationMatrix = zoom;
977 // Suspend all screen updates to the backingstore.
978 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
980 updateViewportSize();
982 IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))),
983 max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale)))));
985 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
986 // This is a hack for email which has reflow always turned on.
987 m_mainFrame->view()->setNeedsLayout();
988 requestLayoutIfNeeded();
989 if (m_currentPinchZoomNode)
990 newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale);
991 m_currentPinchZoomNode = 0;
992 m_anchorInNodeRectRatio = FloatPoint(-1, -1);
995 setScrollPosition(newScrollPosition);
997 notifyTransformChanged();
999 bool isLoading = this->isLoading();
1001 // We need to invalidate all tiles both visible and non-visible if we're loading.
1002 m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */);
1004 m_client->resetBitmapZoomScale(m_transformationMatrix->m11());
1006 bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering;
1007 bool shouldClearVisibleZoom = isLoading && shouldRender;
1009 if (shouldClearVisibleZoom) {
1010 // If we are loading and rendering then we need to clear the render queue's
1011 // visible zoom jobs as they will be irrelevant with the render below.
1012 m_backingStore->d->clearVisibleZoom();
1015 // Clear window to make sure there are no artifacts.
1017 m_backingStore->d->clearWindow();
1018 // Resume all screen updates to the backingstore and render+blit visible contents to screen.
1019 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
1021 // Resume all screen updates to the backingstore but do not blit to the screen because we not rendering.
1022 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1025 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1030 IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale)
1032 // Should only be invoked when text reflow is enabled.
1033 ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
1038 IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
1040 if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) {
1041 offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y();
1042 if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0)
1043 offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale;
1046 IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get());
1048 return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))),
1049 max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale))));
1052 bool WebPagePrivate::scheduleZoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering)
1055 if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1056 // We could be back to the right zoom level before the timer has
1057 // timed out, because of wiggling back and forth. Stop the timer.
1058 unscheduleZoomAboutPoint();
1062 // For some reason, the bitmap zoom wants an anchor in backingstore coordinates!
1063 // this is different from zoomAboutPoint, which wants content coordinates.
1064 // See RIM Bug #641.
1066 FloatPoint transformedAnchor = mapToTransformedFloatPoint(anchor);
1067 FloatPoint transformedScrollPosition = mapToTransformedFloatPoint(scrollPosition());
1069 // Prohibit backingstore from updating the window overtop of the bitmap.
1070 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1072 // Need to invert the previous transform to anchor the viewport.
1073 double zoomFraction = scale / transformationMatrix()->m11();
1075 // Anchor offset from scroll position in float.
1076 FloatPoint anchorOffset(transformedAnchor.x() - transformedScrollPosition.x(),
1077 transformedAnchor.y() - transformedScrollPosition.y());
1080 static_cast<int>(roundf(transformedAnchor.x() - anchorOffset.x() / zoomFraction)),
1081 static_cast<int>(roundf(transformedAnchor.y() - anchorOffset.y() / zoomFraction)));
1083 const IntRect viewportRect = IntRect(IntPoint::zero(), transformedViewportSize());
1084 const IntRect dstRect = viewportRect;
1086 // This is the rect to pass as the actual source rect in the backingstore
1087 // for the transform given by zoom.
1088 IntRect srcRect(srcPoint.x(),
1090 viewportRect.width() / zoomFraction,
1091 viewportRect.height() / zoomFraction);
1092 m_backingStore->d->blitContents(dstRect, srcRect);
1094 m_delayedZoomArguments.scale = scale;
1095 m_delayedZoomArguments.anchor = anchor;
1096 m_delayedZoomArguments.enforceScaleClamping = enforceScaleClamping;
1097 m_delayedZoomArguments.forceRendering = forceRendering;
1098 m_delayedZoomTimer->startOneShot(delayedZoomInterval);
1103 void WebPagePrivate::unscheduleZoomAboutPoint()
1105 if (m_delayedZoomTimer->isActive())
1106 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1108 m_delayedZoomTimer->stop();
1111 void WebPagePrivate::zoomAboutPointTimerFired(Timer<WebPagePrivate>*)
1113 zoomAboutPoint(m_delayedZoomArguments.scale, m_delayedZoomArguments.anchor, m_delayedZoomArguments.enforceScaleClamping, m_delayedZoomArguments.forceRendering);
1116 void WebPagePrivate::setNeedsLayout()
1118 FrameView* view = m_mainFrame->view();
1120 view->setNeedsLayout();
1123 void WebPagePrivate::requestLayoutIfNeeded() const
1125 FrameView* view = m_mainFrame->view();
1127 view->updateLayoutAndStyleIfNeededRecursive();
1128 ASSERT(!view->needsLayout());
1131 IntPoint WebPagePrivate::scrollPosition() const
1133 return m_backingStoreClient->scrollPosition();
1136 IntPoint WebPagePrivate::maximumScrollPosition() const
1138 return m_backingStoreClient->maximumScrollPosition();
1141 void WebPagePrivate::setScrollPosition(const IntPoint& pos)
1143 m_backingStoreClient->setScrollPosition(pos);
1146 // Setting the scroll position is in transformed coordinates.
1147 void WebPage::setScrollPosition(const Platform::IntPoint& point)
1149 if (d->transformedPointEqualsUntransformedPoint(point, d->scrollPosition()))
1152 // If the user recently performed an event, this new scroll position
1153 // could possibly be a result of that. Or not, this is just a heuristic.
1154 if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
1155 d->m_userPerformedManualScroll = true;
1157 d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1158 d->m_mainFrame->view()->setCanOverscroll(true);
1159 d->setScrollPosition(d->mapFromTransformed(point));
1160 d->m_mainFrame->view()->setCanOverscroll(false);
1161 d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1164 bool WebPagePrivate::shouldSendResizeEvent()
1166 if (!m_mainFrame->document())
1169 // PR#96865 : Provide an option to always send resize events, regardless of the loading
1170 // status. The scenario for this are Sapphire applications which tend to
1171 // maintain an open GET request to the server. This open GET results in
1172 // webkit thinking that content is still arriving when at the application
1173 // level it is considered fully loaded.
1175 // NOTE: Care must be exercised in the use of this option, as it bypasses
1176 // the sanity provided in 'isLoadingInAPISense()' below.
1178 static const bool unrestrictedResizeEvents = Platform::Settings::get()->unrestrictedResizeEvents();
1179 if (unrestrictedResizeEvents)
1182 // Don't send the resize event if the document is loading. Some pages automatically reload
1183 // when the window is resized; Safari on iPhone often resizes the window while setting up its
1184 // viewport. This obviously can cause problems.
1185 DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
1186 if (documentLoader && documentLoader->isLoadingInAPISense())
1192 void WebPagePrivate::willDeferLoading()
1194 m_client->willDeferLoading();
1197 void WebPagePrivate::didResumeLoading()
1199 m_client->didResumeLoading();
1202 bool WebPagePrivate::scrollBy(int deltaX, int deltaY, bool scrollMainFrame)
1204 IntSize delta(deltaX, deltaY);
1205 if (!scrollMainFrame) {
1206 // We need to work around the fact that ::map{To,From}Transformed do not
1207 // work well with negative values, like a negative width or height of an IntSize.
1208 IntSize copiedDelta(IntSize(abs(delta.width()), abs(delta.height())));
1209 IntSize untransformedCopiedDelta = mapFromTransformed(copiedDelta);
1211 delta.width() < 0 ? -untransformedCopiedDelta.width() : untransformedCopiedDelta.width(),
1212 delta.height() < 0 ? -untransformedCopiedDelta.height(): untransformedCopiedDelta.height());
1214 if (m_inRegionScrollStartingNode) {
1215 if (scrollNodeRecursively(m_inRegionScrollStartingNode.get(), delta)) {
1216 m_selectionHandler->selectionPositionChanged();
1217 // FIXME: We have code in place to handle scrolling and clipping tap highlight
1218 // on in-region scrolling. As soon as it is fast enough (i.e. we have it backed by
1219 // a backing store), we can reliably make use of it in the real world.
1220 // m_touchEventHandler->drawTapHighlight();
1228 setScrollPosition(scrollPosition() + delta);
1232 bool WebPage::scrollBy(const Platform::IntSize& delta, bool scrollMainFrame)
1234 d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1235 bool b = d->scrollBy(delta.width(), delta.height(), scrollMainFrame);
1236 d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1240 void WebPagePrivate::notifyInRegionScrollStatusChanged(bool status)
1242 if (!status && m_inRegionScrollStartingNode) {
1243 enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(m_inRegionScrollStartingNode.get());
1244 m_inRegionScrollStartingNode = 0;
1248 void WebPage::notifyInRegionScrollStatusChanged(bool status)
1250 d->notifyInRegionScrollStatusChanged(status);
1253 void WebPagePrivate::enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(Node* scrolledNode)
1255 ASSERT(scrolledNode);
1256 if (scrolledNode->isDocumentNode()) {
1257 Frame* frame = static_cast<const Document*>(scrolledNode)->frame();
1261 ASSERT(frame != m_mainFrame);
1262 FrameView* view = frame->view();
1267 // #1 - Get frame rect in contents coords.
1268 // #2 - Get the clipped scrollview rect in contents coords.
1269 // #3 - Take transform into account for 1 and 2.
1270 // #4 - Subtract 2 from 1, so we know exactly which areas of the frame
1271 // are offscreen, and need async repainting.
1272 FrameView* mainFrameView = m_mainFrame->view();
1273 ASSERT(mainFrameView);
1274 IntRect frameRect = view->frameRect();
1275 frameRect = frame->tree()->parent()->view()->contentsToWindow(frameRect);
1276 frameRect = mainFrameView->windowToContents(frameRect);
1278 IntRect visibleWindowRect = getRecursiveVisibleWindowRect(view);
1279 IntRect visibleContentsRect = mainFrameView->windowToContents(visibleWindowRect);
1281 IntRect transformedFrameRect = mapToTransformed(frameRect);
1282 IntRect transformedVisibleContentsRect = mapToTransformed(visibleContentsRect);
1284 Platform::IntRectRegion offscreenRegionOfIframe
1285 = Platform::IntRectRegion::subtractRegions(Platform::IntRect(transformedFrameRect), Platform::IntRect(transformedVisibleContentsRect));
1287 if (!offscreenRegionOfIframe.isEmpty())
1288 m_backingStore->d->m_renderQueue->addToQueue(RenderQueue::RegularRender, offscreenRegionOfIframe.rects());
1292 void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
1294 if (b != m_hasInRegionScrollableAreas)
1295 m_hasInRegionScrollableAreas = b;
1298 IntSize WebPagePrivate::viewportSize() const
1300 return mapFromTransformed(transformedViewportSize());
1303 IntSize WebPagePrivate::actualVisibleSize() const
1305 return mapFromTransformed(transformedActualVisibleSize());
1308 bool WebPagePrivate::hasVirtualViewport() const
1310 return m_virtualViewportWidth && m_virtualViewportHeight;
1313 void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
1315 ASSERT(m_mainFrame->view());
1316 if (setFixedReportedSize)
1317 m_mainFrame->view()->setFixedReportedSize(actualVisibleSize());
1319 IntRect frameRect = IntRect(scrollPosition(), viewportSize());
1320 if (frameRect != m_mainFrame->view()->frameRect()) {
1321 m_mainFrame->view()->setFrameRect(frameRect);
1322 m_mainFrame->view()->adjustViewSize();
1325 // We're going to need to send a resize event to JavaScript because
1326 // innerWidth and innerHeight depend on fixed reported size.
1327 // This is how we support mobile pages where JavaScript resizes
1328 // the page in order to get around the fixed layout size, e.g.
1329 // google maps when it detects a mobile user agent.
1330 if (sendResizeEvent && shouldSendResizeEvent())
1331 m_mainFrame->eventHandler()->sendResizeEvent();
1333 // When the actual visible size changes, we also
1334 // need to reposition fixed elements.
1335 m_mainFrame->view()->repaintFixedElementsAfterScrolling();
1338 FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
1340 // The visible contents rect in float.
1341 FloatRect visibleContentsRect = this->visibleContentsRect();
1343 // The center of the visible contents rect in float.
1344 return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
1345 visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
1348 IntRect WebPagePrivate::visibleContentsRect() const
1350 return m_backingStoreClient->visibleContentsRect();
1353 IntSize WebPagePrivate::contentsSize() const
1355 if (!m_mainFrame->view())
1358 return m_backingStoreClient->contentsSize();
1361 IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
1363 if (!m_mainFrame->contentRenderer())
1366 return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
1369 void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
1371 if (m_previousContentsSize == contentsSize)
1374 // This should only occur in the middle of layout so we set a flag here and
1375 // handle it at the end of the layout.
1376 m_contentsSizeChanged = true;
1378 #if DEBUG_WEBPAGE_LOAD
1379 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %dx%d", contentsSize.width(), contentsSize.height());
1383 void WebPagePrivate::layoutFinished()
1385 if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
1388 m_contentsSizeChanged = false; // Toggle to turn off notification again.
1389 m_overflowExceedsContentsSize = false;
1391 if (contentsSize().isEmpty())
1394 // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from
1395 // the middle of a layout, but the recursion is limited by detection code in
1396 // setViewMode() and mitigation code in fixedLayoutSize().
1397 if (didLayoutExceedMaximumIterations()) {
1398 notifyTransformedContentsSizeChanged();
1402 // Temporarily save the m_previousContentsSize here before updating it (in
1403 // notifyTransformedContentsSizeChanged()) so we can compare if our contents
1404 // shrunk afterwards.
1405 IntSize previousContentsSize = m_previousContentsSize;
1407 m_nestedLayoutFinishedCount++;
1409 if (loadState() == Committed)
1410 zoomToInitialScaleOnLoad();
1411 else if (loadState() != None)
1412 notifyTransformedContentsSizeChanged();
1414 m_nestedLayoutFinishedCount--;
1416 if (!m_nestedLayoutFinishedCount) {
1417 // When the contents shrinks, there is a risk that we
1418 // will be left at a scroll position that lies outside of the
1419 // contents rect. Since we allow overscrolling and neglect
1420 // to clamp overscroll in order to retain input focus (RIM Bug #414)
1421 // we need to clamp somewhere, and this is where we know the
1422 // contents size has changed.
1424 if (contentsSize() != previousContentsSize) {
1426 IntPoint newScrollPosition = scrollPosition();
1428 if (contentsSize().height() < previousContentsSize.height()) {
1429 IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
1430 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
1433 if (contentsSize().width() < previousContentsSize.width()) {
1434 IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
1435 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
1438 if (newScrollPosition != scrollPosition()) {
1439 setScrollPosition(newScrollPosition);
1440 notifyTransformedScrollChanged();
1446 void WebPagePrivate::zoomToInitialScaleOnLoad()
1448 #if DEBUG_WEBPAGE_LOAD
1449 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
1452 bool needsLayout = false;
1454 // If the contents width exceeds the viewport width set to desktop mode.
1455 if (m_shouldUseFixedDesktopMode)
1456 needsLayout = setViewMode(FixedDesktop);
1458 needsLayout = setViewMode(Desktop);
1461 // This can cause recursive layout...
1465 if (contentsSize().isEmpty()) {
1466 #if DEBUG_WEBPAGE_LOAD
1467 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
1469 requestLayoutIfNeeded();
1470 m_client->resetBitmapZoomScale(currentScale());
1471 notifyTransformedContentsSizeChanged();
1475 bool performedZoom = false;
1476 bool shouldZoom = !m_userPerformedManualZoom;
1478 // If this load should restore view state, don't zoom to initial scale
1479 // but instead let the HistoryItem's saved viewport reign supreme.
1480 if (m_mainFrame && m_mainFrame->loader() && m_mainFrame->loader()->shouldRestoreScrollPositionAndViewState())
1483 if (shouldZoom && loadState() == Committed) {
1484 // Preserve at top and at left position, to avoid scrolling
1485 // to a non top-left position for web page with viewport meta tag
1486 // that specifies an initial-scale that is zoomed in.
1487 FloatPoint anchor = centerOfVisibleContentsRect();
1488 if (!scrollPosition().x())
1490 if (!scrollPosition().y())
1492 performedZoom = zoomAboutPoint(initialScale(), anchor);
1495 // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout...
1496 requestLayoutIfNeeded();
1498 if (!performedZoom) {
1499 // We only notify if we didn't perform zoom, because zoom will notify on
1501 m_client->resetBitmapZoomScale(currentScale());
1502 notifyTransformedContentsSizeChanged();
1506 double WebPagePrivate::zoomToFitScale() const
1508 // We must clamp the contents for this calculation so that we do not allow an
1509 // arbitrarily small zoomToFitScale much like we clamp the fixedLayoutSize()
1510 // so that we do not have arbitrarily large layout size.
1511 // If we have a specified viewport, we may need to be able to zoom out more.
1512 int contentWidth = std::min(contentsSize().width(), std::max(m_virtualViewportWidth, static_cast<int>(defaultMaxLayoutSize().width())));
1514 // defaultMaxLayoutSize().width() is a safeguard for excessively large page layouts that
1515 // is too restrictive for image documents. In this case, the document width is sufficient.
1516 Document* doc = m_page->mainFrame()->document();
1517 if (doc && doc->isImageDocument())
1518 contentWidth = contentsSize().width();
1520 // If we have a virtual viewport and its aspect ratio caused content to layout
1521 // wider than the default layout aspect ratio we need to zoom to fit the content height
1522 // in order to avoid showing a grey area below the web page.
1523 // Without virtual viewport we can never get into this situation.
1524 if (hasVirtualViewport()) {
1525 int contentHeight = std::min(contentsSize().height(), std::max(m_virtualViewportHeight, static_cast<int>(defaultMaxLayoutSize().height())));
1527 // Aspect ratio check without division.
1528 if (contentWidth * m_defaultLayoutSize.height() > contentHeight * m_defaultLayoutSize.width())
1529 return contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
1532 return contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
1535 double WebPage::zoomToFitScale() const
1537 return d->zoomToFitScale();
1540 double WebPagePrivate::initialScale() const
1542 if (m_initialScale > 0.0)
1543 return m_initialScale;
1545 if (m_webSettings->isZoomToFitOnLoad())
1546 return zoomToFitScale();
1551 double WebPage::initialScale() const
1553 return d->initialScale();
1556 void WebPage::initializeIconDataBase()
1558 IconDatabaseClientBlackBerry::getInstance()->initIconDatabase(d->m_webSettings);
1561 bool WebPage::isUserScalable() const
1563 return d->isUserScalable();
1566 double WebPage::currentScale() const
1568 return d->currentScale();
1571 void WebPage::setInitialScale(double initialScale)
1573 d->setInitialScale(initialScale);
1576 double WebPage::minimumScale() const
1578 return d->minimumScale();
1581 void WebPage::setMinimumScale(double minimumScale)
1583 d->setMinimumScale(minimumScale);
1586 void WebPage::setMaximumScale(double maximumScale)
1588 d->setMaximumScale(maximumScale);
1591 double WebPagePrivate::maximumScale() const
1593 if (m_maximumScale >= zoomToFitScale() && m_maximumScale >= m_minimumScale)
1594 return m_maximumScale;
1596 return hasVirtualViewport() ? std::max<double>(zoomToFitScale(), 4.0) : 4.0;
1599 double WebPage::maximumScale() const
1601 return d->maximumScale();
1604 void WebPagePrivate::resetScales()
1606 TransformationMatrix identity;
1607 *m_transformationMatrix = identity;
1608 m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0;
1609 m_minimumScale = -1.0;
1610 m_maximumScale = -1.0;
1612 // We have to let WebCore know about updated framerect now that we've
1613 // reset our scales. See: RIM Bug #401.
1614 updateViewportSize();
1617 IntPoint WebPagePrivate::transformedScrollPosition() const
1619 return m_backingStoreClient->transformedScrollPosition();
1622 // Returned scroll position is in transformed coordinates.
1623 Platform::IntPoint WebPage::scrollPosition() const
1625 return d->transformedScrollPosition();
1628 IntPoint WebPagePrivate::transformedMaximumScrollPosition() const
1630 return m_backingStoreClient->transformedMaximumScrollPosition();
1633 IntSize WebPagePrivate::transformedActualVisibleSize() const
1635 return IntSize(m_actualVisibleWidth, m_actualVisibleHeight);
1638 Platform::IntSize WebPage::viewportSize() const
1640 return d->transformedActualVisibleSize();
1643 IntSize WebPagePrivate::transformedViewportSize() const
1645 return Platform::Graphics::Screen::primaryScreen()->size();
1648 IntRect WebPagePrivate::transformedVisibleContentsRect() const
1650 // Usually this would be mapToTransformed(visibleContentsRect()), but
1651 // that results in rounding errors because we already set the WebCore
1652 // viewport size from our original transformedViewportSize().
1653 // Instead, we only transform the scroll position and take the
1654 // viewport size as it is, which ensures that e.g. blitting operations
1655 // always cover the whole widget/screen.
1656 return IntRect(transformedScrollPosition(), transformedViewportSize());
1659 IntSize WebPagePrivate::transformedContentsSize() const
1661 // mapToTransformed() functions use this method to crop their results,
1662 // so we can't make use of them here. While we want rounding inside page
1663 // boundaries to extend rectangles and round points, we need to crop the
1664 // contents size to the floored values so that we don't try to display
1665 // or report points that are not fully covered by the actual float-point
1666 // contents rectangle.
1667 const IntSize untransformedContentsSize = contentsSize();
1668 const FloatPoint transformedBottomRight = m_transformationMatrix->mapPoint(
1669 FloatPoint(untransformedContentsSize.width(), untransformedContentsSize.height()));
1670 return IntSize(floorf(transformedBottomRight.x()), floorf(transformedBottomRight.y()));
1673 IntPoint WebPagePrivate::mapFromContentsToViewport(const IntPoint& point) const
1675 return m_backingStoreClient->mapFromContentsToViewport(point);
1678 IntPoint WebPagePrivate::mapFromViewportToContents(const IntPoint& point) const
1680 return m_backingStoreClient->mapFromViewportToContents(point);
1683 IntRect WebPagePrivate::mapFromContentsToViewport(const IntRect& rect) const
1685 return m_backingStoreClient->mapFromContentsToViewport(rect);
1688 IntRect WebPagePrivate::mapFromViewportToContents(const IntRect& rect) const
1690 return m_backingStoreClient->mapFromViewportToContents(rect);
1693 IntPoint WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntPoint& point) const
1695 return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(point);
1698 IntPoint WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntPoint& point) const
1700 return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(point);
1703 IntRect WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntRect& rect) const
1705 return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(rect);
1708 IntRect WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntRect& rect) const
1710 return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(rect);
1713 // NOTE: PIXEL ROUNDING!
1714 // Accurate back-and-forth rounding is not possible with information loss
1715 // by integer points and sizes, so we always expand the resulting mapped
1716 // float rectangles to the nearest integer. For points, we always use
1717 // floor-rounding in mapToTransformed() so that we don't have to crop to
1718 // the (floor'd) transformed contents size.
1719 static inline IntPoint roundTransformedPoint(const FloatPoint &point)
1721 // Maps by rounding half towards zero.
1722 return IntPoint(static_cast<int>(floorf(point.x())), static_cast<int>(floorf(point.y())));
1725 static inline IntPoint roundUntransformedPoint(const FloatPoint &point)
1727 // Maps by rounding half away from zero.
1728 return IntPoint(static_cast<int>(ceilf(point.x())), static_cast<int>(ceilf(point.y())));
1731 IntPoint WebPagePrivate::mapToTransformed(const IntPoint& point) const
1733 return roundTransformedPoint(m_transformationMatrix->mapPoint(FloatPoint(point)));
1736 FloatPoint WebPagePrivate::mapToTransformedFloatPoint(const FloatPoint& point) const
1738 return m_transformationMatrix->mapPoint(point);
1741 IntPoint WebPagePrivate::mapFromTransformed(const IntPoint& point) const
1743 return roundUntransformedPoint(m_transformationMatrix->inverse().mapPoint(FloatPoint(point)));
1746 FloatPoint WebPagePrivate::mapFromTransformedFloatPoint(const FloatPoint& point) const
1748 return m_transformationMatrix->inverse().mapPoint(point);
1751 FloatRect WebPagePrivate::mapFromTransformedFloatRect(const FloatRect& rect) const
1753 return m_transformationMatrix->inverse().mapRect(rect);
1756 IntSize WebPagePrivate::mapToTransformed(const IntSize& size) const
1758 return mapToTransformed(IntRect(IntPoint::zero(), size)).size();
1761 IntSize WebPagePrivate::mapFromTransformed(const IntSize& size) const
1763 return mapFromTransformed(IntRect(IntPoint::zero(), size)).size();
1766 IntRect WebPagePrivate::mapToTransformed(const IntRect& rect) const
1768 return enclosingIntRect(m_transformationMatrix->mapRect(FloatRect(rect)));
1771 // Use this in conjunction with mapToTransformed(IntRect), in most cases.
1772 void WebPagePrivate::clipToTransformedContentsRect(IntRect& rect) const
1774 rect.intersect(IntRect(IntPoint::zero(), transformedContentsSize()));
1777 IntRect WebPagePrivate::mapFromTransformed(const IntRect& rect) const
1779 return enclosingIntRect(m_transformationMatrix->inverse().mapRect(FloatRect(rect)));
1782 bool WebPagePrivate::transformedPointEqualsUntransformedPoint(const IntPoint& transformedPoint, const IntPoint& untransformedPoint)
1784 // Scaling down is always more accurate than scaling up.
1785 if (m_transformationMatrix->a() > 1.0)
1786 return transformedPoint == mapToTransformed(untransformedPoint);
1788 return mapFromTransformed(transformedPoint) == untransformedPoint;
1791 void WebPagePrivate::notifyTransformChanged()
1793 notifyTransformedContentsSizeChanged();
1794 notifyTransformedScrollChanged();
1796 m_backingStore->d->transformChanged();
1799 void WebPagePrivate::notifyTransformedContentsSizeChanged()
1801 // We mark here as the last reported content size we sent to the client.
1802 m_previousContentsSize = contentsSize();
1804 const IntSize size = transformedContentsSize();
1805 m_backingStore->d->contentsSizeChanged(size);
1806 m_client->contentsSizeChanged(size);
1807 m_selectionHandler->selectionPositionChanged();
1810 void WebPagePrivate::notifyTransformedScrollChanged()
1812 const IntPoint pos = transformedScrollPosition();
1813 m_backingStore->d->scrollChanged(pos);
1814 m_client->scrollChanged(pos);
1817 bool WebPagePrivate::setViewMode(ViewMode mode)
1819 if (!m_mainFrame->view())
1824 // If we're in the middle of a nested layout with a recursion count above
1825 // some maximum threshold, then our algorithm for finding the minimum content
1826 // width of a given page has become dependent on the visible width.
1828 // We need to find some method to ensure that we don't experience excessive
1829 // and even infinite recursion. This can even happen with valid html. The
1830 // former can happen when we run into inline text with few candidates for line
1831 // break. The latter can happen for instance if the page has a negative margin
1832 // set against the right border. Note: this is valid by spec and can lead to
1833 // a situation where there is no value for which the content width will ensure
1834 // no horizontal scrollbar.
1835 // Example: LayoutTests/css1/box_properties/margin.html
1837 // In order to address such situations when we detect a recursion above some
1838 // maximum threshold we snap our fixed layout size to a defined quantum increment.
1839 // Eventually, either the content width will be satisfied to ensure no horizontal
1840 // scrollbar or this increment will run into the maximum layout size and the
1841 // recursion will necessarily end.
1842 bool snapToIncrement = didLayoutExceedMaximumIterations();
1844 IntSize currentSize = m_mainFrame->view()->fixedLayoutSize();
1845 IntSize newSize = fixedLayoutSize(snapToIncrement);
1846 if (currentSize == newSize)
1849 // FIXME: Temp solution. We'll get back to this.
1850 if (m_nestedLayoutFinishedCount) {
1851 double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width());
1852 double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height());
1853 if (widthChange < 0.05 && heightChange < 0.05)
1857 m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
1858 m_mainFrame->view()->setFixedLayoutSize(newSize);
1859 return true; // Needs re-layout!
1862 void WebPagePrivate::setCursor(PlatformCursor handle)
1864 if (m_currentCursor.type() != handle.type()) {
1865 m_currentCursor = handle;
1866 m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot().x(), handle.hotspot().y());
1870 Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory()
1872 return m_client->networkStreamFactory();
1875 Platform::Graphics::Window* WebPagePrivate::platformWindow() const
1877 return m_client->window();
1880 void WebPagePrivate::setPreventsScreenDimming(bool keepAwake)
1883 if (!m_preventIdleDimmingCount)
1884 m_client->setPreventsScreenIdleDimming(true);
1885 m_preventIdleDimmingCount++;
1886 } else if (m_preventIdleDimmingCount > 0) {
1887 m_preventIdleDimmingCount--;
1888 if (!m_preventIdleDimmingCount)
1889 m_client->setPreventsScreenIdleDimming(false);
1891 ASSERT_NOT_REACHED(); // SetPreventsScreenIdleDimming(false) called too many times.
1894 void WebPagePrivate::showVirtualKeyboard(bool showKeyboard)
1896 m_client->showVirtualKeyboard(showKeyboard);
1899 void WebPagePrivate::ensureContentVisible(bool centerInView)
1901 m_inputHandler->ensureFocusElementVisible(centerInView);
1904 void WebPagePrivate::zoomToContentRect(const IntRect& rect)
1906 // Don't scale if the user is not supposed to scale.
1907 if (!isUserScalable())
1910 FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y());
1911 IntSize viewSize = viewportSize();
1913 // Calculate the scale required to scale that dimension to fit.
1914 double scaleH = (double)viewSize.width() / (double)rect.width();
1915 double scaleV = (double)viewSize.height() / (double)rect.height();
1917 // Choose the smaller scale factor so that all of the content is visible.
1918 zoomAboutPoint(min(scaleH, scaleV), anchor);
1921 void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister)
1924 m_pluginViews.add(plugin);
1926 m_pluginViews.remove(plugin);
1929 #define FOR_EACH_PLUGINVIEW(pluginViews) \
1930 HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \
1931 HashSet<PluginView*>::const_iterator last = pluginViews.end(); \
1932 for (; it != last; ++it)
1934 void WebPagePrivate::notifyPageOnLoad()
1936 FOR_EACH_PLUGINVIEW(m_pluginViews)
1937 (*it)->handleOnLoadEvent();
1940 bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
1942 return m_client->shouldPluginEnterFullScreen();
1945 void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
1947 m_fullScreenPluginView = plugin;
1948 m_client->didPluginEnterFullScreen();
1950 if (!m_client->window())
1953 Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix);
1954 m_client->window()->setSensitivityFullscreenOverride(true);
1957 void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* windowUniquePrefix)
1959 m_fullScreenPluginView = 0;
1960 m_client->didPluginExitFullScreen();
1962 if (!m_client->window())
1965 Platform::Graphics::Window::setTransparencyDiscardFilter(0);
1966 m_client->window()->setSensitivityFullscreenOverride(false);
1969 void WebPagePrivate::onPluginStartBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
1971 m_client->onPluginStartBackgroundPlay();
1974 void WebPagePrivate::onPluginStopBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
1976 m_client->onPluginStopBackgroundPlay();
1979 bool WebPagePrivate::lockOrientation(bool landscape)
1981 return m_client->lockOrientation(landscape);
1984 void WebPagePrivate::unlockOrientation()
1986 return m_client->unlockOrientation();
1989 int WebPagePrivate::orientation() const
1991 #if ENABLE(ORIENTATION_EVENTS)
1992 return m_mainFrame->orientation();
1994 #error ORIENTATION_EVENTS must be defined.
1995 // Or a copy of the orientation value will have to be stored in these objects.
1999 double WebPagePrivate::currentZoomFactor() const
2001 return currentScale();
2004 int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype)
2006 return m_client->showAlertDialog(atype);
2009 bool WebPagePrivate::isActive() const
2011 return m_client->isActive();
2014 bool WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSpace& protectionSpace, Credential& inputCredential)
2019 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2020 if (!m_webSettings->isPrivateBrowsingEnabled())
2021 credentialManager().autofillAuthenticationChallenge(protectionSpace, username, password);
2024 bool isConfirmed = m_client->authenticationChallenge(protectionSpace.realm().characters(), protectionSpace.realm().length(), username, password);
2026 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2027 Credential credential(username, password, CredentialPersistencePermanent);
2028 if (!m_webSettings->isPrivateBrowsingEnabled())
2029 credentialManager().saveCredentialIfConfirmed(this, CredentialTransformData(url, protectionSpace, credential));
2031 Credential credential(username, password, CredentialPersistenceNone);
2033 inputCredential = credential;
2037 PageClientBlackBerry::SaveCredentialType WebPagePrivate::notifyShouldSaveCredential(bool isNew)
2039 return static_cast<PageClientBlackBerry::SaveCredentialType>(m_client->notifyShouldSaveCredential(isNew));
2042 bool WebPagePrivate::useFixedLayout() const
2047 Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy)
2049 Platform::WebContext context;
2051 RefPtr<Node> node = contextNode(strategy);
2052 m_currentContextNode = node;
2053 if (!m_currentContextNode)
2056 requestLayoutIfNeeded();
2058 bool nodeAllowSelectionOverride = false;
2059 if (Node* linkNode = node->enclosingLinkEventParentOrSelf()) {
2061 if (linkNode->isLink() && linkNode->hasAttributes()) {
2062 if (Attribute* attribute = linkNode->attributes()->getAttributeItem(HTMLNames::hrefAttr))
2063 href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
2066 String pattern = findPatternStringForUrl(href);
2067 if (!pattern.isEmpty())
2068 context.setPattern(pattern.utf8().data());
2070 if (!href.string().isEmpty()) {
2071 context.setUrl(href.string().utf8().data());
2073 // Links are non-selectable by default, but selection should be allowed
2074 // providing the page is selectable, use the parent to determine it.
2075 if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
2076 nodeAllowSelectionOverride = true;
2080 if (!nodeAllowSelectionOverride && !node->canStartSelection())
2081 context.resetFlag(Platform::WebContext::IsSelectable);
2083 if (node->isHTMLElement()) {
2084 HTMLImageElement* imageElement = 0;
2085 HTMLMediaElement* mediaElement = 0;
2087 if (node->hasTagName(HTMLNames::imgTag))
2088 imageElement = static_cast<HTMLImageElement*>(node.get());
2089 else if (node->hasTagName(HTMLNames::areaTag))
2090 imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement();
2092 if (static_cast<HTMLElement*>(node.get())->isMediaElement())
2093 mediaElement = static_cast<HTMLMediaElement*>(node.get());
2095 if (imageElement && imageElement->renderer()) {
2096 context.setFlag(Platform::WebContext::IsImage);
2097 // FIXME: At the mean time, we only show "Save Image" when the image data is available.
2098 if (CachedResource* cachedResource = imageElement->cachedImage()) {
2099 if (cachedResource->isLoaded() && cachedResource->data()) {
2100 String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
2101 context.setSrc(node->document()->completeURL(url).string().utf8().data());
2104 String alt = imageElement->altText();
2106 context.setAlt(alt.utf8().data());
2110 if (mediaElement->hasAudio())
2111 context.setFlag(Platform::WebContext::IsAudio);
2112 if (mediaElement->hasVideo())
2113 context.setFlag(Platform::WebContext::IsVideo);
2115 String src = stripLeadingAndTrailingHTMLSpaces(mediaElement->getAttribute(HTMLNames::srcAttr).string());
2116 context.setSrc(node->document()->completeURL(src).string().utf8().data());
2120 if (node->isTextNode()) {
2121 Text* curText = static_cast<Text*>(node.get());
2122 if (!curText->wholeText().isEmpty())
2123 context.setText(curText->wholeText().utf8().data());
2126 if (node->isElementNode()) {
2127 Element* element = static_cast<Element*>(node->shadowAncestorNode());
2128 if (DOMSupport::isTextBasedContentEditableElement(element)) {
2129 context.setFlag(Platform::WebContext::IsInput);
2130 if (element->hasTagName(HTMLNames::inputTag))
2131 context.setFlag(Platform::WebContext::IsSingleLine);
2132 if (DOMSupport::isPasswordElement(element))
2133 context.setFlag(Platform::WebContext::IsPassword);
2135 String elementText(DOMSupport::inputElementText(element));
2136 if (!elementText.stripWhiteSpace().isEmpty())
2137 context.setText(elementText.utf8().data());
2141 if (node->isFocusable())
2142 context.setFlag(Platform::WebContext::IsFocusable);
2147 Platform::WebContext WebPage::webContext(TargetDetectionStrategy strategy) const
2149 return d->webContext(strategy);
2152 void WebPagePrivate::updateCursor()
2155 if (m_lastMouseEvent.button() == LeftButton)
2156 buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
2157 else if (m_lastMouseEvent.button() == MiddleButton)
2158 buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
2159 else if (m_lastMouseEvent.button() == RightButton)
2160 buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
2162 BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask, mapToTransformed(m_lastMouseEvent.position()), mapToTransformed(m_lastMouseEvent.globalPosition()), 0, 0);
2163 m_webPage->mouseEvent(event);
2166 IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
2168 if (hasVirtualViewport())
2169 return IntSize(m_virtualViewportWidth, m_virtualViewportHeight);
2171 const int defaultLayoutWidth = m_defaultLayoutSize.width();
2172 const int defaultLayoutHeight = m_defaultLayoutSize.height();
2174 int minWidth = defaultLayoutWidth;
2175 int maxWidth = defaultMaxLayoutSize().width();
2176 int maxHeight = defaultMaxLayoutSize().height();
2178 // If the load state is none then we haven't actually got anything yet, but we need to layout
2179 // the entire page so that the user sees the entire page (unrendered) instead of just part of it.
2180 if (m_loadState == None)
2181 return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2183 if (m_viewMode == FixedDesktop) {
2184 int width = maxWidth;
2185 // if the defaultLayoutHeight is at minimum, it probably was set as 0
2186 // and clamped, meaning it's effectively not set. (Even if it happened
2187 // to be set exactly to the minimum, it's too small to be useful.) So
2190 if (defaultLayoutHeight <= minimumLayoutSize.height())
2193 height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2194 return IntSize(width, height);
2197 if (m_viewMode == Desktop) {
2198 // If we detect an overflow larger than the contents size then use that instead since
2199 // it'll still be clamped by the maxWidth below...
2200 int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
2202 if (snapToIncrement) {
2203 // Snap to increments of defaultLayoutWidth / 2.0.
2204 float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
2205 factor = ceilf(factor);
2206 width = (defaultLayoutWidth / 2.0) * factor;
2209 if (width < minWidth)
2211 if (width > maxWidth)
2213 int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2214 return IntSize(width, height);
2217 if (m_webSettings->isZoomToFitOnLoad()) {
2218 // We need to clamp the layout width to the minimum of the layout
2219 // width or the content width. This is important under rotation for mobile
2220 // websites. We want the page to remain layouted at the same width which
2221 // it was loaded with, and instead change the zoom level to fit to screen.
2222 // The height is welcome to adapt to the height used in the new orientation,
2223 // otherwise we will get a grey bar below the web page.
2224 if (m_mainFrame->view() && !contentsSize().isEmpty())
2225 minWidth = contentsSize().width();
2227 // If there is no contents width, use the minimum of screen width
2228 // and layout width to shape the first layout to a contents width
2229 // that we could reasonably zoom to fit, in a manner that takes
2230 // orientation into account and still respects a small default
2232 #if ENABLE(ORIENTATION_EVENTS)
2233 minWidth = m_mainFrame->orientation() % 180
2234 ? Platform::Graphics::Screen::primaryScreen()->height()
2235 : Platform::Graphics::Screen::primaryScreen()->width();
2237 minWidth = Platform::Graphics::Screen::primaryScreen()->width();
2242 return IntSize(std::min(minWidth, defaultLayoutWidth), defaultLayoutHeight);
2245 BackingStoreClient* WebPagePrivate::backingStoreClientForFrame(const Frame* frame) const
2248 BackingStoreClient* backingStoreClient = 0;
2249 if (m_backingStoreClientForFrameMap.contains(frame))
2250 backingStoreClient = m_backingStoreClientForFrameMap.get(frame);
2251 return backingStoreClient;
2254 void WebPagePrivate::addBackingStoreClientForFrame(const Frame* frame, BackingStoreClient* client)
2258 m_backingStoreClientForFrameMap.add(frame, client);
2261 void WebPagePrivate::removeBackingStoreClientForFrame(const Frame* frame)
2264 if (m_backingStoreClientForFrameMap.contains(frame))
2265 m_backingStoreClientForFrameMap.remove(frame);
2269 void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
2271 ASSERT(documentGoingAway);
2272 if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
2273 m_currentContextNode = 0;
2275 if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
2276 m_currentPinchZoomNode = 0;
2278 if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
2279 m_currentBlockZoomAdjustedNode = 0;
2281 if (m_inRegionScrollStartingNode && m_inRegionScrollStartingNode->document() == documentGoingAway)
2282 m_inRegionScrollStartingNode = 0;
2284 Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
2285 if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
2286 m_touchEventHandler->resetLastFatFingersResult();
2288 // NOTE: m_fullscreenVideoNode, m_fullScreenPluginView and m_pluginViews
2289 // are cleared in other methods already.
2292 typedef bool (*PredicateFunction)(RenderLayer*);
2293 static bool isPositionedContainer(RenderLayer* layer)
2295 RenderObject* o = layer->renderer();
2296 return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform();
2299 static bool isNonRenderViewFixedPositionedContainer(RenderLayer* layer)
2301 RenderObject* o = layer->renderer();
2302 if (o->isRenderView())
2305 return o->isPositioned() && o->style()->position() == FixedPosition;
2308 static bool isFixedPositionedContainer(RenderLayer* layer)
2310 RenderObject* o = layer->renderer();
2311 return o->isRenderView() || (o->isPositioned() && o->style()->position() == FixedPosition);
2314 static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
2316 RenderLayer* curr = layer;
2317 while (curr && !predicate(curr))
2318 curr = curr->parent();
2323 RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
2325 return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
2328 RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
2330 return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
2333 static inline Frame* frameForNode(Node* node)
2335 Node* origNode = node;
2336 for (; node; node = node->parentNode()) {
2337 if (RenderObject* renderer = node->renderer()) {
2338 if (renderer->isRenderView()) {
2339 if (FrameView* view = toRenderView(renderer)->frameView()) {
2340 if (Frame* frame = view->frame())
2344 if (renderer->isWidget()) {
2345 Widget* widget = toRenderWidget(renderer)->widget();
2346 if (widget && widget->isFrameView()) {
2347 if (Frame* frame = static_cast<FrameView*>(widget)->frame())
2354 for (node = origNode; node; node = node->parentNode()) {
2355 if (Document* doc = node->document()) {
2356 if (Frame* frame = doc->frame())
2364 static IntRect getNodeWindowRect(Node* node)
2366 if (Frame* frame = frameForNode(node)) {
2367 if (FrameView* view = frame->view())
2368 return view->contentsToWindow(node->getRect());
2370 ASSERT_NOT_REACHED();
2374 IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
2376 ASSERT(m_mainFrame);
2378 // Don't call this function asking to not clip the main frame providing only
2379 // the main frame. All that can be returned is the content rect which
2380 // isn't what this function is for.
2381 if (noClipOfMainFrame && view == m_mainFrame->view()) {
2382 ASSERT_NOT_REACHED();
2383 return IntRect(IntPoint::zero(), view->contentsSize());
2386 IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect(false)));
2387 if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
2388 // Intersect with parent visible rect.
2389 visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
2391 return visibleWindowRect;
2394 void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
2396 ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
2397 ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
2398 ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
2400 // First we clear the focus, since we want to focus either initial or the last
2401 // focusable element in the webpage (according to the TABINDEX), or simply clear
2405 switch (direction) {
2406 case FocusDirectionForward:
2407 case FocusDirectionBackward:
2408 m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
2410 case FocusDirectionNone:
2413 ASSERT_NOT_REACHED();
2417 void WebPage::assignFocus(Platform::FocusDirection direction)
2419 d->assignFocus(direction);
2422 Platform::IntRect WebPagePrivate::focusNodeRect()
2424 Frame* frame = focusedOrMainFrame();
2426 return Platform::IntRect();
2428 Document* doc = frame->document();
2429 FrameView* view = frame->view();
2430 if (!doc || !view || view->needsLayout())
2431 return Platform::IntRect();
2433 IntRect focusRect = rectForNode(doc->focusedNode());
2434 focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
2435 focusRect = mapToTransformed(focusRect);
2436 clipToTransformedContentsRect(focusRect);
2440 PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
2442 EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2443 const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
2444 bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
2446 // Unpress the mouse button always.
2447 if (eventHandler->mousePressed())
2448 eventHandler->setMousePressed(false);
2450 // Check if we're using LinkToLink and the user is not touching the screen.
2451 if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
2453 node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
2455 IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
2456 if (!visibleRect.intersects(getNodeWindowRect(node.get())))
2459 return node.release();
2462 // Check for text input.
2463 if (isTouching && lastFatFingersResult.isTextInput())
2464 return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
2466 IntPoint contentPos;
2468 contentPos = lastFatFingersResult.adjustedPosition();
2470 contentPos = mapFromViewportToContents(m_lastMouseEvent.position());
2472 if (strategy == RectBased) {
2473 FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
2474 return result.node(FatFingersResult::ShadowContentNotAllowed);
2477 HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos, false /*allowShadowContent*/);
2478 return result.innerNode();
2481 static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
2483 // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709).
2484 double dx = static_cast<double>(p1.x() - p2.x());
2485 double dy = static_cast<double>(p1.y() - p2.y());
2486 return sqrt((dx * dx) + (dy * dy));
2489 Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& point)
2491 IntPoint pt = mapFromTransformed(point);
2492 IntRect clickRect(pt.x() - blockClickRadius, pt.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
2493 Node* originalNode = nodeForZoomUnderPoint(point);
2496 Node* node = bestChildNodeForClickRect(originalNode, clickRect);
2497 return node ? adjustedBlockZoomNodeForZoomLimits(node) : adjustedBlockZoomNodeForZoomLimits(originalNode);
2500 Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
2505 int bestDistance = std::numeric_limits<int>::max();
2507 Node* node = parentNode->firstChild();
2509 for (; node; node = node->nextSibling()) {
2510 IntRect rect = rectForNode(node);
2511 if (!clickRect.intersects(rect))
2514 int distance = distanceBetweenPoints(rect.center(), clickRect.center());
2515 Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
2516 if (bestChildNode) {
2517 IntRect bestChildRect = rectForNode(bestChildNode);
2518 int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
2519 if (bestChildDistance < distance && bestChildDistance < bestDistance) {
2520 bestNode = bestChildNode;
2521 bestDistance = bestChildDistance;
2523 if (distance < bestDistance) {
2525 bestDistance = distance;
2529 if (distance < bestDistance) {
2531 bestDistance = distance;
2539 double WebPagePrivate::maxBlockZoomScale() const
2541 return std::min(maximumBlockZoomScale, maximumScale());
2544 Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& point)
2549 HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromTransformed(point), false);
2551 Node* node = result.innerNonSharedNode();
2556 RenderObject* renderer = node->renderer();
2558 node = node->parentNode();
2559 renderer = node->renderer();
2565 Node* WebPagePrivate::adjustedBlockZoomNodeForZoomLimits(Node* node)
2567 Node* initialNode = node;
2568 RenderObject* renderer = node->renderer();
2569 bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2571 while (!renderer || !acceptableNodeSize) {
2572 node = node->parentNode();
2577 renderer = node->renderer();
2578 acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2584 bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
2589 return (n2 == n1) || n2->isDescendantOf(n1);
2592 double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
2595 return std::numeric_limits<double>::max();
2597 ASSERT(rect.width() + margin);
2599 double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
2604 IntRect WebPagePrivate::rectForNode(Node* node)
2609 RenderObject* renderer = node->renderer();
2614 // Return rect in un-transformed content coordinates.
2617 // FIXME: Ensure this works with iframes.
2618 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
2619 RenderBlock* renderBlock = renderer->containingBlock();
2622 while (!renderBlock->isRoot()) {
2623 xOffset += renderBlock->x();
2624 yOffset += renderBlock->y();
2625 renderBlock = renderBlock->containingBlock();
2627 const RenderText* renderText = toRenderText(renderer);
2628 IntRect linesBox = renderText->linesBoundingBox();
2629 blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height());
2631 blockRect = renderer->absoluteClippedOverflowRect();
2633 if (renderer->isText()) {
2634 RenderBlock* rb = renderer->containingBlock();
2636 // Inefficient? Way to find width when floats intersect a block.
2638 int lineCount = rb->lineCount();
2639 for (int i = 0; i < lineCount; i++)
2640 blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false));
2642 blockRect.setWidth(blockWidth);
2643 blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
2646 // Strip off padding.
2647 if (renderer->style()->hasPadding()) {
2648 blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
2649 blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
2650 blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
2651 blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
2657 IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
2661 // FIXME: This function can be called when page is being destroyed and JS triggers selection change.
2662 // We could break the call chain at upper levels, but I think it is better to check the frame pointer
2663 // here because the pointer is explicitly cleared in WebPage::destroy().
2667 // Convert 0,0 in the frame's coordinate system to window coordinates to
2668 // get the frame's global position, and return this position in the main
2669 // frame's coordinates. (So the main frame's coordinates will be 0,0.)
2670 return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
2673 IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
2678 // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames.
2679 // FIXME: can we just use frameOffset instead of this big routine?
2680 const Node* tnode = node;
2681 IntRect adjustedRect = rect;
2683 Frame* frame = tnode->document()->frame();
2687 Node* ownerNode = static_cast<Node*>(frame->ownerElement());
2689 if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
2692 iFrameRect = rectForNode(ownerNode);
2693 adjustedRect.move(iFrameRect.x(), iFrameRect.y());
2694 adjustedRect.intersect(iFrameRect);
2695 ownerNode = ownerNode->parentNode();
2696 } while (iFrameRect.isEmpty() && ownerNode);
2699 } while (tnode = tnode->parentNode());
2701 return adjustedRect;
2704 IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
2706 if (!node || contentsSize().isEmpty())
2710 m_currentBlockZoomAdjustedNode = tnode;
2712 IntRect blockRect = rectForNode(tnode);
2713 IntRect originalRect = blockRect;
2715 int originalArea = originalRect.width() * originalRect.height();
2716 int pageArea = contentsSize().width() * contentsSize().height();
2717 double blockToPageRatio = static_cast<double>(1 - originalArea / pageArea);
2718 double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
2720 if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
2721 while (tnode = tnode->parentNode()) {
2723 IntRect tRect = rectForNode(tnode);
2724 int tempBlockArea = tRect.width() * tRect.height();
2725 // Don't expand the block if it will be too large relative to the content.
2726 if (static_cast<double>(1 - tempBlockArea / pageArea) < minimumExpandingRatio)
2728 if (tRect.isEmpty())
2729 continue; // No renderer.
2730 if (tempBlockArea < 1.1 * originalArea)
2731 continue; // The size of this parent is very close to the child, no need to go to this parent.
2732 // Don't expand the block if the parent node size is already almost the size of actual visible size.
2733 IntSize actualSize = actualVisibleSize();
2734 if (static_cast<double>(1 - tRect.width() / actualSize.width()) < minimumExpandingRatio)
2736 if (tempBlockArea < blockExpansionRatio * originalArea) {
2738 m_currentBlockZoomAdjustedNode = tnode;
2744 blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
2745 blockRect = mapToTransformed(blockRect);
2746 clipToTransformedContentsRect(blockRect);
2748 #if DEBUG_BLOCK_ZOOM
2749 // Re-paint the backingstore to screen to erase other annotations.
2750 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::Blit);
2752 // Render a black square over the calculated block and a gray square over the original block for visual inspection.
2753 originalRect = mapToTransformed(originalRect);
2754 clipToTransformedContentsRect(originalRect);
2755 IntRect renderRect = mapFromTransformedContentsToTransformedViewport(blockRect);
2756 IntRect originalRenderRect = mapFromTransformedContentsToTransformedViewport(originalRect);
2757 IntSize viewportSize = transformedViewportSize();
2758 renderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
2759 originalRenderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
2760 m_backingStore->d->clearWindow(renderRect, 0, 0, 0);
2761 m_backingStore->d->clearWindow(originalRenderRect, 120, 120, 120);
2762 m_backingStore->d->invalidateWindow(renderRect);
2768 // This function should not be called directly.
2769 // It is called after the animation ends (see above).
2770 void WebPagePrivate::zoomBlock()
2775 IntPoint anchor(roundUntransformedPoint(mapFromTransformedFloatPoint(m_finalBlockPoint)));
2776 bool willUseTextReflow = false;
2778 #if ENABLE(VIEWPORT_REFLOW)
2779 willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
2780 toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
2784 TransformationMatrix zoom;
2785 zoom.scale(m_blockZoomFinalScale);
2786 *m_transformationMatrix = zoom;
2787 m_client->resetBitmapZoomScale(m_blockZoomFinalScale);
2788 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
2789 updateViewportSize();
2791 #if ENABLE(VIEWPORT_REFLOW)
2792 requestLayoutIfNeeded();
2793 if (willUseTextReflow && m_shouldReflowBlock) {
2794 IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
2795 reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
2796 reflowedRect.move(roundTransformedPoint(m_finalBlockPointReflowOffset).x(), roundTransformedPoint(m_finalBlockPointReflowOffset).y());
2797 RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
2798 IntPoint topLeftPoint(reflowedRect.location());
2799 if (renderer && renderer->isText()) {
2800 ETextAlign textAlign = renderer->style()->textAlign();
2801 IntPoint textAnchor;
2802 switch (textAlign) {
2805 textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
2809 textAnchor = topLeftPoint;
2813 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
2818 if (renderer->style()->isLeftToRightDirection())
2819 textAnchor = topLeftPoint;
2821 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
2824 setScrollPosition(textAnchor);
2826 renderer->style()->isLeftToRightDirection()
2827 ? setScrollPosition(topLeftPoint)
2828 : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
2830 } else if (willUseTextReflow) {
2831 IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
2832 finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
2833 setScrollPosition(IntPoint(0, finalRect.y() + m_finalBlockPointReflowOffset.y()));
2837 if (!willUseTextReflow) {
2838 setScrollPosition(anchor);
2839 if (!m_shouldReflowBlock)
2843 notifyTransformChanged();
2844 m_backingStore->d->clearWindow();
2845 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
2846 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
2849 void WebPage::blockZoomAnimationFinished()
2854 void WebPagePrivate::resetBlockZoom()
2856 m_currentBlockZoomNode = 0;
2857 m_currentBlockZoomAdjustedNode = 0;
2858 m_shouldReflowBlock = false;
2861 void WebPage::destroyWebPageCompositor()
2863 #if USE(ACCELERATED_COMPOSITING)
2864 // Destroy the layer renderer in a sync command before we destroy the backing store,
2865 // to flush any pending compositing messages on the compositing thread.
2866 // The backing store is indirectly deleted by the 'detachFromParent' call below.
2867 d->syncDestroyCompositorOnCompositingThread();
2871 void WebPage::destroy()
2873 // TODO: need to verify if this call needs to be made before calling
2874 // WebPage::destroyWebPageCompositor()
2875 d->m_backingStore->d->suspendScreenAndBackingStoreUpdates();
2877 // Close the backforward list and release the cached pages.
2878 d->m_page->backForward()->close();
2879 pageCache()->releaseAutoreleasedPagesNow();
2881 FrameLoader* loader = d->m_mainFrame->loader();
2883 // Remove main frame's backing store client from the map
2884 // to prevent FrameLoaderClientBlackyBerry::detachFromParent2(),
2885 // which is called by loader->detachFromParent(), deleting it.
2886 // We will delete it in ~WebPagePrivate().
2887 // Reason: loader->detachFromParent() may ping back to backing store
2888 // indirectly through ChromeClientBlackBerry::invalidateContentsAndWindow().
2889 // see RIM PR #93256.
2890 d->removeBackingStoreClientForFrame(d->m_mainFrame);
2892 // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion.
2895 loader->detachFromParent();
2900 WebPageClient* WebPage::client() const
2905 int WebPage::backForwardListLength() const
2907 return d->m_page->getHistoryLength();
2910 bool WebPage::canGoBackOrForward(int delta) const
2912 return d->m_page->canGoBackOrForward(delta);
2915 bool WebPage::goBackOrForward(int delta)
2917 if (d->m_page->canGoBackOrForward(delta)) {
2918 d->m_page->goBackOrForward(delta);
2924 void WebPage::goToBackForwardEntry(BackForwardId id)
2926 HistoryItem* item = historyItemFromBackForwardId(id);
2928 d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
2931 void WebPage::reload()
2933 d->m_mainFrame->loader()->reload(/* bypassCache */ true);
2936 void WebPage::reloadFromCache()
2938 d->m_mainFrame->loader()->reload(/* bypassCache */ false);
2941 WebSettings* WebPage::settings() const
2943 return d->m_webSettings;
2946 bool WebPage::isVisible() const
2948 return d->m_visible;
2951 #if ENABLE(PAGE_VISIBILITY_API)
2952 void WebPagePrivate::setPageVisibilityState()
2954 static bool s_initialVisibilityState = true;
2956 m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
2957 s_initialVisibilityState = false;
2961 void WebPagePrivate::setVisible(bool visible)
2963 m_visible = visible;
2965 #if ENABLE(PAGE_VISIBILITY_API)
2966 setPageVisibilityState();
2970 void WebPage::setVisible(bool visible)
2972 if (d->m_visible == visible)
2975 d->setVisible(visible);
2978 d->suspendBackingStore();
2980 // Remove this WebPage from the visible pages list.
2981 size_t foundIndex = visibleWebPages()->find(this);
2982 if (foundIndex != WTF::notFound)
2983 visibleWebPages()->remove(foundIndex);
2985 // Return the backing store to the last visible WebPage.
2986 if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
2987 visibleWebPages()->last()->d->resumeBackingStore();
2989 #if USE(ACCELERATED_COMPOSITING)
2990 // Root layer commit is not necessary for invisible tabs.
2991 // And release layer resources can reduce memory consumption.
2992 d->suspendRootLayerCommit();
2997 #if USE(ACCELERATED_COMPOSITING)
2998 d->resumeRootLayerCommit();
3001 // Push this WebPage to the top of the visible pages list.
3002 if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
3003 size_t foundIndex = visibleWebPages()->find(this);
3004 if (foundIndex != WTF::notFound)
3005 visibleWebPages()->remove(foundIndex);
3007 visibleWebPages()->append(this);
3009 if (BackingStorePrivate::currentBackingStoreOwner()
3010 && BackingStorePrivate::currentBackingStoreOwner() != this)
3011 BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
3013 // resumeBackingStore will set the current owner to this webpage.
3014 // If we set the owner prematurely, then the tiles will not be reset.
3015 d->resumeBackingStore();
3018 void WebPagePrivate::selectionChanged(Frame* frame)
3020 m_inputHandler->selectionChanged();
3022 // FIXME: This is a hack!
3023 // To ensure the selection being changed has its frame 'focused', lets
3024 // set it as focused ourselves (PR #104724).
3025 m_page->focusController()->setFocusedFrame(frame);
3028 void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
3030 // Track a dispatched message, we don't want to flood the webkit thread.
3031 // There can be as many as one more message enqued as needed but never less.
3033 m_updateDelegatedOverlaysDispatched = false;
3034 else if (m_updateDelegatedOverlaysDispatched) {
3035 // Early return if there is message already pending on the webkit thread.
3039 if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
3040 // Must be called on the WebKit thread.
3041 if (m_selectionHandler->isSelectionActive())
3042 m_selectionHandler->selectionPositionChanged(true /* visualChangeOnly */);
3044 } else if (m_selectionHandler->isSelectionActive()) {
3045 // Don't bother dispatching to webkit thread if selection and tap highlight are not active.
3046 m_updateDelegatedOverlaysDispatched = true;
3047 Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/));
3051 void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle style)
3055 bool WebPage::setBatchEditingActive(bool active)
3057 return d->m_inputHandler->setBatchEditingActive(active);
3060 bool WebPage::setInputSelection(unsigned start, unsigned end)
3062 return d->m_inputHandler->setSelection(start, end);
3065 int WebPage::inputCaretPosition() const
3067 return d->m_inputHandler->caretPosition();
3070 void WebPage::popupListClosed(int size, bool* selecteds)
3072 d->m_inputHandler->setPopupListIndexes(size, selecteds);
3075 void WebPage::popupListClosed(int index)
3077 d->m_inputHandler->setPopupListIndex(index);
3080 void WebPage::setDateTimeInput(const WebString& value)
3082 d->m_inputHandler->setInputValue(String(value.impl()));
3085 void WebPage::setColorInput(const WebString& value)
3087 d->m_inputHandler->setInputValue(String(value.impl()));
3090 void WebPage::setVirtualViewportSize(int width, int height)
3092 d->m_virtualViewportWidth = width;
3093 d->m_virtualViewportHeight = height;
3096 void WebPage::resetVirtualViewportOnCommitted(bool reset)
3098 d->m_resetVirtualViewportOnCommitted = reset;
3101 IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments()
3103 static ViewportArguments defaultViewportArguments;
3104 if (m_viewportArguments == defaultViewportArguments)
3107 int desktopWidth = defaultMaxLayoutSize().width();
3108 int deviceWidth = Platform::Graphics::Screen::primaryScreen()->width();
3109 int deviceHeight = Platform::Graphics::Screen::primaryScreen()->height();
3110 FloatSize currentPPI = Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(-1);
3111 int deviceDPI = int(roundf((currentPPI.width() + currentPPI.height()) / 2));
3112 if (m_viewportArguments.targetDensityDpi == ViewportArguments::ValueAuto
3113 && !Platform::DeviceInfo::instance()->isMobile()) {
3114 // If the content provider hasn't specified a target dpi and we have a large
3115 // screen we assume the content is fine and set the targetDensityDpi to our dpi.
3116 // On smaller screen mobile devices we skip this and use WebCore dpi scaling.
3117 m_viewportArguments.targetDensityDpi = deviceDPI;
3120 ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, deviceDPI, m_defaultLayoutSize);
3121 m_page->setDeviceScaleFactor(result.devicePixelRatio);
3122 return IntSize(result.layoutSize.width(), result.layoutSize.height());
3125 #if ENABLE(EVENT_MODE_METATAGS)
3126 void WebPagePrivate::didReceiveCursorEventMode(CursorEventMode mode)
3128 if (mode != m_cursorEventMode)
3129 m_client->cursorEventModeChanged(toPlatformCursorEventMode(mode));
3130 m_cursorEventMode = mode;
3133 void WebPagePrivate::didReceiveTouchEventMode(TouchEventMode mode)
3135 if (mode != m_touchEventMode)
3136 m_client->touchEventModeChanged(toPlatformTouchEventMode(mode));
3137 m_touchEventMode = mode;
3141 void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments)
3143 static ViewportArguments defaultViewportArguments;
3144 if (arguments == defaultViewportArguments)
3147 m_viewportArguments = arguments;
3149 // 0 width or height in viewport arguments makes no sense, and results in a very large initial scale.
3150 // In real world, a 0 width or height is usually caused by a syntax error in "content" field of viewport
3151 // meta tag, for example, using semicolon instead of comma as separator ("width=device-width; initial-scale=1.0").
3152 // We don't have a plan to tolerate the semicolon separator, but we can avoid applying 0 width/height.
3153 // I default it to ValueDeviceWidth rather than ValueAuto because in more cases the web site wants "device-width"
3154 // when they specify the viewport width.
3155 if (!m_viewportArguments.width)
3156 m_viewportArguments.width = ViewportArguments::ValueDeviceWidth;
3157 if (!m_viewportArguments.height)
3158 m_viewportArguments.height = ViewportArguments::ValueDeviceHeight;
3160 setUserScalable(arguments.userScalable == ViewportArguments::ValueAuto ? true : arguments.userScalable);
3161 if (arguments.initialScale > 0)
3162 setInitialScale(arguments.initialScale);
3163 if (arguments.minimumScale > 0)
3164 setMinimumScale(arguments.minimumScale);
3165 if (arguments.maximumScale > 0)
3166 setMaximumScale(arguments.maximumScale);
3168 IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
3169 m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
3171 if (loadState() == WebKit::WebPagePrivate::Committed)
3172 zoomToInitialScaleOnLoad();
3175 void WebPagePrivate::onInputLocaleChanged(bool isRTL)
3177 if (isRTL != m_webSettings->isWritingDirectionRTL()) {
3178 m_webSettings->setWritingDirectionRTL(isRTL);
3179 m_inputHandler->handleInputLocaleChanged(isRTL);
3183 void WebPage::onInputLocaleChanged(bool isRTL)
3185 d->onInputLocaleChanged(isRTL);
3188 void WebPagePrivate::suspendBackingStore()
3190 #if USE(ACCELERATED_COMPOSITING)
3191 resetCompositingSurface();
3195 void WebPagePrivate::resumeBackingStore()
3197 ASSERT(m_webPage->isVisible());
3199 #if USE(ACCELERATED_COMPOSITING)
3200 setNeedsOneShotDrawingSynchronization();
3203 bool directRendering = m_backingStore->d->shouldDirectRenderingToWindow();
3204 if (!m_backingStore->d->isActive()
3205 || shouldResetTilesWhenShown()
3206 || directRendering) {
3207 // We need to reset all tiles so that we do not show any tiles whose content may
3208 // have been replaced by another WebPage instance (i.e. another tab).
3209 BackingStorePrivate::setCurrentBackingStoreOwner(m_webPage);
3210 m_backingStore->d->orientationChanged(); // Updates tile geometry and creates visible tile buffer.
3211 m_backingStore->d->resetTiles(true /* resetBackground */);
3212 m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
3213 // This value may have changed, so we need to update it.
3214 directRendering = m_backingStore->d->shouldDirectRenderingToWindow();
3215 if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !directRendering)
3216 m_backingStore->d->blitVisibleContents();
3218 // Rendering was disabled while we were hidden, so we need to update all tiles.
3219 m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
3222 setShouldResetTilesWhenShown(false);
3225 void WebPagePrivate::setScreenOrientation(int orientation)
3227 FOR_EACH_PLUGINVIEW(m_pluginViews)
3228 (*it)->handleOrientationEvent(orientation);
3230 m_pendingOrientation = -1;
3232 #if ENABLE(ORIENTATION_EVENTS)
3233 if (m_mainFrame->orientation() == orientation)
3235 for (RefPtr<Frame> frame = m_mainFrame; frame; frame = frame->tree()->traverseNext())
3236 frame->sendOrientationChangeEvent(orientation);
3240 void WebPage::setScreenOrientation(int orientation)
3242 d->m_pendingOrientation = orientation;
3245 void WebPage::applyPendingOrientationIfNeeded()
3247 if (d->m_pendingOrientation != -1)
3248 d->setScreenOrientation(d->m_pendingOrientation);
3251 void WebPagePrivate::screenRotated()
3253 // This call will cause the client to reallocate the window buffer to new size,
3254 // which needs to be serialized with usage of the window buffer. Accomplish
3255 // this by sending a sync message to the compositing thread. All other usage of
3256 // the window buffer happens on the compositing thread.
3257 if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
3258 Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
3259 Platform::createMethodCallMessage(&WebPagePrivate::screenRotated, this));
3263 SurfacePool::globalSurfacePool()->notifyScreenRotated();
3264 m_client->notifyScreenRotated();
3267 void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize, bool ensureFocusElementVisible)
3269 if (m_pendingOrientation == -1 && transformedActualVisibleSize == this->transformedActualVisibleSize())
3272 // Suspend all screen updates to the backingstore to make sure no-one tries to blit
3273 // while the window surface and the BackingStore are out of sync.
3274 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3276 // The screen rotation is a major state transition that in this case is not properly
3277 // communicated to the backing store, since it does early return in most methods when
3279 if (!m_visible || !m_backingStore->d->isActive())
3280 setShouldResetTilesWhenShown(true);
3282 bool hasPendingOrientation = m_pendingOrientation != -1;
3283 if (hasPendingOrientation)
3286 // The window buffers might have been recreated, cleared, moved, etc., so:
3287 m_backingStore->d->windowFrontBufferState()->clearBlittedRegion();
3288 m_backingStore->d->windowBackBufferState()->clearBlittedRegion();
3290 IntSize viewportSizeBefore = actualVisibleSize();
3291 FloatPoint centerOfVisibleContentsRect = this->centerOfVisibleContentsRect();
3292 bool newVisibleRectContainsOldVisibleRect = (m_actualVisibleHeight <= transformedActualVisibleSize.height())
3293 && (m_actualVisibleWidth <= transformedActualVisibleSize.width());
3295 bool atInitialScale = m_webPage->isAtInitialZoom();
3296 bool atTop = !scrollPosition().y();
3297 bool atLeft = !scrollPosition().x();
3299 // We need to reorient the visibleTileRect because the following code
3300 // could cause BackingStore::transformChanged to be called, where it
3302 // It is only dependent on the transformedViewportSize which has been
3304 m_backingStore->d->createVisibleTileBuffer();
3306 setDefaultLayoutSize(transformedActualVisibleSize);
3308 // Recompute our virtual viewport.
3309 bool needsLayout = false;
3310 static ViewportArguments defaultViewportArguments;
3311 if (!(m_viewportArguments == defaultViewportArguments)) {
3312 // We may need to infer the width and height for the viewport with respect to the rotation.
3313 IntSize newVirtualViewport = recomputeVirtualViewportFromViewportArguments();
3314 ASSERT(!newVirtualViewport.isEmpty());
3315 m_webPage->setVirtualViewportSize(newVirtualViewport.width(), newVirtualViewport.height());
3316 m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
3317 m_mainFrame->view()->setFixedLayoutSize(fixedLayoutSize());
3321 // We switch this strictly after recomputing our virtual viewport as zoomToFitScale is dependent
3322 // upon these values and so is the virtual viewport recalculation.
3323 m_actualVisibleWidth = transformedActualVisibleSize.width();
3324 m_actualVisibleHeight = transformedActualVisibleSize.height();
3326 IntSize viewportSizeAfter = actualVisibleSize();
3328 IntPoint offset(roundf((viewportSizeBefore.width() - viewportSizeAfter.width()) / 2.0),
3329 roundf((viewportSizeBefore.height() - viewportSizeAfter.height()) / 2.0));
3331 // As a special case, if we were anchored to the top left position at
3332 // the beginning of the rotation then preserve that anchor.
3338 // If we're about to overscroll, cap the offset to valid content.
3339 IntPoint bottomRight(
3340 scrollPosition().x() + viewportSizeAfter.width(),
3341 scrollPosition().y() + viewportSizeAfter.height());
3343 if (bottomRight.x() + offset.x() > contentsSize().width())
3344 offset.setX(contentsSize().width() - bottomRight.x());
3345 if (bottomRight.y() + offset.y() > contentsSize().height())
3346 offset.setY(contentsSize().height() - bottomRight.y());
3347 if (scrollPosition().x() + offset.x() < 0)
3348 offset.setX(-scrollPosition().x());
3349 if (scrollPosition().y() + offset.y() < 0)
3350 offset.setY(-scrollPosition().y());
3352 // ...before scrolling, because the backing store will align its
3353 // tile matrix with the viewport as reported by the ScrollView.
3354 scrollBy(offset.x(), offset.y());
3355 notifyTransformedScrollChanged();
3357 m_backingStore->d->orientationChanged();
3358 m_backingStore->d->actualVisibleSizeChanged(transformedActualVisibleSize);
3360 // Update view mode only after we have updated the actual
3361 // visible size and reset the contents rect if necessary.
3362 if (setViewMode(viewMode()))
3365 bool needsLayoutToFindContentSize = hasPendingOrientation;
3367 // We need to update the viewport size of the WebCore::ScrollView...
3368 updateViewportSize(!needsLayoutToFindContentSize /* setFixedReportedSize */, false /* sendResizeEvent */);
3369 notifyTransformedContentsSizeChanged();
3371 // If automatic zooming is disabled, prevent zooming below.
3372 if (!m_webSettings->isZoomToFitOnLoad()) {
3373 atInitialScale = false;
3375 // Normally, if the contents size is smaller than the layout width,
3376 // we would zoom in. If zoom is disabled, we need to do something else,
3377 // or there will be artifacts due to non-rendered areas outside of the
3378 // contents size. If there is a virtual viewport, we are not allowed
3379 // to modify the fixed layout size, however.
3380 if (!hasVirtualViewport() && contentsSize().width() < m_defaultLayoutSize.width()) {
3381 m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
3382 m_mainFrame->view()->setFixedLayoutSize(m_defaultLayoutSize);
3390 // Need to resume so that the backingstore will start recording the invalidated
3391 // rects from below.
3392 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
3394 // We might need to layout here to get a correct contentsSize so that zoomToFit
3395 // is calculated correctly.
3396 requestLayoutIfNeeded();
3398 // As a special case if we were zoomed to the initial scale at the beginning
3399 // of the rotation then preserve that zoom level even when it is zoomToFit.
3400 double scale = atInitialScale ? initialScale() : currentScale();
3402 // Do our own clamping.
3403 scale = clampedScale(scale);
3405 if (needsLayoutToFindContentSize) {
3406 // Set the fixed reported size here so that innerWidth|innerHeight works
3407 // with this new scale.
3408 TransformationMatrix rotationMatrix;
3409 rotationMatrix.scale(scale);
3410 IntRect viewportRect = IntRect(IntPoint::zero(), transformedActualVisibleSize);
3411 IntRect actualVisibleRect = enclosingIntRect(rotationMatrix.inverse().mapRect(FloatRect(viewportRect)));
3412 m_mainFrame->view()->setFixedReportedSize(actualVisibleRect.size());
3413 m_mainFrame->view()->repaintFixedElementsAfterScrolling();
3416 // We're going to need to send a resize event to JavaScript because
3417 // innerWidth and innerHeight depend on fixed reported size.
3418 // This is how we support mobile pages where JavaScript resizes
3419 // the page in order to get around the fixed layout size, e.g.
3420 // google maps when it detects a mobile user agent.
3421 if (shouldSendResizeEvent())
3422 m_mainFrame->eventHandler()->sendResizeEvent();
3424 // As a special case if we were anchored to the top left position at the beginning
3425 // of the rotation then preserve that anchor.
3426 FloatPoint anchor = centerOfVisibleContentsRect;
3432 // Try and zoom here with clamping on.
3433 if (m_backingStore->d->shouldDirectRenderingToWindow()) {
3434 bool success = zoomAboutPoint(scale, anchor, false /* enforceScaleClamping */, true /* forceRendering */);
3435 if (!success && ensureFocusElementVisible)
3436 ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3437 } else if (!scheduleZoomAboutPoint(scale, anchor, false /* enforceScaleClamping */, true /* forceRendering */)) {
3438 // Suspend all screen updates to the backingstore.
3439 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3441 // If the zoom failed, then we should still preserve the special case of scroll position.
3442 IntPoint scrollPosition = this->scrollPosition();
3444 scrollPosition.setY(0);
3446 scrollPosition.setX(0);
3447 setScrollPosition(scrollPosition);
3449 // These might have been altered even if we didn't zoom so notify the client.
3450 notifyTransformedContentsSizeChanged();
3451 notifyTransformedScrollChanged();
3454 // The visible tiles for scroll must be up-to-date before we blit since we are not performing a layout.
3455 m_backingStore->d->updateTilesForScrollOrNotRenderedRegion();
3458 if (ensureFocusElementVisible)
3459 ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3462 m_backingStore->d->resetTiles(true);
3463 m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
3466 // If we need layout then render and blit, otherwise just blit as our viewport has changed.
3467 m_backingStore->d->resumeScreenAndBackingStoreUpdates(needsLayout ? BackingStore::RenderAndBlit : BackingStore::Blit);
3468 } else if (ensureFocusElementVisible)
3469 ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3472 void WebPage::setViewportSize(const Platform::IntSize& viewportSize, bool ensureFocusElementVisible)
3474 d->setViewportSize(viewportSize, ensureFocusElementVisible);
3477 void WebPagePrivate::setDefaultLayoutSize(const IntSize& size)
3479 IntSize screenSize = Platform::Graphics::Screen::primaryScreen()->size();
3480 ASSERT(size.width() <= screenSize.width() && size.height() <= screenSize.height());