diff options
Diffstat (limited to 'Source/WebKit/blackberry/Api/WebPage.cpp')
| -rw-r--r-- | Source/WebKit/blackberry/Api/WebPage.cpp | 1937 |
1 files changed, 1029 insertions, 908 deletions
diff --git a/Source/WebKit/blackberry/Api/WebPage.cpp b/Source/WebKit/blackberry/Api/WebPage.cpp index 23d1d3557..08af55b11 100644 --- a/Source/WebKit/blackberry/Api/WebPage.cpp +++ b/Source/WebKit/blackberry/Api/WebPage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved. + * 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 @@ -19,11 +19,12 @@ #include "config.h" #include "WebPage.h" +#include "APIShims.h" #include "ApplicationCacheStorage.h" #include "AuthenticationChallengeManager.h" #include "AutofillManager.h" #include "BackForwardController.h" -#include "BackForwardListImpl.h" +#include "BackForwardListBlackBerry.h" #include "BackingStoreClient.h" #include "BackingStore_p.h" #if ENABLE(BATTERY_STATUS) @@ -32,15 +33,12 @@ #include "CachedImage.h" #include "Chrome.h" #include "ChromeClientBlackBerry.h" -#include "ContextMenuClientBlackBerry.h" #include "CookieManager.h" #include "CredentialManager.h" #include "CredentialStorage.h" #include "CredentialTransformData.h" #include "DOMSupport.h" -#include "Database.h" -#include "DatabaseSync.h" -#include "DatabaseTracker.h" +#include "DatabaseManager.h" #include "DefaultTapHighlight.h" #include "DeviceMotionClientBlackBerry.h" #include "DeviceOrientationClientBlackBerry.h" @@ -70,6 +68,7 @@ #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "HTMLParserIdioms.h" +#include "HTMLTextAreaElement.h" #include "HTTPParsers.h" #include "HistoryItem.h" #include "IconDatabaseClientBlackBerry.h" @@ -85,11 +84,13 @@ #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 @@ -99,7 +100,8 @@ #include "Page.h" #include "PageCache.h" #include "PageGroup.h" -#include "PagePopupBlackBerry.h" +#include "PagePopup.h" +#include "PagePopupClient.h" #include "PlatformTouchEvent.h" #include "PlatformWheelEvent.h" #include "PluginDatabase.h" @@ -114,6 +116,7 @@ #include "RenderTreeAsText.h" #include "RenderView.h" #include "RenderWidget.h" +#include "ScriptController.h" #include "ScriptSourceCode.h" #include "ScriptValue.h" #include "ScrollTypes.h" @@ -136,9 +139,6 @@ #endif #include "VisiblePosition.h" #include "WebCookieJar.h" -#if ENABLE(WEBDOM) -#include "WebDOMDocument.h" -#endif #include "WebKitThreadViewportAccessor.h" #include "WebKitVersion.h" #include "WebOverlay.h" @@ -154,10 +154,6 @@ #include "MediaPlayerPrivateBlackBerry.h" #endif -#if USE(SKIA) -#include "PlatformContextSkia.h" -#endif - #if USE(ACCELERATED_COMPOSITING) #include "FrameLayers.h" #include "WebPageCompositorClient.h" @@ -171,10 +167,12 @@ #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 @@ -184,11 +182,6 @@ #include <memalloc.h> #endif -#if ENABLE(ACCELERATED_2D_CANVAS) -#include "GrContext.h" -#include "SharedGraphicsContext3D.h" -#endif - #if ENABLE(REQUEST_ANIMATION_FRAME) #include "PlatformScreen.h" #endif @@ -343,11 +336,6 @@ void WebPage::autofillTextField(const BlackBerry::Platform::String& item) d->m_autofillManager->autofillTextField(item); } -void WebPage::enableQnxJavaScriptObject(bool enabled) -{ - d->m_enableQnxJavaScriptObject = enabled; -} - BlackBerry::Platform::String WebPage::renderTreeAsText() { return externalRepresentation(d->m_mainFrame); @@ -373,6 +361,7 @@ WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const In , m_overflowExceedsContentsSize(false) , m_resetVirtualViewportOnCommitted(true) , m_shouldUseFixedDesktopMode(false) + , m_inspectorEnabled(false) , m_preventIdleDimmingCount(0) #if ENABLE(TOUCH_EVENTS) , m_preventDefaultOnTouchStart(false) @@ -387,25 +376,25 @@ WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const In , m_transformationMatrix(new TransformationMatrix()) , m_backingStore(0) // Initialized by init. , m_backingStoreClient(0) // Initialized by init. - , m_webkitThreadViewportAccessor(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) - , m_xScrollOffsetBeforeFullScreen(-1) #endif , m_currentCursor(Platform::CursorNone) , m_dumpRenderTree(0) // Lazy initialization. , m_initialScale(-1.0) , m_minimumScale(-1.0) , m_maximumScale(-1.0) - , m_blockZoomFinalScale(1.0) + , m_forceRespectViewportArguments(false) , m_anchorInNodeRectRatio(-1, -1) , m_currentBlockZoomNode(0) , m_currentBlockZoomAdjustedNode(0) @@ -420,18 +409,25 @@ WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const In , m_suspendRootLayerCommit(false) #endif , m_pendingOrientation(-1) - , m_fullscreenVideoNode(0) + , m_fullscreenNode(0) , m_hasInRegionScrollableAreas(false) , m_updateDelegatedOverlaysDispatched(false) - , m_enableQnxJavaScriptObject(false) , m_deferredTasksTimer(this, &WebPagePrivate::deferredTasksTimerFired) - , m_selectPopup(0) + , 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) { @@ -458,6 +454,13 @@ WebPagePrivate::~WebPagePrivate() 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; @@ -489,8 +492,11 @@ WebPagePrivate::~WebPagePrivate() delete m_touchEventHandler; m_touchEventHandler = 0; + delete m_proximityDetector; + m_proximityDetector = 0; + #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD - delete m_dumpRenderTree; + BlackBerry::Platform::deleteGuardedObject(static_cast<DumpRenderTree*>(m_dumpRenderTree)); m_dumpRenderTree = 0; #endif @@ -510,11 +516,10 @@ Page* WebPagePrivate::core(const WebPage* webPage) void WebPagePrivate::init(const BlackBerry::Platform::String& pageGroupName) { + m_webSettings = WebSettings::createFromStandardSettings(); + m_webSettings->setUserAgentString(defaultUserAgent()); + ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this); - ContextMenuClientBlackBerry* contextMenuClient = 0; -#if ENABLE(CONTEXT_MENUS) - contextMenuClient = new ContextMenuClientBlackBerry(); -#endif EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this); DragClientBlackBerry* dragClient = 0; #if ENABLE(DRAG_SUPPORT) @@ -528,10 +533,10 @@ void WebPagePrivate::init(const BlackBerry::Platform::String& pageGroupName) Page::PageClients pageClients; pageClients.chromeClient = chromeClient; - pageClients.contextMenuClient = contextMenuClient; 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 @@ -568,21 +573,21 @@ void WebPagePrivate::init(const BlackBerry::Platform::String& pageGroupName) #endif #if ENABLE(NAVIGATOR_CONTENT_UTILS) - WebCore::provideNavigatorContentUtilsTo(m_page, new NavigatorContentUtilsClientBlackBerry(this)); + 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_webSettings = WebSettings::createFromStandardSettings(); - m_webSettings->setUserAgentString(defaultUserAgent()); 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 @@ -615,14 +620,13 @@ void WebPagePrivate::init(const BlackBerry::Platform::String& pageGroupName) 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(); - m_webkitThreadViewportAccessor = new WebKitThreadViewportAccessor(this); - 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); @@ -631,8 +635,12 @@ void WebPagePrivate::init(const BlackBerry::Platform::String& pageGroupName) m_page->windowScreenDidChange((PlatformDisplayID)0); #endif -#if ENABLE(WEB_TIMING) - m_page->settings()->setMemoryInfoEnabled(true); +#if ENABLE(FILE_SYSTEM) + static bool localFileSystemInitialized = false; + if (!localFileSystemInitialized) { + localFileSystemInitialized = true; + WebCore::LocalFileSystem::initializeLocalFileSystem("/"); + } #endif #if USE(ACCELERATED_COMPOSITING) @@ -640,7 +648,7 @@ void WebPagePrivate::init(const BlackBerry::Platform::String& pageGroupName) // 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)); + createMethodCallMessage(&WebPagePrivate::createCompositor, this)); #endif } @@ -658,12 +666,12 @@ private: } }; -void WebPagePrivate::load(const BlackBerry::Platform::String& url, const BlackBerry::Platform::String& networkToken, const BlackBerry::Platform::String& method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool isInitial, bool mustHandleInternally, bool forceDownload, const BlackBerry::Platform::String& overrideContentType, const BlackBerry::Platform::String& suggestedSaveName) +void WebPagePrivate::load(const Platform::NetworkRequest& netReq, bool needReferer) { stopCurrentLoad(); DeferredTaskLoadManualScript::finishOrCancel(this); - String urlString(url); + String urlString(netReq.getUrlRef()); if (urlString.startsWith("vs:", false)) { urlString = urlString.substring(3); m_mainFrame->setInViewSourceMode(true); @@ -680,65 +688,48 @@ void WebPagePrivate::load(const BlackBerry::Platform::String& url, const BlackBe return; } - if (isInitial) - NetworkManager::instance()->setInitialURL(kurl); - ResourceRequest request(kurl); - request.setToken(networkToken); - if (isInitial || mustHandleInternally) - request.setMustHandleInternally(true); - request.setHTTPMethod(method); - request.setCachePolicy(toWebCoreCachePolicy(cachePolicy)); - if (!overrideContentType.empty()) - request.setOverrideContentType(overrideContentType); + request.setHTTPMethod(netReq.getMethodRef()); + request.setCachePolicy(toWebCoreCachePolicy(netReq.getCachePolicy())); + if (!netReq.getOverrideContentType().empty()) + request.setOverrideContentType(netReq.getOverrideContentType()); - if (data) - request.setHTTPBody(FormData::create(data, dataLength)); + 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()); + } - for (unsigned i = 0; i + 1 < headersLength; i += 2) - request.addHTTPHeaderField(headers[i], headers[i + 1]); + if (needReferer && focusedOrMainFrame() && focusedOrMainFrame()->document()) + request.addHTTPHeaderField("Referer", focusedOrMainFrame()->document()->url().string().utf8().data()); - if (forceDownload) + if (Platform::NetworkRequest::TargetIsDownload == netReq.getTargetType()) request.setForceDownload(true); + if (!netReq.getSuggestedSaveName().empty()) + request.setSuggestedSaveName(netReq.getSuggestedSaveName()); - request.setSuggestedSaveName(suggestedSaveName); - - FrameLoadRequest frameRequest(m_mainFrame, request); - frameRequest.setFrameName(""); - frameRequest.setShouldCheckNewWindowPolicy(true); - m_mainFrame->loader()->load(frameRequest); -} - -void WebPage::load(const BlackBerry::Platform::String& url, const BlackBerry::Platform::String& networkToken, bool isInitial) -{ - d->load(url, networkToken, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, isInitial, false); -} - -void WebPage::loadExtended(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool mustHandleInternally) -{ - d->load(url, networkToken, method, cachePolicy, data, dataLength, headers, headersLength, false, mustHandleInternally, false, ""); + 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 = BlackBerry::Platform::String("file://", 7) + fileUrl; - else if (!fileUrl.startsWith("file:///")) + if (fileUrl.startsWith('/')) + fileUrl = s_filePrefix + fileUrl; + else if (!fileUrl.startsWith(s_fileRootPrefix)) return; - d->load(fileUrl, BlackBerry::Platform::String::emptyString(), BlackBerry::Platform::String("GET", 3), Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, false, overrideContentType.c_str()); + Platform::NetworkRequest netRequest; + netRequest.setRequestUrl(fileUrl); + netRequest.setOverrideContentType(overrideContentType); + d->load(netRequest, false); } -void WebPage::download(const Platform::NetworkRequest& request) +void WebPage::load(const Platform::NetworkRequest& request, bool needReferer) { - vector<const char*> headers; - Platform::NetworkRequest::HeaderList& list = request.getHeaderListRef(); - for (unsigned i = 0; i < list.size(); i++) { - headers.push_back(list[i].first.c_str()); - headers.push_back(list[i].second.c_str()); - } - d->load(request.getUrlRef(), BlackBerry::Platform::String::emptyString(), "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, headers.empty() ? 0 : &headers[0], headers.size(), false, false, true, "", request.getSuggestedSaveName().c_str()); + 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) @@ -759,7 +750,7 @@ void WebPage::loadString(const BlackBerry::Platform::String& string, const Black d->loadString(string, baseURL, mimeType, failingURL); } -bool WebPagePrivate::executeJavaScript(const BlackBerry::Platform::String& scriptUTF8, JavaScriptDataType& returnType, WebString& returnValue) +bool WebPagePrivate::executeJavaScript(const BlackBerry::Platform::String& scriptUTF8, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue) { BLACKBERRY_ASSERT(scriptUTF8.isUtf8()); String script = scriptUTF8; @@ -847,7 +838,7 @@ bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& so bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue) { - // On our platform wchar_t is unsigned int and UChar is unsigned short + // 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; @@ -889,12 +880,12 @@ void WebPage::executeJavaScriptFunction(const std::vector<BlackBerry::Platform:: JSC::ExecState* exec = root->globalObject()->globalExec(); JSGlobalContextRef ctx = toGlobalRef(exec); - JSC::JSLockHolder lock(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 = windowObject(); + 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) { @@ -1038,37 +1029,24 @@ void WebPagePrivate::setLoadState(LoadState state) m_mainFrame->document()->updateStyleIfNeeded(); // Dispatch the backingstore background color at important state changes. - m_backingStore->d->setWebPageBackgroundColor(m_mainFrame && m_mainFrame->view() - ? m_mainFrame->view()->documentBackgroundColor() - : m_webSettings->backgroundColor()); + m_backingStore->d->setWebPageBackgroundColor(documentBackgroundColor()); m_loadState = state; #if DEBUG_WEBPAGE_LOAD - BBLOG(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state); + Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state); #endif switch (m_loadState) { case Provisional: if (isFirstLoad) { - // Paints the visible backingstore as white to prevent initial checkerboard on - // the first blit. - if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow()) - m_backingStore->d->blitVisibleContents(); + // Paints the visible backingstore as settings()->backgroundColor() + // to prevent initial checkerboard on the first blit. + m_backingStore->d->renderAndBlitVisibleContentsImmediately(); } break; case Committed: { -#if ENABLE(ACCELERATED_2D_CANVAS) - if (m_page->settings()->canvasUsesAcceleratedDrawing()) { - // Free GPU resources as we're on a new page. - // This will help us to free memory pressure. - SharedGraphicsContext3D::get()->makeContextCurrent(); - GrContext* grContext = Platform::Graphics::getGrContext(); - grContext->freeGpuResources(); - } -#endif - #if USE(ACCELERATED_COMPOSITING) releaseLayerResources(); #endif @@ -1080,12 +1058,13 @@ void WebPagePrivate::setLoadState(LoadState state) m_previousContentsSize = IntSize(); m_backingStore->d->resetRenderQueue(); - m_backingStore->d->resetTiles(true /* resetBackground */); + 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) @@ -1107,11 +1086,18 @@ void WebPagePrivate::setLoadState(LoadState state) // 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); @@ -1134,14 +1120,11 @@ void WebPagePrivate::setLoadState(LoadState state) // FIXME: Do we really need to suspend/resume both backingstore and screen here? m_backingStore->d->resumeBackingStoreUpdates(); - m_backingStore->d->resumeScreenUpdates(BackingStore::None); - // 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. - if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow()) - m_backingStore->d->blitVisibleContents(); + m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); // Update cursor status. updateCursor(); @@ -1170,7 +1153,7 @@ double WebPagePrivate::clampedScale(double scale) const bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale) { - if (!m_mainFrame->view()) + if (!m_mainFrame || !m_mainFrame->view()) return false; if (enforceScaleClamping) @@ -1179,10 +1162,8 @@ bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool ASSERT(clampedScale); *clampedScale = scale; - if (currentScale() == scale) { - m_client->scaleChanged(); + if (currentScale() == scale) return false; - } return true; } @@ -1215,8 +1196,11 @@ bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anc zoom.scale(scale); #if DEBUG_WEBPAGE_LOAD - if (loadState() < Finished) - BBLOG(Platform::LogLevelInfo, "WebPagePrivate::zoomAboutPoint scale %f anchor (%f, %f)", scale, anchor.x(), anchor.y()); + 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. @@ -1243,16 +1227,16 @@ bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anc 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))))); + 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. - m_mainFrame->view()->setNeedsLayout(); - requestLayoutIfNeeded(); + setNeedsLayout(); + layoutIfNeeded(); if (m_currentPinchZoomNode) newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale); - m_currentPinchZoomNode = 0; - m_anchorInNodeRectRatio = FloatPoint(-1, -1); + m_currentPinchZoomNode = 0; + m_anchorInNodeRectRatio = FloatPoint(-1, -1); } setScrollPosition(newScrollPosition); @@ -1265,13 +1249,6 @@ bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anc m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */); bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering; - bool shouldClearVisibleZoom = isLoading && shouldRender; - - if (shouldClearVisibleZoom) { - // If we are loading and rendering then we need to clear the render queue's - // visible zoom jobs as they will be irrelevant with the render below. - m_backingStore->d->clearVisibleZoom(); - } m_client->scaleChanged(); @@ -1312,7 +1289,7 @@ IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& ancho 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)))); + max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale)))); } void WebPagePrivate::setNeedsLayout() @@ -1322,7 +1299,7 @@ void WebPagePrivate::setNeedsLayout() view->setNeedsLayout(); } -void WebPagePrivate::requestLayoutIfNeeded() const +void WebPagePrivate::updateLayoutAndStyleIfNeededRecursive() const { FrameView* view = m_mainFrame->view(); ASSERT(view); @@ -1330,18 +1307,33 @@ void WebPagePrivate::requestLayoutIfNeeded() const 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); } @@ -1373,7 +1365,7 @@ void WebPage::setDocumentScrollPosition(const Platform::IntPoint& documentScroll bool WebPagePrivate::shouldSendResizeEvent() { - if (!m_mainFrame->document()) + if (!m_mainFrame || !m_mainFrame->document()) return false; // PR#96865 : Provide an option to always send resize events, regardless of the loading @@ -1415,7 +1407,7 @@ void WebPagePrivate::didResumeLoading() void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*) { ASSERT(!m_deferredTasks.isEmpty()); - if (!m_deferredTasks.isEmpty()) + if (m_deferredTasks.isEmpty()) return; OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release(); @@ -1429,12 +1421,8 @@ void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*) void WebPagePrivate::notifyInRegionScrollStopped() { - if (m_inRegionScroller->d->isActive()) { - // Notify the client side to clear InRegion scrollable areas before we destroy them here. - std::vector<Platform::ScrollViewBase*> emptyInRegionScrollableAreas; - m_client->notifyInRegionScrollableAreasChanged(emptyInRegionScrollableAreas); + if (m_inRegionScroller->d->isActive()) m_inRegionScroller->d->reset(); - } } void WebPage::notifyInRegionScrollStopped() @@ -1450,12 +1438,12 @@ void WebPagePrivate::setHasInRegionScrollableAreas(bool b) IntSize WebPagePrivate::viewportSize() const { - return mapFromTransformed(transformedViewportSize()); + return m_webkitThreadViewportAccessor->roundToDocumentFromPixelContents(Platform::IntRect(Platform::IntPoint::zero(), transformedViewportSize())).size(); } IntSize WebPagePrivate::actualVisibleSize() const { - return mapFromTransformed(transformedActualVisibleSize()); + return m_webkitThreadViewportAccessor->documentViewportSize(); } bool WebPagePrivate::hasVirtualViewport() const @@ -1480,16 +1468,7 @@ void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResi m_mainFrame->view()->adjustViewSize(); #if ENABLE(FULLSCREEN_API) - // 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_fullscreenVideoNode) { - Document* document = m_fullscreenVideoNode->document(); - ASSERT(document); - ASSERT(document->fullScreenRenderer()); - - int width = m_mainFrame->view()->visibleContentRect().size().width(); - document->fullScreenRenderer()->style()->setWidth(Length(width, Fixed)); - } + adjustFullScreenElementDimensionsIfNeeded(); #endif } @@ -1513,7 +1492,7 @@ FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const // The center of the visible contents rect in float. return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0, - visibleContentsRect.y() + visibleContentsRect.height() / 2.0); + visibleContentsRect.y() + visibleContentsRect.height() / 2.0); } IntRect WebPagePrivate::visibleContentsRect() const @@ -1523,7 +1502,7 @@ IntRect WebPagePrivate::visibleContentsRect() const IntSize WebPagePrivate::contentsSize() const { - if (!m_mainFrame->view()) + if (!m_mainFrame || !m_mainFrame->view()) return IntSize(); return m_backingStoreClient->contentsSize(); @@ -1531,7 +1510,7 @@ IntSize WebPagePrivate::contentsSize() const IntSize WebPagePrivate::absoluteVisibleOverflowSize() const { - if (!m_mainFrame->contentRenderer()) + if (!m_mainFrame || !m_mainFrame->contentRenderer()) return IntSize(); return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow()); @@ -1547,12 +1526,26 @@ void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize) m_contentsSizeChanged = true; #if DEBUG_WEBPAGE_LOAD - BBLOG(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %dx%d", contentsSize.width(), contentsSize.height()); + 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; @@ -1611,6 +1604,12 @@ void WebPagePrivate::layoutFinished() 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); } } } @@ -1618,7 +1617,7 @@ void WebPagePrivate::layoutFinished() void WebPagePrivate::zoomToInitialScaleOnLoad() { #if DEBUG_WEBPAGE_LOAD - BBLOG(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad"); + Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad"); #endif bool needsLayout = false; @@ -1636,9 +1635,9 @@ void WebPagePrivate::zoomToInitialScaleOnLoad() if (contentsSize().isEmpty()) { #if DEBUG_WEBPAGE_LOAD - BBLOG(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!"); + Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!"); #endif - requestLayoutIfNeeded(); + layoutIfNeeded(); notifyTransformedContentsSizeChanged(); return; } @@ -1664,7 +1663,7 @@ void WebPagePrivate::zoomToInitialScaleOnLoad() } // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout... - requestLayoutIfNeeded(); + layoutIfNeeded(); if (!performedZoom) { // We only notify if we didn't perform zoom, because zoom will notify on @@ -1696,9 +1695,15 @@ double WebPagePrivate::zoomToFitScale() const 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) + + if (m_initialScale > 0.0 && respectViewport()) return m_initialScale; if (m_webSettings->isZoomToFitOnLoad()) @@ -1754,10 +1759,11 @@ void WebPage::setMaximumScale(double maximumScale) double WebPagePrivate::maximumScale() const { - if (m_maximumScale >= zoomToFitScale() && m_maximumScale >= m_minimumScale) - return m_maximumScale; + double zoomToFitScale = this->zoomToFitScale(); + if (m_maximumScale >= m_minimumScale && respectViewport()) + return std::max(zoomToFitScale, m_maximumScale); - return hasVirtualViewport() ? std::max<double>(zoomToFitScale(), 4.0) : 4.0; + return hasVirtualViewport() ? std::max<double>(zoomToFitScale, 5.0) : 5.0; } double WebPage::maximumScale() const @@ -1772,6 +1778,7 @@ void WebPagePrivate::resetScales() 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. @@ -1805,150 +1812,7 @@ Platform::IntSize WebPage::viewportSize() const IntSize WebPagePrivate::transformedViewportSize() const { - return Platform::Graphics::Screen::primaryScreen()->size(); -} - -IntRect WebPagePrivate::transformedVisibleContentsRect() const -{ - // Usually this would be mapToTransformed(visibleContentsRect()), but - // that results in rounding errors because we already set the WebCore - // viewport size from our original transformedViewportSize(). - // Instead, we only transform the scroll position and take the - // viewport size as it is, which ensures that e.g. blitting operations - // always cover the whole widget/screen. - return IntRect(transformedScrollPosition(), transformedViewportSize()); -} - -IntSize WebPagePrivate::transformedContentsSize() const -{ - // mapToTransformed() functions use this method to crop their results, - // so we can't make use of them here. While we want rounding inside page - // boundaries to extend rectangles and round points, we need to crop the - // contents size to the floored values so that we don't try to display - // or report points that are not fully covered by the actual float-point - // contents rectangle. - const IntSize untransformedContentsSize = contentsSize(); - const FloatPoint transformedBottomRight = m_transformationMatrix->mapPoint( - FloatPoint(untransformedContentsSize.width(), untransformedContentsSize.height())); - return IntSize(floorf(transformedBottomRight.x()), floorf(transformedBottomRight.y())); -} - -IntPoint WebPagePrivate::mapFromContentsToViewport(const IntPoint& point) const -{ - return m_backingStoreClient->mapFromContentsToViewport(point); -} - -IntPoint WebPagePrivate::mapFromViewportToContents(const IntPoint& point) const -{ - return m_backingStoreClient->mapFromViewportToContents(point); -} - -IntRect WebPagePrivate::mapFromContentsToViewport(const IntRect& rect) const -{ - return m_backingStoreClient->mapFromContentsToViewport(rect); -} - -IntRect WebPagePrivate::mapFromViewportToContents(const IntRect& rect) const -{ - return m_backingStoreClient->mapFromViewportToContents(rect); -} - -IntPoint WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntPoint& point) const -{ - return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(point); -} - -IntPoint WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntPoint& point) const -{ - return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(point); -} - -IntRect WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntRect& rect) const -{ - return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(rect); -} - -IntRect WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntRect& rect) const -{ - return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(rect); -} - -// NOTE: PIXEL ROUNDING! -// Accurate back-and-forth rounding is not possible with information loss -// by integer points and sizes, so we always expand the resulting mapped -// float rectangles to the nearest integer. For points, we always use -// floor-rounding in mapToTransformed() so that we don't have to crop to -// the (floor'd) transformed contents size. -static inline IntPoint roundTransformedPoint(const FloatPoint &point) -{ - // Maps by rounding half towards zero. - return IntPoint(static_cast<int>(floorf(point.x())), static_cast<int>(floorf(point.y()))); -} - -static inline IntPoint roundUntransformedPoint(const FloatPoint &point) -{ - // Maps by rounding half away from zero. - return IntPoint(static_cast<int>(ceilf(point.x())), static_cast<int>(ceilf(point.y()))); -} - -IntPoint WebPagePrivate::mapToTransformed(const IntPoint& point) const -{ - return roundTransformedPoint(m_transformationMatrix->mapPoint(FloatPoint(point))); -} - -FloatPoint WebPagePrivate::mapToTransformedFloatPoint(const FloatPoint& point) const -{ - return m_transformationMatrix->mapPoint(point); -} - -IntPoint WebPagePrivate::mapFromTransformed(const IntPoint& point) const -{ - return roundUntransformedPoint(m_transformationMatrix->inverse().mapPoint(FloatPoint(point))); -} - -FloatPoint WebPagePrivate::mapFromTransformedFloatPoint(const FloatPoint& point) const -{ - return m_transformationMatrix->inverse().mapPoint(point); -} - -FloatRect WebPagePrivate::mapFromTransformedFloatRect(const FloatRect& rect) const -{ - return m_transformationMatrix->inverse().mapRect(rect); -} - -IntSize WebPagePrivate::mapToTransformed(const IntSize& size) const -{ - return mapToTransformed(IntRect(IntPoint::zero(), size)).size(); -} - -IntSize WebPagePrivate::mapFromTransformed(const IntSize& size) const -{ - return mapFromTransformed(IntRect(IntPoint::zero(), size)).size(); -} - -IntRect WebPagePrivate::mapToTransformed(const IntRect& rect) const -{ - return enclosingIntRect(m_transformationMatrix->mapRect(FloatRect(rect))); -} - -// Use this in conjunction with mapToTransformed(IntRect), in most cases. -void WebPagePrivate::clipToTransformedContentsRect(IntRect& rect) const -{ - rect.intersect(IntRect(IntPoint::zero(), transformedContentsSize())); -} - -IntRect WebPagePrivate::mapFromTransformed(const IntRect& rect) const -{ - return enclosingIntRect(m_transformationMatrix->inverse().mapRect(FloatRect(rect))); -} - -bool WebPagePrivate::transformedPointEqualsUntransformedPoint(const IntPoint& transformedPoint, const IntPoint& untransformedPoint) -{ - // Scaling down is always more accurate than scaling up. - if (m_transformationMatrix->a() > 1.0) - return transformedPoint == mapToTransformed(untransformedPoint); - - return mapFromTransformed(transformedPoint) == untransformedPoint; + return BlackBerry::Platform::Settings::instance()->applicationSize(); } void WebPagePrivate::notifyTransformChanged() @@ -1964,7 +1828,7 @@ void WebPagePrivate::notifyTransformedContentsSizeChanged() // We mark here as the last reported content size we sent to the client. m_previousContentsSize = contentsSize(); - const IntSize size = transformedContentsSize(); + const IntSize size = m_webkitThreadViewportAccessor->pixelContentsSize(); m_backingStore->d->contentsSizeChanged(size); m_client->contentsSizeChanged(); } @@ -1974,11 +1838,15 @@ 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->view()) + if (!m_mainFrame || !m_mainFrame->view()) return false; m_viewMode = mode; @@ -2104,7 +1972,7 @@ void WebPagePrivate::notifyPageOnLoad() (*it)->handleOnLoadEvent(); } -bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix) +bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView*, const char*) { return m_client->shouldPluginEnterFullScreen(); } @@ -2121,7 +1989,7 @@ void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* wi m_client->window()->setSensitivityFullscreenOverride(true); } -void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* windowUniquePrefix) +void WebPagePrivate::didPluginExitFullScreen(PluginView*, const char*) { m_fullScreenPluginView = 0; m_client->didPluginExitFullScreen(); @@ -2133,12 +2001,12 @@ void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* win m_client->window()->setSensitivityFullscreenOverride(false); } -void WebPagePrivate::onPluginStartBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix) +void WebPagePrivate::onPluginStartBackgroundPlay(PluginView*, const char*) { m_client->onPluginStartBackgroundPlay(); } -void WebPagePrivate::onPluginStopBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix) +void WebPagePrivate::onPluginStopBackgroundPlay(PluginView*, const char*) { m_client->onPluginStopBackgroundPlay(); } @@ -2183,6 +2051,7 @@ void WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSp 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) { @@ -2200,12 +2069,12 @@ void WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSp credentialManager().autofillAuthenticationChallenge(protectionSpace, username, password); #endif - bool isConfirmed = m_client->authenticationChallenge(protectionSpace.realm().characters(), protectionSpace.realm().length(), username, password); + 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(url, protectionSpace, credential)); + credentialManager().saveCredentialIfConfirmed(this, CredentialTransformData(protectionSpace, credential)); #else Credential credential(username, password, CredentialPersistenceNone); #endif @@ -2256,19 +2125,22 @@ Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy // 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, TouchScreen); - if (m_currentContextNode->dispatchMouseEvent(mouseEvent, eventNames().contextmenuEvent, 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; } - requestLayoutIfNeeded(); + layoutIfNeeded(); bool nodeAllowSelectionOverride = false; - if (Node* linkNode = node->enclosingLinkEventParentOrSelf()) { + 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 (Attribute* attribute = static_cast<Element*>(linkNode)->getAttributeItem(HTMLNames::hrefAttr)) + if (const Attribute* attribute = toElement(linkNode)->getAttributeItem(HTMLNames::hrefAttr)) href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value())); } @@ -2290,21 +2162,36 @@ Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy HTMLImageElement* imageElement = 0; HTMLMediaElement* mediaElement = 0; - if (node->hasTagName(HTMLNames::imgTag)) - imageElement = static_cast<HTMLImageElement*>(node.get()); - else if (node->hasTagName(HTMLNames::areaTag)) - imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement(); + if (isHTMLImageElement(node)) + imageElement = toHTMLImageElement(node.get()); + else if (isHTMLAreaElement(node)) + imageElement = toHTMLAreaElement(node.get())->imageElement(); if (static_cast<HTMLElement*>(node.get())->isMediaElement()) - mediaElement = static_cast<HTMLMediaElement*>(node.get()); + 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 (CachedResource* cachedResource = imageElement->cachedImage()) { - if (cachedResource->isLoaded() && cachedResource->data()) { + 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(); @@ -2332,7 +2219,7 @@ Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy bool canStartSelection = node->canStartSelection(); if (node->isElementNode()) { - Element* element = static_cast<Element*>(node->shadowAncestorNode()); + Element* element = toElement(node->deprecatedShadowAncestorNode()); if (DOMSupport::isTextBasedContentEditableElement(element)) { if (!canStartSelection) { @@ -2343,7 +2230,7 @@ Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy canStartSelection = nodeUnderFinger->canStartSelection(); } context.setFlag(Platform::WebContext::IsInput); - if (element->hasTagName(HTMLNames::inputTag)) + if (isHTMLInputElement(element)) context.setFlag(Platform::WebContext::IsSingleLine); if (DOMSupport::isPasswordElement(element)) context.setFlag(Platform::WebContext::IsPassword); @@ -2367,7 +2254,7 @@ Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy // Walk up the node tree looking for our custom webworks context attribute. while (node) { if (node->isElementNode()) { - Element* element = static_cast<Element*>(node->shadowAncestorNode()); + Element* element = toElement(node->deprecatedShadowAncestorNode()); String webWorksContext(DOMSupport::webWorksContext(element)); if (!webWorksContext.stripWhiteSpace().isEmpty()) { context.setFlag(Platform::WebContext::IsWebWorksContext); @@ -2396,7 +2283,20 @@ void WebPagePrivate::updateCursor() else if (m_lastMouseEvent.button() == RightButton) buttonMask = Platform::MouseEvent::ScreenRightMouseButton; - BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask, mapToTransformed(m_lastMouseEvent.position()), mapToTransformed(m_lastMouseEvent.globalPosition()), 0, 0); + 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); } @@ -2414,7 +2314,10 @@ IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const // 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 (m_loadState == None) + // 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) { @@ -2435,7 +2338,7 @@ IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const // 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) + if (m_pendingOrientation != -1 && !m_nestedLayoutFinishedCount && !m_overflowExceedsContentsSize) width = 0; if (snapToIncrement) { @@ -2484,7 +2387,7 @@ void WebPagePrivate::clearDocumentData(const Document* documentGoingAway) if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway) m_touchEventHandler->resetLastFatFingersResult(); - // NOTE: m_fullscreenVideoNode, m_fullScreenPluginView and m_pluginViews + // NOTE: m_fullscreenNode, m_fullScreenPluginView and m_pluginViews // are cleared in other methods already. } @@ -2534,7 +2437,7 @@ static inline Frame* frameForNode(Node* node) if (renderer->isWidget()) { Widget* widget = toRenderWidget(renderer)->widget(); if (widget && widget->isFrameView()) { - if (Frame* frame = static_cast<FrameView*>(widget)->frame()) + if (Frame* frame = toFrameView(widget)->frame()) return frame; } } @@ -2573,7 +2476,7 @@ IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noC return IntRect(IntPoint::zero(), view->contentsSize()); } - IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect(false))); + 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)); @@ -2607,10 +2510,25 @@ void WebPagePrivate::assignFocus(Platform::FocusDirection direction) void WebPage::assignFocus(Platform::FocusDirection direction) { if (d->m_page->defersLoading()) - return; + 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(); @@ -2622,10 +2540,12 @@ Platform::IntRect WebPagePrivate::focusNodeRect() if (!doc || !view || view->needsLayout()) return Platform::IntRect(); - IntRect focusRect = rectForNode(doc->focusedNode()); - focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode()); - focusRect = mapToTransformed(focusRect); - clipToTransformedContentsRect(focusRect); + 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; } @@ -2638,7 +2558,7 @@ PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy) // 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()->focusedNode(); + node = m_page->focusController()->focusedOrMainFrame()->document()->focusedElement(); if (node) { IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize()); if (!visibleRect.intersects(getNodeWindowRect(node.get()))) @@ -2653,6 +2573,8 @@ PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy) 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) @@ -2662,9 +2584,9 @@ PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy) if (isTouching) contentPos = lastFatFingersResult.adjustedPosition(); else - contentPos = mapFromViewportToContents(m_lastMouseEvent.position()); + contentPos = m_webkitThreadViewportAccessor->documentContentsFromViewport(m_lastMouseEvent.position()); - HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos, false /*allowShadowContent*/); + HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos); return result.innerNode(); } @@ -2735,7 +2657,7 @@ Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& documentPoint) if (!m_mainFrame) return 0; - HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(documentPoint, false); + HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(documentPoint); Node* node = result.innerNonSharedNode(); @@ -2755,7 +2677,7 @@ Node* WebPagePrivate::adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(Node* { Node* initialNode = node; RenderObject* renderer = node->renderer(); - bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale(); + bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maximumScale(); IntSize actualVisibleSize = this->actualVisibleSize(); while (!renderer || !acceptableNodeSize) { @@ -2768,7 +2690,7 @@ Node* WebPagePrivate::adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(Node* return initialNode; renderer = node->renderer(); - acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale(); + acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maximumScale(); } return node; @@ -2813,15 +2735,15 @@ IntRect WebPagePrivate::rectForNode(Node* node) int xOffset = 0; int yOffset = 0; while (!renderBlock->isRoot()) { - xOffset += renderBlock->x(); - yOffset += renderBlock->y(); + 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 = renderer->absoluteClippedOverflowRect(); + blockRect = IntRect(renderer->absoluteClippedOverflowRect()); if (renderer->isText()) { RenderBlock* rb = renderer->containingBlock(); @@ -2830,7 +2752,7 @@ IntRect WebPagePrivate::rectForNode(Node* node) int blockWidth = 0; int lineCount = rb->lineCount(); for (int i = 0; i < lineCount; i++) - blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false)); + blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false).toInt()); blockRect.setWidth(blockWidth); blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false)); @@ -2889,7 +2811,7 @@ IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, cons } while (iFrameRect.isEmpty() && ownerNode); } else break; - } while (tnode = tnode->parentNode()); + } while ((tnode = tnode->parentNode())); return adjustedRect; } @@ -2910,8 +2832,8 @@ IntRect WebPagePrivate::blockZoomRectForNode(Node* node) double blockToPageRatio = static_cast<double>(pageArea - originalArea) / pageArea; double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio; - if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) { - while (tnode = tnode->parentNode()) { + if (!isHTMLImageElement(tnode) && !isHTMLInputElement(tnode) && !isHTMLTextAreaElement(tnode)) { + while ((tnode = tnode->parentNode())) { ASSERT(tnode); IntRect tRect = rectForNode(tnode); int tempBlockArea = tRect.width() * tRect.height(); @@ -2934,21 +2856,25 @@ IntRect WebPagePrivate::blockZoomRectForNode(Node* node) } } + const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor; + blockRect = adjustRectOffsetForFrameOffset(blockRect, node); - blockRect = mapToTransformed(blockRect); - clipToTransformedContentsRect(blockRect); + 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::zoomBlock() +void WebPagePrivate::zoomAnimationFinished(double finalAnimationScale, const WebCore::FloatPoint& finalAnimationDocumentScrollPosition, bool shouldConstrainScrollingToContentEdge) { if (!m_mainFrame) return; - IntPoint anchor(roundUntransformedPoint(m_finalBlockPoint)); + const Platform::ViewportAccessor* viewportAccessor = m_webkitThreadViewportAccessor; + + IntPoint anchor(viewportAccessor->roundedDocumentContents(finalAnimationDocumentScrollPosition)); bool willUseTextReflow = false; #if ENABLE(VIEWPORT_REFLOW) @@ -2958,19 +2884,31 @@ void WebPagePrivate::zoomBlock() #endif TransformationMatrix zoom; - zoom.scale(m_blockZoomFinalScale); + 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) - requestLayoutIfNeeded(); + 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(roundTransformedPoint(m_finalBlockPointReflowOffset).x(), roundTransformedPoint(m_finalBlockPointReflowOffset).y()); + reflowedRect.move(roundedReflowOffset.x(), roundedReflowOffset.y()); + RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer(); IntPoint topLeftPoint(reflowedRect.location()); if (renderer && renderer->isText()) { @@ -2989,7 +2927,7 @@ void WebPagePrivate::zoomBlock() case WEBKIT_RIGHT: textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()); break; - case TAAUTO: + case TASTART: case JUSTIFY: default: if (renderer->style()->isLeftToRightDirection()) @@ -3007,7 +2945,7 @@ void WebPagePrivate::zoomBlock() } else if (willUseTextReflow) { IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get()); finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get()); - setScrollPosition(IntPoint(0, finalRect.y() + m_finalBlockPointReflowOffset.y())); + setScrollPosition(IntPoint(0, finalRect.y() + m_finalAnimationDocumentScrollPositionReflowOffset.y())); resetBlockZoom(); } #endif @@ -3019,14 +2957,18 @@ void WebPagePrivate::zoomBlock() 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::blockZoomAnimationFinished() +void WebPage::zoomAnimationFinished(double finalScale, const Platform::FloatPoint& finalDocumentScrollPosition, bool shouldConstrainScrollingToContentEdge) { - d->zoomBlock(); + d->zoomAnimationFinished(finalScale, finalDocumentScrollPosition, shouldConstrainScrollingToContentEdge); } void WebPage::resetBlockZoom() @@ -3064,7 +3006,6 @@ void WebPage::destroy() // Close the backforward list and release the cached pages. d->m_page->backForward()->close(); - pageCache()->releaseAutoreleasedPagesNow(); FrameLoader* loader = d->m_mainFrame->loader(); @@ -3094,7 +3035,11 @@ bool WebPage::canGoBackOrForward(int delta) const 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; @@ -3130,6 +3075,11 @@ WebCookieJar* WebPage::cookieJar() const return d->m_cookieJar; } +bool WebPage::isLoading() const +{ + return d->isLoading(); +} + bool WebPage::isVisible() const { return d->m_visible; @@ -3177,9 +3127,12 @@ void WebPagePrivate::setVisible(bool visible) m_mainFrame->animation()->suspendAnimations(); if (!m_page->scriptedAnimationsSuspended()) m_page->suspendScriptedAnimations(); + + closePagePopup(); } m_visible = visible; + m_backingStore->d->updateSuspendScreenUpdateState(); } #if ENABLE(PAGE_VISIBILITY_API) @@ -3210,16 +3163,26 @@ void WebPage::setVisible(bool visible) #if USE(ACCELERATED_COMPOSITING) // Root layer commit is not necessary for invisible tabs. // And release layer resources can reduce memory consumption. - d->suspendRootLayerCommit(); + d->updateRootLayerCommitEnabled(); #endif return; } #if USE(ACCELERATED_COMPOSITING) - d->resumeRootLayerCommit(); + 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); @@ -3247,6 +3210,11 @@ void WebPagePrivate::selectionChanged(Frame* frame) 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. @@ -3272,7 +3240,7 @@ void WebPagePrivate::updateDelegatedOverlays(bool dispatched) } } -void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle style) +void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle) { } @@ -3448,9 +3416,10 @@ void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments // If the caller is trying to reset to default arguments, use the user supplied ones instead. static const ViewportArguments defaultViewportArguments; - if (arguments == defaultViewportArguments) + if (arguments == defaultViewportArguments) { m_viewportArguments = m_userViewportArguments; - else + 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. @@ -3478,19 +3447,6 @@ void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments zoomToInitialScaleOnLoad(); } -void WebPagePrivate::onInputLocaleChanged(bool isRTL) -{ - if (isRTL != m_webSettings->isWritingDirectionRTL()) { - m_webSettings->setWritingDirectionRTL(isRTL); - m_inputHandler->handleInputLocaleChanged(isRTL); - } -} - -void WebPage::onInputLocaleChanged(bool isRTL) -{ - d->onInputLocaleChanged(isRTL); -} - void WebPagePrivate::suspendBackingStore() { #if USE(ACCELERATED_COMPOSITING) @@ -3509,12 +3465,7 @@ void WebPagePrivate::resumeBackingStore() { ASSERT(m_webPage->isVisible()); - bool directRendering = m_backingStore->d->shouldDirectRenderingToWindow(); - if (!m_backingStore->d->isActive() - || shouldResetTilesWhenShown() - || directRendering) { - // We need to reset all tiles so that we do not show any tiles whose content may - // have been replaced by another WebPage instance (i.e. another tab). + if (!m_backingStore->d->isActive() || shouldResetTilesWhenShown()) { BackingStorePrivate::setCurrentBackingStoreOwner(m_webPage); // If we're OpenGL compositing, switching to accel comp drawing of the root layer @@ -3523,27 +3474,24 @@ void WebPagePrivate::resumeBackingStore() setCompositorDrawsRootLayer(!m_backingStore->d->isActive()); m_backingStore->d->orientationChanged(); // Updates tile geometry and creates visible tile buffer. - m_backingStore->d->resetTiles(true /* resetBackground */); + m_backingStore->d->resetTiles(); m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */); - // This value may have changed, so we need to update it. - directRendering = m_backingStore->d->shouldDirectRenderingToWindow(); - if (m_backingStore->d->renderVisibleContents()) { - if (!m_backingStore->d->isSuspended() && !directRendering) - m_backingStore->d->blitVisibleContents(); - m_client->notifyPixelContentRendered(m_backingStore->d->visibleContentsRect()); - } +#if USE(ACCELERATED_COMPOSITING) + setNeedsOneShotDrawingSynchronization(); +#endif + + m_backingStore->d->renderAndBlitVisibleContentsImmediately(); } else { if (m_backingStore->d->isOpenGLCompositing()) - setCompositorDrawsRootLayer(false); + 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(); + setNeedsOneShotDrawingSynchronization(); #endif + } setShouldResetTilesWhenShown(false); } @@ -3572,18 +3520,21 @@ 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 */); } -void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize, bool ensureFocusElementVisible) +bool WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize, const IntSize& defaultLayoutSize, bool ensureFocusElementVisible) { if (m_pendingOrientation == -1 && transformedActualVisibleSize == this->transformedActualVisibleSize()) - return; + 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. - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->suspendBackingStoreUpdates(); + 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 @@ -3593,35 +3544,21 @@ void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize bool hasPendingOrientation = m_pendingOrientation != -1; - // The window buffers might have been recreated, cleared, moved, etc., so: - m_backingStore->d->windowFrontBufferState()->clearBlittedRegion(); - m_backingStore->d->windowBackBufferState()->clearBlittedRegion(); - IntSize viewportSizeBefore = actualVisibleSize(); FloatPoint centerOfVisibleContentsRect = this->centerOfVisibleContentsRect(); bool newVisibleRectContainsOldVisibleRect = (m_actualVisibleHeight <= transformedActualVisibleSize.height()) - && (m_actualVisibleWidth <= transformedActualVisibleSize.width()); + && (m_actualVisibleWidth <= transformedActualVisibleSize.width()); bool atInitialScale = m_webPage->isAtInitialZoom(); bool atTop = !scrollPosition().y(); bool atLeft = !scrollPosition().x(); - // We need to reorient the visibleTileRect because the following code - // could cause BackingStore::transformChanged to be called, where it - // is used. - // It is only dependent on the transformedViewportSize which has been - // updated by now. - m_backingStore->d->createVisibleTileBuffer(); - - setDefaultLayoutSize(transformedActualVisibleSize); + setDefaultLayoutSize(defaultLayoutSize); // Recompute our virtual viewport. bool needsLayout = false; - static ViewportArguments defaultViewportArguments; - if (m_viewportArguments != defaultViewportArguments) { - // We may need to infer the width and height for the viewport with respect to the rotation. - Platform::IntSize newVirtualViewport = recomputeVirtualViewportFromViewportArguments(); - ASSERT(!newVirtualViewport.isEmpty()); + Platform::IntSize newVirtualViewport = recomputeVirtualViewportFromViewportArguments(); + if (!newVirtualViewport.isEmpty()) { m_webPage->setVirtualViewportSize(newVirtualViewport); m_mainFrame->view()->setUseFixedLayout(useFixedLayout()); m_mainFrame->view()->setFixedLayoutSize(fixedLayoutSize()); @@ -3636,7 +3573,7 @@ void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize IntSize viewportSizeAfter = actualVisibleSize(); IntSize offset; - if (hasPendingOrientation) { + if (hasPendingOrientation && !m_fullscreenNode) { offset = IntSize(roundf((viewportSizeBefore.width() - viewportSizeAfter.width()) / 2.0), roundf((viewportSizeBefore.height() - viewportSizeAfter.height()) / 2.0)); } @@ -3699,16 +3636,14 @@ void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize // Need to resume so that the backingstore will start recording the invalidated // rects from below. - // FIXME: Do we really need to suspend/resume both backingstore and screen here? m_backingStore->d->resumeBackingStoreUpdates(); - m_backingStore->d->resumeScreenUpdates(BackingStore::None); // We might need to layout here to get a correct contentsSize so that zoomToFit // is calculated correctly. bool stillNeedsLayout = needsLayout; while (stillNeedsLayout) { setNeedsLayout(); - requestLayoutIfNeeded(); + layoutIfNeeded(); stillNeedsLayout = false; // Emulate the zoomToFitWidthOnLoad algorithm if we're rotating. @@ -3736,7 +3671,7 @@ void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize IntRect actualVisibleRect = enclosingIntRect(rotationMatrix.inverse().mapRect(FloatRect(viewportRect))); m_mainFrame->view()->setFixedReportedSize(actualVisibleRect.size()); m_mainFrame->view()->repaintFixedElementsAfterScrolling(); - requestLayoutIfNeeded(); + layoutIfNeeded(); m_mainFrame->view()->updateFixedElementsAfterScrolling(); } @@ -3759,24 +3694,12 @@ void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize // Try and zoom here with clamping on. // FIXME: Determine why the above comment says "clamping on", yet we // don't set enforceScaleClamping to true. - // FIXME: Determine why ensureContentVisible() is only called for !success - // in the direct-rendering case, but in all cases otherwise. Chances are - // one of these is incorrect and we can unify two branches into one. - if (m_backingStore->d->shouldDirectRenderingToWindow()) { - bool success = zoomAboutPoint(scale, anchor, false /* enforceScaleClamping */, true /* forceRendering */); - if (!success && ensureFocusElementVisible) - ensureContentVisible(!newVisibleRectContainsOldVisibleRect); - - } else if (zoomAboutPoint(scale, anchor, false /*enforceScaleClamping*/, true /*forceRendering*/)) { + if (zoomAboutPoint(scale, anchor, false /*enforceScaleClamping*/, true /*forceRendering*/)) { if (ensureFocusElementVisible) ensureContentVisible(!newVisibleRectContainsOldVisibleRect); - } else { - - // Suspend all screen updates to the backingstore. - // FIXME: Do we really need to suspend/resume both backingstore and screen here? + // Suspend all updates to the backingstore. m_backingStore->d->suspendBackingStoreUpdates(); - m_backingStore->d->suspendScreenUpdates(); // If the zoom failed, then we should still preserve the special case of scroll position. IntPoint scrollPosition = this->scrollPosition(); @@ -3799,41 +3722,101 @@ void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize ensureContentVisible(!newVisibleRectContainsOldVisibleRect); if (needsLayout) { - m_backingStore->d->resetTiles(true); + 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. - // FIXME: Do we really need to suspend/resume both backingstore and screen here? m_backingStore->d->resumeBackingStoreUpdates(); - m_backingStore->d->resumeScreenUpdates(needsLayout ? BackingStore::RenderAndBlit : BackingStore::Blit); } + +#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, bool ensureFocusElementVisible) +void WebPage::setViewportSize(const Platform::IntSize& viewportSize, const Platform::IntSize& defaultLayoutSize, bool ensureFocusElementVisible) { - d->setViewportSize(viewportSize, 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::Graphics::Screen::primaryScreen()->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); - bool needsLayout = d->setViewMode(d->viewMode()); + + // 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->requestLayoutIfNeeded(); + d->layoutIfNeeded(); } } @@ -3869,18 +3852,19 @@ bool WebPage::mouseEvent(const Platform::MouseEvent& mouseEvent, bool* wheelDelt buttonType = MiddleButton; // Create our event. - PlatformMouseEvent platformMouseEvent(d->mapFromTransformed(mouseEvent.position()), mouseEvent.screenPosition(), - toWebCoreMouseEventType(mouseEvent.type()), clickCount, buttonType, PointingDevice); + 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(d->mapFromTransformed(mouseEvent.position()), mouseEvent.screenPosition(), - 0, -mouseEvent.wheelDelta(), - 0, -mouseEvent.wheelTicks(), - ScrollByPixelWheelEvent, - false /* shiftKey */, false /* ctrlKey */, - false /* altKey */, false /* metaKey */); + 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) @@ -3938,10 +3922,14 @@ bool WebPagePrivate::handleMouseEvent(PlatformMouseEvent& mouseEvent) // 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) { - HitTestResult result = eventHandler->hitTestResultAtPoint(mapFromViewportToContents(mouseEvent.position()), false /*allowShadowContent*/); + IntPoint documentContentsPoint = m_webkitThreadViewportAccessor->documentContentsFromViewport(mouseEvent.position()); + HitTestResult result = eventHandler->hitTestResultAtPoint(documentContentsPoint); node = result.innerNode(); } @@ -3952,24 +3940,19 @@ bool WebPagePrivate::handleMouseEvent(PlatformMouseEvent& mouseEvent) // 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. - // - // FIXME: We explicitly do not forward this event to WebCore so as to preserve symmetry with - // the MouseEventReleased handling (below). This has the side-effect that mousedown events - // are not fired for human generated mouse press events. See RIM Bug #1579. // 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(node->isElementNode()); + ASSERT_WITH_SECURITY_IMPLICATION(node->isElementNode()); if (node->isElementNode()) { - Element* element = static_cast<Element*>(node); + Element* element = toElement(node); element->focus(); } } else eventHandler->handleMousePressEvent(mouseEvent); } else if (mouseEvent.type() == WebCore::PlatformEvent::MouseReleased) { - // FIXME: For <select> and <options> elements, we explicitly do not forward this event to WebCore so - // as to preserve symmetry with the MouseEventPressed handling (above). This has the side-effect that - // mouseup events are not fired on such elements for human generated mouse release events. See RIM Bug #1579. + // 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); } @@ -3985,7 +3968,7 @@ bool WebPagePrivate::handleWheelEvent(PlatformWheelEvent& wheelEvent) bool WebPage::touchEvent(const Platform::TouchEvent& event) { #if DEBUG_TOUCH_EVENTS - BBLOG(LogLevelCritical, "%s", event.toString().c_str()); + Platform::logAlways(Platform::LogLevelCritical, "%s", event.toString().c_str()); #endif #if ENABLE(TOUCH_EVENTS) @@ -3995,27 +3978,35 @@ bool WebPage::touchEvent(const Platform::TouchEvent& event) 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; - for (unsigned i = 0; i < event.m_points.size(); i++) { - tEvent.m_points[i].m_pos = d->mapFromTransformed(tEvent.m_points[i].m_pos); - tEvent.m_points[i].m_screenPos = tEvent.m_points[i].m_screenPos; - } - 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) + 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) + if (event.m_type != Platform::TouchEvent::TouchInjected) handled = d->m_mainFrame->eventHandler()->handleTouchEvent(PlatformTouchEvent(&tEvent)); if (d->m_preventDefaultOnTouchStart) { @@ -4029,10 +4020,6 @@ bool WebPage::touchEvent(const Platform::TouchEvent& event) d->m_preventDefaultOnTouchStart = true; return true; } - - if (event.isTouchHold()) - d->m_touchEventHandler->doFatFingers(tEvent.m_points[0]); - #endif return false; @@ -4057,7 +4044,7 @@ void WebPage::setDocumentScrollOriginPoint(const Platform::IntPoint& documentScr d->setScrollOriginPoint(documentScrollOrigin); } -void WebPage::touchPointAsMouseEvent(const Platform::TouchPoint& point) +void WebPage::touchPointAsMouseEvent(const Platform::TouchPoint& point, unsigned modifiers) { if (d->m_page->defersLoading()) return; @@ -4067,11 +4054,7 @@ void WebPage::touchPointAsMouseEvent(const Platform::TouchPoint& point) d->m_lastUserEventTimestamp = currentTime(); - Platform::TouchPoint tPoint = point; - tPoint.m_pos = d->mapFromTransformed(tPoint.m_pos); - tPoint.m_screenPos = tPoint.m_screenPos; - - d->m_touchEventHandler->handleTouchPoint(tPoint); + d->m_touchEventHandler->handleTouchPoint(point, modifiers); } void WebPage::playSoundIfAnchorIsTarget() const @@ -4101,13 +4084,13 @@ bool WebPagePrivate::dispatchTouchEventToFullScreenPlugin(PluginView* plugin, co 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].m_id; - npTouchEvent.points[i].clientX = event.m_points[i].m_screenPos.x(); - npTouchEvent.points[i].clientY = event.m_points[i].m_screenPos.y(); - npTouchEvent.points[i].screenX = event.m_points[i].m_screenPos.x(); - npTouchEvent.points[i].screenY = event.m_points[i].m_screenPos.y(); - npTouchEvent.points[i].pageX = event.m_points[i].m_pos.x(); - npTouchEvent.points[i].pageY = event.m_points[i].m_pos.y(); + 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(); } } @@ -4129,7 +4112,7 @@ bool WebPagePrivate::dispatchTouchPointAsMouseEventToFullScreenPlugin(PluginView NPEvent npEvent; NPMouseEvent mouse; - switch (point.m_state) { + switch (point.state()) { case Platform::TouchPoint::TouchPressed: mouse.type = MOUSE_BUTTON_DOWN; break; @@ -4143,8 +4126,8 @@ bool WebPagePrivate::dispatchTouchPointAsMouseEventToFullScreenPlugin(PluginView return true; } - mouse.x = point.m_screenPos.x(); - mouse.y = point.m_screenPos.y(); + mouse.x = point.screenPosition().x(); + mouse.y = point.screenPosition().y(); mouse.button = mouse.type != MOUSE_BUTTON_UP; mouse.flags = 0; npEvent.type = NP_MouseEvent; @@ -4173,19 +4156,19 @@ void WebPagePrivate::clearFocusNode() return; ASSERT(frame->document()); - if (frame->document()->focusedNode()) - frame->page()->focusController()->setFocusedNode(0, frame); + if (frame->document()->focusedElement()) + frame->page()->focusController()->setFocusedElement(0, frame); } BlackBerry::Platform::String WebPage::textEncoding() { Frame* frame = d->focusedOrMainFrame(); if (!frame) - return ""; + return BlackBerry::Platform::String::emptyString(); Document* document = frame->document(); if (!document) - return ""; + return BlackBerry::Platform::String::emptyString(); return document->loader()->writer()->encoding(); } @@ -4206,55 +4189,7 @@ BlackBerry::Platform::String WebPage::forcedTextEncoding() void WebPage::setForcedTextEncoding(const BlackBerry::Platform::String& encoding) { if (!encoding.empty() && d->focusedOrMainFrame() && d->focusedOrMainFrame()->loader() && d->focusedOrMainFrame()->loader()) - return d->focusedOrMainFrame()->loader()->reloadWithOverrideEncoding(encoding); -} - -static void handleScrolling(unsigned short character, WebPagePrivate* scroller) -{ - const int scrollFactor = 20; - int dx = 0, dy = 0; - switch (character) { - case KEYCODE_LEFT: - dx = -scrollFactor; - break; - case KEYCODE_RIGHT: - dx = scrollFactor; - break; - case KEYCODE_UP: - dy = -scrollFactor; - break; - case KEYCODE_DOWN: - dy = scrollFactor; - break; - case KEYCODE_PG_UP: - ASSERT(scroller); - dy = scrollFactor - scroller->actualVisibleSize().height(); - break; - case KEYCODE_PG_DOWN: - ASSERT(scroller); - dy = scroller->actualVisibleSize().height() - scrollFactor; - break; - } - - if (dx || dy) { - // Don't use the scrollBy function because it triggers the scroll as originating from BlackBerry - // but then it expects a separate invalidate which isn't sent in this case. - ASSERT(scroller && scroller->m_mainFrame && scroller->m_mainFrame->view()); - IntPoint pos(scroller->scrollPosition() + IntSize(dx, dy)); - - // Prevent over scrolling for arrows and Page up/down. - if (pos.x() < 0) - pos.setX(0); - if (pos.y() < 0) - pos.setY(0); - if (pos.x() + scroller->actualVisibleSize().width() > scroller->contentsSize().width()) - pos.setX(scroller->contentsSize().width() - scroller->actualVisibleSize().width()); - if (pos.y() + scroller->actualVisibleSize().height() > scroller->contentsSize().height()) - pos.setY(scroller->contentsSize().height() - scroller->actualVisibleSize().height()); - - scroller->m_mainFrame->view()->setScrollPosition(pos); - scroller->m_client->scrollChanged(); - } + d->focusedOrMainFrame()->loader()->reloadWithOverrideEncoding(encoding); } bool WebPage::keyEvent(const Platform::KeyboardEvent& keyboardEvent) @@ -4267,18 +4202,10 @@ bool WebPage::keyEvent(const Platform::KeyboardEvent& keyboardEvent) ASSERT(d->m_page->focusController()); - bool handled = d->m_inputHandler->handleKeyboardInput(keyboardEvent); - - if (!handled && keyboardEvent.type() == Platform::KeyboardEvent::KeyDown && !d->m_inputHandler->isInputMode()) { - IntPoint previousPos = d->scrollPosition(); - handleScrolling(keyboardEvent.character(), d); - handled = previousPos != d->scrollPosition(); - } - - return handled; + return d->m_inputHandler->handleKeyboardInput(keyboardEvent); } -bool WebPage::deleteTextRelativeToCursor(unsigned int leftOffset, unsigned int rightOffset) +bool WebPage::deleteTextRelativeToCursor(unsigned leftOffset, unsigned rightOffset) { if (d->m_page->defersLoading()) return false; @@ -4333,11 +4260,11 @@ int32_t WebPage::commitText(spannable_string_t* spannableString, int32_t relativ void WebPage::setSpellCheckingEnabled(bool enabled) { static_cast<EditorClientBlackBerry*>(d->m_page->editorClient())->enableSpellChecking(enabled); -} -void WebPage::spellCheckingRequestCancelled(int32_t transactionId) -{ - d->m_inputHandler->spellCheckingRequestCancelled(transactionId); + d->m_inputHandler->setSystemSpellCheckStatus(enabled); + + if (!enabled) + d->m_inputHandler->stopPendingSpellCheckRequests(); } void WebPage::spellCheckingRequestProcessed(int32_t transactionId, spannable_string_t* spannableString) @@ -4433,6 +4360,11 @@ void WebPage::selectAll() 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()) @@ -4450,12 +4382,41 @@ void WebPage::setDocumentCaretPosition(const Platform::IntPoint& documentCaretPo d->m_selectionHandler->setCaretPosition(documentCaretPosition); } -void WebPage::selectAtDocumentPoint(const Platform::IntPoint& documentPoint) +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); +} - d->m_selectionHandler->selectAtPoint(documentPoint); +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 @@ -4524,10 +4485,13 @@ bool WebPage::blockZoom(const Platform::IntPoint& documentTargetPoint) const double margin = endOfBlockZoomMode ? 0 : blockZoomMargin * 2 * oldScale; bool isFirstZoom = false; + const Platform::ViewportAccessor* viewportAccessor = webkitThreadViewportAccessor(); + if (endOfBlockZoomMode) { // End of block zoom mode - IntRect rect = d->blockZoomRectForNode(node); - blockRect = IntRect(0, rect.y(), d->transformedContentsSize().width(), d->transformedContentsSize().height() - rect.y()); + 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 @@ -4536,8 +4500,8 @@ bool WebPage::blockZoom(const Platform::IntPoint& documentTargetPoint) // 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 (!node->hasTagName(HTMLNames::imgTag)) { - IntRect tRect = d->mapFromTransformed(blockRect); + 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; @@ -4580,16 +4544,16 @@ bool WebPage::blockZoom(const Platform::IntPoint& documentTargetPoint) #endif // Align the zoomed block in the screen. - double newBlockHeight = d->mapFromTransformed(blockRect).height(); - double newBlockWidth = d->mapFromTransformed(blockRect).width(); - double scaledViewportWidth = static_cast<double>(d->actualVisibleSize().width()) * oldScale / newScale; - double scaledViewportHeight = static_cast<double>(d->actualVisibleSize().height()) * oldScale / newScale; - double dx = std::max(0.0, (scaledViewportWidth - newBlockWidth) / 2.0); - double dy = std::max(0.0, (scaledViewportHeight - newBlockHeight) / 2.0); - - RenderObject* renderer = d->m_currentBlockZoomAdjustedNode->renderer(); + 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; - FloatPoint topLeftPoint(d->mapFromTransformed(blockRect).location()); + if (renderer && renderer->isText()) { ETextAlign textAlign = renderer->style()->textAlign(); switch (textAlign) { @@ -4605,7 +4569,7 @@ bool WebPage::blockZoom(const Platform::IntPoint& documentTargetPoint) case WEBKIT_RIGHT: anchor = FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y()); break; - case TAAUTO: + case TASTART: case JUSTIFY: default: if (renderer->style()->isLeftToRightDirection()) @@ -4617,19 +4581,21 @@ bool WebPage::blockZoom(const Platform::IntPoint& documentTargetPoint) } else anchor = renderer->style()->isLeftToRightDirection() ? topLeftPoint : FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y()); - if (newBlockHeight <= scaledViewportHeight) { + WebCore::FloatPoint finalAnimationDocumentScrollPosition; + + if (newBlockRect.height() <= scaledViewportHeight) { // The block fits in the viewport so center it. - d->m_finalBlockPoint = FloatPoint(anchor.x() - dx, anchor.y() - dy); + 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. - d->m_finalBlockPoint = FloatPoint(anchor.x() - dx, anchor.y() - 3); + 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) { - d->m_finalBlockPoint = FloatPoint(anchor.x() - dx, anchor.y() - 3); - d->m_finalBlockPointReflowOffset = FloatPoint(-dx, -3); + finalAnimationDocumentScrollPosition = FloatPoint(anchor.x() - dx, anchor.y() - 3); + d->m_finalAnimationDocumentScrollPositionReflowOffset = FloatPoint(-dx, -3); } #endif @@ -4637,33 +4603,35 @@ bool WebPage::blockZoom(const Platform::IntPoint& documentTargetPoint) // 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_finalBlockPointReflowOffset.move(0, (documentTargetPoint.y() - scaledViewportHeight / 2) - d->m_finalBlockPoint.y()); - d->m_finalBlockPoint = FloatPoint(d->m_finalBlockPoint.x(), documentTargetPoint.y() - scaledViewportHeight / 2); + 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 (d->m_finalBlockPoint.x() < 0) { - d->m_finalBlockPoint.setX(0); - d->m_finalBlockPointReflowOffset.setX(0); - } else if (d->m_finalBlockPoint.x() + scaledViewportWidth > d->contentsSize().width()) { - d->m_finalBlockPoint.setX(d->contentsSize().width() - scaledViewportWidth); - d->m_finalBlockPointReflowOffset.setX(0); + 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 (d->m_finalBlockPoint.y() < 0) { - d->m_finalBlockPoint.setY(0); - d->m_finalBlockPointReflowOffset.setY(0); - } else if (d->m_finalBlockPoint.y() + scaledViewportHeight > d->contentsSize().height()) { - d->m_finalBlockPoint.setY(d->contentsSize().height() - scaledViewportHeight); - d->m_finalBlockPointReflowOffset.setY(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 * webkitThreadViewportAccessor()->documentViewportSize().width(); - if (oldScale == d->minimumScale() || (distanceBetweenPoints(d->scrollPosition(), roundUntransformedPoint(d->m_finalBlockPoint)) < minimumDisplacement && abs(newScale - oldScale) / oldScale < 0.10)) { + 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; @@ -4674,12 +4642,10 @@ bool WebPage::blockZoom(const Platform::IntPoint& documentTargetPoint) } } - d->m_blockZoomFinalScale = newScale; - // 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->animateBlockZoom(d->m_blockZoomFinalScale, d->m_finalBlockPoint); + d->m_client->animateToScaleAndDocumentScrollPosition(newScale, finalAnimationDocumentScrollPosition, true); return true; } @@ -4730,7 +4696,7 @@ void WebPage::setFocused(bool focused) focusController->setFocused(focused); } -bool WebPage::findNextString(const char* text, bool forward, bool caseSensitive, bool wrap, bool highlightAllMatches) +bool WebPage::findNextString(const char* text, bool forward, bool caseSensitive, bool wrap, bool highlightAllMatches, bool selectActiveMatchOnClear) { WebCore::FindOptions findOptions = WebCore::StartInSelection; if (!forward) @@ -4741,7 +4707,7 @@ bool WebPage::findNextString(const char* text, bool forward, bool caseSensitive, // 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); + return d->m_inPageSearchManager->findNextString(String::fromUTF8(text), findOptions, wrap, highlightAllMatches, selectActiveMatchOnClear); } void WebPage::runLayoutTests() @@ -4764,30 +4730,14 @@ unsigned WebPage::timeoutForJavaScriptExecution() const void WebPage::setTimeoutForJavaScriptExecution(unsigned ms) { Settings::setTimeoutForJavaScriptExecution(d->m_page->groupName(), ms); - - Document* doc = d->m_page->mainFrame()->document(); - if (!doc) - return; - - doc->globalData()->timeoutChecker.setTimeoutInterval(ms); } -JSContextRef WebPage::scriptContext() const +JSGlobalContextRef WebPage::globalContext() const { if (!d->m_mainFrame) return 0; - JSC::Bindings::RootObject *root = d->m_mainFrame->script()->bindingRootObject(); - if (!root) - return 0; - - JSC::ExecState *exec = root->globalObject()->globalExec(); - return toRef(exec); -} - -JSValueRef WebPage::windowObject() const -{ - return toRef(d->m_mainFrame->script()->globalObject(mainThreadNormalWorld())); + return toGlobalRef(d->m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec()); } // Serialize only the members of HistoryItem which are needed by the client, @@ -4795,7 +4745,7 @@ JSValueRef WebPage::windowObject() const // 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<BackForwardListImpl*>(d->m_page->backForward()->client())->entries(); + 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) { @@ -4830,6 +4780,7 @@ void WebPage::clearBrowsingData() clearCookieCache(); clearHistory(); clearPluginSiteData(); + clearWebFileSystem(); } void WebPage::clearHistory() @@ -4873,6 +4824,13 @@ void WebPage::clearNeverRememberSites() #endif } +void WebPage::clearWebFileSystem() +{ +#if ENABLE(FILE_SYSTEM) + Platform::WebFileSystem::deleteAllFileSystems(); +#endif +} + void WebPage::clearCache() { clearMemoryCaches(); @@ -4881,12 +4839,11 @@ void WebPage::clearCache() void WebPage::clearBackForwardList(bool keepCurrentPage) const { - BackForwardListImpl* backForwardList = static_cast<BackForwardListImpl*>(d->m_page->backForward()->client()); + BackForwardListBlackBerry* backForwardList = static_cast<BackForwardListBlackBerry*>(d->m_page->backForward()->client()); RefPtr<HistoryItem> currentItem = backForwardList->currentItem(); - while (!backForwardList->entries().isEmpty()) - backForwardList->removeItem(backForwardList->entries().last().get()); + backForwardList->clear(); if (keepCurrentPage) - backForwardList->addItem(currentItem); + d->m_page->backForward()->client()->addItem(currentItem); } bool WebPage::isEnableLocalAccessToAllCookies() const @@ -4899,93 +4856,26 @@ void WebPage::setEnableLocalAccessToAllCookies(bool enabled) cookieManager().setCanLocalAccessAllCookies(enabled); } -void WebPage::addVisitedLink(const unsigned short* url, unsigned int length) +void WebPage::addVisitedLink(const unsigned short* url, unsigned length) { ASSERT(d->m_page); d->m_page->group().addVisitedLink(url, length); } -#if ENABLE(WEBDOM) -WebDOMDocument WebPage::document() const -{ - if (!d->m_mainFrame) - return WebDOMDocument(); - return WebDOMDocument(d->m_mainFrame->document()); -} - -WebDOMNode WebPage::nodeAtDocumentPoint(const Platform::IntPoint& documentPoint) -{ - HitTestResult result = d->m_mainFrame->eventHandler()->hitTestResultAtPoint(WebCore::IntPoint(documentPoint), false); - Node* node = result.innerNonSharedNode(); - return WebDOMNode(node); -} - -bool WebPage::getNodeRect(const WebDOMNode& node, Platform::IntRect& result) -{ - Node* nodeImpl = node.impl(); - if (nodeImpl && nodeImpl->renderer()) { - result = nodeImpl->getRect(); - return true; - } - - return false; -} - -bool WebPage::setNodeFocus(const WebDOMNode& node, bool on) -{ - Node* nodeImpl = node.impl(); - - if (nodeImpl && nodeImpl->isFocusable()) { - Document* doc = nodeImpl->document(); - if (Page* page = doc->page()) { - // Modify if focusing on node or turning off focused node. - if (on) { - page->focusController()->setFocusedNode(nodeImpl, doc->frame()); - if (nodeImpl->isElementNode()) - static_cast<Element*>(nodeImpl)->updateFocusAppearance(true); - d->m_inputHandler->didNodeOpenPopup(nodeImpl); - } else if (doc->focusedNode() == nodeImpl) // && !on - page->focusController()->setFocusedNode(0, doc->frame()); - - return true; - } - } - return false; -} - -bool WebPage::setNodeHovered(const WebDOMNode& node, bool on) -{ - if (Node* nodeImpl = node.impl()) { - nodeImpl->setHovered(on); - return true; - } - return false; -} - -bool WebPage::nodeHasHover(const WebDOMNode& node) -{ - if (Node* nodeImpl = node.impl()) { - if (RenderStyle* style = nodeImpl->renderStyle()) - return style->affectedByHoverRules(); - } - return false; -} -#endif - void WebPage::initPopupWebView(BlackBerry::WebKit::WebPage* webPage) { - d->m_selectPopup->init(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")) { + || protocolIs(url, "tel") + || protocolIs(url, "wtai") + || protocolIs(url, "cti") + || protocolIs(url, "mailto") + || protocolIs(url, "sms") + || protocolIs(url, "pin")) { return url; } return String(); @@ -5042,6 +4932,10 @@ void WebPagePrivate::notifyAppActivationStateChange(ActivationStateType activati { m_activationState = activationState; +#if USE(ACCELERATED_COMPOSITING) + updateRootLayerCommitEnabled(); +#endif + #if ENABLE(PAGE_VISIBILITY_API) setPageVisibilityState(); #endif @@ -5073,30 +4967,30 @@ void WebPage::notifyAppActivationStateChange(ActivationStateType activationState void WebPage::notifySwipeEvent() { if (d->m_fullScreenPluginView.get()) - d->m_fullScreenPluginView->handleSwipeEvent(); + d->m_fullScreenPluginView->handleSwipeEvent(); else - notifyFullScreenVideoExited(true); + notifyFullScreenVideoExited(true); } void WebPage::notifyScreenPowerStateChanged(bool powered) { FOR_EACH_PLUGINVIEW(d->m_pluginViews) - (*it)->handleScreenPowerEvent(powered); + (*it)->handleScreenPowerEvent(powered); } void WebPage::notifyFullScreenVideoExited(bool done) { UNUSED_PARAM(done); #if ENABLE(VIDEO) - if (d->m_webSettings->fullScreenVideoCapable()) { - if (HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(d->m_fullscreenVideoNode.get())) - mediaElement->exitFullscreen(); - } else { + 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) - if (Element* element = static_cast<Element*>(d->m_fullscreenVideoNode.get())) - element->document()->webkitCancelFullScreen(); + else + element->document()->webkitCancelFullScreen(); #endif - } #endif } @@ -5114,6 +5008,66 @@ void WebPage::clearPluginSiteData() (*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); @@ -5143,26 +5097,29 @@ bool WebPage::isDNSPrefetchEnabled() const void WebPage::enableWebInspector() { - if (!d->m_inspectorClient) + 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()) { - d->m_page->inspectorController()->disconnectFrontend(); - d->m_page->settings()->setDeveloperExtrasEnabled(false); - d->setPreventsScreenDimming(false); - } + 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_page->settings()->developerExtrasEnabled(); + return d->m_inspectorEnabled; } void WebPage::enablePasswordEcho() @@ -5186,8 +5143,31 @@ void WebPage::inspectCurrentContextElement() 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(); @@ -5197,7 +5177,7 @@ bool WebPagePrivate::compositorDrawsRootLayer() const if (!renderView || !renderView->layer() || !renderView->layer()->backing()) return false; - return !renderView->layer()->backing()->paintingGoesToWindow(); + return !renderView->layer()->backing()->paintsIntoWindow(); #else return false; #endif @@ -5212,6 +5192,7 @@ void WebPagePrivate::setCompositorDrawsRootLayer(bool compositorDrawsRootLayer) // 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; @@ -5230,7 +5211,9 @@ void WebPagePrivate::scheduleRootLayerCommit() m_needsCommit = true; if (!m_rootLayerCommitTimer->isActive()) { #if DEBUG_AC_COMMIT - BBLOG(Platform::LogLevelCritical, "%s: m_rootLayerCommitTimer->isActive() = %d", WTF_PRETTY_FUNCTION, m_rootLayerCommitTimer->isActive()); + Platform::logAlways(Platform::LogLevelCritical, + "%s: m_rootLayerCommitTimer->isActive() = %d", + WTF_PRETTY_FUNCTION, m_rootLayerCommitTimer->isActive()); #endif m_rootLayerCommitTimer->startOneShot(0); } @@ -5247,7 +5230,7 @@ static bool needsLayoutRecursive(FrameView* view) for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end && !subframesNeedsLayout; ++current) { Widget* widget = (*current).get(); if (widget->isFrameView()) - subframesNeedsLayout |= needsLayoutRecursive(static_cast<FrameView*>(widget)); + subframesNeedsLayout |= needsLayoutRecursive(toFrameView(widget)); } return subframesNeedsLayout; @@ -5276,15 +5259,13 @@ void WebPagePrivate::setCompositor(PassRefPtr<WebPageCompositorPrivate> composit // That seems extremely likely to be the case, but let's assert just to make sure. ASSERT(webKitThreadMessageClient()->isCurrentThread()); - if (m_compositor || m_client->window()) - m_backingStore->d->suspendScreenUpdates(); + 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)); - if (m_compositor || m_client->window()) // the new compositor, if one was set - m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); + m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); } void WebPagePrivate::setCompositorHelper(PassRefPtr<WebPageCompositorPrivate> compositor) @@ -5313,13 +5294,12 @@ void WebPagePrivate::setCompositorBackgroundColor(const Color& backgroundColor) m_compositor->setBackgroundColor(backgroundColor); } -void WebPagePrivate::commitRootLayer(const IntRect& layoutRectForCompositing, - const IntSize& contentsSizeForCompositing, - bool drawsRootLayer) +void WebPagePrivate::commitRootLayer(const IntRect& layoutRect, const IntRect& documentRect, bool drawsRootLayer) { #if DEBUG_AC_COMMIT - BBLOG(Platform::LogLevelCritical, "%s: m_compositor = 0x%x", - WTF_PRETTY_FUNCTION, m_compositor.get()); + Platform::logAlways(Platform::LogLevelCritical, + "%s: m_compositor = 0x%p", + WTF_PRETTY_FUNCTION, m_compositor.get()); #endif if (!m_compositor) @@ -5341,29 +5321,36 @@ void WebPagePrivate::commitRootLayer(const IntRect& layoutRectForCompositing, if (overlayLayer && overlayLayer->layerCompositingThread() != m_compositor->overlayLayer()) m_compositor->setOverlayLayer(overlayLayer->layerCompositingThread()); - m_compositor->setLayoutRectForCompositing(layoutRectForCompositing); - m_compositor->setContentsSizeForCompositing(contentsSizeForCompositing); + 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 - BBLOG(Platform::LogLevelCritical, "%s: m_suspendRootLayerCommit = %d, m_needsCommit = %d, m_frameLayers = 0x%x, 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())); + 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) @@ -5373,8 +5360,7 @@ bool WebPagePrivate::commitRootLayerIfNeeded() 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) + if (!(m_frameLayers && m_frameLayers->hasLayer()) && !m_overlayLayer && !m_needsOneShotDrawingSynchronization) return false; FrameView* view = m_mainFrame->view(); @@ -5394,7 +5380,6 @@ bool WebPagePrivate::commitRootLayerIfNeeded() return false; } - willComposite(); 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 @@ -5411,11 +5396,12 @@ bool WebPagePrivate::commitRootLayerIfNeeded() 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 layoutRectForCompositing(scrollPosition(), actualVisibleSize()); - IntSize contentsSizeForCompositing = contentsSize(); + IntRect layoutRect(scrollPosition(), actualVisibleSize()); + IntRect documentRect(view->minimumScrollPosition(), view->contentsSize()); bool drawsRootLayer = compositorDrawsRootLayer(); // Commit changes made to the layers synchronously with the compositing thread. @@ -5423,10 +5409,19 @@ bool WebPagePrivate::commitRootLayerIfNeeded() Platform::createMethodCallMessage( &WebPagePrivate::commitRootLayer, this, - layoutRectForCompositing, - contentsSizeForCompositing, + 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; } @@ -5437,7 +5432,7 @@ void WebPagePrivate::rootLayerCommitTimerFired(Timer<WebPagePrivate>*) return; #if DEBUG_AC_COMMIT - BBLOG(Platform::LogLevelCritical, "%s", WTF_PRETTY_FUNCTION); + Platform::logAlways(Platform::LogLevelCritical, "%s", WTF_PRETTY_FUNCTION); #endif m_backingStore->d->instrumentBeginFrame(); @@ -5448,29 +5443,21 @@ void WebPagePrivate::rootLayerCommitTimerFired(Timer<WebPagePrivate>*) // 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. - requestLayoutIfNeeded(); + 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()) { - // If we are doing direct rendering and have a single rendering target, - // committing is equivalent to a one shot drawing synchronization. - // We need to re-render the web page, re-render the layers, and - // then blit them on top of the re-rendered web page. - if (m_backingStore->d->isOpenGLCompositing() && m_backingStore->d->shouldDirectRenderingToWindow()) - setNeedsOneShotDrawingSynchronization(); - - if (needsOneShotDrawingSynchronization()) { + if (!compositorDrawsRootLayer() && needsOneShotDrawingSynchronization()) { #if DEBUG_AC_COMMIT - BBLOG(Platform::LogLevelCritical, "%s: OneShotDrawingSynchronization code path!", WTF_PRETTY_FUNCTION); + 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; - } + const IntRect windowRect = IntRect(IntPoint::zero(), viewportSize()); + m_backingStore->d->repaint(windowRect, true /*contentChanged*/, true /*immediate*/); + return; } commitRootLayerIfNeeded(); @@ -5485,10 +5472,10 @@ void WebPagePrivate::setRootLayerWebKitThread(Frame* frame, LayerWebKitThread* l return; if (!layer) { - ASSERT(m_frameLayers); - m_frameLayers->removeLayerByFrame(frame); - if (!m_frameLayers->hasLayer()) - m_frameLayers.clear(); + ASSERT(m_frameLayers); + m_frameLayers->removeLayerByFrame(frame); + if (!m_frameLayers->hasLayer()) + m_frameLayers.clear(); } else { if (!m_frameLayers) m_frameLayers = adoptPtr(new FrameLayers(this)); @@ -5573,29 +5560,29 @@ void WebPagePrivate::releaseLayerResources() void WebPagePrivate::releaseLayerResourcesCompositingThread() { - m_compositor->releaseLayerResources(); + m_compositor->releaseLayerResources(); } -void WebPagePrivate::suspendRootLayerCommit() +void WebPagePrivate::updateRootLayerCommitEnabled() { - if (m_suspendRootLayerCommit) - return; - - m_suspendRootLayerCommit = true; + bool shouldSuspend = !m_visible || m_activationState != ActivationActive; - if (!m_compositor) + if (m_suspendRootLayerCommit == shouldSuspend) return; - releaseLayerResources(); -} + m_suspendRootLayerCommit = shouldSuspend; + + if (m_suspendRootLayerCommit) { + if (m_compositor) + releaseLayerResources(); -void WebPagePrivate::resumeRootLayerCommit() -{ - if (!m_suspendRootLayerCommit) return; + } - m_suspendRootLayerCommit = false; 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() @@ -5628,7 +5615,7 @@ void WebPagePrivate::enterFullscreenForNode(Node* node) if (!node || !node->hasTagName(HTMLNames::videoTag)) return; - MediaPlayer* player = static_cast<HTMLMediaElement*>(node)->player(); + MediaPlayer* player = toHTMLMediaElement(node)->player(); if (!player) return; @@ -5645,7 +5632,7 @@ void WebPagePrivate::enterFullscreenForNode(Node* node) return; mmrPlayer->setFullscreenWebPageClient(m_client); - m_fullscreenVideoNode = node; + m_fullscreenNode = node; m_client->fullscreenStart(contextName, window, mmrPlayer->getWindowScreenRect()); #endif } @@ -5653,15 +5640,15 @@ void WebPagePrivate::enterFullscreenForNode(Node* node) void WebPagePrivate::exitFullscreenForNode(Node* node) { #if ENABLE(VIDEO) - if (m_fullscreenVideoNode.get()) { + if (m_fullscreenNode.get()) { m_client->fullscreenStop(); - m_fullscreenVideoNode = 0; + m_fullscreenNode = 0; } if (!node || !node->hasTagName(HTMLNames::videoTag)) return; - MediaPlayer* player = static_cast<HTMLMediaElement*>(node)->player(); + MediaPlayer* player = toHTMLMediaElement(node)->player(); if (!player) return; @@ -5675,23 +5662,12 @@ void WebPagePrivate::exitFullscreenForNode(Node* node) } #if ENABLE(FULLSCREEN_API) -// TODO: We should remove this helper class when we decide to support all elements. -static bool containsVideoTags(Element* element) -{ - for (Node* node = element->firstChild(); node; node = node->traverseNextNode(element)) { - if (node->hasTagName(HTMLNames::videoTag)) - return true; - } - return false; -} - void WebPagePrivate::enterFullScreenForElement(Element* element) { #if ENABLE(VIDEO) - // TODO: We should not check video tag when we decide to support all elements. - if (!element || (!element->hasTagName(HTMLNames::videoTag) && !containsVideoTags(element))) + if (!element) return; - if (m_webSettings->fullScreenVideoCapable()) { + 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 @@ -5699,23 +5675,31 @@ void WebPagePrivate::enterFullScreenForElement(Element* element) // is so that exitFullScreenForElement() gets called later. enterFullscreenForNode(element); } else { - // 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. - WebCore::IntPoint scrollPosition = m_mainFrame->view()->scrollPosition(); - m_xScrollOffsetBeforeFullScreen = scrollPosition.x(); - - // 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(); + // 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_fullscreenVideoNode = element; + m_fullscreenNode = element; } #endif } @@ -5723,47 +5707,53 @@ void WebPagePrivate::enterFullScreenForElement(Element* element) void WebPagePrivate::exitFullScreenForElement(Element* element) { #if ENABLE(VIDEO) - // TODO: We should not check video tag when we decide to support all elements. - if (!element || (!element->hasTagName(HTMLNames::videoTag) && !containsVideoTags(element))) + if (!element) return; - if (m_webSettings->fullScreenVideoCapable()) { + if (m_webSettings->fullScreenVideoCapable() && element->hasTagName(HTMLNames::videoTag)) { // The Browser chrome has its own fullscreen video widget. exitFullscreenForNode(element); } else { - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->suspendBackingStoreUpdates(); - m_backingStore->d->suspendScreenUpdates(); - - // When leaving fullscreen mode, we need to restore the 'x' scroll position - // before fullscreen. - // FIXME: We may need to respect 'y' position as well, because the web page always scrolls to - // the top when leaving fullscreen mode. - WebCore::IntPoint scrollPosition = m_mainFrame->view()->scrollPosition(); - m_mainFrame->view()->setScrollPosition( - WebCore::IntPoint(m_xScrollOffsetBeforeFullScreen, scrollPosition.y())); - m_xScrollOffsetBeforeFullScreen = -1; - - if (m_scaleBeforeFullScreen > 0) { - // 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. - m_transformationMatrix->setM11(m_scaleBeforeFullScreen); - m_transformationMatrix->setM22(m_scaleBeforeFullScreen); - m_scaleBeforeFullScreen = -1.0; - } - - notifyTransformChanged(); - // FIXME: Do we really need to suspend/resume both backingstore and screen here? - m_backingStore->d->resumeBackingStoreUpdates(); - m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit); - // This is where we would restore the browser's chrome // if hidden above. client()->fullscreenStop(); - m_fullscreenVideoNode = 0; + 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) @@ -5774,7 +5764,6 @@ void WebPagePrivate::didChangeSettings(WebSettings* webSettings) coreSettings->setLoadsImagesAutomatically(webSettings->loadsImagesAutomatically()); coreSettings->setShouldDrawBorderWhileLoadingImages(webSettings->shouldDrawBorderWhileLoadingImages()); coreSettings->setScriptEnabled(webSettings->isJavaScriptEnabled()); - coreSettings->setPrivateBrowsingEnabled(webSettings->isPrivateBrowsingEnabled()); coreSettings->setDeviceSupportsMouse(webSettings->deviceSupportsMouse()); coreSettings->setDefaultFixedFontSize(webSettings->defaultFixedFontSize()); coreSettings->setDefaultFontSize(webSettings->defaultFontSize()); @@ -5803,14 +5792,20 @@ void WebPagePrivate::didChangeSettings(WebSettings* webSettings) 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) - // DatabaseTracker can only be initialized for once, so it doesn't - // make sense to change database path after DatabaseTracker has + // 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; - DatabaseTracker::initializeTracker(webSettings->databasePath()); + DatabaseManager::manager().initialize(webSettings->databasePath()); } // The directory of cacheStorage for one page group can only be initialized once. @@ -5821,8 +5816,7 @@ void WebPagePrivate::didChangeSettings(WebSettings* webSettings) } coreSettings->setLocalStorageDatabasePath(webSettings->localStoragePath()); - Database::setIsAvailable(webSettings->isDatabasesEnabled()); - DatabaseSync::setIsAvailable(webSettings->isDatabasesEnabled()); + DatabaseManager::manager().setIsAvailable(webSettings->isDatabasesEnabled()); coreSettings->setLocalStorageEnabled(webSettings->isLocalStorageEnabled()); coreSettings->setOfflineWebApplicationCacheEnabled(webSettings->isAppCacheEnabled()); @@ -5858,25 +5852,15 @@ void WebPagePrivate::didChangeSettings(WebSettings* webSettings) coreSettings->setShouldUseCrossOriginProtocolCheck(!webSettings->allowCrossSiteRequests()); coreSettings->setWebSecurityEnabled(!webSettings->allowCrossSiteRequests()); + coreSettings->setApplyDeviceScaleFactorInCompositor(webSettings->applyDeviceScaleFactorInCompositor()); - cookieManager().setPrivateMode(webSettings->isPrivateBrowsingEnabled()); - - CredentialStorage::setPrivateMode(webSettings->isPrivateBrowsingEnabled()); - - if (m_mainFrame && m_mainFrame->view()) { - Color backgroundColor(webSettings->backgroundColor()); - m_mainFrame->view()->updateBackgroundRecursively(backgroundColor, backgroundColor.hasAlpha()); - - Platform::userInterfaceThreadMessageClient()->dispatchMessage( - createMethodCallMessage(&WebPagePrivate::setCompositorBackgroundColor, this, backgroundColor)); - } - if (m_backingStore) { - m_backingStore->d->setWebPageBackgroundColor(m_mainFrame && m_mainFrame->view() - ? m_mainFrame->view()->documentBackgroundColor() - : webSettings->backgroundColor()); - } + 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 @@ -5884,7 +5868,7 @@ BlackBerry::Platform::String WebPage::textHasAttribute(const BlackBerry::Platfor if (Document* doc = d->m_page->focusController()->focusedOrMainFrame()->document()) return doc->queryCommandValue(query); - return ""; + return BlackBerry::Platform::String::emptyString(); } void WebPage::setJavaScriptCanAccessClipboard(bool enabled) @@ -5893,14 +5877,6 @@ void WebPage::setJavaScriptCanAccessClipboard(bool enabled) } #if USE(ACCELERATED_COMPOSITING) -void WebPagePrivate::blitVisibleContents() -{ - if (m_backingStore->d->shouldDirectRenderingToWindow()) - return; - - m_backingStore->d->blitVisibleContents(); -} - void WebPagePrivate::scheduleCompositingRun() { if (WebPageCompositorClient* compositorClient = compositor()->client()) { @@ -5909,9 +5885,8 @@ void WebPagePrivate::scheduleCompositingRun() return; } - blitVisibleContents(); + m_backingStore->d->blitVisibleContents(); } - #endif void WebPage::setWebGLEnabled(bool enabled) @@ -5943,7 +5918,7 @@ const BlackBerry::Platform::String& WebPagePrivate::defaultUserAgent() if (uaSize <= 0 || uaSize >= 256) BLACKBERRY_CRASH(); - defaultUserAgent = new BlackBerry::Platform::String(uaBuffer, uaSize); + defaultUserAgent = new BlackBerry::Platform::String(BlackBerry::Platform::String::fromUtf8(uaBuffer, uaSize)); } return *defaultUserAgent; @@ -5954,6 +5929,11 @@ 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) @@ -5999,26 +5979,34 @@ void WebPage::removeCompositingThreadOverlay(WebOverlay* overlay) #endif } -void WebPage::popupOpened(PagePopupBlackBerry* webPopup) +bool WebPagePrivate::openPagePopup(PagePopupClient* popupClient, const WebCore::IntRect& originBoundsInRootView) { - ASSERT(!d->m_selectPopup); - d->m_selectPopup = webPopup; -} + closePagePopup(); + m_pagePopup = PagePopup::create(this, popupClient); -void WebPage::popupClosed() -{ - ASSERT(d->m_selectPopup); - d->m_selectPopup = 0; + WebCore::IntRect popupRect = m_page->chrome().client()->rootViewToScreen(originBoundsInRootView); + popupRect.setSize(popupClient->contentSize()); + if (!m_client->createPopupWebView(popupRect)) { + closePagePopup(); + return false; + } + + return true; } -bool WebPage::hasOpenedPopup() const +void WebPagePrivate::closePagePopup() { - return d->m_selectPopup; + if (!m_pagePopup) + return; + + m_pagePopup->close(); + m_client->closePopupWebView(); + m_pagePopup = 0; } -PagePopupBlackBerry* WebPage::popup() +bool WebPagePrivate::hasOpenedPopup() const { - return d->m_selectPopup; + return m_pagePopup; } void WebPagePrivate::setInspectorOverlayClient(InspectorOverlay::InspectorOverlayClient* inspectorOverlayClient) @@ -6052,7 +6040,7 @@ void WebPagePrivate::setTextZoomFactor(float textZoomFactor) m_mainFrame->setTextZoomFactor(textZoomFactor); } -void WebPagePrivate::restoreHistoryViewState(Platform::IntSize contentsSize, Platform::IntPoint scrollPosition, double scale, bool shouldReflowBlock) +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? @@ -6061,29 +6049,35 @@ void WebPagePrivate::restoreHistoryViewState(Platform::IntSize contentsSize, Pla return; } - m_mainFrame->view()->setContentsSizeFromHistory(contentsSize); + // 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(scrollPosition); + setScrollPosition(adjustedScrollPosition); m_mainFrame->view()->setConstrainsScrollingToContentEdge(oldConstrainsScrollingToContentEdge); m_shouldReflowBlock = shouldReflowBlock; - bool didZoom = zoomAboutPoint(scale, m_mainFrame->view()->scrollPosition(), true /* enforceScaleClamping */, true /*forceRendering*/, true /*isRestoringZoomLevel*/); + 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); - - if (!didZoom) { - // We need to notify the client of the scroll position and content size change(s) above even if we didn't scale. - notifyTransformedContentsSizeChanged(); - notifyTransformedScrollChanged(); - } } IntSize WebPagePrivate::screenSize() const @@ -6097,7 +6091,7 @@ void WebPagePrivate::postponeDocumentStyleRecalc() m_documentChildNeedsStyleRecalc = document->childNeedsStyleRecalc(); document->clearChildNeedsStyleRecalc(); - m_documentStyleRecalcPostponed = document->isPendingStyleRecalc(); + m_documentStyleRecalcPostponed = document->hasPendingStyleRecalc(); document->unscheduleStyleRecalc(); } } @@ -6120,7 +6114,8 @@ const HitTestResult& WebPagePrivate::hitTestResult(const IntPoint& contentPos) { if (m_cachedHitTestContentPos != contentPos) { m_cachedHitTestContentPos = contentPos; - m_cachedHitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_cachedHitTestContentPos, true /*allowShadowContent*/); + m_cachedRectHitTestResults.clear(); + m_cachedHitTestResult = m_mainFrame->eventHandler()->hitTestResultAtPoint(m_cachedHitTestContentPos, HitTestRequest::ReadOnly | HitTestRequest::Active); } return m_cachedHitTestResult; @@ -6135,14 +6130,14 @@ void WebPagePrivate::willComposite() { if (!m_page->settings()->developerExtrasEnabled()) return; - InspectorInstrumentation::willComposite(m_page); + m_page->inspectorController()->willComposite(); } void WebPagePrivate::didComposite() { if (!m_page->settings()->developerExtrasEnabled()) return; - InspectorInstrumentation::didComposite(m_page); + m_page->inspectorController()->didComposite(); } void WebPage::updateNotificationPermission(const BlackBerry::Platform::String& requestId, bool allowed) @@ -6191,5 +6186,131 @@ void WebPage::notificationShown(const BlackBerry::Platform::String& notification #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 +} + } } |
