diff options
| author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
|---|---|---|
| committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
| commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
| tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebKit/blackberry/Api/WebPage.cpp | |
| parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
| download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz | |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebKit/blackberry/Api/WebPage.cpp')
| -rw-r--r-- | Source/WebKit/blackberry/Api/WebPage.cpp | 6316 |
1 files changed, 0 insertions, 6316 deletions
diff --git a/Source/WebKit/blackberry/Api/WebPage.cpp b/Source/WebKit/blackberry/Api/WebPage.cpp deleted file mode 100644 index 08af55b11..000000000 --- a/Source/WebKit/blackberry/Api/WebPage.cpp +++ /dev/null @@ -1,6316 +0,0 @@ -/* - * Copyright (C) 2009, 2010, 2011, 2012, 2013 Research In Motion Limited. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "WebPage.h" - -#include "APIShims.h" -#include "ApplicationCacheStorage.h" -#include "AuthenticationChallengeManager.h" -#include "AutofillManager.h" -#include "BackForwardController.h" -#include "BackForwardListBlackBerry.h" -#include "BackingStoreClient.h" -#include "BackingStore_p.h" -#if ENABLE(BATTERY_STATUS) -#include "BatteryClientBlackBerry.h" -#endif -#include "CachedImage.h" -#include "Chrome.h" -#include "ChromeClientBlackBerry.h" -#include "CookieManager.h" -#include "CredentialManager.h" -#include "CredentialStorage.h" -#include "CredentialTransformData.h" -#include "DOMSupport.h" -#include "DatabaseManager.h" -#include "DefaultTapHighlight.h" -#include "DeviceMotionClientBlackBerry.h" -#include "DeviceOrientationClientBlackBerry.h" -#if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD -#include "DeviceOrientationClientMock.h" -#endif -#include "DragClientBlackBerry.h" -// FIXME: We should be using DumpRenderTreeClient, but I'm not sure where we should -// create the DRT_BB object. See PR #120355. -#if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD -#include "DumpRenderTreeBlackBerry.h" -#endif -#include "EditorClientBlackBerry.h" -#include "FocusController.h" -#include "Frame.h" -#include "FrameLoadRequest.h" -#include "FrameLoaderClientBlackBerry.h" -#if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD -#include "GeolocationClientMock.h" -#endif -#include "GeolocationClientBlackBerry.h" -#include "GroupSettings.h" -#include "HTMLAreaElement.h" -#include "HTMLFrameOwnerElement.h" -#include "HTMLImageElement.h" -#include "HTMLInputElement.h" -#include "HTMLMediaElement.h" -#include "HTMLNames.h" -#include "HTMLParserIdioms.h" -#include "HTMLTextAreaElement.h" -#include "HTTPParsers.h" -#include "HistoryItem.h" -#include "IconDatabaseClientBlackBerry.h" -#include "ImageDocument.h" -#include "InPageSearchManager.h" -#include "InRegionScrollableArea.h" -#include "InRegionScroller_p.h" -#include "InputHandler.h" -#include "InspectorBackendDispatcher.h" -#include "InspectorClientBlackBerry.h" -#include "InspectorController.h" -#include "InspectorInstrumentation.h" -#include "InspectorOverlay.h" -#include "JavaScriptVariant_p.h" -#include "LayerWebKitThread.h" -#include "LocalFileSystem.h" -#if ENABLE(NETWORK_INFO) -#include "NetworkInfoClientBlackBerry.h" -#endif -#include "NetworkManager.h" -#include "NodeRenderStyle.h" -#include "NodeTraversal.h" -#if ENABLE(NAVIGATOR_CONTENT_UTILS) -#include "NavigatorContentUtilsClientBlackBerry.h" -#endif -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) -#include "NotificationClientBlackBerry.h" -#endif -#include "Page.h" -#include "PageCache.h" -#include "PageGroup.h" -#include "PagePopup.h" -#include "PagePopupClient.h" -#include "PlatformTouchEvent.h" -#include "PlatformWheelEvent.h" -#include "PluginDatabase.h" -#include "PluginView.h" -#include "RenderLayerBacking.h" -#include "RenderLayerCompositor.h" -#if ENABLE(FULLSCREEN_API) -#include "RenderFullScreen.h" -#endif -#include "RenderText.h" -#include "RenderThemeBlackBerry.h" -#include "RenderTreeAsText.h" -#include "RenderView.h" -#include "RenderWidget.h" -#include "ScriptController.h" -#include "ScriptSourceCode.h" -#include "ScriptValue.h" -#include "ScrollTypes.h" -#include "SecurityPolicy.h" -#include "SelectionHandler.h" -#include "SelectionOverlay.h" -#include "Settings.h" -#include "Storage.h" -#include "StorageNamespace.h" -#include "SurfacePool.h" -#include "Text.h" -#include "ThreadCheck.h" -#include "TouchEventHandler.h" -#include "TransformationMatrix.h" -#if ENABLE(MEDIA_STREAM) -#include "UserMediaClientImpl.h" -#endif -#if ENABLE(VIBRATION) -#include "VibrationClientBlackBerry.h" -#endif -#include "VisiblePosition.h" -#include "WebCookieJar.h" -#include "WebKitThreadViewportAccessor.h" -#include "WebKitVersion.h" -#include "WebOverlay.h" -#include "WebOverlay_p.h" -#include "WebPageClient.h" -#include "WebSocket.h" -#include "WebViewportArguments.h" -#include "npapi.h" -#include "runtime_root.h" - -#if ENABLE(VIDEO) -#include "MediaPlayer.h" -#include "MediaPlayerPrivateBlackBerry.h" -#endif - -#if USE(ACCELERATED_COMPOSITING) -#include "FrameLayers.h" -#include "WebPageCompositorClient.h" -#include "WebPageCompositor_p.h" -#endif - -#include <BlackBerryPlatformDeviceInfo.h> -#include <BlackBerryPlatformExecutableMessage.h> -#include <BlackBerryPlatformKeyboardEvent.h> -#include <BlackBerryPlatformMessageClient.h> -#include <BlackBerryPlatformMouseEvent.h> -#include <BlackBerryPlatformScreen.h> -#include <BlackBerryPlatformSettings.h> -#include <BlackBerryPlatformWebFileSystem.h> -#include <JavaScriptCore/APICast.h> -#include <JavaScriptCore/JSContextRef.h> -#include <JavaScriptCore/JSStringRef.h> -#include <SharedPointer.h> -#include <cmath> -#include <sys/keycodes.h> -#include <unicode/ustring.h> // platform ICU - -#include <wtf/text/CString.h> - -#ifndef USER_PROCESSES -#include <memalloc.h> -#endif - -#if ENABLE(REQUEST_ANIMATION_FRAME) -#include "PlatformScreen.h" -#endif - -#define DEBUG_TOUCH_EVENTS 0 -#define DEBUG_WEBPAGE_LOAD 0 -#define DEBUG_AC_COMMIT 0 - -using namespace std; -using namespace WebCore; - -typedef const unsigned short* CUShortPtr; - -namespace BlackBerry { -namespace WebKit { - -static Vector<WebPage*>* visibleWebPages() -{ - static Vector<WebPage*>* s_visibleWebPages = 0; // Initially, no web page is visible. - if (!s_visibleWebPages) - s_visibleWebPages = new Vector<WebPage*>; - return s_visibleWebPages; -} - -const unsigned blockZoomMargin = 3; // Add 3 pixel margin on each side. -static int blockClickRadius = 0; -static double maximumBlockZoomScale = 3; // This scale can be clamped by the maximumScale set for the page. - -const double manualScrollInterval = 0.1; // The time interval during which we associate user action with scrolling. - -const IntSize minimumLayoutSize(10, 10); // Needs to be a small size, greater than 0, that we can grow the layout from. - -const double minimumExpandingRatio = 0.15; - -const double minimumZoomToFitScale = 0.25; -const double maximumImageDocumentZoomToFitScale = 2; - -// Helper function to parse a URL and fill in missing parts. -static KURL parseUrl(const String& url) -{ - String urlString(url); - KURL kurl = KURL(KURL(), urlString); - if (kurl.protocol().isEmpty()) { - urlString.insert("http://", 0); - kurl = KURL(KURL(), urlString); - } - - return kurl; -} - -// Helper functions to convert to and from WebCore types. -static inline WebCore::PlatformEvent::Type toWebCoreMouseEventType(const BlackBerry::Platform::MouseEvent::Type type) -{ - switch (type) { - case BlackBerry::Platform::MouseEvent::MouseButtonDown: - return WebCore::PlatformEvent::MousePressed; - case Platform::MouseEvent::MouseButtonUp: - return WebCore::PlatformEvent::MouseReleased; - case Platform::MouseEvent::MouseMove: - default: - return WebCore::PlatformEvent::MouseMoved; - } -} - -static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy) -{ - switch (policy) { - case Platform::NetworkRequest::UseProtocolCachePolicy: - return UseProtocolCachePolicy; - case Platform::NetworkRequest::ReloadIgnoringCacheData: - return ReloadIgnoringCacheData; - case Platform::NetworkRequest::ReturnCacheDataElseLoad: - return ReturnCacheDataElseLoad; - case Platform::NetworkRequest::ReturnCacheDataDontLoad: - return ReturnCacheDataDontLoad; - default: - ASSERT_NOT_REACHED(); - return UseProtocolCachePolicy; - } -} - -#if ENABLE(EVENT_MODE_METATAGS) -static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode) -{ - switch (mode) { - case ProcessedCursorEvents: - return Platform::ProcessedCursorEvents; - case NativeCursorEvents: - return Platform::NativeCursorEvents; - default: - ASSERT_NOT_REACHED(); - return Platform::ProcessedCursorEvents; - } -} - -static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode) -{ - switch (mode) { - case ProcessedTouchEvents: - return Platform::ProcessedTouchEvents; - case NativeTouchEvents: - return Platform::NativeTouchEvents; - case PureTouchEventsWithMouseConversion: - return Platform::PureTouchEventsWithMouseConversion; - default: - ASSERT_NOT_REACHED(); - return Platform::ProcessedTouchEvents; - } -} -#endif - -static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id) -{ - return reinterpret_cast<HistoryItem*>(id); -} - -static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item) -{ - return reinterpret_cast<WebPage::BackForwardId>(item); -} - -void WebPage::setUserViewportArguments(const WebViewportArguments& viewportArguments) -{ - d->m_userViewportArguments = *(viewportArguments.d); -} - -void WebPage::resetUserViewportArguments() -{ - d->m_userViewportArguments = ViewportArguments(); -} - -template <bool WebPagePrivate::* isActive> -class DeferredTask: public WebPagePrivate::DeferredTaskBase { -public: - static void finishOrCancel(WebPagePrivate* webPagePrivate) - { - webPagePrivate->*isActive = false; - } -protected: - DeferredTask(WebPagePrivate* webPagePrivate) - : DeferredTaskBase(webPagePrivate, isActive) - { - } - typedef DeferredTask<isActive> DeferredTaskType; -}; - -void WebPage::autofillTextField(const BlackBerry::Platform::String& item) -{ - if (!d->m_webSettings->isFormAutofillEnabled()) - return; - - d->m_autofillManager->autofillTextField(item); -} - -BlackBerry::Platform::String WebPage::renderTreeAsText() -{ - return externalRepresentation(d->m_mainFrame); -} - -WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect) - : m_webPage(webPage) - , m_client(client) - , m_inspectorClient(0) - , m_page(0) // Initialized by init. - , m_mainFrame(0) // Initialized by init. - , m_currentContextNode(0) - , m_webSettings(0) // Initialized by init. - , m_cookieJar(0) - , m_visible(false) - , m_activationState(ActivationActive) - , m_shouldResetTilesWhenShown(false) - , m_shouldZoomToInitialScaleAfterLoadFinished(false) - , m_userScalable(true) - , m_userPerformedManualZoom(false) - , m_userPerformedManualScroll(false) - , m_contentsSizeChanged(false) - , m_overflowExceedsContentsSize(false) - , m_resetVirtualViewportOnCommitted(true) - , m_shouldUseFixedDesktopMode(false) - , m_inspectorEnabled(false) - , m_preventIdleDimmingCount(0) -#if ENABLE(TOUCH_EVENTS) - , m_preventDefaultOnTouchStart(false) -#endif - , m_nestedLayoutFinishedCount(0) - , m_actualVisibleWidth(rect.width()) - , m_actualVisibleHeight(rect.height()) - , m_defaultLayoutSize(minimumLayoutSize) - , m_didRestoreFromPageCache(false) - , m_viewMode(WebPagePrivate::Desktop) // Default to Desktop mode for PB. - , m_loadState(WebPagePrivate::None) - , m_transformationMatrix(new TransformationMatrix()) - , m_backingStore(0) // Initialized by init. - , m_backingStoreClient(0) // Initialized by init. - , m_webkitThreadViewportAccessor(new WebKitThreadViewportAccessor(this)) - , m_inPageSearchManager(new InPageSearchManager(this)) - , m_inputHandler(new InputHandler(this)) - , m_selectionHandler(new SelectionHandler(this)) - , m_touchEventHandler(new TouchEventHandler(this)) - , m_proximityDetector(new ProximityDetector(this)) -#if ENABLE(EVENT_MODE_METATAGS) - , m_cursorEventMode(ProcessedCursorEvents) - , m_touchEventMode(ProcessedTouchEvents) -#endif -#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO) - , m_scaleBeforeFullScreen(-1.0) -#endif - , m_currentCursor(Platform::CursorNone) - , m_dumpRenderTree(0) // Lazy initialization. - , m_initialScale(-1.0) - , m_minimumScale(-1.0) - , m_maximumScale(-1.0) - , m_forceRespectViewportArguments(false) - , m_anchorInNodeRectRatio(-1, -1) - , m_currentBlockZoomNode(0) - , m_currentBlockZoomAdjustedNode(0) - , m_shouldReflowBlock(false) - , m_lastUserEventTimestamp(0.0) - , m_pluginMouseButtonPressed(false) - , m_pluginMayOpenNewTab(false) -#if USE(ACCELERATED_COMPOSITING) - , m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired))) - , m_needsOneShotDrawingSynchronization(false) - , m_needsCommit(false) - , m_suspendRootLayerCommit(false) -#endif - , m_pendingOrientation(-1) - , m_fullscreenNode(0) - , m_hasInRegionScrollableAreas(false) - , m_updateDelegatedOverlaysDispatched(false) - , m_deferredTasksTimer(this, &WebPagePrivate::deferredTasksTimerFired) - , m_pagePopup(0) - , m_autofillManager(AutofillManager::create(this)) - , m_documentStyleRecalcPostponed(false) - , m_documentChildNeedsStyleRecalc(false) -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) - , m_notificationManager(this) -#endif - , m_didStartAnimations(false) - , m_animationStartTime(0) -#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) - , m_isRunningRefreshAnimationClient(false) - , m_animationScheduled(false) - , m_previousFrameDone(true) - , m_monotonicAnimationStartTime(0) -#endif -{ - static bool isInitialized = false; - if (!isInitialized) { - isInitialized = true; - BlackBerry::Platform::DeviceInfo::instance(); - defaultUserAgent(); - } - - AuthenticationChallengeManager::instance()->pageCreated(this); - clearCachedHitTestResult(); -} - -WebPage::WebPage(WebPageClient* client, const BlackBerry::Platform::String& pageGroupName, const Platform::IntRect& rect) -{ - globalInitialize(); - d = new WebPagePrivate(this, client, rect); - d->init(pageGroupName); -} - -WebPagePrivate::~WebPagePrivate() -{ - // Hand the backingstore back to another owner if necessary. - m_webPage->setVisible(false); - if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage) - BackingStorePrivate::setCurrentBackingStoreOwner(0); - -#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) - stopRefreshAnimationClient(); - cancelCallOnMainThread(handleServiceScriptedAnimationsOnMainThread, this); -#endif - - closePagePopup(); - - delete m_webSettings; - m_webSettings = 0; - - delete m_cookieJar; - m_cookieJar = 0; - - delete m_webkitThreadViewportAccessor; - m_webkitThreadViewportAccessor = 0; - - delete m_backingStoreClient; - m_backingStoreClient = 0; - m_backingStore = 0; - - delete m_page; - m_page = 0; - - delete m_transformationMatrix; - m_transformationMatrix = 0; - - delete m_inPageSearchManager; - m_inPageSearchManager = 0; - - delete m_selectionHandler; - m_selectionHandler = 0; - - delete m_inputHandler; - m_inputHandler = 0; - - delete m_touchEventHandler; - m_touchEventHandler = 0; - - delete m_proximityDetector; - m_proximityDetector = 0; - -#if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD - BlackBerry::Platform::deleteGuardedObject(static_cast<DumpRenderTree*>(m_dumpRenderTree)); - m_dumpRenderTree = 0; -#endif - - AuthenticationChallengeManager::instance()->pageDeleted(this); -} - -WebPage::~WebPage() -{ - deleteGuardedObject(d); - d = 0; -} - -Page* WebPagePrivate::core(const WebPage* webPage) -{ - return webPage->d->m_page; -} - -void WebPagePrivate::init(const BlackBerry::Platform::String& pageGroupName) -{ - m_webSettings = WebSettings::createFromStandardSettings(); - m_webSettings->setUserAgentString(defaultUserAgent()); - - ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this); - EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this); - DragClientBlackBerry* dragClient = 0; -#if ENABLE(DRAG_SUPPORT) - dragClient = new DragClientBlackBerry(); -#endif -#if ENABLE(INSPECTOR) - m_inspectorClient = new InspectorClientBlackBerry(this); -#endif - - FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry(); - - Page::PageClients pageClients; - pageClients.chromeClient = chromeClient; - pageClients.editorClient = editorClient; - pageClients.dragClient = dragClient; - pageClients.inspectorClient = m_inspectorClient; - pageClients.backForwardClient = BackForwardListBlackBerry::create(this); - - m_page = new Page(pageClients); -#if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD - if (isRunningDrt()) { - // In case running in DumpRenderTree mode set the controller to mock provider. - GeolocationClientMock* mock = new GeolocationClientMock(); - WebCore::provideGeolocationTo(m_page, mock); - mock->setController(WebCore::GeolocationController::from(m_page)); - } else -#endif - WebCore::provideGeolocationTo(m_page, new GeolocationClientBlackBerry(this)); -#if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD - if (getenv("drtRun")) - WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientMock); - else -#endif - WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientBlackBerry(this)); - - WebCore::provideDeviceMotionTo(m_page, new DeviceMotionClientBlackBerry(this)); -#if ENABLE(VIBRATION) - WebCore::provideVibrationTo(m_page, new VibrationClientBlackBerry()); -#endif - -#if ENABLE(BATTERY_STATUS) - WebCore::provideBatteryTo(m_page, new WebCore::BatteryClientBlackBerry(this)); -#endif - -#if ENABLE(MEDIA_STREAM) - WebCore::provideUserMediaTo(m_page, new UserMediaClientImpl(m_webPage)); -#endif - -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) - WebCore::provideNotification(m_page, new NotificationClientBlackBerry(this)); -#endif - -#if ENABLE(NAVIGATOR_CONTENT_UTILS) - m_navigatorContentUtilsClient = adoptPtr(new NavigatorContentUtilsClientBlackBerry(this)); - WebCore::provideNavigatorContentUtilsTo(m_page, m_navigatorContentUtilsClient.get()); -#endif - -#if ENABLE(NETWORK_INFO) - WebCore::provideNetworkInfoTo(m_page, new WebCore::NetworkInfoClientBlackBerry(this)); -#endif - - m_page->setDeviceScaleFactor(m_webSettings->devicePixelRatio()); - - m_page->addLayoutMilestones(DidFirstVisuallyNonEmptyLayout); - -#if USE(ACCELERATED_COMPOSITING) - m_tapHighlight = DefaultTapHighlight::create(this); - m_selectionHighlight = DefaultTapHighlight::create(this); - m_selectionOverlay = SelectionOverlay::create(this); - m_page->settings()->setAcceleratedCompositingForFixedPositionEnabled(true); -#endif - - // FIXME: We explicitly call setDelegate() instead of passing ourself in createFromStandardSettings() - // so that we only get one didChangeSettings() callback when we set the page group name. This causes us - // to make a copy of the WebSettings since some WebSettings method make use of the page group name. - // Instead, we shouldn't be storing the page group name in WebSettings. - m_webSettings->setPageGroupName(pageGroupName); - m_webSettings->setDelegate(this); - didChangeSettings(m_webSettings); - - RefPtr<Frame> newFrame = Frame::create(m_page, /* HTMLFrameOwnerElement* */ 0, frameLoaderClient); - - m_mainFrame = newFrame.get(); - frameLoaderClient->setFrame(m_mainFrame, this); - m_mainFrame->init(); - - m_inRegionScroller = adoptPtr(new InRegionScroller(this)); - -#if ENABLE(WEBGL) - m_page->settings()->setWebGLEnabled(true); -#endif -#if ENABLE(ACCELERATED_2D_CANVAS) - m_page->settings()->setCanvasUsesAcceleratedDrawing(true); - m_page->settings()->setAccelerated2dCanvasEnabled(true); -#endif - - m_page->settings()->setInteractiveFormValidationEnabled(true); - m_page->settings()->setAllowUniversalAccessFromFileURLs(false); - m_page->settings()->setAllowFileAccessFromFileURLs(false); - m_page->settings()->setFixedPositionCreatesStackingContext(true); - m_page->settings()->setWantsBalancedSetDefersLoadingBehavior(true); - - m_backingStoreClient = BackingStoreClient::create(m_mainFrame, /* parent frame */ 0, m_webPage); - // The direct access to BackingStore is left here for convenience since it - // is owned by BackingStoreClient and then deleted by its destructor. - m_backingStore = m_backingStoreClient->backingStore(); - - blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(0).width())); // The clicked rectangle area should be a fixed unit of measurement. - - m_page->settings()->setDelegateSelectionPaint(true); - -#if ENABLE(REQUEST_ANIMATION_FRAME) - m_page->windowScreenDidChange((PlatformDisplayID)0); -#endif - -#if ENABLE(FILE_SYSTEM) - static bool localFileSystemInitialized = false; - if (!localFileSystemInitialized) { - localFileSystemInitialized = true; - WebCore::LocalFileSystem::initializeLocalFileSystem("/"); - } -#endif - -#if USE(ACCELERATED_COMPOSITING) - // The compositor will be needed for overlay rendering, so create it - // unconditionally. It will allocate OpenGL objects lazily, so this incurs - // no overhead in the unlikely case where the compositor is not needed. - Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage( - createMethodCallMessage(&WebPagePrivate::createCompositor, this)); -#endif -} - -class DeferredTaskLoadManualScript: public DeferredTask<&WebPagePrivate::m_wouldLoadManualScript> { -public: - explicit DeferredTaskLoadManualScript(WebPagePrivate* webPagePrivate, const KURL& url) - : DeferredTaskType(webPagePrivate) - { - webPagePrivate->m_cachedManualScript = url; - } -private: - virtual void performInternal(WebPagePrivate* webPagePrivate) - { - webPagePrivate->m_mainFrame->script()->executeIfJavaScriptURL(webPagePrivate->m_cachedManualScript, DoNotReplaceDocumentIfJavaScriptURL); - } -}; - -void WebPagePrivate::load(const Platform::NetworkRequest& netReq, bool needReferer) -{ - stopCurrentLoad(); - DeferredTaskLoadManualScript::finishOrCancel(this); - - String urlString(netReq.getUrlRef()); - if (urlString.startsWith("vs:", false)) { - urlString = urlString.substring(3); - m_mainFrame->setInViewSourceMode(true); - } else - m_mainFrame->setInViewSourceMode(false); - - KURL kurl = parseUrl(urlString); - if (protocolIs(kurl, "javascript")) { - // Never run javascript while loading is deferred. - if (m_page->defersLoading()) - m_deferredTasks.append(adoptPtr(new DeferredTaskLoadManualScript(this, kurl))); - else - m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL); - return; - } - - ResourceRequest request(kurl); - request.setHTTPMethod(netReq.getMethodRef()); - request.setCachePolicy(toWebCoreCachePolicy(netReq.getCachePolicy())); - if (!netReq.getOverrideContentType().empty()) - request.setOverrideContentType(netReq.getOverrideContentType()); - - Platform::NetworkRequest::HeaderList& list = netReq.getHeaderListRef(); - if (!list.empty()) { - for (unsigned i = 0; i < list.size(); i++) - request.addHTTPHeaderField(list[i].first.c_str(), list[i].second.c_str()); - } - - if (needReferer && focusedOrMainFrame() && focusedOrMainFrame()->document()) - request.addHTTPHeaderField("Referer", focusedOrMainFrame()->document()->url().string().utf8().data()); - - if (Platform::NetworkRequest::TargetIsDownload == netReq.getTargetType()) - request.setForceDownload(true); - if (!netReq.getSuggestedSaveName().empty()) - request.setSuggestedSaveName(netReq.getSuggestedSaveName()); - - m_mainFrame->loader()->load(FrameLoadRequest(m_mainFrame, request)); -} - -void WebPage::loadFile(const BlackBerry::Platform::String& path, const BlackBerry::Platform::String& overrideContentType) -{ - STATIC_LOCAL_STRING(s_filePrefix, "file://"); - STATIC_LOCAL_STRING(s_fileRootPrefix, "file:///"); - BlackBerry::Platform::String fileUrl(path); - if (fileUrl.startsWith('/')) - fileUrl = s_filePrefix + fileUrl; - else if (!fileUrl.startsWith(s_fileRootPrefix)) - return; - - Platform::NetworkRequest netRequest; - netRequest.setRequestUrl(fileUrl); - netRequest.setOverrideContentType(overrideContentType); - d->load(netRequest, false); -} - -void WebPage::load(const Platform::NetworkRequest& request, bool needReferer) -{ - d->load(request, needReferer); -} - -void WebPagePrivate::loadString(const BlackBerry::Platform::String& string, const BlackBerry::Platform::String& baseURL, const BlackBerry::Platform::String& contentType, const BlackBerry::Platform::String& failingURL) -{ - KURL kurl = parseUrl(baseURL); - ResourceRequest request(kurl); - WTF::RefPtr<SharedBuffer> buffer - = SharedBuffer::create(string.c_str(), string.length()); - SubstituteData substituteData(buffer, - extractMIMETypeFromMediaType(contentType), - extractCharsetFromMediaType(contentType), - !failingURL.empty() ? parseUrl(failingURL) : KURL()); - m_mainFrame->loader()->load(FrameLoadRequest(m_mainFrame, request, substituteData)); -} - -void WebPage::loadString(const BlackBerry::Platform::String& string, const BlackBerry::Platform::String& baseURL, const BlackBerry::Platform::String& mimeType, const BlackBerry::Platform::String& failingURL) -{ - d->loadString(string, baseURL, mimeType, failingURL); -} - -bool WebPagePrivate::executeJavaScript(const BlackBerry::Platform::String& scriptUTF8, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue) -{ - BLACKBERRY_ASSERT(scriptUTF8.isUtf8()); - String script = scriptUTF8; - - if (script.isNull()) { - returnType = JSException; - return false; - } - - if (script.isEmpty()) { - returnType = JSUndefined; - return true; - } - - ScriptValue result = m_mainFrame->script()->executeScript(script, false); - JSC::JSValue value = result.jsValue(); - if (!value) { - returnType = JSException; - return false; - } - - if (value.isUndefined()) - returnType = JSUndefined; - else if (value.isNull()) - returnType = JSNull; - else if (value.isBoolean()) - returnType = JSBoolean; - else if (value.isNumber()) - returnType = JSNumber; - else if (value.isString()) - returnType = JSString; - else if (value.isObject()) - returnType = JSObject; - else - returnType = JSUndefined; - - if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) { - JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec(); - returnValue = result.toString(exec); - } - - return true; -} - -bool WebPage::executeJavaScript(const BlackBerry::Platform::String& script, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue) -{ - return d->executeJavaScript(script, returnType, returnValue); -} - -bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& sourceCode, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue) -{ - if (!m_isolatedWorld) - m_isolatedWorld = m_mainFrame->script()->createWorld(); - - // Use evaluateInWorld to avoid canExecuteScripts check. - ScriptValue result = m_mainFrame->script()->evaluateInWorld(sourceCode, m_isolatedWorld.get()); - JSC::JSValue value = result.jsValue(); - if (!value) { - returnType = JSException; - return false; - } - - if (value.isUndefined()) - returnType = JSUndefined; - else if (value.isNull()) - returnType = JSNull; - else if (value.isBoolean()) - returnType = JSBoolean; - else if (value.isNumber()) - returnType = JSNumber; - else if (value.isString()) - returnType = JSString; - else if (value.isObject()) - returnType = JSObject; - else - returnType = JSUndefined; - - if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) { - JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec(); - returnValue = result.toString(exec); - } - - return true; -} - -bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue) -{ - // On our platform wchar_t is unsigned and UChar is unsigned short - // so we have to convert using ICU conversion function - int lengthCopied = 0; - UErrorCode error = U_ZERO_ERROR; - const int length = script.length() + 1 /*null termination char*/; - UChar data[length]; - - // FIXME: PR 138162 is giving U_INVALID_CHAR_FOUND error. - u_strFromUTF32(data, length, &lengthCopied, reinterpret_cast<const UChar32*>(script.c_str()), script.length(), &error); - BLACKBERRY_ASSERT(error == U_ZERO_ERROR); - if (error != U_ZERO_ERROR) { - Platform::logAlways(Platform::LogLevelCritical, "WebPage::executeJavaScriptInIsolatedWorld failed to convert UTF16 to JavaScript!"); - return false; - } - String str = String(data, lengthCopied); - ScriptSourceCode sourceCode(str, KURL()); - return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue); -} - -bool WebPage::executeJavaScriptInIsolatedWorld(const BlackBerry::Platform::String& scriptUTF8, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue) -{ - BLACKBERRY_ASSERT(scriptUTF8.isUtf8()); - ScriptSourceCode sourceCode(scriptUTF8, KURL()); - return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue); -} - -void WebPage::executeJavaScriptFunction(const std::vector<BlackBerry::Platform::String> &function, const std::vector<JavaScriptVariant> &args, JavaScriptVariant& returnValue) -{ - if (!d->m_mainFrame) { - returnValue.setType(JavaScriptVariant::Exception); - return; - } - - JSC::Bindings::RootObject* root = d->m_mainFrame->script()->bindingRootObject(); - if (!root) { - returnValue.setType(JavaScriptVariant::Exception); - return; - } - - JSC::ExecState* exec = root->globalObject()->globalExec(); - JSGlobalContextRef ctx = toGlobalRef(exec); - - JSC::APIEntryShim shim(exec); - WTF::Vector<JSValueRef> argListRef(args.size()); - for (unsigned i = 0; i < args.size(); ++i) - argListRef[i] = BlackBerryJavaScriptVariantToJSValueRef(ctx, args[i]); - - JSValueRef windowObjectValue = toRef(d->m_mainFrame->script()->globalObject(mainThreadNormalWorld())); - JSObjectRef obj = JSValueToObject(ctx, windowObjectValue, 0); - JSObjectRef thisObject = obj; - for (unsigned i = 0; i < function.size(); ++i) { - JSStringRef str = JSStringCreateWithUTF8CString(function[i].c_str()); - thisObject = obj; - obj = JSValueToObject(ctx, JSObjectGetProperty(ctx, obj, str, 0), 0); - JSStringRelease(str); - if (!obj) - break; - } - - JSObjectRef functionObject = obj; - JSValueRef result = 0; - if (functionObject && thisObject) - result = JSObjectCallAsFunction(ctx, functionObject, thisObject, args.size(), argListRef.data(), 0); - - if (!result) { - returnValue.setType(JavaScriptVariant::Exception); - return; - } - - returnValue = JSValueRefToBlackBerryJavaScriptVariant(ctx, result); -} - -void WebPagePrivate::stopCurrentLoad() -{ - // This function should contain all common code triggered by WebPage::load - // (which stops any load in progress before starting the new load) and - // WebPage::stoploading (the entry point for the client to stop the load - // explicitly). If it should only be done while stopping the load - // explicitly, it goes in WebPage::stopLoading, not here. - m_mainFrame->loader()->stopAllLoaders(); - - // Cancel any deferred script that hasn't been processed yet. - DeferredTaskLoadManualScript::finishOrCancel(this); -} - -void WebPage::stopLoading() -{ - d->stopCurrentLoad(); -} - -static void closeURLRecursively(Frame* frame) -{ - // Do not create more frame please. - FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client()); - frameLoaderClient->suppressChildFrameCreation(); - - frame->loader()->closeURL(); - - Vector<RefPtr<Frame>, 10> childFrames; - - for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling()) - childFrames.append(childFrame); - - unsigned size = childFrames.size(); - for (unsigned i = 0; i < size; i++) - closeURLRecursively(childFrames[i].get()); -} - -void WebPagePrivate::prepareToDestroy() -{ - // Before the client starts tearing itself down, dispatch the unload event - // so it can take effect while all the client's state (e.g. scroll position) - // is still present. - closeURLRecursively(m_mainFrame); -} - -void WebPage::prepareToDestroy() -{ - d->prepareToDestroy(); -} - -bool WebPage::dispatchBeforeUnloadEvent() -{ - return d->m_page->mainFrame()->loader()->shouldClose(); -} - -static void enableCrossSiteXHRRecursively(Frame* frame) -{ - frame->document()->securityOrigin()->grantUniversalAccess(); - - Vector<RefPtr<Frame>, 10> childFrames; - for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling()) - childFrames.append(childFrame); - - unsigned size = childFrames.size(); - for (unsigned i = 0; i < size; i++) - enableCrossSiteXHRRecursively(childFrames[i].get()); -} - -void WebPagePrivate::enableCrossSiteXHR() -{ - enableCrossSiteXHRRecursively(m_mainFrame); -} - -void WebPage::enableCrossSiteXHR() -{ - d->enableCrossSiteXHR(); -} - -void WebPagePrivate::addOriginAccessWhitelistEntry(const BlackBerry::Platform::String& sourceOrigin, const BlackBerry::Platform::String& destinationOrigin, bool allowDestinationSubdomains) -{ - RefPtr<SecurityOrigin> source = SecurityOrigin::createFromString(sourceOrigin); - if (source->isUnique()) - return; - - KURL destination(KURL(), destinationOrigin); - SecurityPolicy::addOriginAccessWhitelistEntry(*source, destination.protocol(), destination.host(), allowDestinationSubdomains); -} - -void WebPage::addOriginAccessWhitelistEntry(const BlackBerry::Platform::String& sourceOrigin, const BlackBerry::Platform::String& destinationOrigin, bool allowDestinationSubdomains) -{ - d->addOriginAccessWhitelistEntry(sourceOrigin, destinationOrigin, allowDestinationSubdomains); -} - -void WebPagePrivate::removeOriginAccessWhitelistEntry(const BlackBerry::Platform::String& sourceOrigin, const BlackBerry::Platform::String& destinationOrigin, bool allowDestinationSubdomains) -{ - RefPtr<SecurityOrigin> source = SecurityOrigin::createFromString(sourceOrigin); - if (source->isUnique()) - return; - - KURL destination(KURL(), destinationOrigin); - SecurityPolicy::removeOriginAccessWhitelistEntry(*source, destination.protocol(), destination.host(), allowDestinationSubdomains); -} - -void WebPage::removeOriginAccessWhitelistEntry(const BlackBerry::Platform::String& sourceOrigin, const BlackBerry::Platform::String& destinationOrigin, bool allowDestinationSubdomains) -{ - d->removeOriginAccessWhitelistEntry(sourceOrigin, destinationOrigin, allowDestinationSubdomains); -} - -void WebPagePrivate::setLoadState(LoadState state) -{ - if (m_loadState == state) - return; - - bool isFirstLoad = m_loadState == None; - - // See RIM Bug #1068. - if (state == Finished && m_mainFrame && m_mainFrame->document()) - m_mainFrame->document()->updateStyleIfNeeded(); - - // Dispatch the backingstore background color at important state changes. - m_backingStore->d->setWebPageBackgroundColor(documentBackgroundColor()); - - m_loadState = state; - -#if DEBUG_WEBPAGE_LOAD - Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state); -#endif - - switch (m_loadState) { - case Provisional: - if (isFirstLoad) { - // Paints the visible backingstore as settings()->backgroundColor() - // to prevent initial checkerboard on the first blit. - m_backingStore->d->renderAndBlitVisibleContentsImmediately(); - } - break; - case Committed: - { -#if USE(ACCELERATED_COMPOSITING) - releaseLayerResources(); -#endif - - // Suspend screen update to avoid ui thread blitting while resetting backingstore. - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->suspendBackingStoreUpdates(); - m_backingStore->d->suspendScreenUpdates(); - - m_previousContentsSize = IntSize(); - m_backingStore->d->resetRenderQueue(); - m_backingStore->d->resetTiles(); - m_backingStore->d->setScrollingOrZooming(false, false /* shouldBlit */); - m_shouldZoomToInitialScaleAfterLoadFinished = false; - m_userPerformedManualZoom = false; - m_userPerformedManualScroll = false; - m_shouldUseFixedDesktopMode = false; - m_forceRespectViewportArguments = false; - if (m_resetVirtualViewportOnCommitted) // For DRT. - m_virtualViewportSize = IntSize(); - if (m_webSettings->viewportWidth() > 0) - m_virtualViewportSize = IntSize(m_webSettings->viewportWidth(), m_defaultLayoutSize.height()); - - // Check if we have already process the meta viewport tag, this only happens on history navigation. - // For back/forward history navigation, we should only keep these previous values if the document - // has the meta viewport tag when the state is Committed in setLoadState. - static ViewportArguments defaultViewportArguments; - bool documentHasViewportArguments = false; - if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->viewportArguments() != defaultViewportArguments) - documentHasViewportArguments = true; - if (!(m_didRestoreFromPageCache && documentHasViewportArguments)) { - m_viewportArguments = ViewportArguments(); - m_userScalable = m_webSettings->isUserScalable(); - resetScales(); - - // At the moment we commit a new load, set the viewport arguments - // to any fallback values. If there is a meta viewport in the - // content it will overwrite the fallback arguments soon. - dispatchViewportPropertiesDidChange(m_userViewportArguments); - if (m_userViewportArguments != defaultViewportArguments) - m_forceRespectViewportArguments = true; - } else { - Platform::IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments(); - m_webPage->setVirtualViewportSize(virtualViewport); - } - - if (m_shouldUseFixedDesktopMode) - setViewMode(FixedDesktop); - else - setViewMode(Desktop); - -#if ENABLE(EVENT_MODE_METATAGS) - didReceiveCursorEventMode(ProcessedCursorEvents); - didReceiveTouchEventMode(ProcessedTouchEvents); -#endif - - // Reset block zoom and reflow. - resetBlockZoom(); -#if ENABLE(VIEWPORT_REFLOW) - toggleTextReflowIfEnabledForBlockZoomOnly(); -#endif - - // Notify InputHandler of state change. - m_inputHandler->setInputModeEnabled(false); - - // Set the scroll to origin here and notify the client since we'll be - // zooming below without any real contents yet thus the contents size - // we report to the client could make our current scroll position invalid. - setScrollPosition(IntPoint::zero()); - notifyTransformedScrollChanged(); - - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->resumeBackingStoreUpdates(); - // Paints the visible backingstore as white. Note it is important we do - // this strictly after re-setting the scroll position to origin and resetting - // the scales otherwise the visible contents calculation is wrong and we - // can end up blitting artifacts instead. See: RIM Bug #401. - m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); - - // Update cursor status. - updateCursor(); - - break; - } - case Finished: - case Failed: - // Notify client of the initial zoom change. - m_client->scaleChanged(); - m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */); - break; - default: - break; - } -} - -double WebPagePrivate::clampedScale(double scale) const -{ - if (scale < minimumScale()) - return minimumScale(); - if (scale > maximumScale()) - return maximumScale(); - return scale; -} - -bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale) -{ - if (!m_mainFrame || !m_mainFrame->view()) - return false; - - if (enforceScaleClamping) - scale = this->clampedScale(scale); - - ASSERT(clampedScale); - *clampedScale = scale; - - if (currentScale() == scale) - return false; - - return true; -} - -bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel) -{ - if (!isRestoringZoomLevel) { - // Clear any existing block zoom. (If we are restoring a saved zoom level on page load, - // there is guaranteed to be no existing block zoom and we don't want to clear m_shouldReflowBlock.) - resetBlockZoom(); - } - - // The reflow and block zoom stuff here needs to happen regardless of - // whether we shouldZoomAboutPoint. -#if ENABLE(VIEWPORT_REFLOW) - toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock); - if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view()) - setNeedsLayout(); -#endif - - double scale; - if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) { - if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) { - m_currentPinchZoomNode = 0; - m_anchorInNodeRectRatio = FloatPoint(-1, -1); - } - return false; - } - TransformationMatrix zoom; - zoom.scale(scale); - -#if DEBUG_WEBPAGE_LOAD - if (loadState() < Finished) { - Platform::logAlways(Platform::LogLevelInfo, - "WebPagePrivate::zoomAboutPoint scale %f anchor %s", - scale, Platform::FloatPoint(anchor).toString().c_str()); - } -#endif - - // Our current scroll position in float. - FloatPoint scrollPosition = this->scrollPosition(); - - // Anchor offset from scroll position in float. - FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y()); - - // The horizontal scaling factor and vertical scaling factor should be equal - // to preserve aspect ratio of content. - ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22()); - - // Need to invert the previous transform to anchor the viewport. - double inverseScale = scale / m_transformationMatrix->m11(); - - // Actual zoom. - *m_transformationMatrix = zoom; - - // Suspend all screen updates to the backingstore. - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->suspendBackingStoreUpdates(); - m_backingStore->d->suspendScreenUpdates(); - - updateViewportSize(); - - IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))), - max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale))))); - - if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) { - // This is a hack for email which has reflow always turned on. - setNeedsLayout(); - layoutIfNeeded(); - if (m_currentPinchZoomNode) - newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale); - m_currentPinchZoomNode = 0; - m_anchorInNodeRectRatio = FloatPoint(-1, -1); - } - - setScrollPosition(newScrollPosition); - - notifyTransformChanged(); - - bool isLoading = this->isLoading(); - - // We need to invalidate all tiles both visible and non-visible if we're loading. - m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */); - - bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering; - - m_client->scaleChanged(); - - if (m_pendingOrientation != -1) - m_client->updateInteractionViews(); - - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->resumeBackingStoreUpdates(); - - // Clear window to make sure there are no artifacts. - if (shouldRender) { - // Resume all screen updates to the backingstore and render+blit visible contents to screen. - m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); - } else { - // Resume all screen updates to the backingstore but do not blit to the screen because we not rendering. - m_backingStore->d->resumeScreenUpdates(BackingStore::None); - } - - return true; -} - -IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale) -{ - // Should only be invoked when text reflow is enabled. - ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled); - - int offsetY = 0; - int offsetX = 0; - - IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get()); - - if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) { - offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y(); - if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0) - offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale; - } - - IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get()); - - return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))), - max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale)))); -} - -void WebPagePrivate::setNeedsLayout() -{ - FrameView* view = m_mainFrame->view(); - ASSERT(view); - view->setNeedsLayout(); -} - -void WebPagePrivate::updateLayoutAndStyleIfNeededRecursive() const -{ - FrameView* view = m_mainFrame->view(); - ASSERT(view); - view->updateLayoutAndStyleIfNeededRecursive(); - ASSERT(!view->needsLayout()); -} - -void WebPagePrivate::layoutIfNeeded() const -{ - FrameView* view = m_mainFrame->view(); - ASSERT(view); - if (view->needsLayout()) - view->layout(); -} - -IntPoint WebPagePrivate::scrollPosition() const -{ - if (!m_backingStoreClient) - return IntPoint(); - - return m_backingStoreClient->scrollPosition(); -} - -IntPoint WebPagePrivate::maximumScrollPosition() const -{ - if (!m_backingStoreClient) - return IntPoint(); - - return m_backingStoreClient->maximumScrollPosition(); -} - -void WebPagePrivate::setScrollPosition(const IntPoint& pos) -{ - ASSERT(m_backingStoreClient); - m_backingStoreClient->setScrollPosition(pos); -} - -// Setting the scroll position is in transformed coordinates. -void WebPage::setDocumentScrollPosition(const Platform::IntPoint& documentScrollPosition) -{ - WebCore::IntPoint scrollPosition = documentScrollPosition; - if (scrollPosition == d->scrollPosition()) - return; - - // If the user recently performed an event, this new scroll position - // could possibly be a result of that. Or not, this is just a heuristic. - if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval) - d->m_userPerformedManualScroll = true; - - d->m_backingStoreClient->setIsClientGeneratedScroll(true); - - // UI thread can call BackingStorePrivate::setScrollingOrZooming(false) before WebKit thread calls WebPage::setScrollPosition(), - // in which case it will set ScrollableArea::m_constrainsScrollingToContentEdge to true earlier. - // We can cache ScrollableArea::m_constrainsScrollingToContentEdge and always set it to false before we set scroll position in - // WebKit thread to avoid scroll position clamping during scrolling, and restore it to what it was after that. - bool constrainsScrollingToContentEdge = d->m_mainFrame->view()->constrainsScrollingToContentEdge(); - d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(false); - d->setScrollPosition(scrollPosition); - d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge); - - d->m_backingStoreClient->setIsClientGeneratedScroll(false); -} - -bool WebPagePrivate::shouldSendResizeEvent() -{ - if (!m_mainFrame || !m_mainFrame->document()) - return false; - - // PR#96865 : Provide an option to always send resize events, regardless of the loading - // status. The scenario for this are Sapphire applications which tend to - // maintain an open GET request to the server. This open GET results in - // webkit thinking that content is still arriving when at the application - // level it is considered fully loaded. - // - // NOTE: Care must be exercised in the use of this option, as it bypasses - // the sanity provided in 'isLoadingInAPISense()' below. - // - static const bool unrestrictedResizeEvents = Platform::Settings::instance()->unrestrictedResizeEvents(); - if (unrestrictedResizeEvents) - return true; - - // Don't send the resize event if the document is loading. Some pages automatically reload - // when the window is resized; Safari on iPhone often resizes the window while setting up its - // viewport. This obviously can cause problems. - DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader(); - if (documentLoader && documentLoader->isLoadingInAPISense()) - return false; - - return true; -} - -void WebPagePrivate::willDeferLoading() -{ - m_deferredTasksTimer.stop(); - m_client->willDeferLoading(); -} - -void WebPagePrivate::didResumeLoading() -{ - if (!m_deferredTasks.isEmpty()) - m_deferredTasksTimer.startOneShot(0); - m_client->didResumeLoading(); -} - -void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*) -{ - ASSERT(!m_deferredTasks.isEmpty()); - if (m_deferredTasks.isEmpty()) - return; - - OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release(); - m_deferredTasks.remove(0); - - if (!m_deferredTasks.isEmpty()) - m_deferredTasksTimer.startOneShot(0); - - task->perform(this); -} - -void WebPagePrivate::notifyInRegionScrollStopped() -{ - if (m_inRegionScroller->d->isActive()) - m_inRegionScroller->d->reset(); -} - -void WebPage::notifyInRegionScrollStopped() -{ - d->notifyInRegionScrollStopped(); -} - -void WebPagePrivate::setHasInRegionScrollableAreas(bool b) -{ - if (b != m_hasInRegionScrollableAreas) - m_hasInRegionScrollableAreas = b; -} - -IntSize WebPagePrivate::viewportSize() const -{ - return m_webkitThreadViewportAccessor->roundToDocumentFromPixelContents(Platform::IntRect(Platform::IntPoint::zero(), transformedViewportSize())).size(); -} - -IntSize WebPagePrivate::actualVisibleSize() const -{ - return m_webkitThreadViewportAccessor->documentViewportSize(); -} - -bool WebPagePrivate::hasVirtualViewport() const -{ - return !m_virtualViewportSize.isEmpty(); -} - -void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent) -{ - // This checks to make sure we're not calling updateViewportSize - // during WebPagePrivate::init(). - if (!m_backingStore) - return; - ASSERT(m_mainFrame->view()); - IntSize visibleSize = actualVisibleSize(); - if (setFixedReportedSize) - m_mainFrame->view()->setFixedReportedSize(visibleSize); - - IntRect frameRect = IntRect(scrollPosition(), visibleSize); - if (frameRect != m_mainFrame->view()->frameRect()) { - m_mainFrame->view()->setFrameRect(frameRect); - m_mainFrame->view()->adjustViewSize(); - -#if ENABLE(FULLSCREEN_API) - adjustFullScreenElementDimensionsIfNeeded(); -#endif - } - - // We're going to need to send a resize event to JavaScript because - // innerWidth and innerHeight depend on fixed reported size. - // This is how we support mobile pages where JavaScript resizes - // the page in order to get around the fixed layout size, e.g. - // google maps when it detects a mobile user agent. - if (sendResizeEvent && shouldSendResizeEvent()) - m_mainFrame->eventHandler()->sendResizeEvent(); - - // When the actual visible size changes, we also - // need to reposition fixed elements. - m_mainFrame->view()->repaintFixedElementsAfterScrolling(); -} - -FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const -{ - // The visible contents rect in float. - FloatRect visibleContentsRect = this->visibleContentsRect(); - - // The center of the visible contents rect in float. - return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0, - visibleContentsRect.y() + visibleContentsRect.height() / 2.0); -} - -IntRect WebPagePrivate::visibleContentsRect() const -{ - return m_backingStoreClient->visibleContentsRect(); -} - -IntSize WebPagePrivate::contentsSize() const -{ - if (!m_mainFrame || !m_mainFrame->view()) - return IntSize(); - - return m_backingStoreClient->contentsSize(); -} - -IntSize WebPagePrivate::absoluteVisibleOverflowSize() const -{ - if (!m_mainFrame || !m_mainFrame->contentRenderer()) - return IntSize(); - - return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow()); -} - -void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize) -{ - if (m_previousContentsSize == contentsSize) - return; - - // This should only occur in the middle of layout so we set a flag here and - // handle it at the end of the layout. - m_contentsSizeChanged = true; - -#if DEBUG_WEBPAGE_LOAD - Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %s", Platform::IntSize(contentsSize).toString().c_str()); -#endif -} - -void WebPagePrivate::overflowExceedsContentsSize() -{ - m_overflowExceedsContentsSize = true; - if (absoluteVisibleOverflowSize().width() < DEFAULT_MAX_LAYOUT_WIDTH && !hasVirtualViewport()) { - if (setViewMode(viewMode())) { - setNeedsLayout(); - layoutIfNeeded(); - } - } -} - -void WebPagePrivate::layoutFinished() -{ - // If a layout change has occurred, we need to invalidate any current spellcheck requests and trigger a new run. - m_inputHandler->stopPendingSpellCheckRequests(true /* isRestartRequired */); - - if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize) - return; - - m_contentsSizeChanged = false; // Toggle to turn off notification again. - m_overflowExceedsContentsSize = false; - - if (contentsSize().isEmpty()) - return; - - // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from - // the middle of a layout, but the recursion is limited by detection code in - // setViewMode() and mitigation code in fixedLayoutSize(). - if (didLayoutExceedMaximumIterations()) { - notifyTransformedContentsSizeChanged(); - return; - } - - // Temporarily save the m_previousContentsSize here before updating it (in - // notifyTransformedContentsSizeChanged()) so we can compare if our contents - // shrunk afterwards. - IntSize previousContentsSize = m_previousContentsSize; - - m_nestedLayoutFinishedCount++; - - if (shouldZoomToInitialScaleOnLoad()) { - zoomToInitialScaleOnLoad(); - m_shouldZoomToInitialScaleAfterLoadFinished = false; - } else if (loadState() != None) - notifyTransformedContentsSizeChanged(); - - m_nestedLayoutFinishedCount--; - - if (!m_nestedLayoutFinishedCount) { - // When the contents shrinks, there is a risk that we - // will be left at a scroll position that lies outside of the - // contents rect. Since we allow overscrolling and neglect - // to clamp overscroll in order to retain input focus (RIM Bug #414) - // we need to clamp somewhere, and this is where we know the - // contents size has changed. - - if (contentsSize() != previousContentsSize) { - - IntPoint newScrollPosition = scrollPosition(); - - if (contentsSize().height() < previousContentsSize.height()) { - IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y()); - newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk); - } - - if (contentsSize().width() < previousContentsSize.width()) { - IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y()); - newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk); - } - - if (newScrollPosition != scrollPosition()) { - setScrollPosition(newScrollPosition); - notifyTransformedScrollChanged(); - } - - const Platform::IntSize pixelContentsSize = m_webkitThreadViewportAccessor->pixelContentsSize(); - - // If the content size is too small, zoom it to fit the viewport. - if ((loadState() == Finished || loadState() == Committed) && (pixelContentsSize.width() < m_actualVisibleWidth || pixelContentsSize.height() < m_actualVisibleHeight)) - zoomAboutPoint(initialScale(), newScrollPosition); - } - } -} - -void WebPagePrivate::zoomToInitialScaleOnLoad() -{ -#if DEBUG_WEBPAGE_LOAD - Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad"); -#endif - - bool needsLayout = false; - - // If the contents width exceeds the viewport width set to desktop mode. - if (m_shouldUseFixedDesktopMode) - needsLayout = setViewMode(FixedDesktop); - else - needsLayout = setViewMode(Desktop); - - if (needsLayout) { - // This can cause recursive layout... - setNeedsLayout(); - } - - if (contentsSize().isEmpty()) { -#if DEBUG_WEBPAGE_LOAD - Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!"); -#endif - layoutIfNeeded(); - notifyTransformedContentsSizeChanged(); - return; - } - - bool performedZoom = false; - bool shouldZoom = !m_userPerformedManualZoom; - - // If this is a back/forward type navigation, don't zoom to initial scale - // but instead let the HistoryItem's saved viewport reign supreme. - if (m_mainFrame && m_mainFrame->loader() && isBackForwardLoadType(m_mainFrame->loader()->loadType())) - shouldZoom = false; - - if (shouldZoom && shouldZoomToInitialScaleOnLoad()) { - // Preserve at top and at left position, to avoid scrolling - // to a non top-left position for web page with viewport meta tag - // that specifies an initial-scale that is zoomed in. - FloatPoint anchor = centerOfVisibleContentsRect(); - if (!scrollPosition().x()) - anchor.setX(0); - if (!scrollPosition().y()) - anchor.setY(0); - performedZoom = zoomAboutPoint(initialScale(), anchor); - } - - // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout... - layoutIfNeeded(); - - if (!performedZoom) { - // We only notify if we didn't perform zoom, because zoom will notify on - // its own... - notifyTransformedContentsSizeChanged(); - } -} - -double WebPagePrivate::zoomToFitScale() const -{ - int contentWidth = contentsSize().width(); - - // For image document, zoom to fit the screen based on the actual image width - // instead of the contents width within a maximum scale . - Document* doc = m_page->mainFrame()->document(); - bool isImageDocument = doc && doc->isImageDocument(); - if (isImageDocument) - contentWidth = static_cast<ImageDocument*>(doc)->imageSize().width(); - - double zoomToFitScale = contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0; - int contentHeight = contentsSize().height(); - if (contentHeight * zoomToFitScale < static_cast<double>(m_defaultLayoutSize.height())) - zoomToFitScale = contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0; - zoomToFitScale = std::max(zoomToFitScale, minimumZoomToFitScale); - - if (!isImageDocument) - return zoomToFitScale; - - return std::min(zoomToFitScale, maximumImageDocumentZoomToFitScale); -} - -bool WebPagePrivate::respectViewport() const -{ - return m_forceRespectViewportArguments || contentsSize().width() <= m_virtualViewportSize.width() + 1; -} - -double WebPagePrivate::initialScale() const -{ - - if (m_initialScale > 0.0 && respectViewport()) - return m_initialScale; - - if (m_webSettings->isZoomToFitOnLoad()) - return zoomToFitScale(); - - return 1.0; -} - -double WebPage::initialScale() const -{ - return d->initialScale(); -} - -void WebPage::initializeIconDataBase() -{ - IconDatabaseClientBlackBerry::instance()->initIconDatabase(d->m_webSettings); -} - -bool WebPage::isUserScalable() const -{ - return d->isUserScalable(); -} - -void WebPage::setUserScalable(bool userScalable) -{ - d->setUserScalable(userScalable); -} - -double WebPage::currentScale() const -{ - return d->currentScale(); -} - -void WebPage::setInitialScale(double initialScale) -{ - d->setInitialScale(initialScale); -} - -double WebPage::minimumScale() const -{ - return d->minimumScale(); -} - -void WebPage::setMinimumScale(double minimumScale) -{ - d->setMinimumScale(minimumScale); -} - -void WebPage::setMaximumScale(double maximumScale) -{ - d->setMaximumScale(maximumScale); -} - -double WebPagePrivate::maximumScale() const -{ - double zoomToFitScale = this->zoomToFitScale(); - if (m_maximumScale >= m_minimumScale && respectViewport()) - return std::max(zoomToFitScale, m_maximumScale); - - return hasVirtualViewport() ? std::max<double>(zoomToFitScale, 5.0) : 5.0; -} - -double WebPage::maximumScale() const -{ - return d->maximumScale(); -} - -void WebPagePrivate::resetScales() -{ - TransformationMatrix identity; - *m_transformationMatrix = identity; - m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0; - m_minimumScale = -1.0; - m_maximumScale = -1.0; - m_client->scaleChanged(); - - // We have to let WebCore know about updated framerect now that we've - // reset our scales. See: RIM Bug #401. - updateViewportSize(); -} - -IntPoint WebPagePrivate::transformedScrollPosition() const -{ - return m_backingStoreClient->transformedScrollPosition(); -} - -IntPoint WebPagePrivate::transformedMaximumScrollPosition() const -{ - return m_backingStoreClient->transformedMaximumScrollPosition(); -} - -IntSize WebPagePrivate::transformedActualVisibleSize() const -{ - return IntSize(m_actualVisibleWidth, m_actualVisibleHeight); -} - -Platform::ViewportAccessor* WebPage::webkitThreadViewportAccessor() const -{ - return d->m_webkitThreadViewportAccessor; -} - -Platform::IntSize WebPage::viewportSize() const -{ - return d->transformedActualVisibleSize(); -} - -IntSize WebPagePrivate::transformedViewportSize() const -{ - return BlackBerry::Platform::Settings::instance()->applicationSize(); -} - -void WebPagePrivate::notifyTransformChanged() -{ - notifyTransformedContentsSizeChanged(); - notifyTransformedScrollChanged(); - - m_backingStore->d->transformChanged(); -} - -void WebPagePrivate::notifyTransformedContentsSizeChanged() -{ - // We mark here as the last reported content size we sent to the client. - m_previousContentsSize = contentsSize(); - - const IntSize size = m_webkitThreadViewportAccessor->pixelContentsSize(); - m_backingStore->d->contentsSizeChanged(size); - m_client->contentsSizeChanged(); -} - -void WebPagePrivate::notifyTransformedScrollChanged() -{ - const IntPoint pos = transformedScrollPosition(); - m_backingStore->d->scrollChanged(pos); - m_client->scrollChanged(); - -#if ENABLE(FULLSCREEN_API) - adjustFullScreenElementDimensionsIfNeeded(); -#endif -} - -bool WebPagePrivate::setViewMode(ViewMode mode) -{ - if (!m_mainFrame || !m_mainFrame->view()) - return false; - - m_viewMode = mode; - - // If we're in the middle of a nested layout with a recursion count above - // some maximum threshold, then our algorithm for finding the minimum content - // width of a given page has become dependent on the visible width. - // - // We need to find some method to ensure that we don't experience excessive - // and even infinite recursion. This can even happen with valid html. The - // former can happen when we run into inline text with few candidates for line - // break. The latter can happen for instance if the page has a negative margin - // set against the right border. Note: this is valid by spec and can lead to - // a situation where there is no value for which the content width will ensure - // no horizontal scrollbar. - // Example: LayoutTests/css1/box_properties/margin.html - // - // In order to address such situations when we detect a recursion above some - // maximum threshold we snap our fixed layout size to a defined quantum increment. - // Eventually, either the content width will be satisfied to ensure no horizontal - // scrollbar or this increment will run into the maximum layout size and the - // recursion will necessarily end. - bool snapToIncrement = didLayoutExceedMaximumIterations(); - - IntSize currentSize = m_mainFrame->view()->fixedLayoutSize(); - IntSize newSize = fixedLayoutSize(snapToIncrement); - if (currentSize == newSize) - return false; - - // FIXME: Temp solution. We'll get back to this. - if (m_nestedLayoutFinishedCount) { - double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width()); - double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height()); - if (widthChange < 0.05 && heightChange < 0.05) - return false; - } - - m_mainFrame->view()->setUseFixedLayout(useFixedLayout()); - m_mainFrame->view()->setFixedLayoutSize(newSize); - return true; // Needs re-layout! -} - -int WebPagePrivate::playerID() const -{ - return m_client ? m_client->getInstanceId() : 0; -} - -void WebPagePrivate::setCursor(PlatformCursor handle) -{ - if (m_currentCursor.type() != handle.type()) { - m_currentCursor = handle; - m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot()); - } -} - -Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory() -{ - return m_client->networkStreamFactory(); -} - -Platform::Graphics::Window* WebPagePrivate::platformWindow() const -{ - return m_client->window(); -} - -void WebPagePrivate::setPreventsScreenDimming(bool keepAwake) -{ - if (keepAwake) { - if (!m_preventIdleDimmingCount) - m_client->setPreventsScreenIdleDimming(true); - m_preventIdleDimmingCount++; - } else if (m_preventIdleDimmingCount > 0) { - m_preventIdleDimmingCount--; - if (!m_preventIdleDimmingCount) - m_client->setPreventsScreenIdleDimming(false); - } else - ASSERT_NOT_REACHED(); // SetPreventsScreenIdleDimming(false) called too many times. -} - -void WebPagePrivate::showVirtualKeyboard(bool showKeyboard) -{ - m_client->showVirtualKeyboard(showKeyboard); -} - -void WebPagePrivate::ensureContentVisible(bool centerInView) -{ - m_inputHandler->ensureFocusElementVisible(centerInView); -} - -void WebPagePrivate::zoomToContentRect(const IntRect& rect) -{ - // Don't scale if the user is not supposed to scale. - if (!isUserScalable()) - return; - - FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y()); - IntSize viewSize = viewportSize(); - - // Calculate the scale required to scale that dimension to fit. - double scaleH = (double)viewSize.width() / (double)rect.width(); - double scaleV = (double)viewSize.height() / (double)rect.height(); - - // Choose the smaller scale factor so that all of the content is visible. - zoomAboutPoint(min(scaleH, scaleV), anchor); -} - -void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister) -{ - if (shouldRegister) - m_pluginViews.add(plugin); - else - m_pluginViews.remove(plugin); -} - -#define FOR_EACH_PLUGINVIEW(pluginViews) \ - HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \ - HashSet<PluginView*>::const_iterator last = pluginViews.end(); \ - for (; it != last; ++it) - -void WebPagePrivate::notifyPageOnLoad() -{ - FOR_EACH_PLUGINVIEW(m_pluginViews) - (*it)->handleOnLoadEvent(); -} - -bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView*, const char*) -{ - return m_client->shouldPluginEnterFullScreen(); -} - -void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix) -{ - m_fullScreenPluginView = plugin; - m_client->didPluginEnterFullScreen(); - - if (!m_client->window()) - return; - - Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix); - m_client->window()->setSensitivityFullscreenOverride(true); -} - -void WebPagePrivate::didPluginExitFullScreen(PluginView*, const char*) -{ - m_fullScreenPluginView = 0; - m_client->didPluginExitFullScreen(); - - if (!m_client->window()) - return; - - Platform::Graphics::Window::setTransparencyDiscardFilter(0); - m_client->window()->setSensitivityFullscreenOverride(false); -} - -void WebPagePrivate::onPluginStartBackgroundPlay(PluginView*, const char*) -{ - m_client->onPluginStartBackgroundPlay(); -} - -void WebPagePrivate::onPluginStopBackgroundPlay(PluginView*, const char*) -{ - m_client->onPluginStopBackgroundPlay(); -} - -bool WebPagePrivate::lockOrientation(bool landscape) -{ - return m_client->lockOrientation(landscape); -} - -void WebPagePrivate::unlockOrientation() -{ - return m_client->unlockOrientation(); -} - -int WebPagePrivate::orientation() const -{ -#if ENABLE(ORIENTATION_EVENTS) - return m_mainFrame->orientation(); -#else -#error ORIENTATION_EVENTS must be defined. -// Or a copy of the orientation value will have to be stored in these objects. -#endif -} - -double WebPagePrivate::currentZoomFactor() const -{ - return currentScale(); -} - -int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype) -{ - return m_client->showAlertDialog(atype); -} - -bool WebPagePrivate::isActive() const -{ - return m_client->isActive(); -} - -void WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSpace& protectionSpace, const Credential& inputCredential) -{ - AuthenticationChallengeManager* authmgr = AuthenticationChallengeManager::instance(); - BlackBerry::Platform::String username; - BlackBerry::Platform::String password; - BlackBerry::Platform::String requestURL(url.string()); - -#if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD - if (m_dumpRenderTree) { - Credential credential(inputCredential, inputCredential.persistence()); - if (m_dumpRenderTree->didReceiveAuthenticationChallenge(credential)) - authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeSuccess, credential); - else - authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeCancelled, inputCredential); - return; - } -#endif - -#if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST) - if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled()) - credentialManager().autofillAuthenticationChallenge(protectionSpace, username, password); -#endif - - bool isConfirmed = m_client->authenticationChallenge(protectionSpace.realm().characters(), protectionSpace.realm().length(), username, password, requestURL, protectionSpace.isProxy()); - -#if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST) - Credential credential(username, password, CredentialPersistencePermanent); - if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled() && isConfirmed) - credentialManager().saveCredentialIfConfirmed(this, CredentialTransformData(protectionSpace, credential)); -#else - Credential credential(username, password, CredentialPersistenceNone); -#endif - - if (isConfirmed) - authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeSuccess, credential); - else - authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeCancelled, inputCredential); -} - -PageClientBlackBerry::SaveCredentialType WebPagePrivate::notifyShouldSaveCredential(bool isNew) -{ - return static_cast<PageClientBlackBerry::SaveCredentialType>(m_client->notifyShouldSaveCredential(isNew)); -} - -void WebPagePrivate::syncProxyCredential(const WebCore::Credential& credential) -{ - m_client->syncProxyCredential(credential.user(), credential.password()); -} - -void WebPagePrivate::notifyPopupAutofillDialog(const Vector<String>& candidates) -{ - vector<BlackBerry::Platform::String> textItems; - for (size_t i = 0; i < candidates.size(); i++) - textItems.push_back(candidates[i]); - m_client->notifyPopupAutofillDialog(textItems); -} - -void WebPagePrivate::notifyDismissAutofillDialog() -{ - m_client->notifyDismissAutofillDialog(); -} - -bool WebPagePrivate::useFixedLayout() const -{ - return true; -} - -Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy) -{ - Platform::WebContext context; - - RefPtr<Node> node = contextNode(strategy); - m_currentContextNode = node; - if (!m_currentContextNode) - return context; - - // Send an onContextMenu event to the current context ndoe and get the result. Since we've already figured out - // which node we want, we can send it directly to the node and not do a hit test. The onContextMenu event doesn't require - // mouse positions so we just set the position at (0,0) - PlatformMouseEvent mouseEvent(IntPoint(), IntPoint(), PlatformEvent::MouseMoved, 0, NoButton, false, false, false, TouchScreen); - if (!m_currentContextNode->dispatchMouseEvent(mouseEvent, eventNames().contextmenuEvent, 0)) { - context.setFlag(Platform::WebContext::IsOnContextMenuPrevented); - return context; - } - - layoutIfNeeded(); - - bool nodeAllowSelectionOverride = false; - bool nodeIsImage = node->isHTMLElement() && isHTMLImageElement(node); - Node* linkNode = node->enclosingLinkEventParentOrSelf(); - // Set link url only when the node is linked image, or text inside anchor. Prevent CCM popup when long press non-link element(eg. button) inside an anchor. - if (linkNode && (node == linkNode || node->isTextNode() || nodeIsImage)) { - KURL href; - if (linkNode->isLink() && linkNode->hasAttributes()) { - if (const Attribute* attribute = toElement(linkNode)->getAttributeItem(HTMLNames::hrefAttr)) - href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value())); - } - - String pattern = findPatternStringForUrl(href); - if (!pattern.isEmpty()) - context.setPattern(pattern); - - if (!href.string().isEmpty()) { - context.setUrl(href.string()); - - // Links are non-selectable by default, but selection should be allowed - // providing the page is selectable, use the parent to determine it. - if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection()) - nodeAllowSelectionOverride = true; - } - } - - if (node->isHTMLElement()) { - HTMLImageElement* imageElement = 0; - HTMLMediaElement* mediaElement = 0; - - if (isHTMLImageElement(node)) - imageElement = toHTMLImageElement(node.get()); - else if (isHTMLAreaElement(node)) - imageElement = toHTMLAreaElement(node.get())->imageElement(); - - if (static_cast<HTMLElement*>(node.get())->isMediaElement()) - mediaElement = toHTMLMediaElement(node.get()); - - if (imageElement && imageElement->renderer()) { - context.setFlag(Platform::WebContext::IsImage); - // FIXME: At the mean time, we only show "Save Image" when the image data is available. - if (CachedImage* cachedImage = imageElement->cachedImage()) { - if (cachedImage->isLoaded() && cachedImage->resourceBuffer()) { - String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string()); - context.setSrc(node->document()->completeURL(url).string()); - - String mimeType = cachedImage->response().mimeType(); - if (mimeType.isEmpty()) { - StringBuilder builder; - String extension = cachedImage->image()->filenameExtension(); - builder.append("image/"); - if (extension.isEmpty()) - builder.append("unknown"); - else if (extension == "jpg") - builder.append("jpeg"); - else - builder.append(extension); - mimeType = builder.toString(); - } - context.setMimeType(mimeType); - } - } - String alt = imageElement->altText(); - if (!alt.isNull()) - context.setAlt(alt); - } - - if (mediaElement) { - if (mediaElement->hasAudio()) - context.setFlag(Platform::WebContext::IsAudio); - if (mediaElement->hasVideo()) - context.setFlag(Platform::WebContext::IsVideo); - - String src = stripLeadingAndTrailingHTMLSpaces(mediaElement->getAttribute(HTMLNames::srcAttr).string()); - context.setSrc(node->document()->completeURL(src).string()); - } - } - - if (node->isTextNode()) { - Text* curText = toText(node.get()); - if (!curText->wholeText().isEmpty()) - context.setText(curText->wholeText()); - } - - bool canStartSelection = node->canStartSelection(); - - if (node->isElementNode()) { - Element* element = toElement(node->deprecatedShadowAncestorNode()); - - if (DOMSupport::isTextBasedContentEditableElement(element)) { - if (!canStartSelection) { - // Input fields host node is by spec non-editable unless the field itself has content editable enabled. - // Enable selection if the shadow tree for the input field is selectable. - Node* nodeUnderFinger = m_touchEventHandler->lastFatFingersResult().isValid() ? m_touchEventHandler->lastFatFingersResult().node(FatFingersResult::ShadowContentAllowed) : 0; - if (nodeUnderFinger) - canStartSelection = nodeUnderFinger->canStartSelection(); - } - context.setFlag(Platform::WebContext::IsInput); - if (isHTMLInputElement(element)) - context.setFlag(Platform::WebContext::IsSingleLine); - if (DOMSupport::isPasswordElement(element)) - context.setFlag(Platform::WebContext::IsPassword); - - String elementText(DOMSupport::inputElementText(element)); - if (!elementText.stripWhiteSpace().isEmpty()) - context.setText(elementText); - else if (!node->focused() && m_touchEventHandler->lastFatFingersResult().isValid() && strategy == RectBased) { - // If an input field is empty and not focused send a mouse click so that it gets a cursor and we can paste into it. - m_touchEventHandler->sendClickAtFatFingersPoint(); - } - } - } - - if (!nodeAllowSelectionOverride && !canStartSelection) - context.resetFlag(Platform::WebContext::IsSelectable); - - if (node->isFocusable()) - context.setFlag(Platform::WebContext::IsFocusable); - - // Walk up the node tree looking for our custom webworks context attribute. - while (node) { - if (node->isElementNode()) { - Element* element = toElement(node->deprecatedShadowAncestorNode()); - String webWorksContext(DOMSupport::webWorksContext(element)); - if (!webWorksContext.stripWhiteSpace().isEmpty()) { - context.setFlag(Platform::WebContext::IsWebWorksContext); - context.setWebWorksContext(webWorksContext); - break; - } - } - node = node->parentNode(); - } - - return context; -} - -Platform::WebContext WebPage::webContext(TargetDetectionStrategy strategy) const -{ - return d->webContext(strategy); -} - -void WebPagePrivate::updateCursor() -{ - int buttonMask = 0; - if (m_lastMouseEvent.button() == LeftButton) - buttonMask = Platform::MouseEvent::ScreenLeftMouseButton; - else if (m_lastMouseEvent.button() == MiddleButton) - buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton; - else if (m_lastMouseEvent.button() == RightButton) - buttonMask = Platform::MouseEvent::ScreenRightMouseButton; - - unsigned modifiers = m_lastMouseEvent.shiftKey() ? 0 : KEYMOD_SHIFT | - m_lastMouseEvent.ctrlKey() ? 0 : KEYMOD_CTRL | - m_lastMouseEvent.altKey() ? 0 : KEYMOD_ALT; - - const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor; - - BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask, - viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatPoint(m_lastMouseEvent.position())), - viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatPoint(m_lastMouseEvent.globalPosition())), - 0, modifiers, 0); - - // We have added document viewport position and document content position as members of the mouse event. When we create the event, we should initialize them as well. - event.populateDocumentPosition(m_lastMouseEvent.position(), viewportAccessor->documentContentsFromViewport(m_lastMouseEvent.position())); - - m_webPage->mouseEvent(event); -} - -IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const -{ - if (hasVirtualViewport()) - return m_virtualViewportSize; - - const int defaultLayoutWidth = m_defaultLayoutSize.width(); - const int defaultLayoutHeight = m_defaultLayoutSize.height(); - - int minWidth = defaultLayoutWidth; - int maxWidth = DEFAULT_MAX_LAYOUT_WIDTH; - int maxHeight = DEFAULT_MAX_LAYOUT_HEIGHT; - - // If the load state is none then we haven't actually got anything yet, but we need to layout - // the entire page so that the user sees the entire page (unrendered) instead of just part of it. - // If the load state is Provisional, it is possible that absoluteVisibleOverflowSize() and - // contentsSize() are based on the old page and cause inconsistent fixedLayoutSize, so layout the - // new page based on the defaultLayoutSize as well. - if (m_loadState == None || m_loadState == Provisional) - return IntSize(defaultLayoutWidth, defaultLayoutHeight); - - if (m_viewMode == FixedDesktop) { - int width = maxWidth; - // if the defaultLayoutHeight is at minimum, it probably was set as 0 - // and clamped, meaning it's effectively not set. (Even if it happened - // to be set exactly to the minimum, it's too small to be useful.) So - // ignore it. - int height; - if (defaultLayoutHeight <= minimumLayoutSize.height()) - height = maxHeight; - else - height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight)); - return IntSize(width, height); - } - - if (m_viewMode == Desktop) { - // If we detect an overflow larger than the contents size then use that instead since - // it'll still be clamped by the maxWidth below... - int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width()); - if (m_pendingOrientation != -1 && !m_nestedLayoutFinishedCount && !m_overflowExceedsContentsSize) - width = 0; - - if (snapToIncrement) { - // Snap to increments of defaultLayoutWidth / 2.0. - float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0); - factor = ceilf(factor); - width = (defaultLayoutWidth / 2.0) * factor; - } - - if (width < minWidth) - width = minWidth; - if (width > maxWidth) - width = maxWidth; - int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight)); - return IntSize(width, height); - } - - ASSERT_NOT_REACHED(); - return IntSize(defaultLayoutWidth, defaultLayoutHeight); -} - -BackingStoreClient* WebPagePrivate::backingStoreClient() const -{ - return m_backingStoreClient; -} - -void WebPagePrivate::clearDocumentData(const Document* documentGoingAway) -{ - ASSERT(documentGoingAway); - if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway) - m_currentContextNode = 0; - - if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway) - m_currentPinchZoomNode = 0; - - if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway) - m_currentBlockZoomAdjustedNode = 0; - - if (m_inRegionScroller->d->isActive()) - m_inRegionScroller->d->clearDocumentData(documentGoingAway); - - if (documentGoingAway->frame()) - m_inputHandler->frameUnloaded(documentGoingAway->frame()); - - Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node(); - if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway) - m_touchEventHandler->resetLastFatFingersResult(); - - // NOTE: m_fullscreenNode, m_fullScreenPluginView and m_pluginViews - // are cleared in other methods already. -} - -typedef bool (*PredicateFunction)(RenderLayer*); -static bool isPositionedContainer(RenderLayer* layer) -{ - RenderObject* o = layer->renderer(); - return o->isRenderView() || o->isOutOfFlowPositioned() || o->isRelPositioned() || layer->hasTransform(); -} - -static bool isFixedPositionedContainer(RenderLayer* layer) -{ - RenderObject* o = layer->renderer(); - return o->isRenderView() || (o->isOutOfFlowPositioned() && o->style()->position() == FixedPosition); -} - -static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer) -{ - RenderLayer* curr = layer; - while (curr && !predicate(curr)) - curr = curr->parent(); - - return curr; -} - -RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer) -{ - return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer); -} - -RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer) -{ - return findAncestorOrSelfNotMatching(&isPositionedContainer, layer); -} - -static inline Frame* frameForNode(Node* node) -{ - Node* origNode = node; - for (; node; node = node->parentNode()) { - if (RenderObject* renderer = node->renderer()) { - if (renderer->isRenderView()) { - if (FrameView* view = toRenderView(renderer)->frameView()) { - if (Frame* frame = view->frame()) - return frame; - } - } - if (renderer->isWidget()) { - Widget* widget = toRenderWidget(renderer)->widget(); - if (widget && widget->isFrameView()) { - if (Frame* frame = toFrameView(widget)->frame()) - return frame; - } - } - } - } - - for (node = origNode; node; node = node->parentNode()) { - if (Document* doc = node->document()) { - if (Frame* frame = doc->frame()) - return frame; - } - } - - return 0; -} - -static IntRect getNodeWindowRect(Node* node) -{ - if (Frame* frame = frameForNode(node)) { - if (FrameView* view = frame->view()) - return view->contentsToWindow(node->getRect()); - } - ASSERT_NOT_REACHED(); - return IntRect(); -} - -IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame) -{ - ASSERT(m_mainFrame); - - // Don't call this function asking to not clip the main frame providing only - // the main frame. All that can be returned is the content rect which - // isn't what this function is for. - if (noClipOfMainFrame && view == m_mainFrame->view()) { - ASSERT_NOT_REACHED(); - return IntRect(IntPoint::zero(), view->contentsSize()); - } - - IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect())); - if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) { - // Intersect with parent visible rect. - visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame)); - } - return visibleWindowRect; -} - -void WebPagePrivate::assignFocus(Platform::FocusDirection direction) -{ - ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone); - ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward); - ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward); - - // First we clear the focus, since we want to focus either initial or the last - // focusable element in the webpage (according to the TABINDEX), or simply clear - // the focus. - clearFocusNode(); - - switch (direction) { - case FocusDirectionForward: - case FocusDirectionBackward: - m_page->focusController()->setInitialFocus((FocusDirection) direction, 0); - break; - case FocusDirectionNone: - break; - default: - ASSERT_NOT_REACHED(); - } -} - -void WebPage::assignFocus(Platform::FocusDirection direction) -{ - if (d->m_page->defersLoading()) - return; - d->assignFocus(direction); -} - -void WebPage::focusNextField() -{ - d->m_inputHandler->focusNextField(); -} - -void WebPage::focusPreviousField() -{ - d->m_inputHandler->focusPreviousField(); -} - -void WebPage::submitForm() -{ - d->m_inputHandler->submitForm(); -} - -Platform::IntRect WebPagePrivate::focusNodeRect() -{ - Frame* frame = focusedOrMainFrame(); - if (!frame) - return Platform::IntRect(); - - Document* doc = frame->document(); - FrameView* view = frame->view(); - if (!doc || !view || view->needsLayout()) - return Platform::IntRect(); - - const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor; - - IntRect focusRect = rectForNode(doc->focusedElement()); - focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedElement()); - focusRect = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatRect(focusRect)); - focusRect.intersect(viewportAccessor->pixelContentsRect()); - return focusRect; -} - -PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy) -{ - EventHandler* eventHandler = focusedOrMainFrame()->eventHandler(); - const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult(); - bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased; - - // Check if we're using LinkToLink and the user is not touching the screen. - if (m_webSettings->doesGetFocusNodeContext() && !isTouching) { - RefPtr<Node> node; - node = m_page->focusController()->focusedOrMainFrame()->document()->focusedElement(); - if (node) { - IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize()); - if (!visibleRect.intersects(getNodeWindowRect(node.get()))) - return 0; - } - return node.release(); - } - - // Check for text input. - if (isTouching && lastFatFingersResult.isTextInput()) - return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed); - - if (strategy == RectBased) { - FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint(); - // Cache text result for later use. - m_touchEventHandler->cacheTextResult(result); - return result.node(FatFingersResult::ShadowContentNotAllowed); - } - if (strategy == FocusBased) - return m_inputHandler->currentFocusElement(); - - IntPoint contentPos; - if (isTouching) - contentPos = lastFatFingersResult.adjustedPosition(); - else - contentPos = m_webkitThreadViewportAccessor->documentContentsFromViewport(m_lastMouseEvent.position()); - - HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos); - return result.innerNode(); -} - -static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2) -{ - // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709). - double dx = static_cast<double>(p1.x() - p2.x()); - double dy = static_cast<double>(p1.y() - p2.y()); - return sqrt((dx * dx) + (dy * dy)); -} - -Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& documentPoint) -{ - IntRect clickRect(documentPoint.x() - blockClickRadius, documentPoint.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius); - Node* originalNode = nodeForZoomUnderPoint(documentPoint); - if (!originalNode) - return 0; - Node* node = bestChildNodeForClickRect(originalNode, clickRect); - return node ? adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(node) : adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(originalNode); -} - -Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect) -{ - if (!parentNode) - return 0; - - int bestDistance = std::numeric_limits<int>::max(); - - Node* node = parentNode->firstChild(); - Node* bestNode = 0; - for (; node; node = node->nextSibling()) { - IntRect rect = rectForNode(node); - if (!clickRect.intersects(rect)) - continue; - - int distance = distanceBetweenPoints(rect.center(), clickRect.center()); - Node* bestChildNode = bestChildNodeForClickRect(node, clickRect); - if (bestChildNode) { - IntRect bestChildRect = rectForNode(bestChildNode); - int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center()); - if (bestChildDistance < distance && bestChildDistance < bestDistance) { - bestNode = bestChildNode; - bestDistance = bestChildDistance; - } else { - if (distance < bestDistance) { - bestNode = node; - bestDistance = distance; - } - } - } else { - if (distance < bestDistance) { - bestNode = node; - bestDistance = distance; - } - } - } - - return bestNode; -} - -double WebPagePrivate::maxBlockZoomScale() const -{ - return std::min(maximumBlockZoomScale, maximumScale()); -} - -Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& documentPoint) -{ - if (!m_mainFrame) - return 0; - - HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(documentPoint); - - Node* node = result.innerNonSharedNode(); - - if (!node) - return 0; - - RenderObject* renderer = node->renderer(); - while (!renderer) { - node = node->parentNode(); - renderer = node->renderer(); - } - - return node; -} - -Node* WebPagePrivate::adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(Node* node) -{ - Node* initialNode = node; - RenderObject* renderer = node->renderer(); - bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maximumScale(); - IntSize actualVisibleSize = this->actualVisibleSize(); - - while (!renderer || !acceptableNodeSize) { - node = node->parentNode(); - IntRect nodeRect = rectForNode(node); - - // Don't choose a node if the width of the node size is very close to the width of the actual visible size, - // as block zoom can do nothing on such kind of node. - if (!node || static_cast<double>(actualVisibleSize.width() - nodeRect.width()) / actualVisibleSize.width() < minimumExpandingRatio) - return initialNode; - - renderer = node->renderer(); - acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maximumScale(); - } - - return node; -} - -bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2) -{ - if (!n1 || !n2) - return false; - - return (n2 == n1) || n2->isDescendantOf(n1); -} - -double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin) -{ - if (rect.isEmpty()) - return std::numeric_limits<double>::max(); - - ASSERT(rect.width() + margin); - - double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin); - - return newScale; -} - -IntRect WebPagePrivate::rectForNode(Node* node) -{ - if (!node) - return IntRect(); - - RenderObject* renderer = node->renderer(); - - if (!renderer) - return IntRect(); - - // Return rect in un-transformed content coordinates. - IntRect blockRect; - - // FIXME: Ensure this works with iframes. - if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) { - RenderBlock* renderBlock = renderer->containingBlock(); - int xOffset = 0; - int yOffset = 0; - while (!renderBlock->isRoot()) { - xOffset += renderBlock->x().toInt(); - yOffset += renderBlock->y().toInt(); - renderBlock = renderBlock->containingBlock(); - } - const RenderText* renderText = toRenderText(renderer); - IntRect linesBox = renderText->linesBoundingBox(); - blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height()); - } else - blockRect = IntRect(renderer->absoluteClippedOverflowRect()); - - if (renderer->isText()) { - RenderBlock* rb = renderer->containingBlock(); - - // Inefficient? Way to find width when floats intersect a block. - int blockWidth = 0; - int lineCount = rb->lineCount(); - for (int i = 0; i < lineCount; i++) - blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false).toInt()); - - blockRect.setWidth(blockWidth); - blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false)); - } - - // Strip off padding. - if (renderer->style()->hasPadding()) { - blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value()); - blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value()); - blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value()); - blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value()); - } - - return blockRect; -} - -IntPoint WebPagePrivate::frameOffset(const Frame* frame) const -{ - ASSERT(frame); - - // FIXME: This function can be called when page is being destroyed and JS triggers selection change. - // We could break the call chain at upper levels, but I think it is better to check the frame pointer - // here because the pointer is explicitly cleared in WebPage::destroy(). - if (!mainFrame()) - return IntPoint(); - - // Convert 0,0 in the frame's coordinate system to window coordinates to - // get the frame's global position, and return this position in the main - // frame's coordinates. (So the main frame's coordinates will be 0,0.) - return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero())); -} - -IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node) -{ - if (!node) - return rect; - - // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames. - // FIXME: can we just use frameOffset instead of this big routine? - const Node* tnode = node; - IntRect adjustedRect = rect; - do { - Frame* frame = tnode->document()->frame(); - if (!frame) - continue; - - Node* ownerNode = static_cast<Node*>(frame->ownerElement()); - tnode = ownerNode; - if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) { - IntRect iFrameRect; - do { - iFrameRect = rectForNode(ownerNode); - adjustedRect.move(iFrameRect.x(), iFrameRect.y()); - adjustedRect.intersect(iFrameRect); - ownerNode = ownerNode->parentNode(); - } while (iFrameRect.isEmpty() && ownerNode); - } else - break; - } while ((tnode = tnode->parentNode())); - - return adjustedRect; -} - -IntRect WebPagePrivate::blockZoomRectForNode(Node* node) -{ - if (!node || contentsSize().isEmpty()) - return IntRect(); - - Node* tnode = node; - m_currentBlockZoomAdjustedNode = tnode; - - IntRect blockRect = rectForNode(tnode); - IntRect originalRect = blockRect; - - int originalArea = originalRect.width() * originalRect.height(); - int pageArea = contentsSize().width() * contentsSize().height(); - double blockToPageRatio = static_cast<double>(pageArea - originalArea) / pageArea; - double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio; - - if (!isHTMLImageElement(tnode) && !isHTMLInputElement(tnode) && !isHTMLTextAreaElement(tnode)) { - while ((tnode = tnode->parentNode())) { - ASSERT(tnode); - IntRect tRect = rectForNode(tnode); - int tempBlockArea = tRect.width() * tRect.height(); - // Don't expand the block if it will be too large relative to the content. - if (static_cast<double>(pageArea - tempBlockArea) / pageArea < minimumExpandingRatio) - break; - if (tRect.isEmpty()) - continue; // No renderer. - if (tempBlockArea < 1.1 * originalArea) - continue; // The size of this parent is very close to the child, no need to go to this parent. - // Don't expand the block if the parent node size is already almost the size of actual visible size. - IntSize actualSize = actualVisibleSize(); - if (static_cast<double>(actualSize.width() - tRect.width()) / actualSize.width() < minimumExpandingRatio) - break; - if (tempBlockArea < blockExpansionRatio * originalArea) { - blockRect = tRect; - m_currentBlockZoomAdjustedNode = tnode; - } else - break; - } - } - - const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor; - - blockRect = adjustRectOffsetForFrameOffset(blockRect, node); - blockRect = viewportAccessor->roundToPixelFromDocumentContents(WebCore::FloatRect(blockRect)); - blockRect.intersect(viewportAccessor->pixelContentsRect()); - - return blockRect; -} - -// This function should not be called directly. -// It is called after the animation ends (see above). -void WebPagePrivate::zoomAnimationFinished(double finalAnimationScale, const WebCore::FloatPoint& finalAnimationDocumentScrollPosition, bool shouldConstrainScrollingToContentEdge) -{ - if (!m_mainFrame) - return; - - const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor; - - IntPoint anchor(viewportAccessor->roundedDocumentContents(finalAnimationDocumentScrollPosition)); - bool willUseTextReflow = false; - -#if ENABLE(VIEWPORT_REFLOW) - willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled; - toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock); - setNeedsLayout(); -#endif - - TransformationMatrix zoom; - zoom.scale(finalAnimationScale); - *m_transformationMatrix = zoom; - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->suspendBackingStoreUpdates(); - m_backingStore->d->suspendScreenUpdates(); - updateViewportSize(); - - FrameView* mainFrameView = m_mainFrame->view(); - bool constrainsScrollingToContentEdge = true; - if (mainFrameView) { - constrainsScrollingToContentEdge = mainFrameView->constrainsScrollingToContentEdge(); - mainFrameView->setConstrainsScrollingToContentEdge(shouldConstrainScrollingToContentEdge); - } - -#if ENABLE(VIEWPORT_REFLOW) - layoutIfNeeded(); - if (willUseTextReflow && m_shouldReflowBlock) { - Platform::IntPoint roundedReflowOffset( - std::floorf(m_finalAnimationDocumentScrollPositionReflowOffset.x()), - std::floorf(m_finalAnimationDocumentScrollPositionReflowOffset.y())); - - IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get()); - reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get()); - reflowedRect.move(roundedReflowOffset.x(), roundedReflowOffset.y()); - - RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer(); - IntPoint topLeftPoint(reflowedRect.location()); - if (renderer && renderer->isText()) { - ETextAlign textAlign = renderer->style()->textAlign(); - IntPoint textAnchor; - switch (textAlign) { - case CENTER: - case WEBKIT_CENTER: - textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y()); - break; - case LEFT: - case WEBKIT_LEFT: - textAnchor = topLeftPoint; - break; - case RIGHT: - case WEBKIT_RIGHT: - textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()); - break; - case TASTART: - case JUSTIFY: - default: - if (renderer->style()->isLeftToRightDirection()) - textAnchor = topLeftPoint; - else - textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()); - break; - } - setScrollPosition(textAnchor); - } else { - renderer->style()->isLeftToRightDirection() - ? setScrollPosition(topLeftPoint) - : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y())); - } - } else if (willUseTextReflow) { - IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get()); - finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get()); - setScrollPosition(IntPoint(0, finalRect.y() + m_finalAnimationDocumentScrollPositionReflowOffset.y())); - resetBlockZoom(); - } -#endif - if (!willUseTextReflow) { - setScrollPosition(anchor); - if (!m_shouldReflowBlock) - resetBlockZoom(); - } - - notifyTransformChanged(); - m_client->scaleChanged(); - - if (mainFrameView) - mainFrameView->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge); - - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->resumeBackingStoreUpdates(); - m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); -} - -void WebPage::zoomAnimationFinished(double finalScale, const Platform::FloatPoint& finalDocumentScrollPosition, bool shouldConstrainScrollingToContentEdge) -{ - d->zoomAnimationFinished(finalScale, finalDocumentScrollPosition, shouldConstrainScrollingToContentEdge); -} - -void WebPage::resetBlockZoom() -{ - d->resetBlockZoom(); -} - -void WebPagePrivate::resetBlockZoom() -{ - m_currentBlockZoomNode = 0; - m_currentBlockZoomAdjustedNode = 0; - m_shouldReflowBlock = false; -} - -void WebPage::destroyWebPageCompositor() -{ -#if USE(ACCELERATED_COMPOSITING) - // Destroy the layer renderer in a sync command before we destroy the backing store, - // to flush any pending compositing messages on the compositing thread. - // The backing store is indirectly deleted by the 'detachFromParent' call below. - d->syncDestroyCompositorOnCompositingThread(); -#endif -} - -void WebPage::destroy() -{ - // TODO: need to verify if this call needs to be made before calling - // Close the Inspector to resume the JS engine if it's paused. - disableWebInspector(); - - // WebPage::destroyWebPageCompositor() - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - d->m_backingStore->d->suspendBackingStoreUpdates(); - d->m_backingStore->d->suspendScreenUpdates(); - - // Close the backforward list and release the cached pages. - d->m_page->backForward()->close(); - - FrameLoader* loader = d->m_mainFrame->loader(); - - // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion. - d->m_mainFrame = 0; - if (loader) - loader->detachFromParent(); - - deleteGuardedObject(this); -} - -WebPageClient* WebPage::client() const -{ - return d->m_client; -} - -int WebPage::backForwardListLength() const -{ - return d->m_page->getHistoryLength(); -} - -bool WebPage::canGoBackOrForward(int delta) const -{ - return d->m_page->canGoBackOrForward(delta); -} - -bool WebPage::goBackOrForward(int delta) -{ - if (d->m_page->canGoBackOrForward(delta)) { - d->m_userPerformedManualZoom = false; - d->m_userPerformedManualScroll = false; - d->m_backingStore->d->suspendScreenUpdates(); - d->m_page->goBackOrForward(delta); - d->m_backingStore->d->resumeScreenUpdates(BackingStore::None); - return true; - } - return false; -} - -void WebPage::goToBackForwardEntry(BackForwardId id) -{ - HistoryItem* item = historyItemFromBackForwardId(id); - ASSERT(item); - d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward); -} - -void WebPage::reload() -{ - d->m_mainFrame->loader()->reload(/* bypassCache */ true); -} - -void WebPage::reloadFromCache() -{ - d->m_mainFrame->loader()->reload(/* bypassCache */ false); -} - -WebSettings* WebPage::settings() const -{ - return d->m_webSettings; -} - -WebCookieJar* WebPage::cookieJar() const -{ - if (!d->m_cookieJar) - d->m_cookieJar = new WebCookieJar(); - - return d->m_cookieJar; -} - -bool WebPage::isLoading() const -{ - return d->isLoading(); -} - -bool WebPage::isVisible() const -{ - return d->m_visible; -} - -#if ENABLE(PAGE_VISIBILITY_API) -class DeferredTaskSetPageVisibilityState: public DeferredTask<&WebPagePrivate::m_wouldSetPageVisibilityState> { -public: - explicit DeferredTaskSetPageVisibilityState(WebPagePrivate* webPagePrivate) - : DeferredTaskType(webPagePrivate) - { - } -private: - virtual void performInternal(WebPagePrivate* webPagePrivate) - { - webPagePrivate->setPageVisibilityState(); - } -}; - -void WebPagePrivate::setPageVisibilityState() -{ - if (m_page->defersLoading()) - m_deferredTasks.append(adoptPtr(new DeferredTaskSetPageVisibilityState(this))); - else { - DeferredTaskSetPageVisibilityState::finishOrCancel(this); - - static bool s_initialVisibilityState = true; - - m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState); - s_initialVisibilityState = false; - } -} -#endif - -void WebPagePrivate::setVisible(bool visible) -{ - if (visible != m_visible) { - if (visible) { - if (m_mainFrame) - m_mainFrame->animation()->resumeAnimations(); - if (m_page->scriptedAnimationsSuspended()) - m_page->resumeScriptedAnimations(); - } else { - if (m_mainFrame) - m_mainFrame->animation()->suspendAnimations(); - if (!m_page->scriptedAnimationsSuspended()) - m_page->suspendScriptedAnimations(); - - closePagePopup(); - } - - m_visible = visible; - m_backingStore->d->updateSuspendScreenUpdateState(); - } - -#if ENABLE(PAGE_VISIBILITY_API) - setPageVisibilityState(); -#endif -} - -void WebPage::setVisible(bool visible) -{ - if (d->m_visible == visible) - return; - - d->setVisible(visible); - AuthenticationChallengeManager::instance()->pageVisibilityChanged(d, visible); - - if (!visible) { - d->suspendBackingStore(); - - // Remove this WebPage from the visible pages list. - size_t foundIndex = visibleWebPages()->find(this); - if (foundIndex != WTF::notFound) - visibleWebPages()->remove(foundIndex); - - // Return the backing store to the last visible WebPage. - if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty()) - visibleWebPages()->last()->d->resumeBackingStore(); - -#if USE(ACCELERATED_COMPOSITING) - // Root layer commit is not necessary for invisible tabs. - // And release layer resources can reduce memory consumption. - d->updateRootLayerCommitEnabled(); -#endif - - return; - } - -#if USE(ACCELERATED_COMPOSITING) - d->updateRootLayerCommitEnabled(); -#endif - - // We want to become visible but not get backing store ownership. - if (d->m_backingStore->d->isOpenGLCompositing() && !d->m_webSettings->isBackingStoreEnabled()) { - d->setCompositorDrawsRootLayer(true); -#if USE(ACCELERATED_COMPOSITING) - d->setNeedsOneShotDrawingSynchronization(); -#endif - d->setShouldResetTilesWhenShown(true); - return; - } - - // Push this WebPage to the top of the visible pages list. - if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) { - size_t foundIndex = visibleWebPages()->find(this); - if (foundIndex != WTF::notFound) - visibleWebPages()->remove(foundIndex); - } - visibleWebPages()->append(this); - - if (BackingStorePrivate::currentBackingStoreOwner() - && BackingStorePrivate::currentBackingStoreOwner() != this) - BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore(); - - // resumeBackingStore will set the current owner to this webpage. - // If we set the owner prematurely, then the tiles will not be reset. - d->resumeBackingStore(); -} - -void WebPagePrivate::selectionChanged(Frame* frame) -{ - m_inputHandler->selectionChanged(); - - // FIXME: This is a hack! - // To ensure the selection being changed has its frame 'focused', lets - // set it as focused ourselves (PR #104724). - m_page->focusController()->setFocusedFrame(frame); -} - -void WebPagePrivate::updateSelectionScrollView(const Node* node) -{ - m_inRegionScroller->d->updateSelectionScrollView(node); -} - -void WebPagePrivate::updateDelegatedOverlays(bool dispatched) -{ - // Track a dispatched message, we don't want to flood the webkit thread. - // There can be as many as one more message enqued as needed but never less. - if (dispatched) - m_updateDelegatedOverlaysDispatched = false; - else if (m_updateDelegatedOverlaysDispatched) { - // Early return if there is message already pending on the webkit thread. - return; - } - - if (Platform::webKitThreadMessageClient()->isCurrentThread()) { - // Must be called on the WebKit thread. - if (m_selectionHandler->isSelectionActive()) - m_selectionHandler->selectionPositionChanged(); - if (m_inspectorOverlay) - m_inspectorOverlay->update(); - - } else if (m_selectionHandler->isSelectionActive()) { - // Don't bother dispatching to webkit thread if selection and tap highlight are not active. - m_updateDelegatedOverlaysDispatched = true; - Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/)); - } -} - -void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle) -{ -} - -bool WebPage::setBatchEditingActive(bool active) -{ - return d->m_inputHandler->setBatchEditingActive(active); -} - -bool WebPage::setInputSelection(unsigned start, unsigned end) -{ - if (d->m_page->defersLoading()) - return false; - return d->m_inputHandler->setSelection(start, end); -} - -int WebPage::inputCaretPosition() const -{ - return d->m_inputHandler->caretPosition(); -} - -class DeferredTaskPopupListSelectMultiple: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectMultiple> { -public: - DeferredTaskPopupListSelectMultiple(WebPagePrivate* webPagePrivate, int size, const bool* selecteds) - : DeferredTaskType(webPagePrivate) - { - webPagePrivate->m_cachedPopupListSelecteds.append(selecteds, size); - } -private: - virtual void performInternal(WebPagePrivate* webPagePrivate) - { - webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelecteds.size(), webPagePrivate->m_cachedPopupListSelecteds.data()); - } -}; - -class DeferredTaskPopupListSelectSingle: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectSingle> { -public: - explicit DeferredTaskPopupListSelectSingle(WebPagePrivate* webPagePrivate, int index) - : DeferredTaskType(webPagePrivate) - { - webPagePrivate->m_cachedPopupListSelectedIndex = index; - } -private: - virtual void performInternal(WebPagePrivate* webPagePrivate) - { - webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelectedIndex); - } -}; - -void WebPage::popupListClosed(int size, const bool* selecteds) -{ - DeferredTaskPopupListSelectSingle::finishOrCancel(d); - if (d->m_page->defersLoading()) { - d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectMultiple(d, size, selecteds))); - return; - } - DeferredTaskPopupListSelectMultiple::finishOrCancel(d); - d->m_inputHandler->setPopupListIndexes(size, selecteds); -} - -void WebPage::popupListClosed(int index) -{ - DeferredTaskPopupListSelectMultiple::finishOrCancel(d); - if (d->m_page->defersLoading()) { - d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectSingle(d, index))); - return; - } - DeferredTaskPopupListSelectSingle::finishOrCancel(d); - d->m_inputHandler->setPopupListIndex(index); -} - -class DeferredTaskSetDateTimeInput: public DeferredTask<&WebPagePrivate::m_wouldSetDateTimeInput> { -public: - explicit DeferredTaskSetDateTimeInput(WebPagePrivate* webPagePrivate, BlackBerry::Platform::String value) - : DeferredTaskType(webPagePrivate) - { - webPagePrivate->m_cachedDateTimeInput = value; - } -private: - virtual void performInternal(WebPagePrivate* webPagePrivate) - { - webPagePrivate->m_webPage->setDateTimeInput(webPagePrivate->m_cachedDateTimeInput); - } -}; - -void WebPage::setDateTimeInput(const BlackBerry::Platform::String& value) -{ - if (d->m_page->defersLoading()) { - d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetDateTimeInput(d, value))); - return; - } - DeferredTaskSetDateTimeInput::finishOrCancel(d); - d->m_inputHandler->setInputValue(value); -} - -class DeferredTaskSetColorInput: public DeferredTask<&WebPagePrivate::m_wouldSetColorInput> { -public: - explicit DeferredTaskSetColorInput(WebPagePrivate* webPagePrivate, BlackBerry::Platform::String value) - : DeferredTaskType(webPagePrivate) - { - webPagePrivate->m_cachedColorInput = value; - } -private: - virtual void performInternal(WebPagePrivate* webPagePrivate) - { - webPagePrivate->m_webPage->setColorInput(webPagePrivate->m_cachedColorInput); - } -}; - -void WebPage::setColorInput(const BlackBerry::Platform::String& value) -{ - if (d->m_page->defersLoading()) { - d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetColorInput(d, value))); - return; - } - DeferredTaskSetColorInput::finishOrCancel(d); - d->m_inputHandler->setInputValue(value); -} - -void WebPage::setVirtualViewportSize(const Platform::IntSize& size) -{ - d->m_virtualViewportSize = WebCore::IntSize(size); -} - -void WebPage::resetVirtualViewportOnCommitted(bool reset) -{ - d->m_resetVirtualViewportOnCommitted = reset; -} - -Platform::IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments() -{ - static const ViewportArguments defaultViewportArguments; - if (m_viewportArguments == defaultViewportArguments) - return IntSize(); - - int desktopWidth = DEFAULT_MAX_LAYOUT_WIDTH; - int deviceWidth = Platform::Graphics::Screen::primaryScreen()->width(); - int deviceHeight = Platform::Graphics::Screen::primaryScreen()->height(); - float devicePixelRatio = m_webSettings->devicePixelRatio(); - ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, devicePixelRatio, m_defaultLayoutSize); - m_page->setDeviceScaleFactor(devicePixelRatio); - - setUserScalable(m_webSettings->isUserScalable() && result.userScalable); - if (result.initialScale > 0) - setInitialScale(result.initialScale * devicePixelRatio); - if (result.minimumScale > 0) - setMinimumScale(result.minimumScale * devicePixelRatio); - if (result.maximumScale > 0) - setMaximumScale(result.maximumScale * devicePixelRatio); - - return Platform::IntSize(result.layoutSize.width(), result.layoutSize.height()); -} - -#if ENABLE(EVENT_MODE_METATAGS) -void WebPagePrivate::didReceiveCursorEventMode(CursorEventMode mode) -{ - if (mode != m_cursorEventMode) - m_client->cursorEventModeChanged(toPlatformCursorEventMode(mode)); - m_cursorEventMode = mode; -} - -void WebPagePrivate::didReceiveTouchEventMode(TouchEventMode mode) -{ - if (mode != m_touchEventMode) - m_client->touchEventModeChanged(toPlatformTouchEventMode(mode)); - m_touchEventMode = mode; -} -#endif - -void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments) -{ - if (arguments == m_viewportArguments) - return; - - // If the caller is trying to reset to default arguments, use the user supplied ones instead. - static const ViewportArguments defaultViewportArguments; - if (arguments == defaultViewportArguments) { - m_viewportArguments = m_userViewportArguments; - m_forceRespectViewportArguments = m_userViewportArguments != defaultViewportArguments; - } else - m_viewportArguments = arguments; - - // 0 width or height in viewport arguments makes no sense, and results in a very large initial scale. - // In real world, a 0 width or height is usually caused by a syntax error in "content" field of viewport - // meta tag, for example, using semicolon instead of comma as separator ("width=device-width; initial-scale=1.0"). - // We don't have a plan to tolerate the semicolon separator, but we can avoid applying 0 width/height. - // I default it to ValueDeviceWidth rather than ValueAuto because in more cases the web site wants "device-width" - // when they specify the viewport width. - if (!m_viewportArguments.width) - m_viewportArguments.width = ViewportArguments::ValueDeviceWidth; - if (!m_viewportArguments.height) - m_viewportArguments.height = ViewportArguments::ValueDeviceHeight; - - Platform::IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments(); - m_webPage->setVirtualViewportSize(virtualViewport); - - // Reset m_userPerformedManualZoom and enable m_shouldZoomToInitialScaleAfterLoadFinished so that we can relayout - // the page and zoom it to fit the screen when we dynamically change the meta viewport after the load is finished. - bool isLoadFinished = loadState() == Finished; - if (isLoadFinished) { - m_userPerformedManualZoom = false; - setShouldZoomToInitialScaleAfterLoadFinished(true); - } - if (loadState() == Committed || isLoadFinished) - zoomToInitialScaleOnLoad(); -} - -void WebPagePrivate::suspendBackingStore() -{ -#if USE(ACCELERATED_COMPOSITING) - if (m_backingStore->d->isOpenGLCompositing()) { - // A visible web page's backing store can be suspended when another web - // page is taking over the backing store. - if (m_visible) - setCompositorDrawsRootLayer(true); - - return; - } -#endif -} - -void WebPagePrivate::resumeBackingStore() -{ - ASSERT(m_webPage->isVisible()); - - if (!m_backingStore->d->isActive() || shouldResetTilesWhenShown()) { - BackingStorePrivate::setCurrentBackingStoreOwner(m_webPage); - - // If we're OpenGL compositing, switching to accel comp drawing of the root layer - // is a good substitute for backingstore blitting. - if (m_backingStore->d->isOpenGLCompositing()) - setCompositorDrawsRootLayer(!m_backingStore->d->isActive()); - - m_backingStore->d->orientationChanged(); // Updates tile geometry and creates visible tile buffer. - m_backingStore->d->resetTiles(); - m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */); - -#if USE(ACCELERATED_COMPOSITING) - setNeedsOneShotDrawingSynchronization(); -#endif - - m_backingStore->d->renderAndBlitVisibleContentsImmediately(); - } else { - if (m_backingStore->d->isOpenGLCompositing()) - setCompositorDrawsRootLayer(false); - - // Rendering was disabled while we were hidden, so we need to update all tiles. - m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */); -#if USE(ACCELERATED_COMPOSITING) - setNeedsOneShotDrawingSynchronization(); -#endif - } - - setShouldResetTilesWhenShown(false); -} - -void WebPagePrivate::setScreenOrientation(int orientation) -{ - FOR_EACH_PLUGINVIEW(m_pluginViews) - (*it)->handleOrientationEvent(orientation); - - m_pendingOrientation = -1; - -#if ENABLE(ORIENTATION_EVENTS) - if (m_mainFrame->orientation() == orientation) - return; - for (RefPtr<Frame> frame = m_mainFrame; frame; frame = frame->tree()->traverseNext()) - frame->sendOrientationChangeEvent(orientation); -#endif -} - -void WebPage::setScreenOrientation(int orientation) -{ - d->m_pendingOrientation = orientation; -} - -void WebPage::applyPendingOrientationIfNeeded() -{ - if (d->m_pendingOrientation != -1) - d->setScreenOrientation(d->m_pendingOrientation); - - // After rotation, we should redraw the dialog box instead of just moving it since rotation dismisses all dialogs. - d->m_inputHandler->redrawSpellCheckDialogIfRequired(false /* shouldMoveDialog */); -} - -bool WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize, const IntSize& defaultLayoutSize, bool ensureFocusElementVisible) -{ - if (m_pendingOrientation == -1 && transformedActualVisibleSize == this->transformedActualVisibleSize()) - return false; - - // Suspend all screen updates to the backingstore to make sure no-one tries to blit - // while the window surface and the BackingStore are out of sync. - BackingStore::ResumeUpdateOperation screenResumeOperation = BackingStore::Blit; - m_backingStore->d->suspendScreenUpdates(); - m_backingStore->d->suspendBackingStoreUpdates(); - - // The screen rotation is a major state transition that in this case is not properly - // communicated to the backing store, since it does early return in most methods when - // not visible. - if (!m_visible || !m_backingStore->d->isActive()) - setShouldResetTilesWhenShown(true); - - bool hasPendingOrientation = m_pendingOrientation != -1; - - IntSize viewportSizeBefore = actualVisibleSize(); - FloatPoint centerOfVisibleContentsRect = this->centerOfVisibleContentsRect(); - bool newVisibleRectContainsOldVisibleRect = (m_actualVisibleHeight <= transformedActualVisibleSize.height()) - && (m_actualVisibleWidth <= transformedActualVisibleSize.width()); - - bool atInitialScale = m_webPage->isAtInitialZoom(); - bool atTop = !scrollPosition().y(); - bool atLeft = !scrollPosition().x(); - - setDefaultLayoutSize(defaultLayoutSize); - - // Recompute our virtual viewport. - bool needsLayout = false; - Platform::IntSize newVirtualViewport = recomputeVirtualViewportFromViewportArguments(); - if (!newVirtualViewport.isEmpty()) { - m_webPage->setVirtualViewportSize(newVirtualViewport); - m_mainFrame->view()->setUseFixedLayout(useFixedLayout()); - m_mainFrame->view()->setFixedLayoutSize(fixedLayoutSize()); - needsLayout = true; - } - - // We switch this strictly after recomputing our virtual viewport as zoomToFitScale is dependent - // upon these values and so is the virtual viewport recalculation. - m_actualVisibleWidth = transformedActualVisibleSize.width(); - m_actualVisibleHeight = transformedActualVisibleSize.height(); - - IntSize viewportSizeAfter = actualVisibleSize(); - - IntSize offset; - if (hasPendingOrientation && !m_fullscreenNode) { - offset = IntSize(roundf((viewportSizeBefore.width() - viewportSizeAfter.width()) / 2.0), - roundf((viewportSizeBefore.height() - viewportSizeAfter.height()) / 2.0)); - } - - // As a special case, if we were anchored to the top left position at - // the beginning of the rotation then preserve that anchor. - if (atTop) - offset.setHeight(0); - if (atLeft) - offset.setWidth(0); - - // If we're about to overscroll, cap the offset to valid content. - IntPoint bottomRight( - scrollPosition().x() + viewportSizeAfter.width(), - scrollPosition().y() + viewportSizeAfter.height()); - - if (bottomRight.x() + offset.width() > contentsSize().width()) - offset.setWidth(contentsSize().width() - bottomRight.x()); - if (bottomRight.y() + offset.height() > contentsSize().height()) - offset.setHeight(contentsSize().height() - bottomRight.y()); - if (scrollPosition().x() + offset.width() < 0) - offset.setWidth(-scrollPosition().x()); - if (scrollPosition().y() + offset.height() < 0) - offset.setHeight(-scrollPosition().y()); - - // ...before scrolling, because the backing store will align its - // tile matrix with the viewport as reported by the ScrollView. - setScrollPosition(scrollPosition() + offset); - notifyTransformedScrollChanged(); - - m_backingStore->d->orientationChanged(); - m_backingStore->d->actualVisibleSizeChanged(transformedActualVisibleSize); - - // Update view mode only after we have updated the actual - // visible size and reset the contents rect if necessary. - if (setViewMode(viewMode())) - needsLayout = true; - - bool needsLayoutToFindContentSize = hasPendingOrientation; - - // We need to update the viewport size of the WebCore::ScrollView... - updateViewportSize(!needsLayoutToFindContentSize /* setFixedReportedSize */, false /* sendResizeEvent */); - notifyTransformedContentsSizeChanged(); - - // If automatic zooming is disabled, prevent zooming below. - if (!m_webSettings->isZoomToFitOnLoad()) { - atInitialScale = false; - - // Normally, if the contents size is smaller than the layout width, - // we would zoom in. If zoom is disabled, we need to do something else, - // or there will be artifacts due to non-rendered areas outside of the - // contents size. If there is a virtual viewport, we are not allowed - // to modify the fixed layout size, however. - if (!hasVirtualViewport() && contentsSize().width() < m_defaultLayoutSize.width()) { - m_mainFrame->view()->setUseFixedLayout(useFixedLayout()); - m_mainFrame->view()->setFixedLayoutSize(m_defaultLayoutSize); - needsLayout = true; - } - } - - // Need to resume so that the backingstore will start recording the invalidated - // rects from below. - m_backingStore->d->resumeBackingStoreUpdates(); - - // We might need to layout here to get a correct contentsSize so that zoomToFit - // is calculated correctly. - bool stillNeedsLayout = needsLayout; - while (stillNeedsLayout) { - setNeedsLayout(); - layoutIfNeeded(); - stillNeedsLayout = false; - - // Emulate the zoomToFitWidthOnLoad algorithm if we're rotating. - ++m_nestedLayoutFinishedCount; - if (needsLayoutToFindContentSize) { - if (setViewMode(viewMode())) - stillNeedsLayout = true; - } - } - m_nestedLayoutFinishedCount = 0; - - // As a special case if we were zoomed to the initial scale at the beginning - // of the rotation then preserve that zoom level even when it is zoomToFit. - double scale = atInitialScale ? initialScale() : currentScale(); - - // Do our own clamping. - scale = clampedScale(scale); - - if (needsLayoutToFindContentSize) { - // Set the fixed reported size here so that innerWidth|innerHeight works - // with this new scale. - TransformationMatrix rotationMatrix; - rotationMatrix.scale(scale); - IntRect viewportRect = IntRect(IntPoint::zero(), transformedActualVisibleSize); - IntRect actualVisibleRect = enclosingIntRect(rotationMatrix.inverse().mapRect(FloatRect(viewportRect))); - m_mainFrame->view()->setFixedReportedSize(actualVisibleRect.size()); - m_mainFrame->view()->repaintFixedElementsAfterScrolling(); - layoutIfNeeded(); - m_mainFrame->view()->updateFixedElementsAfterScrolling(); - } - - // We're going to need to send a resize event to JavaScript because - // innerWidth and innerHeight depend on fixed reported size. - // This is how we support mobile pages where JavaScript resizes - // the page in order to get around the fixed layout size, e.g. - // google maps when it detects a mobile user agent. - if (shouldSendResizeEvent()) - m_mainFrame->eventHandler()->sendResizeEvent(); - - // As a special case if we were anchored to the top left position at the beginning - // of the rotation then preserve that anchor. - FloatPoint anchor = centerOfVisibleContentsRect; - if (atTop) - anchor.setY(0); - if (atLeft) - anchor.setX(0); - - // Try and zoom here with clamping on. - // FIXME: Determine why the above comment says "clamping on", yet we - // don't set enforceScaleClamping to true. - if (zoomAboutPoint(scale, anchor, false /*enforceScaleClamping*/, true /*forceRendering*/)) { - if (ensureFocusElementVisible) - ensureContentVisible(!newVisibleRectContainsOldVisibleRect); - } else { - // Suspend all updates to the backingstore. - m_backingStore->d->suspendBackingStoreUpdates(); - - // If the zoom failed, then we should still preserve the special case of scroll position. - IntPoint scrollPosition = this->scrollPosition(); - if (atTop) - scrollPosition.setY(0); - if (atLeft) - scrollPosition.setX(0); - setScrollPosition(scrollPosition); - - // These might have been altered even if we didn't zoom so notify the client. - notifyTransformedContentsSizeChanged(); - notifyTransformedScrollChanged(); - - if (!needsLayout) { - // The visible tiles for scroll must be up-to-date before we blit since we are not performing a layout. - m_backingStore->d->updateTilesForScrollOrNotRenderedRegion(); - } - - if (ensureFocusElementVisible) - ensureContentVisible(!newVisibleRectContainsOldVisibleRect); - - if (needsLayout) { - m_backingStore->d->resetTiles(); - m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */); - screenResumeOperation = BackingStore::RenderAndBlit; - } - - // If we need layout then render and blit, otherwise just blit as our viewport has changed. - m_backingStore->d->resumeBackingStoreUpdates(); - } - -#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO) - // When leaving fullscreen mode, restore the scale and scroll position if needed. - // We also need to make sure the scale and scroll position won't cause over scale or over scroll. - if (m_scaleBeforeFullScreen > 0 && !m_fullscreenNode) { - // Restore the scale when leaving fullscreen. We can't use TransformationMatrix::scale(double) here, - // as it will multiply the scale rather than set the scale. - // FIXME: We can refactor this into setCurrentScale(double) if it is useful in the future. - if (m_orientationBeforeFullScreen % 180 != orientation() % 180) { // Orientation changed - if (m_actualVisibleWidth > contentsSize().width() * m_scaleBeforeFullScreen) { - // Cached scale need to be adjusted after rotation. - m_scaleBeforeFullScreen = double(m_actualVisibleWidth) / contentsSize().width(); - } - if (m_scaleBeforeFullScreen * contentsSize().height() < m_actualVisibleHeight) { - // Use zoom to fit height scale in order to cover the screen height. - m_scaleBeforeFullScreen = double(m_actualVisibleHeight) / contentsSize().height(); - } - - if (m_actualVisibleWidth > m_scaleBeforeFullScreen * (contentsSize().width() - m_scrollPositionBeforeFullScreen.x())) { - // Cached scroll position over scrolls horizontally after rotation. - m_scrollPositionBeforeFullScreen.setX(contentsSize().width() - m_actualVisibleWidth / m_scaleBeforeFullScreen); - } - if (m_actualVisibleHeight > m_scaleBeforeFullScreen * (contentsSize().height() - m_scrollPositionBeforeFullScreen.y())) { - // Cached scroll position over scrolls vertically after rotation. - m_scrollPositionBeforeFullScreen.setY(contentsSize().height() - m_actualVisibleHeight / m_scaleBeforeFullScreen); - } - } - - m_transformationMatrix->setM11(m_scaleBeforeFullScreen); - m_transformationMatrix->setM22(m_scaleBeforeFullScreen); - m_scaleBeforeFullScreen = -1.0; - - setScrollPosition(m_scrollPositionBeforeFullScreen); - notifyTransformChanged(); - m_client->scaleChanged(); - } -#endif - - m_backingStore->d->resumeScreenUpdates(screenResumeOperation); - m_inputHandler->redrawSpellCheckDialogIfRequired(); - - return true; -} - -void WebPage::setViewportSize(const Platform::IntSize& viewportSize, const Platform::IntSize& defaultLayoutSize, bool ensureFocusElementVisible) -{ - if (!d->setViewportSize(viewportSize, defaultLayoutSize, ensureFocusElementVisible)) { - // If the viewport didn't change, try to apply only the new default layout size. - setDefaultLayoutSize(defaultLayoutSize); - } -} - -void WebPagePrivate::setDefaultLayoutSize(const IntSize& size) -{ - IntSize screenSize = Platform::Settings::instance()->applicationSize(); - ASSERT(size.width() <= screenSize.width() && size.height() <= screenSize.height()); - m_defaultLayoutSize = size.expandedTo(minimumLayoutSize).shrunkTo(screenSize); -} - -Platform::IntSize WebPage::defaultLayoutSize() const -{ - return d->m_defaultLayoutSize; -} - -void WebPage::setDefaultLayoutSize(const Platform::IntSize& platformSize) -{ - bool needsLayout = false; - WebCore::IntSize size = platformSize; - if (size == d->m_defaultLayoutSize) - return; - - d->setDefaultLayoutSize(size); - - // The default layout size affects interpretation of any viewport arguments present. - Platform::IntSize virtualViewportSize = d->recomputeVirtualViewportFromViewportArguments(); - if (!virtualViewportSize.isEmpty()) { - setVirtualViewportSize(virtualViewportSize); - needsLayout = true; - } - - if (d->setViewMode(d->viewMode())) - needsLayout = true; - - if (needsLayout) { - d->setNeedsLayout(); - if (!d->isLoading()) - d->layoutIfNeeded(); - } -} - -bool WebPage::mouseEvent(const Platform::MouseEvent& mouseEvent, bool* wheelDeltaAccepted) -{ - if (!d->m_mainFrame->view()) - return false; - - if (d->m_page->defersLoading()) - return false; - - PluginView* pluginView = d->m_fullScreenPluginView.get(); - if (pluginView) - return d->dispatchMouseEventToFullScreenPlugin(pluginView, mouseEvent); - - if (mouseEvent.type() == Platform::MouseEvent::MouseAborted) { - d->m_mainFrame->eventHandler()->setMousePressed(false); - return false; - } - - d->m_pluginMayOpenNewTab = true; - - d->m_lastUserEventTimestamp = currentTime(); - int clickCount = (d->m_selectionHandler->isSelectionActive() || mouseEvent.type() != Platform::MouseEvent::MouseMove) ? 1 : 0; - - // Set the button type. - MouseButton buttonType = NoButton; - if (mouseEvent.isLeftButton()) - buttonType = LeftButton; - else if (mouseEvent.isRightButton()) - buttonType = RightButton; - else if (mouseEvent.isMiddleButton()) - buttonType = MiddleButton; - - // Create our event. - PlatformMouseEvent platformMouseEvent(mouseEvent.documentViewportPosition(), mouseEvent.screenPosition(), - toWebCoreMouseEventType(mouseEvent.type()), clickCount, buttonType, - mouseEvent.shiftActive(), mouseEvent.ctrlActive(), mouseEvent.altActive(), PointingDevice); - d->m_lastMouseEvent = platformMouseEvent; - bool success = d->handleMouseEvent(platformMouseEvent); - - if (mouseEvent.wheelTicks()) { - PlatformWheelEvent wheelEvent(mouseEvent.documentViewportPosition(), mouseEvent.screenPosition(), - 0, -mouseEvent.wheelDelta(), - 0, -mouseEvent.wheelTicks(), - ScrollByPixelWheelEvent, - mouseEvent.shiftActive(), mouseEvent.ctrlActive(), - mouseEvent.altActive(), false /* metaKey */); - if (wheelDeltaAccepted) - *wheelDeltaAccepted = d->handleWheelEvent(wheelEvent); - } else if (wheelDeltaAccepted) - *wheelDeltaAccepted = false; - - return success; -} - -bool WebPagePrivate::dispatchMouseEventToFullScreenPlugin(PluginView* plugin, const Platform::MouseEvent& event) -{ - NPEvent npEvent; - NPMouseEvent mouseEvent; - - mouseEvent.x = event.screenPosition().x(); - mouseEvent.y = event.screenPosition().y(); - - switch (event.type()) { - case Platform::MouseEvent::MouseButtonDown: - mouseEvent.type = MOUSE_BUTTON_DOWN; - m_pluginMouseButtonPressed = true; - break; - case Platform::MouseEvent::MouseButtonUp: - mouseEvent.type = MOUSE_BUTTON_UP; - m_pluginMouseButtonPressed = false; - break; - case Platform::MouseEvent::MouseMove: - mouseEvent.type = MOUSE_MOTION; - break; - default: - return false; - } - - mouseEvent.flags = 0; - mouseEvent.button = m_pluginMouseButtonPressed; - - npEvent.type = NP_MouseEvent; - npEvent.data = &mouseEvent; - - return plugin->dispatchFullScreenNPEvent(npEvent); -} - -bool WebPagePrivate::handleMouseEvent(PlatformMouseEvent& mouseEvent) -{ - EventHandler* eventHandler = m_mainFrame->eventHandler(); - - if (mouseEvent.type() == WebCore::PlatformEvent::MouseMoved) - return eventHandler->mouseMoved(mouseEvent); - - if (mouseEvent.type() == WebCore::PlatformEvent::MouseScroll) - return true; - - Node* node = 0; - if (mouseEvent.inputMethod() == TouchScreen) { - const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult(); - - // Fat fingers can deal with shadow content. - node = lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed); - - // Save mouse event state for later. This allows us to know why some responses have occurred, namely selection changes. - m_touchEventHandler->m_userTriggeredTouchPressOnTextInput = mouseEvent.type() == WebCore::PlatformEvent::MousePressed && lastFatFingersResult.isTextInput(); - } - - if (!node) { - IntPoint documentContentsPoint = m_webkitThreadViewportAccessor->documentContentsFromViewport(mouseEvent.position()); - HitTestResult result = eventHandler->hitTestResultAtPoint(documentContentsPoint); - node = result.innerNode(); - } - - if (mouseEvent.type() == WebCore::PlatformEvent::MousePressed) { - m_inputHandler->setInputModeEnabled(); - if (m_inputHandler->willOpenPopupForNode(node)) { - // Do not allow any human generated mouse or keyboard events to select <option>s in the list box - // because we use a pop up dialog to handle the actual selections. This prevents options from - // being selected prior to displaying the pop up dialog. The contents of the listbox are for - // display only. - - // We do focus <select>/<option> on mouse down so that a Focus event is fired and have the - // element painted in its focus state on repaint. - ASSERT_WITH_SECURITY_IMPLICATION(node->isElementNode()); - if (node->isElementNode()) { - Element* element = toElement(node); - element->focus(); - } - } else - eventHandler->handleMousePressEvent(mouseEvent); - } else if (mouseEvent.type() == WebCore::PlatformEvent::MouseReleased) { - // Do not send the mouse event if this is a popup field as the mouse down has been - // suppressed and symmetry should be maintained. - if (!m_inputHandler->didNodeOpenPopup(node)) - eventHandler->handleMouseReleaseEvent(mouseEvent); - } - - return true; -} - -bool WebPagePrivate::handleWheelEvent(PlatformWheelEvent& wheelEvent) -{ - return m_mainFrame->eventHandler()->handleWheelEvent(wheelEvent); -} - -bool WebPage::touchEvent(const Platform::TouchEvent& event) -{ -#if DEBUG_TOUCH_EVENTS - Platform::logAlways(Platform::LogLevelCritical, "%s", event.toString().c_str()); -#endif - -#if ENABLE(TOUCH_EVENTS) - if (!d->m_mainFrame) - return false; - - if (d->m_page->defersLoading()) - return false; - - if (d->m_inputHandler) - d->m_inputHandler->setInputModeEnabled(); - - PluginView* pluginView = d->m_fullScreenPluginView.get(); - if (pluginView) - return d->dispatchTouchEventToFullScreenPlugin(pluginView, event); - - Platform::TouchEvent tEvent = event; - if (event.isSingleTap()) - d->m_pluginMayOpenNewTab = true; - else if (tEvent.m_type == Platform::TouchEvent::TouchStart || tEvent.m_type == Platform::TouchEvent::TouchCancel) - d->m_pluginMayOpenNewTab = false; - - if (tEvent.m_type == Platform::TouchEvent::TouchStart) { - d->clearCachedHitTestResult(); - d->m_touchEventHandler->doFatFingers(tEvent.m_points[0]); - - // Draw tap highlight as soon as possible if we can - Element* elementUnderFatFinger = d->m_touchEventHandler->lastFatFingersResult().nodeAsElementIfApplicable(); - if (elementUnderFatFinger) - d->m_touchEventHandler->drawTapHighlight(); - } - - if (event.isTouchHold()) - d->m_touchEventHandler->handleTouchHold(); - - bool handled = false; - - if (event.m_type != Platform::TouchEvent::TouchInjected) - handled = d->m_mainFrame->eventHandler()->handleTouchEvent(PlatformTouchEvent(&tEvent)); - - if (d->m_preventDefaultOnTouchStart) { - if (tEvent.m_type == Platform::TouchEvent::TouchEnd || tEvent.m_type == Platform::TouchEvent::TouchCancel) - d->m_preventDefaultOnTouchStart = false; - return true; - } - - if (handled) { - if (tEvent.m_type == Platform::TouchEvent::TouchStart) - d->m_preventDefaultOnTouchStart = true; - return true; - } -#endif - - return false; -} - -void WebPagePrivate::setScrollOriginPoint(const Platform::IntPoint& documentScrollOrigin) -{ - m_inRegionScroller->d->reset(); - - if (!m_hasInRegionScrollableAreas) - return; - - postponeDocumentStyleRecalc(); - m_inRegionScroller->d->calculateInRegionScrollableAreasForPoint(documentScrollOrigin); - if (!m_inRegionScroller->d->activeInRegionScrollableAreas().empty()) - m_client->notifyInRegionScrollableAreasChanged(m_inRegionScroller->d->activeInRegionScrollableAreas()); - resumeDocumentStyleRecalc(); -} - -void WebPage::setDocumentScrollOriginPoint(const Platform::IntPoint& documentScrollOrigin) -{ - d->setScrollOriginPoint(documentScrollOrigin); -} - -void WebPage::touchPointAsMouseEvent(const Platform::TouchPoint& point, unsigned modifiers) -{ - if (d->m_page->defersLoading()) - return; - - if (d->m_fullScreenPluginView.get()) - return; - - d->m_lastUserEventTimestamp = currentTime(); - - d->m_touchEventHandler->handleTouchPoint(point, modifiers); -} - -void WebPage::playSoundIfAnchorIsTarget() const -{ - d->m_touchEventHandler->playSoundIfAnchorIsTarget(); -} - -bool WebPagePrivate::dispatchTouchEventToFullScreenPlugin(PluginView* plugin, const Platform::TouchEvent& event) -{ - // Always convert touch events to mouse events. - // Don't send actual touch events because no one has ever implemented them in flash. - if (!event.neverHadMultiTouch()) - return false; - - if (event.isDoubleTap() || event.isTouchHold() || event.m_type == Platform::TouchEvent::TouchCancel) { - NPTouchEvent npTouchEvent; - - if (event.isDoubleTap()) - npTouchEvent.type = TOUCH_EVENT_DOUBLETAP; - else if (event.isTouchHold()) - npTouchEvent.type = TOUCH_EVENT_TOUCHHOLD; - else if (event.m_type == Platform::TouchEvent::TouchCancel) - npTouchEvent.type = TOUCH_EVENT_CANCEL; - - npTouchEvent.points = 0; - npTouchEvent.size = event.m_points.size(); - if (npTouchEvent.size) { - npTouchEvent.points = new NPTouchPoint[npTouchEvent.size]; - for (int i = 0; i < npTouchEvent.size; i++) { - npTouchEvent.points[i].touchId = event.m_points[i].id(); - npTouchEvent.points[i].clientX = event.m_points[i].screenPosition().x(); - npTouchEvent.points[i].clientY = event.m_points[i].screenPosition().y(); - npTouchEvent.points[i].screenX = event.m_points[i].screenPosition().x(); - npTouchEvent.points[i].screenY = event.m_points[i].screenPosition().y(); - npTouchEvent.points[i].pageX = event.m_points[i].pixelViewportPosition().x(); - npTouchEvent.points[i].pageY = event.m_points[i].pixelViewportPosition().y(); - } - } - - NPEvent npEvent; - npEvent.type = NP_TouchEvent; - npEvent.data = &npTouchEvent; - - plugin->dispatchFullScreenNPEvent(npEvent); - delete[] npTouchEvent.points; - return true; - } - - dispatchTouchPointAsMouseEventToFullScreenPlugin(plugin, event.m_points[0]); - return true; -} - -bool WebPagePrivate::dispatchTouchPointAsMouseEventToFullScreenPlugin(PluginView* pluginView, const Platform::TouchPoint& point) -{ - NPEvent npEvent; - NPMouseEvent mouse; - - switch (point.state()) { - case Platform::TouchPoint::TouchPressed: - mouse.type = MOUSE_BUTTON_DOWN; - break; - case Platform::TouchPoint::TouchReleased: - mouse.type = MOUSE_BUTTON_UP; - break; - case Platform::TouchPoint::TouchMoved: - mouse.type = MOUSE_MOTION; - break; - case Platform::TouchPoint::TouchStationary: - return true; - } - - mouse.x = point.screenPosition().x(); - mouse.y = point.screenPosition().y(); - mouse.button = mouse.type != MOUSE_BUTTON_UP; - mouse.flags = 0; - npEvent.type = NP_MouseEvent; - npEvent.data = &mouse; - - pluginView->dispatchFullScreenNPEvent(npEvent); - return true; -} - -void WebPage::touchEventCancel() -{ - d->m_pluginMayOpenNewTab = false; - if (d->m_page->defersLoading()) - return; -} - -Frame* WebPagePrivate::focusedOrMainFrame() const -{ - return m_page->focusController()->focusedOrMainFrame(); -} - -void WebPagePrivate::clearFocusNode() -{ - Frame* frame = focusedOrMainFrame(); - if (!frame) - return; - ASSERT(frame->document()); - - if (frame->document()->focusedElement()) - frame->page()->focusController()->setFocusedElement(0, frame); -} - -BlackBerry::Platform::String WebPage::textEncoding() -{ - Frame* frame = d->focusedOrMainFrame(); - if (!frame) - return BlackBerry::Platform::String::emptyString(); - - Document* document = frame->document(); - if (!document) - return BlackBerry::Platform::String::emptyString(); - - return document->loader()->writer()->encoding(); -} - -BlackBerry::Platform::String WebPage::forcedTextEncoding() -{ - Frame* frame = d->focusedOrMainFrame(); - if (!frame) - return BlackBerry::Platform::String::emptyString(); - - Document* document = frame->document(); - if (!document) - return BlackBerry::Platform::String::emptyString(); - - return document->loader()->overrideEncoding(); -} - -void WebPage::setForcedTextEncoding(const BlackBerry::Platform::String& encoding) -{ - if (!encoding.empty() && d->focusedOrMainFrame() && d->focusedOrMainFrame()->loader() && d->focusedOrMainFrame()->loader()) - d->focusedOrMainFrame()->loader()->reloadWithOverrideEncoding(encoding); -} - -bool WebPage::keyEvent(const Platform::KeyboardEvent& keyboardEvent) -{ - if (!d->m_mainFrame->view()) - return false; - - if (d->m_page->defersLoading()) - return false; - - ASSERT(d->m_page->focusController()); - - return d->m_inputHandler->handleKeyboardInput(keyboardEvent); -} - -bool WebPage::deleteTextRelativeToCursor(unsigned leftOffset, unsigned rightOffset) -{ - if (d->m_page->defersLoading()) - return false; - - return d->m_inputHandler->deleteTextRelativeToCursor(leftOffset, rightOffset); -} - -spannable_string_t* WebPage::selectedText(int32_t flags) -{ - return d->m_inputHandler->selectedText(flags); -} - -spannable_string_t* WebPage::textBeforeCursor(int32_t length, int32_t flags) -{ - return d->m_inputHandler->textBeforeCursor(length, flags); -} - -spannable_string_t* WebPage::textAfterCursor(int32_t length, int32_t flags) -{ - return d->m_inputHandler->textAfterCursor(length, flags); -} - -extracted_text_t* WebPage::extractedTextRequest(extracted_text_request_t* request, int32_t flags) -{ - return d->m_inputHandler->extractedTextRequest(request, flags); -} - -int32_t WebPage::setComposingRegion(int32_t start, int32_t end) -{ - return d->m_inputHandler->setComposingRegion(start, end); -} - -int32_t WebPage::finishComposition() -{ - return d->m_inputHandler->finishComposition(); -} - -int32_t WebPage::setComposingText(spannable_string_t* spannableString, int32_t relativeCursorPosition) -{ - if (d->m_page->defersLoading()) - return -1; - return d->m_inputHandler->setComposingText(spannableString, relativeCursorPosition); -} - -int32_t WebPage::commitText(spannable_string_t* spannableString, int32_t relativeCursorPosition) -{ - if (d->m_page->defersLoading()) - return -1; - return d->m_inputHandler->commitText(spannableString, relativeCursorPosition); -} - -void WebPage::setSpellCheckingEnabled(bool enabled) -{ - static_cast<EditorClientBlackBerry*>(d->m_page->editorClient())->enableSpellChecking(enabled); - - d->m_inputHandler->setSystemSpellCheckStatus(enabled); - - if (!enabled) - d->m_inputHandler->stopPendingSpellCheckRequests(); -} - -void WebPage::spellCheckingRequestProcessed(int32_t transactionId, spannable_string_t* spannableString) -{ - d->m_inputHandler->spellCheckingRequestProcessed(transactionId, spannableString); -} - -class DeferredTaskSelectionCancelled: public DeferredTask<&WebPagePrivate::m_wouldCancelSelection> { -public: - explicit DeferredTaskSelectionCancelled(WebPagePrivate* webPagePrivate) - : DeferredTaskType(webPagePrivate) - { - } -private: - virtual void performInternal(WebPagePrivate* webPagePrivate) - { - webPagePrivate->m_webPage->selectionCancelled(); - } -}; - -void WebPage::selectionCancelled() -{ - if (d->m_page->defersLoading()) { - d->m_deferredTasks.append(adoptPtr(new DeferredTaskSelectionCancelled(d))); - return; - } - DeferredTaskSelectionCancelled::finishOrCancel(d); - d->m_selectionHandler->cancelSelection(); -} - -bool WebPage::selectionContainsDocumentPoint(const Platform::IntPoint& point) -{ - return d->m_selectionHandler->selectionContains(point); -} - -BlackBerry::Platform::String WebPage::title() const -{ - if (d->m_mainFrame->document()) - return d->m_mainFrame->loader()->documentLoader()->title().string(); - return BlackBerry::Platform::String::emptyString(); -} - -BlackBerry::Platform::String WebPage::selectedText() const -{ - return d->m_selectionHandler->selectedText(); -} - -BlackBerry::Platform::String WebPage::cutSelectedText() -{ - BlackBerry::Platform::String selectedText = d->m_selectionHandler->selectedText(); - if (!d->m_page->defersLoading() && !selectedText.empty()) - d->m_inputHandler->deleteSelection(); - return selectedText; -} - -void WebPage::insertText(const BlackBerry::Platform::String& string) -{ - if (d->m_page->defersLoading()) - return; - d->m_inputHandler->insertText(string); -} - -void WebPage::clearCurrentInputField() -{ - if (d->m_page->defersLoading()) - return; - d->m_inputHandler->clearField(); -} - -void WebPage::cut() -{ - if (d->m_page->defersLoading()) - return; - d->m_inputHandler->cut(); -} - -void WebPage::copy() -{ - d->m_inputHandler->copy(); -} - -void WebPage::paste() -{ - if (d->m_page->defersLoading()) - return; - d->m_inputHandler->paste(); -} - -void WebPage::selectAll() -{ - if (d->m_page->defersLoading()) - return; - d->m_inputHandler->selectAll(); -} - -bool WebPage::isInputMode() const -{ - return d->m_inputHandler->isInputMode(); -} - -void WebPage::setDocumentSelection(const Platform::IntPoint& documentStartPoint, const Platform::IntPoint& documentEndPoint) -{ - if (d->m_page->defersLoading()) - return; - - d->m_selectionHandler->setSelection(documentStartPoint, documentEndPoint); -} - -void WebPage::setDocumentCaretPosition(const Platform::IntPoint& documentCaretPosition) -{ - if (d->m_page->defersLoading()) - return; - - // Handled by selection handler as it's point based. - d->m_selectionHandler->setCaretPosition(documentCaretPosition); -} - -void WebPage::selectAtDocumentPoint(const Platform::IntPoint& documentPoint, SelectionExpansionType selectionExpansionType) -{ - if (d->m_page->defersLoading()) - return; - d->m_selectionHandler->selectAtPoint(documentPoint, selectionExpansionType); -} - -void WebPage::expandSelection(bool isScrollStarted) -{ - if (d->m_page->defersLoading()) - return; - d->m_selectionHandler->expandSelection(isScrollStarted); -} - -void WebPage::setOverlayExpansionPixelHeight(int dy) -{ - d->setOverlayExpansionPixelHeight(dy); -} - -void WebPagePrivate::setOverlayExpansionPixelHeight(int dy) -{ - // Transform from pixel to document coordinates. - m_selectionHandler->setOverlayExpansionHeight(m_webkitThreadViewportAccessor->roundToDocumentFromPixelContents(Platform::IntPoint(0, dy)).y()); -} - -void WebPage::setParagraphExpansionPixelScrollMargin(const Platform::IntSize& scrollMargin) -{ - // Transform from pixel to document coordinates. - Platform::IntSize documentScrollMargin = d->m_webkitThreadViewportAccessor->roundToDocumentFromPixelContents(Platform::IntRect(Platform::IntPoint(), scrollMargin)).size(); - d->m_selectionHandler->setParagraphExpansionScrollMargin(documentScrollMargin); -} - -void WebPage::setSelectionDocumentViewportSize(const Platform::IntSize& selectionDocumentViewportSize) -{ - d->m_selectionHandler->setSelectionViewportSize(selectionDocumentViewportSize); -} - -BackingStore* WebPage::backingStore() const -{ - return d->m_backingStore; -} - -InRegionScroller* WebPage::inRegionScroller() const -{ - return d->m_inRegionScroller.get(); -} - -void WebPagePrivate::setTextReflowAnchorPoint(const Platform::IntPoint& documentFocalPoint) -{ - // Should only be invoked when text reflow is enabled. - ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled); - - m_currentPinchZoomNode = bestNodeForZoomUnderPoint(documentFocalPoint); - if (!m_currentPinchZoomNode) - return; - - IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get()); - m_anchorInNodeRectRatio.set( - static_cast<float>(documentFocalPoint.x() - nodeRect.x()) / nodeRect.width(), - static_cast<float>(documentFocalPoint.y() - nodeRect.y()) / nodeRect.height()); -} - -bool WebPage::pinchZoomAboutPoint(double scale, const Platform::FloatPoint& documentFocalPoint) -{ - d->m_userPerformedManualZoom = true; - d->m_userPerformedManualScroll = true; - - if (d->m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) { - d->setTextReflowAnchorPoint(webkitThreadViewportAccessor()->roundedDocumentContents(documentFocalPoint)); - - // Theoretically, d->nodeForZoomUnderPoint(documentFocalPoint) can return null. - if (!d->m_currentPinchZoomNode) - return false; - } - - return d->zoomAboutPoint(scale, documentFocalPoint); -} - -#if ENABLE(VIEWPORT_REFLOW) -void WebPagePrivate::toggleTextReflowIfEnabledForBlockZoomOnly(bool shouldEnableTextReflow) -{ - if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabledOnlyForBlockZoom) - m_page->settings()->setTextReflowEnabled(shouldEnableTextReflow); -} -#endif - -bool WebPage::blockZoom(const Platform::IntPoint& documentTargetPoint) -{ - if (!d->m_mainFrame->view() || !d->isUserScalable()) - return false; - - Node* node = d->bestNodeForZoomUnderPoint(documentTargetPoint); - if (!node) - return false; - - IntRect nodeRect = d->rectForNode(node); - IntRect blockRect; - bool endOfBlockZoomMode = d->compareNodesForBlockZoom(d->m_currentBlockZoomAdjustedNode.get(), node); - const double oldScale = d->m_transformationMatrix->m11(); - double newScale = 0; - const double margin = endOfBlockZoomMode ? 0 : blockZoomMargin * 2 * oldScale; - bool isFirstZoom = false; - - const Platform::ViewportAccessor* viewportAccessor = webkitThreadViewportAccessor(); - - if (endOfBlockZoomMode) { - // End of block zoom mode - const Platform::IntSize pixelContentsSize = viewportAccessor->pixelContentsSize(); - const IntRect rect = d->blockZoomRectForNode(node); - blockRect = IntRect(0, rect.y(), pixelContentsSize.width(), pixelContentsSize.height() - rect.y()); - d->m_shouldReflowBlock = false; - } else { - // Start/continue block zoom mode - Node* tempBlockZoomAdjustedNode = d->m_currentBlockZoomAdjustedNode.get(); - blockRect = d->blockZoomRectForNode(node); - - // Don't use a block if it is too close to the size of the actual contents. - // We allow this for images only so that they can be zoomed tight to the screen. - if (!isHTMLImageElement(node)) { - const IntRect tRect = viewportAccessor->roundToDocumentFromPixelContents(WebCore::FloatRect(blockRect)); - int blockArea = tRect.width() * tRect.height(); - int pageArea = d->contentsSize().width() * d->contentsSize().height(); - double blockToPageRatio = static_cast<double>(pageArea - blockArea) / pageArea; - if (blockToPageRatio < minimumExpandingRatio) { - // Restore old adjust node because zoom was canceled. - d->m_currentBlockZoomAdjustedNode = tempBlockZoomAdjustedNode; - return false; - } - } - - if (blockRect.isEmpty() || !blockRect.width() || !blockRect.height()) - return false; - - if (!d->m_currentBlockZoomNode.get()) - isFirstZoom = true; - - d->m_currentBlockZoomNode = node; - d->m_shouldReflowBlock = true; - } - - newScale = std::min(d->newScaleForBlockZoomRect(blockRect, oldScale, margin), d->maxBlockZoomScale()); - newScale = std::max(newScale, minimumScale()); - -#if ENABLE(VIEWPORT_REFLOW) - // If reflowing, adjust the reflow-width of text node to make sure the font is a reasonable size. - if (d->m_currentBlockZoomNode && d->m_shouldReflowBlock && settings()->textReflowMode() != WebSettings::TextReflowDisabled) { - RenderObject* renderer = d->m_currentBlockZoomNode->renderer(); - if (renderer && renderer->isText()) { - double newFontSize = renderer->style()->fontSize() * newScale; - if (newFontSize < d->m_webSettings->defaultFontSize()) { - newScale = std::min(static_cast<double>(d->m_webSettings->defaultFontSize()) / renderer->style()->fontSize(), d->maxBlockZoomScale()); - newScale = std::max(newScale, minimumScale()); - } - blockRect.setWidth(oldScale * static_cast<double>(d->transformedActualVisibleSize().width()) / newScale); - // Re-calculate the scale here to take in to account the margin. - newScale = std::min(d->newScaleForBlockZoomRect(blockRect, oldScale, margin), d->maxBlockZoomScale()); - newScale = std::max(newScale, minimumScale()); // Still, it's not allowed to be smaller than minimum scale. - } - } -#endif - - // Align the zoomed block in the screen. - const Platform::FloatRect newBlockRect = viewportAccessor->documentFromPixelContents(WebCore::FloatRect(blockRect)); - float scaledViewportWidth = static_cast<double>(d->actualVisibleSize().width()) * oldScale / newScale; - float scaledViewportHeight = static_cast<double>(d->actualVisibleSize().height()) * oldScale / newScale; - float dx = std::max(0.0f, (scaledViewportWidth - newBlockRect.width()) / 2.0f); - float dy = std::max(0.0f, (scaledViewportHeight - newBlockRect.height()) / 2.0f); - - const RenderObject* renderer = d->m_currentBlockZoomAdjustedNode->renderer(); - const FloatPoint topLeftPoint = newBlockRect.location(); - FloatPoint anchor; - - if (renderer && renderer->isText()) { - ETextAlign textAlign = renderer->style()->textAlign(); - switch (textAlign) { - case CENTER: - case WEBKIT_CENTER: - anchor = FloatPoint(nodeRect.x() + (nodeRect.width() - scaledViewportWidth) / 2, topLeftPoint.y()); - break; - case LEFT: - case WEBKIT_LEFT: - anchor = topLeftPoint; - break; - case RIGHT: - case WEBKIT_RIGHT: - anchor = FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y()); - break; - case TASTART: - case JUSTIFY: - default: - if (renderer->style()->isLeftToRightDirection()) - anchor = topLeftPoint; - else - anchor = FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y()); - break; - } - } else - anchor = renderer->style()->isLeftToRightDirection() ? topLeftPoint : FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y()); - - WebCore::FloatPoint finalAnimationDocumentScrollPosition; - - if (newBlockRect.height() <= scaledViewportHeight) { - // The block fits in the viewport so center it. - finalAnimationDocumentScrollPosition = FloatPoint(anchor.x() - dx, anchor.y() - dy); - } else { - // The block is longer than the viewport so top align it and add 3 pixel margin. - finalAnimationDocumentScrollPosition = FloatPoint(anchor.x() - dx, anchor.y() - 3); - } - -#if ENABLE(VIEWPORT_REFLOW) - // We don't know how long the reflowed block will be so we position it at the top of the screen with a small margin. - if (settings()->textReflowMode() != WebSettings::TextReflowDisabled) { - finalAnimationDocumentScrollPosition = FloatPoint(anchor.x() - dx, anchor.y() - 3); - d->m_finalAnimationDocumentScrollPositionReflowOffset = FloatPoint(-dx, -3); - } -#endif - - // Make sure that the original node rect is visible in the screen after the zoom. This is necessary because the identified block rect might - // not be the same as the original node rect, and it could force the original node rect off the screen. - FloatRect br(anchor, FloatSize(scaledViewportWidth, scaledViewportHeight)); - if (!br.contains(IntPoint(documentTargetPoint))) { - d->m_finalAnimationDocumentScrollPositionReflowOffset.move(0, (documentTargetPoint.y() - scaledViewportHeight / 2) - finalAnimationDocumentScrollPosition.y()); - finalAnimationDocumentScrollPosition = FloatPoint(finalAnimationDocumentScrollPosition.x(), documentTargetPoint.y() - scaledViewportHeight / 2); - } - - // Clamp the finalBlockPoint to not cause any overflow scrolling. - if (finalAnimationDocumentScrollPosition.x() < 0) { - finalAnimationDocumentScrollPosition.setX(0); - d->m_finalAnimationDocumentScrollPositionReflowOffset.setX(0); - } else if (finalAnimationDocumentScrollPosition.x() + scaledViewportWidth > d->contentsSize().width()) { - finalAnimationDocumentScrollPosition.setX(d->contentsSize().width() - scaledViewportWidth); - d->m_finalAnimationDocumentScrollPositionReflowOffset.setX(0); - } - - if (finalAnimationDocumentScrollPosition.y() < 0) { - finalAnimationDocumentScrollPosition.setY(0); - d->m_finalAnimationDocumentScrollPositionReflowOffset.setY(0); - } else if (finalAnimationDocumentScrollPosition.y() + scaledViewportHeight > d->contentsSize().height()) { - finalAnimationDocumentScrollPosition.setY(d->contentsSize().height() - scaledViewportHeight); - d->m_finalAnimationDocumentScrollPositionReflowOffset.setY(0); - } - - // Don't block zoom if the user is zooming and the new scale is only marginally different from the - // oldScale with only a marginal change in scroll position. Ignore scroll difference in the special case - // that the zoom level is the minimumScale. - if (!endOfBlockZoomMode && abs(newScale - oldScale) / oldScale < minimumExpandingRatio) { - const double minimumDisplacement = minimumExpandingRatio * viewportAccessor->documentViewportSize().width(); - const int scrollPositionDisplacement = distanceBetweenPoints(viewportAccessor->documentScrollPosition(), viewportAccessor->roundedDocumentContents(finalAnimationDocumentScrollPosition)); - - if (oldScale == d->minimumScale() || (scrollPositionDisplacement < minimumDisplacement && abs(newScale - oldScale) / oldScale < 0.10)) { - if (isFirstZoom) { - d->resetBlockZoom(); - return false; - } - // Zoom out of block zoom. - blockZoom(documentTargetPoint); - return true; - } - } - - // We set this here to make sure we don't try to re-render the page at a different zoom level during loading. - d->m_userPerformedManualZoom = true; - d->m_userPerformedManualScroll = true; - d->m_client->animateToScaleAndDocumentScrollPosition(newScale, finalAnimationDocumentScrollPosition, true); - - return true; -} - -bool WebPage::isMaxZoomed() const -{ - return (d->currentScale() == d->maximumScale()) || !d->isUserScalable(); -} - -bool WebPage::isMinZoomed() const -{ - return (d->currentScale() == d->minimumScale()) || !d->isUserScalable(); -} - -bool WebPage::isAtInitialZoom() const -{ - return (d->currentScale() == d->initialScale()) || !d->isUserScalable(); -} - -class DeferredTaskSetFocused: public DeferredTask<&WebPagePrivate::m_wouldSetFocused> { -public: - explicit DeferredTaskSetFocused(WebPagePrivate* webPagePrivate, bool focused) - : DeferredTaskType(webPagePrivate) - { - webPagePrivate->m_cachedFocused = focused; - } -private: - virtual void performInternal(WebPagePrivate* webPagePrivate) - { - webPagePrivate->m_webPage->setFocused(webPagePrivate->m_cachedFocused); - } -}; - -void WebPage::setFocused(bool focused) -{ - if (d->m_page->defersLoading()) { - d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetFocused(d, focused))); - return; - } - DeferredTaskSetFocused::finishOrCancel(d); - FocusController* focusController = d->m_page->focusController(); - focusController->setActive(focused); - if (focused) { - Frame* frame = focusController->focusedFrame(); - if (!frame) - focusController->setFocusedFrame(d->m_mainFrame); - } - focusController->setFocused(focused); -} - -bool WebPage::findNextString(const char* text, bool forward, bool caseSensitive, bool wrap, bool highlightAllMatches, bool selectActiveMatchOnClear) -{ - WebCore::FindOptions findOptions = WebCore::StartInSelection; - if (!forward) - findOptions |= WebCore::Backwards; - if (!caseSensitive) - findOptions |= WebCore::CaseInsensitive; - - // The WebCore::FindOptions::WrapAround boolean actually wraps the search - // within the current frame as opposed to the entire Document, so we have to - // provide our own wrapping code to wrap at the whole Document level. - return d->m_inPageSearchManager->findNextString(String::fromUTF8(text), findOptions, wrap, highlightAllMatches, selectActiveMatchOnClear); -} - -void WebPage::runLayoutTests() -{ -#if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD - // FIXME: do we need API to toggle this? - d->m_page->settings()->setDeveloperExtrasEnabled(true); - - if (!d->m_dumpRenderTree) - d->m_dumpRenderTree = new DumpRenderTree(this); - d->m_dumpRenderTree->runTests(); -#endif -} - -unsigned WebPage::timeoutForJavaScriptExecution() const -{ - return Settings::timeoutForJavaScriptExecution(d->m_page->groupName()); -} - -void WebPage::setTimeoutForJavaScriptExecution(unsigned ms) -{ - Settings::setTimeoutForJavaScriptExecution(d->m_page->groupName(), ms); -} - -JSGlobalContextRef WebPage::globalContext() const -{ - if (!d->m_mainFrame) - return 0; - - return toGlobalRef(d->m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec()); -} - -// Serialize only the members of HistoryItem which are needed by the client, -// and copy them into a SharedArray. Also include the HistoryItem pointer which -// will be used by the client as an opaque reference to identify the item. -void WebPage::getBackForwardList(SharedArray<BackForwardEntry>& result) const -{ - HistoryItemVector entries = static_cast<BackForwardListBlackBerry*>(d->m_page->backForward()->client())->entries(); - result.reset(new BackForwardEntry[entries.size()], entries.size()); - - for (unsigned i = 0; i < entries.size(); ++i) { - RefPtr<HistoryItem> entry = entries[i]; - BackForwardEntry& resultEntry = result[i]; - resultEntry.url = entry->urlString(); - resultEntry.originalUrl = entry->originalURLString(); - resultEntry.title = entry->title(); - resultEntry.networkToken = entry->viewState().networkToken; - resultEntry.lastVisitWasHTTPNonGet = entry->lastVisitWasHTTPNonGet(); - resultEntry.id = backForwardIdFromHistoryItem(entry.get()); - - // FIXME: seems we can remove this now? - // Make sure the HistoryItem is not disposed while the result list is still being used, to make sure the pointer is not reused - // will be balanced by deref in releaseBackForwardEntry. - entry->ref(); - } -} - -void WebPage::releaseBackForwardEntry(BackForwardId id) const -{ - HistoryItem* item = historyItemFromBackForwardId(id); - ASSERT(item); - item->deref(); -} - -void WebPage::clearBrowsingData() -{ - clearMemoryCaches(); - clearAppCache(d->m_page->groupName()); - clearLocalStorage(); - clearCookieCache(); - clearHistory(); - clearPluginSiteData(); - clearWebFileSystem(); -} - -void WebPage::clearHistory() -{ - // Don't clear the back-forward list as we might like to keep it. - PageGroup::removeAllVisitedLinks(); -} - -void WebPage::clearCookies() -{ - clearCookieCache(); -} - -void WebPage::clearLocalStorage() -{ - if (PageGroup* group = d->m_page->groupPtr()) { - if (StorageNamespace* storage = group->localStorage()) - storage->clearAllOriginsForDeletion(); - } -} - -void WebPage::clearCredentials() -{ -#if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST) - if (d->m_webSettings->isCredentialAutofillEnabled()) - credentialManager().clearCredentials(); -#endif -} - -void WebPage::clearAutofillData() -{ - if (d->m_webSettings->isFormAutofillEnabled()) - AutofillManager::clear(); -} - -void WebPage::clearNeverRememberSites() -{ -#if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST) - if (d->m_webSettings->isCredentialAutofillEnabled()) - credentialManager().clearNeverRememberSites(); -#endif -} - -void WebPage::clearWebFileSystem() -{ -#if ENABLE(FILE_SYSTEM) - Platform::WebFileSystem::deleteAllFileSystems(); -#endif -} - -void WebPage::clearCache() -{ - clearMemoryCaches(); - clearAppCache(d->m_page->groupName()); -} - -void WebPage::clearBackForwardList(bool keepCurrentPage) const -{ - BackForwardListBlackBerry* backForwardList = static_cast<BackForwardListBlackBerry*>(d->m_page->backForward()->client()); - RefPtr<HistoryItem> currentItem = backForwardList->currentItem(); - backForwardList->clear(); - if (keepCurrentPage) - d->m_page->backForward()->client()->addItem(currentItem); -} - -bool WebPage::isEnableLocalAccessToAllCookies() const -{ - return cookieManager().canLocalAccessAllCookies(); -} - -void WebPage::setEnableLocalAccessToAllCookies(bool enabled) -{ - cookieManager().setCanLocalAccessAllCookies(enabled); -} - -void WebPage::addVisitedLink(const unsigned short* url, unsigned length) -{ - ASSERT(d->m_page); - d->m_page->group().addVisitedLink(url, length); -} - -void WebPage::initPopupWebView(BlackBerry::WebKit::WebPage* webPage) -{ - d->m_pagePopup->initialize(webPage); -} - -String WebPagePrivate::findPatternStringForUrl(const KURL& url) const -{ - if ((m_webSettings->shouldHandlePatternUrls() && protocolIs(url, "pattern")) - || protocolIs(url, "tel") - || protocolIs(url, "wtai") - || protocolIs(url, "cti") - || protocolIs(url, "mailto") - || protocolIs(url, "sms") - || protocolIs(url, "pin")) { - return url; - } - return String(); -} - -bool WebPage::defersLoading() const -{ - return d->m_page->defersLoading(); -} - -void WebPage::notifyPagePause() -{ - FOR_EACH_PLUGINVIEW(d->m_pluginViews) - (*it)->handlePauseEvent(); -} - -void WebPage::notifyPageResume() -{ - FOR_EACH_PLUGINVIEW(d->m_pluginViews) - (*it)->handleResumeEvent(); -} - -void WebPage::notifyPageBackground() -{ - FOR_EACH_PLUGINVIEW(d->m_pluginViews) - (*it)->handleBackgroundEvent(); -} - -void WebPage::notifyPageForeground() -{ - FOR_EACH_PLUGINVIEW(d->m_pluginViews) - (*it)->handleForegroundEvent(); -} - -void WebPage::notifyPageFullScreenAllowed() -{ - FOR_EACH_PLUGINVIEW(d->m_pluginViews) - (*it)->handleFullScreenAllowedEvent(); -} - -void WebPage::notifyPageFullScreenExit() -{ - FOR_EACH_PLUGINVIEW(d->m_pluginViews) - (*it)->handleFullScreenExitEvent(); -} - -void WebPage::notifyDeviceIdleStateChange(bool enterIdle) -{ - FOR_EACH_PLUGINVIEW(d->m_pluginViews) - (*it)->handleIdleEvent(enterIdle); -} - -void WebPagePrivate::notifyAppActivationStateChange(ActivationStateType activationState) -{ - m_activationState = activationState; - -#if USE(ACCELERATED_COMPOSITING) - updateRootLayerCommitEnabled(); -#endif - -#if ENABLE(PAGE_VISIBILITY_API) - setPageVisibilityState(); -#endif -} - -void WebPage::notifyAppActivationStateChange(ActivationStateType activationState) -{ -#if ENABLE(VIDEO) - MediaPlayerPrivate::notifyAppActivatedEvent(activationState == ActivationActive); -#endif - - FOR_EACH_PLUGINVIEW(d->m_pluginViews) { - switch (activationState) { - case ActivationActive: - (*it)->handleAppActivatedEvent(); - break; - case ActivationInactive: - (*it)->handleAppDeactivatedEvent(); - break; - case ActivationStandby: - (*it)->handleAppStandbyEvent(); - break; - } - } - - d->notifyAppActivationStateChange(activationState); -} - -void WebPage::notifySwipeEvent() -{ - if (d->m_fullScreenPluginView.get()) - d->m_fullScreenPluginView->handleSwipeEvent(); - else - notifyFullScreenVideoExited(true); -} - -void WebPage::notifyScreenPowerStateChanged(bool powered) -{ - FOR_EACH_PLUGINVIEW(d->m_pluginViews) - (*it)->handleScreenPowerEvent(powered); -} - -void WebPage::notifyFullScreenVideoExited(bool done) -{ - UNUSED_PARAM(done); -#if ENABLE(VIDEO) - Element* element = toElement(d->m_fullscreenNode.get()); - if (!element) - return; - if (d->m_webSettings->fullScreenVideoCapable() && element->hasTagName(HTMLNames::videoTag)) - toHTMLMediaElement(element)->exitFullscreen(); -#if ENABLE(FULLSCREEN_API) - else - element->document()->webkitCancelFullScreen(); -#endif -#endif -} - -void WebPage::clearPluginSiteData() -{ - PluginDatabase* database = PluginDatabase::installedPlugins(true); - - if (!database) - return; - - Vector<PluginPackage*> plugins = database->plugins(); - - Vector<PluginPackage*>::const_iterator end = plugins.end(); - for (Vector<PluginPackage*>::const_iterator it = plugins.begin(); it != end; ++it) - (*it)->clearSiteData(String()); -} - -void WebPage::setExtraPluginDirectory(const BlackBerry::Platform::String& path) -{ - PluginDatabase* database = PluginDatabase::installedPlugins(true /* true for loading default directories */); - if (!database) - return; - - Vector<String> pluginDirectories = database->pluginDirectories(); - if (path.empty() || pluginDirectories.contains(String(path))) - return; - - pluginDirectories.append(path); - database->setPluginDirectories(pluginDirectories); - // Clear out every Page's local copy of PluginData, so it will - // retrieve it again when necessary. Otherwise each page will be - // using old data and may either direct content to a plugin that - // doesn't exist (causing a crash) or not direct content to a plugin - // that does exist. We do this even if plugins are disabled because - // this step is not done when plugins get enabled. - - // True only needs to be passed here if we want to reload each frame - // in the page's frame tree. Here we are passing false for minimum disruption, - // and because this does exactly what we need and nothing more: refresh the plugin data. - d->m_page->refreshPlugins(false /* false for minimum disruption as described above */); - - if (d->m_webSettings->arePluginsEnabled()) - database->refresh(); -} - -void WebPage::updateDisabledPluginFiles(const BlackBerry::Platform::String& fileName, bool disabled) -{ - // Passing true will set plugin database with default plugin directories and refresh it. - PluginDatabase* database = PluginDatabase::installedPlugins(true /* true for loading default directories */); - if (!database) - return; - - if (disabled) { - if (!database->addDisabledPluginFile(fileName)) - return; - } else { - if (!database->removeDisabledPluginFile(fileName)) - return; - } - - // Clear out every Page's local copy of PluginData, so it will - // retrieve it again when necessary. Otherwise each page will be - // using old data and may either direct content to a plugin that - // doesn't exist (causing a crash) or not direct content to a plugin - // that does exist. We do this even if plugins are disabled because - // this step is not done when plugins get enabled. - - // True only needs to be passed here if we want to reload each frame - // in the page's frame tree. Here we are passing false for minimum disruption, - // and because this does exactly what we need and nothing more: refresh the plugin data. - d->m_page->refreshPlugins(false /* false for minimum disruption as described above */); - - // Refresh the plugin database if necessary. - if (d->m_webSettings->arePluginsEnabled()) - database->refresh(); -} - -void WebPage::onNetworkAvailabilityChanged(bool available) -{ - updateOnlineStatus(available); -} - -void WebPage::onCertificateStoreLocationSet(const BlackBerry::Platform::String& caPath) -{ -#if ENABLE(VIDEO) - MediaPlayerPrivate::setCertificatePath(caPath); -#endif -} - -void WebPage::enableDNSPrefetch() -{ - d->m_page->settings()->setDNSPrefetchingEnabled(true); -} - -void WebPage::disableDNSPrefetch() -{ - d->m_page->settings()->setDNSPrefetchingEnabled(false); -} - -bool WebPage::isDNSPrefetchEnabled() const -{ - return d->m_page->settings()->dnsPrefetchingEnabled(); -} - -void WebPage::enableWebInspector() -{ - if (isWebInspectorEnabled() || !d->m_inspectorClient) - return; - - d->m_page->inspectorController()->connectFrontend(d->m_inspectorClient); - d->m_page->settings()->setDeveloperExtrasEnabled(true); - d->setPreventsScreenDimming(true); - d->m_inspectorEnabled = true; -} - -void WebPage::disableWebInspector() -{ - if (!isWebInspectorEnabled()) - return; - - d->m_page->inspectorController()->disconnectFrontend(); - d->m_page->settings()->setDeveloperExtrasEnabled(false); - d->setPreventsScreenDimming(false); - d->m_inspectorEnabled = false; -} - -bool WebPage::isWebInspectorEnabled() -{ - return d->m_inspectorEnabled; -} - -void WebPage::enablePasswordEcho() -{ - d->m_page->settings()->setPasswordEchoEnabled(true); -} - -void WebPage::disablePasswordEcho() -{ - d->m_page->settings()->setPasswordEchoEnabled(false); -} - -void WebPage::dispatchInspectorMessage(const BlackBerry::Platform::String& message) -{ - d->m_page->inspectorController()->dispatchMessageFromFrontend(message); -} - -void WebPage::inspectCurrentContextElement() -{ - if (isWebInspectorEnabled() && d->m_currentContextNode.get()) - d->m_page->inspectorController()->inspect(d->m_currentContextNode.get()); -} - -Platform::IntPoint WebPage::adjustDocumentScrollPosition(const Platform::IntPoint& documentScrollPosition, const Platform::IntRect& documentPaddingRect) -{ - return d->m_proximityDetector->findBestPoint(documentScrollPosition, documentPaddingRect); -} - -Platform::IntSize WebPage::fixedElementSizeDelta() -{ - ASSERT(Platform::userInterfaceThreadMessageClient()->isCurrentThread()); - - // Traverse the layer tree and find the fixed element rect if there is one. - IntRect fixedElementRect; - if (d->compositor() && d->compositor()->rootLayer()) - d->compositor()->findFixedElementRect(d->compositor()->rootLayer(), fixedElementRect); - - // Ignore the fixed element if it is not at the top of page. - if (!fixedElementRect.isEmpty() && !fixedElementRect.y()) - return Platform::IntSize(0, fixedElementRect.height()); - return Platform::IntSize(); -} - -bool WebPagePrivate::compositorDrawsRootLayer() const -{ - if (!m_mainFrame) - return false; - -#if USE(ACCELERATED_COMPOSITING) - if (Platform::userInterfaceThreadMessageClient()->isCurrentThread()) - return m_compositor && m_compositor->drawsRootLayer(); - - // WebKit thread implementation: - RenderView* renderView = m_mainFrame->contentRenderer(); - if (!renderView || !renderView->layer() || !renderView->layer()->backing()) - return false; - - return !renderView->layer()->backing()->paintsIntoWindow(); -#else - return false; -#endif -} - -void WebPagePrivate::setCompositorDrawsRootLayer(bool compositorDrawsRootLayer) -{ -#if USE(ACCELERATED_COMPOSITING) - if (m_page->settings()->forceCompositingMode() == compositorDrawsRootLayer) - return; - - // When the BlackBerry port forces compositing mode, the root layer stops - // painting to window and starts painting to layer instead. - m_page->settings()->setForceCompositingMode(compositorDrawsRootLayer); - m_backingStore->d->updateSuspendScreenUpdateState(); - - if (!m_mainFrame) - return; - - if (FrameView* view = m_mainFrame->view()) - view->updateCompositingLayers(); -#endif -} - -#if USE(ACCELERATED_COMPOSITING) -void WebPagePrivate::scheduleRootLayerCommit() -{ - if (!(m_frameLayers && m_frameLayers->hasLayer()) && !m_overlayLayer) - return; - - m_needsCommit = true; - if (!m_rootLayerCommitTimer->isActive()) { -#if DEBUG_AC_COMMIT - Platform::logAlways(Platform::LogLevelCritical, - "%s: m_rootLayerCommitTimer->isActive() = %d", - WTF_PRETTY_FUNCTION, m_rootLayerCommitTimer->isActive()); -#endif - m_rootLayerCommitTimer->startOneShot(0); - } -} - -static bool needsLayoutRecursive(FrameView* view) -{ - if (view->needsLayout()) - return true; - - bool subframesNeedsLayout = false; - const HashSet<RefPtr<Widget> >* viewChildren = view->children(); - HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end(); - for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end && !subframesNeedsLayout; ++current) { - Widget* widget = (*current).get(); - if (widget->isFrameView()) - subframesNeedsLayout |= needsLayoutRecursive(toFrameView(widget)); - } - - return subframesNeedsLayout; -} - -LayerRenderingResults WebPagePrivate::lastCompositingResults() const -{ - if (m_compositor) - return m_compositor->lastCompositingResults(); - return LayerRenderingResults(); -} - -GraphicsLayer* WebPagePrivate::overlayLayer() -{ - if (!m_overlayLayer) - m_overlayLayer = GraphicsLayer::create(0, this); - - return m_overlayLayer.get(); -} - -void WebPagePrivate::setCompositor(PassRefPtr<WebPageCompositorPrivate> compositor) -{ - using namespace BlackBerry::Platform; - - // We depend on the current thread being the WebKit thread when it's not the Compositing thread. - // That seems extremely likely to be the case, but let's assert just to make sure. - ASSERT(webKitThreadMessageClient()->isCurrentThread()); - - m_backingStore->d->suspendScreenUpdates(); - - // The m_compositor member has to be modified during a sync call for thread - // safe access to m_compositor and its refcount. - userInterfaceThreadMessageClient()->dispatchSyncMessage(createMethodCallMessage(&WebPagePrivate::setCompositorHelper, this, compositor)); - - m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); -} - -void WebPagePrivate::setCompositorHelper(PassRefPtr<WebPageCompositorPrivate> compositor) -{ - using namespace BlackBerry::Platform; - - // The m_compositor member has to be modified during a sync call for thread - // safe access to m_compositor and its refcount. - ASSERT(userInterfaceThreadMessageClient()->isCurrentThread()); - - m_compositor = compositor; - if (m_compositor) { - m_compositor->setPage(this); - - m_compositor->setBackgroundColor(m_webSettings->backgroundColor()); - } - - // The previous compositor, if any, has now released it's OpenGL resources, - // so we can safely free the owned context, if any. - m_ownedContext.clear(); -} - -void WebPagePrivate::setCompositorBackgroundColor(const Color& backgroundColor) -{ - if (m_compositor) - m_compositor->setBackgroundColor(backgroundColor); -} - -void WebPagePrivate::commitRootLayer(const IntRect& layoutRect, const IntRect& documentRect, bool drawsRootLayer) -{ -#if DEBUG_AC_COMMIT - Platform::logAlways(Platform::LogLevelCritical, - "%s: m_compositor = 0x%p", - WTF_PRETTY_FUNCTION, m_compositor.get()); -#endif - - if (!m_compositor) - return; - - // Frame layers - LayerWebKitThread* rootLayer = 0; - if (m_frameLayers) - rootLayer = m_frameLayers->rootLayer(); - - if (rootLayer && rootLayer->layerCompositingThread() != m_compositor->rootLayer()) - m_compositor->setRootLayer(rootLayer->layerCompositingThread()); - - // Overlay layers - LayerWebKitThread* overlayLayer = 0; - if (m_overlayLayer) - overlayLayer = m_overlayLayer->platformLayer(); - - if (overlayLayer && overlayLayer->layerCompositingThread() != m_compositor->overlayLayer()) - m_compositor->setOverlayLayer(overlayLayer->layerCompositingThread()); - - m_compositor->setLayoutRect(layoutRect); - m_compositor->setDocumentRect(documentRect); - m_compositor->setDrawsRootLayer(drawsRootLayer); - - if (rootLayer) - rootLayer->commitOnCompositingThread(); - if (overlayLayer) - overlayLayer->commitOnCompositingThread(); - - m_animationStartTime = currentTime(); - m_didStartAnimations = false; - if (rootLayer) - m_didStartAnimations |= rootLayer->startAnimations(m_animationStartTime); - if (overlayLayer) - m_didStartAnimations |= overlayLayer->startAnimations(m_animationStartTime); - - scheduleCompositingRun(); -} - -bool WebPagePrivate::commitRootLayerIfNeeded() -{ -#if DEBUG_AC_COMMIT - Platform::logAlways(Platform::LogLevelCritical, - "%s: m_suspendRootLayerCommit = %d, m_needsCommit = %d, m_frameLayers = 0x%p, m_frameLayers->hasLayer() = %d, needsLayoutRecursive() = %d", - WTF_PRETTY_FUNCTION, - m_suspendRootLayerCommit, - m_needsCommit, - m_frameLayers.get(), - m_frameLayers && m_frameLayers->hasLayer(), - m_mainFrame && m_mainFrame->view() && needsLayoutRecursive(m_mainFrame->view())); -#endif - - if (m_suspendRootLayerCommit) - return false; - - if (!m_needsCommit) - return false; - - // Don't bail if the layers were removed and we now need a one shot drawing sync as a consequence. - if (!(m_frameLayers && m_frameLayers->hasLayer()) && !m_overlayLayer && !m_needsOneShotDrawingSynchronization) - return false; - - FrameView* view = m_mainFrame->view(); - if (!view) - return false; - - // This can do pretty much anything depending on the overlay, - // so in case it causes relayout or schedule a commit, call it early. - updateDelegatedOverlays(); - - // If we sync compositing layers when a layout is pending, we may cause painting of compositing - // layer content to occur before layout has happened, which will cause paintContents() to bail. - if (needsLayoutRecursive(view)) { - // In case of one shot drawing synchronization, you - // should first layoutIfNeeded, render, then commit and draw the layers. - ASSERT(!needsOneShotDrawingSynchronization()); - return false; - } - - m_needsCommit = false; - // We get here either due to the commit timer, which would have called - // render if a one shot sync was needed. Or we get called from render - // before the timer times out, which means we are doing a one shot anyway. - m_needsOneShotDrawingSynchronization = false; - - if (m_rootLayerCommitTimer->isActive()) - m_rootLayerCommitTimer->stop(); - - double scale = currentScale(); - if (m_frameLayers && m_frameLayers->hasLayer()) - m_frameLayers->commitOnWebKitThread(scale); - - if (m_overlayLayer) - m_overlayLayer->platformLayer()->commitOnWebKitThread(scale); - - willComposite(); - // Stash the visible content rect according to webkit thread - // This is the rectangle used to layout fixed positioned elements, - // and that's what the layer renderer wants. - IntRect layoutRect(scrollPosition(), actualVisibleSize()); - IntRect documentRect(view->minimumScrollPosition(), view->contentsSize()); - bool drawsRootLayer = compositorDrawsRootLayer(); - - // Commit changes made to the layers synchronously with the compositing thread. - Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage( - Platform::createMethodCallMessage( - &WebPagePrivate::commitRootLayer, - this, - layoutRect, - documentRect, - drawsRootLayer)); - - if (m_didStartAnimations) { - if (m_frameLayers && m_frameLayers->hasLayer()) - m_frameLayers->notifyAnimationsStarted(m_animationStartTime); - if (m_overlayLayer) - m_overlayLayer->platformLayer()->notifyAnimationsStarted(m_animationStartTime); - - m_didStartAnimations = false; - } - - didComposite(); - return true; -} - -void WebPagePrivate::rootLayerCommitTimerFired(Timer<WebPagePrivate>*) -{ - if (m_suspendRootLayerCommit) - return; - -#if DEBUG_AC_COMMIT - Platform::logAlways(Platform::LogLevelCritical, "%s", WTF_PRETTY_FUNCTION); -#endif - - m_backingStore->d->instrumentBeginFrame(); - - // The commit timer may have fired just before the layout timer, or for some - // other reason we need layout. It's not allowed to commit when a layout is - // pending, becaues a commit can cause parts of the web page to be rendered - // to texture. - // The layout can also turn of compositing altogether, so we need to be prepared - // to handle a one shot drawing synchronization after the layout. - updateLayoutAndStyleIfNeededRecursive(); - - // If we transitioned to drawing the root layer using compositor instead of - // backing store, doing a one shot drawing synchronization with the - // backing store is never necessary, because the backing store draws - // nothing. - if (!compositorDrawsRootLayer() && needsOneShotDrawingSynchronization()) { -#if DEBUG_AC_COMMIT - Platform::logAlways(Platform::LogLevelCritical, - "%s: OneShotDrawingSynchronization code path!", - WTF_PRETTY_FUNCTION); -#endif - const IntRect windowRect = IntRect(IntPoint::zero(), viewportSize()); - m_backingStore->d->repaint(windowRect, true /*contentChanged*/, true /*immediate*/); - return; - } - - commitRootLayerIfNeeded(); -} - -void WebPagePrivate::setRootLayerWebKitThread(Frame* frame, LayerWebKitThread* layer) -{ - // This method updates the FrameLayers based on input from WebCore. - // FrameLayers keeps track of the layer proxies attached to frames. - // We will have to compute a new root layer and update the compositor. - if (!layer && !m_frameLayers) - return; - - if (!layer) { - ASSERT(m_frameLayers); - m_frameLayers->removeLayerByFrame(frame); - if (!m_frameLayers->hasLayer()) - m_frameLayers.clear(); - } else { - if (!m_frameLayers) - m_frameLayers = adoptPtr(new FrameLayers(this)); - - if (!m_frameLayers->containsLayerForFrame(frame)) - m_frameLayers->addLayer(frame, layer); - - ASSERT(m_frameLayers); - } - - LayerCompositingThread* rootLayerCompositingThread = 0; - if (m_frameLayers && m_frameLayers->rootLayer()) - rootLayerCompositingThread = m_frameLayers->rootLayer()->layerCompositingThread(); - - setRootLayerCompositingThread(rootLayerCompositingThread); -} - -void WebPagePrivate::setRootLayerCompositingThread(LayerCompositingThread* layer) -{ - if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) { - Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage( - Platform::createMethodCallMessage(&WebPagePrivate::setRootLayerCompositingThread, this, layer)); - return; - } - - if (layer && !m_compositor) - createCompositor(); - - // Don't ASSERT(m_compositor) here because setIsAcceleratedCompositingActive(true) - // may not turn accelerated compositing on since m_backingStore is 0. - if (m_compositor) - m_compositor->setRootLayer(layer); -} - -bool WebPagePrivate::createCompositor() -{ - // If there's no window, the compositor will be supplied by the API client - if (!m_client->window()) - return false; - - m_ownedContext = GLES2Context::create(this); - m_compositor = WebPageCompositorPrivate::create(this, 0); - m_compositor->setContext(m_ownedContext.get()); - - // The compositor is created in a sync message, so there's no risk of race condition on the - // WebSettings. - m_compositor->setBackgroundColor(m_webSettings->backgroundColor()); - - return true; -} - -void WebPagePrivate::destroyCompositor() -{ - // m_compositor is a RefPtr, so it may live on beyond this point. - // Disconnect the compositor from us - m_compositor->detach(); - m_compositor.clear(); - m_ownedContext.clear(); -} - -void WebPagePrivate::syncDestroyCompositorOnCompositingThread() -{ - if (!m_compositor) - return; - - Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage( - Platform::createMethodCallMessage( - &WebPagePrivate::destroyCompositor, this)); -} - -void WebPagePrivate::releaseLayerResources() -{ - if (!isAcceleratedCompositingActive()) - return; - - if (m_frameLayers) - m_frameLayers->releaseLayerResources(); - - Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage( - Platform::createMethodCallMessage(&WebPagePrivate::releaseLayerResourcesCompositingThread, this)); -} - -void WebPagePrivate::releaseLayerResourcesCompositingThread() -{ - m_compositor->releaseLayerResources(); -} - -void WebPagePrivate::updateRootLayerCommitEnabled() -{ - bool shouldSuspend = !m_visible || m_activationState != ActivationActive; - - if (m_suspendRootLayerCommit == shouldSuspend) - return; - - m_suspendRootLayerCommit = shouldSuspend; - - if (m_suspendRootLayerCommit) { - if (m_compositor) - releaseLayerResources(); - - return; - } - - m_needsCommit = true; - // PR 330917, explicitly start root layer commit timer, so that there's a commit - // even if BackingStore got disabled/removed. - scheduleRootLayerCommit(); -} - -bool WebPagePrivate::needsOneShotDrawingSynchronization() -{ - return m_needsOneShotDrawingSynchronization; -} - -void WebPagePrivate::setNeedsOneShotDrawingSynchronization() -{ - if (compositorDrawsRootLayer()) { - scheduleRootLayerCommit(); - return; - } - - // This means we have to commit layers on next render, or render on the next commit, - // whichever happens first. - m_needsCommit = true; - m_needsOneShotDrawingSynchronization = true; -} - -void WebPagePrivate::notifyFlushRequired(const GraphicsLayer*) -{ - scheduleRootLayerCommit(); -} -#endif // USE(ACCELERATED_COMPOSITING) - -void WebPagePrivate::enterFullscreenForNode(Node* node) -{ -#if ENABLE(VIDEO) - if (!node || !node->hasTagName(HTMLNames::videoTag)) - return; - - MediaPlayer* player = toHTMLMediaElement(node)->player(); - if (!player) - return; - - MediaPlayerPrivate* mmrPlayer = static_cast<MediaPlayerPrivate*>(player->implementation()); - if (!mmrPlayer) - return; - - Platform::Graphics::Window* window = mmrPlayer->getWindow(); - if (!window) - return; - - const char* contextName = mmrPlayer->mmrContextName(); - if (!contextName) - return; - - mmrPlayer->setFullscreenWebPageClient(m_client); - m_fullscreenNode = node; - m_client->fullscreenStart(contextName, window, mmrPlayer->getWindowScreenRect()); -#endif -} - -void WebPagePrivate::exitFullscreenForNode(Node* node) -{ -#if ENABLE(VIDEO) - if (m_fullscreenNode.get()) { - m_client->fullscreenStop(); - m_fullscreenNode = 0; - } - - if (!node || !node->hasTagName(HTMLNames::videoTag)) - return; - - MediaPlayer* player = toHTMLMediaElement(node)->player(); - if (!player) - return; - - MediaPlayerPrivate* mmrPlayer = static_cast<MediaPlayerPrivate*>(player->implementation()); - if (!mmrPlayer) - return; - - // Fullscreen mode is being turned off, so MediaPlayerPrivate no longer needs the pointer. - mmrPlayer->setFullscreenWebPageClient(0); -#endif -} - -#if ENABLE(FULLSCREEN_API) -void WebPagePrivate::enterFullScreenForElement(Element* element) -{ -#if ENABLE(VIDEO) - if (!element) - return; - if (m_webSettings->fullScreenVideoCapable() && element->hasTagName(HTMLNames::videoTag)) { - // The Browser chrome has its own fullscreen video widget it wants to - // use, and this is a video element. The only reason that - // webkitWillEnterFullScreenForElement() and - // webkitDidEnterFullScreenForElement() are still called in this case - // is so that exitFullScreenForElement() gets called later. - enterFullscreenForNode(element); - } else { - // At this point, we can assume that there would be a viewport size change if - // the current visible size and screen size are not equal. - if (transformedActualVisibleSize() != transformedViewportSize()) { - // The current scale can be clamped to a greater minimum scale when we relayout contents during - // the change of the viewport size. Cache the current scale so that we can restore it when - // leaving fullscreen. Otherwise, it is possible that we will use the wrong scale. - m_scaleBeforeFullScreen = currentScale(); - - // When an element goes fullscreen, the viewport size changes and the scroll - // position might change. So we keep track of it here, in order to restore it - // once element leaves fullscreen. - m_scrollPositionBeforeFullScreen = m_mainFrame->view()->scrollPosition(); - - // We need to remember the orientation before entering fullscreen, so that we can adjust - // the scale and scroll position when exiting fullscreen if needed, because the scale and - // scroll position may not apply (overscale and/or overscroll) in the other orientation. - m_orientationBeforeFullScreen = orientation(); - } - - // No fullscreen video widget has been made available by the Browser - // chrome, or this is not a video element. The webkitRequestFullScreen - // Javascript call is often made on a div element. - // This is where we would hide the browser's chrome if we wanted to. - client()->fullscreenStart(); - m_fullscreenNode = element; - } -#endif -} - -void WebPagePrivate::exitFullScreenForElement(Element* element) -{ -#if ENABLE(VIDEO) - if (!element) - return; - if (m_webSettings->fullScreenVideoCapable() && element->hasTagName(HTMLNames::videoTag)) { - // The Browser chrome has its own fullscreen video widget. - exitFullscreenForNode(element); - } else { - // This is where we would restore the browser's chrome - // if hidden above. - client()->fullscreenStop(); - m_fullscreenNode = 0; - } -#endif -} - -// FIXME: Move this method to WebCore. -void WebPagePrivate::adjustFullScreenElementDimensionsIfNeeded() -{ - // If we are in fullscreen video mode, and we change the FrameView::viewportRect, - // we need to adjust the media container to the new size. - if (!m_fullscreenNode || !m_fullscreenNode->renderer() - || !m_fullscreenNode->document() || !m_fullscreenNode->document()->fullScreenRenderer()) - return; - - ASSERT(m_fullscreenNode->isElementNode()); - ASSERT(toElement(m_fullscreenNode.get())->isMediaElement()); - - Document* document = m_fullscreenNode->document(); - RenderStyle* fullScreenStyle = document->fullScreenRenderer()->style(); - ASSERT(fullScreenStyle); - - // In order to compensate possible round errors when we scale the fullscreen - // container element to fit to the viewport, lets make the fullscreen 1px wider - // than the viewport size on the right, and one pixel longer at the bottom - // of the scroll position. - IntRect viewportRect = m_mainFrame->view()->visibleContentRect(); - int viewportWidth = viewportRect.width() + 1; - int viewportHeight = viewportRect.height() + 1; - - fullScreenStyle->setWidth(Length(viewportWidth, WebCore::Fixed)); - fullScreenStyle->setHeight(Length(viewportHeight, WebCore::Fixed)); - fullScreenStyle->setLeft(Length(0, WebCore::Fixed)); - fullScreenStyle->setTop(Length(0, WebCore::Fixed)); - fullScreenStyle->setBackgroundColor(Color::black); - - document->fullScreenRenderer()->setNeedsLayoutAndPrefWidthsRecalc(); - document->recalcStyle(Node::Force); -} -#endif - -void WebPagePrivate::didChangeSettings(WebSettings* webSettings) -{ - Settings* coreSettings = m_page->settings(); - m_page->setGroupName(webSettings->pageGroupName()); - coreSettings->setXSSAuditorEnabled(webSettings->xssAuditorEnabled()); - coreSettings->setLoadsImagesAutomatically(webSettings->loadsImagesAutomatically()); - coreSettings->setShouldDrawBorderWhileLoadingImages(webSettings->shouldDrawBorderWhileLoadingImages()); - coreSettings->setScriptEnabled(webSettings->isJavaScriptEnabled()); - coreSettings->setDeviceSupportsMouse(webSettings->deviceSupportsMouse()); - coreSettings->setDefaultFixedFontSize(webSettings->defaultFixedFontSize()); - coreSettings->setDefaultFontSize(webSettings->defaultFontSize()); - coreSettings->setMinimumLogicalFontSize(webSettings->minimumFontSize()); - if (!webSettings->serifFontFamily().empty()) - coreSettings->setSerifFontFamily(String(webSettings->serifFontFamily())); - if (!webSettings->fixedFontFamily().empty()) - coreSettings->setFixedFontFamily(String(webSettings->fixedFontFamily())); - if (!webSettings->sansSerifFontFamily().empty()) - coreSettings->setSansSerifFontFamily(String(webSettings->sansSerifFontFamily())); - if (!webSettings->standardFontFamily().empty()) - coreSettings->setStandardFontFamily(String(webSettings->standardFontFamily())); - coreSettings->setJavaScriptCanOpenWindowsAutomatically(webSettings->canJavaScriptOpenWindowsAutomatically()); - coreSettings->setAllowScriptsToCloseWindows(webSettings->canJavaScriptOpenWindowsAutomatically()); // Why are we using the same value as setJavaScriptCanOpenWindowsAutomatically()? - coreSettings->setPluginsEnabled(webSettings->arePluginsEnabled()); - coreSettings->setDefaultTextEncodingName(webSettings->defaultTextEncodingName()); - coreSettings->setDownloadableBinaryFontsEnabled(webSettings->downloadableBinaryFontsEnabled()); - coreSettings->setSpatialNavigationEnabled(m_webSettings->isSpatialNavigationEnabled()); - coreSettings->setAsynchronousSpellCheckingEnabled(m_webSettings->isAsynchronousSpellCheckingEnabled()); - - BlackBerry::Platform::String stylesheetURL = webSettings->userStyleSheetLocation(); - if (!stylesheetURL.empty()) - coreSettings->setUserStyleSheetLocation(KURL(KURL(), stylesheetURL)); - - coreSettings->setFirstScheduledLayoutDelay(webSettings->firstScheduledLayoutDelay()); - coreSettings->setUseCache(webSettings->useWebKitCache()); - coreSettings->setCookieEnabled(webSettings->areCookiesEnabled()); - - if (coreSettings->privateBrowsingEnabled() != webSettings->isPrivateBrowsingEnabled()) { - coreSettings->setPrivateBrowsingEnabled(webSettings->isPrivateBrowsingEnabled()); - cookieManager().setPrivateMode(webSettings->isPrivateBrowsingEnabled()); - CredentialStorage::setPrivateMode(webSettings->isPrivateBrowsingEnabled()); - } - -#if ENABLE(SQL_DATABASE) - // DatabaseManager can only be initialized for once, so it doesn't - // make sense to change database path after DatabaseManager has - // already been initialized. - static bool dbinit = false; - if (!dbinit && !webSettings->databasePath().empty()) { - dbinit = true; - DatabaseManager::manager().initialize(webSettings->databasePath()); - } - - // The directory of cacheStorage for one page group can only be initialized once. - static bool acinit = false; - if (!acinit && !webSettings->appCachePath().empty()) { - acinit = true; - cacheStorage().setCacheDirectory(webSettings->appCachePath()); - } - - coreSettings->setLocalStorageDatabasePath(webSettings->localStoragePath()); - DatabaseManager::manager().setIsAvailable(webSettings->isDatabasesEnabled()); - - coreSettings->setLocalStorageEnabled(webSettings->isLocalStorageEnabled()); - coreSettings->setOfflineWebApplicationCacheEnabled(webSettings->isAppCacheEnabled()); - - m_page->group().groupSettings()->setLocalStorageQuotaBytes(webSettings->localStorageQuota()); - coreSettings->setSessionStorageQuota(webSettings->sessionStorageQuota()); - coreSettings->setUsesPageCache(webSettings->maximumPagesInCache()); - coreSettings->setFrameFlatteningEnabled(webSettings->isFrameFlatteningEnabled()); -#endif - -#if ENABLE(INDEXED_DATABASE) - m_page->group().groupSettings()->setIndexedDBDatabasePath(webSettings->indexedDataBasePath()); -#endif - - -#if ENABLE(WEB_SOCKETS) - WebSocket::setIsAvailable(webSettings->areWebSocketsEnabled()); -#endif - -#if ENABLE(FULLSCREEN_API) - // This allows Javascript to call webkitRequestFullScreen() on an element. - coreSettings->setFullScreenEnabled(true); -#endif - -#if ENABLE(VIEWPORT_REFLOW) - coreSettings->setTextReflowEnabled(webSettings->textReflowMode() == WebSettings::TextReflowEnabled); -#endif - - // FIXME: We don't want HTMLTokenizer to yield for anything other than email case because - // call to currentTime() is too expensive on our platform. See RIM Bug #746. - coreSettings->setShouldUseFirstScheduledLayoutDelay(webSettings->isEmailMode()); - coreSettings->setProcessHTTPEquiv(!webSettings->isEmailMode()); - - coreSettings->setShouldUseCrossOriginProtocolCheck(!webSettings->allowCrossSiteRequests()); - coreSettings->setWebSecurityEnabled(!webSettings->allowCrossSiteRequests()); - coreSettings->setApplyDeviceScaleFactorInCompositor(webSettings->applyDeviceScaleFactorInCompositor()); - - updateBackgroundColor(webSettings->backgroundColor()); - - m_page->setDeviceScaleFactor(webSettings->devicePixelRatio()); - -#if ENABLE(TEXT_AUTOSIZING) - coreSettings->setTextAutosizingEnabled(webSettings->isTextAutosizingEnabled()); -#endif -} - -BlackBerry::Platform::String WebPage::textHasAttribute(const BlackBerry::Platform::String& query) const -{ - if (Document* doc = d->m_page->focusController()->focusedOrMainFrame()->document()) - return doc->queryCommandValue(query); - - return BlackBerry::Platform::String::emptyString(); -} - -void WebPage::setJavaScriptCanAccessClipboard(bool enabled) -{ - d->m_page->settings()->setJavaScriptCanAccessClipboard(enabled); -} - -#if USE(ACCELERATED_COMPOSITING) -void WebPagePrivate::scheduleCompositingRun() -{ - if (WebPageCompositorClient* compositorClient = compositor()->client()) { - double animationTime = compositorClient->requestAnimationFrame(); - compositorClient->invalidate(animationTime); - return; - } - - m_backingStore->d->blitVisibleContents(); -} -#endif - -void WebPage::setWebGLEnabled(bool enabled) -{ - d->m_page->settings()->setWebGLEnabled(enabled); -} - -bool WebPage::isWebGLEnabled() const -{ - return d->m_page->settings()->webGLEnabled(); -} - -void WebPagePrivate::frameUnloaded(const Frame* frame) -{ - m_inputHandler->frameUnloaded(frame); - m_inPageSearchManager->frameUnloaded(frame); -} - -const BlackBerry::Platform::String& WebPagePrivate::defaultUserAgent() -{ - static BlackBerry::Platform::String* defaultUserAgent = 0; - if (!defaultUserAgent) { - BlackBerry::Platform::DeviceInfo* info = BlackBerry::Platform::DeviceInfo::instance(); - char uaBuffer[256]; - int uaSize = snprintf(uaBuffer, 256, "Mozilla/5.0 (%s) AppleWebKit/%d.%d+ (KHTML, like Gecko) Version/%s %sSafari/%d.%d+", - info->family(), WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION, info->osVersion(), - info->isMobile() ? "Mobile " : "", WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION); - - if (uaSize <= 0 || uaSize >= 256) - BLACKBERRY_CRASH(); - - defaultUserAgent = new BlackBerry::Platform::String(BlackBerry::Platform::String::fromUtf8(uaBuffer, uaSize)); - } - - return *defaultUserAgent; -} - -WebTapHighlight* WebPage::tapHighlight() const -{ - return d->m_tapHighlight.get(); -} - -WebTapHighlight* WebPage::selectionHighlight() const -{ - return d->m_selectionHighlight.get(); -} - -void WebPage::addOverlay(WebOverlay* overlay) -{ -#if USE(ACCELERATED_COMPOSITING) - if (overlay->d->graphicsLayer()) { - overlay->d->setPage(d); - d->overlayLayer()->addChild(overlay->d->graphicsLayer()); - } -#endif -} - -void WebPage::removeOverlay(WebOverlay* overlay) -{ -#if USE(ACCELERATED_COMPOSITING) - if (overlay->d->graphicsLayer()->parent() != d->overlayLayer()) - return; - - overlay->removeFromParent(); - overlay->d->clear(); - overlay->d->setPage(0); -#endif -} - -void WebPage::addCompositingThreadOverlay(WebOverlay* overlay) -{ -#if USE(ACCELERATED_COMPOSITING) - ASSERT(Platform::userInterfaceThreadMessageClient()->isCurrentThread()); - if (!d->compositor()) - return; - - overlay->d->setPage(d); - d->compositor()->addOverlay(overlay->d->layerCompositingThread()); -#endif -} - -void WebPage::removeCompositingThreadOverlay(WebOverlay* overlay) -{ -#if USE(ACCELERATED_COMPOSITING) - ASSERT(Platform::userInterfaceThreadMessageClient()->isCurrentThread()); - if (d->compositor()) - d->compositor()->removeOverlay(overlay->d->layerCompositingThread()); - overlay->d->clear(); - overlay->d->setPage(0); -#endif -} - -bool WebPagePrivate::openPagePopup(PagePopupClient* popupClient, const WebCore::IntRect& originBoundsInRootView) -{ - closePagePopup(); - m_pagePopup = PagePopup::create(this, popupClient); - - WebCore::IntRect popupRect = m_page->chrome().client()->rootViewToScreen(originBoundsInRootView); - popupRect.setSize(popupClient->contentSize()); - if (!m_client->createPopupWebView(popupRect)) { - closePagePopup(); - return false; - } - - return true; -} - -void WebPagePrivate::closePagePopup() -{ - if (!m_pagePopup) - return; - - m_pagePopup->close(); - m_client->closePopupWebView(); - m_pagePopup = 0; -} - -bool WebPagePrivate::hasOpenedPopup() const -{ - return m_pagePopup; -} - -void WebPagePrivate::setInspectorOverlayClient(InspectorOverlay::InspectorOverlayClient* inspectorOverlayClient) -{ - if (inspectorOverlayClient) { - if (!m_inspectorOverlay) - m_inspectorOverlay = InspectorOverlay::create(this, inspectorOverlayClient); - else - m_inspectorOverlay->setClient(inspectorOverlayClient); - m_inspectorOverlay->update(); - scheduleRootLayerCommit(); - } else { - if (m_inspectorOverlay) { - m_inspectorOverlay->clear(); - m_inspectorOverlay = nullptr; - scheduleRootLayerCommit(); - } - } -} - -void WebPagePrivate::applySizeOverride(int overrideWidth, int overrideHeight) -{ - m_client->requestUpdateViewport(overrideWidth, overrideHeight); -} - -void WebPagePrivate::setTextZoomFactor(float textZoomFactor) -{ - if (!m_mainFrame) - return; - - m_mainFrame->setTextZoomFactor(textZoomFactor); -} - -void WebPagePrivate::restoreHistoryViewState(const WebCore::IntPoint& scrollPosition, double scale, bool shouldReflowBlock) -{ - if (!m_mainFrame) { - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->resumeBackingStoreUpdates(); - m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); - return; - } - - // If we are about to overscroll, scroll back to the valid contents area. - WebCore::IntPoint adjustedScrollPosition = scrollPosition; - WebCore::IntSize validContentsSize = contentsSize(); - WebCore::IntSize viewportSize = actualVisibleSize(); - if (adjustedScrollPosition.x() + viewportSize.width() > validContentsSize.width()) - adjustedScrollPosition.setX(validContentsSize.width() - viewportSize.width()); - if (adjustedScrollPosition.y() + viewportSize.height() > validContentsSize.height()) - adjustedScrollPosition.setY(validContentsSize.height() - viewportSize.height()); - - // Here we need to set scroll position what we asked for. - // So we use ScrollView::constrainsScrollingToContentEdge(false). - bool oldConstrainsScrollingToContentEdge = m_mainFrame->view()->constrainsScrollingToContentEdge(); - m_mainFrame->view()->setConstrainsScrollingToContentEdge(false); - setScrollPosition(adjustedScrollPosition); - m_mainFrame->view()->setConstrainsScrollingToContentEdge(oldConstrainsScrollingToContentEdge); - - m_shouldReflowBlock = shouldReflowBlock; - - if (!zoomAboutPoint(scale, m_mainFrame->view()->scrollPosition(), true /* enforceScaleClamping */, true /*forceRendering*/, true /*isRestoringZoomLevel*/)) { - // We need to notify the client of the scroll position and content size change(s) above even if we didn't scale. - notifyTransformedContentsSizeChanged(); - notifyTransformedScrollChanged(); - } - - // If we're already at that scale, then we should still force rendering - // since our scroll position changed. - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->resumeBackingStoreUpdates(); - m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); -} - -IntSize WebPagePrivate::screenSize() const -{ - return Platform::Graphics::Screen::primaryScreen()->size(); -} - -void WebPagePrivate::postponeDocumentStyleRecalc() -{ - if (Document* document = m_mainFrame->document()) { - m_documentChildNeedsStyleRecalc = document->childNeedsStyleRecalc(); - document->clearChildNeedsStyleRecalc(); - - m_documentStyleRecalcPostponed = document->hasPendingStyleRecalc(); - document->unscheduleStyleRecalc(); - } -} - -void WebPagePrivate::resumeDocumentStyleRecalc() -{ - if (Document* document = m_mainFrame->document()) { - if (m_documentChildNeedsStyleRecalc) - document->setChildNeedsStyleRecalc(); - - if (m_documentStyleRecalcPostponed) - document->scheduleStyleRecalc(); - } - - m_documentChildNeedsStyleRecalc = false; - m_documentStyleRecalcPostponed = false; -} - -const HitTestResult& WebPagePrivate::hitTestResult(const IntPoint& contentPos) -{ - if (m_cachedHitTestContentPos != contentPos) { - m_cachedHitTestContentPos = contentPos; - m_cachedRectHitTestResults.clear(); - m_cachedHitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_cachedHitTestContentPos, HitTestRequest::ReadOnly | HitTestRequest::Active); - } - - return m_cachedHitTestResult; -} - -void WebPagePrivate::clearCachedHitTestResult() -{ - m_cachedHitTestContentPos = WebCore::IntPoint(-1, -1); -} - -void WebPagePrivate::willComposite() -{ - if (!m_page->settings()->developerExtrasEnabled()) - return; - m_page->inspectorController()->willComposite(); -} - -void WebPagePrivate::didComposite() -{ - if (!m_page->settings()->developerExtrasEnabled()) - return; - m_page->inspectorController()->didComposite(); -} - -void WebPage::updateNotificationPermission(const BlackBerry::Platform::String& requestId, bool allowed) -{ -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) - d->notificationManager().updatePermission(requestId, allowed); -#else - UNUSED_PARAM(requestId); - UNUSED_PARAM(allowed); -#endif -} - -void WebPage::notificationClicked(const BlackBerry::Platform::String& notificationId) -{ -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) - d->notificationManager().notificationClicked(notificationId); -#else - UNUSED_PARAM(notificationId); -#endif -} - -void WebPage::notificationClosed(const BlackBerry::Platform::String& notificationId) -{ -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) - d->notificationManager().notificationClosed(notificationId); -#else - UNUSED_PARAM(notificationId); -#endif -} - -void WebPage::notificationError(const BlackBerry::Platform::String& notificationId) -{ -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) - d->notificationManager().notificationError(notificationId); -#else - UNUSED_PARAM(notificationId); -#endif -} - -void WebPage::notificationShown(const BlackBerry::Platform::String& notificationId) -{ -#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS) - d->notificationManager().notificationShown(notificationId); -#else - UNUSED_PARAM(notificationId); -#endif -} - -void WebPagePrivate::animateToScaleAndDocumentScrollPosition(double destinationZoomScale, const WebCore::FloatPoint& destinationScrollPosition, bool shouldConstrainScrollingToContentEdge) -{ - if (destinationScrollPosition == scrollPosition() && destinationZoomScale == currentScale()) - return; - - m_shouldReflowBlock = false; - m_userPerformedManualZoom = true; - m_userPerformedManualScroll = true; - client()->animateToScaleAndDocumentScrollPosition(destinationZoomScale, destinationScrollPosition, shouldConstrainScrollingToContentEdge); -} - -void WebPage::animateToScaleAndDocumentScrollPosition(double destinationZoomScale, const BlackBerry::Platform::FloatPoint& destinationScrollPosition, bool shouldConstrainScrollingToContentEdge) -{ - d->animateToScaleAndDocumentScrollPosition(destinationZoomScale, destinationScrollPosition, shouldConstrainScrollingToContentEdge); -} - -void WebPagePrivate::updateBackgroundColor(const Color& backgroundColor) -{ - if (!m_mainFrame || !m_mainFrame->view()) - return; - - m_mainFrame->view()->updateBackgroundRecursively(backgroundColor, backgroundColor.hasAlpha()); - - // FIXME: The BackingStore uses the document background color but the WebPageCompositor gets - // the color from settings, which can be different. - Platform::userInterfaceThreadMessageClient()->dispatchMessage( - createMethodCallMessage(&WebPagePrivate::setCompositorBackgroundColor, this, backgroundColor)); - - if (m_backingStore) - m_backingStore->d->setWebPageBackgroundColor(documentBackgroundColor()); -} - -Color WebPagePrivate::documentBackgroundColor() const -{ - Color color; - if (m_mainFrame && m_mainFrame->view()) - color = m_mainFrame->view()->documentBackgroundColor(); - if (!color.isValid()) - color = m_webSettings->backgroundColor(); - return color; -} - -bool WebPage::isProcessingUserGesture() const -{ - return ScriptController::processingUserGesture(); -} - -#if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) -void WebPagePrivate::animationFrameChanged() -{ - if (!m_animationMutex.tryLock()) - return; - - if (!m_previousFrameDone) { - m_animationMutex.unlock(); - return; - } - - if (!m_animationScheduled) { - stopRefreshAnimationClient(); - m_animationMutex.unlock(); - return; - } - - m_previousFrameDone = false; - - m_monotonicAnimationStartTime = monotonicallyIncreasingTime(); - callOnMainThread(handleServiceScriptedAnimationsOnMainThread, this); - m_animationMutex.unlock(); -} - -void WebPagePrivate::scheduleAnimation() -{ - if (m_animationScheduled) - return; - MutexLocker lock(m_animationMutex); - m_animationScheduled = true; - startRefreshAnimationClient(); -} - -void WebPagePrivate::startRefreshAnimationClient() -{ - if (m_isRunningRefreshAnimationClient) - return; - m_isRunningRefreshAnimationClient = true; - BlackBerry::Platform::AnimationFrameRateController::instance()->addClient(this); -} - -void WebPagePrivate::stopRefreshAnimationClient() -{ - if (!m_isRunningRefreshAnimationClient) - return; - m_isRunningRefreshAnimationClient = false; - BlackBerry::Platform::AnimationFrameRateController::instance()->removeClient(this); -} - -void WebPagePrivate::serviceAnimations() -{ - double monotonicAnimationStartTime; - { - MutexLocker lock(m_animationMutex); - m_animationScheduled = false; - monotonicAnimationStartTime = m_monotonicAnimationStartTime; - } - - m_mainFrame->view()->serviceScriptedAnimations(monotonicAnimationStartTime); - - { - MutexLocker lock(m_animationMutex); - m_previousFrameDone = true; - } -} - -void WebPagePrivate::handleServiceScriptedAnimationsOnMainThread(void* data) -{ - static_cast<WebPagePrivate*>(data)->serviceAnimations(); -} -#endif - -void WebPage::setShowDebugBorders(bool show) -{ -#if USE(ACCELERATED_COMPOSITING) - d->m_page->settings()->setShowDebugBorders(show); -#endif -} - -} -} |
