#include "config.h"
#include "WebPage.h"
#include "ApplicationCacheStorage.h"
#include "BackForwardController.h"
#include "BackForwardListImpl.h"
#include "BackingStoreClient.h"
#include "BackingStoreCompositingSurface.h"
#include "BackingStore_p.h"
#if ENABLE(BATTERY_STATUS)
#include "BatteryClientBlackBerry.h"
#endif
#include "CString.h"
#include "CachedImage.h"
#include "Chrome.h"
#include "ChromeClientBlackBerry.h"
#include "ContextMenuClientBlackBerry.h"
#include "CookieManager.h"
#include "CredentialManager.h"
#include "CredentialTransformData.h"
#include "DOMSupport.h"
#include "Database.h"
#include "DatabaseSync.h"
#include "DatabaseTracker.h"
#include "DeviceMotionClientBlackBerry.h"
#include "DeviceOrientationClientBlackBerry.h"
#include "DragClientBlackBerry.h"
#if ENABLE_DRT
#include "DumpRenderTreeBlackBerry.h"
#endif
#include "EditorClientBlackBerry.h"
#include "FocusController.h"
#include "FrameLoaderClientBlackBerry.h"
#if ENABLE_DRT
#include "GeolocationClientMock.h"
#endif
#include "GeolocationControllerClientBlackBerry.h"
#include "GroupSettings.h"
#include "HTMLAreaElement.h"
#include "HTMLFrameOwnerElement.h"
#include "HTMLImageElement.h"
#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
#include "HTMLParserIdioms.h"
#include "HTTPParsers.h"
#include "HistoryItem.h"
#include "IconDatabaseClientBlackBerry.h"
#include "InPageSearchManager.h"
#include "InRegionScrollableArea.h"
#include "InputHandler.h"
#include "InspectorBackendDispatcher.h"
#include "InspectorClientBlackBerry.h"
#include "InspectorController.h"
#include "JavaScriptDebuggerBlackBerry.h"
#include "LayerWebKitThread.h"
#include "NetworkManager.h"
#include "NodeRenderStyle.h"
#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
#include "NotificationPresenterImpl.h"
#endif
#include "Page.h"
#include "PageCache.h"
#include "PageGroup.h"
#include "PlatformTouchEvent.h"
#include "PlatformWheelEvent.h"
#include "PluginDatabase.h"
#include "PluginView.h"
#include "RenderLayerBacking.h"
#include "RenderLayerCompositor.h"
#include "RenderText.h"
#include "RenderThemeBlackBerry.h"
#include "RenderTreeAsText.h"
#include "RenderView.h"
#include "RenderWidget.h"
#include "ScriptSourceCode.h"
#include "ScriptValue.h"
#include "ScrollTypes.h"
#include "SelectionHandler.h"
#include "Settings.h"
#include "Storage.h"
#include "StorageNamespace.h"
#include "SurfacePool.h"
#include "Text.h"
#include "ThreadCheck.h"
#include "TouchEventHandler.h"
#include "TransformationMatrix.h"
#if ENABLE(VIBRATION)
#include "VibrationClientBlackBerry.h"
#endif
#include "VisiblePosition.h"
#if ENABLE(WEBDOM)
#include "WebDOMDocument.h"
#endif
#include "WebKitVersion.h"
#include "WebPageClient.h"
#include "WebSocket.h"
#include "WebViewportArguments.h"
#include "npapi.h"
#include "runtime_root.h"
#if ENABLE(VIDEO)
#include "HTMLMediaElement.h"
#include "MediaPlayer.h"
#include "MediaPlayerPrivateBlackBerry.h"
#endif
#if USE(SKIA)
#include "PlatformContextSkia.h"
#endif
#if USE(ACCELERATED_COMPOSITING)
#include "FrameLayers.h"
#include "WebPageCompositor_p.h"
#endif
#include <BlackBerryPlatformDeviceInfo.h>
#include <BlackBerryPlatformExecutableMessage.h>
#include <BlackBerryPlatformITPolicy.h>
#include <BlackBerryPlatformKeyboardEvent.h>
#include <BlackBerryPlatformMessageClient.h>
#include <BlackBerryPlatformMouseEvent.h>
#include <BlackBerryPlatformScreen.h>
#include <BlackBerryPlatformSettings.h>
#include <JavaScriptCore/APICast.h>
#include <JavaScriptCore/JSContextRef.h>
#include <SharedPointer.h>
#include <sys/keycodes.h>
#include <unicode/ustring.h> // platform ICU
#ifndef USER_PROCESSES
#include <memalloc.h>
#endif
#if ENABLE(ACCELERATED_2D_CANVAS)
#include "SharedGraphicsContext3D.h"
#include "GrContext.h"
#endif
#if ENABLE(REQUEST_ANIMATION_FRAME)
#include "PlatformScreen.h"
#endif
#define DEBUG_BLOCK_ZOOM 0
#define DEBUG_TOUCH_EVENTS 0
#define DEBUG_WEBPAGE_LOAD 0
#define DEBUG_AC_COMMIT 0
using namespace std;
using namespace WebCore;
typedef const unsigned short* CUShortPtr;
namespace BlackBerry {
namespace WebKit {
static Vector<WebPage*>* visibleWebPages()
{
static Vector<WebPage*>* s_visibleWebPages = 0; if (!s_visibleWebPages)
s_visibleWebPages = new Vector<WebPage*>;
return s_visibleWebPages;
}
const unsigned blockZoomMargin = 3; static int blockClickRadius = 0;
static double maximumBlockZoomScale = 3;
const double manualScrollInterval = 0.1;
const double delayedZoomInterval = 0;
const IntSize minimumLayoutSize(10, 10); const IntSize maximumLayoutSize(10000, 10000);
const double minimumExpandingRatio = 0.15;
static KURL parseUrl(const String& url)
{
String urlString(url);
KURL kurl = KURL(KURL(), urlString);
if (kurl.protocol().isEmpty()) {
urlString.insert("http://", 0);
kurl = KURL(KURL(), urlString);
}
return kurl;
}
static inline WebCore::PlatformEvent::Type toWebCoreMouseEventType(const BlackBerry::Platform::MouseEvent::Type type)
{
switch (type) {
case BlackBerry::Platform::MouseEvent::MouseButtonDown:
return WebCore::PlatformEvent::MousePressed;
case Platform::MouseEvent::MouseButtonUp:
return WebCore::PlatformEvent::MouseReleased;
case Platform::MouseEvent::MouseMove:
default:
return WebCore::PlatformEvent::MouseMoved;
}
}
static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy)
{
switch (policy) {
case Platform::NetworkRequest::UseProtocolCachePolicy:
return UseProtocolCachePolicy;
case Platform::NetworkRequest::ReloadIgnoringCacheData:
return ReloadIgnoringCacheData;
case Platform::NetworkRequest::ReturnCacheDataElseLoad:
return ReturnCacheDataElseLoad;
case Platform::NetworkRequest::ReturnCacheDataDontLoad:
return ReturnCacheDataDontLoad;
default:
ASSERT_NOT_REACHED();
return UseProtocolCachePolicy;
}
}
#if ENABLE(EVENT_MODE_METATAGS)
static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode)
{
switch (mode) {
case ProcessedCursorEvents:
return Platform::ProcessedCursorEvents;
case NativeCursorEvents:
return Platform::NativeCursorEvents;
default:
ASSERT_NOT_REACHED();
return Platform::ProcessedCursorEvents;
}
}
static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode)
{
switch (mode) {
case ProcessedTouchEvents:
return Platform::ProcessedTouchEvents;
case NativeTouchEvents:
return Platform::NativeTouchEvents;
case PureTouchEventsWithMouseConversion:
return Platform::PureTouchEventsWithMouseConversion;
default:
ASSERT_NOT_REACHED();
return Platform::ProcessedTouchEvents;
}
}
#endif
static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id)
{
return reinterpret_cast<HistoryItem*>(id);
}
static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item)
{
return reinterpret_cast<WebPage::BackForwardId>(item);
}
void WebPage::setUserViewportArguments(const WebViewportArguments& viewportArguments)
{
d->m_userViewportArguments = *(viewportArguments.d);
}
void WebPage::resetUserViewportArguments()
{
d->m_userViewportArguments = ViewportArguments();
}
template <bool WebPagePrivate::* isActive>
class DeferredTask: public WebPagePrivate::DeferredTaskBase {
public:
static void finishOrCancel(WebPagePrivate* webPagePrivate)
{
webPagePrivate->*isActive = false;
}
protected:
DeferredTask(WebPagePrivate* webPagePrivate)
: DeferredTaskBase(webPagePrivate, isActive)
{
}
typedef DeferredTask<isActive> DeferredTaskType;
};
WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
: m_webPage(webPage)
, m_client(client)
, m_page(0) , m_mainFrame(0) , m_currentContextNode(0)
, m_webSettings(0) , m_visible(false)
, m_activationState(ActivationActive)
, m_shouldResetTilesWhenShown(false)
, m_userScalable(true)
, m_userPerformedManualZoom(false)
, m_userPerformedManualScroll(false)
, m_contentsSizeChanged(false)
, m_overflowExceedsContentsSize(false)
, m_resetVirtualViewportOnCommitted(true)
, m_shouldUseFixedDesktopMode(false)
, m_needTouchEvents(false)
, m_preventIdleDimmingCount(0)
#if ENABLE(TOUCH_EVENTS)
, m_preventDefaultOnTouchStart(false)
#endif
, m_nestedLayoutFinishedCount(0)
, m_actualVisibleWidth(rect.width())
, m_actualVisibleHeight(rect.height())
, m_virtualViewportWidth(0)
, m_virtualViewportHeight(0)
, m_defaultLayoutSize(minimumLayoutSize)
, m_didRestoreFromPageCache(false)
, m_viewMode(WebPagePrivate::Desktop) , m_loadState(WebPagePrivate::None)
, m_transformationMatrix(new TransformationMatrix())
, m_backingStore(0) , m_backingStoreClient(0) , m_inPageSearchManager(new InPageSearchManager(this))
, m_inputHandler(new InputHandler(this))
, m_selectionHandler(new SelectionHandler(this))
, m_touchEventHandler(new TouchEventHandler(this))
#if ENABLE(EVENT_MODE_METATAGS)
, m_cursorEventMode(ProcessedCursorEvents)
, m_touchEventMode(ProcessedTouchEvents)
#endif
, m_currentCursor(Platform::CursorNone)
, m_dumpRenderTree(0) , m_initialScale(-1.0)
, m_minimumScale(-1.0)
, m_maximumScale(-1.0)
, m_blockZoomFinalScale(1.0)
, m_anchorInNodeRectRatio(-1, -1)
, m_currentBlockZoomNode(0)
, m_currentBlockZoomAdjustedNode(0)
, m_shouldReflowBlock(false)
, m_delayedZoomTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::zoomAboutPointTimerFired)))
, m_lastUserEventTimestamp(0.0)
, m_pluginMouseButtonPressed(false)
, m_pluginMayOpenNewTab(false)
, m_inRegionScrollStartingNode(0)
#if USE(ACCELERATED_COMPOSITING)
, m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
, m_needsOneShotDrawingSynchronization(false)
, m_needsCommit(false)
, m_suspendRootLayerCommit(false)
#endif
, m_pendingOrientation(-1)
, m_fullscreenVideoNode(0)
, m_hasInRegionScrollableAreas(false)
, m_updateDelegatedOverlaysDispatched(false)
, m_deferredTasksTimer(this, &WebPagePrivate::deferredTasksTimerFired)
{
static bool isInitialized = false;
if (!isInitialized) {
isInitialized = true;
BlackBerry::Platform::DeviceInfo::instance();
defaultUserAgent();
}
}
WebPage::WebPage(WebPageClient* client, const WebString& pageGroupName, const Platform::IntRect& rect)
{
globalInitialize();
d = new WebPagePrivate(this, client, rect);
d->init(pageGroupName);
}
WebPagePrivate::~WebPagePrivate()
{
m_webPage->setVisible(false);
if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage)
BackingStorePrivate::setCurrentBackingStoreOwner(0);
delete m_webSettings;
m_webSettings = 0;
delete m_backingStoreClient;
m_backingStoreClient = 0;
m_backingStore = 0;
delete m_page;
m_page = 0;
delete m_transformationMatrix;
m_transformationMatrix = 0;
delete m_inPageSearchManager;
m_inPageSearchManager = 0;
delete m_selectionHandler;
m_selectionHandler = 0;
delete m_inputHandler;
m_inputHandler = 0;
delete m_touchEventHandler;
m_touchEventHandler = 0;
#if ENABLE_DRT
delete m_dumpRenderTree;
m_dumpRenderTree = 0;
#endif
}
WebPage::~WebPage()
{
deleteGuardedObject(d);
d = 0;
}
Page* WebPagePrivate::core(const WebPage* webPage)
{
return webPage->d->m_page;
}
void WebPagePrivate::init(const WebString& pageGroupName)
{
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)
dragClient = new DragClientBlackBerry();
#endif
InspectorClientBlackBerry* inspectorClient = 0;
#if ENABLE(INSPECTOR)
inspectorClient = new InspectorClientBlackBerry(this);
#endif
FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry();
Page::PageClients pageClients;
pageClients.chromeClient = chromeClient;
pageClients.contextMenuClient = contextMenuClient;
pageClients.editorClient = editorClient;
pageClients.dragClient = dragClient;
pageClients.inspectorClient = inspectorClient;
m_page = new Page(pageClients);
#if ENABLE_DRT
if (getenv("drtRun")) {
GeolocationClientMock* mock = new GeolocationClientMock();
WebCore::provideGeolocationTo(m_page, mock);
mock->setController(WebCore::GeolocationController::from(m_page));
} else
#else
WebCore::provideGeolocationTo(m_page, new GeolocationControllerClientBlackBerry(this));
#endif
WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientBlackBerry(this));
WebCore::provideDeviceMotionTo(m_page, new DeviceMotionClientBlackBerry(this));
#if ENABLE(VIBRATION)
WebCore::provideVibrationTo(m_page, new VibrationClientBlackBerry());
#endif
#if ENABLE(BATTERY_STATUS)
WebCore::provideBatteryTo(m_page, new WebCore::BatteryClientBlackBerry);
#endif
#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
WebCore::provideNotification(m_page, NotificationPresenterImpl::instance());
#endif
m_page->setCustomHTMLTokenizerChunkSize(256);
m_page->setCustomHTMLTokenizerTimeDelay(0.3);
m_webSettings = WebSettings::createFromStandardSettings();
m_webSettings->setUserAgentString(defaultUserAgent());
m_webSettings->setDelegate(this);
m_webSettings->setPageGroupName(pageGroupName);
RefPtr<Frame> newFrame = Frame::create(m_page, 0, frameLoaderClient);
m_mainFrame = newFrame.get();
frameLoaderClient->setFrame(m_mainFrame, this);
m_mainFrame->init();
#if ENABLE(WEBGL)
Platform::Settings* settings = Platform::Settings::get();
m_page->settings()->setWebGLEnabled(settings && settings->isWebGLSupported());
#endif
#if ENABLE(ACCELERATED_2D_CANVAS)
m_page->settings()->setCanvasUsesAcceleratedDrawing(true);
m_page->settings()->setAccelerated2dCanvasEnabled(true);
#endif
#if ENABLE(VIEWPORT_REFLOW)
m_page->settings()->setTextReflowEnabled(m_webSettings->textReflowMode() == WebSettings::TextReflowEnabled);
#endif
m_page->settings()->setUseHixie76WebSocketProtocol(false);
m_page->settings()->setInteractiveFormValidationEnabled(true);
m_page->settings()->setAllowUniversalAccessFromFileURLs(false);
m_page->settings()->setAllowFileAccessFromFileURLs(false);
m_backingStoreClient = BackingStoreClient::create(m_mainFrame, 0, m_webPage);
m_backingStore = m_backingStoreClient->backingStore();
m_page->settings()->setSpatialNavigationEnabled(m_webSettings->isSpatialNavigationEnabled());
blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(0).width()));
m_page->settings()->setDelegateSelectionPaint(true);
#if ENABLE(REQUEST_ANIMATION_FRAME)
m_page->windowScreenDidChange((PlatformDisplayID)0);
#endif
#if ENABLE(WEB_TIMING)
m_page->settings()->setMemoryInfoEnabled(true);
#endif
}
class DeferredTaskLoadManualScript: public DeferredTask<&WebPagePrivate::m_wouldLoadManualScript> {
public:
explicit DeferredTaskLoadManualScript(WebPagePrivate* webPagePrivate, const KURL& url)
: DeferredTaskType(webPagePrivate)
{
webPagePrivate->m_cachedManualScript = url;
}
private:
virtual void performInternal(WebPagePrivate* webPagePrivate)
{
webPagePrivate->m_mainFrame->script()->executeIfJavaScriptURL(webPagePrivate->m_cachedManualScript, DoNotReplaceDocumentIfJavaScriptURL);
}
};
void WebPagePrivate::load(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool isInitial, bool mustHandleInternally, bool forceDownload, const char* overrideContentType)
{
stopCurrentLoad();
DeferredTaskLoadManualScript::finishOrCancel(this);
String urlString(url);
if (urlString.startsWith("vs:", false)) {
urlString = urlString.substring(3);
m_mainFrame->setInViewSourceMode(true);
} else
m_mainFrame->setInViewSourceMode(false);
KURL kurl = parseUrl(urlString);
if (protocolIs(kurl, "javascript")) {
if (m_page->defersLoading())
m_deferredTasks.append(adoptPtr(new DeferredTaskLoadManualScript(this, kurl)));
else
m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL);
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)
request.setOverrideContentType(overrideContentType);
if (data)
request.setHTTPBody(FormData::create(data, dataLength));
for (unsigned i = 0; i + 1 < headersLength; i += 2)
request.addHTTPHeaderField(headers[i], headers[i + 1]);
if (forceDownload)
request.setForceDownload(true);
m_mainFrame->loader()->load(request, "" , false);
}
void WebPage::load(const char* url, const char* 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, "");
}
void WebPage::loadFile(const char* path, const char* overrideContentType)
{
std::string fileUrl(path);
if (!fileUrl.find("/"))
fileUrl.insert(0, "file://");
else if (fileUrl.find("file:///"))
return;
d->load(fileUrl.c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, false, overrideContentType);
}
void WebPage::download(const Platform::NetworkRequest& request)
{
d->load(request.getUrlRef().c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, true, "");
}
void WebPagePrivate::loadString(const char* string, const char* baseURL, const char* contentType, const char* failingURL)
{
KURL kurl = parseUrl(baseURL);
ResourceRequest request(kurl);
WTF::RefPtr<SharedBuffer> buffer
= SharedBuffer::create(string, strlen(string));
SubstituteData substituteData(buffer,
extractMIMETypeFromMediaType(contentType),
extractCharsetFromMediaType(contentType),
failingURL ? parseUrl(failingURL) : KURL());
m_mainFrame->loader()->load(request, substituteData, false);
}
void WebPage::loadString(const char* string, const char* baseURL, const char* mimeType, const char* failingURL)
{
d->loadString(string, baseURL, mimeType, failingURL);
}
bool WebPagePrivate::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
{
ScriptValue result = m_mainFrame->script()->executeScript(String::fromUTF8(script), false);
JSC::JSValue value = result.jsValue();
if (!value) {
returnType = JSException;
return false;
}
JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
JSGlobalContextRef context = toGlobalRef(exec);
JSType type = JSValueGetType(context, toRef(exec, value));
switch (type) {
case kJSTypeNull:
returnType = JSNull;
break;
case kJSTypeBoolean:
returnType = JSBoolean;
break;
case kJSTypeNumber:
returnType = JSNumber;
break;
case kJSTypeString:
returnType = JSString;
break;
case kJSTypeObject:
returnType = JSObject;
break;
case kJSTypeUndefined:
default:
returnType = JSUndefined;
break;
}
if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
String str = result.toString(exec);
returnValue = WebString(str.impl());
}
return true;
}
bool WebPage::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
{
return d->executeJavaScript(script, returnType, returnValue);
}
bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& sourceCode, JavaScriptDataType& returnType, WebString& returnValue)
{
if (!m_isolatedWorld)
m_isolatedWorld = m_mainFrame->script()->createWorld();
ScriptValue result = m_mainFrame->script()->evaluateInWorld(sourceCode, m_isolatedWorld.get());
JSC::JSValue value = result.jsValue();
if (!value) {
returnType = JSException;
return false;
}
JSC::ExecState* exec = m_mainFrame->script()->globalObject(m_isolatedWorld.get())->globalExec();
JSGlobalContextRef context = toGlobalRef(exec);
JSType type = JSValueGetType(context, toRef(exec, value));
switch (type) {
case kJSTypeNull:
returnType = JSNull;
break;
case kJSTypeBoolean:
returnType = JSBoolean;
break;
case kJSTypeNumber:
returnType = JSNumber;
break;
case kJSTypeString:
returnType = JSString;
break;
case kJSTypeObject:
returnType = JSObject;
break;
case kJSTypeUndefined:
default:
returnType = JSUndefined;
break;
}
if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
String str = result.toString(exec);
returnValue = WebString(str.impl());
}
return true;
}
bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, WebString& returnValue)
{
int lengthCopied = 0;
UErrorCode error = U_ZERO_ERROR;
const int length = script.length() + 1 ;
UChar data[length];
u_strFromUTF32(data, length, &lengthCopied, reinterpret_cast<const UChar32*>(script.c_str()), script.length(), &error);
BLACKBERRY_ASSERT(error == U_ZERO_ERROR);
if (error != U_ZERO_ERROR) {
Platform::logAlways(Platform::LogLevelCritical, "WebPage::executeJavaScriptInIsolatedWorld failed to convert UTF16 to JavaScript!");
return false;
}
String str = String(data, lengthCopied);
ScriptSourceCode sourceCode(str, KURL());
return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
}
bool WebPage::executeJavaScriptInIsolatedWorld(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
{
ScriptSourceCode sourceCode(String::fromUTF8(script), KURL());
return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
}
void WebPagePrivate::stopCurrentLoad()
{
m_mainFrame->loader()->stopAllLoaders();
DeferredTaskLoadManualScript::finishOrCancel(this);
}
void WebPage::stopLoading()
{
d->stopCurrentLoad();
}
static void closeURLRecursively(Frame* frame)
{
FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client());
frameLoaderClient->suppressChildFrameCreation();
frame->loader()->closeURL();
Vector<RefPtr<Frame>, 10> childFrames;
for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
childFrames.append(childFrame);
unsigned size = childFrames.size();
for (unsigned i = 0; i < size; i++)
closeURLRecursively(childFrames[i].get());
}
void WebPagePrivate::prepareToDestroy()
{
closeURLRecursively(m_mainFrame);
}
void WebPage::prepareToDestroy()
{
d->prepareToDestroy();
}
void WebPagePrivate::setLoadState(LoadState state)
{
if (m_loadState == state)
return;
bool isFirstLoad = m_loadState == None;
if (state == Finished && m_mainFrame && m_mainFrame->document())
m_mainFrame->document()->updateStyleIfNeeded();
m_loadState = state;
#if DEBUG_WEBPAGE_LOAD
Platform::log(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state);
#endif
switch (m_loadState) {
case Provisional:
if (isFirstLoad) {
if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
m_backingStore->d->blitVisibleContents();
}
break;
case Committed:
{
unscheduleZoomAboutPoint();
#if ENABLE(ACCELERATED_2D_CANVAS)
if (m_page->settings()->canvasUsesAcceleratedDrawing()) {
SharedGraphicsContext3D::get()->makeContextCurrent();
GrContext* grContext = Platform::Graphics::getGrContext();
grContext->freeGpuResources();
}
#endif
#if USE(ACCELERATED_COMPOSITING)
if (isAcceleratedCompositingActive() && !compositorDrawsRootLayer())
syncDestroyCompositorOnCompositingThread();
#endif
m_previousContentsSize = IntSize();
m_backingStore->d->resetRenderQueue();
m_backingStore->d->resetTiles(true );
m_backingStore->d->setScrollingOrZooming(false, false );
m_userPerformedManualZoom = false;
m_userPerformedManualScroll = false;
m_shouldUseFixedDesktopMode = false;
if (m_resetVirtualViewportOnCommitted) { m_virtualViewportWidth = 0;
m_virtualViewportHeight = 0;
}
if (m_webSettings->viewportWidth() > 0) {
m_virtualViewportWidth = m_webSettings->viewportWidth();
m_virtualViewportHeight = m_defaultLayoutSize.height();
}
if (!m_didRestoreFromPageCache) {
m_viewportArguments = ViewportArguments();
dispatchViewportPropertiesDidChange(m_userViewportArguments);
m_userScalable = m_webSettings->isUserScalable();
resetScales();
} else {
IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
}
#if ENABLE(EVENT_MODE_METATAGS)
didReceiveCursorEventMode(ProcessedCursorEvents);
didReceiveTouchEventMode(ProcessedTouchEvents);
#endif
if (m_page->mainFrame()->document()->isSVGDocument()) {
setShouldUseFixedDesktopMode(true);
setViewMode(FixedDesktop);
} else
setViewMode(Mobile);
resetBlockZoom();
#if ENABLE(VIEWPORT_REFLOW)
toggleTextReflowIfEnabledForBlockZoomOnly();
#endif
m_inputHandler->enableInputMode(false);
setScrollPosition(IntPoint::zero());
notifyTransformedScrollChanged();
if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
m_backingStore->d->blitVisibleContents();
zoomToInitialScaleOnLoad();
updateCursor();
#if USE(ACCELERATED_COMPOSITING)
resetCompositingSurface();
#endif
break;
}
case Finished:
case Failed:
m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
m_backingStore->d->updateTiles(true , false );
break;
default:
break;
}
}
double WebPagePrivate::clampedScale(double scale) const
{
if (scale < minimumScale())
return minimumScale();
if (scale > maximumScale())
return maximumScale();
return scale;
}
bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale)
{
if (!m_mainFrame->view())
return false;
if (enforceScaleClamping)
scale = this->clampedScale(scale);
ASSERT(clampedScale);
*clampedScale = scale;
if (currentScale() == scale) {
m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
return false;
}
return true;
}
bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel)
{
if (!isRestoringZoomLevel) {
resetBlockZoom();
}
#if ENABLE(VIEWPORT_REFLOW)
toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view())
setNeedsLayout();
#endif
double scale;
if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
m_currentPinchZoomNode = 0;
m_anchorInNodeRectRatio = FloatPoint(-1, -1);
}
return false;
}
TransformationMatrix zoom;
zoom.scale(scale);
#if DEBUG_WEBPAGE_LOAD
if (loadState() < Finished)
Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomAboutPoint scale %f anchor (%f, %f)", scale, anchor.x(), anchor.y());
#endif
FloatPoint scrollPosition = this->scrollPosition();
FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y());
ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22());
double inverseScale = scale / m_transformationMatrix->m11();
*m_transformationMatrix = zoom;
m_backingStore->d->suspendScreenAndBackingStoreUpdates();
updateViewportSize();
IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))),
max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale)))));
if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
m_mainFrame->view()->setNeedsLayout();
requestLayoutIfNeeded();
if (m_currentPinchZoomNode)
newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale);
m_currentPinchZoomNode = 0;
m_anchorInNodeRectRatio = FloatPoint(-1, -1);
}
setScrollPosition(newScrollPosition);
notifyTransformChanged();
bool isLoading = this->isLoading();
m_backingStore->d->updateTiles(isLoading , false );
m_client->resetBitmapZoomScale(m_transformationMatrix->m11());
bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering;
bool shouldClearVisibleZoom = isLoading && shouldRender;
if (shouldClearVisibleZoom) {
m_backingStore->d->clearVisibleZoom();
}
if (shouldRender) {
m_backingStore->d->clearWindow();
m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
} else {
m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
}
m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
return true;
}
IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale)
{
ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
int offsetY = 0;
int offsetX = 0;
IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) {
offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y();
if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0)
offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale;
}
IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get());
return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))),
max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale))));
}
bool WebPagePrivate::scheduleZoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering)
{
double scale;
if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
unscheduleZoomAboutPoint();
return false;
}
FloatPoint transformedAnchor = mapToTransformedFloatPoint(anchor);
FloatPoint transformedScrollPosition = mapToTransformedFloatPoint(scrollPosition());
m_backingStore->d->suspendScreenAndBackingStoreUpdates();
double zoomFraction = scale / transformationMatrix()->m11();
FloatPoint anchorOffset(transformedAnchor.x() - transformedScrollPosition.x(),
transformedAnchor.y() - transformedScrollPosition.y());
IntPoint srcPoint(
static_cast<int>(roundf(transformedAnchor.x() - anchorOffset.x() / zoomFraction)),
static_cast<int>(roundf(transformedAnchor.y() - anchorOffset.y() / zoomFraction)));
const IntRect viewportRect = IntRect(IntPoint::zero(), transformedViewportSize());
const IntRect dstRect = viewportRect;
IntRect srcRect(srcPoint.x(),
srcPoint.y(),
viewportRect.width() / zoomFraction,
viewportRect.height() / zoomFraction);
m_backingStore->d->blitContents(dstRect, srcRect);
m_delayedZoomArguments.scale = scale;
m_delayedZoomArguments.anchor = anchor;
m_delayedZoomArguments.enforceScaleClamping = enforceScaleClamping;
m_delayedZoomArguments.forceRendering = forceRendering;
m_delayedZoomTimer->startOneShot(delayedZoomInterval);
return true;
}
void WebPagePrivate::unscheduleZoomAboutPoint()
{
if (m_delayedZoomTimer->isActive())
m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
m_delayedZoomTimer->stop();
}
void WebPagePrivate::zoomAboutPointTimerFired(Timer<WebPagePrivate>*)
{
zoomAboutPoint(m_delayedZoomArguments.scale, m_delayedZoomArguments.anchor, m_delayedZoomArguments.enforceScaleClamping, m_delayedZoomArguments.forceRendering);
}
void WebPagePrivate::setNeedsLayout()
{
FrameView* view = m_mainFrame->view();
ASSERT(view);
view->setNeedsLayout();
}
void WebPagePrivate::requestLayoutIfNeeded() const
{
FrameView* view = m_mainFrame->view();
ASSERT(view);
view->updateLayoutAndStyleIfNeededRecursive();
ASSERT(!view->needsLayout());
}
IntPoint WebPagePrivate::scrollPosition() const
{
return m_backingStoreClient->scrollPosition();
}
IntPoint WebPagePrivate::maximumScrollPosition() const
{
return m_backingStoreClient->maximumScrollPosition();
}
void WebPagePrivate::setScrollPosition(const IntPoint& pos)
{
m_backingStoreClient->setScrollPosition(pos);
}
void WebPage::setScrollPosition(const Platform::IntPoint& point)
{
if (d->transformedPointEqualsUntransformedPoint(point, d->scrollPosition()))
return;
if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
d->m_userPerformedManualScroll = true;
d->m_backingStoreClient->setIsClientGeneratedScroll(true);
d->m_mainFrame->view()->setCanOverscroll(true);
d->setScrollPosition(d->mapFromTransformed(point));
d->m_mainFrame->view()->setCanOverscroll(false);
d->m_backingStoreClient->setIsClientGeneratedScroll(false);
}
bool WebPagePrivate::shouldSendResizeEvent()
{
if (!m_mainFrame->document())
return false;
static const bool unrestrictedResizeEvents = Platform::Settings::get()->unrestrictedResizeEvents();
if (unrestrictedResizeEvents)
return true;
DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
if (documentLoader && documentLoader->isLoadingInAPISense())
return false;
return true;
}
void WebPagePrivate::willDeferLoading()
{
m_deferredTasksTimer.stop();
m_client->willDeferLoading();
}
void WebPagePrivate::didResumeLoading()
{
if (!m_deferredTasks.isEmpty())
m_deferredTasksTimer.startOneShot(0);
m_client->didResumeLoading();
}
void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*)
{
ASSERT(!m_deferredTasks.isEmpty());
if (!m_deferredTasks.isEmpty())
return;
OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release();
m_deferredTasks.remove(0);
if (!m_deferredTasks.isEmpty())
m_deferredTasksTimer.startOneShot(0);
task->perform(this);
}
bool WebPagePrivate::scrollBy(int deltaX, int deltaY, bool scrollMainFrame)
{
IntSize delta(deltaX, deltaY);
if (!scrollMainFrame) {
IntSize copiedDelta(IntSize(abs(delta.width()), abs(delta.height())));
IntSize untransformedCopiedDelta = mapFromTransformed(copiedDelta);
delta = IntSize(
delta.width() < 0 ? -untransformedCopiedDelta.width() : untransformedCopiedDelta.width(),
delta.height() < 0 ? -untransformedCopiedDelta.height(): untransformedCopiedDelta.height());
if (m_inRegionScrollStartingNode) {
if (scrollNodeRecursively(m_inRegionScrollStartingNode.get(), delta)) {
m_selectionHandler->selectionPositionChanged();
return true;
}
}
return false;
}
setScrollPosition(scrollPosition() + delta);
return true;
}
bool WebPage::scrollBy(const Platform::IntSize& delta, bool scrollMainFrame)
{
d->m_backingStoreClient->setIsClientGeneratedScroll(true);
bool b = d->scrollBy(delta.width(), delta.height(), scrollMainFrame);
d->m_backingStoreClient->setIsClientGeneratedScroll(false);
return b;
}
void WebPagePrivate::notifyInRegionScrollStatusChanged(bool status)
{
if (!status && m_inRegionScrollStartingNode) {
enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(m_inRegionScrollStartingNode.get());
m_inRegionScrollStartingNode = 0;
}
}
void WebPage::notifyInRegionScrollStatusChanged(bool status)
{
d->notifyInRegionScrollStatusChanged(status);
}
void WebPagePrivate::enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(Node* scrolledNode)
{
ASSERT(scrolledNode);
if (scrolledNode->isDocumentNode()) {
Frame* frame = static_cast<const Document*>(scrolledNode)->frame();
ASSERT(frame);
if (!frame)
return;
ASSERT(frame != m_mainFrame);
FrameView* view = frame->view();
if (!view)
return;
FrameView* mainFrameView = m_mainFrame->view();
ASSERT(mainFrameView);
IntRect frameRect = view->frameRect();
frameRect = frame->tree()->parent()->view()->contentsToWindow(frameRect);
frameRect = mainFrameView->windowToContents(frameRect);
IntRect visibleWindowRect = getRecursiveVisibleWindowRect(view);
IntRect visibleContentsRect = mainFrameView->windowToContents(visibleWindowRect);
IntRect transformedFrameRect = mapToTransformed(frameRect);
IntRect transformedVisibleContentsRect = mapToTransformed(visibleContentsRect);
Platform::IntRectRegion offscreenRegionOfIframe
= Platform::IntRectRegion::subtractRegions(Platform::IntRect(transformedFrameRect), Platform::IntRect(transformedVisibleContentsRect));
if (!offscreenRegionOfIframe.isEmpty())
m_backingStore->d->m_renderQueue->addToQueue(RenderQueue::RegularRender, offscreenRegionOfIframe.rects());
}
}
void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
{
if (b != m_hasInRegionScrollableAreas)
m_hasInRegionScrollableAreas = b;
}
IntSize WebPagePrivate::viewportSize() const
{
return mapFromTransformed(transformedViewportSize());
}
IntSize WebPagePrivate::actualVisibleSize() const
{
return mapFromTransformed(transformedActualVisibleSize());
}
bool WebPagePrivate::hasVirtualViewport() const
{
return m_virtualViewportWidth && m_virtualViewportHeight;
}
void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
{
ASSERT(m_mainFrame->view());
if (setFixedReportedSize)
m_mainFrame->view()->setFixedReportedSize(actualVisibleSize());
IntRect frameRect = IntRect(scrollPosition(), viewportSize());
if (frameRect != m_mainFrame->view()->frameRect()) {
m_mainFrame->view()->setFrameRect(frameRect);
m_mainFrame->view()->adjustViewSize();
}
if (sendResizeEvent && shouldSendResizeEvent())
m_mainFrame->eventHandler()->sendResizeEvent();
m_mainFrame->view()->repaintFixedElementsAfterScrolling();
}
FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
{
FloatRect visibleContentsRect = this->visibleContentsRect();
return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
}
IntRect WebPagePrivate::visibleContentsRect() const
{
return m_backingStoreClient->visibleContentsRect();
}
IntSize WebPagePrivate::contentsSize() const
{
if (!m_mainFrame->view())
return IntSize();
return m_backingStoreClient->contentsSize();
}
IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
{
if (!m_mainFrame->contentRenderer())
return IntSize();
return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
}
void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
{
if (m_previousContentsSize == contentsSize)
return;
m_contentsSizeChanged = true;
#if DEBUG_WEBPAGE_LOAD
Platform::log(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %dx%d", contentsSize.width(), contentsSize.height());
#endif
}
void WebPagePrivate::layoutFinished()
{
if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
return;
m_contentsSizeChanged = false; m_overflowExceedsContentsSize = false;
if (contentsSize().isEmpty())
return;
if (didLayoutExceedMaximumIterations()) {
notifyTransformedContentsSizeChanged();
return;
}
IntSize previousContentsSize = m_previousContentsSize;
m_nestedLayoutFinishedCount++;
if (loadState() == Committed)
zoomToInitialScaleOnLoad();
else if (loadState() != None)
notifyTransformedContentsSizeChanged();
m_nestedLayoutFinishedCount--;
if (!m_nestedLayoutFinishedCount) {
if (contentsSize() != previousContentsSize) {
IntPoint newScrollPosition = scrollPosition();
if (contentsSize().height() < previousContentsSize.height()) {
IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
}
if (contentsSize().width() < previousContentsSize.width()) {
IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
}
if (newScrollPosition != scrollPosition()) {
setScrollPosition(newScrollPosition);
notifyTransformedScrollChanged();
}
}
}
}
void WebPagePrivate::zoomToInitialScaleOnLoad()
{
#if DEBUG_WEBPAGE_LOAD
Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
#endif
bool needsLayout = false;
if (m_shouldUseFixedDesktopMode)
needsLayout = setViewMode(FixedDesktop);
else
needsLayout = setViewMode(Desktop);
if (needsLayout) {
setNeedsLayout();
}
if (contentsSize().isEmpty()) {
#if DEBUG_WEBPAGE_LOAD
Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
#endif
requestLayoutIfNeeded();
m_client->resetBitmapZoomScale(currentScale());
notifyTransformedContentsSizeChanged();
return;
}
bool performedZoom = false;
bool shouldZoom = !m_userPerformedManualZoom;
if (m_mainFrame && m_mainFrame->loader() && m_mainFrame->loader()->shouldRestoreScrollPositionAndViewState())
shouldZoom = false;
if (shouldZoom && loadState() == Committed) {
FloatPoint anchor = centerOfVisibleContentsRect();
if (!scrollPosition().x())
anchor.setX(0);
if (!scrollPosition().y())
anchor.setY(0);
performedZoom = zoomAboutPoint(initialScale(), anchor);
}
requestLayoutIfNeeded();
if (!performedZoom) {
m_client->resetBitmapZoomScale(currentScale());
notifyTransformedContentsSizeChanged();
}
}
double WebPagePrivate::zoomToFitScale() const
{
int contentWidth = std::min(contentsSize().width(), std::max(m_virtualViewportWidth, static_cast<int>(defaultMaxLayoutSize().width())));
Document* doc = m_page->mainFrame()->document();
if (doc && doc->isImageDocument())
contentWidth = contentsSize().width();
if (hasVirtualViewport()) {
int contentHeight = std::min(contentsSize().height(), std::max(m_virtualViewportHeight, static_cast<int>(defaultMaxLayoutSize().height())));
if (contentWidth * m_defaultLayoutSize.height() > contentHeight * m_defaultLayoutSize.width())
return contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
}
return contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
}
double WebPage::zoomToFitScale() const
{
return d->zoomToFitScale();
}
double WebPagePrivate::initialScale() const
{
if (m_initialScale > 0.0)
return m_initialScale;
if (m_webSettings->isZoomToFitOnLoad())
return zoomToFitScale();
return 1.0;
}
double WebPage::initialScale() const
{
return d->initialScale();
}
void WebPage::initializeIconDataBase()
{
IconDatabaseClientBlackBerry::getInstance()->initIconDatabase(d->m_webSettings);
}
bool WebPage::isUserScalable() const
{
return d->isUserScalable();
}
void WebPage::setUserScalable(bool userScalable)
{
d->setUserScalable(userScalable);
}
double WebPage::currentScale() const
{
return d->currentScale();
}
void WebPage::setInitialScale(double initialScale)
{
d->setInitialScale(initialScale);
}
double WebPage::minimumScale() const
{
return d->minimumScale();
}
void WebPage::setMinimumScale(double minimumScale)
{
d->setMinimumScale(minimumScale);
}
void WebPage::setMaximumScale(double maximumScale)
{
d->setMaximumScale(maximumScale);
}
double WebPagePrivate::maximumScale() const
{
if (m_maximumScale >= zoomToFitScale() && m_maximumScale >= m_minimumScale)
return m_maximumScale;
return hasVirtualViewport() ? std::max<double>(zoomToFitScale(), 4.0) : 4.0;
}
double WebPage::maximumScale() const
{
return d->maximumScale();
}
void WebPagePrivate::resetScales()
{
TransformationMatrix identity;
*m_transformationMatrix = identity;
m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0;
m_minimumScale = -1.0;
m_maximumScale = -1.0;
updateViewportSize();
}
IntPoint WebPagePrivate::transformedScrollPosition() const
{
return m_backingStoreClient->transformedScrollPosition();
}
Platform::IntPoint WebPage::scrollPosition() const
{
return d->transformedScrollPosition();
}
IntPoint WebPagePrivate::transformedMaximumScrollPosition() const
{
return m_backingStoreClient->transformedMaximumScrollPosition();
}
IntSize WebPagePrivate::transformedActualVisibleSize() const
{
return IntSize(m_actualVisibleWidth, m_actualVisibleHeight);
}
Platform::IntSize WebPage::viewportSize() const
{
return d->transformedActualVisibleSize();
}
IntSize WebPagePrivate::transformedViewportSize() const
{
return Platform::Graphics::Screen::primaryScreen()->size();
}
IntRect WebPagePrivate::transformedVisibleContentsRect() const
{
return IntRect(transformedScrollPosition(), transformedViewportSize());
}
IntSize WebPagePrivate::transformedContentsSize() const
{
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);
}
static inline IntPoint roundTransformedPoint(const FloatPoint &point)
{
return IntPoint(static_cast<int>(floorf(point.x())), static_cast<int>(floorf(point.y())));
}
static inline IntPoint roundUntransformedPoint(const FloatPoint &point)
{
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)));
}
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)
{
if (m_transformationMatrix->a() > 1.0)
return transformedPoint == mapToTransformed(untransformedPoint);
return mapFromTransformed(transformedPoint) == untransformedPoint;
}
void WebPagePrivate::notifyTransformChanged()
{
notifyTransformedContentsSizeChanged();
notifyTransformedScrollChanged();
m_backingStore->d->transformChanged();
}
void WebPagePrivate::notifyTransformedContentsSizeChanged()
{
m_previousContentsSize = contentsSize();
const IntSize size = transformedContentsSize();
m_backingStore->d->contentsSizeChanged(size);
m_client->contentsSizeChanged(size);
m_selectionHandler->selectionPositionChanged();
}
void WebPagePrivate::notifyTransformedScrollChanged()
{
const IntPoint pos = transformedScrollPosition();
m_backingStore->d->scrollChanged(pos);
m_client->scrollChanged(pos);
}
bool WebPagePrivate::setViewMode(ViewMode mode)
{
if (!m_mainFrame->view())
return false;
m_viewMode = mode;
bool snapToIncrement = didLayoutExceedMaximumIterations();
IntSize currentSize = m_mainFrame->view()->fixedLayoutSize();
IntSize newSize = fixedLayoutSize(snapToIncrement);
if (currentSize == newSize)
return false;
if (m_nestedLayoutFinishedCount) {
double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width());
double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height());
if (widthChange < 0.05 && heightChange < 0.05)
return false;
}
m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
m_mainFrame->view()->setFixedLayoutSize(newSize);
return true; }
void WebPagePrivate::setCursor(PlatformCursor handle)
{
if (m_currentCursor.type() != handle.type()) {
m_currentCursor = handle;
m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot().x(), handle.hotspot().y());
}
}
Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory()
{
return m_client->networkStreamFactory();
}
Platform::Graphics::Window* WebPagePrivate::platformWindow() const
{
return m_client->window();
}
void WebPagePrivate::setPreventsScreenDimming(bool keepAwake)
{
if (keepAwake) {
if (!m_preventIdleDimmingCount)
m_client->setPreventsScreenIdleDimming(true);
m_preventIdleDimmingCount++;
} else if (m_preventIdleDimmingCount > 0) {
m_preventIdleDimmingCount--;
if (!m_preventIdleDimmingCount)
m_client->setPreventsScreenIdleDimming(false);
} else
ASSERT_NOT_REACHED(); }
void WebPagePrivate::showVirtualKeyboard(bool showKeyboard)
{
m_client->showVirtualKeyboard(showKeyboard);
}
void WebPagePrivate::ensureContentVisible(bool centerInView)
{
m_inputHandler->ensureFocusElementVisible(centerInView);
}
void WebPagePrivate::zoomToContentRect(const IntRect& rect)
{
if (!isUserScalable())
return;
FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y());
IntSize viewSize = viewportSize();
double scaleH = (double)viewSize.width() / (double)rect.width();
double scaleV = (double)viewSize.height() / (double)rect.height();
zoomAboutPoint(min(scaleH, scaleV), anchor);
}
void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister)
{
if (shouldRegister)
m_pluginViews.add(plugin);
else
m_pluginViews.remove(plugin);
}
#define FOR_EACH_PLUGINVIEW(pluginViews) \
HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \
HashSet<PluginView*>::const_iterator last = pluginViews.end(); \
for (; it != last; ++it)
void WebPagePrivate::notifyPageOnLoad()
{
FOR_EACH_PLUGINVIEW(m_pluginViews)
(*it)->handleOnLoadEvent();
}
bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
{
return m_client->shouldPluginEnterFullScreen();
}
void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
{
m_fullScreenPluginView = plugin;
m_client->didPluginEnterFullScreen();
if (!m_client->window())
return;
Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix);
m_client->window()->setSensitivityFullscreenOverride(true);
}
void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* windowUniquePrefix)
{
m_fullScreenPluginView = 0;
m_client->didPluginExitFullScreen();
if (!m_client->window())
return;
Platform::Graphics::Window::setTransparencyDiscardFilter(0);
m_client->window()->setSensitivityFullscreenOverride(false);
}
void WebPagePrivate::onPluginStartBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
{
m_client->onPluginStartBackgroundPlay();
}
void WebPagePrivate::onPluginStopBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
{
m_client->onPluginStopBackgroundPlay();
}
bool WebPagePrivate::lockOrientation(bool landscape)
{
return m_client->lockOrientation(landscape);
}
void WebPagePrivate::unlockOrientation()
{
return m_client->unlockOrientation();
}
int WebPagePrivate::orientation() const
{
#if ENABLE(ORIENTATION_EVENTS)
return m_mainFrame->orientation();
#else
#error ORIENTATION_EVENTS must be defined.
#endif
}
double WebPagePrivate::currentZoomFactor() const
{
return currentScale();
}
int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype)
{
return m_client->showAlertDialog(atype);
}
bool WebPagePrivate::isActive() const
{
return m_client->isActive();
}
Credential WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSpace& protectionSpace)
{
WebString username;
WebString password;
#if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
if (!m_webSettings->isPrivateBrowsingEnabled())
credentialManager().autofillAuthenticationChallenge(protectionSpace, username, password);
#endif
m_client->authenticationChallenge(protectionSpace.realm().characters(), protectionSpace.realm().length(), username, password);
#if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
Credential inputCredential(username, password, CredentialPersistencePermanent);
if (!m_webSettings->isPrivateBrowsingEnabled())
credentialManager().saveCredentialIfConfirmed(this, CredentialTransformData(url, protectionSpace, inputCredential));
#else
Credential inputCredential(username, password, CredentialPersistenceNone);
#endif
return inputCredential;
}
PageClientBlackBerry::SaveCredentialType WebPagePrivate::notifyShouldSaveCredential(bool isNew)
{
return static_cast<PageClientBlackBerry::SaveCredentialType>(m_client->notifyShouldSaveCredential(isNew));
}
bool WebPagePrivate::useFixedLayout() const
{
return true;
}
Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy)
{
Platform::WebContext context;
RefPtr<Node> node = contextNode(strategy);
m_currentContextNode = node;
if (!m_currentContextNode)
return context;
requestLayoutIfNeeded();
bool nodeAllowSelectionOverride = false;
if (Node* linkNode = node->enclosingLinkEventParentOrSelf()) {
KURL href;
if (linkNode->isLink() && linkNode->hasAttributes()) {
if (Attribute* attribute = static_cast<Element*>(linkNode)->getAttributeItem(HTMLNames::hrefAttr))
href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
}
String pattern = findPatternStringForUrl(href);
if (!pattern.isEmpty())
context.setPattern(pattern.utf8().data());
if (!href.string().isEmpty()) {
context.setUrl(href.string().utf8().data());
if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
nodeAllowSelectionOverride = true;
}
}
if (!nodeAllowSelectionOverride && !node->canStartSelection())
context.resetFlag(Platform::WebContext::IsSelectable);
if (node->isHTMLElement()) {
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 (static_cast<HTMLElement*>(node.get())->isMediaElement())
mediaElement = static_cast<HTMLMediaElement*>(node.get());
if (imageElement && imageElement->renderer()) {
context.setFlag(Platform::WebContext::IsImage);
if (CachedResource* cachedResource = imageElement->cachedImage()) {
if (cachedResource->isLoaded() && cachedResource->data()) {
String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
context.setSrc(node->document()->completeURL(url).string().utf8().data());
}
}
String alt = imageElement->altText();
if (!alt.isNull())
context.setAlt(alt.utf8().data());
}
if (mediaElement) {
if (mediaElement->hasAudio())
context.setFlag(Platform::WebContext::IsAudio);
if (mediaElement->hasVideo())
context.setFlag(Platform::WebContext::IsVideo);
String src = stripLeadingAndTrailingHTMLSpaces(mediaElement->getAttribute(HTMLNames::srcAttr).string());
context.setSrc(node->document()->completeURL(src).string().utf8().data());
}
}
if (node->isTextNode()) {
Text* curText = static_cast<Text*>(node.get());
if (!curText->wholeText().isEmpty())
context.setText(curText->wholeText().utf8().data());
}
if (node->isElementNode()) {
Element* element = static_cast<Element*>(node->shadowAncestorNode());
if (DOMSupport::isTextBasedContentEditableElement(element)) {
context.setFlag(Platform::WebContext::IsInput);
if (element->hasTagName(HTMLNames::inputTag))
context.setFlag(Platform::WebContext::IsSingleLine);
if (DOMSupport::isPasswordElement(element))
context.setFlag(Platform::WebContext::IsPassword);
String elementText(DOMSupport::inputElementText(element));
if (!elementText.stripWhiteSpace().isEmpty())
context.setText(elementText.utf8().data());
}
}
if (node->isFocusable())
context.setFlag(Platform::WebContext::IsFocusable);
return context;
}
Platform::WebContext WebPage::webContext(TargetDetectionStrategy strategy) const
{
return d->webContext(strategy);
}
void WebPagePrivate::updateCursor()
{
int buttonMask = 0;
if (m_lastMouseEvent.button() == LeftButton)
buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
else if (m_lastMouseEvent.button() == MiddleButton)
buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
else if (m_lastMouseEvent.button() == RightButton)
buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask, mapToTransformed(m_lastMouseEvent.position()), mapToTransformed(m_lastMouseEvent.globalPosition()), 0, 0);
m_webPage->mouseEvent(event);
}
IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
{
if (hasVirtualViewport())
return IntSize(m_virtualViewportWidth, m_virtualViewportHeight);
const int defaultLayoutWidth = m_defaultLayoutSize.width();
const int defaultLayoutHeight = m_defaultLayoutSize.height();
int minWidth = defaultLayoutWidth;
int maxWidth = defaultMaxLayoutSize().width();
int maxHeight = defaultMaxLayoutSize().height();
if (m_loadState == None)
return IntSize(defaultLayoutWidth, defaultLayoutHeight);
if (m_viewMode == FixedDesktop) {
int width = maxWidth;
int height;
if (defaultLayoutHeight <= minimumLayoutSize.height())
height = maxHeight;
else
height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
return IntSize(width, height);
}
if (m_viewMode == Desktop) {
int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
if (snapToIncrement) {
float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
factor = ceilf(factor);
width = (defaultLayoutWidth / 2.0) * factor;
}
if (width < minWidth)
width = minWidth;
if (width > maxWidth)
width = maxWidth;
int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
return IntSize(width, height);
}
if (m_webSettings->isZoomToFitOnLoad()) {
if (m_mainFrame->view() && !contentsSize().isEmpty())
minWidth = contentsSize().width();
else {
#if ENABLE(ORIENTATION_EVENTS)
minWidth = m_mainFrame->orientation() % 180
? Platform::Graphics::Screen::primaryScreen()->height()
: Platform::Graphics::Screen::primaryScreen()->width();
#else
minWidth = Platform::Graphics::Screen::primaryScreen()->width();
#endif
}
}
return IntSize(std::min(minWidth, defaultLayoutWidth), defaultLayoutHeight);
}
BackingStoreClient* WebPagePrivate::backingStoreClientForFrame(const Frame* frame) const
{
ASSERT(frame);
BackingStoreClient* backingStoreClient = 0;
if (m_backingStoreClientForFrameMap.contains(frame))
backingStoreClient = m_backingStoreClientForFrameMap.get(frame);
return backingStoreClient;
}
void WebPagePrivate::addBackingStoreClientForFrame(const Frame* frame, BackingStoreClient* client)
{
ASSERT(frame);
ASSERT(client);
m_backingStoreClientForFrameMap.add(frame, client);
}
void WebPagePrivate::removeBackingStoreClientForFrame(const Frame* frame)
{
ASSERT(frame);
if (m_backingStoreClientForFrameMap.contains(frame))
m_backingStoreClientForFrameMap.remove(frame);
}
void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
{
ASSERT(documentGoingAway);
if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
m_currentContextNode = 0;
if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
m_currentPinchZoomNode = 0;
if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
m_currentBlockZoomAdjustedNode = 0;
if (m_inRegionScrollStartingNode && m_inRegionScrollStartingNode->document() == documentGoingAway)
m_inRegionScrollStartingNode = 0;
Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
m_touchEventHandler->resetLastFatFingersResult();
}
typedef bool (*PredicateFunction)(RenderLayer*);
static bool isPositionedContainer(RenderLayer* layer)
{
RenderObject* o = layer->renderer();
return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform();
}
static bool isNonRenderViewFixedPositionedContainer(RenderLayer* layer)
{
RenderObject* o = layer->renderer();
if (o->isRenderView())
return false;
return o->isPositioned() && o->style()->position() == FixedPosition;
}
static bool isFixedPositionedContainer(RenderLayer* layer)
{
RenderObject* o = layer->renderer();
return o->isRenderView() || (o->isPositioned() && o->style()->position() == FixedPosition);
}
static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
{
RenderLayer* curr = layer;
while (curr && !predicate(curr))
curr = curr->parent();
return curr;
}
RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
{
return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
}
RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
{
return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
}
static inline Frame* frameForNode(Node* node)
{
Node* origNode = node;
for (; node; node = node->parentNode()) {
if (RenderObject* renderer = node->renderer()) {
if (renderer->isRenderView()) {
if (FrameView* view = toRenderView(renderer)->frameView()) {
if (Frame* frame = view->frame())
return frame;
}
}
if (renderer->isWidget()) {
Widget* widget = toRenderWidget(renderer)->widget();
if (widget && widget->isFrameView()) {
if (Frame* frame = static_cast<FrameView*>(widget)->frame())
return frame;
}
}
}
}
for (node = origNode; node; node = node->parentNode()) {
if (Document* doc = node->document()) {
if (Frame* frame = doc->frame())
return frame;
}
}
return 0;
}
static IntRect getNodeWindowRect(Node* node)
{
if (Frame* frame = frameForNode(node)) {
if (FrameView* view = frame->view())
return view->contentsToWindow(node->getRect());
}
ASSERT_NOT_REACHED();
return IntRect();
}
IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
{
ASSERT(m_mainFrame);
if (noClipOfMainFrame && view == m_mainFrame->view()) {
ASSERT_NOT_REACHED();
return IntRect(IntPoint::zero(), view->contentsSize());
}
IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect(false)));
if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
}
return visibleWindowRect;
}
void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
{
ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
clearFocusNode();
switch (direction) {
case FocusDirectionForward:
case FocusDirectionBackward:
m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
break;
case FocusDirectionNone:
break;
default:
ASSERT_NOT_REACHED();
}
}
void WebPage::assignFocus(Platform::FocusDirection direction)
{
if (d->m_page->defersLoading())
return;
d->assignFocus(direction);
}
Platform::IntRect WebPagePrivate::focusNodeRect()
{
Frame* frame = focusedOrMainFrame();
if (!frame)
return Platform::IntRect();
Document* doc = frame->document();
FrameView* view = frame->view();
if (!doc || !view || view->needsLayout())
return Platform::IntRect();
IntRect focusRect = rectForNode(doc->focusedNode());
focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
focusRect = mapToTransformed(focusRect);
clipToTransformedContentsRect(focusRect);
return focusRect;
}
PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
{
EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
if (eventHandler->mousePressed())
eventHandler->setMousePressed(false);
if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
RefPtr<Node> node;
node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
if (node) {
IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
if (!visibleRect.intersects(getNodeWindowRect(node.get())))
return 0;
}
return node.release();
}
if (isTouching && lastFatFingersResult.isTextInput())
return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
IntPoint contentPos;
if (isTouching)
contentPos = lastFatFingersResult.adjustedPosition();
else
contentPos = mapFromViewportToContents(m_lastMouseEvent.position());
if (strategy == RectBased) {
FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
return result.node(FatFingersResult::ShadowContentNotAllowed);
}
HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos, false );
return result.innerNode();
}
static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
{
double dx = static_cast<double>(p1.x() - p2.x());
double dy = static_cast<double>(p1.y() - p2.y());
return sqrt((dx * dx) + (dy * dy));
}
Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& point)
{
IntPoint pt = mapFromTransformed(point);
IntRect clickRect(pt.x() - blockClickRadius, pt.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
Node* originalNode = nodeForZoomUnderPoint(point);
if (!originalNode)
return 0;
Node* node = bestChildNodeForClickRect(originalNode, clickRect);
return node ? adjustedBlockZoomNodeForZoomLimits(node) : adjustedBlockZoomNodeForZoomLimits(originalNode);
}
Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
{
if (!parentNode)
return 0;
int bestDistance = std::numeric_limits<int>::max();
Node* node = parentNode->firstChild();
Node* bestNode = 0;
for (; node; node = node->nextSibling()) {
IntRect rect = rectForNode(node);
if (!clickRect.intersects(rect))
continue;
int distance = distanceBetweenPoints(rect.center(), clickRect.center());
Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
if (bestChildNode) {
IntRect bestChildRect = rectForNode(bestChildNode);
int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
if (bestChildDistance < distance && bestChildDistance < bestDistance) {
bestNode = bestChildNode;
bestDistance = bestChildDistance;
} else {
if (distance < bestDistance) {
bestNode = node;
bestDistance = distance;
}
}
} else {
if (distance < bestDistance) {
bestNode = node;
bestDistance = distance;
}
}
}
return bestNode;
}
double WebPagePrivate::maxBlockZoomScale() const
{
return std::min(maximumBlockZoomScale, maximumScale());
}
Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& point)
{
if (!m_mainFrame)
return 0;
HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromTransformed(point), false);
Node* node = result.innerNonSharedNode();
if (!node)
return 0;
RenderObject* renderer = node->renderer();
while (!renderer) {
node = node->parentNode();
renderer = node->renderer();
}
return node;
}
Node* WebPagePrivate::adjustedBlockZoomNodeForZoomLimits(Node* node)
{
Node* initialNode = node;
RenderObject* renderer = node->renderer();
bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
while (!renderer || !acceptableNodeSize) {
node = node->parentNode();
if (!node)
return initialNode;
renderer = node->renderer();
acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
}
if (initialNode != node) {
IntRect nodeRect = rectForNode(node);
nodeRect = adjustRectOffsetForFrameOffset(nodeRect, node);
nodeRect.intersect(IntRect(IntPoint::zero(), contentsSize()));
int nodeArea = nodeRect.width() * nodeRect.height();
int pageArea = contentsSize().width() * contentsSize().height();
if (static_cast<double>(pageArea - nodeArea) / pageArea < minimumExpandingRatio)
return initialNode;
}
return node;
}
bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
{
if (!n1 || !n2)
return false;
return (n2 == n1) || n2->isDescendantOf(n1);
}
double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
{
if (rect.isEmpty())
return std::numeric_limits<double>::max();
ASSERT(rect.width() + margin);
double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
return newScale;
}
IntRect WebPagePrivate::rectForNode(Node* node)
{
if (!node)
return IntRect();
RenderObject* renderer = node->renderer();
if (!renderer)
return IntRect();
IntRect blockRect;
if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
RenderBlock* renderBlock = renderer->containingBlock();
int xOffset = 0;
int yOffset = 0;
while (!renderBlock->isRoot()) {
xOffset += renderBlock->x();
yOffset += renderBlock->y();
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();
if (renderer->isText()) {
RenderBlock* rb = renderer->containingBlock();
int blockWidth = 0;
int lineCount = rb->lineCount();
for (int i = 0; i < lineCount; i++)
blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false));
blockRect.setWidth(blockWidth);
blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
}
if (renderer->style()->hasPadding()) {
blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
}
return blockRect;
}
IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
{
ASSERT(frame);
if (!mainFrame())
return IntPoint();
return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
}
IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
{
if (!node)
return rect;
const Node* tnode = node;
IntRect adjustedRect = rect;
do {
Frame* frame = tnode->document()->frame();
if (!frame)
continue;
Node* ownerNode = static_cast<Node*>(frame->ownerElement());
tnode = ownerNode;
if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
IntRect iFrameRect;
do {
iFrameRect = rectForNode(ownerNode);
adjustedRect.move(iFrameRect.x(), iFrameRect.y());
adjustedRect.intersect(iFrameRect);
ownerNode = ownerNode->parentNode();
} while (iFrameRect.isEmpty() && ownerNode);
} else
break;
} while (tnode = tnode->parentNode());
return adjustedRect;
}
IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
{
if (!node || contentsSize().isEmpty())
return IntRect();
Node* tnode = node;
m_currentBlockZoomAdjustedNode = tnode;
IntRect blockRect = rectForNode(tnode);
IntRect originalRect = blockRect;
int originalArea = originalRect.width() * originalRect.height();
int pageArea = contentsSize().width() * contentsSize().height();
double blockToPageRatio = static_cast<double>(pageArea - originalArea) / pageArea;
double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
while (tnode = tnode->parentNode()) {
ASSERT(tnode);
IntRect tRect = rectForNode(tnode);
int tempBlockArea = tRect.width() * tRect.height();
if (static_cast<double>(pageArea - tempBlockArea) / pageArea < minimumExpandingRatio)
break;
if (tRect.isEmpty())
continue; if (tempBlockArea < 1.1 * originalArea)
continue; IntSize actualSize = actualVisibleSize();
if (static_cast<double>(actualSize.width() - tRect.width()) / actualSize.width() < minimumExpandingRatio)
break;
if (tempBlockArea < blockExpansionRatio * originalArea) {
blockRect = tRect;
m_currentBlockZoomAdjustedNode = tnode;
} else
break;
}
}
blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
blockRect = mapToTransformed(blockRect);
clipToTransformedContentsRect(blockRect);
#if DEBUG_BLOCK_ZOOM
m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::Blit);
originalRect = mapToTransformed(originalRect);
clipToTransformedContentsRect(originalRect);
IntRect renderRect = mapFromTransformedContentsToTransformedViewport(blockRect);
IntRect originalRenderRect = mapFromTransformedContentsToTransformedViewport(originalRect);
IntSize viewportSize = transformedViewportSize();
renderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
originalRenderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
m_backingStore->d->clearWindow(renderRect, 0, 0, 0);
m_backingStore->d->clearWindow(originalRenderRect, 120, 120, 120);
m_backingStore->d->invalidateWindow(renderRect);
#endif
return blockRect;
}
void WebPagePrivate::zoomBlock()
{
if (!m_mainFrame)
return;
IntPoint anchor(roundUntransformedPoint(mapFromTransformedFloatPoint(m_finalBlockPoint)));
bool willUseTextReflow = false;
#if ENABLE(VIEWPORT_REFLOW)
willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
setNeedsLayout();
#endif
TransformationMatrix zoom;
zoom.scale(m_blockZoomFinalScale);
*m_transformationMatrix = zoom;
m_client->resetBitmapZoomScale(m_blockZoomFinalScale);
m_backingStore->d->suspendScreenAndBackingStoreUpdates();
updateViewportSize();
#if ENABLE(VIEWPORT_REFLOW)
requestLayoutIfNeeded();
if (willUseTextReflow && m_shouldReflowBlock) {
IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
reflowedRect.move(roundTransformedPoint(m_finalBlockPointReflowOffset).x(), roundTransformedPoint(m_finalBlockPointReflowOffset).y());
RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
IntPoint topLeftPoint(reflowedRect.location());
if (renderer && renderer->isText()) {
ETextAlign textAlign = renderer->style()->textAlign();
IntPoint textAnchor;
switch (textAlign) {
case CENTER:
case WEBKIT_CENTER:
textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
break;
case LEFT:
case WEBKIT_LEFT:
textAnchor = topLeftPoint;
break;
case RIGHT:
case WEBKIT_RIGHT:
textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
break;
case TAAUTO:
case JUSTIFY:
default:
if (renderer->style()->isLeftToRightDirection())
textAnchor = topLeftPoint;
else
textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
break;
}
setScrollPosition(textAnchor);
} else {
renderer->style()->isLeftToRightDirection()
? setScrollPosition(topLeftPoint)
: setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
}
} else if (willUseTextReflow) {
IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
setScrollPosition(IntPoint(0, finalRect.y() + m_finalBlockPointReflowOffset.y()));
resetBlockZoom();
}
#endif
if (!willUseTextReflow) {
setScrollPosition(anchor);
if (!m_shouldReflowBlock)
resetBlockZoom();
}
notifyTransformChanged();
m_backingStore->d->clearWindow();
m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
}
void WebPage::blockZoomAnimationFinished()
{
d->zoomBlock();
}
void WebPagePrivate::resetBlockZoom()
{
m_currentBlockZoomNode = 0;
m_currentBlockZoomAdjustedNode = 0;
m_shouldReflowBlock = false;
}
void WebPage::destroyWebPageCompositor()
{
#if USE(ACCELERATED_COMPOSITING)
d->syncDestroyCompositorOnCompositingThread();
#endif
}
void WebPage::destroy()
{
d->m_backingStore->d->suspendScreenAndBackingStoreUpdates();
d->m_page->backForward()->close();
pageCache()->releaseAutoreleasedPagesNow();
FrameLoader* loader = d->m_mainFrame->loader();
d->removeBackingStoreClientForFrame(d->m_mainFrame);
d->m_mainFrame = 0;
if (loader)
loader->detachFromParent();
deleteGuardedObject(this);
}
WebPageClient* WebPage::client() const
{
return d->m_client;
}
int WebPage::backForwardListLength() const
{
return d->m_page->getHistoryLength();
}
bool WebPage::canGoBackOrForward(int delta) const
{
return d->m_page->canGoBackOrForward(delta);
}
bool WebPage::goBackOrForward(int delta)
{
if (d->m_page->canGoBackOrForward(delta)) {
d->m_page->goBackOrForward(delta);
return true;
}
return false;
}
void WebPage::goToBackForwardEntry(BackForwardId id)
{
HistoryItem* item = historyItemFromBackForwardId(id);
ASSERT(item);
d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
}
void WebPage::reload()
{
d->m_mainFrame->loader()->reload( true);
}
void WebPage::reloadFromCache()
{
d->m_mainFrame->loader()->reload( false);
}
WebSettings* WebPage::settings() const
{
return d->m_webSettings;
}
bool WebPage::isVisible() const
{
return d->m_visible;
}
#if ENABLE(PAGE_VISIBILITY_API)
class DeferredTaskSetPageVisibilityState: public DeferredTask<&WebPagePrivate::m_wouldSetPageVisibilityState> {
public:
explicit DeferredTaskSetPageVisibilityState(WebPagePrivate* webPagePrivate)
: DeferredTaskType(webPagePrivate)
{
}
private:
virtual void performInternal(WebPagePrivate* webPagePrivate)
{
webPagePrivate->setPageVisibilityState();
}
};
void WebPagePrivate::setPageVisibilityState()
{
if (m_page->defersLoading())
m_deferredTasks.append(adoptPtr(new DeferredTaskSetPageVisibilityState(this)));
else {
DeferredTaskSetPageVisibilityState::finishOrCancel(this);
static bool s_initialVisibilityState = true;
m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
s_initialVisibilityState = false;
}
}
#endif
void WebPagePrivate::setVisible(bool visible)
{
m_visible = visible;
#if ENABLE(PAGE_VISIBILITY_API)
setPageVisibilityState();
#endif
}
void WebPage::setVisible(bool visible)
{
if (d->m_visible == visible)
return;
d->setVisible(visible);
if (!visible) {
d->suspendBackingStore();
size_t foundIndex = visibleWebPages()->find(this);
if (foundIndex != WTF::notFound)
visibleWebPages()->remove(foundIndex);
if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
visibleWebPages()->last()->d->resumeBackingStore();
#if USE(ACCELERATED_COMPOSITING)
d->suspendRootLayerCommit();
#endif
return;
}
#if USE(ACCELERATED_COMPOSITING)
d->resumeRootLayerCommit();
#endif
if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
size_t foundIndex = visibleWebPages()->find(this);
if (foundIndex != WTF::notFound)
visibleWebPages()->remove(foundIndex);
}
visibleWebPages()->append(this);
if (BackingStorePrivate::currentBackingStoreOwner()
&& BackingStorePrivate::currentBackingStoreOwner() != this)
BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
d->resumeBackingStore();
}
void WebPagePrivate::selectionChanged(Frame* frame)
{
m_inputHandler->selectionChanged();
m_page->focusController()->setFocusedFrame(frame);
}
void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
{
if (dispatched)
m_updateDelegatedOverlaysDispatched = false;
else if (m_updateDelegatedOverlaysDispatched) {
return;
}
if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
if (m_selectionHandler->isSelectionActive())
m_selectionHandler->selectionPositionChanged(true );
} else if (m_selectionHandler->isSelectionActive()) {
m_updateDelegatedOverlaysDispatched = true;
Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true ));
}
}
void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle style)
{
}
bool WebPage::setBatchEditingActive(bool active)
{
return d->m_inputHandler->setBatchEditingActive(active);
}
bool WebPage::setInputSelection(unsigned start, unsigned end)
{
if (d->m_page->defersLoading())
return false;
return d->m_inputHandler->setSelection(start, end);
}
int WebPage::inputCaretPosition() const
{
return d->m_inputHandler->caretPosition();
}
class DeferredTaskPopupListSelectMultiple: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectMultiple> {
public:
DeferredTaskPopupListSelectMultiple(WebPagePrivate* webPagePrivate, int size, const bool* selecteds)
: DeferredTaskType(webPagePrivate)
{
webPagePrivate->m_cachedPopupListSelecteds.append(selecteds, size);
}
private:
virtual void performInternal(WebPagePrivate* webPagePrivate)
{
webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelecteds.size(), webPagePrivate->m_cachedPopupListSelecteds.data());
}
};
class DeferredTaskPopupListSelectSingle: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectSingle> {
public:
explicit DeferredTaskPopupListSelectSingle(WebPagePrivate* webPagePrivate, int index)
: DeferredTaskType(webPagePrivate)
{
webPagePrivate->m_cachedPopupListSelectedIndex = index;
}
private:
virtual void performInternal(WebPagePrivate* webPagePrivate)
{
webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelectedIndex);
}
};
void WebPage::popupListClosed(int size, const bool* selecteds)
{
DeferredTaskPopupListSelectSingle::finishOrCancel(d);
if (d->m_page->defersLoading()) {
d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectMultiple(d, size, selecteds)));
return;
}
DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
d->m_inputHandler->setPopupListIndexes(size, selecteds);
}
void WebPage::popupListClosed(int index)
{
DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
if (d->m_page->defersLoading()) {
d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectSingle(d, index)));
return;
}
DeferredTaskPopupListSelectSingle::finishOrCancel(d);
d->m_inputHandler->setPopupListIndex(index);
}
class DeferredTaskSetDateTimeInput: public DeferredTask<&WebPagePrivate::m_wouldSetDateTimeInput> {
public:
explicit DeferredTaskSetDateTimeInput(WebPagePrivate* webPagePrivate, WebString value)
: DeferredTaskType(webPagePrivate)
{
webPagePrivate->m_cachedDateTimeInput = value;
}
private:
virtual void performInternal(WebPagePrivate* webPagePrivate)
{
webPagePrivate->m_webPage->setDateTimeInput(webPagePrivate->m_cachedDateTimeInput);
}
};
void WebPage::setDateTimeInput(const WebString& value)
{
if (d->m_page->defersLoading()) {
d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetDateTimeInput(d, value)));
return;
}
DeferredTaskSetDateTimeInput::finishOrCancel(d);
d->m_inputHandler->setInputValue(String(value.impl()));
}
class DeferredTaskSetColorInput: public DeferredTask<&WebPagePrivate::m_wouldSetColorInput> {
public:
explicit DeferredTaskSetColorInput(WebPagePrivate* webPagePrivate, WebString value)
: DeferredTaskType(webPagePrivate)
{
webPagePrivate->m_cachedColorInput = value;
}
private:
virtual void performInternal(WebPagePrivate* webPagePrivate)
{
webPagePrivate->m_webPage->setColorInput(webPagePrivate->m_cachedColorInput);
}
};
void WebPage::setColorInput(const WebString& value)
{
if (d->m_page->defersLoading()) {
d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetColorInput(d, value)));
return;
}
DeferredTaskSetColorInput::finishOrCancel(d);
d->m_inputHandler->setInputValue(String(value.impl()));
}
void WebPage::setVirtualViewportSize(int width, int height)
{
d->m_virtualViewportWidth = width;
d->m_virtualViewportHeight = height;
}
void WebPage::resetVirtualViewportOnCommitted(bool reset)
{
d->m_resetVirtualViewportOnCommitted = reset;
}
IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments()
{
static const ViewportArguments defaultViewportArguments;
if (m_viewportArguments == defaultViewportArguments)
return IntSize();
int desktopWidth = defaultMaxLayoutSize().width();
int deviceWidth = Platform::Graphics::Screen::primaryScreen()->width();
int deviceHeight = Platform::Graphics::Screen::primaryScreen()->height();
FloatSize currentPPI = Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(-1);
int deviceDPI = int(roundf((currentPPI.width() + currentPPI.height()) / 2));
if (m_viewportArguments.targetDensityDpi == ViewportArguments::ValueAuto
&& !Platform::DeviceInfo::instance()->isMobile()) {
m_viewportArguments.targetDensityDpi = deviceDPI;
}
ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, deviceDPI, m_defaultLayoutSize);
m_page->setDeviceScaleFactor(result.devicePixelRatio);
return IntSize(result.layoutSize.width(), result.layoutSize.height());
}
#if ENABLE(EVENT_MODE_METATAGS)
void WebPagePrivate::didReceiveCursorEventMode(CursorEventMode mode)
{
if (mode != m_cursorEventMode)
m_client->cursorEventModeChanged(toPlatformCursorEventMode(mode));
m_cursorEventMode = mode;
}
void WebPagePrivate::didReceiveTouchEventMode(TouchEventMode mode)
{
if (mode != m_touchEventMode)
m_client->touchEventModeChanged(toPlatformTouchEventMode(mode));
m_touchEventMode = mode;
}
#endif
void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments)
{
static ViewportArguments defaultViewportArguments;
if (arguments == defaultViewportArguments)
return;
m_viewportArguments = arguments;
if (!m_viewportArguments.width)
m_viewportArguments.width = ViewportArguments::ValueDeviceWidth;
if (!m_viewportArguments.height)
m_viewportArguments.height = ViewportArguments::ValueDeviceHeight;
setUserScalable(arguments.userScalable == ViewportArguments::ValueAuto ? true : arguments.userScalable);
if (arguments.initialScale > 0)
setInitialScale(arguments.initialScale);
if (arguments.minimumScale > 0)
setMinimumScale(arguments.minimumScale);
if (arguments.maximumScale > 0)
setMaximumScale(arguments.maximumScale);
IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
if (loadState() == WebKit::WebPagePrivate::Committed)
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)
if (m_backingStore->d->isOpenGLCompositing()) {
if (m_visible)
setCompositorDrawsRootLayer(true);
return;
}
resetCompositingSurface();
#endif
}
void WebPagePrivate::resumeBackingStore()
{
ASSERT(m_webPage->isVisible());
bool directRendering = m_backingStore->d->shouldDirectRenderingToWindow();
if (!m_backingStore->d->isActive()
|| shouldResetTilesWhenShown()
|| directRendering) {
BackingStorePrivate::setCurrentBackingStoreOwner(m_webPage);
if (m_backingStore->d->isOpenGLCompositing())
setCompositorDrawsRootLayer(!m_backingStore->d->isActive());
m_backingStore->d->orientationChanged(); m_backingStore->d->resetTiles(true );
m_backingStore->d->updateTiles(false , false );
directRendering = m_backingStore->d->shouldDirectRenderingToWindow();
if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !directRendering)
m_backingStore->d->blitVisibleContents();
} else {
if (m_backingStore->d->isOpenGLCompositing())
setCompositorDrawsRootLayer(false);
m_backingStore->d->updateTiles(true , false );
}
#if USE(ACCELERATED_COMPOSITING)
setNeedsOneShotDrawingSynchronization();
#endif
setShouldResetTilesWhenShown(false);
}
void WebPagePrivate::setScreenOrientation(int orientation)
{
FOR_EACH_PLUGINVIEW(m_pluginViews)
(*it)->handleOrientationEvent(orientation);
m_pendingOrientation = -1;
#if ENABLE(ORIENTATION_EVENTS)
if (m_mainFrame->orientation() == orientation)
return;
for (RefPtr<Frame> frame = m_mainFrame; frame; frame = frame->tree()->traverseNext())
frame->sendOrientationChangeEvent(orientation);
#endif
}
void WebPage::setScreenOrientation(int orientation)
{
d->m_pendingOrientation = orientation;
}
void WebPage::applyPendingOrientationIfNeeded()
{
if (d->m_pendingOrientation != -1)
d->setScreenOrientation(d->m_pendingOrientation);
}
void WebPagePrivate::screenRotated()
{
if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
Platform::createMethodCallMessage(&WebPagePrivate::screenRotated, this));
return;
}
SurfacePool::globalSurfacePool()->notifyScreenRotated();
m_client->notifyScreenRotated();
}
void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize, bool ensureFocusElementVisible)
{
if (m_pendingOrientation == -1 && transformedActualVisibleSize == this->transformedActualVisibleSize())
return;
m_backingStore->d->suspendScreenAndBackingStoreUpdates();
if (!m_visible || !m_backingStore->d->isActive())
setShouldResetTilesWhenShown(true);
bool hasPendingOrientation = m_pendingOrientation != -1;
if (hasPendingOrientation)
screenRotated();
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());
bool atInitialScale = m_webPage->isAtInitialZoom();
bool atTop = !scrollPosition().y();
bool atLeft = !scrollPosition().x();
m_backingStore->d->createVisibleTileBuffer();
setDefaultLayoutSize(transformedActualVisibleSize);
bool needsLayout = false;
static ViewportArguments defaultViewportArguments;
if (!(m_viewportArguments == defaultViewportArguments)) {
IntSize newVirtualViewport = recomputeVirtualViewportFromViewportArguments();
ASSERT(!newVirtualViewport.isEmpty());
m_webPage->setVirtualViewportSize(newVirtualViewport.width(), newVirtualViewport.height());
m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
m_mainFrame->view()->setFixedLayoutSize(fixedLayoutSize());
needsLayout = true;
}
m_actualVisibleWidth = transformedActualVisibleSize.width();
m_actualVisibleHeight = transformedActualVisibleSize.height();
IntSize viewportSizeAfter = actualVisibleSize();
IntPoint offset(roundf((viewportSizeBefore.width() - viewportSizeAfter.width()) / 2.0),
roundf((viewportSizeBefore.height() - viewportSizeAfter.height()) / 2.0));
if (atTop)
offset.setY(0);
if (atLeft)
offset.setX(0);
IntPoint bottomRight(
scrollPosition().x() + viewportSizeAfter.width(),
scrollPosition().y() + viewportSizeAfter.height());
if (bottomRight.x() + offset.x() > contentsSize().width())
offset.setX(contentsSize().width() - bottomRight.x());
if (bottomRight.y() + offset.y() > contentsSize().height())
offset.setY(contentsSize().height() - bottomRight.y());
if (scrollPosition().x() + offset.x() < 0)
offset.setX(-scrollPosition().x());
if (scrollPosition().y() + offset.y() < 0)
offset.setY(-scrollPosition().y());
scrollBy(offset.x(), offset.y());
notifyTransformedScrollChanged();
m_backingStore->d->orientationChanged();
m_backingStore->d->actualVisibleSizeChanged(transformedActualVisibleSize);
if (setViewMode(viewMode()))
needsLayout = true;
bool needsLayoutToFindContentSize = hasPendingOrientation;
updateViewportSize(!needsLayoutToFindContentSize , false );
notifyTransformedContentsSizeChanged();
if (!m_webSettings->isZoomToFitOnLoad()) {
atInitialScale = false;
if (!hasVirtualViewport() && contentsSize().width() < m_defaultLayoutSize.width()) {
m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
m_mainFrame->view()->setFixedLayoutSize(m_defaultLayoutSize);
needsLayout = true;
}
}
if (needsLayout)
setNeedsLayout();
m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
requestLayoutIfNeeded();
double scale = atInitialScale ? initialScale() : currentScale();
scale = clampedScale(scale);
if (needsLayoutToFindContentSize) {
TransformationMatrix rotationMatrix;
rotationMatrix.scale(scale);
IntRect viewportRect = IntRect(IntPoint::zero(), transformedActualVisibleSize);
IntRect actualVisibleRect = enclosingIntRect(rotationMatrix.inverse().mapRect(FloatRect(viewportRect)));
m_mainFrame->view()->setFixedReportedSize(actualVisibleRect.size());
m_mainFrame->view()->repaintFixedElementsAfterScrolling();
}
if (shouldSendResizeEvent())
m_mainFrame->eventHandler()->sendResizeEvent();
FloatPoint anchor = centerOfVisibleContentsRect;
if (atTop)
anchor.setY(0);
if (atLeft)
anchor.setX(0);
if (m_backingStore->d->shouldDirectRenderingToWindow()) {
bool success = zoomAboutPoint(scale, anchor, false , true );
if (!success && ensureFocusElementVisible)
ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
} else if (!scheduleZoomAboutPoint(scale, anchor, false , true )) {
m_backingStore->d->suspendScreenAndBackingStoreUpdates();
IntPoint scrollPosition = this->scrollPosition();
if (atTop)
scrollPosition.setY(0);
if (atLeft)
scrollPosition.setX(0);
setScrollPosition(scrollPosition);
notifyTransformedContentsSizeChanged();
notifyTransformedScrollChanged();
if (!needsLayout) {
m_backingStore->d->updateTilesForScrollOrNotRenderedRegion();
}
if (ensureFocusElementVisible)
ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
if (needsLayout) {
m_backingStore->d->resetTiles(true);
m_backingStore->d->updateTiles(false , false );
}
m_backingStore->d->resumeScreenAndBackingStoreUpdates(needsLayout ? BackingStore::RenderAndBlit : BackingStore::Blit);
} else if (ensureFocusElementVisible)
ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
}
void WebPage::setViewportSize(const Platform::IntSize& viewportSize, bool ensureFocusElementVisible)
{
d->setViewportSize(viewportSize, ensureFocusElementVisible);
}
void WebPagePrivate::setDefaultLayoutSize(const IntSize& size)
{
IntSize screenSize = Platform::Graphics::Screen::primaryScreen()->size();
ASSERT(size.width() <= screenSize.width() && size.height() <= screenSize.height());
m_defaultLayoutSize = size.expandedTo(minimumLayoutSize).shrunkTo(screenSize);
}
void WebPage::setDefaultLayoutSize(int width, int height)
{
IntSize size(width, height);
if (size == d->m_defaultLayoutSize)
return;
d->setDefaultLayoutSize(size);
bool needsLayout = d->setViewMode(d->viewMode());
if (needsLayout) {
d->setNeedsLayout();
if (!d->isLoading())
d->requestLayoutIfNeeded();
}
}
bool WebPage::mouseEvent(const Platform::MouseEvent& mouseEvent, bool* wheelDeltaAccepted)
{
if (!d->m_mainFrame->view())
return false;
if (d->m_page->defersLoading())
return false;
PluginView* pluginView = d->m_fullScreenPluginView.get();
if (pluginView)
return d->dispatchMouseEventToFullScreenPlugin(pluginView, mouseEvent);
if (mouseEvent.type() == Platform::MouseEvent::MouseAborted) {
d->m_mainFrame->eventHandler()->setMousePressed(false);
return false;
}
d->m_pluginMayOpenNewTab = true;
d->m_lastUserEventTimestamp = currentTime();
int clickCount = (d->m_selectionHandler->isSelectionActive() || mouseEvent.type() != Platform::MouseEvent::MouseMove) ? 1 : 0;
MouseButton buttonType = NoButton;
if (mouseEvent.isLeftButton())
buttonType = LeftButton;
else if (mouseEvent.isRightButton())
buttonType = RightButton;
else if (mouseEvent.isMiddleButton())
buttonType = MiddleButton;
PlatformMouseEvent platformMouseEvent(d->mapFromTransformed(mouseEvent.position()),
d->mapFromTransformed(mouseEvent.screenPosition()),
toWebCoreMouseEventType(mouseEvent.type()), clickCount, buttonType, PointingDevice);
d->m_lastMouseEvent = platformMouseEvent;
bool success = d->handleMouseEvent(platformMouseEvent);
if (mouseEvent.wheelTicks()) {
PlatformWheelEvent wheelEvent(d->mapFromTransformed(mouseEvent.position()),
d->mapFromTransformed(mouseEvent.screenPosition()),
0, -mouseEvent.wheelDelta(),
0, -mouseEvent.wheelTicks(),
ScrollByPixelWheelEvent,
false , false ,
false , false );
if (wheelDeltaAccepted)
*wheelDeltaAccepted = d->handleWheelEvent(wheelEvent);
} else if (wheelDeltaAccepted)
*wheelDeltaAccepted = false;
return success;
}
bool WebPagePrivate::dispatchMouseEventToFullScreenPlugin(PluginView* plugin, const Platform::MouseEvent& event)
{
NPEvent npEvent;
NPMouseEvent mouseEvent;
mouseEvent.x = event.screenPosition().x();
mouseEvent.y = event.screenPosition().y();
switch (event.type()) {
case Platform::MouseEvent::MouseButtonDown:
mouseEvent.type = MOUSE_BUTTON_DOWN;
m_pluginMouseButtonPressed = true;
break;
case Platform::MouseEvent::MouseButtonUp:
mouseEvent.type = MOUSE_BUTTON_UP;
m_pluginMouseButtonPressed = false;
break;
case Platform::MouseEvent::MouseMove:
mouseEvent.type = MOUSE_MOTION;
break;
default:
return false;
}
mouseEvent.flags = 0;
mouseEvent.button = m_pluginMouseButtonPressed;
npEvent.type = NP_MouseEvent;
npEvent.data = &mouseEvent;
return plugin->dispatchFullScreenNPEvent(npEvent);
}
bool WebPagePrivate::handleMouseEvent(PlatformMouseEvent& mouseEvent)
{
EventHandler* eventHandler = m_mainFrame->eventHandler();
if (mouseEvent.type() == WebCore::PlatformEvent::MouseMoved)
return eventHandler->mouseMoved(mouseEvent);
if (mouseEvent.type() == WebCore::PlatformEvent::MouseScroll)
return true;
Node* node = 0;
if (mouseEvent.inputMethod() == TouchScreen) {
const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
node = lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
}
if (!node) {
HitTestResult result = eventHandler->hitTestResultAtPoint(mapFromViewportToContents(mouseEvent.position()), false );
node = result.innerNode();
}
if (mouseEvent.type() == WebCore::PlatformEvent::MousePressed) {
m_inputHandler->enableInputMode();
if (m_inputHandler->willOpenPopupForNode(node)) {
ASSERT(node->isElementNode());
if (node->isElementNode()) {
Element* element = static_cast<Element*>(node);
element->focus();
}
} else
eventHandler->handleMousePressEvent(mouseEvent);
} else if (mouseEvent.type() == WebCore::PlatformEvent::MouseReleased) {
if (!m_inputHandler->didNodeOpenPopup(node))
eventHandler->handleMouseReleaseEvent(mouseEvent);
}
return true;
}
bool WebPagePrivate::handleWheelEvent(PlatformWheelEvent& wheelEvent)
{
return m_mainFrame->eventHandler()->handleWheelEvent(wheelEvent);
}
bool WebPage::touchEvent(const Platform::TouchEvent& event)
{
#if DEBUG_TOUCH_EVENTS
switch (event.m_type) {
case Platform::TouchEvent::TouchEnd:
Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent Touch End");
break;
case Platform::TouchEvent::TouchStart:
Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent Touch Start");
break;
case Platform::TouchEvent::TouchMove:
Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent Touch Move");
break;
case Platform::TouchEvent::TouchCancel:
Platform::log(Platform::LogLevelCritical, "WebPage::touchCancel Touch Cancel");
break;
}
for (unsigned i = 0; i < event.m_points.size(); i++) {
switch (event.m_points[i].m_state) {
case Platform::TouchPoint::TouchPressed:
Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent %d Touch Pressed (%d, %d)", event.m_points[i].m_id, event.m_points[i].m_pos.x(), event.m_points[i].m_pos.y());
break;
case Platform::TouchPoint::TouchReleased:
Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent %d Touch Released (%d, %d)", event.m_points[i].m_id, event.m_points[i].m_pos.x(), event.m_points[i].m_pos.y());
break;
case Platform::TouchPoint::TouchMoved:
Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent %d Touch Moved (%d, %d)", event.m_points[i].m_id, event.m_points[i].m_pos.x(), event.m_points[i].m_pos.y());
break;
case Platform::TouchPoint::TouchStationary:
Platform::log(Platform::LogLevelCritical, "WebPage::touchEvent %d Touch Stationary (%d, %d)", event.m_points[i].m_id, event.m_points[i].m_pos.x(), event.m_points[i].m_pos.y());
break;
}
}
#endif
#if ENABLE(TOUCH_EVENTS)
if (!d->m_mainFrame)
return false;
if (d->m_page->defersLoading())
return false;
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 = d->mapFromTransformed(tEvent.m_points[i].m_screenPos);
}
Platform::Gesture tapGesture;
if (event.hasGesture(Platform::Gesture::SingleTap))
d->m_pluginMayOpenNewTab = true;
else if (tEvent.m_type == Platform::TouchEvent::TouchStart || tEvent.m_type == Platform::TouchEvent::TouchCancel)
d->m_pluginMayOpenNewTab = false;
bool handled = false;
if (d->m_needTouchEvents && !event.hasGesture(Platform::Gesture::Injected))
handled = d->m_mainFrame->eventHandler()->handleTouchEvent(PlatformTouchEvent(&tEvent));
if (tEvent.m_type == Platform::TouchEvent::TouchEnd && handled && d->m_mainFrame->eventHandler()->mousePressed())
d->m_touchEventHandler->touchEventCancel();
if (d->m_preventDefaultOnTouchStart) {
if (tEvent.m_type == Platform::TouchEvent::TouchEnd || tEvent.m_type == Platform::TouchEvent::TouchCancel)
d->m_preventDefaultOnTouchStart = false;
return true;
}
if (handled) {
if (tEvent.m_type == Platform::TouchEvent::TouchStart)
d->m_preventDefaultOnTouchStart = true;
return true;
}
if (event.hasGesture(Platform::Gesture::TouchHold))
d->m_touchEventHandler->touchHoldEvent();
#endif
return false;
}
void WebPagePrivate::setScrollOriginPoint(const Platform::IntPoint& point)
{
m_inRegionScrollStartingNode = 0;
if (!m_hasInRegionScrollableAreas)
return;
m_client->notifyInRegionScrollingStartingPointChanged(inRegionScrollableAreasForPoint(point));
}
void WebPage::setScrollOriginPoint(const Platform::IntPoint& point)
{
Platform::IntPoint untransformedPoint = d->mapFromTransformed(point);
d->setScrollOriginPoint(untransformedPoint);
}
bool WebPagePrivate::dispatchTouchEventToFullScreenPlugin(PluginView* plugin, const Platform::TouchEvent& event)
{
NPTouchEvent npTouchEvent;
if (event.hasGesture(Platform::Gesture::DoubleTap))
npTouchEvent.type = TOUCH_EVENT_DOUBLETAP;
else if (event.hasGesture(Platform::Gesture::TouchHold))
npTouchEvent.type = TOUCH_EVENT_TOUCHHOLD;
else {
switch (event.m_type) {
case Platform::TouchEvent::TouchStart:
npTouchEvent.type = TOUCH_EVENT_START;
break;
case Platform::TouchEvent::TouchEnd:
npTouchEvent.type = TOUCH_EVENT_END;
break;
case Platform::TouchEvent::TouchMove:
npTouchEvent.type = TOUCH_EVENT_MOVE;
break;
case Platform::TouchEvent::TouchCancel:
npTouchEvent.type = TOUCH_EVENT_CANCEL;
break;
default:
return false;
}
}
npTouchEvent.points = 0;
npTouchEvent.size = event.m_points.size();
if (npTouchEvent.size) {
npTouchEvent.points = new NPTouchPoint[npTouchEvent.size];
for (int i = 0; i < npTouchEvent.size; i++) {
npTouchEvent.points[i].touchId = event.m_points[i].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();
}
}
NPEvent npEvent;
npEvent.type = NP_TouchEvent;
npEvent.data = &npTouchEvent;
bool handled = plugin->dispatchFullScreenNPEvent(npEvent);
if (npTouchEvent.type == TOUCH_EVENT_DOUBLETAP && !handled) {
npTouchEvent.type = TOUCH_EVENT_END;
npEvent.data = &npTouchEvent;
handled = plugin->dispatchFullScreenNPEvent(npEvent);
}
delete[] npTouchEvent.points;
return handled;
}
bool WebPage::touchPointAsMouseEvent(const Platform::TouchPoint& point)
{
if (d->m_page->defersLoading())
return false;
PluginView* pluginView = d->m_fullScreenPluginView.get();
if (pluginView)
return d->dispatchTouchPointAsMouseEventToFullScreenPlugin(pluginView, point);
d->m_lastUserEventTimestamp = currentTime();
Platform::TouchPoint tPoint = point;
tPoint.m_pos = d->mapFromTransformed(tPoint.m_pos);
tPoint.m_screenPos = d->mapFromTransformed(tPoint.m_screenPos);
return d->m_touchEventHandler->handleTouchPoint(tPoint);
}
bool WebPagePrivate::dispatchTouchPointAsMouseEventToFullScreenPlugin(PluginView* pluginView, const Platform::TouchPoint& point)
{
NPEvent npEvent;
NPMouseEvent mouse;
switch (point.m_state) {
case Platform::TouchPoint::TouchPressed:
mouse.type = MOUSE_BUTTON_DOWN;
break;
case Platform::TouchPoint::TouchReleased:
mouse.type = MOUSE_BUTTON_UP;
break;
case Platform::TouchPoint::TouchMoved:
mouse.type = MOUSE_MOTION;
break;
case Platform::TouchPoint::TouchStationary:
return false;
}
mouse.x = point.m_screenPos.x();
mouse.y = point.m_screenPos.y();
mouse.button = mouse.type != MOUSE_BUTTON_UP;
mouse.flags = 0;
npEvent.type = NP_MouseEvent;
npEvent.data = &mouse;
return pluginView->dispatchFullScreenNPEvent(npEvent);
}
void WebPage::touchEventCancel()
{
d->m_pluginMayOpenNewTab = false;
if (d->m_page->defersLoading())
return;
d->m_touchEventHandler->touchEventCancel();
}
void WebPage::touchEventCancelAndClearFocusedNode()
{
if (d->m_page->defersLoading())
return;
d->m_touchEventHandler->touchEventCancelAndClearFocusedNode();
}
Frame* WebPagePrivate::focusedOrMainFrame() const
{
return m_page->focusController()->focusedOrMainFrame();
}
void WebPagePrivate::clearFocusNode()
{
Frame* frame = focusedOrMainFrame();
if (!frame)
return;
ASSERT(frame->document());
if (frame->document()->focusedNode())
frame->page()->focusController()->setFocusedNode(0, frame);
}
WebString WebPage::textEncoding()
{
Frame* frame = d->focusedOrMainFrame();
if (!frame)
return "";
Document* document = frame->document();
if (!document)
return "";
return document->loader()->writer()->encoding();
}
WebString WebPage::forcedTextEncoding()
{
Frame* frame = d->focusedOrMainFrame();
if (!frame)
return "";
Document* document = frame->document();
if (!document)
return "";
return document->loader()->overrideEncoding();
}
void WebPage::setForcedTextEncoding(const char* encoding)
{
if (encoding && d->focusedOrMainFrame() && d->focusedOrMainFrame()->loader() && d->focusedOrMainFrame()->loader())
return d->focusedOrMainFrame()->loader()->reloadWithOverrideEncoding(encoding);
}
bool WebPagePrivate::scrollNodeRecursively(Node* node, const IntSize& delta)
{
if (delta.isZero())
return true;
if (!node)
return false;
RenderObject* renderer = node->renderer();
if (!renderer)
return false;
FrameView* view = renderer->view()->frameView();
if (!view)
return false;
if (scrollRenderer(renderer, delta))
return true;
if (view == m_mainFrame->view())
return false;
if (canScrollInnerFrame(view->frame())) {
IntSize viewDelta = delta;
IntPoint newViewOffset = view->scrollPosition();
IntPoint maxViewOffset = view->maximumScrollPosition();
adjustScrollDelta(maxViewOffset, newViewOffset, viewDelta);
if (!viewDelta.isZero()) {
view->setCanBlitOnScroll(false);
BackingStoreClient* backingStoreClient = backingStoreClientForFrame(view->frame());
if (backingStoreClient) {
backingStoreClient->setIsClientGeneratedScroll(true);
backingStoreClient->setIsScrollNotificationSuppressed(true);
}
m_inRegionScrollStartingNode = view->frame()->document();
view->scrollBy(viewDelta);
if (backingStoreClient) {
backingStoreClient->setIsClientGeneratedScroll(false);
backingStoreClient->setIsScrollNotificationSuppressed(false);
}
return true;
}
}
Frame* frame = node->document()->frame();
if (frame) {
Node* ownerNode = frame->ownerElement();
if (scrollNodeRecursively(ownerNode, delta))
return true;
}
return false;
}
void WebPagePrivate::adjustScrollDelta(const IntPoint& maxOffset, const IntPoint& currentOffset, IntSize& delta) const
{
if (currentOffset.x() + delta.width() > maxOffset.x())
delta.setWidth(min(maxOffset.x() - currentOffset.x(), delta.width()));
if (currentOffset.x() + delta.width() < 0)
delta.setWidth(max(-currentOffset.x(), delta.width()));
if (currentOffset.y() + delta.height() > maxOffset.y())
delta.setHeight(min(maxOffset.y() - currentOffset.y(), delta.height()));
if (currentOffset.y() + delta.height() < 0)
delta.setHeight(max(-currentOffset.y(), delta.height()));
}
static Node* enclosingLayerNode(RenderLayer*);
bool WebPagePrivate::scrollRenderer(RenderObject* renderer, const IntSize& delta)
{
RenderLayer* layer = renderer->enclosingLayer();
if (!layer)
return false;
bool restrictedByLineClamp = false;
if (renderer->parent())
restrictedByLineClamp = !renderer->parent()->style()->lineClamp().isNone();
if (renderer->hasOverflowClip() && !restrictedByLineClamp) {
IntSize layerDelta = delta;
IntPoint maxOffset(layer->scrollWidth() - layer->renderBox()->clientWidth(), layer->scrollHeight() - layer->renderBox()->clientHeight());
IntPoint currentOffset(layer->scrollXOffset(), layer->scrollYOffset());
adjustScrollDelta(maxOffset, currentOffset, layerDelta);
if (!layerDelta.isZero()) {
m_inRegionScrollStartingNode = enclosingLayerNode(layer);
IntPoint newOffset = currentOffset + layerDelta;
layer->scrollToOffset(newOffset.x(), newOffset.y());
renderer->repaint(true);
return true;
}
}
while (layer = layer->parent()) {
if (canScrollRenderBox(layer->renderBox()))
return scrollRenderer(layer->renderBox(), delta);
}
return false;
}
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) {
ASSERT(scroller && scroller->m_mainFrame && scroller->m_mainFrame->view());
IntPoint pos(scroller->scrollPosition() + IntSize(dx, dy));
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(pos);
}
}
bool WebPage::keyEvent(const Platform::KeyboardEvent& keyboardEvent)
{
if (!d->m_mainFrame->view())
return false;
if (d->m_page->defersLoading())
return false;
ASSERT(d->m_page->focusController());
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;
}
bool WebPage::deleteTextRelativeToCursor(unsigned int leftOffset, unsigned int rightOffset)
{
if (d->m_page->defersLoading())
return false;
return d->m_inputHandler->deleteTextRelativeToCursor(leftOffset, rightOffset);
}
spannable_string_t* WebPage::selectedText(int32_t flags)
{
return d->m_inputHandler->selectedText(flags);
}
spannable_string_t* WebPage::textBeforeCursor(int32_t length, int32_t flags)
{
return d->m_inputHandler->textBeforeCursor(length, flags);
}
spannable_string_t* WebPage::textAfterCursor(int32_t length, int32_t flags)
{
return d->m_inputHandler->textAfterCursor(length, flags);
}
extracted_text_t* WebPage::extractedTextRequest(extracted_text_request_t* request, int32_t flags)
{
return d->m_inputHandler->extractedTextRequest(request, flags);
}
int32_t WebPage::setComposingRegion(int32_t start, int32_t end)
{
return d->m_inputHandler->setComposingRegion(start, end);
}
int32_t WebPage::finishComposition()
{
return d->m_inputHandler->finishComposition();
}
int32_t WebPage::setComposingText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
{
if (d->m_page->defersLoading())
return -1;
return d->m_inputHandler->setComposingText(spannableString, relativeCursorPosition);
}
int32_t WebPage::commitText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
{
if (d->m_page->defersLoading())
return -1;
return d->m_inputHandler->commitText(spannableString, relativeCursorPosition);
}
void WebPage::setSpellCheckingEnabled(bool enabled)
{
static_cast<EditorClientBlackBerry*>(d->m_page->editorClient())->enableSpellChecking(enabled);
}
class DeferredTaskSelectionCancelled: public DeferredTask<&WebPagePrivate::m_wouldCancelSelection> {
public:
explicit DeferredTaskSelectionCancelled(WebPagePrivate* webPagePrivate)
: DeferredTaskType(webPagePrivate)
{
}
private:
virtual void performInternal(WebPagePrivate* webPagePrivate)
{
webPagePrivate->m_webPage->selectionCancelled();
}
};
void WebPage::selectionCancelled()
{
if (d->m_page->defersLoading()) {
d->m_deferredTasks.append(adoptPtr(new DeferredTaskSelectionCancelled(d)));
return;
}
DeferredTaskSelectionCancelled::finishOrCancel(d);
d->m_selectionHandler->cancelSelection();
}
bool WebPage::selectionContains(const Platform::IntPoint& point)
{
return d->m_selectionHandler->selectionContains(d->mapFromTransformed(point));
}
WebString WebPage::title() const
{
if (d->m_mainFrame->document())
return d->m_mainFrame->loader()->documentLoader()->title().string();
return WebString();
}
WebString WebPage::selectedText() const
{
return d->m_selectionHandler->selectedText();
}
WebString WebPage::cutSelectedText()
{
WebString selectedText = d->m_selectionHandler->selectedText();
if (!d->m_page->defersLoading() && !selectedText.isEmpty())
d->m_inputHandler->deleteSelection();
return selectedText;
}
void WebPage::insertText(const WebString& string)
{
if (d->m_page->defersLoading())
return;
d->m_inputHandler->insertText(string);
}
void WebPage::clearCurrentInputField()
{
if (d->m_page->defersLoading())
return;
d->m_inputHandler->clearField();
}
void WebPage::cut()
{
if (d->m_page->defersLoading())
return;
d->m_inputHandler->cut();
}
void WebPage::copy()
{
d->m_inputHandler->copy();
}
void WebPage::paste()
{
if (d->m_page->defersLoading())
return;
d->m_inputHandler->paste();
}
void WebPage::setSelection(const Platform::IntPoint& startPoint, const Platform::IntPoint& endPoint)
{
if (d->m_page->defersLoading())
return;
bool invalidPoint = IntPoint(startPoint) == DOMSupport::InvalidPoint;
IntPoint start = invalidPoint ? DOMSupport::InvalidPoint : d->mapFromTransformed(startPoint);
invalidPoint = IntPoint(endPoint) == DOMSupport::InvalidPoint;
IntPoint end = invalidPoint ? DOMSupport::InvalidPoint : d->mapFromTransformed(endPoint);
d->m_selectionHandler->setSelection(start, end);
}
void WebPage::setCaretPosition(const Platform::IntPoint& position)
{
if (d->m_page->defersLoading())
return;
d->m_selectionHandler->setCaretPosition(d->mapFromTransformed(position));
}
void WebPage::selectAtPoint(const Platform::IntPoint& location)
{
if (d->m_page->defersLoading())
return;
IntPoint selectionLocation =
IntPoint(location) == DOMSupport::InvalidPoint ?
DOMSupport::InvalidPoint :
d->mapFromTransformed(location);
d->m_selectionHandler->selectAtPoint(selectionLocation);
}
bool WebPagePrivate::canScrollInnerFrame(Frame* frame) const
{
if (!frame || !frame->view())
return false;
if (!frame->ownerElement())
return false;
ASSERT(frame != m_mainFrame);
IntSize visibleSize = frame->view()->visibleContentRect().size();
IntSize contentsSize = frame->view()->contentsSize();
bool canBeScrolled = contentsSize.height() > visibleSize.height() || contentsSize.width() > visibleSize.width();
return canBeScrolled && (frame->ownerElement()->scrollingMode() != ScrollbarAlwaysOff);
}
bool WebPagePrivate::canScrollRenderBox(RenderBox* box)
{
if (!box || !box->hasOverflowClip())
return false;
if (box->scrollsOverflowX() && (box->scrollWidth() != box->clientWidth())
|| box->scrollsOverflowY() && (box->scrollHeight() != box->clientHeight()))
return true;
Node* node = box->node();
return node && (node->rendererIsEditable() || node->isDocumentNode());
}
static RenderLayer* parentLayer(RenderLayer* layer)
{
ASSERT(layer);
if (layer->parent())
return layer->parent();
RenderObject* renderer = layer->renderer();
if (renderer->document() && renderer->document()->ownerElement() && renderer->document()->ownerElement()->renderer())
return renderer->document()->ownerElement()->renderer()->enclosingLayer();
return 0;
}
static Node* enclosingLayerNode(RenderLayer* layer)
{
for (RenderObject* r = layer->renderer(); r; r = r->parent()) {
if (Node* e = r->node())
return e;
}
ASSERT_NOT_REACHED();
return 0;
}
static void pushBackInRegionScrollable(std::vector<Platform::ScrollViewBase>& vector, InRegionScrollableArea scroller, WebPagePrivate* webPage)
{
ASSERT(webPage);
ASSERT(!scroller.isNull());
scroller.setCanPropagateScrollingToEnclosingScrollable(!isNonRenderViewFixedPositionedContainer(scroller.layer()));
vector.push_back(scroller);
if (vector.size() == 1) {
webPage->m_inRegionScrollStartingNode = enclosingLayerNode(scroller.layer());
}
}
std::vector<Platform::ScrollViewBase> WebPagePrivate::inRegionScrollableAreasForPoint(const Platform::IntPoint& point)
{
std::vector<Platform::ScrollViewBase> validReturn;
std::vector<Platform::ScrollViewBase> emptyReturn;
HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromViewportToContents(point), false );
Node* node = result.innerNonSharedNode();
if (!node)
return emptyReturn;
RenderObject* renderer = node->renderer();
if (!renderer)
return emptyReturn;
RenderLayer* layer = renderer->enclosingLayer();
do {
RenderObject* renderer = layer->renderer();
if (renderer->isRenderView()) {
if (RenderView* renderView = toRenderView(renderer)) {
FrameView* view = renderView->frameView();
if (!view)
return emptyReturn;
if (canScrollInnerFrame(view->frame())) {
pushBackInRegionScrollable(validReturn, InRegionScrollableArea(this, layer), this);
continue;
}
}
} else if (canScrollRenderBox(layer->renderBox())) {
pushBackInRegionScrollable(validReturn, InRegionScrollableArea(this, layer), this);
continue;
}
if (isNonRenderViewFixedPositionedContainer(layer) && validReturn.size()) {
Platform::ScrollViewBase& end = validReturn.back();
end.setCanPropagateScrollingToEnclosingScrollable(false);
}
} while (layer = parentLayer(layer));
if (validReturn.empty())
return emptyReturn;
return validReturn;
}
BackingStore* WebPage::backingStore() const
{
return d->m_backingStore;
}
bool WebPage::zoomToFit()
{
if (d->contentsSize().isEmpty() || !d->isUserScalable())
return false;
d->m_userPerformedManualZoom = true;
return d->zoomAboutPoint(d->zoomToFitScale(), d->centerOfVisibleContentsRect());
}
void WebPagePrivate::setTextReflowAnchorPoint(const Platform::IntPoint& focalPoint)
{
ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
m_currentPinchZoomNode = bestNodeForZoomUnderPoint(focalPoint);
if (!m_currentPinchZoomNode)
return;
IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
m_anchorInNodeRectRatio.set(static_cast<float>(mapFromTransformed(focalPoint).x() - nodeRect.x()) / nodeRect.width(),
static_cast<float>(mapFromTransformed(focalPoint).y() - nodeRect.y()) / nodeRect.height());
}
bool WebPage::pinchZoomAboutPoint(double scale, int x, int y)
{
IntPoint anchor(x, y);
d->m_userPerformedManualZoom = true;
d->m_userPerformedManualScroll = true;
if (d->m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
d->setTextReflowAnchorPoint(anchor);
if (!d->m_currentPinchZoomNode)
return false;
}
return d->zoomAboutPoint(scale, d->mapFromTransformed(anchor));
}
#if ENABLE(VIEWPORT_REFLOW)
void WebPagePrivate::toggleTextReflowIfEnabledForBlockZoomOnly(bool shouldEnableTextReflow)
{
if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabledOnlyForBlockZoom)
m_page->settings()->setTextReflowEnabled(shouldEnableTextReflow);
}
#endif
bool WebPage::blockZoom(int x, int y)
{
if (!d->m_mainFrame->view() || !d->isUserScalable())
return false;
Node* node = d->bestNodeForZoomUnderPoint(IntPoint(x, y));
if (!node)
return false;
IntRect nodeRect = d->rectForNode(node);
IntRect blockRect;
bool endOfBlockZoomMode = d->compareNodesForBlockZoom(d->m_currentBlockZoomAdjustedNode.get(), node);
const double oldScale = d->m_transformationMatrix->m11();
double newScale = 0;
const double margin = endOfBlockZoomMode ? 0 : blockZoomMargin * 2 * oldScale;
bool isFirstZoom = false;
if (endOfBlockZoomMode) {
IntRect rect = d->blockZoomRectForNode(node);
blockRect = IntRect(0, rect.y(), d->transformedContentsSize().width(), d->transformedContentsSize().height() - rect.y());
d->m_shouldReflowBlock = false;
} else {
Node* tempBlockZoomAdjustedNode = d->m_currentBlockZoomAdjustedNode.get();
blockRect = d->blockZoomRectForNode(node);
if (!node->hasTagName(HTMLNames::imgTag)) {
IntRect tRect = d->mapFromTransformed(blockRect);
int blockArea = tRect.width() * tRect.height();
int pageArea = d->contentsSize().width() * d->contentsSize().height();
double blockToPageRatio = static_cast<double>(pageArea - blockArea) / pageArea;
if (blockToPageRatio < minimumExpandingRatio) {
d->m_currentBlockZoomAdjustedNode = tempBlockZoomAdjustedNode;
return false;
}
}
if (blockRect.isEmpty() || !blockRect.width() || !blockRect.height())
return false;
if (!d->m_currentBlockZoomNode.get())
isFirstZoom = true;
d->m_currentBlockZoomNode = node;
d->m_shouldReflowBlock = true;
}
newScale = std::min(d->newScaleForBlockZoomRect(blockRect, oldScale, margin), d->maxBlockZoomScale());
newScale = std::max(newScale, minimumScale());
#if DEBUG_BLOCK_ZOOM
IntRect renderRect(x, y, 1, 1);
renderRect = d->mapFromTransformedContentsToTransformedViewport(renderRect);
IntSize viewportSize = d->transformedViewportSize();
renderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
d->m_backingStore->d->clearWindow(renderRect, 0, 0, 0);
d->m_backingStore->d->invalidateWindow(renderRect);
#endif
#if ENABLE(VIEWPORT_REFLOW)
if (d->m_currentBlockZoomNode && d->m_shouldReflowBlock && settings()->textReflowMode() != WebSettings::TextReflowDisabled) {
RenderObject* renderer = d->m_currentBlockZoomNode->renderer();
if (renderer && renderer->isText()) {
double newFontSize = renderer->style()->fontSize() * newScale;
if (newFontSize < d->m_webSettings->defaultFontSize()) {
newScale = std::min(static_cast<double>(d->m_webSettings->defaultFontSize()) / renderer->style()->fontSize(), d->maxBlockZoomScale());
newScale = std::max(newScale, minimumScale());
}
blockRect.setWidth(oldScale * static_cast<double>(d->transformedActualVisibleSize().width()) / newScale);
newScale = std::min(d->newScaleForBlockZoomRect(blockRect, oldScale, margin), d->maxBlockZoomScale());
newScale = std::max(newScale, minimumScale()); }
}
#endif
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();
FloatPoint anchor;
FloatPoint topLeftPoint(d->mapFromTransformed(blockRect).location());
if (renderer && renderer->isText()) {
ETextAlign textAlign = renderer->style()->textAlign();
switch (textAlign) {
case CENTER:
case WEBKIT_CENTER:
anchor = FloatPoint(nodeRect.x() + (nodeRect.width() - scaledViewportWidth) / 2, topLeftPoint.y());
break;
case LEFT:
case WEBKIT_LEFT:
anchor = topLeftPoint;
break;
case RIGHT:
case WEBKIT_RIGHT:
anchor = FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y());
break;
case TAAUTO:
case JUSTIFY:
default:
if (renderer->style()->isLeftToRightDirection())
anchor = topLeftPoint;
else
anchor = FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y());
break;
}
} else
anchor = renderer->style()->isLeftToRightDirection() ? topLeftPoint : FloatPoint(nodeRect.x() + nodeRect.width() - scaledViewportWidth, topLeftPoint.y());
if (newBlockHeight <= scaledViewportHeight) {
d->m_finalBlockPoint = FloatPoint(anchor.x() - dx, anchor.y() - dy);
} else {
d->m_finalBlockPoint = FloatPoint(anchor.x() - dx, anchor.y() - 3);
}
#if ENABLE(VIEWPORT_REFLOW)
if (settings()->textReflowMode() != WebSettings::TextReflowDisabled) {
d->m_finalBlockPoint = FloatPoint(anchor.x() - dx, anchor.y() - 3);
d->m_finalBlockPointReflowOffset = FloatPoint(-dx, -3);
}
#endif
FloatRect br(anchor, FloatSize(scaledViewportWidth, scaledViewportHeight));
IntPoint clickPoint = d->mapFromTransformed(IntPoint(x, y));
if (!br.contains(clickPoint)) {
d->m_finalBlockPointReflowOffset.move(0, (clickPoint.y() - scaledViewportHeight / 2) - d->m_finalBlockPoint.y());
d->m_finalBlockPoint = FloatPoint(d->m_finalBlockPoint.x(), clickPoint.y() - scaledViewportHeight / 2);
}
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 (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);
}
d->m_finalBlockPoint = d->mapToTransformedFloatPoint(d->m_finalBlockPoint);
if (!endOfBlockZoomMode && abs(newScale - oldScale) / oldScale < minimumExpandingRatio) {
const double minimumDisplacement = minimumExpandingRatio * d->transformedActualVisibleSize().width();
if (oldScale == d->minimumScale() || (distanceBetweenPoints(roundTransformedPoint(d->mapToTransformed(d->scrollPosition())), roundTransformedPoint(d->m_finalBlockPoint)) < minimumDisplacement && abs(newScale - oldScale) / oldScale < 0.10)) {
if (isFirstZoom) {
d->resetBlockZoom();
return false;
}
blockZoom(x, y);
return true;
}
}
d->m_blockZoomFinalScale = newScale;
d->m_userPerformedManualZoom = true;
d->m_userPerformedManualScroll = true;
d->m_client->animateBlockZoom(d->m_finalBlockPoint, d->m_blockZoomFinalScale);
return true;
}
bool WebPage::isMaxZoomed() const
{
return (d->currentScale() == d->maximumScale()) || !d->isUserScalable();
}
bool WebPage::isMinZoomed() const
{
return (d->currentScale() == d->minimumScale()) || !d->isUserScalable();
}
bool WebPage::isAtInitialZoom() const
{
return (d->currentScale() == d->initialScale()) || !d->isUserScalable();
}
bool WebPagePrivate::shouldZoomOnEscape() const
{
if (!isUserScalable())
return false;
if (initialScale() < minimumScale() || initialScale() > maximumScale())
return false;
if (initialScale() >= currentScale())
return false;
return currentScale() != initialScale();
}
void WebPage::zoomToInitialScale()
{
if (!d->isUserScalable())
return;
d->zoomAboutPoint(d->initialScale(), d->centerOfVisibleContentsRect());
}
bool WebPage::zoomToOneOne()
{
if (!d->isUserScalable())
return false;
double scale = 1;
return d->zoomAboutPoint(scale, d->centerOfVisibleContentsRect());
}
class DeferredTaskSetFocused: public DeferredTask<&WebPagePrivate::m_wouldSetFocused> {
public:
explicit DeferredTaskSetFocused(WebPagePrivate* webPagePrivate, bool focused)
: DeferredTaskType(webPagePrivate)
{
webPagePrivate->m_cachedFocused = focused;
}
private:
virtual void performInternal(WebPagePrivate* webPagePrivate)
{
webPagePrivate->m_webPage->setFocused(webPagePrivate->m_cachedFocused);
}
};
void WebPage::setFocused(bool focused)
{
if (d->m_page->defersLoading()) {
d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetFocused(d, focused)));
return;
}
DeferredTaskSetFocused::finishOrCancel(d);
FocusController* focusController = d->m_page->focusController();
focusController->setActive(focused);
if (focused) {
Frame* frame = focusController->focusedFrame();
if (!frame)
focusController->setFocusedFrame(d->m_mainFrame);
}
focusController->setFocused(focused);
}
bool WebPage::findNextString(const char* text, bool forward, bool caseSensitive, bool wrap, bool highlightAllMatches)
{
WebCore::FindOptions findOptions = WebCore::StartInSelection;
if (!forward)
findOptions |= WebCore::Backwards;
if (!caseSensitive)
findOptions |= WebCore::CaseInsensitive;
return d->m_inPageSearchManager->findNextString(String::fromUTF8(text), findOptions, wrap, highlightAllMatches);
}
void WebPage::runLayoutTests()
{
#if ENABLE_DRT
d->m_page->settings()->setDeveloperExtrasEnabled(true);
if (!d->m_dumpRenderTree)
d->m_dumpRenderTree = new DumpRenderTree(this);
d->m_dumpRenderTree->runTests();
#endif
}
bool WebPage::enableScriptDebugger()
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
return true;
d->m_scriptDebugger = adoptPtr(new JavaScriptDebuggerBlackBerry(this->d));
return !!d->m_scriptDebugger;
#endif
}
bool WebPage::disableScriptDebugger()
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (!d->m_scriptDebugger)
return true;
d->m_scriptDebugger.clear();
return true;
#endif
}
void WebPage::addBreakpoint(const unsigned short* url, unsigned urlLength, int lineNumber, const unsigned short* condition, unsigned conditionLength)
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
d->m_scriptDebugger->addBreakpoint(url, urlLength, lineNumber, condition, conditionLength);
#endif
}
void WebPage::updateBreakpoint(const unsigned short* url, unsigned urlLength, int lineNumber, const unsigned short* condition, unsigned conditionLength)
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
d->m_scriptDebugger->updateBreakpoint(url, urlLength, lineNumber, condition, conditionLength);
#endif
}
void WebPage::removeBreakpoint(const unsigned short* url, unsigned urlLength, int lineNumber)
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
d->m_scriptDebugger->removeBreakpoint(url, urlLength, lineNumber);
#endif
}
bool WebPage::pauseOnExceptions()
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
return d->m_scriptDebugger ? d->m_scriptDebugger->pauseOnExceptions() : false;
#endif
}
void WebPage::setPauseOnExceptions(bool pause)
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
d->m_scriptDebugger->setPauseOnExceptions(pause);
#endif
}
void WebPage::pauseInDebugger()
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
d->m_scriptDebugger->pauseInDebugger();
#endif
}
void WebPage::resumeDebugger()
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
d->m_scriptDebugger->resumeDebugger();
#endif
}
void WebPage::stepOverStatementInDebugger()
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
d->m_scriptDebugger->stepOverStatementInDebugger();
#endif
}
void WebPage::stepIntoStatementInDebugger()
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
d->m_scriptDebugger->stepIntoStatementInDebugger();
#endif
}
void WebPage::stepOutOfFunctionInDebugger()
{
#if ENABLE(JAVASCRIPT_DEBUGGER)
if (d->m_scriptDebugger)
d->m_scriptDebugger->stepOutOfFunctionInDebugger();
#endif
}
unsigned WebPage::timeoutForJavaScriptExecution() const
{
return Settings::timeoutForJavaScriptExecution(d->m_page->groupName());
}
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
{
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()));
}
void WebPage::getBackForwardList(SharedArray<BackForwardEntry>& result, unsigned int& resultSize) const
{
HistoryItemVector entries = static_cast<BackForwardListImpl*>(d->m_page->backForward()->client())->entries();
resultSize = entries.size();
result.reset(new BackForwardEntry[resultSize]);
for (unsigned i = 0; i < resultSize; ++i) {
RefPtr<HistoryItem> entry = entries[i];
BackForwardEntry& resultEntry = result[i];
resultEntry.url = entry->urlString();
resultEntry.originalUrl = entry->originalURLString();
resultEntry.title = entry->title();
resultEntry.networkToken = entry->viewState().networkToken;
resultEntry.lastVisitWasHTTPNonGet = entry->lastVisitWasHTTPNonGet();
resultEntry.id = backForwardIdFromHistoryItem(entry.get());
entry->ref();
}
}
void WebPage::releaseBackForwardEntry(BackForwardId id) const
{
HistoryItem* item = historyItemFromBackForwardId(id);
ASSERT(item);
item->deref();
}
void WebPage::clearBrowsingData()
{
clearMemoryCaches();
clearAppCache(d->m_page->groupName());
clearLocalStorage();
clearCookieCache();
clearHistory();
clearPluginSiteData();
}
void WebPage::clearHistory()
{
}
void WebPage::clearCookies()
{
clearCookieCache();
}
void WebPage::clearLocalStorage()
{
if (PageGroup* group = d->m_page->groupPtr()) {
if (StorageNamespace* storage = group->localStorage())
storage->clearAllOriginsForDeletion();
}
}
void WebPage::clearCredentials()
{
#if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
credentialManager().clearCredentials();
#endif
}
void WebPage::clearNeverRememberSites()
{
#if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
credentialManager().clearNeverRememberSites();
#endif
}
void WebPage::clearCache()
{
clearMemoryCaches();
clearAppCache(d->m_page->groupName());
}
void WebPage::clearBackForwardList(bool keepCurrentPage) const
{
BackForwardListImpl* backForwardList = static_cast<BackForwardListImpl*>(d->m_page->backForward()->client());
RefPtr<HistoryItem> currentItem = backForwardList->currentItem();
while (!backForwardList->entries().isEmpty())
backForwardList->removeItem(backForwardList->entries().last().get());
if (keepCurrentPage)
backForwardList->addItem(currentItem);
}
bool WebPage::isEnableLocalAccessToAllCookies() const
{
return cookieManager().canLocalAccessAllCookies();
}
void WebPage::setEnableLocalAccessToAllCookies(bool enabled)
{
cookieManager().setCanLocalAccessAllCookies(enabled);
}
void WebPage::addVisitedLink(const unsigned short* url, unsigned int 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::nodeAtPoint(int x, int y)
{
HitTestResult result = d->m_mainFrame->eventHandler()->hitTestResultAtPoint(d->mapFromTransformed(IntPoint(x, y)), 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()) {
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) 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
String WebPagePrivate::findPatternStringForUrl(const KURL& url) const
{
if ((m_webSettings->shouldHandlePatternUrls() && protocolIs(url, "pattern"))
|| protocolIs(url, "tel")
|| protocolIs(url, "wtai")
|| protocolIs(url, "cti")
|| protocolIs(url, "mailto")
|| protocolIs(url, "sms")
|| protocolIs(url, "pin")) {
return url;
}
return String();
}
bool WebPage::defersLoading() const
{
return d->m_page->defersLoading();
}
bool WebPage::willFireTimer()
{
if (d->isLoading())
return true;
return d->m_backingStore->d->willFireTimer();
}
void WebPage::notifyPagePause()
{
FOR_EACH_PLUGINVIEW(d->m_pluginViews)
(*it)->handlePauseEvent();
}
void WebPage::notifyPageResume()
{
FOR_EACH_PLUGINVIEW(d->m_pluginViews)
(*it)->handleResumeEvent();
}
void WebPage::notifyPageBackground()
{
FOR_EACH_PLUGINVIEW(d->m_pluginViews)
(*it)->handleBackgroundEvent();
}
void WebPage::notifyPageForeground()
{
FOR_EACH_PLUGINVIEW(d->m_pluginViews)
(*it)->handleForegroundEvent();
}
void WebPage::notifyPageFullScreenAllowed()
{
FOR_EACH_PLUGINVIEW(d->m_pluginViews)
(*it)->handleFullScreenAllowedEvent();
}
void WebPage::notifyPageFullScreenExit()
{
FOR_EACH_PLUGINVIEW(d->m_pluginViews)
(*it)->handleFullScreenExitEvent();
}
void WebPage::notifyDeviceIdleStateChange(bool enterIdle)
{
FOR_EACH_PLUGINVIEW(d->m_pluginViews)
(*it)->handleIdleEvent(enterIdle);
}
void WebPagePrivate::notifyAppActivationStateChange(ActivationStateType activationState)
{
m_activationState = activationState;
#if ENABLE(PAGE_VISIBILITY_API)
setPageVisibilityState();
#endif
}
void WebPage::notifyAppActivationStateChange(ActivationStateType activationState)
{
#if ENABLE(VIDEO)
MediaPlayerPrivate::notifyAppActivatedEvent(activationState == ActivationActive);
#endif
FOR_EACH_PLUGINVIEW(d->m_pluginViews) {
switch (activationState) {
case ActivationActive:
(*it)->handleAppActivatedEvent();
break;
case ActivationInactive:
(*it)->handleAppDeactivatedEvent();
break;
case ActivationStandby:
(*it)->handleAppStandbyEvent();
break;
}
}
d->notifyAppActivationStateChange(activationState);
}
void WebPage::notifySwipeEvent()
{
FOR_EACH_PLUGINVIEW(d->m_pluginViews)
(*it)->handleSwipeEvent();
}
void WebPage::notifyScreenPowerStateChanged(bool powered)
{
FOR_EACH_PLUGINVIEW(d->m_pluginViews)
(*it)->handleScreenPowerEvent(powered);
}
void WebPage::notifyFullScreenVideoExited(bool done)
{
UNUSED_PARAM(done);
#if ENABLE(VIDEO)
if (HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(d->m_fullscreenVideoNode.get()))
mediaElement->exitFullscreen();
#endif
}
void WebPage::clearPluginSiteData()
{
PluginDatabase* database = PluginDatabase::installedPlugins(true);
if (!database)
return;
Vector<PluginPackage*> plugins = database->plugins();
Vector<PluginPackage*>::const_iterator end = plugins.end();
for (Vector<PluginPackage*>::const_iterator it = plugins.begin(); it != end; ++it)
(*it)->clearSiteData(String());
}
void WebPage::onNetworkAvailabilityChanged(bool available)
{
updateOnlineStatus(available);
}
void WebPage::onCertificateStoreLocationSet(const WebString& caPath)
{
#if ENABLE(VIDEO)
MediaPlayerPrivate::setCertificatePath(caPath);
#endif
}
void WebPage::enableWebInspector()
{
d->m_page->inspectorController()->connectFrontend();
d->m_page->settings()->setDeveloperExtrasEnabled(true);
}
void WebPage::disableWebInspector()
{
d->m_page->inspectorController()->disconnectFrontend();
d->m_page->settings()->setDeveloperExtrasEnabled(false);
}
bool WebPage::isWebInspectorEnabled()
{
return d->m_page->settings()->developerExtrasEnabled();
}
void WebPage::enablePasswordEcho()
{
d->m_page->settings()->setPasswordEchoEnabled(true);
}
void WebPage::disablePasswordEcho()
{
d->m_page->settings()->setPasswordEchoEnabled(false);
}
void WebPage::dispatchInspectorMessage(const std::string& message)
{
String stringMessage = String::fromUTF8(message.data(), message.length());
d->m_page->inspectorController()->dispatchMessageFromFrontend(stringMessage);
}
bool WebPagePrivate::compositorDrawsRootLayer() const
{
#if USE(ACCELERATED_COMPOSITING)
if (Platform::userInterfaceThreadMessageClient()->isCurrentThread())
return m_compositor && m_compositor->drawsRootLayer();
RenderView* renderView = m_mainFrame->contentRenderer();
if (!renderView || !renderView->layer() || !renderView->layer()->backing())
return false;
return !renderView->layer()->backing()->paintingGoesToWindow();
#else
return false;
#endif
}
void WebPagePrivate::setCompositorDrawsRootLayer(bool compositorDrawsRootLayer)
{
#if USE(ACCELERATED_COMPOSITING)
if (m_page->settings()->forceCompositingMode() == compositorDrawsRootLayer)
return;
m_page->settings()->setForceCompositingMode(compositorDrawsRootLayer);
if (FrameView* view = m_mainFrame->view())
view->updateCompositingLayers();
#endif
}
#if USE(ACCELERATED_COMPOSITING)
void WebPagePrivate::drawLayersOnCommit()
{
if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
ASSERT(!needsOneShotDrawingSynchronization());
if (!m_webPage->isVisible())
return;
m_backingStore->d->willDrawLayersOnCommit();
Platform::userInterfaceThreadMessageClient()->dispatchMessage(
Platform::createMethodCallMessage(&WebPagePrivate::drawLayersOnCommit, this));
return;
}
#if DEBUG_AC_COMMIT
Platform::log(Platform::LogLevelCritical, "%s", WTF_PRETTY_FUNCTION);
#endif
if (!m_backingStore->d->shouldDirectRenderingToWindow())
m_backingStore->d->blitVisibleContents();
}
void WebPagePrivate::scheduleRootLayerCommit()
{
if (!m_frameLayers || !m_frameLayers->hasLayer())
return;
m_needsCommit = true;
if (!m_rootLayerCommitTimer->isActive()) {
#if DEBUG_AC_COMMIT
Platform::log(Platform::LogLevelCritical, "%s: m_rootLayerCommitTimer->isActive() = %d", WTF_PRETTY_FUNCTION, m_rootLayerCommitTimer->isActive());
#endif
m_rootLayerCommitTimer->startOneShot(0);
}
}
static bool needsLayoutRecursive(FrameView* view)
{
if (view->needsLayout())
return true;
bool subframesNeedsLayout = false;
const HashSet<RefPtr<Widget> >* viewChildren = view->children();
HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end && !subframesNeedsLayout; ++current) {
Widget* widget = (*current).get();
if (widget->isFrameView())
subframesNeedsLayout |= needsLayoutRecursive(static_cast<FrameView*>(widget));
}
return subframesNeedsLayout;
}
LayerRenderingResults WebPagePrivate::lastCompositingResults() const
{
if (m_compositor)
return m_compositor->lastCompositingResults();
return LayerRenderingResults();
}
void WebPagePrivate::setCompositor(PassRefPtr<WebPageCompositorPrivate> compositor)
{
using namespace BlackBerry::Platform;
if (!userInterfaceThreadMessageClient()->isCurrentThread()) {
userInterfaceThreadMessageClient()->dispatchSyncMessage(createMethodCallMessage(&WebPagePrivate::setCompositor, this, compositor));
return;
}
m_compositor = compositor;
m_ownedContext.clear();
}
void WebPagePrivate::commitRootLayer(const IntRect& layoutRectForCompositing,
const IntSize& contentsSizeForCompositing,
bool drawsRootLayer)
{
#if DEBUG_AC_COMMIT
Platform::log(Platform::LogLevelCritical, "%s: m_compositor = 0x%x",
WTF_PRETTY_FUNCTION, m_compositor.get());
#endif
if (!m_frameLayers || !m_compositor)
return;
if (m_frameLayers->rootLayer() && m_frameLayers->rootLayer()->layerCompositingThread() != m_compositor->rootLayer())
m_compositor->setRootLayer(m_frameLayers->rootLayer()->layerCompositingThread());
m_compositor->setLayoutRectForCompositing(layoutRectForCompositing);
m_compositor->setContentsSizeForCompositing(contentsSizeForCompositing);
m_compositor->setDrawsRootLayer(drawsRootLayer);
m_compositor->commit(m_frameLayers->rootLayer());
}
bool WebPagePrivate::commitRootLayerIfNeeded()
{
#if DEBUG_AC_COMMIT
Platform::log(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()));
#endif
if (m_suspendRootLayerCommit)
return false;
if (!m_needsCommit)
return false;
if (!m_frameLayers || !m_frameLayers->hasLayer())
return false;
FrameView* view = m_mainFrame->view();
if (!view)
return false;
if (needsLayoutRecursive(view)) {
ASSERT(!needsOneShotDrawingSynchronization());
return false;
}
m_needsCommit = false;
m_needsOneShotDrawingSynchronization = false;
if (m_rootLayerCommitTimer->isActive())
m_rootLayerCommitTimer->stop();
m_frameLayers->commitOnWebKitThread(currentScale());
updateDelegatedOverlays();
IntRect layoutRectForCompositing(scrollPosition(), actualVisibleSize());
IntSize contentsSizeForCompositing = contentsSize();
bool drawsRootLayer = compositorDrawsRootLayer();
Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
Platform::createMethodCallMessage(
&WebPagePrivate::commitRootLayer,
this,
layoutRectForCompositing,
contentsSizeForCompositing,
drawsRootLayer));
return true;
}
void WebPagePrivate::rootLayerCommitTimerFired(Timer<WebPagePrivate>*)
{
if (m_suspendRootLayerCommit)
return;
#if DEBUG_AC_COMMIT
Platform::log(Platform::LogLevelCritical, "%s", WTF_PRETTY_FUNCTION);
#endif
requestLayoutIfNeeded();
if (!compositorDrawsRootLayer()) {
bool isSingleTargetWindow = SurfacePool::globalSurfacePool()->compositingSurface()
|| m_backingStore->d->isOpenGLCompositing();
if (isSingleTargetWindow && m_backingStore->d->shouldDirectRenderingToWindow())
setNeedsOneShotDrawingSynchronization();
if (needsOneShotDrawingSynchronization()) {
#if DEBUG_AC_COMMIT
Platform::log(Platform::LogLevelCritical, "%s: OneShotDrawingSynchronization code path!", WTF_PRETTY_FUNCTION);
#endif
const IntRect windowRect = IntRect(IntPoint::zero(), viewportSize());
m_backingStore->d->repaint(windowRect, true , true );
return;
}
}
if (commitRootLayerIfNeeded())
drawLayersOnCommit();
}
void WebPagePrivate::resetCompositingSurface()
{
if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
Platform::userInterfaceThreadMessageClient()->dispatchMessage(
Platform::createMethodCallMessage(
&WebPagePrivate::resetCompositingSurface, this));
return;
}
if (m_compositor)
m_compositor->setLastCompositingResults(LayerRenderingResults());
}
void WebPagePrivate::setRootLayerWebKitThread(Frame* frame, LayerWebKitThread* layer)
{
if (!layer && !m_frameLayers)
return;
if (!layer) {
ASSERT(m_frameLayers);
m_frameLayers->removeLayerByFrame(frame);
if (!m_frameLayers->hasLayer())
m_frameLayers.clear();
} else {
if (!m_frameLayers)
m_frameLayers = adoptPtr(new FrameLayers(this));
if (!m_frameLayers->containsLayerForFrame(frame))
m_frameLayers->addLayer(frame, layer);
ASSERT(m_frameLayers);
}
LayerCompositingThread* rootLayerCompositingThread = 0;
if (m_frameLayers && m_frameLayers->rootLayer())
rootLayerCompositingThread = m_frameLayers->rootLayer()->layerCompositingThread();
setRootLayerCompositingThread(rootLayerCompositingThread);
}
void WebPagePrivate::setRootLayerCompositingThread(LayerCompositingThread* layer)
{
if (!Platform::userInterfaceThreadMessageClient()->isCurrentThread()) {
Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
Platform::createMethodCallMessage(&WebPagePrivate::setRootLayerCompositingThread, this, layer));
return;
}
if (!layer) {
resetCompositingSurface();
} else if (!m_compositor)
createCompositor();
if (m_compositor)
m_compositor->setRootLayer(layer);
}
bool WebPagePrivate::createCompositor()
{
if (!m_client->window())
return false;
m_ownedContext = GLES2Context::create(this);
m_compositor = WebPageCompositorPrivate::create(this, 0);
m_compositor->setContext(m_ownedContext.get());
if (!m_compositor->hardwareCompositing()) {
destroyCompositor();
return false;
}
return true;
}
void WebPagePrivate::destroyCompositor()
{
if (!m_ownedContext)
return;
m_compositor.clear();
m_ownedContext.clear();
}
void WebPagePrivate::syncDestroyCompositorOnCompositingThread()
{
if (!m_compositor)
return;
Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
Platform::createMethodCallMessage(
&WebPagePrivate::destroyCompositor, this));
}
void WebPagePrivate::destroyLayerResources()
{
m_compositor->releaseLayerResources();
}
void WebPagePrivate::suspendRootLayerCommit()
{
if (m_suspendRootLayerCommit)
return;
m_suspendRootLayerCommit = true;
if (!m_compositor)
return;
Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
Platform::createMethodCallMessage(&WebPagePrivate::destroyLayerResources, this));
}
void WebPagePrivate::resumeRootLayerCommit()
{
if (!m_suspendRootLayerCommit)
return;
m_suspendRootLayerCommit = false;
m_needsCommit = true;
commitRootLayerIfNeeded();
}
bool WebPagePrivate::needsOneShotDrawingSynchronization()
{
return m_needsOneShotDrawingSynchronization;
}
void WebPagePrivate::setNeedsOneShotDrawingSynchronization()
{
if (compositorDrawsRootLayer()) {
scheduleRootLayerCommit();
return;
}
m_needsCommit = true;
m_needsOneShotDrawingSynchronization = true;
}
#endif // USE(ACCELERATED_COMPOSITING)
void WebPagePrivate::enterFullscreenForNode(Node* node)
{
#if ENABLE(VIDEO)
if (!node || !node->hasTagName(HTMLNames::videoTag))
return;
MediaPlayer* player = static_cast<HTMLMediaElement*>(node)->player();
if (!player)
return;
MediaPlayerPrivate* mmrPlayer = static_cast<MediaPlayerPrivate*>(player->implementation());
if (!mmrPlayer)
return;
Platform::Graphics::Window* window = mmrPlayer->getWindow();
if (!window)
return;
unsigned x, y, width, height;
mmrPlayer->getWindowPosition(x, y, width, height);
const char* contextName = mmrPlayer->mmrContextName();
if (!contextName)
return;
mmrPlayer->setFullscreenWebPageClient(m_client);
m_fullscreenVideoNode = node;
m_client->fullscreenStart(contextName, window, x, y, width, height);
#endif
}
void WebPagePrivate::exitFullscreenForNode(Node* node)
{
#if ENABLE(VIDEO)
if (m_fullscreenVideoNode.get()) {
m_client->fullscreenStop();
m_fullscreenVideoNode = 0;
}
if (!node || !node->hasTagName(HTMLNames::videoTag))
return;
MediaPlayer* player = static_cast<HTMLMediaElement*>(node)->player();
if (!player)
return;
MediaPlayerPrivate* mmrPlayer = static_cast<MediaPlayerPrivate*>(player->implementation());
if (!mmrPlayer)
return;
mmrPlayer->setFullscreenWebPageClient(0);
#endif
}
void WebPagePrivate::didChangeSettings(WebSettings* webSettings)
{
Settings* coreSettings = m_page->settings();
m_page->setGroupName(webSettings->pageGroupName());
coreSettings->setXSSAuditorEnabled(webSettings->xssAuditorEnabled());
coreSettings->setLoadsImagesAutomatically(webSettings->loadsImagesAutomatically());
coreSettings->setShouldDrawBorderWhileLoadingImages(webSettings->shouldDrawBorderWhileLoadingImages());
coreSettings->setScriptEnabled(webSettings->isJavaScriptEnabled());
coreSettings->setPrivateBrowsingEnabled(webSettings->isPrivateBrowsingEnabled());
coreSettings->setDefaultFixedFontSize(webSettings->defaultFixedFontSize());
coreSettings->setDefaultFontSize(webSettings->defaultFontSize());
coreSettings->setMinimumLogicalFontSize(webSettings->minimumFontSize());
coreSettings->setSerifFontFamily(webSettings->serifFontFamily().impl());
coreSettings->setFixedFontFamily(webSettings->fixedFontFamily().impl());
coreSettings->setSansSerifFontFamily(webSettings->sansSerifFontFamily().impl());
coreSettings->setStandardFontFamily(webSettings->standardFontFamily().impl());
coreSettings->setJavaScriptCanOpenWindowsAutomatically(webSettings->canJavaScriptOpenWindowsAutomatically());
coreSettings->setAllowScriptsToCloseWindows(webSettings->canJavaScriptOpenWindowsAutomatically()); coreSettings->setPluginsEnabled(webSettings->arePluginsEnabled());
coreSettings->setDefaultTextEncodingName(webSettings->defaultTextEncodingName().impl());
coreSettings->setDownloadableBinaryFontsEnabled(webSettings->downloadableBinaryFontsEnabled());
coreSettings->setSpatialNavigationEnabled(m_webSettings->isSpatialNavigationEnabled());
WebString stylesheetURL = webSettings->userStyleSheetString();
if (stylesheetURL.isEmpty())
stylesheetURL = webSettings->userStyleSheetLocation();
if (!stylesheetURL.isEmpty())
coreSettings->setUserStyleSheetLocation(KURL(KURL(), stylesheetURL));
coreSettings->setFirstScheduledLayoutDelay(webSettings->firstScheduledLayoutDelay());
coreSettings->setUseCache(webSettings->useWebKitCache());
#if ENABLE(SQL_DATABASE)
static bool dbinit = false;
if (!dbinit && !webSettings->databasePath().isEmpty()) {
dbinit = true;
DatabaseTracker::initializeTracker(webSettings->databasePath());
}
static bool acinit = false;
if (!acinit && !webSettings->appCachePath().isEmpty()) {
acinit = true;
cacheStorage().setCacheDirectory(webSettings->appCachePath());
}
coreSettings->setLocalStorageDatabasePath(webSettings->localStoragePath());
Database::setIsAvailable(webSettings->isDatabasesEnabled());
DatabaseSync::setIsAvailable(webSettings->isDatabasesEnabled());
coreSettings->setLocalStorageEnabled(webSettings->isLocalStorageEnabled());
coreSettings->setOfflineWebApplicationCacheEnabled(webSettings->isAppCacheEnabled());
m_page->group().groupSettings()->setLocalStorageQuotaBytes(webSettings->localStorageQuota());
coreSettings->setUsesPageCache(webSettings->maximumPagesInCache());
coreSettings->setFrameFlatteningEnabled(webSettings->isFrameFlatteningEnabled());
#endif
#if ENABLE(WEB_SOCKETS)
WebSocket::setIsAvailable(webSettings->areWebSocketsEnabled());
#endif
#if ENABLE(VIEWPORT_REFLOW)
coreSettings->setTextReflowEnabled(webSettings->textReflowMode() == WebSettings::TextReflowEnabled);
#endif
coreSettings->setShouldUseFirstScheduledLayoutDelay(webSettings->isEmailMode());
coreSettings->setProcessHTTPEquiv(!webSettings->isEmailMode());
coreSettings->setShouldUseCrossOriginProtocolCheck(!webSettings->allowCrossSiteRequests());
cookieManager().setPrivateMode(webSettings->isPrivateBrowsingEnabled());
if (m_mainFrame && m_mainFrame->view()) {
Color backgroundColor(webSettings->backgroundColor());
m_mainFrame->view()->updateBackgroundRecursively(backgroundColor, backgroundColor.hasAlpha());
}
}
IntSize WebPagePrivate::defaultMaxLayoutSize()
{
static IntSize size;
if (size.isEmpty())
size = IntSize(std::max(1024, Platform::Graphics::Screen::primaryScreen()->landscapeWidth()),
std::max(768, Platform::Graphics::Screen::primaryScreen()->landscapeHeight()));
return size;
}
WebString WebPage::textHasAttribute(const WebString& query) const
{
if (Document* doc = d->m_page->focusController()->focusedOrMainFrame()->document())
return doc->queryCommandValue(query);
return "";
}
void WebPage::setJavaScriptCanAccessClipboard(bool enabled)
{
d->m_page->settings()->setJavaScriptCanAccessClipboard(enabled);
}
#if USE(ACCELERATED_COMPOSITING)
void WebPagePrivate::blitVisibleContents()
{
if (m_backingStore->d->shouldDirectRenderingToWindow())
return;
m_backingStore->d->blitVisibleContents();
}
#endif
void WebPage::setWebGLEnabled(bool enabled)
{
if (!Platform::ITPolicy::isWebGLEnabled()) {
d->m_page->settings()->setWebGLEnabled(false);
return;
}
d->m_page->settings()->setWebGLEnabled(enabled);
}
bool WebPage::isWebGLEnabled() const
{
return d->m_page->settings()->webGLEnabled();
}
void WebPagePrivate::setNeedTouchEvents(bool value)
{
m_needTouchEvents = value;
}
void WebPagePrivate::frameUnloaded(const Frame* frame)
{
m_inputHandler->frameUnloaded(frame);
m_inPageSearchManager->frameUnloaded(frame);
}
const String& WebPagePrivate::defaultUserAgent()
{
static String* defaultUserAgent = new String;
if (defaultUserAgent->isEmpty()) {
BlackBerry::Platform::DeviceInfo* info = BlackBerry::Platform::DeviceInfo::instance();
char uaBuffer[256];
int uaSize = snprintf(uaBuffer, 256, "Mozilla/5.0 (%s) AppleWebKit/%d.%d+ (KHTML, like Gecko) Version/%s %sSafari/%d.%d+",
info->family(), WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION, info->osVersion(),
info->isMobile() ? "Mobile " : "", WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION);
if (uaSize <= 0 || uaSize >= 256)
BLACKBERRY_CRASH();
defaultUserAgent->append(uaBuffer);
}
return *defaultUserAgent;
}
}
}