2 * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "ApplicationCacheStorage.h"
23 #include "AuthenticationChallengeManager.h"
24 #include "AutofillManager.h"
25 #include "BackForwardController.h"
26 #include "BackForwardListImpl.h"
27 #include "BackingStoreClient.h"
28 #include "BackingStore_p.h"
29 #if ENABLE(BATTERY_STATUS)
30 #include "BatteryClientBlackBerry.h"
32 #include "CachedImage.h"
34 #include "ChromeClientBlackBerry.h"
35 #include "ContextMenuClientBlackBerry.h"
36 #include "CookieManager.h"
37 #include "CredentialManager.h"
38 #include "CredentialStorage.h"
39 #include "CredentialTransformData.h"
40 #include "DOMSupport.h"
42 #include "DatabaseManager.h"
43 #include "DatabaseSync.h"
44 #include "DefaultTapHighlight.h"
45 #include "DeviceMotionClientBlackBerry.h"
46 #include "DeviceOrientationClientBlackBerry.h"
47 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
48 #include "DeviceOrientationClientMock.h"
50 #include "DragClientBlackBerry.h"
51 // FIXME: We should be using DumpRenderTreeClient, but I'm not sure where we should
52 // create the DRT_BB object. See PR #120355.
53 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
54 #include "DumpRenderTreeBlackBerry.h"
56 #include "EditorClientBlackBerry.h"
57 #include "FocusController.h"
59 #include "FrameLoadRequest.h"
60 #include "FrameLoaderClientBlackBerry.h"
61 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
62 #include "GeolocationClientMock.h"
64 #include "GeolocationClientBlackBerry.h"
65 #include "GroupSettings.h"
66 #include "HTMLAreaElement.h"
67 #include "HTMLFrameOwnerElement.h"
68 #include "HTMLImageElement.h"
69 #include "HTMLInputElement.h"
70 #include "HTMLMediaElement.h"
71 #include "HTMLNames.h"
72 #include "HTMLParserIdioms.h"
73 #include "HTTPParsers.h"
74 #include "HistoryItem.h"
75 #include "IconDatabaseClientBlackBerry.h"
76 #include "ImageDocument.h"
77 #include "InPageSearchManager.h"
78 #include "InRegionScrollableArea.h"
79 #include "InRegionScroller_p.h"
80 #include "InputHandler.h"
81 #include "InspectorBackendDispatcher.h"
82 #include "InspectorClientBlackBerry.h"
83 #include "InspectorController.h"
84 #include "InspectorInstrumentation.h"
85 #include "InspectorOverlay.h"
86 #include "JavaScriptVariant_p.h"
87 #include "LayerWebKitThread.h"
88 #if ENABLE(NETWORK_INFO)
89 #include "NetworkInfoClientBlackBerry.h"
91 #include "NetworkManager.h"
92 #include "NodeRenderStyle.h"
93 #include "NodeTraversal.h"
94 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
95 #include "NavigatorContentUtilsClientBlackBerry.h"
97 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
98 #include "NotificationClientBlackBerry.h"
101 #include "PageCache.h"
102 #include "PageGroup.h"
103 #include "PagePopupBlackBerry.h"
104 #include "PlatformTouchEvent.h"
105 #include "PlatformWheelEvent.h"
106 #include "PluginDatabase.h"
107 #include "PluginView.h"
108 #include "RenderLayerBacking.h"
109 #include "RenderLayerCompositor.h"
110 #if ENABLE(FULLSCREEN_API)
111 #include "RenderFullScreen.h"
113 #include "RenderText.h"
114 #include "RenderThemeBlackBerry.h"
115 #include "RenderTreeAsText.h"
116 #include "RenderView.h"
117 #include "RenderWidget.h"
118 #include "ScriptSourceCode.h"
119 #include "ScriptValue.h"
120 #include "ScrollTypes.h"
121 #include "SecurityPolicy.h"
122 #include "SelectionHandler.h"
123 #include "SelectionOverlay.h"
124 #include "Settings.h"
126 #include "StorageNamespace.h"
127 #include "SurfacePool.h"
129 #include "ThreadCheck.h"
130 #include "TouchEventHandler.h"
131 #include "TransformationMatrix.h"
132 #if ENABLE(MEDIA_STREAM)
133 #include "UserMediaClientImpl.h"
135 #if ENABLE(VIBRATION)
136 #include "VibrationClientBlackBerry.h"
138 #include "VisiblePosition.h"
139 #include "WebCookieJar.h"
141 #include "WebDOMDocument.h"
143 #include "WebKitThreadViewportAccessor.h"
144 #include "WebKitVersion.h"
145 #include "WebOverlay.h"
146 #include "WebOverlay_p.h"
147 #include "WebPageClient.h"
148 #include "WebSocket.h"
149 #include "WebViewportArguments.h"
151 #include "runtime_root.h"
154 #include "MediaPlayer.h"
155 #include "MediaPlayerPrivateBlackBerry.h"
159 #include "PlatformContextSkia.h"
162 #if USE(ACCELERATED_COMPOSITING)
163 #include "FrameLayers.h"
164 #include "WebPageCompositorClient.h"
165 #include "WebPageCompositor_p.h"
168 #include <BlackBerryPlatformDeviceInfo.h>
169 #include <BlackBerryPlatformExecutableMessage.h>
170 #include <BlackBerryPlatformKeyboardEvent.h>
171 #include <BlackBerryPlatformMessageClient.h>
172 #include <BlackBerryPlatformMouseEvent.h>
173 #include <BlackBerryPlatformScreen.h>
174 #include <BlackBerryPlatformSettings.h>
175 #include <JavaScriptCore/APICast.h>
176 #include <JavaScriptCore/JSContextRef.h>
177 #include <JavaScriptCore/JSStringRef.h>
178 #include <SharedPointer.h>
179 #include <sys/keycodes.h>
180 #include <unicode/ustring.h> // platform ICU
182 #include <wtf/text/CString.h>
184 #ifndef USER_PROCESSES
185 #include <memalloc.h>
188 #if ENABLE(ACCELERATED_2D_CANVAS)
189 #include "GrContext.h"
190 #include "SharedGraphicsContext3D.h"
193 #if ENABLE(REQUEST_ANIMATION_FRAME)
194 #include "PlatformScreen.h"
197 #define DEBUG_TOUCH_EVENTS 0
198 #define DEBUG_WEBPAGE_LOAD 0
199 #define DEBUG_AC_COMMIT 0
202 using namespace WebCore;
204 typedef const unsigned short* CUShortPtr;
206 namespace BlackBerry {
209 static Vector<WebPage*>* visibleWebPages()
211 static Vector<WebPage*>* s_visibleWebPages = 0; // Initially, no web page is visible.
212 if (!s_visibleWebPages)
213 s_visibleWebPages = new Vector<WebPage*>;
214 return s_visibleWebPages;
217 const unsigned blockZoomMargin = 3; // Add 3 pixel margin on each side.
218 static int blockClickRadius = 0;
219 static double maximumBlockZoomScale = 3; // This scale can be clamped by the maximumScale set for the page.
221 const double manualScrollInterval = 0.1; // The time interval during which we associate user action with scrolling.
223 const IntSize minimumLayoutSize(10, 10); // Needs to be a small size, greater than 0, that we can grow the layout from.
225 const double minimumExpandingRatio = 0.15;
227 const double minimumZoomToFitScale = 0.25;
228 const double maximumImageDocumentZoomToFitScale = 2;
230 // Helper function to parse a URL and fill in missing parts.
231 static KURL parseUrl(const String& url)
233 String urlString(url);
234 KURL kurl = KURL(KURL(), urlString);
235 if (kurl.protocol().isEmpty()) {
236 urlString.insert("http://", 0);
237 kurl = KURL(KURL(), urlString);
243 // Helper functions to convert to and from WebCore types.
244 static inline WebCore::PlatformEvent::Type toWebCoreMouseEventType(const BlackBerry::Platform::MouseEvent::Type type)
247 case BlackBerry::Platform::MouseEvent::MouseButtonDown:
248 return WebCore::PlatformEvent::MousePressed;
249 case Platform::MouseEvent::MouseButtonUp:
250 return WebCore::PlatformEvent::MouseReleased;
251 case Platform::MouseEvent::MouseMove:
253 return WebCore::PlatformEvent::MouseMoved;
257 static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy)
260 case Platform::NetworkRequest::UseProtocolCachePolicy:
261 return UseProtocolCachePolicy;
262 case Platform::NetworkRequest::ReloadIgnoringCacheData:
263 return ReloadIgnoringCacheData;
264 case Platform::NetworkRequest::ReturnCacheDataElseLoad:
265 return ReturnCacheDataElseLoad;
266 case Platform::NetworkRequest::ReturnCacheDataDontLoad:
267 return ReturnCacheDataDontLoad;
269 ASSERT_NOT_REACHED();
270 return UseProtocolCachePolicy;
274 #if ENABLE(EVENT_MODE_METATAGS)
275 static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode)
278 case ProcessedCursorEvents:
279 return Platform::ProcessedCursorEvents;
280 case NativeCursorEvents:
281 return Platform::NativeCursorEvents;
283 ASSERT_NOT_REACHED();
284 return Platform::ProcessedCursorEvents;
288 static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode)
291 case ProcessedTouchEvents:
292 return Platform::ProcessedTouchEvents;
293 case NativeTouchEvents:
294 return Platform::NativeTouchEvents;
295 case PureTouchEventsWithMouseConversion:
296 return Platform::PureTouchEventsWithMouseConversion;
298 ASSERT_NOT_REACHED();
299 return Platform::ProcessedTouchEvents;
304 static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id)
306 return reinterpret_cast<HistoryItem*>(id);
309 static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item)
311 return reinterpret_cast<WebPage::BackForwardId>(item);
314 void WebPage::setUserViewportArguments(const WebViewportArguments& viewportArguments)
316 d->m_userViewportArguments = *(viewportArguments.d);
319 void WebPage::resetUserViewportArguments()
321 d->m_userViewportArguments = ViewportArguments();
324 template <bool WebPagePrivate::* isActive>
325 class DeferredTask: public WebPagePrivate::DeferredTaskBase {
327 static void finishOrCancel(WebPagePrivate* webPagePrivate)
329 webPagePrivate->*isActive = false;
332 DeferredTask(WebPagePrivate* webPagePrivate)
333 : DeferredTaskBase(webPagePrivate, isActive)
336 typedef DeferredTask<isActive> DeferredTaskType;
339 void WebPage::autofillTextField(const BlackBerry::Platform::String& item)
341 if (!d->m_webSettings->isFormAutofillEnabled())
344 d->m_autofillManager->autofillTextField(item);
347 void WebPage::enableQnxJavaScriptObject(bool enabled)
349 d->m_enableQnxJavaScriptObject = enabled;
352 BlackBerry::Platform::String WebPage::renderTreeAsText()
354 return externalRepresentation(d->m_mainFrame);
357 WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
360 , m_inspectorClient(0)
361 , m_page(0) // Initialized by init.
362 , m_mainFrame(0) // Initialized by init.
363 , m_currentContextNode(0)
364 , m_webSettings(0) // Initialized by init.
367 , m_activationState(ActivationActive)
368 , m_shouldResetTilesWhenShown(false)
369 , m_shouldZoomToInitialScaleAfterLoadFinished(false)
370 , m_userScalable(true)
371 , m_userPerformedManualZoom(false)
372 , m_userPerformedManualScroll(false)
373 , m_contentsSizeChanged(false)
374 , m_overflowExceedsContentsSize(false)
375 , m_resetVirtualViewportOnCommitted(true)
376 , m_shouldUseFixedDesktopMode(false)
377 , m_preventIdleDimmingCount(0)
378 #if ENABLE(TOUCH_EVENTS)
379 , m_preventDefaultOnTouchStart(false)
381 , m_nestedLayoutFinishedCount(0)
382 , m_actualVisibleWidth(rect.width())
383 , m_actualVisibleHeight(rect.height())
384 , m_defaultLayoutSize(minimumLayoutSize)
385 , m_didRestoreFromPageCache(false)
386 , m_viewMode(WebPagePrivate::Desktop) // Default to Desktop mode for PB.
387 , m_loadState(WebPagePrivate::None)
388 , m_transformationMatrix(new TransformationMatrix())
389 , m_backingStore(0) // Initialized by init.
390 , m_backingStoreClient(0) // Initialized by init.
391 , m_webkitThreadViewportAccessor(0) // Initialized by init.
392 , m_inPageSearchManager(new InPageSearchManager(this))
393 , m_inputHandler(new InputHandler(this))
394 , m_selectionHandler(new SelectionHandler(this))
395 , m_touchEventHandler(new TouchEventHandler(this))
396 #if ENABLE(EVENT_MODE_METATAGS)
397 , m_cursorEventMode(ProcessedCursorEvents)
398 , m_touchEventMode(ProcessedTouchEvents)
400 #if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
401 , m_scaleBeforeFullScreen(-1.0)
403 , m_currentCursor(Platform::CursorNone)
404 , m_dumpRenderTree(0) // Lazy initialization.
405 , m_initialScale(-1.0)
406 , m_minimumScale(-1.0)
407 , m_maximumScale(-1.0)
408 , m_forceRespectViewportArguments(false)
409 , m_blockZoomFinalScale(1.0)
410 , m_anchorInNodeRectRatio(-1, -1)
411 , m_currentBlockZoomNode(0)
412 , m_currentBlockZoomAdjustedNode(0)
413 , m_shouldReflowBlock(false)
414 , m_shouldConstrainScrollingToContentEdge(true)
415 , m_lastUserEventTimestamp(0.0)
416 , m_pluginMouseButtonPressed(false)
417 , m_pluginMayOpenNewTab(false)
418 #if USE(ACCELERATED_COMPOSITING)
419 , m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
420 , m_needsOneShotDrawingSynchronization(false)
421 , m_needsCommit(false)
422 , m_suspendRootLayerCommit(false)
424 , m_pendingOrientation(-1)
425 , m_fullscreenNode(0)
426 , m_hasInRegionScrollableAreas(false)
427 , m_updateDelegatedOverlaysDispatched(false)
428 , m_enableQnxJavaScriptObject(false)
429 , m_deferredTasksTimer(this, &WebPagePrivate::deferredTasksTimerFired)
431 , m_autofillManager(AutofillManager::create(this))
432 , m_documentStyleRecalcPostponed(false)
433 , m_documentChildNeedsStyleRecalc(false)
434 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
435 , m_notificationManager(this)
438 static bool isInitialized = false;
439 if (!isInitialized) {
440 isInitialized = true;
441 BlackBerry::Platform::DeviceInfo::instance();
445 AuthenticationChallengeManager::instance()->pageCreated(this);
446 clearCachedHitTestResult();
449 WebPage::WebPage(WebPageClient* client, const BlackBerry::Platform::String& pageGroupName, const Platform::IntRect& rect)
452 d = new WebPagePrivate(this, client, rect);
453 d->init(pageGroupName);
456 WebPagePrivate::~WebPagePrivate()
458 // Hand the backingstore back to another owner if necessary.
459 m_webPage->setVisible(false);
460 if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage)
461 BackingStorePrivate::setCurrentBackingStoreOwner(0);
463 delete m_webSettings;
469 delete m_webkitThreadViewportAccessor;
470 m_webkitThreadViewportAccessor = 0;
472 delete m_backingStoreClient;
473 m_backingStoreClient = 0;
479 delete m_transformationMatrix;
480 m_transformationMatrix = 0;
482 delete m_inPageSearchManager;
483 m_inPageSearchManager = 0;
485 delete m_selectionHandler;
486 m_selectionHandler = 0;
488 delete m_inputHandler;
491 delete m_touchEventHandler;
492 m_touchEventHandler = 0;
494 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
495 delete m_dumpRenderTree;
496 m_dumpRenderTree = 0;
499 AuthenticationChallengeManager::instance()->pageDeleted(this);
504 deleteGuardedObject(d);
508 Page* WebPagePrivate::core(const WebPage* webPage)
510 return webPage->d->m_page;
513 void WebPagePrivate::init(const BlackBerry::Platform::String& pageGroupName)
515 ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this);
516 ContextMenuClientBlackBerry* contextMenuClient = 0;
517 #if ENABLE(CONTEXT_MENUS)
518 contextMenuClient = new ContextMenuClientBlackBerry();
520 EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this);
521 DragClientBlackBerry* dragClient = 0;
522 #if ENABLE(DRAG_SUPPORT)
523 dragClient = new DragClientBlackBerry();
525 #if ENABLE(INSPECTOR)
526 m_inspectorClient = new InspectorClientBlackBerry(this);
529 FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry();
531 Page::PageClients pageClients;
532 pageClients.chromeClient = chromeClient;
533 pageClients.contextMenuClient = contextMenuClient;
534 pageClients.editorClient = editorClient;
535 pageClients.dragClient = dragClient;
536 pageClients.inspectorClient = m_inspectorClient;
538 m_page = new Page(pageClients);
539 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
540 if (isRunningDrt()) {
541 // In case running in DumpRenderTree mode set the controller to mock provider.
542 GeolocationClientMock* mock = new GeolocationClientMock();
543 WebCore::provideGeolocationTo(m_page, mock);
544 mock->setController(WebCore::GeolocationController::from(m_page));
547 WebCore::provideGeolocationTo(m_page, new GeolocationClientBlackBerry(this));
548 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
549 if (getenv("drtRun"))
550 WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientMock);
553 WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientBlackBerry(this));
555 WebCore::provideDeviceMotionTo(m_page, new DeviceMotionClientBlackBerry(this));
556 #if ENABLE(VIBRATION)
557 WebCore::provideVibrationTo(m_page, new VibrationClientBlackBerry());
560 #if ENABLE(BATTERY_STATUS)
561 WebCore::provideBatteryTo(m_page, new WebCore::BatteryClientBlackBerry(this));
564 #if ENABLE(MEDIA_STREAM)
565 WebCore::provideUserMediaTo(m_page, new UserMediaClientImpl(m_webPage));
568 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
569 WebCore::provideNotification(m_page, new NotificationClientBlackBerry(this));
572 #if ENABLE(NAVIGATOR_CONTENT_UTILS)
573 WebCore::provideNavigatorContentUtilsTo(m_page, new NavigatorContentUtilsClientBlackBerry(this));
576 #if ENABLE(NETWORK_INFO)
577 WebCore::provideNetworkInfoTo(m_page, new WebCore::NetworkInfoClientBlackBerry(this));
580 m_webSettings = WebSettings::createFromStandardSettings();
581 m_webSettings->setUserAgentString(defaultUserAgent());
582 m_page->setDeviceScaleFactor(m_webSettings->devicePixelRatio());
584 m_page->addLayoutMilestones(DidFirstVisuallyNonEmptyLayout);
586 #if USE(ACCELERATED_COMPOSITING)
587 m_tapHighlight = DefaultTapHighlight::create(this);
588 m_selectionOverlay = SelectionOverlay::create(this);
589 m_page->settings()->setAcceleratedCompositingForFixedPositionEnabled(true);
592 // FIXME: We explicitly call setDelegate() instead of passing ourself in createFromStandardSettings()
593 // so that we only get one didChangeSettings() callback when we set the page group name. This causes us
594 // to make a copy of the WebSettings since some WebSettings method make use of the page group name.
595 // Instead, we shouldn't be storing the page group name in WebSettings.
596 m_webSettings->setPageGroupName(pageGroupName);
597 m_webSettings->setDelegate(this);
598 didChangeSettings(m_webSettings);
600 RefPtr<Frame> newFrame = Frame::create(m_page, /* HTMLFrameOwnerElement* */ 0, frameLoaderClient);
602 m_mainFrame = newFrame.get();
603 frameLoaderClient->setFrame(m_mainFrame, this);
606 m_inRegionScroller = adoptPtr(new InRegionScroller(this));
609 m_page->settings()->setWebGLEnabled(true);
611 #if ENABLE(ACCELERATED_2D_CANVAS)
612 m_page->settings()->setCanvasUsesAcceleratedDrawing(true);
613 m_page->settings()->setAccelerated2dCanvasEnabled(true);
616 m_page->settings()->setInteractiveFormValidationEnabled(true);
617 m_page->settings()->setAllowUniversalAccessFromFileURLs(false);
618 m_page->settings()->setAllowFileAccessFromFileURLs(false);
619 m_page->settings()->setFixedPositionCreatesStackingContext(true);
621 m_backingStoreClient = BackingStoreClient::create(m_mainFrame, /* parent frame */ 0, m_webPage);
622 // The direct access to BackingStore is left here for convenience since it
623 // is owned by BackingStoreClient and then deleted by its destructor.
624 m_backingStore = m_backingStoreClient->backingStore();
626 m_webkitThreadViewportAccessor = new WebKitThreadViewportAccessor(this);
628 blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(0).width())); // The clicked rectangle area should be a fixed unit of measurement.
630 m_page->settings()->setDelegateSelectionPaint(true);
632 #if ENABLE(REQUEST_ANIMATION_FRAME)
633 m_page->windowScreenDidChange((PlatformDisplayID)0);
636 #if ENABLE(WEB_TIMING)
637 m_page->settings()->setMemoryInfoEnabled(true);
640 #if USE(ACCELERATED_COMPOSITING)
641 // The compositor will be needed for overlay rendering, so create it
642 // unconditionally. It will allocate OpenGL objects lazily, so this incurs
643 // no overhead in the unlikely case where the compositor is not needed.
644 Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
645 createMethodCallMessage(&WebPagePrivate::createCompositor, this));
649 class DeferredTaskLoadManualScript: public DeferredTask<&WebPagePrivate::m_wouldLoadManualScript> {
651 explicit DeferredTaskLoadManualScript(WebPagePrivate* webPagePrivate, const KURL& url)
652 : DeferredTaskType(webPagePrivate)
654 webPagePrivate->m_cachedManualScript = url;
657 virtual void performInternal(WebPagePrivate* webPagePrivate)
659 webPagePrivate->m_mainFrame->script()->executeIfJavaScriptURL(webPagePrivate->m_cachedManualScript, DoNotReplaceDocumentIfJavaScriptURL);
663 void WebPagePrivate::load(const BlackBerry::Platform::String& url, const BlackBerry::Platform::String& networkToken, const BlackBerry::Platform::String& method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool isInitial, bool mustHandleInternally, bool forceDownload, const BlackBerry::Platform::String& overrideContentType, const BlackBerry::Platform::String& suggestedSaveName)
666 DeferredTaskLoadManualScript::finishOrCancel(this);
668 String urlString(url);
669 if (urlString.startsWith("vs:", false)) {
670 urlString = urlString.substring(3);
671 m_mainFrame->setInViewSourceMode(true);
673 m_mainFrame->setInViewSourceMode(false);
675 KURL kurl = parseUrl(urlString);
676 if (protocolIs(kurl, "javascript")) {
677 // Never run javascript while loading is deferred.
678 if (m_page->defersLoading())
679 m_deferredTasks.append(adoptPtr(new DeferredTaskLoadManualScript(this, kurl)));
681 m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL);
686 NetworkManager::instance()->setInitialURL(kurl);
688 ResourceRequest request(kurl);
689 request.setToken(networkToken);
690 if (isInitial || mustHandleInternally)
691 request.setMustHandleInternally(true);
692 request.setHTTPMethod(method);
693 request.setCachePolicy(toWebCoreCachePolicy(cachePolicy));
694 if (!overrideContentType.empty())
695 request.setOverrideContentType(overrideContentType);
698 request.setHTTPBody(FormData::create(data, dataLength));
700 for (unsigned i = 0; i + 1 < headersLength; i += 2)
701 request.addHTTPHeaderField(headers[i], headers[i + 1]);
704 request.setForceDownload(true);
706 request.setSuggestedSaveName(suggestedSaveName);
708 FrameLoadRequest frameRequest(m_mainFrame, request);
709 frameRequest.setFrameName("");
710 frameRequest.setShouldCheckNewWindowPolicy(true);
711 m_mainFrame->loader()->load(frameRequest);
714 void WebPage::load(const BlackBerry::Platform::String& url, const BlackBerry::Platform::String& networkToken, bool isInitial)
716 d->load(url, networkToken, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, isInitial, false);
719 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)
721 d->load(url, networkToken, method, cachePolicy, data, dataLength, headers, headersLength, false, mustHandleInternally, false, "");
724 void WebPage::loadFile(const BlackBerry::Platform::String& path, const BlackBerry::Platform::String& overrideContentType)
726 BlackBerry::Platform::String fileUrl(path);
727 if (fileUrl.startsWith("/"))
728 fileUrl = BlackBerry::Platform::String("file://", 7) + fileUrl;
729 else if (!fileUrl.startsWith("file:///"))
732 d->load(fileUrl, BlackBerry::Platform::String::emptyString(), BlackBerry::Platform::String("GET", 3), Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, false, overrideContentType.c_str());
735 void WebPage::download(const Platform::NetworkRequest& request)
737 vector<const char*> headers;
738 Platform::NetworkRequest::HeaderList& list = request.getHeaderListRef();
739 for (unsigned i = 0; i < list.size(); i++) {
740 headers.push_back(list[i].first.c_str());
741 headers.push_back(list[i].second.c_str());
743 d->load(request.getUrlRef(), BlackBerry::Platform::String::emptyString(), "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, headers.empty() ? 0 : &headers[0], headers.size(), false, false, true, "", request.getSuggestedSaveName().c_str());
746 void WebPagePrivate::loadString(const BlackBerry::Platform::String& string, const BlackBerry::Platform::String& baseURL, const BlackBerry::Platform::String& contentType, const BlackBerry::Platform::String& failingURL)
748 KURL kurl = parseUrl(baseURL);
749 ResourceRequest request(kurl);
750 WTF::RefPtr<SharedBuffer> buffer
751 = SharedBuffer::create(string.c_str(), string.length());
752 SubstituteData substituteData(buffer,
753 extractMIMETypeFromMediaType(contentType),
754 extractCharsetFromMediaType(contentType),
755 !failingURL.empty() ? parseUrl(failingURL) : KURL());
756 m_mainFrame->loader()->load(FrameLoadRequest(m_mainFrame, request, substituteData));
759 void WebPage::loadString(const BlackBerry::Platform::String& string, const BlackBerry::Platform::String& baseURL, const BlackBerry::Platform::String& mimeType, const BlackBerry::Platform::String& failingURL)
761 d->loadString(string, baseURL, mimeType, failingURL);
764 bool WebPagePrivate::executeJavaScript(const BlackBerry::Platform::String& scriptUTF8, JavaScriptDataType& returnType, WebString& returnValue)
766 BLACKBERRY_ASSERT(scriptUTF8.isUtf8());
767 String script = scriptUTF8;
769 if (script.isNull()) {
770 returnType = JSException;
774 if (script.isEmpty()) {
775 returnType = JSUndefined;
779 ScriptValue result = m_mainFrame->script()->executeScript(script, false);
780 JSC::JSValue value = result.jsValue();
782 returnType = JSException;
786 if (value.isUndefined())
787 returnType = JSUndefined;
788 else if (value.isNull())
790 else if (value.isBoolean())
791 returnType = JSBoolean;
792 else if (value.isNumber())
793 returnType = JSNumber;
794 else if (value.isString())
795 returnType = JSString;
796 else if (value.isObject())
797 returnType = JSObject;
799 returnType = JSUndefined;
801 if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
802 JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
803 returnValue = result.toString(exec);
809 bool WebPage::executeJavaScript(const BlackBerry::Platform::String& script, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue)
811 return d->executeJavaScript(script, returnType, returnValue);
814 bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& sourceCode, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue)
816 if (!m_isolatedWorld)
817 m_isolatedWorld = m_mainFrame->script()->createWorld();
819 // Use evaluateInWorld to avoid canExecuteScripts check.
820 ScriptValue result = m_mainFrame->script()->evaluateInWorld(sourceCode, m_isolatedWorld.get());
821 JSC::JSValue value = result.jsValue();
823 returnType = JSException;
827 if (value.isUndefined())
828 returnType = JSUndefined;
829 else if (value.isNull())
831 else if (value.isBoolean())
832 returnType = JSBoolean;
833 else if (value.isNumber())
834 returnType = JSNumber;
835 else if (value.isString())
836 returnType = JSString;
837 else if (value.isObject())
838 returnType = JSObject;
840 returnType = JSUndefined;
842 if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
843 JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
844 returnValue = result.toString(exec);
850 bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue)
852 // On our platform wchar_t is unsigned int and UChar is unsigned short
853 // so we have to convert using ICU conversion function
854 int lengthCopied = 0;
855 UErrorCode error = U_ZERO_ERROR;
856 const int length = script.length() + 1 /*null termination char*/;
859 // FIXME: PR 138162 is giving U_INVALID_CHAR_FOUND error.
860 u_strFromUTF32(data, length, &lengthCopied, reinterpret_cast<const UChar32*>(script.c_str()), script.length(), &error);
861 BLACKBERRY_ASSERT(error == U_ZERO_ERROR);
862 if (error != U_ZERO_ERROR) {
863 Platform::logAlways(Platform::LogLevelCritical, "WebPage::executeJavaScriptInIsolatedWorld failed to convert UTF16 to JavaScript!");
866 String str = String(data, lengthCopied);
867 ScriptSourceCode sourceCode(str, KURL());
868 return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
871 bool WebPage::executeJavaScriptInIsolatedWorld(const BlackBerry::Platform::String& scriptUTF8, JavaScriptDataType& returnType, BlackBerry::Platform::String& returnValue)
873 BLACKBERRY_ASSERT(scriptUTF8.isUtf8());
874 ScriptSourceCode sourceCode(scriptUTF8, KURL());
875 return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
878 void WebPage::executeJavaScriptFunction(const std::vector<BlackBerry::Platform::String> &function, const std::vector<JavaScriptVariant> &args, JavaScriptVariant& returnValue)
880 if (!d->m_mainFrame) {
881 returnValue.setType(JavaScriptVariant::Exception);
885 JSC::Bindings::RootObject* root = d->m_mainFrame->script()->bindingRootObject();
887 returnValue.setType(JavaScriptVariant::Exception);
891 JSC::ExecState* exec = root->globalObject()->globalExec();
892 JSGlobalContextRef ctx = toGlobalRef(exec);
894 JSC::JSLockHolder lock(exec);
895 WTF::Vector<JSValueRef> argListRef(args.size());
896 for (unsigned i = 0; i < args.size(); ++i)
897 argListRef[i] = BlackBerryJavaScriptVariantToJSValueRef(ctx, args[i]);
899 JSValueRef windowObjectValue = windowObject();
900 JSObjectRef obj = JSValueToObject(ctx, windowObjectValue, 0);
901 JSObjectRef thisObject = obj;
902 for (unsigned i = 0; i < function.size(); ++i) {
903 JSStringRef str = JSStringCreateWithUTF8CString(function[i].c_str());
905 obj = JSValueToObject(ctx, JSObjectGetProperty(ctx, obj, str, 0), 0);
906 JSStringRelease(str);
911 JSObjectRef functionObject = obj;
912 JSValueRef result = 0;
913 if (functionObject && thisObject)
914 result = JSObjectCallAsFunction(ctx, functionObject, thisObject, args.size(), argListRef.data(), 0);
917 returnValue.setType(JavaScriptVariant::Exception);
921 returnValue = JSValueRefToBlackBerryJavaScriptVariant(ctx, result);
924 void WebPagePrivate::stopCurrentLoad()
926 // This function should contain all common code triggered by WebPage::load
927 // (which stops any load in progress before starting the new load) and
928 // WebPage::stoploading (the entry point for the client to stop the load
929 // explicitly). If it should only be done while stopping the load
930 // explicitly, it goes in WebPage::stopLoading, not here.
931 m_mainFrame->loader()->stopAllLoaders();
933 // Cancel any deferred script that hasn't been processed yet.
934 DeferredTaskLoadManualScript::finishOrCancel(this);
937 void WebPage::stopLoading()
939 d->stopCurrentLoad();
942 static void closeURLRecursively(Frame* frame)
944 // Do not create more frame please.
945 FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client());
946 frameLoaderClient->suppressChildFrameCreation();
948 frame->loader()->closeURL();
950 Vector<RefPtr<Frame>, 10> childFrames;
952 for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
953 childFrames.append(childFrame);
955 unsigned size = childFrames.size();
956 for (unsigned i = 0; i < size; i++)
957 closeURLRecursively(childFrames[i].get());
960 void WebPagePrivate::prepareToDestroy()
962 // Before the client starts tearing itself down, dispatch the unload event
963 // so it can take effect while all the client's state (e.g. scroll position)
965 closeURLRecursively(m_mainFrame);
968 void WebPage::prepareToDestroy()
970 d->prepareToDestroy();
973 bool WebPage::dispatchBeforeUnloadEvent()
975 return d->m_page->mainFrame()->loader()->shouldClose();
978 static void enableCrossSiteXHRRecursively(Frame* frame)
980 frame->document()->securityOrigin()->grantUniversalAccess();
982 Vector<RefPtr<Frame>, 10> childFrames;
983 for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
984 childFrames.append(childFrame);
986 unsigned size = childFrames.size();
987 for (unsigned i = 0; i < size; i++)
988 enableCrossSiteXHRRecursively(childFrames[i].get());
991 void WebPagePrivate::enableCrossSiteXHR()
993 enableCrossSiteXHRRecursively(m_mainFrame);
996 void WebPage::enableCrossSiteXHR()
998 d->enableCrossSiteXHR();
1001 void WebPagePrivate::addOriginAccessWhitelistEntry(const BlackBerry::Platform::String& sourceOrigin, const BlackBerry::Platform::String& destinationOrigin, bool allowDestinationSubdomains)
1003 RefPtr<SecurityOrigin> source = SecurityOrigin::createFromString(sourceOrigin);
1004 if (source->isUnique())
1007 KURL destination(KURL(), destinationOrigin);
1008 SecurityPolicy::addOriginAccessWhitelistEntry(*source, destination.protocol(), destination.host(), allowDestinationSubdomains);
1011 void WebPage::addOriginAccessWhitelistEntry(const BlackBerry::Platform::String& sourceOrigin, const BlackBerry::Platform::String& destinationOrigin, bool allowDestinationSubdomains)
1013 d->addOriginAccessWhitelistEntry(sourceOrigin, destinationOrigin, allowDestinationSubdomains);
1016 void WebPagePrivate::removeOriginAccessWhitelistEntry(const BlackBerry::Platform::String& sourceOrigin, const BlackBerry::Platform::String& destinationOrigin, bool allowDestinationSubdomains)
1018 RefPtr<SecurityOrigin> source = SecurityOrigin::createFromString(sourceOrigin);
1019 if (source->isUnique())
1022 KURL destination(KURL(), destinationOrigin);
1023 SecurityPolicy::removeOriginAccessWhitelistEntry(*source, destination.protocol(), destination.host(), allowDestinationSubdomains);
1026 void WebPage::removeOriginAccessWhitelistEntry(const BlackBerry::Platform::String& sourceOrigin, const BlackBerry::Platform::String& destinationOrigin, bool allowDestinationSubdomains)
1028 d->removeOriginAccessWhitelistEntry(sourceOrigin, destinationOrigin, allowDestinationSubdomains);
1031 void WebPagePrivate::setLoadState(LoadState state)
1033 if (m_loadState == state)
1036 bool isFirstLoad = m_loadState == None;
1038 // See RIM Bug #1068.
1039 if (state == Finished && m_mainFrame && m_mainFrame->document())
1040 m_mainFrame->document()->updateStyleIfNeeded();
1042 // Dispatch the backingstore background color at important state changes.
1043 m_backingStore->d->setWebPageBackgroundColor(m_mainFrame && m_mainFrame->view()
1044 ? m_mainFrame->view()->documentBackgroundColor()
1045 : m_webSettings->backgroundColor());
1047 m_loadState = state;
1049 #if DEBUG_WEBPAGE_LOAD
1050 Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state);
1053 switch (m_loadState) {
1056 // Paints the visible backingstore as settings()->backgroundColor()
1057 // to prevent initial checkerboard on the first blit.
1058 m_backingStore->d->renderAndBlitVisibleContentsImmediately();
1063 #if ENABLE(ACCELERATED_2D_CANVAS)
1064 if (m_page->settings()->canvasUsesAcceleratedDrawing()) {
1065 // Free GPU resources as we're on a new page.
1066 // This will help us to free memory pressure.
1067 SharedGraphicsContext3D::get()->makeContextCurrent();
1068 GrContext* grContext = Platform::Graphics::getGrContext();
1069 grContext->freeGpuResources();
1073 #if USE(ACCELERATED_COMPOSITING)
1074 releaseLayerResources();
1077 // Suspend screen update to avoid ui thread blitting while resetting backingstore.
1078 // FIXME: Do we really need to suspend/resume both backingstore and screen here?
1079 m_backingStore->d->suspendBackingStoreUpdates();
1080 m_backingStore->d->suspendScreenUpdates();
1082 m_previousContentsSize = IntSize();
1083 m_backingStore->d->resetRenderQueue();
1084 m_backingStore->d->resetTiles();
1085 m_backingStore->d->setScrollingOrZooming(false, false /* shouldBlit */);
1086 m_shouldZoomToInitialScaleAfterLoadFinished = false;
1087 m_userPerformedManualZoom = false;
1088 m_userPerformedManualScroll = false;
1089 m_shouldUseFixedDesktopMode = false;
1090 m_forceRespectViewportArguments = false;
1091 if (m_resetVirtualViewportOnCommitted) // For DRT.
1092 m_virtualViewportSize = IntSize();
1093 if (m_webSettings->viewportWidth() > 0)
1094 m_virtualViewportSize = IntSize(m_webSettings->viewportWidth(), m_defaultLayoutSize.height());
1096 // Check if we have already process the meta viewport tag, this only happens on history navigation.
1097 // For back/forward history navigation, we should only keep these previous values if the document
1098 // has the meta viewport tag when the state is Committed in setLoadState.
1099 static ViewportArguments defaultViewportArguments;
1100 bool documentHasViewportArguments = false;
1101 if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->viewportArguments() != defaultViewportArguments)
1102 documentHasViewportArguments = true;
1103 if (!(m_didRestoreFromPageCache && documentHasViewportArguments)) {
1104 m_viewportArguments = ViewportArguments();
1105 m_userScalable = m_webSettings->isUserScalable();
1108 // At the moment we commit a new load, set the viewport arguments
1109 // to any fallback values. If there is a meta viewport in the
1110 // content it will overwrite the fallback arguments soon.
1111 dispatchViewportPropertiesDidChange(m_userViewportArguments);
1112 if (m_userViewportArguments != defaultViewportArguments)
1113 m_forceRespectViewportArguments = true;
1115 Platform::IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
1116 m_webPage->setVirtualViewportSize(virtualViewport);
1117 if (m_shouldUseFixedDesktopMode)
1118 setViewMode(FixedDesktop);
1120 setViewMode(Desktop);
1123 #if ENABLE(EVENT_MODE_METATAGS)
1124 didReceiveCursorEventMode(ProcessedCursorEvents);
1125 didReceiveTouchEventMode(ProcessedTouchEvents);
1128 // Reset block zoom and reflow.
1130 #if ENABLE(VIEWPORT_REFLOW)
1131 toggleTextReflowIfEnabledForBlockZoomOnly();
1134 // Notify InputHandler of state change.
1135 m_inputHandler->setInputModeEnabled(false);
1137 // Set the scroll to origin here and notify the client since we'll be
1138 // zooming below without any real contents yet thus the contents size
1139 // we report to the client could make our current scroll position invalid.
1140 setScrollPosition(IntPoint::zero());
1141 notifyTransformedScrollChanged();
1143 // FIXME: Do we really need to suspend/resume both backingstore and screen here?
1144 m_backingStore->d->resumeBackingStoreUpdates();
1145 // Paints the visible backingstore as white. Note it is important we do
1146 // this strictly after re-setting the scroll position to origin and resetting
1147 // the scales otherwise the visible contents calculation is wrong and we
1148 // can end up blitting artifacts instead. See: RIM Bug #401.
1149 m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit);
1151 // Update cursor status.
1158 // Notify client of the initial zoom change.
1159 m_client->scaleChanged();
1160 m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
1167 double WebPagePrivate::clampedScale(double scale) const
1169 if (scale < minimumScale())
1170 return minimumScale();
1171 if (scale > maximumScale())
1172 return maximumScale();
1176 bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale)
1178 if (!m_mainFrame->view())
1181 if (enforceScaleClamping)
1182 scale = this->clampedScale(scale);
1184 ASSERT(clampedScale);
1185 *clampedScale = scale;
1187 if (currentScale() == scale)
1193 bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel)
1195 if (!isRestoringZoomLevel) {
1196 // Clear any existing block zoom. (If we are restoring a saved zoom level on page load,
1197 // there is guaranteed to be no existing block zoom and we don't want to clear m_shouldReflowBlock.)
1201 // The reflow and block zoom stuff here needs to happen regardless of
1202 // whether we shouldZoomAboutPoint.
1203 #if ENABLE(VIEWPORT_REFLOW)
1204 toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
1205 if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view())
1210 if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1211 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1212 m_currentPinchZoomNode = 0;
1213 m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1217 TransformationMatrix zoom;
1220 #if DEBUG_WEBPAGE_LOAD
1221 if (loadState() < Finished) {
1222 Platform::logAlways(Platform::LogLevelInfo,
1223 "WebPagePrivate::zoomAboutPoint scale %f anchor %s",
1224 scale, Platform::FloatPoint(anchor).toString().c_str());
1228 // Our current scroll position in float.
1229 FloatPoint scrollPosition = this->scrollPosition();
1231 // Anchor offset from scroll position in float.
1232 FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y());
1234 // The horizontal scaling factor and vertical scaling factor should be equal
1235 // to preserve aspect ratio of content.
1236 ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22());
1238 // Need to invert the previous transform to anchor the viewport.
1239 double inverseScale = scale / m_transformationMatrix->m11();
1242 *m_transformationMatrix = zoom;
1244 // Suspend all screen updates to the backingstore.
1245 // FIXME: Do we really need to suspend/resume both backingstore and screen here?
1246 m_backingStore->d->suspendBackingStoreUpdates();
1247 m_backingStore->d->suspendScreenUpdates();
1249 updateViewportSize();
1251 IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))),
1252 max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale)))));
1254 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1255 // This is a hack for email which has reflow always turned on.
1256 m_mainFrame->view()->setNeedsLayout();
1257 requestLayoutIfNeeded();
1258 if (m_currentPinchZoomNode)
1259 newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale);
1260 m_currentPinchZoomNode = 0;
1261 m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1264 setScrollPosition(newScrollPosition);
1266 notifyTransformChanged();
1268 bool isLoading = this->isLoading();
1270 // We need to invalidate all tiles both visible and non-visible if we're loading.
1271 m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */);
1273 bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering;
1275 m_client->scaleChanged();
1277 if (m_pendingOrientation != -1)
1278 m_client->updateInteractionViews();
1280 // FIXME: Do we really need to suspend/resume both backingstore and screen here?
1281 m_backingStore->d->resumeBackingStoreUpdates();
1283 // Clear window to make sure there are no artifacts.
1285 // Resume all screen updates to the backingstore and render+blit visible contents to screen.
1286 m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit);
1288 // Resume all screen updates to the backingstore but do not blit to the screen because we not rendering.
1289 m_backingStore->d->resumeScreenUpdates(BackingStore::None);
1295 IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale)
1297 // Should only be invoked when text reflow is enabled.
1298 ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
1303 IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
1305 if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) {
1306 offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y();
1307 if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0)
1308 offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale;
1311 IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get());
1313 return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))),
1314 max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale))));
1317 void WebPagePrivate::setNeedsLayout()
1319 FrameView* view = m_mainFrame->view();
1321 view->setNeedsLayout();
1324 void WebPagePrivate::requestLayoutIfNeeded() const
1326 FrameView* view = m_mainFrame->view();
1328 view->updateLayoutAndStyleIfNeededRecursive();
1329 ASSERT(!view->needsLayout());
1332 IntPoint WebPagePrivate::scrollPosition() const
1334 return m_backingStoreClient->scrollPosition();
1337 IntPoint WebPagePrivate::maximumScrollPosition() const
1339 return m_backingStoreClient->maximumScrollPosition();
1342 void WebPagePrivate::setScrollPosition(const IntPoint& pos)
1344 m_backingStoreClient->setScrollPosition(pos);
1347 // Setting the scroll position is in transformed coordinates.
1348 void WebPage::setDocumentScrollPosition(const Platform::IntPoint& documentScrollPosition)
1350 WebCore::IntPoint scrollPosition = documentScrollPosition;
1351 if (scrollPosition == d->scrollPosition())
1354 // If the user recently performed an event, this new scroll position
1355 // could possibly be a result of that. Or not, this is just a heuristic.
1356 if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
1357 d->m_userPerformedManualScroll = true;
1359 d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1361 // UI thread can call BackingStorePrivate::setScrollingOrZooming(false) before WebKit thread calls WebPage::setScrollPosition(),
1362 // in which case it will set ScrollableArea::m_constrainsScrollingToContentEdge to true earlier.
1363 // We can cache ScrollableArea::m_constrainsScrollingToContentEdge and always set it to false before we set scroll position in
1364 // WebKit thread to avoid scroll position clamping during scrolling, and restore it to what it was after that.
1365 bool constrainsScrollingToContentEdge = d->m_mainFrame->view()->constrainsScrollingToContentEdge();
1366 d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(false);
1367 d->setScrollPosition(scrollPosition);
1368 d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge);
1370 d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1373 bool WebPagePrivate::shouldSendResizeEvent()
1375 if (!m_mainFrame->document())
1378 // PR#96865 : Provide an option to always send resize events, regardless of the loading
1379 // status. The scenario for this are Sapphire applications which tend to
1380 // maintain an open GET request to the server. This open GET results in
1381 // webkit thinking that content is still arriving when at the application
1382 // level it is considered fully loaded.
1384 // NOTE: Care must be exercised in the use of this option, as it bypasses
1385 // the sanity provided in 'isLoadingInAPISense()' below.
1387 static const bool unrestrictedResizeEvents = Platform::Settings::instance()->unrestrictedResizeEvents();
1388 if (unrestrictedResizeEvents)
1391 // Don't send the resize event if the document is loading. Some pages automatically reload
1392 // when the window is resized; Safari on iPhone often resizes the window while setting up its
1393 // viewport. This obviously can cause problems.
1394 DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
1395 if (documentLoader && documentLoader->isLoadingInAPISense())
1401 void WebPagePrivate::willDeferLoading()
1403 m_deferredTasksTimer.stop();
1404 m_client->willDeferLoading();
1407 void WebPagePrivate::didResumeLoading()
1409 if (!m_deferredTasks.isEmpty())
1410 m_deferredTasksTimer.startOneShot(0);
1411 m_client->didResumeLoading();
1414 void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*)
1416 ASSERT(!m_deferredTasks.isEmpty());
1417 if (m_deferredTasks.isEmpty())
1420 OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release();
1421 m_deferredTasks.remove(0);
1423 if (!m_deferredTasks.isEmpty())
1424 m_deferredTasksTimer.startOneShot(0);
1426 task->perform(this);
1429 void WebPagePrivate::notifyInRegionScrollStopped()
1431 if (m_inRegionScroller->d->isActive())
1432 m_inRegionScroller->d->reset();
1435 void WebPage::notifyInRegionScrollStopped()
1437 d->notifyInRegionScrollStopped();
1440 void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
1442 if (b != m_hasInRegionScrollableAreas)
1443 m_hasInRegionScrollableAreas = b;
1446 IntSize WebPagePrivate::viewportSize() const
1448 return mapFromTransformed(transformedViewportSize());
1451 IntSize WebPagePrivate::actualVisibleSize() const
1453 return mapFromTransformed(transformedActualVisibleSize());
1456 bool WebPagePrivate::hasVirtualViewport() const
1458 return !m_virtualViewportSize.isEmpty();
1461 void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
1463 // This checks to make sure we're not calling updateViewportSize
1464 // during WebPagePrivate::init().
1465 if (!m_backingStore)
1467 ASSERT(m_mainFrame->view());
1468 IntSize visibleSize = actualVisibleSize();
1469 if (setFixedReportedSize)
1470 m_mainFrame->view()->setFixedReportedSize(visibleSize);
1472 IntRect frameRect = IntRect(scrollPosition(), visibleSize);
1473 if (frameRect != m_mainFrame->view()->frameRect()) {
1474 m_mainFrame->view()->setFrameRect(frameRect);
1475 m_mainFrame->view()->adjustViewSize();
1477 #if ENABLE(FULLSCREEN_API)
1478 adjustFullScreenElementDimensionsIfNeeded();
1482 // We're going to need to send a resize event to JavaScript because
1483 // innerWidth and innerHeight depend on fixed reported size.
1484 // This is how we support mobile pages where JavaScript resizes
1485 // the page in order to get around the fixed layout size, e.g.
1486 // google maps when it detects a mobile user agent.
1487 if (sendResizeEvent && shouldSendResizeEvent())
1488 m_mainFrame->eventHandler()->sendResizeEvent();
1490 // When the actual visible size changes, we also
1491 // need to reposition fixed elements.
1492 m_mainFrame->view()->repaintFixedElementsAfterScrolling();
1495 FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
1497 // The visible contents rect in float.
1498 FloatRect visibleContentsRect = this->visibleContentsRect();
1500 // The center of the visible contents rect in float.
1501 return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
1502 visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
1505 IntRect WebPagePrivate::visibleContentsRect() const
1507 return m_backingStoreClient->visibleContentsRect();
1510 IntSize WebPagePrivate::contentsSize() const
1512 if (!m_mainFrame->view())
1515 return m_backingStoreClient->contentsSize();
1518 IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
1520 if (!m_mainFrame->contentRenderer())
1523 return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
1526 void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
1528 if (m_previousContentsSize == contentsSize)
1531 // This should only occur in the middle of layout so we set a flag here and
1532 // handle it at the end of the layout.
1533 m_contentsSizeChanged = true;
1535 #if DEBUG_WEBPAGE_LOAD
1536 Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %s", Platform::IntSize(contentsSize).toString().c_str());
1540 void WebPagePrivate::overflowExceedsContentsSize()
1542 m_overflowExceedsContentsSize = true;
1543 if (absoluteVisibleOverflowSize().width() < DEFAULT_MAX_LAYOUT_WIDTH && !hasVirtualViewport()) {
1544 if (setViewMode(viewMode())) {
1546 requestLayoutIfNeeded();
1551 void WebPagePrivate::layoutFinished()
1553 if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
1556 m_contentsSizeChanged = false; // Toggle to turn off notification again.
1557 m_overflowExceedsContentsSize = false;
1559 if (contentsSize().isEmpty())
1562 // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from
1563 // the middle of a layout, but the recursion is limited by detection code in
1564 // setViewMode() and mitigation code in fixedLayoutSize().
1565 if (didLayoutExceedMaximumIterations()) {
1566 notifyTransformedContentsSizeChanged();
1570 // Temporarily save the m_previousContentsSize here before updating it (in
1571 // notifyTransformedContentsSizeChanged()) so we can compare if our contents
1572 // shrunk afterwards.
1573 IntSize previousContentsSize = m_previousContentsSize;
1575 m_nestedLayoutFinishedCount++;
1577 if (shouldZoomToInitialScaleOnLoad()) {
1578 zoomToInitialScaleOnLoad();
1579 m_shouldZoomToInitialScaleAfterLoadFinished = false;
1580 } else if (loadState() != None)
1581 notifyTransformedContentsSizeChanged();
1583 m_nestedLayoutFinishedCount--;
1585 if (!m_nestedLayoutFinishedCount) {
1586 // When the contents shrinks, there is a risk that we
1587 // will be left at a scroll position that lies outside of the
1588 // contents rect. Since we allow overscrolling and neglect
1589 // to clamp overscroll in order to retain input focus (RIM Bug #414)
1590 // we need to clamp somewhere, and this is where we know the
1591 // contents size has changed.
1593 if (contentsSize() != previousContentsSize) {
1595 IntPoint newScrollPosition = scrollPosition();
1597 if (contentsSize().height() < previousContentsSize.height()) {
1598 IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
1599 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
1602 if (contentsSize().width() < previousContentsSize.width()) {
1603 IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
1604 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
1607 if (newScrollPosition != scrollPosition()) {
1608 setScrollPosition(newScrollPosition);
1609 notifyTransformedScrollChanged();
1612 // If the content size is too small, zoom it to fit the viewport.
1613 if ((loadState() == Finished || loadState() == Committed)
1614 && (transformedContentsSize().width() < transformedActualVisibleSize().width() || transformedContentsSize().height() < transformedActualVisibleSize().height()))
1615 zoomAboutPoint(initialScale(), newScrollPosition);
1621 void WebPagePrivate::zoomToInitialScaleOnLoad()
1623 #if DEBUG_WEBPAGE_LOAD
1624 Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
1627 bool needsLayout = false;
1629 // If the contents width exceeds the viewport width set to desktop mode.
1630 if (m_shouldUseFixedDesktopMode)
1631 needsLayout = setViewMode(FixedDesktop);
1633 needsLayout = setViewMode(Desktop);
1636 // This can cause recursive layout...
1640 if (contentsSize().isEmpty()) {
1641 #if DEBUG_WEBPAGE_LOAD
1642 Platform::logAlways(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
1644 requestLayoutIfNeeded();
1645 notifyTransformedContentsSizeChanged();
1649 bool performedZoom = false;
1650 bool shouldZoom = !m_userPerformedManualZoom;
1652 // If this is a back/forward type navigation, don't zoom to initial scale
1653 // but instead let the HistoryItem's saved viewport reign supreme.
1654 if (m_mainFrame && m_mainFrame->loader() && isBackForwardLoadType(m_mainFrame->loader()->loadType()))
1657 if (shouldZoom && shouldZoomToInitialScaleOnLoad()) {
1658 // Preserve at top and at left position, to avoid scrolling
1659 // to a non top-left position for web page with viewport meta tag
1660 // that specifies an initial-scale that is zoomed in.
1661 FloatPoint anchor = centerOfVisibleContentsRect();
1662 if (!scrollPosition().x())
1664 if (!scrollPosition().y())
1666 performedZoom = zoomAboutPoint(initialScale(), anchor);
1669 // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout...
1670 requestLayoutIfNeeded();
1672 if (!performedZoom) {
1673 // We only notify if we didn't perform zoom, because zoom will notify on
1675 notifyTransformedContentsSizeChanged();
1679 double WebPagePrivate::zoomToFitScale() const
1681 int contentWidth = contentsSize().width();
1683 // For image document, zoom to fit the screen based on the actual image width
1684 // instead of the contents width within a maximum scale .
1685 Document* doc = m_page->mainFrame()->document();
1686 bool isImageDocument = doc && doc->isImageDocument();
1687 if (isImageDocument)
1688 contentWidth = static_cast<ImageDocument*>(doc)->imageSize().width();
1690 double zoomToFitScale = contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
1691 int contentHeight = contentsSize().height();
1692 if (contentHeight * zoomToFitScale < static_cast<double>(m_defaultLayoutSize.height()))
1693 zoomToFitScale = contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
1694 zoomToFitScale = std::max(zoomToFitScale, minimumZoomToFitScale);
1696 if (!isImageDocument)
1697 return zoomToFitScale;
1699 return std::min(zoomToFitScale, maximumImageDocumentZoomToFitScale);
1702 bool WebPagePrivate::respectViewport() const
1704 return m_forceRespectViewportArguments || contentsSize().width() <= m_virtualViewportSize.width() + 1;
1707 double WebPagePrivate::initialScale() const
1710 if (m_initialScale > 0.0 && respectViewport())
1711 return m_initialScale;
1713 if (m_webSettings->isZoomToFitOnLoad())
1714 return zoomToFitScale();
1719 double WebPage::initialScale() const
1721 return d->initialScale();
1724 void WebPage::initializeIconDataBase()
1726 IconDatabaseClientBlackBerry::instance()->initIconDatabase(d->m_webSettings);
1729 bool WebPage::isUserScalable() const
1731 return d->isUserScalable();
1734 void WebPage::setUserScalable(bool userScalable)
1736 d->setUserScalable(userScalable);
1739 double WebPage::currentScale() const
1741 return d->currentScale();
1744 void WebPage::setInitialScale(double initialScale)
1746 d->setInitialScale(initialScale);
1749 double WebPage::minimumScale() const
1751 return d->minimumScale();
1754 void WebPage::setMinimumScale(double minimumScale)
1756 d->setMinimumScale(minimumScale);
1759 void WebPage::setMaximumScale(double maximumScale)
1761 d->setMaximumScale(maximumScale);
1764 double WebPagePrivate::maximumScale() const
1766 double zoomToFitScale = this->zoomToFitScale();
1767 if (m_maximumScale >= m_minimumScale && respectViewport())
1768 return std::max(zoomToFitScale, m_maximumScale);
1770 return hasVirtualViewport() ? std::max<double>(zoomToFitScale, 4.0) : 4.0;
1773 double WebPage::maximumScale() const
1775 return d->maximumScale();
1778 void WebPagePrivate::resetScales()
1780 TransformationMatrix identity;
1781 *m_transformationMatrix = identity;
1782 m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0;
1783 m_minimumScale = -1.0;
1784 m_maximumScale = -1.0;
1785 m_client->scaleChanged();
1787 // We have to let WebCore know about updated framerect now that we've
1788 // reset our scales. See: RIM Bug #401.
1789 updateViewportSize();
1792 IntPoint WebPagePrivate::transformedScrollPosition() const
1794 return m_backingStoreClient->transformedScrollPosition();
1797 IntPoint WebPagePrivate::transformedMaximumScrollPosition() const
1799 return m_backingStoreClient->transformedMaximumScrollPosition();
1802 IntSize WebPagePrivate::transformedActualVisibleSize() const
1804 return IntSize(m_actualVisibleWidth, m_actualVisibleHeight);
1807 Platform::ViewportAccessor* WebPage::webkitThreadViewportAccessor() const
1809 return d->m_webkitThreadViewportAccessor;
1812 Platform::IntSize WebPage::viewportSize() const
1814 return d->transformedActualVisibleSize();
1817 IntSize WebPagePrivate::transformedViewportSize() const
1819 return BlackBerry::Platform::Settings::instance()->applicationSize();
1822 IntRect WebPagePrivate::transformedVisibleContentsRect() const
1824 // Usually this would be mapToTransformed(visibleContentsRect()), but
1825 // that results in rounding errors because we already set the WebCore
1826 // viewport size from our original transformedViewportSize().
1827 // Instead, we only transform the scroll position and take the
1828 // viewport size as it is, which ensures that e.g. blitting operations
1829 // always cover the whole widget/screen.
1830 return IntRect(transformedScrollPosition(), transformedViewportSize());
1833 IntSize WebPagePrivate::transformedContentsSize() const
1835 // mapToTransformed() functions use this method to crop their results,
1836 // so we can't make use of them here. While we want rounding inside page
1837 // boundaries to extend rectangles and round points, we need to crop the
1838 // contents size to the floored values so that we don't try to display
1839 // or report points that are not fully covered by the actual float-point
1840 // contents rectangle.
1841 const IntSize untransformedContentsSize = contentsSize();
1842 const FloatPoint transformedBottomRight = m_transformationMatrix->mapPoint(
1843 FloatPoint(untransformedContentsSize.width(), untransformedContentsSize.height()));
1844 return IntSize(floorf(transformedBottomRight.x()), floorf(transformedBottomRight.y()));
1847 IntPoint WebPagePrivate::mapFromContentsToViewport(const IntPoint& point) const
1849 return m_backingStoreClient->mapFromContentsToViewport(point);
1852 IntPoint WebPagePrivate::mapFromViewportToContents(const IntPoint& point) const
1854 return m_backingStoreClient->mapFromViewportToContents(point);
1857 IntRect WebPagePrivate::mapFromContentsToViewport(const IntRect& rect) const
1859 return m_backingStoreClient->mapFromContentsToViewport(rect);
1862 IntRect WebPagePrivate::mapFromViewportToContents(const IntRect& rect) const
1864 return m_backingStoreClient->mapFromViewportToContents(rect);
1867 IntPoint WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntPoint& point) const
1869 return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(point);
1872 IntPoint WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntPoint& point) const
1874 return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(point);
1877 IntRect WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntRect& rect) const
1879 return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(rect);
1882 IntRect WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntRect& rect) const
1884 return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(rect);
1887 // NOTE: PIXEL ROUNDING!
1888 // Accurate back-and-forth rounding is not possible with information loss
1889 // by integer points and sizes, so we always expand the resulting mapped
1890 // float rectangles to the nearest integer. For points, we always use
1891 // floor-rounding in mapToTransformed() so that we don't have to crop to
1892 // the (floor'd) transformed contents size.
1893 static inline IntPoint roundTransformedPoint(const FloatPoint &point)
1895 // Maps by rounding half towards zero.
1896 return IntPoint(static_cast<int>(floorf(point.x())), static_cast<int>(floorf(point.y())));
1899 static inline IntPoint roundUntransformedPoint(const FloatPoint &point)
1901 // Maps by rounding half away from zero.
1902 return IntPoint(static_cast<int>(ceilf(point.x())), static_cast<int>(ceilf(point.y())));
1905 IntPoint WebPagePrivate::mapToTransformed(const IntPoint& point) const
1907 return roundTransformedPoint(m_transformationMatrix->mapPoint(FloatPoint(point)));
1910 FloatPoint WebPagePrivate::mapToTransformedFloatPoint(const FloatPoint& point) const
1912 return m_transformationMatrix->mapPoint(point);
1915 IntPoint WebPagePrivate::mapFromTransformed(const IntPoint& point) const
1917 return roundUntransformedPoint(m_transformationMatrix->inverse().mapPoint(FloatPoint(point)));
1920 FloatPoint WebPagePrivate::mapFromTransformedFloatPoint(const FloatPoint& point) const
1922 return m_transformationMatrix->inverse().mapPoint(point);
1925 FloatRect WebPagePrivate::mapFromTransformedFloatRect(const FloatRect& rect) const
1927 return m_transformationMatrix->inverse().mapRect(rect);
1930 IntSize WebPagePrivate::mapToTransformed(const IntSize& size) const
1932 return mapToTransformed(IntRect(IntPoint::zero(), size)).size();
1935 IntSize WebPagePrivate::mapFromTransformed(const IntSize& size) const
1937 return mapFromTransformed(IntRect(IntPoint::zero(), size)).size();
1940 IntRect WebPagePrivate::mapToTransformed(const IntRect& rect) const
1942 return enclosingIntRect(m_transformationMatrix->mapRect(FloatRect(rect)));
1945 // Use this in conjunction with mapToTransformed(IntRect), in most cases.
1946 void WebPagePrivate::clipToTransformedContentsRect(IntRect& rect) const
1948 rect.intersect(IntRect(IntPoint::zero(), transformedContentsSize()));
1951 IntRect WebPagePrivate::mapFromTransformed(const IntRect& rect) const
1953 return enclosingIntRect(m_transformationMatrix->inverse().mapRect(FloatRect(rect)));
1956 bool WebPagePrivate::transformedPointEqualsUntransformedPoint(const IntPoint& transformedPoint, const IntPoint& untransformedPoint)
1958 // Scaling down is always more accurate than scaling up.
1959 if (m_transformationMatrix->a() > 1.0)
1960 return transformedPoint == mapToTransformed(untransformedPoint);
1962 return mapFromTransformed(transformedPoint) == untransformedPoint;
1965 void WebPagePrivate::notifyTransformChanged()
1967 notifyTransformedContentsSizeChanged();
1968 notifyTransformedScrollChanged();
1970 m_backingStore->d->transformChanged();
1973 void WebPagePrivate::notifyTransformedContentsSizeChanged()
1975 // We mark here as the last reported content size we sent to the client.
1976 m_previousContentsSize = contentsSize();
1978 const IntSize size = transformedContentsSize();
1979 m_backingStore->d->contentsSizeChanged(size);
1980 m_client->contentsSizeChanged();
1983 void WebPagePrivate::notifyTransformedScrollChanged()
1985 const IntPoint pos = transformedScrollPosition();
1986 m_backingStore->d->scrollChanged(pos);
1987 m_client->scrollChanged();
1989 #if ENABLE(FULLSCREEN_API)
1990 adjustFullScreenElementDimensionsIfNeeded();
1994 bool WebPagePrivate::setViewMode(ViewMode mode)
1996 if (!m_mainFrame->view())
2001 // If we're in the middle of a nested layout with a recursion count above
2002 // some maximum threshold, then our algorithm for finding the minimum content
2003 // width of a given page has become dependent on the visible width.
2005 // We need to find some method to ensure that we don't experience excessive
2006 // and even infinite recursion. This can even happen with valid html. The
2007 // former can happen when we run into inline text with few candidates for line
2008 // break. The latter can happen for instance if the page has a negative margin
2009 // set against the right border. Note: this is valid by spec and can lead to
2010 // a situation where there is no value for which the content width will ensure
2011 // no horizontal scrollbar.
2012 // Example: LayoutTests/css1/box_properties/margin.html
2014 // In order to address such situations when we detect a recursion above some
2015 // maximum threshold we snap our fixed layout size to a defined quantum increment.
2016 // Eventually, either the content width will be satisfied to ensure no horizontal
2017 // scrollbar or this increment will run into the maximum layout size and the
2018 // recursion will necessarily end.
2019 bool snapToIncrement = didLayoutExceedMaximumIterations();
2021 IntSize currentSize = m_mainFrame->view()->fixedLayoutSize();
2022 IntSize newSize = fixedLayoutSize(snapToIncrement);
2023 if (currentSize == newSize)
2026 // FIXME: Temp solution. We'll get back to this.
2027 if (m_nestedLayoutFinishedCount) {
2028 double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width());
2029 double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height());
2030 if (widthChange < 0.05 && heightChange < 0.05)
2034 m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
2035 m_mainFrame->view()->setFixedLayoutSize(newSize);
2036 return true; // Needs re-layout!
2039 int WebPagePrivate::playerID() const
2041 return m_client ? m_client->getInstanceId() : 0;
2044 void WebPagePrivate::setCursor(PlatformCursor handle)
2046 if (m_currentCursor.type() != handle.type()) {
2047 m_currentCursor = handle;
2048 m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot());
2052 Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory()
2054 return m_client->networkStreamFactory();
2057 Platform::Graphics::Window* WebPagePrivate::platformWindow() const
2059 return m_client->window();
2062 void WebPagePrivate::setPreventsScreenDimming(bool keepAwake)
2065 if (!m_preventIdleDimmingCount)
2066 m_client->setPreventsScreenIdleDimming(true);
2067 m_preventIdleDimmingCount++;
2068 } else if (m_preventIdleDimmingCount > 0) {
2069 m_preventIdleDimmingCount--;
2070 if (!m_preventIdleDimmingCount)
2071 m_client->setPreventsScreenIdleDimming(false);
2073 ASSERT_NOT_REACHED(); // SetPreventsScreenIdleDimming(false) called too many times.
2076 void WebPagePrivate::showVirtualKeyboard(bool showKeyboard)
2078 m_client->showVirtualKeyboard(showKeyboard);
2081 void WebPagePrivate::ensureContentVisible(bool centerInView)
2083 m_inputHandler->ensureFocusElementVisible(centerInView);
2086 void WebPagePrivate::zoomToContentRect(const IntRect& rect)
2088 // Don't scale if the user is not supposed to scale.
2089 if (!isUserScalable())
2092 FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y());
2093 IntSize viewSize = viewportSize();
2095 // Calculate the scale required to scale that dimension to fit.
2096 double scaleH = (double)viewSize.width() / (double)rect.width();
2097 double scaleV = (double)viewSize.height() / (double)rect.height();
2099 // Choose the smaller scale factor so that all of the content is visible.
2100 zoomAboutPoint(min(scaleH, scaleV), anchor);
2103 void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister)
2106 m_pluginViews.add(plugin);
2108 m_pluginViews.remove(plugin);
2111 #define FOR_EACH_PLUGINVIEW(pluginViews) \
2112 HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \
2113 HashSet<PluginView*>::const_iterator last = pluginViews.end(); \
2114 for (; it != last; ++it)
2116 void WebPagePrivate::notifyPageOnLoad()
2118 FOR_EACH_PLUGINVIEW(m_pluginViews)
2119 (*it)->handleOnLoadEvent();
2122 bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2124 return m_client->shouldPluginEnterFullScreen();
2127 void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2129 m_fullScreenPluginView = plugin;
2130 m_client->didPluginEnterFullScreen();
2132 if (!m_client->window())
2135 Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix);
2136 m_client->window()->setSensitivityFullscreenOverride(true);
2139 void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2141 m_fullScreenPluginView = 0;
2142 m_client->didPluginExitFullScreen();
2144 if (!m_client->window())
2147 Platform::Graphics::Window::setTransparencyDiscardFilter(0);
2148 m_client->window()->setSensitivityFullscreenOverride(false);
2151 void WebPagePrivate::onPluginStartBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
2153 m_client->onPluginStartBackgroundPlay();
2156 void WebPagePrivate::onPluginStopBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
2158 m_client->onPluginStopBackgroundPlay();
2161 bool WebPagePrivate::lockOrientation(bool landscape)
2163 return m_client->lockOrientation(landscape);
2166 void WebPagePrivate::unlockOrientation()
2168 return m_client->unlockOrientation();
2171 int WebPagePrivate::orientation() const
2173 #if ENABLE(ORIENTATION_EVENTS)
2174 return m_mainFrame->orientation();
2176 #error ORIENTATION_EVENTS must be defined.
2177 // Or a copy of the orientation value will have to be stored in these objects.
2181 double WebPagePrivate::currentZoomFactor() const
2183 return currentScale();
2186 int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype)
2188 return m_client->showAlertDialog(atype);
2191 bool WebPagePrivate::isActive() const
2193 return m_client->isActive();
2196 void WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSpace& protectionSpace, const Credential& inputCredential)
2198 AuthenticationChallengeManager* authmgr = AuthenticationChallengeManager::instance();
2199 BlackBerry::Platform::String username;
2200 BlackBerry::Platform::String password;
2202 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
2203 if (m_dumpRenderTree) {
2204 Credential credential(inputCredential, inputCredential.persistence());
2205 if (m_dumpRenderTree->didReceiveAuthenticationChallenge(credential))
2206 authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeSuccess, credential);
2208 authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeCancelled, inputCredential);
2213 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2214 if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled())
2215 credentialManager().autofillAuthenticationChallenge(protectionSpace, username, password);
2218 bool isConfirmed = m_client->authenticationChallenge(protectionSpace.realm().characters(), protectionSpace.realm().length(), username, password);
2220 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2221 Credential credential(username, password, CredentialPersistencePermanent);
2222 if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled() && isConfirmed)
2223 credentialManager().saveCredentialIfConfirmed(this, CredentialTransformData(url, protectionSpace, credential));
2225 Credential credential(username, password, CredentialPersistenceNone);
2229 authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeSuccess, credential);
2231 authmgr->notifyChallengeResult(url, protectionSpace, AuthenticationChallengeCancelled, inputCredential);
2234 PageClientBlackBerry::SaveCredentialType WebPagePrivate::notifyShouldSaveCredential(bool isNew)
2236 return static_cast<PageClientBlackBerry::SaveCredentialType>(m_client->notifyShouldSaveCredential(isNew));
2239 void WebPagePrivate::syncProxyCredential(const WebCore::Credential& credential)
2241 m_client->syncProxyCredential(credential.user(), credential.password());
2244 void WebPagePrivate::notifyPopupAutofillDialog(const Vector<String>& candidates)
2246 vector<BlackBerry::Platform::String> textItems;
2247 for (size_t i = 0; i < candidates.size(); i++)
2248 textItems.push_back(candidates[i]);
2249 m_client->notifyPopupAutofillDialog(textItems);
2252 void WebPagePrivate::notifyDismissAutofillDialog()
2254 m_client->notifyDismissAutofillDialog();
2257 bool WebPagePrivate::useFixedLayout() const
2262 Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy)
2264 Platform::WebContext context;
2266 RefPtr<Node> node = contextNode(strategy);
2267 m_currentContextNode = node;
2268 if (!m_currentContextNode)
2271 // Send an onContextMenu event to the current context ndoe and get the result. Since we've already figured out
2272 // which node we want, we can send it directly to the node and not do a hit test. The onContextMenu event doesn't require
2273 // mouse positions so we just set the position at (0,0)
2274 PlatformMouseEvent mouseEvent(IntPoint(), IntPoint(), PlatformEvent::MouseMoved, 0, NoButton, false, false, false, TouchScreen);
2275 if (m_currentContextNode->dispatchMouseEvent(mouseEvent, eventNames().contextmenuEvent, 0)) {
2276 context.setFlag(Platform::WebContext::IsOnContextMenuPrevented);
2280 requestLayoutIfNeeded();
2282 bool nodeAllowSelectionOverride = false;
2283 if (Node* linkNode = node->enclosingLinkEventParentOrSelf()) {
2285 if (linkNode->isLink() && linkNode->hasAttributes()) {
2286 if (Attribute* attribute = static_cast<Element*>(linkNode)->getAttributeItem(HTMLNames::hrefAttr))
2287 href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
2290 String pattern = findPatternStringForUrl(href);
2291 if (!pattern.isEmpty())
2292 context.setPattern(pattern);
2294 if (!href.string().isEmpty()) {
2295 context.setUrl(href.string());
2297 // Links are non-selectable by default, but selection should be allowed
2298 // providing the page is selectable, use the parent to determine it.
2299 if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
2300 nodeAllowSelectionOverride = true;
2304 if (node->isHTMLElement()) {
2305 HTMLImageElement* imageElement = 0;
2306 HTMLMediaElement* mediaElement = 0;
2308 if (node->hasTagName(HTMLNames::imgTag))
2309 imageElement = static_cast<HTMLImageElement*>(node.get());
2310 else if (node->hasTagName(HTMLNames::areaTag))
2311 imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement();
2313 if (static_cast<HTMLElement*>(node.get())->isMediaElement())
2314 mediaElement = static_cast<HTMLMediaElement*>(node.get());
2316 if (imageElement && imageElement->renderer()) {
2317 context.setFlag(Platform::WebContext::IsImage);
2318 // FIXME: At the mean time, we only show "Save Image" when the image data is available.
2319 if (CachedResource* cachedResource = imageElement->cachedImage()) {
2320 if (cachedResource->isLoaded() && cachedResource->data()) {
2321 String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
2322 context.setSrc(node->document()->completeURL(url).string());
2325 String alt = imageElement->altText();
2327 context.setAlt(alt);
2331 if (mediaElement->hasAudio())
2332 context.setFlag(Platform::WebContext::IsAudio);
2333 if (mediaElement->hasVideo())
2334 context.setFlag(Platform::WebContext::IsVideo);
2336 String src = stripLeadingAndTrailingHTMLSpaces(mediaElement->getAttribute(HTMLNames::srcAttr).string());
2337 context.setSrc(node->document()->completeURL(src).string());
2341 if (node->isTextNode()) {
2342 Text* curText = toText(node.get());
2343 if (!curText->wholeText().isEmpty())
2344 context.setText(curText->wholeText());
2347 bool canStartSelection = node->canStartSelection();
2349 if (node->isElementNode()) {
2350 Element* element = static_cast<Element*>(node->deprecatedShadowAncestorNode());
2352 if (DOMSupport::isTextBasedContentEditableElement(element)) {
2353 if (!canStartSelection) {
2354 // Input fields host node is by spec non-editable unless the field itself has content editable enabled.
2355 // Enable selection if the shadow tree for the input field is selectable.
2356 Node* nodeUnderFinger = m_touchEventHandler->lastFatFingersResult().isValid() ? m_touchEventHandler->lastFatFingersResult().node(FatFingersResult::ShadowContentAllowed) : 0;
2357 if (nodeUnderFinger)
2358 canStartSelection = nodeUnderFinger->canStartSelection();
2360 context.setFlag(Platform::WebContext::IsInput);
2361 if (element->hasTagName(HTMLNames::inputTag))
2362 context.setFlag(Platform::WebContext::IsSingleLine);
2363 if (DOMSupport::isPasswordElement(element))
2364 context.setFlag(Platform::WebContext::IsPassword);
2366 String elementText(DOMSupport::inputElementText(element));
2367 if (!elementText.stripWhiteSpace().isEmpty())
2368 context.setText(elementText);
2369 else if (!node->focused() && m_touchEventHandler->lastFatFingersResult().isValid() && strategy == RectBased) {
2370 // If an input field is empty and not focused send a mouse click so that it gets a cursor and we can paste into it.
2371 m_touchEventHandler->sendClickAtFatFingersPoint();
2376 if (!nodeAllowSelectionOverride && !canStartSelection)
2377 context.resetFlag(Platform::WebContext::IsSelectable);
2379 if (node->isFocusable())
2380 context.setFlag(Platform::WebContext::IsFocusable);
2382 // Walk up the node tree looking for our custom webworks context attribute.
2384 if (node->isElementNode()) {
2385 Element* element = static_cast<Element*>(node->deprecatedShadowAncestorNode());
2386 String webWorksContext(DOMSupport::webWorksContext(element));
2387 if (!webWorksContext.stripWhiteSpace().isEmpty()) {
2388 context.setFlag(Platform::WebContext::IsWebWorksContext);
2389 context.setWebWorksContext(webWorksContext);
2393 node = node->parentNode();
2399 Platform::WebContext WebPage::webContext(TargetDetectionStrategy strategy) const
2401 return d->webContext(strategy);
2404 void WebPagePrivate::updateCursor()
2407 if (m_lastMouseEvent.button() == LeftButton)
2408 buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
2409 else if (m_lastMouseEvent.button() == MiddleButton)
2410 buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
2411 else if (m_lastMouseEvent.button() == RightButton)
2412 buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
2414 unsigned modifiers = m_lastMouseEvent.shiftKey() ? 0 : KEYMOD_SHIFT |
2415 m_lastMouseEvent.ctrlKey() ? 0 : KEYMOD_CTRL |
2416 m_lastMouseEvent.altKey() ? 0 : KEYMOD_ALT;
2418 BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask, mapToTransformed(m_lastMouseEvent.position()), mapToTransformed(m_lastMouseEvent.globalPosition()), 0, modifiers, 0);
2419 m_webPage->mouseEvent(event);
2422 IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
2424 if (hasVirtualViewport())
2425 return m_virtualViewportSize;
2427 const int defaultLayoutWidth = m_defaultLayoutSize.width();
2428 const int defaultLayoutHeight = m_defaultLayoutSize.height();
2430 int minWidth = defaultLayoutWidth;
2431 int maxWidth = DEFAULT_MAX_LAYOUT_WIDTH;
2432 int maxHeight = DEFAULT_MAX_LAYOUT_HEIGHT;
2434 // If the load state is none then we haven't actually got anything yet, but we need to layout
2435 // the entire page so that the user sees the entire page (unrendered) instead of just part of it.
2436 if (m_loadState == None)
2437 return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2439 if (m_viewMode == FixedDesktop) {
2440 int width = maxWidth;
2441 // if the defaultLayoutHeight is at minimum, it probably was set as 0
2442 // and clamped, meaning it's effectively not set. (Even if it happened
2443 // to be set exactly to the minimum, it's too small to be useful.) So
2446 if (defaultLayoutHeight <= minimumLayoutSize.height())
2449 height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2450 return IntSize(width, height);
2453 if (m_viewMode == Desktop) {
2454 // If we detect an overflow larger than the contents size then use that instead since
2455 // it'll still be clamped by the maxWidth below...
2456 int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
2457 if (m_pendingOrientation != -1 && !m_nestedLayoutFinishedCount && !m_overflowExceedsContentsSize)
2460 if (snapToIncrement) {
2461 // Snap to increments of defaultLayoutWidth / 2.0.
2462 float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
2463 factor = ceilf(factor);
2464 width = (defaultLayoutWidth / 2.0) * factor;
2467 if (width < minWidth)
2469 if (width > maxWidth)
2471 int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2472 return IntSize(width, height);
2475 ASSERT_NOT_REACHED();
2476 return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2479 BackingStoreClient* WebPagePrivate::backingStoreClient() const
2481 return m_backingStoreClient;
2484 void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
2486 ASSERT(documentGoingAway);
2487 if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
2488 m_currentContextNode = 0;
2490 if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
2491 m_currentPinchZoomNode = 0;
2493 if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
2494 m_currentBlockZoomAdjustedNode = 0;
2496 if (m_inRegionScroller->d->isActive())
2497 m_inRegionScroller->d->clearDocumentData(documentGoingAway);
2499 if (documentGoingAway->frame())
2500 m_inputHandler->frameUnloaded(documentGoingAway->frame());
2502 Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
2503 if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
2504 m_touchEventHandler->resetLastFatFingersResult();
2506 // NOTE: m_fullscreenNode, m_fullScreenPluginView and m_pluginViews
2507 // are cleared in other methods already.
2510 typedef bool (*PredicateFunction)(RenderLayer*);
2511 static bool isPositionedContainer(RenderLayer* layer)
2513 RenderObject* o = layer->renderer();
2514 return o->isRenderView() || o->isOutOfFlowPositioned() || o->isRelPositioned() || layer->hasTransform();
2517 static bool isFixedPositionedContainer(RenderLayer* layer)
2519 RenderObject* o = layer->renderer();
2520 return o->isRenderView() || (o->isOutOfFlowPositioned() && o->style()->position() == FixedPosition);
2523 static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
2525 RenderLayer* curr = layer;
2526 while (curr && !predicate(curr))
2527 curr = curr->parent();
2532 RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
2534 return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
2537 RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
2539 return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
2542 static inline Frame* frameForNode(Node* node)
2544 Node* origNode = node;
2545 for (; node; node = node->parentNode()) {
2546 if (RenderObject* renderer = node->renderer()) {
2547 if (renderer->isRenderView()) {
2548 if (FrameView* view = toRenderView(renderer)->frameView()) {
2549 if (Frame* frame = view->frame())
2553 if (renderer->isWidget()) {
2554 Widget* widget = toRenderWidget(renderer)->widget();
2555 if (widget && widget->isFrameView()) {
2556 if (Frame* frame = static_cast<FrameView*>(widget)->frame())
2563 for (node = origNode; node; node = node->parentNode()) {
2564 if (Document* doc = node->document()) {
2565 if (Frame* frame = doc->frame())
2573 static IntRect getNodeWindowRect(Node* node)
2575 if (Frame* frame = frameForNode(node)) {
2576 if (FrameView* view = frame->view())
2577 return view->contentsToWindow(node->getRect());
2579 ASSERT_NOT_REACHED();
2583 IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
2585 ASSERT(m_mainFrame);
2587 // Don't call this function asking to not clip the main frame providing only
2588 // the main frame. All that can be returned is the content rect which
2589 // isn't what this function is for.
2590 if (noClipOfMainFrame && view == m_mainFrame->view()) {
2591 ASSERT_NOT_REACHED();
2592 return IntRect(IntPoint::zero(), view->contentsSize());
2595 IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect(false)));
2596 if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
2597 // Intersect with parent visible rect.
2598 visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
2600 return visibleWindowRect;
2603 void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
2605 ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
2606 ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
2607 ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
2609 // First we clear the focus, since we want to focus either initial or the last
2610 // focusable element in the webpage (according to the TABINDEX), or simply clear
2614 switch (direction) {
2615 case FocusDirectionForward:
2616 case FocusDirectionBackward:
2617 m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
2619 case FocusDirectionNone:
2622 ASSERT_NOT_REACHED();
2626 void WebPage::assignFocus(Platform::FocusDirection direction)
2628 if (d->m_page->defersLoading())
2630 d->assignFocus(direction);
2633 Platform::IntRect WebPagePrivate::focusNodeRect()
2635 Frame* frame = focusedOrMainFrame();
2637 return Platform::IntRect();
2639 Document* doc = frame->document();
2640 FrameView* view = frame->view();
2641 if (!doc || !view || view->needsLayout())
2642 return Platform::IntRect();
2644 IntRect focusRect = rectForNode(doc->focusedNode());
2645 focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
2646 focusRect = mapToTransformed(focusRect);
2647 clipToTransformedContentsRect(focusRect);
2651 PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
2653 EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2654 const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
2655 bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
2657 // Check if we're using LinkToLink and the user is not touching the screen.
2658 if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
2660 node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
2662 IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
2663 if (!visibleRect.intersects(getNodeWindowRect(node.get())))
2666 return node.release();
2669 // Check for text input.
2670 if (isTouching && lastFatFingersResult.isTextInput())
2671 return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
2673 if (strategy == RectBased) {
2674 FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
2675 return result.node(FatFingersResult::ShadowContentNotAllowed);
2677 if (strategy == FocusBased)
2678 return m_inputHandler->currentFocusElement();
2680 IntPoint contentPos;
2682 contentPos = lastFatFingersResult.adjustedPosition();
2684 contentPos = mapFromViewportToContents(m_lastMouseEvent.position());
2686 HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos, false /*allowShadowContent*/);
2687 return result.innerNode();
2690 static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
2692 // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709).
2693 double dx = static_cast<double>(p1.x() - p2.x());
2694 double dy = static_cast<double>(p1.y() - p2.y());
2695 return sqrt((dx * dx) + (dy * dy));
2698 Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& documentPoint)
2700 IntRect clickRect(documentPoint.x() - blockClickRadius, documentPoint.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
2701 Node* originalNode = nodeForZoomUnderPoint(documentPoint);
2704 Node* node = bestChildNodeForClickRect(originalNode, clickRect);
2705 return node ? adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(node) : adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(originalNode);
2708 Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
2713 int bestDistance = std::numeric_limits<int>::max();
2715 Node* node = parentNode->firstChild();
2717 for (; node; node = node->nextSibling()) {
2718 IntRect rect = rectForNode(node);
2719 if (!clickRect.intersects(rect))
2722 int distance = distanceBetweenPoints(rect.center(), clickRect.center());
2723 Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
2724 if (bestChildNode) {
2725 IntRect bestChildRect = rectForNode(bestChildNode);
2726 int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
2727 if (bestChildDistance < distance && bestChildDistance < bestDistance) {
2728 bestNode = bestChildNode;
2729 bestDistance = bestChildDistance;
2731 if (distance < bestDistance) {
2733 bestDistance = distance;
2737 if (distance < bestDistance) {
2739 bestDistance = distance;
2747 double WebPagePrivate::maxBlockZoomScale() const
2749 return std::min(maximumBlockZoomScale, maximumScale());
2752 Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& documentPoint)
2757 HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(documentPoint, false);
2759 Node* node = result.innerNonSharedNode();
2764 RenderObject* renderer = node->renderer();
2766 node = node->parentNode();
2767 renderer = node->renderer();
2773 Node* WebPagePrivate::adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(Node* node)
2775 Node* initialNode = node;
2776 RenderObject* renderer = node->renderer();
2777 bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2778 IntSize actualVisibleSize = this->actualVisibleSize();
2780 while (!renderer || !acceptableNodeSize) {
2781 node = node->parentNode();
2782 IntRect nodeRect = rectForNode(node);
2784 // Don't choose a node if the width of the node size is very close to the width of the actual visible size,
2785 // as block zoom can do nothing on such kind of node.
2786 if (!node || static_cast<double>(actualVisibleSize.width() - nodeRect.width()) / actualVisibleSize.width() < minimumExpandingRatio)
2789 renderer = node->renderer();
2790 acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2796 bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
2801 return (n2 == n1) || n2->isDescendantOf(n1);
2804 double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
2807 return std::numeric_limits<double>::max();
2809 ASSERT(rect.width() + margin);
2811 double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
2816 IntRect WebPagePrivate::rectForNode(Node* node)
2821 RenderObject* renderer = node->renderer();
2826 // Return rect in un-transformed content coordinates.
2829 // FIXME: Ensure this works with iframes.
2830 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
2831 RenderBlock* renderBlock = renderer->containingBlock();
2834 while (!renderBlock->isRoot()) {
2835 xOffset += renderBlock->x();
2836 yOffset += renderBlock->y();
2837 renderBlock = renderBlock->containingBlock();
2839 const RenderText* renderText = toRenderText(renderer);
2840 IntRect linesBox = renderText->linesBoundingBox();
2841 blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height());
2843 blockRect = renderer->absoluteClippedOverflowRect();
2845 if (renderer->isText()) {
2846 RenderBlock* rb = renderer->containingBlock();
2848 // Inefficient? Way to find width when floats intersect a block.
2850 int lineCount = rb->lineCount();
2851 for (int i = 0; i < lineCount; i++)
2852 blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false));
2854 blockRect.setWidth(blockWidth);
2855 blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
2858 // Strip off padding.
2859 if (renderer->style()->hasPadding()) {
2860 blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
2861 blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
2862 blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
2863 blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
2869 IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
2873 // FIXME: This function can be called when page is being destroyed and JS triggers selection change.
2874 // We could break the call chain at upper levels, but I think it is better to check the frame pointer
2875 // here because the pointer is explicitly cleared in WebPage::destroy().
2879 // Convert 0,0 in the frame's coordinate system to window coordinates to
2880 // get the frame's global position, and return this position in the main
2881 // frame's coordinates. (So the main frame's coordinates will be 0,0.)
2882 return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
2885 IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
2890 // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames.
2891 // FIXME: can we just use frameOffset instead of this big routine?
2892 const Node* tnode = node;
2893 IntRect adjustedRect = rect;
2895 Frame* frame = tnode->document()->frame();
2899 Node* ownerNode = static_cast<Node*>(frame->ownerElement());
2901 if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
2904 iFrameRect = rectForNode(ownerNode);
2905 adjustedRect.move(iFrameRect.x(), iFrameRect.y());
2906 adjustedRect.intersect(iFrameRect);
2907 ownerNode = ownerNode->parentNode();
2908 } while (iFrameRect.isEmpty() && ownerNode);
2911 } while (tnode = tnode->parentNode());
2913 return adjustedRect;
2916 IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
2918 if (!node || contentsSize().isEmpty())
2922 m_currentBlockZoomAdjustedNode = tnode;
2924 IntRect blockRect = rectForNode(tnode);
2925 IntRect originalRect = blockRect;
2927 int originalArea = originalRect.width() * originalRect.height();
2928 int pageArea = contentsSize().width() * contentsSize().height();
2929 double blockToPageRatio = static_cast<double>(pageArea - originalArea) / pageArea;
2930 double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
2932 if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
2933 while (tnode = tnode->parentNode()) {
2935 IntRect tRect = rectForNode(tnode);
2936 int tempBlockArea = tRect.width() * tRect.height();
2937 // Don't expand the block if it will be too large relative to the content.
2938 if (static_cast<double>(pageArea - tempBlockArea) / pageArea < minimumExpandingRatio)
2940 if (tRect.isEmpty())
2941 continue; // No renderer.
2942 if (tempBlockArea < 1.1 * originalArea)
2943 continue; // The size of this parent is very close to the child, no need to go to this parent.
2944 // Don't expand the block if the parent node size is already almost the size of actual visible size.
2945 IntSize actualSize = actualVisibleSize();
2946 if (static_cast<double>(actualSize.width() - tRect.width()) / actualSize.width() < minimumExpandingRatio)
2948 if (tempBlockArea < blockExpansionRatio * originalArea) {
2950 m_currentBlockZoomAdjustedNode = tnode;
2956 blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
2957 blockRect = mapToTransformed(blockRect);
2958 clipToTransformedContentsRect(blockRect);
2963 // This function should not be called directly.
2964 // It is called after the animation ends (see above).
2965 void WebPagePrivate::zoomBlock()
2970 IntPoint anchor(roundUntransformedPoint(m_finalBlockPoint));
2971 bool willUseTextReflow = false;
2973 #if ENABLE(VIEWPORT_REFLOW)
2974 willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
2975 toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
2979 TransformationMatrix zoom;
2980 zoom.scale(m_blockZoomFinalScale);
2981 *m_transformationMatrix = zoom;
2982 // FIXME: Do we really need to suspend/resume both backingstore and screen here?
2983 m_backingStore->d->suspendBackingStoreUpdates();
2984 m_backingStore->d->suspendScreenUpdates();
2985 updateViewportSize();
2987 FrameView* mainFrameView = m_mainFrame->view();
2988 bool constrainsScrollingToContentEdge = true;
2989 if (mainFrameView) {
2990 constrainsScrollingToContentEdge = mainFrameView->constrainsScrollingToContentEdge();
2991 mainFrameView->setConstrainsScrollingToContentEdge(m_shouldConstrainScrollingToContentEdge);
2994 #if ENABLE(VIEWPORT_REFLOW)
2995 requestLayoutIfNeeded();
2996 if (willUseTextReflow && m_shouldReflowBlock) {
2997 IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
2998 reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
2999 reflowedRect.move(roundTransformedPoint(m_finalBlockPointReflowOffset).x(), roundTransformedPoint(m_finalBlockPointReflowOffset).y());
3000 RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
3001 IntPoint topLeftPoint(reflowedRect.location());
3002 if (renderer && renderer->isText()) {
3003 ETextAlign textAlign = renderer->style()->textAlign();
3004 IntPoint textAnchor;
3005 switch (textAlign) {
3008 textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
3012 textAnchor = topLeftPoint;
3016 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
3021 if (renderer->style()->isLeftToRightDirection())
3022 textAnchor = topLeftPoint;
3024 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
3027 setScrollPosition(textAnchor);
3029 renderer->style()->isLeftToRightDirection()
3030 ? setScrollPosition(topLeftPoint)
3031 : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
3033 } else if (willUseTextReflow) {
3034 IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
3035 finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
3036 setScrollPosition(IntPoint(0, finalRect.y() + m_finalBlockPointReflowOffset.y()));
3040 if (!willUseTextReflow) {
3041 setScrollPosition(anchor);
3042 if (!m_shouldReflowBlock)
3046 notifyTransformChanged();
3047 m_client->scaleChanged();
3050 mainFrameView->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge);
3052 // FIXME: Do we really need to suspend/resume both backingstore and screen here?
3053 m_backingStore->d->resumeBackingStoreUpdates();
3054 m_backingStore->d->resumeScreenUpdates(BackingStore::RenderAndBlit);
3057 void WebPage::blockZoomAnimationFinished()
3062 void WebPage::resetBlockZoom()
3064 d->resetBlockZoom();
3067 void WebPagePrivate::resetBlockZoom()
3069 m_currentBlockZoomNode = 0;
3070 m_currentBlockZoomAdjustedNode = 0;
3071 m_shouldReflowBlock = false;
3072 m_shouldConstrainScrollingToContentEdge = true;
3075 void WebPage::destroyWebPageCompositor()
3077 #if USE(ACCELERATED_COMPOSITING)
3078 // Destroy the layer renderer in a sync command before we destroy the backing store,
3079 // to flush any pending compositing messages on the compositing thread.
3080 // The backing store is indirectly deleted by the 'detachFromParent' call below.
3081 d->syncDestroyCompositorOnCompositingThread();
3085 void WebPage::destroy()
3087 // TODO: need to verify if this call needs to be made before calling
3088 // Close the Inspector to resume the JS engine if it's paused.
3089 disableWebInspector();
3091 // WebPage::destroyWebPageCompositor()
3092 // FIXME: Do we really need to suspend/resume both backingstore and screen here?
3093 d->m_backingStore->d->suspendBackingStoreUpdates();
3094 d->m_backingStore->d->suspendScreenUpdates();
3096 // Close the backforward list and release the cached pages.
3097 d->m_page->backForward()->close();
3098 pageCache()->releaseAutoreleasedPagesNow();
3100 FrameLoader* loader = d->m_mainFrame->loader();
3102 // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion.
3105 loader->detachFromParent();
3107 deleteGuardedObject(this);
3110 WebPageClient* WebPage::client() const
3115 int WebPage::backForwardListLength() const
3117 return d->m_page->getHistoryLength();
3120 bool WebPage::canGoBackOrForward(int delta) const
3122 return d->m_page->canGoBackOrForward(delta);
3125 bool WebPage::goBackOrForward(int delta)
3127 if (d->m_page->canGoBackOrForward(delta)) {
3128 d->m_backingStore->d->suspendScreenUpdates();
3129 d->m_page->goBackOrForward(delta);
3130 d->m_backingStore->d->resumeScreenUpdates(BackingStore::None);
3136 void WebPage::goToBackForwardEntry(BackForwardId id)
3138 HistoryItem* item = historyItemFromBackForwardId(id);
3140 d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
3143 void WebPage::reload()
3145 d->m_mainFrame->loader()->reload(/* bypassCache */ true);
3148 void WebPage::reloadFromCache()
3150 d->m_mainFrame->loader()->reload(/* bypassCache */ false);
3153 WebSettings* WebPage::settings() const
3155 return d->m_webSettings;
3158 WebCookieJar* WebPage::cookieJar() const
3160 if (!d->m_cookieJar)
3161 d->m_cookieJar = new WebCookieJar();
3163 return d->m_cookieJar;
3166 bool WebPage::isLoading() const
3168 return d->isLoading();
3171 bool WebPage::isVisible() const
3173 return d->m_visible;
3176 #if ENABLE(PAGE_VISIBILITY_API)
3177 class DeferredTaskSetPageVisibilityState: public DeferredTask<&WebPagePrivate::m_wouldSetPageVisibilityState> {
3179 explicit DeferredTaskSetPageVisibilityState(WebPagePrivate* webPagePrivate)
3180 : DeferredTaskType(webPagePrivate)
3184 virtual void performInternal(WebPagePrivate* webPagePrivate)
3186 webPagePrivate->setPageVisibilityState();
3190 void WebPagePrivate::setPageVisibilityState()
3192 if (m_page->defersLoading())
3193 m_deferredTasks.append(adoptPtr(new DeferredTaskSetPageVisibilityState(this)));
3195 DeferredTaskSetPageVisibilityState::finishOrCancel(this);
3197 static bool s_initialVisibilityState = true;
3199 m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
3200 s_initialVisibilityState = false;
3205 void WebPagePrivate::setVisible(bool visible)
3207 if (visible != m_visible) {
3210 m_mainFrame->animation()->resumeAnimations();
3211 if (m_page->scriptedAnimationsSuspended())
3212 m_page->resumeScriptedAnimations();
3215 m_mainFrame->animation()->suspendAnimations();
3216 if (!m_page->scriptedAnimationsSuspended())
3217 m_page->suspendScriptedAnimations();
3219 if (m_webPage->hasOpenedPopup())
3220 m_page->chrome()->client()->closePagePopup(0);
3223 m_visible = visible;
3224 m_backingStore->d->updateSuspendScreenUpdateState();
3227 #if ENABLE(PAGE_VISIBILITY_API)
3228 setPageVisibilityState();
3232 void WebPage::setVisible(bool visible)
3234 if (d->m_visible == visible)
3237 d->setVisible(visible);
3238 AuthenticationChallengeManager::instance()->pageVisibilityChanged(d, visible);
3241 d->suspendBackingStore();
3243 // Remove this WebPage from the visible pages list.
3244 size_t foundIndex = visibleWebPages()->find(this);
3245 if (foundIndex != WTF::notFound)
3246 visibleWebPages()->remove(foundIndex);
3248 // Return the backing store to the last visible WebPage.
3249 if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
3250 visibleWebPages()->last()->d->resumeBackingStore();
3252 #if USE(ACCELERATED_COMPOSITING)
3253 // Root layer commit is not necessary for invisible tabs.
3254 // And release layer resources can reduce memory consumption.
3255 d->suspendRootLayerCommit();
3261 #if USE(ACCELERATED_COMPOSITING)
3262 d->resumeRootLayerCommit();
3265 // We want to become visible but not get backing store ownership.
3266 if (d->m_backingStore->d->isOpenGLCompositing() && !d->m_webSettings->isBackingStoreEnabled()) {
3267 d->setCompositorDrawsRootLayer(true);
3268 #if USE(ACCELERATED_COMPOSITING)
3269 d->setNeedsOneShotDrawingSynchronization();
3271 d->setShouldResetTilesWhenShown(true);
3275 // Push this WebPage to the top of the visible pages list.
3276 if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
3277 size_t foundIndex = visibleWebPages()->find(this);
3278 if (foundIndex != WTF::notFound)
3279 visibleWebPages()->remove(foundIndex);
3281 visibleWebPages()->append(this);
3283 if (BackingStorePrivate::currentBackingStoreOwner()
3284 && BackingStorePrivate::currentBackingStoreOwner() != this)
3285 BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
3287 // resumeBackingStore will set the current owner to this webpage.
3288 // If we set the owner prematurely, then the tiles will not be reset.
3289 d->resumeBackingStore();
3292 void WebPagePrivate::selectionChanged(Frame* frame)
3294 m_inputHandler->selectionChanged();
3296 // FIXME: This is a hack!
3297 // To ensure the selection being changed has its frame 'focused', lets
3298 // set it as focused ourselves (PR #104724).
3299 m_page->focusController()->setFocusedFrame(frame);
3302 void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
3304 // Track a dispatched message, we don't want to flood the webkit thread.
3305 // There can be as many as one more message enqued as needed but never less.
3307 m_updateDelegatedOverlaysDispatched = false;
3308 else if (m_updateDelegatedOverlaysDispatched) {
3309 // Early return if there is message already pending on the webkit thread.
3313 if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
3314 // Must be called on the WebKit thread.
3315 if (m_selectionHandler->isSelectionActive())
3316 m_selectionHandler->selectionPositionChanged();
3317 if (m_inspectorOverlay)
3318 m_inspectorOverlay->update();
3320 } else if (m_selectionHandler->isSelectionActive()) {
3321 // Don't bother dispatching to webkit thread if selection and tap highlight are not active.
3322 m_updateDelegatedOverlaysDispatched = true;
3323 Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/));
3327 void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle style)
3331 bool WebPage::setBatchEditingActive(bool active)
3333 return d->m_inputHandler->setBatchEditingActive(active);
3336 bool WebPage::setInputSelection(unsigned start, unsigned end)
3338 if (d->m_page->defersLoading())
3340 return d->m_inputHandler->setSelection(start, end);
3343 int WebPage::inputCaretPosition() const
3345 return d->m_inputHandler->caretPosition();
3348 class DeferredTaskPopupListSelectMultiple: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectMultiple> {
3350 DeferredTaskPopupListSelectMultiple(WebPagePrivate* webPagePrivate, int size, const bool* selecteds)
3351 : DeferredTaskType(webPagePrivate)
3353 webPagePrivate->m_cachedPopupListSelecteds.append(selecteds, size);
3356 virtual void performInternal(WebPagePrivate* webPagePrivate)
3358 webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelecteds.size(), webPagePrivate->m_cachedPopupListSelecteds.data());
3362 class DeferredTaskPopupListSelectSingle: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectSingle> {
3364 explicit DeferredTaskPopupListSelectSingle(WebPagePrivate* webPagePrivate, int index)
3365 : DeferredTaskType(webPagePrivate)
3367 webPagePrivate->m_cachedPopupListSelectedIndex = index;
3370 virtual void performInternal(WebPagePrivate* webPagePrivate)
3372 webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelectedIndex);
3376 void WebPage::popupListClosed(int size, const bool* selecteds)
3378 DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3379 if (d->m_page->defersLoading()) {
3380 d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectMultiple(d, size, selecteds)));
3383 DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3384 d->m_inputHandler->setPopupListIndexes(size, selecteds);
3387 void WebPage::popupListClosed(int index)
3389 DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3390 if (d->m_page->defersLoading()) {
3391 d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectSingle(d, index)));
3394 DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3395 d->m_inputHandler->setPopupListIndex(index);
3398 class DeferredTaskSetDateTimeInput: public DeferredTask<&WebPagePrivate::m_wouldSetDateTimeInput> {
3400 explicit DeferredTaskSetDateTimeInput(WebPagePrivate* webPagePrivate, BlackBerry::Platform::String value)
3401 : DeferredTaskType(webPagePrivate)
3403 webPagePrivate->m_cachedDateTimeInput = value;
3406 virtual void performInternal(WebPagePrivate* webPagePrivate)
3408 webPagePrivate->m_webPage->setDateTimeInput(webPagePrivate->m_cachedDateTimeInput);
3412 void WebPage::setDateTimeInput(const BlackBerry::Platform::String& value)
3414 if (d->m_page->defersLoading()) {
3415 d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetDateTimeInput(d, value)));
3418 DeferredTaskSetDateTimeInput::finishOrCancel(d);
3419 d->m_inputHandler->setInputValue(value);
3422 class DeferredTaskSetColorInput: public DeferredTask<&WebPagePrivate::m_wouldSetColorInput> {
3424 explicit DeferredTaskSetColorInput(WebPagePrivate* webPagePrivate, BlackBerry::Platform::String value)
3425 : DeferredTaskType(webPagePrivate)
3427 webPagePrivate->m_cachedColorInput = value;
3430 virtual void performInternal(WebPagePrivate* webPagePrivate)
3432 webPagePrivate->m_webPage->setColorInput(webPagePrivate->m_cachedColorInput);
3436 void WebPage::setColorInput(const BlackBerry::Platform::String& value)
3438 if (d->m_page->defersLoading()) {
3439 d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetColorInput(d, value)));
3442 DeferredTaskSetColorInput::finishOrCancel(d);
3443 d->m_inputHandler->setInputValue(value);
3446 void WebPage::setVirtualViewportSize(const Platform::IntSize& size)
3448 d->m_virtualViewportSize = WebCore::IntSize(size);
3451 void WebPage::resetVirtualViewportOnCommitted(bool reset)
3453 d->m_resetVirtualViewportOnCommitted = reset;
3456 Platform::IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments()
3458 static const ViewportArguments defaultViewportArguments;
3459 if (m_viewportArguments == defaultViewportArguments)
3462 int desktopWidth = DEFAULT_MAX_LAYOUT_WIDTH;
3463 int deviceWidth = Platform::Graphics::Screen::primaryScreen()->width();
3464 int deviceHeight = Platform::Graphics::Screen::primaryScreen()->height();
3465 float devicePixelRatio = m_webSettings->devicePixelRatio();
3466 ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, devicePixelRatio, m_defaultLayoutSize);
3467 m_page->setDeviceScaleFactor(devicePixelRatio);
3469 setUserScalable(m_webSettings->isUserScalable() && result.userScalable);
3470 if (result.initialScale > 0)
3471 setInitialScale(result.initialScale * devicePixelRatio);
3472 if (result.minimumScale > 0)
3473 setMinimumScale(result.minimumScale * devicePixelRatio);
3474 if (result.maximumScale > 0)
3475 setMaximumScale(result.maximumScale * devicePixelRatio);
3477 return Platform::IntSize(result.layoutSize.width(), result.layoutSize.height());
3480 #if ENABLE(EVENT_MODE_METATAGS)
3481 void WebPagePrivate::didReceiveCursorEventMode(CursorEventMode mode)
3483 if (mode != m_cursorEventMode)
3484 m_client->cursorEventModeChanged(toPlatformCursorEventMode(mode));
3485 m_cursorEventMode = mode;
3488 void WebPagePrivate::didReceiveTouchEventMode(TouchEventMode mode)
3490 if (mode != m_touchEventMode)
3491 m_client->touchEventModeChanged(toPlatformTouchEventMode(mode));
3492 m_touchEventMode = mode;
3496 void WebPagePrivate::dispatchViewportPropertiesDidChange(const ViewportArguments& arguments)
3498 if (arguments == m_viewportArguments)
3501 // If the caller is trying to reset to default arguments, use the user supplied ones instead.
3502 static const ViewportArguments defaultViewportArguments;
3503 if (arguments == defaultViewportArguments) {
3504 m_viewportArguments = m_userViewportArguments;
3505 m_forceRespectViewportArguments = m_userViewportArguments != defaultViewportArguments;
3507 m_viewportArguments = arguments;
3509 // 0 width or height in viewport arguments makes no sense, and results in a very large initial scale.
3510 // In real world, a 0 width or height is usually caused by a syntax error in "content" field of viewport
3511 // meta tag, for example, using semicolon instead of comma as separator ("width=device-width; initial-scale=1.0").
3512 // We don't have a plan to tolerate the semicolon separator, but we can avoid applying 0 width/height.
3513 // I default it to ValueDeviceWidth rather than ValueAuto because in more cases the web site wants "device-width"
3514 // when they specify the viewport width.
3515 if (!m_viewportArguments.width)
3516 m_viewportArguments.width = ViewportArguments::ValueDeviceWidth;
3517 if (!m_viewportArguments.height)
3518 m_viewportArguments.height = ViewportArguments::ValueDeviceHeight;
3520 Platform::IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
3521 m_webPage->setVirtualViewportSize(virtualViewport);
3523 // Reset m_userPerformedManualZoom and enable m_shouldZoomToInitialScaleAfterLoadFinished so that we can relayout
3524 // the page and zoom it to fit the screen when we dynamically change the meta viewport after the load is finished.
3525 bool isLoadFinished = loadState() == Finished;
3526 if (isLoadFinished) {
3527 m_userPerformedManualZoom = false;
3528 setShouldZoomToInitialScaleAfterLoadFinished(true);
3530 if (loadState() == Committed || isLoadFinished)
3531 zoomToInitialScaleOnLoad();
3534 void WebPagePrivate::suspendBackingStore()
3536 #if USE(ACCELERATED_COMPOSITING)
3537 if (m_backingStore->d->isOpenGLCompositing()) {
3538 // A visible web page's backing store can be suspended when another web
3539 // page is taking over the backing store.
3541 setCompositorDrawsRootLayer(true);
3548 void WebPagePrivate::resumeBackingStore()
3550 ASSERT(m_webPage->isVisible());
3552 bool directRendering = m_backingStore->d->shouldDirectRenderingToWindow();
3553 if (!m_backingStore->d->isActive()
3554 || shouldResetTilesWhenShown()
3555 || directRendering) {
3556 BackingStorePrivate::setCurrentBackingStoreOwner(m_webPage);
3558 // If we're OpenGL compositing, switching to accel comp drawing of the root layer
3559 // is a good substitute for backingstore blitting.
3560 if (m_backingStore->d->isOpenGLCompositing())
3561 setCompositorDrawsRootLayer(!m_backingStore->d->isActive());
3563 m_backingStore->d->orientationChanged(); // Updates tile geometry and creates visible tile buffer.
3564 m_backingStore->d->resetTiles();
3565 m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
3567 #if USE(ACCELERATED_COMPOSITING)
3568 setNeedsOneShotDrawingSynchronization();
3571 m_backingStore->d->renderAndBlitVisibleContentsImmediately();
3573 if (m_backingStore->d->isOpenGLCompositing())
3574 setCompositorDrawsRootLayer(false);
3576 // Rendering was disabled while we were hidden, so we need to update all tiles.
3577 m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
3578 #if USE(ACCELERATED_COMPOSITING)
3579 setNeedsOneShotDrawingSynchronization();
3583 setShouldResetTilesWhenShown(false);
3586 void WebPagePrivate::setScreenOrientation(int orientation)
3588 FOR_EACH_PLUGINVIEW(m_pluginViews)
3589 (*it)->handleOrientationEvent(orientation);
3591 m_pendingOrientation = -1;
3593 #if ENABLE(ORIENTATION_EVENTS)
3594 if (m_mainFrame->orientation() == orientation)
3596 for (RefPtr<Frame> frame = m_mainFrame; frame; frame = frame->tree()->traverseNext())
3597 frame->sendOrientationChangeEvent(orientation);
3601 void WebPage::setScreenOrientation(int orientation)
3603 d->m_pendingOrientation = orientation;
3606 void WebPage::applyPendingOrientationIfNeeded()
3608 if (d->m_pendingOrientation != -1)
3609 d->setScreenOrientation(d->m_pendingOrientation);
3611 // After rotation, we should redraw the dialog box instead of just moving it since rotation dismisses all dialogs.
3612 d->m_inputHandler->redrawSpellCheckDialogIfRequired(false /* shouldMoveDialog */);
3615 void WebPagePrivate::setViewportSize(const IntSize& transformedActualVisibleSize, bool ensureFocusElementVisible)
3617 if (m_pendingOrientation == -1 && transformedActualVisibleSize == this->transformedActualVisibleSize())
3620 // Suspend all screen updates to the backingstore to make sure no-one tries to blit
3621 // while the window surface and the BackingStore are out of sync.
3622 BackingStore::ResumeUpdateOperation screenResumeOperation = BackingStore::Blit;
3623 m_backingStore->d->suspendScreenUpdates();
3624 m_backingStore->d->suspendBackingStoreUpdates();
3626 // The screen rotation is a major state transition that in this case is not properly
3627 // communicated to the backing store, since it does early return in most methods when
3629 if (!m_visible || !m_backingStore->d->isActive())
3630 setShouldResetTilesWhenShown(true);
3632 bool hasPendingOrientation = m_pendingOrientation != -1;
3634 // The window buffers might have been recreated, cleared, moved, etc., so:
3635 m_backingStore->d->windowFrontBufferState()->clearBlittedRegion();
3636 m_backingStore->d->windowBackBufferState()->clearBlittedRegion();
3638 IntSize viewportSizeBefore = actualVisibleSize();
3639 FloatPoint centerOfVisibleContentsRect = this->centerOfVisibleContentsRect();
3640 bool newVisibleRectContainsOldVisibleRect = (m_actualVisibleHeight <= transformedActualVisibleSize.height())
3641 && (m_actualVisibleWidth <= transformedActualVisibleSize.width());
3643 bool atInitialScale = m_webPage->isAtInitialZoom();
3644 bool atTop = !scrollPosition().y();
3645 bool atLeft = !scrollPosition().x();
3647 setDefaultLayoutSize(transformedActualVisibleSize);
3649 // Recompute our virtual viewport.
3650 bool needsLayout = false;
3651 static ViewportArguments defaultViewportArguments;
3652 if (m_viewportArguments != defaultViewportArguments) {
3653 // We may need to infer the width and height for the viewport with respect to the rotation.
3654 Platform::IntSize newVirtualViewport = recomputeVirtualViewportFromViewportArguments();
3655 ASSERT(!newVirtualViewport.isEmpty());
3656 m_webPage->setVirtualViewportSize(newVirtualViewport);
3657 m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
3658 m_mainFrame->view()->setFixedLayoutSize(fixedLayoutSize());
3662 // We switch this strictly after recomputing our virtual viewport as zoomToFitScale is dependent
3663 // upon these values and so is the virtual viewport recalculation.
3664 m_actualVisibleWidth = transformedActualVisibleSize.width();
3665 m_actualVisibleHeight = transformedActualVisibleSize.height();
3667 IntSize viewportSizeAfter = actualVisibleSize();
3670 if (hasPendingOrientation && !m_fullscreenVideoNode) {
3671 offset = IntSize(roundf((viewportSizeBefore.width() - viewportSizeAfter.width()) / 2.0),
3672 roundf((viewportSizeBefore.height() - viewportSizeAfter.height()) / 2.0));
3675 // As a special case, if we were anchored to the top left position at
3676 // the beginning of the rotation then preserve that anchor.
3678 offset.setHeight(0);
3682 // If we're about to overscroll, cap the offset to valid content.
3683 IntPoint bottomRight(
3684 scrollPosition().x() + viewportSizeAfter.width(),
3685 scrollPosition().y() + viewportSizeAfter.height());
3687 if (bottomRight.x() + offset.width() > contentsSize().width())
3688 offset.setWidth(contentsSize().width() - bottomRight.x());
3689 if (bottomRight.y() + offset.height() > contentsSize().height())
3690 offset.setHeight(contentsSize().height() - bottomRight.y());
3691 if (scrollPosition().x() + offset.width() < 0)
3692 offset.setWidth(-scrollPosition().x());
3693 if (scrollPosition().y() + offset.height() < 0)
3694 offset.setHeight(-scrollPosition().y());
3696 // ...before scrolling, because the backing store will align its
3697 // tile matrix with the viewport as reported by the ScrollView.
3698 setScrollPosition(scrollPosition() + offset);
3699 notifyTransformedScrollChanged();
3701 m_backingStore->d->orientationChanged();
3702 m_backingStore->d->actualVisibleSizeChanged(transformedActualVisibleSize);
3704 // Update view mode only after we have updated the actual
3705 // visible size and reset the contents rect if necessary.
3706 if (setViewMode(viewMode()))
3709 bool needsLayoutToFindContentSize = hasPendingOrientation;
3711 // We need to update the viewport size of the WebCore::ScrollView...
3712 updateViewportSize(!needsLayoutToFindContentSize /* setFixedReportedSize */, false /* sendResizeEvent */);
3713 notifyTransformedContentsSizeChanged();
3715 // If automatic zooming is disabled, prevent zooming below.
3716 if (!m_webSettings->isZoomToFitOnLoad()) {
3717 atInitialScale = false;
3719 // Normally, if the contents size is smaller than the layout width,
3720 // we would zoom in. If zoom is disabled, we need to do something else,
3721 // or there will be artifacts due to non-rendered areas outside of the
3722 // contents size. If there is a virtual viewport, we are not allowed
3723 // to modify the fixed layout size, however.
3724 if (!hasVirtualViewport() && contentsSize().width() < m_defaultLayoutSize.width()) {
3725 m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
3726 m_mainFrame->view()->setFixedLayoutSize(m_defaultLayoutSize);
3731 // Need to resume so that the backingstore will start recording the invalidated
3732 // rects from below.
3733 m_backingStore->d->resumeBackingStoreUpdates();
3735 // We might need to layout here to get a correct contentsSize so that zoomToFit
3736 // is calculated correctly.
3737 bool stillNeedsLayout = needsLayout;
3738 while (stillNeedsLayout) {
3740 requestLayoutIfNeeded();
3741 stillNeedsLayout = false;
3743 // Emulate the zoomToFitWidthOnLoad algorithm if we're rotating.
3744 ++m_nestedLayoutFinishedCount;
3745 if (needsLayoutToFindContentSize) {
3746 if (setViewMode(viewMode()))
3747 stillNeedsLayout = true;
3750 m_nestedLayoutFinishedCount = 0;
3752 // As a special case if we were zoomed to the initial scale at the beginning
3753 // of the rotation then preserve that zoom level even when it is zoomToFit.
3754 double scale = atInitialScale ? initialScale() : currentScale();
3756 // Do our own clamping.
3757 scale = clampedScale(scale);
3759 if (needsLayoutToFindContentSize) {
3760 // Set the fixed reported size here so that innerWidth|innerHeight works
3761 // with this new scale.
3762 TransformationMatrix rotationMatrix;
3763 rotationMatrix.scale(scale);
3764 IntRect viewportRect = IntRect(IntPoint::zero(), transformedActualVisibleSize);
3765 IntRect actualVisibleRect = enclosingIntRect(rotationMatrix.inverse().mapRect(FloatRect(viewportRect)));
3766 m_mainFrame->view()->setFixedReportedSize(actualVisibleRect.size());
3767 m_mainFrame->view()->repaintFixedElementsAfterScrolling();
3768 requestLayoutIfNeeded();
3769 m_mainFrame->view()->updateFixedElementsAfterScrolling();
3772 // We're going to need to send a resize event to JavaScript because
3773 // innerWidth and innerHeight depend on fixed reported size.
3774 // This is how we support mobile pages where JavaScript resizes
3775 // the page in order to get around the fixed layout size, e.g.
3776 // google maps when it detects a mobile user agent.
3777 if (shouldSendResizeEvent())
3778 m_mainFrame->eventHandler()->sendResizeEvent();
3780 // As a special case if we were anchored to the top left position at the beginning
3781 // of the rotation then preserve that anchor.
3782 FloatPoint anchor = centerOfVisibleContentsRect;
3788 // Try and zoom here with clamping on.
3789 // FIXME: Determine why the above comment says "clamping on", yet we
3790 // don't set enforceScaleClamping to true.
3791 // FIXME: Determine why ensureContentVisible() is only called for !success
3792 // in the direct-rendering case, but in all cases otherwise. Chances are
3793 // one of these is incorrect and we can unify two branches into one.
3794 if (m_backingStore->d->shouldDirectRenderingToWindow()) {
3795 bool success = zoomAboutPoint(scale, anchor, false /* enforceScaleClamping */, true /* forceRendering */);
3796 if (!success && ensureFocusElementVisible)
3797 ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3799 } else if (zoomAboutPoint(scale, anchor, false /*enforceScaleClamping*/, true /*forceRendering*/)) {
3800 if (ensureFocusElementVisible)
3801 ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3805 // Suspend all updates to the backingstore.
3806 m_backingStore->d->suspendBackingStoreUpdates();
3808 // If the zoom failed, then we should still preserve the special case of scroll position.
3809 IntPoint scrollPosition = this->scrollPosition();
3811 scrollPosition.setY(0);
3813 scrollPosition.setX(0);
3814 setScrollPosition(scrollPosition);
3816 // These might have been altered even if we didn't zoom so notify the client.
3817 notifyTransformedContentsSizeChanged();
3818 notifyTransformedScrollChanged();
3821 // The visible tiles for scroll must be up-to-date before we blit since we are not performing a layout.
3822 m_backingStore->d->updateTilesForScrollOrNotRenderedRegion();
3825 if (ensureFocusElementVisible)
3826 ensureContentVisible(!newVisibleRectContainsOldVisibleRect);
3829 m_backingStore->d->resetTiles();
3830 m_backingStore->d->updateTiles(false /* updateVisible */, false /* immediate */);
3831 screenResumeOperation = BackingStore::RenderAndBlit;
3834 // If we need layout then render and blit, otherwise just blit as our viewport has changed.
3835 m_backingStore->d->resumeBackingStoreUpdates();
3838 #if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
3839 // When leaving fullscreen mode, restore the scale and scroll position if needed.
3840 // We also need to make sure the scale and scroll position won't cause over scale or over scroll.
3841 if (m_scaleBeforeFullScreen > 0 && !m_fullscreenNode) {
3842 // Restore the scale when leaving fullscreen. We can't use TransformationMatrix::scale(double) here,
3843 // as it will multiply the scale rather than set the scale.
3844 // FIXME: We can refactor this into setCurrentScale(double) if it is useful in the future.
3845 if (m_orientationBeforeFullScreen % 180 != orientation() % 180) { // Orientation changed
3846 if (m_actualVisibleWidth > contentsSize().width() * m_scaleBeforeFullScreen) {
3847 // Cached scale need to be adjusted after rotation.
3848 m_scaleBeforeFullScreen = double(m_actualVisibleWidth) / contentsSize().width();
3850 if (m_scaleBeforeFullScreen * contentsSize().height() < m_actualVisibleHeight) {
3851 // Use zoom to fit height scale in order to cover the screen height.
3852 m_scaleBeforeFullScreen = double(m_actualVisibleHeight) / contentsSize().height();
3855 if (m_actualVisibleWidth > m_scaleBeforeFullScreen * (contentsSize().width() - m_scrollPositionBeforeFullScreen.x())) {
3856 // Cached scroll position over scrolls horizontally after rotation.
3857 m_scrollPositionBeforeFullScreen.setX(contentsSize().width() - m_actualVisibleWidth / m_scaleBeforeFullScreen);
3859 if (m_actualVisibleHeight > m_scaleBeforeFullScreen * (contentsSize().height() - m_scrollPositionBeforeFullScreen.y())) {
3860 // Cached scroll position over scrolls vertically after rotation.
3861 m_scrollPositionBeforeFullScreen.setY(contentsSize().height() - m_actualVisibleHeight / m_scaleBeforeFullScreen);
3865 m_transformationMatrix->setM11(m_scaleBeforeFullScreen);
3866 m_transformationMatrix->setM22(m_scaleBeforeFullScreen);
3867 m_scaleBeforeFullScreen = -1.0;
3869 setScrollPosition(m_scrollPositionBeforeFullScreen);
3870 notifyTransformChanged();
3871 m_client->scaleChanged();
3875 m_backingStore->d->resumeScreenUpdates(screenResumeOperation);
3876 m_inputHandler->redrawSpellCheckDialogIfRequired();
3879 void WebPage::setViewportSize(const Platform::IntSize& viewportSize, bool ensureFocusElementVisible)
3881 d->setViewportSize(viewportSize, ensureFocusElementVisible);
3884 void WebPagePrivate::setDefaultLayoutSize(const IntSize& size)
3886 IntSize screenSize = Platform::Settings::instance()->applicationSize();
3887 ASSERT(size.width() <= screenSize.width() && size.height() <= screenSize.height());
3888 m_defaultLayoutSize = size.expandedTo(minimumLayoutSize).shrunkTo(screenSize);
3891 void WebPage::setDefaultLayoutSize(const Platform::IntSize& platformSize)
3893 WebCore::IntSize size = platformSize;
3894 if (size == d->m_defaultLayoutSize)
3897 d->setDefaultLayoutSize(size);
3898 bool needsLayout = d->setViewMode(d->viewMode());
3900 d->setNeedsLayout();
3901 if (!d->isLoading())
3902 d->requestLayoutIfNeeded();
3906 bool WebPage::mouseEvent(const Platform::MouseEvent& mouseEvent, bool* wheelDeltaAccepted)
3908 if (!d->m_mainFrame->view())
3911 if (d->m_page->defersLoading())
3914 PluginView* pluginView = d->m_fullScreenPluginView.get();
3916 return d->dispatchMouseEventToFullScreenPlugin(pluginView, mouseEvent);
3918 if (mouseEvent.type() == Platform::MouseEvent::MouseAborted) {
3919 d->m_mainFrame->eventHandler()->setMousePressed(false);
3923 d->m_pluginMayOpenNewTab = true;
3925 d->m_lastUserEventTimestamp = currentTime();
3926 int clickCount = (d->m_selectionHandler->isSelectionActive() || mouseEvent.type() != Platform::MouseEvent::MouseMove) ? 1 : 0;
3928 // Set the button type.
3929 MouseButton buttonType = NoButton;
3930 if (mouseEvent.isLeftButton())
3931 buttonType = LeftButton;
3932 else if (mouseEvent.isRightButton())
3933 buttonType = RightButton;
3934 else if (mouseEvent.isMiddleButton())
3935 buttonType = MiddleButton;
3937 // Create our event.
3938 PlatformMouseEvent platformMouseEvent(mouseEvent.documentViewportPosition(), mouseEvent.screenPosition(),
3939 toWebCoreMouseEventType(mouseEvent.type()), clickCount, buttonType,
3940 mouseEvent.shiftActive(), mouseEvent.ctrlActive(), mouseEvent.altActive(), PointingDevice);
3941 d->m_lastMouseEvent = platformMouseEvent;
3942 bool success = d->handleMouseEvent(platformMouseEvent);
3944 if (mouseEvent.wheelTicks()) {
3945 PlatformWheelEvent wheelEvent(mouseEvent.documentViewportPosition(), mouseEvent.screenPosition(),
3946 0, -mouseEvent.wheelDelta(),
3947 0, -mouseEvent.wheelTicks(),
3948 ScrollByPixelWheelEvent,
3949 mouseEvent.shiftActive(), mouseEvent.ctrlActive(),
3950 mouseEvent.altActive(), false /* metaKey */);
3951 if (wheelDeltaAccepted)
3952 *wheelDeltaAccepted = d->handleWheelEvent(wheelEvent);
3953 } else if (wheelDeltaAccepted)
3954 *wheelDeltaAccepted = false;
3959 bool WebPagePrivate::dispatchMouseEventToFullScreenPlugin(PluginView* plugin, const Platform::MouseEvent& event)
3962 NPMouseEvent mouseEvent;
3964 mouseEvent.x = event.screenPosition().x();
3965 mouseEvent.y = event.screenPosition().y();
3967 switch (event.type()) {
3968 case Platform::MouseEvent::MouseButtonDown:
3969 mouseEvent.type = MOUSE_BUTTON_DOWN;
3970 m_pluginMouseButtonPressed = true;
3972 case Platform::MouseEvent::MouseButtonUp:
3973 mouseEvent.type = MOUSE_BUTTON_UP;
3974 m_pluginMouseButtonPressed = false;
3976 case Platform::MouseEvent::MouseMove:
3977 mouseEvent.type = MOUSE_MOTION;
3983 mouseEvent.flags = 0;
3984 mouseEvent.button = m_pluginMouseButtonPressed;
3986 npEvent.type = NP_MouseEvent;
3987 npEvent.data = &mouseEvent;
3989 return plugin->dispatchFullScreenNPEvent(npEvent);
3992 bool WebPagePrivate::handleMouseEvent(PlatformMouseEvent& mouseEvent)
3994 EventHandler* eventHandler = m_mainFrame->eventHandler();
3996 if (mouseEvent.type() == WebCore::PlatformEvent::MouseMoved)
3997 return eventHandler->mouseMoved(mouseEvent);
3999 if (mouseEvent.type() == WebCore::PlatformEvent::MouseScroll)
4003 if (mouseEvent.inputMethod() == TouchScreen) {
4004 const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
4006 // Fat fingers can deal with shadow content.
4007 node = lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
4011 HitTestResult result = eventHandler->hitTestResultAtPoint(mapFromViewportToContents(mouseEvent.position()), false /*allowShadowContent*/);
4012 node = result.innerNode();
4015 if (mouseEvent.type() == WebCore::PlatformEvent::MousePressed) {
4016 m_inputHandler->setInputModeEnabled();
4017 if (m_inputHandler->willOpenPopupForNode(node)) {
4018 // Do not allow any human generated mouse or keyboard events to select <option>s in the list box
4019 // because we use a pop up dialog to handle the actual selections. This prevents options from
4020 // being selected prior to displaying the pop up dialog. The contents of the listbox are for
4023 // FIXME: We explicitly do not forward this event to WebCore so as to preserve symmetry with
4024 // the MouseEventReleased handling (below). This has the side-effect that mousedown events
4025 // are not fired for human generated mouse press events. See RIM Bug #1579.
4027 // We do focus <select>/<option> on mouse down so that a Focus event is fired and have the
4028 // element painted in its focus state on repaint.
4029 ASSERT_WITH_SECURITY_IMPLICATION(node->isElementNode());
4030 if (node->isElementNode()) {
4031 Element* element = static_cast<Element*>(node);
4035 eventHandler->handleMousePressEvent(mouseEvent);
4036 } else if (mouseEvent.type() == WebCore::PlatformEvent::MouseReleased) {
4037 // FIXME: For <select> and <options> elements, we explicitly do not forward this event to WebCore so
4038 // as to preserve symmetry with the MouseEventPressed handling (above). This has the side-effect that
4039 // mouseup events are not fired on such elements for human generated mouse release events. See RIM Bug #1579.
4040 if (!m_inputHandler->didNodeOpenPopup(node))
4041 eventHandler->handleMouseReleaseEvent(mouseEvent);
4047 bool WebPagePrivate::handleWheelEvent(PlatformWheelEvent& wheelEvent)
4049 return m_mainFrame->eventHandler()->handleWheelEvent(wheelEvent);
4052 bool WebPage::touchEvent(const Platform::TouchEvent& event)
4054 #if DEBUG_TOUCH_EVENTS
4055 Platform::logAlways(Platform::LogLevelCritical, "%s", event.toString().c_str());
4058 #if ENABLE(TOUCH_EVENTS)
4059 if (!d->m_mainFrame)
4062 if (d->m_page->defersLoading())
4065 if (d->m_inputHandler)
4066 d->m_inputHandler->setInputModeEnabled();
4068 PluginView* pluginView = d->m_fullScreenPluginView.get();
4070 return d->dispatchTouchEventToFullScreenPlugin(pluginView, event);
4072 Platform::TouchEvent tEvent = event;
4073 if (event.isSingleTap())
4074 d->m_pluginMayOpenNewTab = true;
4075 else if (tEvent.m_type == Platform::TouchEvent::TouchStart || tEvent.m_type == Platform::TouchEvent::TouchCancel)
4076 d->m_pluginMayOpenNewTab = false;
4078 if (tEvent.m_type == Platform::TouchEvent::TouchStart) {
4079 d->clearCachedHitTestResult();
4080 d->m_touchEventHandler->doFatFingers(tEvent.m_points[0]);
4082 // Draw tap highlight as soon as possible if we can
4083 Element* elementUnderFatFinger = d->m_touchEventHandler->lastFatFingersResult().nodeAsElementIfApplicable();
4084 if (elementUnderFatFinger)
4085 d->m_touchEventHandler->drawTapHighlight();
4088 bool handled = false;
4090 if (event.m_type != Platform::TouchEvent::TouchInjected)
4091 handled = d->m_mainFrame->eventHandler()->handleTouchEvent(PlatformTouchEvent(&tEvent));
4093 if (d->m_preventDefaultOnTouchStart) {