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 "AutofillManager.h"
24 #include "BackForwardController.h"
25 #include "BackForwardListImpl.h"
26 #include "BackingStoreClient.h"
27 #include "BackingStoreCompositingSurface.h"
28 #include "BackingStore_p.h"
29 #if ENABLE(BATTERY_STATUS)
30 #include "BatteryClientBlackBerry.h"
33 #include "CachedImage.h"
35 #include "ChromeClientBlackBerry.h"
36 #include "ContextMenuClientBlackBerry.h"
37 #include "CookieManager.h"
38 #include "CredentialManager.h"
39 #include "CredentialStorage.h"
40 #include "CredentialTransformData.h"
41 #include "DOMSupport.h"
43 #include "DatabaseSync.h"
44 #include "DatabaseTracker.h"
45 #include "DefaultTapHighlight.h"
46 #include "DeviceMotionClientBlackBerry.h"
47 #include "DeviceOrientationClientBlackBerry.h"
48 #include "DragClientBlackBerry.h"
49 // FIXME: We should be using DumpRenderTreeClient, but I'm not sure where we should
50 // create the DRT_BB object. See PR #120355.
51 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
52 #include "DumpRenderTreeBlackBerry.h"
54 #include "EditorClientBlackBerry.h"
55 #include "FocusController.h"
56 #include "FrameLoaderClientBlackBerry.h"
57 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
58 #include "GeolocationClientMock.h"
60 #include "GeolocationControllerClientBlackBerry.h"
61 #include "GroupSettings.h"
62 #include "HTMLAreaElement.h"
63 #include "HTMLFrameOwnerElement.h"
64 #include "HTMLImageElement.h"
65 #include "HTMLInputElement.h"
66 #include "HTMLMediaElement.h"
67 #include "HTMLNames.h"
68 #include "HTMLParserIdioms.h"
69 #include "HTTPParsers.h"
70 #include "HistoryItem.h"
71 #include "IconDatabaseClientBlackBerry.h"
72 #include "InPageSearchManager.h"
73 #include "InRegionScrollableArea.h"
74 #include "InRegionScroller_p.h"
75 #include "InputHandler.h"
76 #include "InspectorBackendDispatcher.h"
77 #include "InspectorClientBlackBerry.h"
78 #include "InspectorController.h"
79 #include "InspectorOverlay.h"
80 #include "JavaScriptDebuggerBlackBerry.h"
81 #include "JavaScriptVariant_p.h"
82 #include "LayerWebKitThread.h"
83 #include "NetworkManager.h"
84 #include "NodeRenderStyle.h"
85 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
86 #include "NotificationPresenterImpl.h"
89 #include "PageCache.h"
90 #include "PageGroup.h"
91 #include "PagePopupBlackBerry.h"
92 #include "PlatformTouchEvent.h"
93 #include "PlatformWheelEvent.h"
94 #include "PluginDatabase.h"
95 #include "PluginView.h"
96 #include "RenderLayerBacking.h"
97 #include "RenderLayerCompositor.h"
98 #if ENABLE(FULLSCREEN_API)
99 #include "RenderFullScreen.h"
101 #include "RenderText.h"
102 #include "RenderThemeBlackBerry.h"
103 #include "RenderTreeAsText.h"
104 #include "RenderView.h"
105 #include "RenderWidget.h"
106 #include "ScriptSourceCode.h"
107 #include "ScriptValue.h"
108 #include "ScrollTypes.h"
109 #include "SecurityPolicy.h"
110 #include "SelectionHandler.h"
111 #include "SelectionOverlay.h"
112 #include "Settings.h"
114 #include "StorageNamespace.h"
115 #include "SurfacePool.h"
117 #include "ThreadCheck.h"
118 #include "TouchEventHandler.h"
119 #include "TransformationMatrix.h"
120 #if ENABLE(MEDIA_STREAM)
121 #include "UserMediaClientImpl.h"
123 #if ENABLE(VIBRATION)
124 #include "VibrationClientBlackBerry.h"
126 #include "VisiblePosition.h"
128 #include "WebDOMDocument.h"
130 #include "WebKitVersion.h"
131 #include "WebOverlay.h"
132 #include "WebOverlay_p.h"
133 #include "WebPageClient.h"
134 #include "WebSocket.h"
135 #include "WebViewportArguments.h"
137 #include "runtime_root.h"
140 #include "MediaPlayer.h"
141 #include "MediaPlayerPrivateBlackBerry.h"
145 #include "PlatformContextSkia.h"
148 #if USE(ACCELERATED_COMPOSITING)
149 #include "FrameLayers.h"
150 #include "WebPageCompositorClient.h"
151 #include "WebPageCompositor_p.h"
154 #include <BlackBerryPlatformDeviceInfo.h>
155 #include <BlackBerryPlatformExecutableMessage.h>
156 #include <BlackBerryPlatformITPolicy.h>
157 #include <BlackBerryPlatformKeyboardEvent.h>
158 #include <BlackBerryPlatformMessageClient.h>
159 #include <BlackBerryPlatformMouseEvent.h>
160 #include <BlackBerryPlatformScreen.h>
161 #include <BlackBerryPlatformSettings.h>
162 #include <JavaScriptCore/APICast.h>
163 #include <JavaScriptCore/JSContextRef.h>
164 #include <JavaScriptCore/JSStringRef.h>
165 #include <SharedPointer.h>
166 #include <sys/keycodes.h>
167 #include <unicode/ustring.h> // platform ICU
169 #ifndef USER_PROCESSES
170 #include <memalloc.h>
173 #if ENABLE(ACCELERATED_2D_CANVAS)
174 #include "GrContext.h"
175 #include "SharedGraphicsContext3D.h"
178 #if ENABLE(REQUEST_ANIMATION_FRAME)
179 #include "PlatformScreen.h"
182 #define DEBUG_BLOCK_ZOOM 0
183 #define DEBUG_TOUCH_EVENTS 0
184 #define DEBUG_WEBPAGE_LOAD 0
185 #define DEBUG_AC_COMMIT 0
188 using namespace WebCore;
190 typedef const unsigned short* CUShortPtr;
192 namespace BlackBerry {
195 static Vector<WebPage*>* visibleWebPages()
197 static Vector<WebPage*>* s_visibleWebPages = 0; // Initially, no web page is visible.
198 if (!s_visibleWebPages)
199 s_visibleWebPages = new Vector<WebPage*>;
200 return s_visibleWebPages;
203 const unsigned blockZoomMargin = 3; // Add 3 pixel margin on each side.
204 static int blockClickRadius = 0;
205 static double maximumBlockZoomScale = 3; // This scale can be clamped by the maximumScale set for the page.
207 const double manualScrollInterval = 0.1; // The time interval during which we associate user action with scrolling.
209 const double delayedZoomInterval = 0;
211 const IntSize minimumLayoutSize(10, 10); // Needs to be a small size, greater than 0, that we can grow the layout from.
213 const double minimumExpandingRatio = 0.15;
215 const double minimumZoomToFitScale = 0.25;
217 // Helper function to parse a URL and fill in missing parts.
218 static KURL parseUrl(const String& url)
220 String urlString(url);
221 KURL kurl = KURL(KURL(), urlString);
222 if (kurl.protocol().isEmpty()) {
223 urlString.insert("http://", 0);
224 kurl = KURL(KURL(), urlString);
230 // Helper functions to convert to and from WebCore types.
231 static inline WebCore::PlatformEvent::Type toWebCoreMouseEventType(const BlackBerry::Platform::MouseEvent::Type type)
234 case BlackBerry::Platform::MouseEvent::MouseButtonDown:
235 return WebCore::PlatformEvent::MousePressed;
236 case Platform::MouseEvent::MouseButtonUp:
237 return WebCore::PlatformEvent::MouseReleased;
238 case Platform::MouseEvent::MouseMove:
240 return WebCore::PlatformEvent::MouseMoved;
244 static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy)
247 case Platform::NetworkRequest::UseProtocolCachePolicy:
248 return UseProtocolCachePolicy;
249 case Platform::NetworkRequest::ReloadIgnoringCacheData:
250 return ReloadIgnoringCacheData;
251 case Platform::NetworkRequest::ReturnCacheDataElseLoad:
252 return ReturnCacheDataElseLoad;
253 case Platform::NetworkRequest::ReturnCacheDataDontLoad:
254 return ReturnCacheDataDontLoad;
256 ASSERT_NOT_REACHED();
257 return UseProtocolCachePolicy;
261 #if ENABLE(EVENT_MODE_METATAGS)
262 static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode)
265 case ProcessedCursorEvents:
266 return Platform::ProcessedCursorEvents;
267 case NativeCursorEvents:
268 return Platform::NativeCursorEvents;
270 ASSERT_NOT_REACHED();
271 return Platform::ProcessedCursorEvents;
275 static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode)
278 case ProcessedTouchEvents:
279 return Platform::ProcessedTouchEvents;
280 case NativeTouchEvents:
281 return Platform::NativeTouchEvents;
282 case PureTouchEventsWithMouseConversion:
283 return Platform::PureTouchEventsWithMouseConversion;
285 ASSERT_NOT_REACHED();
286 return Platform::ProcessedTouchEvents;
291 static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id)
293 return reinterpret_cast<HistoryItem*>(id);
296 static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item)
298 return reinterpret_cast<WebPage::BackForwardId>(item);
301 void WebPage::setUserViewportArguments(const WebViewportArguments& viewportArguments)
303 d->m_userViewportArguments = *(viewportArguments.d);
306 void WebPage::resetUserViewportArguments()
308 d->m_userViewportArguments = ViewportArguments();
311 template <bool WebPagePrivate::* isActive>
312 class DeferredTask: public WebPagePrivate::DeferredTaskBase {
314 static void finishOrCancel(WebPagePrivate* webPagePrivate)
316 webPagePrivate->*isActive = false;
319 DeferredTask(WebPagePrivate* webPagePrivate)
320 : DeferredTaskBase(webPagePrivate, isActive)
323 typedef DeferredTask<isActive> DeferredTaskType;
326 void WebPage::autofillTextField(const string& item)
328 if (!d->m_webSettings->isFormAutofillEnabled())
331 d->m_autofillManager->autofillTextField(item.c_str());
334 WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
337 , m_inspectorClient(0)
338 , m_page(0) // Initialized by init.
339 , m_mainFrame(0) // Initialized by init.
340 , m_currentContextNode(0)
341 , m_webSettings(0) // Initialized by init.
343 , m_activationState(ActivationActive)
344 , m_shouldResetTilesWhenShown(false)
345 , m_shouldZoomToInitialScaleAfterLoadFinished(false)
346 , m_userScalable(true)
347 , m_userPerformedManualZoom(false)
348 , m_userPerformedManualScroll(false)
349 , m_contentsSizeChanged(false)
350 , m_overflowExceedsContentsSize(false)
351 , m_resetVirtualViewportOnCommitted(true)
352 , m_shouldUseFixedDesktopMode(false)
353 , m_needTouchEvents(false)
354 , m_preventIdleDimmingCount(0)
355 #if ENABLE(TOUCH_EVENTS)
356 , m_preventDefaultOnTouchStart(false)
358 , m_nestedLayoutFinishedCount(0)
359 , m_actualVisibleWidth(rect.width())
360 , m_actualVisibleHeight(rect.height())
361 , m_virtualViewportWidth(0)
362 , m_virtualViewportHeight(0)
363 , m_defaultLayoutSize(minimumLayoutSize)
364 , m_didRestoreFromPageCache(false)
365 , m_viewMode(WebPagePrivate::Desktop) // Default to Desktop mode for PB.
366 , m_loadState(WebPagePrivate::None)
367 , m_transformationMatrix(new TransformationMatrix())
368 , m_backingStore(0) // Initialized by init.
369 , m_backingStoreClient(0) // Initialized by init.
370 , m_inPageSearchManager(new InPageSearchManager(this))
371 , m_inputHandler(new InputHandler(this))
372 , m_selectionHandler(new SelectionHandler(this))
373 , m_touchEventHandler(new TouchEventHandler(this))
374 #if ENABLE(EVENT_MODE_METATAGS)
375 , m_cursorEventMode(ProcessedCursorEvents)
376 , m_touchEventMode(ProcessedTouchEvents)
378 #if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
379 , m_scaleBeforeFullScreen(-1.0)
380 , m_xScrollOffsetBeforeFullScreen(-1)
382 , m_currentCursor(Platform::CursorNone)
383 , m_dumpRenderTree(0) // Lazy initialization.
384 , m_initialScale(-1.0)
385 , m_minimumScale(-1.0)
386 , m_maximumScale(-1.0)
387 , m_blockZoomFinalScale(1.0)
388 , m_anchorInNodeRectRatio(-1, -1)
389 , m_currentBlockZoomNode(0)
390 , m_currentBlockZoomAdjustedNode(0)
391 , m_shouldReflowBlock(false)
392 , m_delayedZoomTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::zoomAboutPointTimerFired)))
393 , m_lastUserEventTimestamp(0.0)
394 , m_pluginMouseButtonPressed(false)
395 , m_pluginMayOpenNewTab(false)
396 #if USE(ACCELERATED_COMPOSITING)
397 , m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
398 , m_needsOneShotDrawingSynchronization(false)
399 , m_needsCommit(false)
400 , m_suspendRootLayerCommit(false)
402 , m_hasPendingSurfaceSizeChange(false)
403 , m_pendingOrientation(-1)
404 , m_fullscreenVideoNode(0)
405 , m_hasInRegionScrollableAreas(false)
406 , m_updateDelegatedOverlaysDispatched(false)
407 , m_deferredTasksTimer(this, &WebPagePrivate::deferredTasksTimerFired)
409 , m_autofillManager(AutofillManager::create(this))
411 static bool isInitialized = false;
412 if (!isInitialized) {
413 isInitialized = true;
414 BlackBerry::Platform::DeviceInfo::instance();
419 WebPage::WebPage(WebPageClient* client, const WebString& pageGroupName, const Platform::IntRect& rect)
422 d = new WebPagePrivate(this, client, rect);
423 d->init(pageGroupName);
426 WebPagePrivate::~WebPagePrivate()
428 // Hand the backingstore back to another owner if necessary.
429 m_webPage->setVisible(false);
430 if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage)
431 BackingStorePrivate::setCurrentBackingStoreOwner(0);
433 delete m_webSettings;
436 delete m_backingStoreClient;
437 m_backingStoreClient = 0;
443 delete m_transformationMatrix;
444 m_transformationMatrix = 0;
446 delete m_inPageSearchManager;
447 m_inPageSearchManager = 0;
449 delete m_selectionHandler;
450 m_selectionHandler = 0;
452 delete m_inputHandler;
455 delete m_touchEventHandler;
456 m_touchEventHandler = 0;
458 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
459 delete m_dumpRenderTree;
460 m_dumpRenderTree = 0;
463 #if USE(ACCELERATED_COMPOSITING)
464 deleteGuardedObject(m_selectionOverlay);
465 m_selectionOverlay = 0;
471 deleteGuardedObject(d);
475 Page* WebPagePrivate::core(const WebPage* webPage)
477 return webPage->d->m_page;
480 void WebPagePrivate::init(const WebString& pageGroupName)
482 ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this);
483 ContextMenuClientBlackBerry* contextMenuClient = 0;
484 #if ENABLE(CONTEXT_MENUS)
485 contextMenuClient = new ContextMenuClientBlackBerry();
487 EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this);
488 DragClientBlackBerry* dragClient = 0;
489 #if ENABLE(DRAG_SUPPORT)
490 dragClient = new DragClientBlackBerry();
492 #if ENABLE(INSPECTOR)
493 m_inspectorClient = new InspectorClientBlackBerry(this);
496 FrameLoaderClientBlackBerry* frameLoaderClient = new FrameLoaderClientBlackBerry();
498 Page::PageClients pageClients;
499 pageClients.chromeClient = chromeClient;
500 pageClients.contextMenuClient = contextMenuClient;
501 pageClients.editorClient = editorClient;
502 pageClients.dragClient = dragClient;
503 pageClients.inspectorClient = m_inspectorClient;
505 m_page = new Page(pageClients);
506 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
507 if (getenv("drtRun")) {
508 // In case running in DumpRenderTree mode set the controller to mock provider.
509 GeolocationClientMock* mock = new GeolocationClientMock();
510 WebCore::provideGeolocationTo(m_page, mock);
511 mock->setController(WebCore::GeolocationController::from(m_page));
514 WebCore::provideGeolocationTo(m_page, new GeolocationControllerClientBlackBerry(this));
516 WebCore::provideDeviceOrientationTo(m_page, new DeviceOrientationClientBlackBerry(this));
517 WebCore::provideDeviceMotionTo(m_page, new DeviceMotionClientBlackBerry(this));
518 #if ENABLE(VIBRATION)
519 WebCore::provideVibrationTo(m_page, new VibrationClientBlackBerry());
522 #if ENABLE(BATTERY_STATUS)
523 WebCore::provideBatteryTo(m_page, new WebCore::BatteryClientBlackBerry(this));
526 #if ENABLE(MEDIA_STREAM)
527 WebCore::provideUserMediaTo(m_page, new UserMediaClientImpl(m_webPage));
530 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
531 WebCore::provideNotification(m_page, NotificationPresenterImpl::instance());
534 m_page->setCustomHTMLTokenizerChunkSize(256);
535 m_page->setCustomHTMLTokenizerTimeDelay(0.3);
537 m_webSettings = WebSettings::createFromStandardSettings();
538 m_webSettings->setUserAgentString(defaultUserAgent());
539 m_page->setDeviceScaleFactor(m_webSettings->devicePixelRatio());
541 #if USE(ACCELERATED_COMPOSITING)
542 m_tapHighlight = DefaultTapHighlight::create(this);
543 m_selectionOverlay = SelectionOverlay::create(this);
544 m_page->settings()->setAcceleratedCompositingForFixedPositionEnabled(true);
547 // FIXME: We explicitly call setDelegate() instead of passing ourself in createFromStandardSettings()
548 // so that we only get one didChangeSettings() callback when we set the page group name. This causes us
549 // to make a copy of the WebSettings since some WebSettings method make use of the page group name.
550 // Instead, we shouldn't be storing the page group name in WebSettings.
551 m_webSettings->setPageGroupName(pageGroupName);
552 m_webSettings->setDelegate(this);
553 didChangeSettings(m_webSettings);
555 RefPtr<Frame> newFrame = Frame::create(m_page, /* HTMLFrameOwnerElement* */ 0, frameLoaderClient);
557 m_mainFrame = newFrame.get();
558 frameLoaderClient->setFrame(m_mainFrame, this);
561 m_inRegionScroller = adoptPtr(new InRegionScroller(this));
564 Platform::Settings* settings = Platform::Settings::instance();
565 m_page->settings()->setWebGLEnabled(settings && settings->isWebGLSupported());
567 #if ENABLE(ACCELERATED_2D_CANVAS)
568 m_page->settings()->setCanvasUsesAcceleratedDrawing(true);
569 m_page->settings()->setAccelerated2dCanvasEnabled(true);
572 m_page->settings()->setInteractiveFormValidationEnabled(true);
573 m_page->settings()->setAllowUniversalAccessFromFileURLs(false);
574 m_page->settings()->setAllowFileAccessFromFileURLs(false);
576 m_backingStoreClient = BackingStoreClient::create(m_mainFrame, /* parent frame */ 0, m_webPage);
577 // The direct access to BackingStore is left here for convenience since it
578 // is owned by BackingStoreClient and then deleted by its destructor.
579 m_backingStore = m_backingStoreClient->backingStore();
581 blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(0).width())); // The clicked rectangle area should be a fixed unit of measurement.
583 m_page->settings()->setDelegateSelectionPaint(true);
585 #if ENABLE(REQUEST_ANIMATION_FRAME)
586 m_page->windowScreenDidChange((PlatformDisplayID)0);
589 #if ENABLE(WEB_TIMING)
590 m_page->settings()->setMemoryInfoEnabled(true);
593 #if USE(ACCELERATED_COMPOSITING)
594 // The compositor will be needed for overlay rendering, so create it
595 // unconditionally. It will allocate OpenGL objects lazily, so this incurs
596 // no overhead in the unlikely case where the compositor is not needed.
597 Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
598 createMethodCallMessage(&WebPagePrivate::createCompositor, this));
600 m_page->settings()->setDNSPrefetchingEnabled(true);
603 class DeferredTaskLoadManualScript: public DeferredTask<&WebPagePrivate::m_wouldLoadManualScript> {
605 explicit DeferredTaskLoadManualScript(WebPagePrivate* webPagePrivate, const KURL& url)
606 : DeferredTaskType(webPagePrivate)
608 webPagePrivate->m_cachedManualScript = url;
611 virtual void performInternal(WebPagePrivate* webPagePrivate)
613 webPagePrivate->m_mainFrame->script()->executeIfJavaScriptURL(webPagePrivate->m_cachedManualScript, DoNotReplaceDocumentIfJavaScriptURL);
617 void WebPagePrivate::load(const char* url, const char* networkToken, const char* method, Platform::NetworkRequest::CachePolicy cachePolicy, const char* data, size_t dataLength, const char* const* headers, size_t headersLength, bool isInitial, bool mustHandleInternally, bool forceDownload, const char* overrideContentType, const char* suggestedSaveName)
620 DeferredTaskLoadManualScript::finishOrCancel(this);
622 String urlString(url);
623 if (urlString.startsWith("vs:", false)) {
624 urlString = urlString.substring(3);
625 m_mainFrame->setInViewSourceMode(true);
627 m_mainFrame->setInViewSourceMode(false);
629 KURL kurl = parseUrl(urlString);
630 if (protocolIs(kurl, "javascript")) {
631 // Never run javascript while loading is deferred.
632 if (m_page->defersLoading())
633 m_deferredTasks.append(adoptPtr(new DeferredTaskLoadManualScript(this, kurl)));
635 m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL);
640 NetworkManager::instance()->setInitialURL(kurl);
642 ResourceRequest request(kurl);
643 request.setToken(networkToken);
644 if (isInitial || mustHandleInternally)
645 request.setMustHandleInternally(true);
646 request.setHTTPMethod(method);
647 request.setCachePolicy(toWebCoreCachePolicy(cachePolicy));
648 if (overrideContentType)
649 request.setOverrideContentType(overrideContentType);
652 request.setHTTPBody(FormData::create(data, dataLength));
654 for (unsigned i = 0; i + 1 < headersLength; i += 2)
655 request.addHTTPHeaderField(headers[i], headers[i + 1]);
658 request.setForceDownload(true);
660 request.setSuggestedSaveName(suggestedSaveName);
662 m_mainFrame->loader()->load(request, "" /* name */, false);
665 void WebPage::load(const char* url, const char* networkToken, bool isInitial)
667 d->load(url, networkToken, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, isInitial, false);
670 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)
672 d->load(url, networkToken, method, cachePolicy, data, dataLength, headers, headersLength, false, mustHandleInternally, false, "");
675 void WebPage::loadFile(const char* path, const char* overrideContentType)
677 std::string fileUrl(path);
678 if (!fileUrl.find("/"))
679 fileUrl.insert(0, "file://");
680 else if (fileUrl.find("file:///"))
683 d->load(fileUrl.c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, false, overrideContentType);
686 void WebPage::download(const Platform::NetworkRequest& request)
688 vector<const char*> headers;
689 Platform::NetworkRequest::HeaderList& list = request.getHeaderListRef();
690 for (unsigned i = 0; i < list.size(); i++) {
691 headers.push_back(list[i].first.c_str());
692 headers.push_back(list[i].second.c_str());
694 d->load(request.getUrlRef().c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, headers.empty() ? 0 : &headers[0], headers.size(), false, false, true, "", request.getSuggestedSaveName().c_str());
697 void WebPagePrivate::loadString(const char* string, const char* baseURL, const char* contentType, const char* failingURL)
699 KURL kurl = parseUrl(baseURL);
700 ResourceRequest request(kurl);
701 WTF::RefPtr<SharedBuffer> buffer
702 = SharedBuffer::create(string, strlen(string));
703 SubstituteData substituteData(buffer,
704 extractMIMETypeFromMediaType(contentType),
705 extractCharsetFromMediaType(contentType),
706 failingURL ? parseUrl(failingURL) : KURL());
707 m_mainFrame->loader()->load(request, substituteData, false);
710 void WebPage::loadString(const char* string, const char* baseURL, const char* mimeType, const char* failingURL)
712 d->loadString(string, baseURL, mimeType, failingURL);
715 bool WebPagePrivate::executeJavaScript(const char* scriptUTF8, JavaScriptDataType& returnType, WebString& returnValue)
717 String script = String::fromUTF8(scriptUTF8);
719 if (script.isNull()) {
720 returnType = JSException;
724 if (script.isEmpty()) {
725 returnType = JSUndefined;
729 ScriptValue result = m_mainFrame->script()->executeScript(script, false);
730 JSC::JSValue value = result.jsValue();
732 returnType = JSException;
736 JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
737 JSGlobalContextRef context = toGlobalRef(exec);
739 JSType type = JSValueGetType(context, toRef(exec, value));
746 returnType = JSBoolean;
749 returnType = JSNumber;
752 returnType = JSString;
755 returnType = JSObject;
757 case kJSTypeUndefined:
759 returnType = JSUndefined;
763 if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
764 String str = result.toString(exec);
765 returnValue = WebString(str.impl());
771 bool WebPage::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
773 return d->executeJavaScript(script, returnType, returnValue);
776 bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& sourceCode, JavaScriptDataType& returnType, WebString& returnValue)
778 if (!m_isolatedWorld)
779 m_isolatedWorld = m_mainFrame->script()->createWorld();
781 // Use evaluateInWorld to avoid canExecuteScripts check.
782 ScriptValue result = m_mainFrame->script()->evaluateInWorld(sourceCode, m_isolatedWorld.get());
783 JSC::JSValue value = result.jsValue();
785 returnType = JSException;
789 JSC::ExecState* exec = m_mainFrame->script()->globalObject(m_isolatedWorld.get())->globalExec();
790 JSGlobalContextRef context = toGlobalRef(exec);
792 JSType type = JSValueGetType(context, toRef(exec, value));
799 returnType = JSBoolean;
802 returnType = JSNumber;
805 returnType = JSString;
808 returnType = JSObject;
810 case kJSTypeUndefined:
812 returnType = JSUndefined;
816 if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
817 String str = result.toString(exec);
818 returnValue = WebString(str.impl());
824 bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, WebString& returnValue)
826 // On our platform wchar_t is unsigned int and UChar is unsigned short
827 // so we have to convert using ICU conversion function
828 int lengthCopied = 0;
829 UErrorCode error = U_ZERO_ERROR;
830 const int length = script.length() + 1 /*null termination char*/;
833 // FIXME: PR 138162 is giving U_INVALID_CHAR_FOUND error.
834 u_strFromUTF32(data, length, &lengthCopied, reinterpret_cast<const UChar32*>(script.c_str()), script.length(), &error);
835 BLACKBERRY_ASSERT(error == U_ZERO_ERROR);
836 if (error != U_ZERO_ERROR) {
837 Platform::logAlways(Platform::LogLevelCritical, "WebPage::executeJavaScriptInIsolatedWorld failed to convert UTF16 to JavaScript!");
840 String str = String(data, lengthCopied);
841 ScriptSourceCode sourceCode(str, KURL());
842 return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
845 bool WebPage::executeJavaScriptInIsolatedWorld(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
847 ScriptSourceCode sourceCode(String::fromUTF8(script), KURL());
848 return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
851 void WebPage::executeJavaScriptFunction(const std::vector<std::string> &function, const std::vector<JavaScriptVariant> &args, JavaScriptVariant& returnValue)
853 if (!d->m_mainFrame) {
854 returnValue.setType(JavaScriptVariant::Exception);
858 JSC::Bindings::RootObject* root = d->m_mainFrame->script()->bindingRootObject();
860 returnValue.setType(JavaScriptVariant::Exception);
864 JSC::ExecState* exec = root->globalObject()->globalExec();
865 JSGlobalContextRef ctx = toGlobalRef(exec);
867 WTF::Vector<JSValueRef> argListRef(args.size());
868 for (unsigned i = 0; i < args.size(); ++i)
869 argListRef[i] = BlackBerryJavaScriptVariantToJSValueRef(ctx, args[i]);
871 JSValueRef windowObjectValue = windowObject();
872 JSObjectRef obj = JSValueToObject(ctx, windowObjectValue, 0);
873 JSObjectRef thisObject = obj;
874 for (unsigned i = 0; i < function.size(); ++i) {
875 JSStringRef str = JSStringCreateWithUTF8CString(function[i].c_str());
877 obj = JSValueToObject(ctx, JSObjectGetProperty(ctx, obj, str, 0), 0);
878 JSStringRelease(str);
883 JSObjectRef functionObject = obj;
884 JSValueRef result = 0;
885 if (functionObject && thisObject)
886 result = JSObjectCallAsFunction(ctx, functionObject, thisObject, args.size(), argListRef.data(), 0);
889 returnValue.setType(JavaScriptVariant::Exception);
893 returnValue = JSValueRefToBlackBerryJavaScriptVariant(ctx, result);
896 void WebPagePrivate::stopCurrentLoad()
898 // This function should contain all common code triggered by WebPage::load
899 // (which stops any load in progress before starting the new load) and
900 // WebPage::stoploading (the entry point for the client to stop the load
901 // explicitly). If it should only be done while stopping the load
902 // explicitly, it goes in WebPage::stopLoading, not here.
903 m_mainFrame->loader()->stopAllLoaders();
905 // Cancel any deferred script that hasn't been processed yet.
906 DeferredTaskLoadManualScript::finishOrCancel(this);
909 void WebPage::stopLoading()
911 d->stopCurrentLoad();
914 static void closeURLRecursively(Frame* frame)
916 // Do not create more frame please.
917 FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client());
918 frameLoaderClient->suppressChildFrameCreation();
920 frame->loader()->closeURL();
922 Vector<RefPtr<Frame>, 10> childFrames;
924 for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
925 childFrames.append(childFrame);
927 unsigned size = childFrames.size();
928 for (unsigned i = 0; i < size; i++)
929 closeURLRecursively(childFrames[i].get());
932 void WebPagePrivate::prepareToDestroy()
934 // Before the client starts tearing itself down, dispatch the unload event
935 // so it can take effect while all the client's state (e.g. scroll position)
937 closeURLRecursively(m_mainFrame);
940 void WebPage::prepareToDestroy()
942 d->prepareToDestroy();
945 bool WebPage::dispatchBeforeUnloadEvent()
947 return d->m_page->mainFrame()->loader()->shouldClose();
950 static void enableCrossSiteXHRRecursively(Frame* frame)
952 frame->document()->securityOrigin()->grantUniversalAccess();
954 Vector<RefPtr<Frame>, 10> childFrames;
955 for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
956 childFrames.append(childFrame);
958 unsigned size = childFrames.size();
959 for (unsigned i = 0; i < size; i++)
960 enableCrossSiteXHRRecursively(childFrames[i].get());
963 void WebPagePrivate::enableCrossSiteXHR()
965 enableCrossSiteXHRRecursively(m_mainFrame);
968 void WebPage::enableCrossSiteXHR()
970 d->enableCrossSiteXHR();
973 void WebPagePrivate::addOriginAccessWhitelistEntry(const char* sourceOrigin, const char* destinationOrigin, bool allowDestinationSubdomains)
975 RefPtr<SecurityOrigin> source = SecurityOrigin::createFromString(sourceOrigin);
976 if (source->isUnique())
979 KURL destination(KURL(), destinationOrigin);
980 SecurityPolicy::addOriginAccessWhitelistEntry(*source, destination.protocol(), destination.host(), allowDestinationSubdomains);
983 void WebPage::addOriginAccessWhitelistEntry(const char* sourceOrigin, const char* destinationOrigin, bool allowDestinationSubdomains)
985 d->addOriginAccessWhitelistEntry(sourceOrigin, destinationOrigin, allowDestinationSubdomains);
988 void WebPagePrivate::removeOriginAccessWhitelistEntry(const char* sourceOrigin, const char* destinationOrigin, bool allowDestinationSubdomains)
990 RefPtr<SecurityOrigin> source = SecurityOrigin::createFromString(sourceOrigin);
991 if (source->isUnique())
994 KURL destination(KURL(), destinationOrigin);
995 SecurityPolicy::removeOriginAccessWhitelistEntry(*source, destination.protocol(), destination.host(), allowDestinationSubdomains);
998 void WebPage::removeOriginAccessWhitelistEntry(const char* sourceOrigin, const char* destinationOrigin, bool allowDestinationSubdomains)
1000 d->removeOriginAccessWhitelistEntry(sourceOrigin, destinationOrigin, allowDestinationSubdomains);
1003 void WebPagePrivate::setLoadState(LoadState state)
1005 if (m_loadState == state)
1008 bool isFirstLoad = m_loadState == None;
1010 // See RIM Bug #1068.
1011 if (state == Finished && m_mainFrame && m_mainFrame->document())
1012 m_mainFrame->document()->updateStyleIfNeeded();
1014 m_loadState = state;
1016 #if DEBUG_WEBPAGE_LOAD
1017 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state);
1020 switch (m_loadState) {
1023 // Paints the visible backingstore as white to prevent initial checkerboard on
1025 if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
1026 m_backingStore->d->blitVisibleContents();
1031 unscheduleZoomAboutPoint();
1033 #if ENABLE(ACCELERATED_2D_CANVAS)
1034 if (m_page->settings()->canvasUsesAcceleratedDrawing()) {
1035 // Free GPU resources as we're on a new page.
1036 // This will help us to free memory pressure.
1037 SharedGraphicsContext3D::get()->makeContextCurrent();
1038 GrContext* grContext = Platform::Graphics::getGrContext();
1039 grContext->freeGpuResources();
1043 #if USE(ACCELERATED_COMPOSITING)
1044 releaseLayerResources();
1047 // Suspend screen update to avoid ui thread blitting while resetting backingstore.
1048 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1050 m_previousContentsSize = IntSize();
1051 m_backingStore->d->resetRenderQueue();
1052 m_backingStore->d->resetTiles(true /* resetBackground */);
1053 m_backingStore->d->setScrollingOrZooming(false, false /* shouldBlit */);
1054 m_shouldZoomToInitialScaleAfterLoadFinished = false;
1055 m_userPerformedManualZoom = false;
1056 m_userPerformedManualScroll = false;
1057 m_shouldUseFixedDesktopMode = false;
1058 if (m_resetVirtualViewportOnCommitted) { // For DRT.
1059 m_virtualViewportWidth = 0;
1060 m_virtualViewportHeight = 0;
1062 if (m_webSettings->viewportWidth() > 0) {
1063 m_virtualViewportWidth = m_webSettings->viewportWidth();
1064 m_virtualViewportHeight = m_defaultLayoutSize.height();
1066 // Check if we have already process the meta viewport tag, this only happens on history navigation.
1067 // For back/forward history navigation, we should only keep these previous values if the document
1068 // has the meta viewport tag when the state is Committed in setLoadState.
1069 // Refreshing should keep these previous values as well.
1070 static ViewportArguments defaultViewportArguments;
1071 bool documentHasViewportArguments = false;
1072 FrameLoadType frameLoadType = FrameLoadTypeStandard;
1073 if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->viewportArguments() != defaultViewportArguments)
1074 documentHasViewportArguments = true;
1075 if (m_mainFrame && m_mainFrame->loader())
1076 frameLoadType = m_mainFrame->loader()->loadType();
1077 if (!((m_didRestoreFromPageCache && documentHasViewportArguments) || (frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin))) {
1078 m_viewportArguments = ViewportArguments();
1079 m_userScalable = m_webSettings->isUserScalable();
1082 // At the moment we commit a new load, set the viewport arguments
1083 // to any fallback values. If there is a meta viewport in the
1084 // content it will overwrite the fallback arguments soon.
1085 dispatchViewportPropertiesDidChange(m_userViewportArguments);
1087 IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
1088 m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
1091 #if ENABLE(EVENT_MODE_METATAGS)
1092 didReceiveCursorEventMode(ProcessedCursorEvents);
1093 didReceiveTouchEventMode(ProcessedTouchEvents);
1096 // Reset block zoom and reflow.
1098 #if ENABLE(VIEWPORT_REFLOW)
1099 toggleTextReflowIfEnabledForBlockZoomOnly();
1102 // Notify InputHandler of state change.
1103 m_inputHandler->setInputModeEnabled(false);
1105 // Set the scroll to origin here and notify the client since we'll be
1106 // zooming below without any real contents yet thus the contents size
1107 // we report to the client could make our current scroll position invalid.
1108 setScrollPosition(IntPoint::zero());
1109 notifyTransformedScrollChanged();
1111 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1113 // Paints the visible backingstore as white. Note it is important we do
1114 // this strictly after re-setting the scroll position to origin and resetting
1115 // the scales otherwise the visible contents calculation is wrong and we
1116 // can end up blitting artifacts instead. See: RIM Bug #401.
1117 if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
1118 m_backingStore->d->blitVisibleContents();
1120 zoomToInitialScaleOnLoad();
1122 // Update cursor status.
1125 #if USE(ACCELERATED_COMPOSITING)
1126 // Don't render compositing contents from previous page.
1127 resetCompositingSurface();
1133 // Notify client of the initial zoom change.
1134 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1135 m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
1142 double WebPagePrivate::clampedScale(double scale) const
1144 if (scale < minimumScale())
1145 return minimumScale();
1146 if (scale > maximumScale())
1147 return maximumScale();
1151 bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale)
1153 if (!m_mainFrame->view())
1156 if (enforceScaleClamping)
1157 scale = this->clampedScale(scale);
1159 ASSERT(clampedScale);
1160 *clampedScale = scale;
1162 if (currentScale() == scale) {
1163 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1170 bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel)
1172 if (!isRestoringZoomLevel) {
1173 // Clear any existing block zoom. (If we are restoring a saved zoom level on page load,
1174 // there is guaranteed to be no existing block zoom and we don't want to clear m_shouldReflowBlock.)
1178 // The reflow and block zoom stuff here needs to happen regardless of
1179 // whether we shouldZoomAboutPoint.
1180 #if ENABLE(VIEWPORT_REFLOW)
1181 toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
1182 if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view())
1187 if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1188 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1189 m_currentPinchZoomNode = 0;
1190 m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1194 TransformationMatrix zoom;
1197 #if DEBUG_WEBPAGE_LOAD
1198 if (loadState() < Finished)
1199 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomAboutPoint scale %f anchor (%f, %f)", scale, anchor.x(), anchor.y());
1202 // Our current scroll position in float.
1203 FloatPoint scrollPosition = this->scrollPosition();
1205 // Anchor offset from scroll position in float.
1206 FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y());
1208 // The horizontal scaling factor and vertical scaling factor should be equal
1209 // to preserve aspect ratio of content.
1210 ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22());
1212 // Need to invert the previous transform to anchor the viewport.
1213 double inverseScale = scale / m_transformationMatrix->m11();
1216 *m_transformationMatrix = zoom;
1218 // Suspend all screen updates to the backingstore.
1219 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1221 updateViewportSize();
1223 IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))),
1224 max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale)))));
1226 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1227 // This is a hack for email which has reflow always turned on.
1228 m_mainFrame->view()->setNeedsLayout();
1229 requestLayoutIfNeeded();
1230 if (m_currentPinchZoomNode)
1231 newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale);
1232 m_currentPinchZoomNode = 0;
1233 m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1236 setScrollPosition(newScrollPosition);
1238 notifyTransformChanged();
1240 bool isLoading = this->isLoading();
1242 // We need to invalidate all tiles both visible and non-visible if we're loading.
1243 m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */);
1245 m_client->resetBitmapZoomScale(m_transformationMatrix->m11());
1247 bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering;
1248 bool shouldClearVisibleZoom = isLoading && shouldRender;
1250 if (shouldClearVisibleZoom) {
1251 // If we are loading and rendering then we need to clear the render queue's
1252 // visible zoom jobs as they will be irrelevant with the render below.
1253 m_backingStore->d->clearVisibleZoom();
1256 // Clear window to make sure there are no artifacts.
1258 // Resume all screen updates to the backingstore and render+blit visible contents to screen.
1259 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
1261 // Resume all screen updates to the backingstore but do not blit to the screen because we not rendering.
1262 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1265 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1270 IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale)
1272 // Should only be invoked when text reflow is enabled.
1273 ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
1278 IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
1280 if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) {
1281 offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y();
1282 if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0)
1283 offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale;
1286 IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get());
1288 return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))),
1289 max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale))));
1292 bool WebPagePrivate::scheduleZoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering)
1295 if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1296 // We could be back to the right zoom level before the timer has
1297 // timed out, because of wiggling back and forth. Stop the timer.
1298 unscheduleZoomAboutPoint();
1302 // For some reason, the bitmap zoom wants an anchor in backingstore coordinates!
1303 // this is different from zoomAboutPoint, which wants content coordinates.
1304 // See RIM Bug #641.
1306 FloatPoint transformedAnchor = mapToTransformedFloatPoint(anchor);
1307 FloatPoint transformedScrollPosition = mapToTransformedFloatPoint(scrollPosition());
1309 // Prohibit backingstore from updating the window overtop of the bitmap.
1310 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1312 // Need to invert the previous transform to anchor the viewport.
1313 double zoomFraction = scale / transformationMatrix()->m11();
1315 // Anchor offset from scroll position in float.
1316 FloatPoint anchorOffset(transformedAnchor.x() - transformedScrollPosition.x(),
1317 transformedAnchor.y() - transformedScrollPosition.y());
1320 static_cast<int>(roundf(transformedAnchor.x() - anchorOffset.x() / zoomFraction)),
1321 static_cast<int>(roundf(transformedAnchor.y() - anchorOffset.y() / zoomFraction)));
1323 const IntRect viewportRect = IntRect(IntPoint::zero(), transformedViewportSize());
1324 const IntRect dstRect = viewportRect;
1326 // This is the rect to pass as the actual source rect in the backingstore
1327 // for the transform given by zoom.
1328 IntRect srcRect(srcPoint.x(),
1330 viewportRect.width() / zoomFraction,
1331 viewportRect.height() / zoomFraction);
1332 m_backingStore->d->blitContents(dstRect, srcRect);
1334 m_delayedZoomArguments.scale = scale;
1335 m_delayedZoomArguments.anchor = anchor;
1336 m_delayedZoomArguments.enforceScaleClamping = enforceScaleClamping;
1337 m_delayedZoomArguments.forceRendering = forceRendering;
1338 m_delayedZoomTimer->startOneShot(delayedZoomInterval);
1343 void WebPagePrivate::unscheduleZoomAboutPoint()
1345 if (m_delayedZoomTimer->isActive())
1346 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1348 m_delayedZoomTimer->stop();
1351 void WebPagePrivate::zoomAboutPointTimerFired(Timer<WebPagePrivate>*)
1353 zoomAboutPoint(m_delayedZoomArguments.scale, m_delayedZoomArguments.anchor, m_delayedZoomArguments.enforceScaleClamping, m_delayedZoomArguments.forceRendering);
1354 m_backingStore->d->resumeScreenAndBackingStoreUpdates(m_delayedZoomArguments.forceRendering ? BackingStore::RenderAndBlit : BackingStore::None);
1357 void WebPagePrivate::setNeedsLayout()
1359 FrameView* view = m_mainFrame->view();
1361 view->setNeedsLayout();
1364 void WebPagePrivate::requestLayoutIfNeeded() const
1366 FrameView* view = m_mainFrame->view();
1368 view->updateLayoutAndStyleIfNeededRecursive();
1369 ASSERT(!view->needsLayout());
1372 IntPoint WebPagePrivate::scrollPosition() const
1374 return m_backingStoreClient->scrollPosition();
1377 IntPoint WebPagePrivate::maximumScrollPosition() const
1379 return m_backingStoreClient->maximumScrollPosition();
1382 void WebPagePrivate::setScrollPosition(const IntPoint& pos)
1384 m_backingStoreClient->setScrollPosition(pos);
1387 // Setting the scroll position is in transformed coordinates.
1388 void WebPage::setScrollPosition(const Platform::IntPoint& point)
1390 if (d->transformedPointEqualsUntransformedPoint(point, d->scrollPosition()))
1393 // If the user recently performed an event, this new scroll position
1394 // could possibly be a result of that. Or not, this is just a heuristic.
1395 if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
1396 d->m_userPerformedManualScroll = true;
1398 d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1400 // UI thread can call BackingStorePrivate::setScrollingOrZooming(false) before WebKit thread calls WebPage::setScrollPosition(),
1401 // in which case it will set ScrollableArea::m_constrainsScrollingToContentEdge to true earlier.
1402 // We can cache ScrollableArea::m_constrainsScrollingToContentEdge and always set it to false before we set scroll position in
1403 // WebKit thread to avoid scroll position clamping during scrolling, and restore it to what it was after that.
1404 bool constrainsScrollingToContentEdge = d->m_mainFrame->view()->constrainsScrollingToContentEdge();
1405 d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(false);
1406 d->setScrollPosition(d->mapFromTransformed(point));
1407 d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge);
1409 d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1412 bool WebPagePrivate::shouldSendResizeEvent()
1414 if (!m_mainFrame->document())
1417 // PR#96865 : Provide an option to always send resize events, regardless of the loading
1418 // status. The scenario for this are Sapphire applications which tend to
1419 // maintain an open GET request to the server. This open GET results in
1420 // webkit thinking that content is still arriving when at the application
1421 // level it is considered fully loaded.
1423 // NOTE: Care must be exercised in the use of this option, as it bypasses
1424 // the sanity provided in 'isLoadingInAPISense()' below.
1426 static const bool unrestrictedResizeEvents = Platform::Settings::instance()->unrestrictedResizeEvents();
1427 if (unrestrictedResizeEvents)
1430 // Don't send the resize event if the document is loading. Some pages automatically reload
1431 // when the window is resized; Safari on iPhone often resizes the window while setting up its
1432 // viewport. This obviously can cause problems.
1433 DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
1434 if (documentLoader && documentLoader->isLoadingInAPISense())
1440 void WebPagePrivate::willDeferLoading()
1442 m_deferredTasksTimer.stop();
1443 m_client->willDeferLoading();
1446 void WebPagePrivate::didResumeLoading()
1448 if (!m_deferredTasks.isEmpty())
1449 m_deferredTasksTimer.startOneShot(0);
1450 m_client->didResumeLoading();
1453 void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*)
1455 ASSERT(!m_deferredTasks.isEmpty());
1456 if (!m_deferredTasks.isEmpty())
1459 OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release();
1460 m_deferredTasks.remove(0);
1462 if (!m_deferredTasks.isEmpty())
1463 m_deferredTasksTimer.startOneShot(0);
1465 task->perform(this);
1468 bool WebPagePrivate::scrollBy(int deltaX, int deltaY, bool scrollMainFrame)
1470 IntSize delta(deltaX, deltaY);
1471 if (!scrollMainFrame) {
1472 // We need to work around the fact that ::map{To,From}Transformed do not
1473 // work well with negative values, like a negative width or height of an IntSize.
1474 IntSize copiedDelta(IntSize(abs(delta.width()), abs(delta.height())));
1475 IntSize untransformedCopiedDelta = mapFromTransformed(copiedDelta);
1477 delta.width() < 0 ? -untransformedCopiedDelta.width() : untransformedCopiedDelta.width(),
1478 delta.height() < 0 ? -untransformedCopiedDelta.height(): untransformedCopiedDelta.height());
1480 if (m_inRegionScroller->d->scrollBy(delta)) {
1481 m_selectionHandler->selectionPositionChanged();
1482 // FIXME: We have code in place to handle scrolling and clipping tap highlight
1483 // on in-region scrolling. As soon as it is fast enough (i.e. we have it backed by
1484 // a backing store), we can reliably make use of it in the real world.
1485 // m_touchEventHandler->drawTapHighlight();
1492 setScrollPosition(scrollPosition() + delta);
1496 bool WebPage::scrollBy(const Platform::IntSize& delta, bool scrollMainFrame)
1498 d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1499 bool b = d->scrollBy(delta.width(), delta.height(), scrollMainFrame);
1500 d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1504 void WebPagePrivate::notifyInRegionScrollStatusChanged(bool status)
1506 if (!status && m_inRegionScroller->d->hasNode()) {
1507 enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(m_inRegionScroller->d->node());
1508 m_inRegionScroller->d->reset();
1512 void WebPage::notifyInRegionScrollStatusChanged(bool status)
1514 d->notifyInRegionScrollStatusChanged(status);
1517 void WebPagePrivate::enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(Node* scrolledNode)
1519 ASSERT(scrolledNode);
1520 if (scrolledNode->isDocumentNode()) {
1521 Frame* frame = static_cast<const Document*>(scrolledNode)->frame();
1525 ASSERT(frame != m_mainFrame);
1526 FrameView* view = frame->view();
1531 // #1 - Get frame rect in contents coords.
1532 // #2 - Get the clipped scrollview rect in contents coords.
1533 // #3 - Take transform into account for 1 and 2.
1534 // #4 - Subtract 2 from 1, so we know exactly which areas of the frame
1535 // are offscreen, and need async repainting.
1536 FrameView* mainFrameView = m_mainFrame->view();
1537 ASSERT(mainFrameView);
1538 IntRect frameRect = view->frameRect();
1539 frameRect = frame->tree()->parent()->view()->contentsToWindow(frameRect);
1540 frameRect = mainFrameView->windowToContents(frameRect);
1542 IntRect visibleWindowRect = getRecursiveVisibleWindowRect(view);
1543 IntRect visibleContentsRect = mainFrameView->windowToContents(visibleWindowRect);
1545 IntRect transformedFrameRect = mapToTransformed(frameRect);
1546 IntRect transformedVisibleContentsRect = mapToTransformed(visibleContentsRect);
1548 Platform::IntRectRegion offscreenRegionOfIframe
1549 = Platform::IntRectRegion::subtractRegions(Platform::IntRect(transformedFrameRect), Platform::IntRect(transformedVisibleContentsRect));
1551 if (!offscreenRegionOfIframe.isEmpty())
1552 m_backingStore->d->m_renderQueue->addToQueue(RenderQueue::RegularRender, offscreenRegionOfIframe.rects());
1556 void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
1558 if (b != m_hasInRegionScrollableAreas)
1559 m_hasInRegionScrollableAreas = b;
1562 IntSize WebPagePrivate::viewportSize() const
1564 return mapFromTransformed(transformedViewportSize());
1567 IntSize WebPagePrivate::actualVisibleSize() const
1569 return mapFromTransformed(transformedActualVisibleSize());
1572 bool WebPagePrivate::hasVirtualViewport() const
1574 return m_virtualViewportWidth && m_virtualViewportHeight;
1577 void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
1579 ASSERT(m_mainFrame->view());
1580 if (setFixedReportedSize)
1581 m_mainFrame->view()->setFixedReportedSize(actualVisibleSize());
1583 IntRect frameRect = IntRect(scrollPosition(), viewportSize());
1584 if (frameRect != m_mainFrame->view()->frameRect()) {
1585 m_mainFrame->view()->setFrameRect(frameRect);
1586 m_mainFrame->view()->adjustViewSize();
1588 #if ENABLE(FULLSCREEN_API)
1589 // If we are in fullscreen video mode, and we change the FrameView::viewportRect,
1590 // we need to adjust the media container to the new size.
1591 if (m_fullscreenVideoNode) {
1592 Document* document = m_fullscreenVideoNode->document();
1594 ASSERT(document->fullScreenRenderer());
1596 int width = m_mainFrame->view()->visibleContentRect().size().width();
1597 document->fullScreenRenderer()->style()->setWidth(Length(width, Fixed));
1602 // We're going to need to send a resize event to JavaScript because
1603 // innerWidth and innerHeight depend on fixed reported size.
1604 // This is how we support mobile pages where JavaScript resizes
1605 // the page in order to get around the fixed layout size, e.g.
1606 // google maps when it detects a mobile user agent.
1607 if (sendResizeEvent && shouldSendResizeEvent())
1608 m_mainFrame->eventHandler()->sendResizeEvent();
1610 // When the actual visible size changes, we also
1611 // need to reposition fixed elements.
1612 m_mainFrame->view()->repaintFixedElementsAfterScrolling();
1615 FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
1617 // The visible contents rect in float.
1618 FloatRect visibleContentsRect = this->visibleContentsRect();
1620 // The center of the visible contents rect in float.
1621 return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
1622 visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
1625 IntRect WebPagePrivate::visibleContentsRect() const
1627 return m_backingStoreClient->visibleContentsRect();
1630 IntSize WebPagePrivate::contentsSize() const
1632 if (!m_mainFrame->view())
1635 return m_backingStoreClient->contentsSize();
1638 IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
1640 if (!m_mainFrame->contentRenderer())
1643 return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
1646 void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
1648 if (m_previousContentsSize == contentsSize)
1651 // This should only occur in the middle of layout so we set a flag here and
1652 // handle it at the end of the layout.
1653 m_contentsSizeChanged = true;
1655 #if DEBUG_WEBPAGE_LOAD
1656 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %dx%d", contentsSize.width(), contentsSize.height());
1660 void WebPagePrivate::layoutFinished()
1662 if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
1665 m_contentsSizeChanged = false; // Toggle to turn off notification again.
1666 m_overflowExceedsContentsSize = false;
1668 if (contentsSize().isEmpty())
1671 // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from
1672 // the middle of a layout, but the recursion is limited by detection code in
1673 // setViewMode() and mitigation code in fixedLayoutSize().
1674 if (didLayoutExceedMaximumIterations()) {
1675 notifyTransformedContentsSizeChanged();
1679 // Temporarily save the m_previousContentsSize here before updating it (in
1680 // notifyTransformedContentsSizeChanged()) so we can compare if our contents
1681 // shrunk afterwards.
1682 IntSize previousContentsSize = m_previousContentsSize;
1684 m_nestedLayoutFinishedCount++;
1686 if (shouldZoomToInitialScaleOnLoad()) {
1687 zoomToInitialScaleOnLoad();
1688 m_shouldZoomToInitialScaleAfterLoadFinished = false;
1689 } else if (loadState() != None)
1690 notifyTransformedContentsSizeChanged();
1692 m_nestedLayoutFinishedCount--;
1694 if (!m_nestedLayoutFinishedCount) {
1695 // When the contents shrinks, there is a risk that we
1696 // will be left at a scroll position that lies outside of the
1697 // contents rect. Since we allow overscrolling and neglect
1698 // to clamp overscroll in order to retain input focus (RIM Bug #414)
1699 // we need to clamp somewhere, and this is where we know the
1700 // contents size has changed.
1702 if (contentsSize() != previousContentsSize) {
1704 IntPoint newScrollPosition = scrollPosition();
1706 if (contentsSize().height() < previousContentsSize.height()) {
1707 IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
1708 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
1711 if (contentsSize().width() < previousContentsSize.width()) {
1712 IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
1713 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
1716 if (newScrollPosition != scrollPosition()) {
1717 setScrollPosition(newScrollPosition);
1718 notifyTransformedScrollChanged();
1724 void WebPagePrivate::zoomToInitialScaleOnLoad()
1726 #if DEBUG_WEBPAGE_LOAD
1727 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
1730 bool needsLayout = false;
1732 // If the contents width exceeds the viewport width set to desktop mode.
1733 if (m_shouldUseFixedDesktopMode)
1734 needsLayout = setViewMode(FixedDesktop);
1736 needsLayout = setViewMode(Desktop);
1739 // This can cause recursive layout...
1743 if (contentsSize().isEmpty()) {
1744 #if DEBUG_WEBPAGE_LOAD
1745 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
1747 requestLayoutIfNeeded();
1748 m_client->resetBitmapZoomScale(currentScale());
1749 notifyTransformedContentsSizeChanged();
1753 bool performedZoom = false;
1754 bool shouldZoom = !m_userPerformedManualZoom;
1756 // If this load should restore view state, don't zoom to initial scale
1757 // but instead let the HistoryItem's saved viewport reign supreme.
1758 if (m_mainFrame && m_mainFrame->loader() && m_mainFrame->loader()->shouldRestoreScrollPositionAndViewState())
1761 if (shouldZoom && shouldZoomToInitialScaleOnLoad()) {
1762 // Preserve at top and at left position, to avoid scrolling
1763 // to a non top-left position for web page with viewport meta tag
1764 // that specifies an initial-scale that is zoomed in.
1765 FloatPoint anchor = centerOfVisibleContentsRect();
1766 if (!scrollPosition().x())
1768 if (!scrollPosition().y())
1770 performedZoom = zoomAboutPoint(initialScale(), anchor);
1773 // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout...
1774 requestLayoutIfNeeded();
1776 if (!performedZoom) {
1777 // We only notify if we didn't perform zoom, because zoom will notify on
1779 m_client->resetBitmapZoomScale(currentScale());
1780 notifyTransformedContentsSizeChanged();
1784 double WebPagePrivate::zoomToFitScale() const
1786 int contentWidth = contentsSize().width();
1787 int contentHeight = contentsSize().height();
1788 double zoomToFitScale = contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
1789 if (contentHeight * zoomToFitScale < static_cast<double>(m_defaultLayoutSize.height()))
1790 zoomToFitScale = contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
1792 return std::max(zoomToFitScale, minimumZoomToFitScale);
1795 double WebPage::zoomToFitScale() const
1797 return d->zoomToFitScale();
1800 double WebPagePrivate::initialScale() const
1802 if (m_initialScale > 0.0)
1803 return m_initialScale;
1805 if (m_webSettings->isZoomToFitOnLoad())
1806 return zoomToFitScale();
1811 double WebPage::initialScale() const
1813 return d->initialScale();
1816 void WebPage::initializeIconDataBase()
1818 IconDatabaseClientBlackBerry::getInstance()->initIconDatabase(d->m_webSettings);
1821 bool WebPage::isUserScalable() const
1823 return d->isUserScalable();
1826 void WebPage::setUserScalable(bool userScalable)
1828 d->setUserScalable(userScalable);
1831 double WebPage::currentScale() const
1833 return d->currentScale();
1836 void WebPage::setInitialScale(double initialScale)
1838 d->setInitialScale(initialScale);
1841 double WebPage::minimumScale() const
1843 return d->minimumScale();
1846 void WebPage::setMinimumScale(double minimumScale)
1848 d->setMinimumScale(minimumScale);
1851 void WebPage::setMaximumScale(double maximumScale)
1853 d->setMaximumScale(maximumScale);
1856 double WebPagePrivate::maximumScale() const
1858 if (m_maximumScale >= zoomToFitScale() && m_maximumScale >= m_minimumScale)
1859 return m_maximumScale;
1861 return hasVirtualViewport() ? std::max<double>(zoomToFitScale(), 4.0) : 4.0;
1864 double WebPage::maximumScale() const
1866 return d->maximumScale();
1869 void WebPagePrivate::resetScales()
1871 TransformationMatrix identity;
1872 *m_transformationMatrix = identity;
1873 m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0;
1874 m_minimumScale = -1.0;
1875 m_maximumScale = -1.0;
1877 // We have to let WebCore know about updated framerect now that we've
1878 // reset our scales. See: RIM Bug #401.
1879 updateViewportSize();
1882 IntPoint WebPagePrivate::transformedScrollPosition() const
1884 return m_backingStoreClient->transformedScrollPosition();
1887 // Returned scroll position is in transformed coordinates.
1888 Platform::IntPoint WebPage::scrollPosition() const
1890 return d->transformedScrollPosition();
1893 IntPoint WebPagePrivate::transformedMaximumScrollPosition() const
1895 return m_backingStoreClient->transformedMaximumScrollPosition();
1898 IntSize WebPagePrivate::transformedActualVisibleSize() const
1900 return IntSize(m_actualVisibleWidth, m_actualVisibleHeight);
1903 Platform::IntSize WebPage::viewportSize() const
1905 return d->transformedActualVisibleSize();
1908 IntSize WebPagePrivate::transformedViewportSize() const
1910 return Platform::Graphics::Screen::primaryScreen()->size();
1913 IntRect WebPagePrivate::transformedVisibleContentsRect() const
1915 // Usually this would be mapToTransformed(visibleContentsRect()), but
1916 // that results in rounding errors because we already set the WebCore
1917 // viewport size from our original transformedViewportSize().
1918 // Instead, we only transform the scroll position and take the
1919 // viewport size as it is, which ensures that e.g. blitting operations
1920 // always cover the whole widget/screen.
1921 return IntRect(transformedScrollPosition(), transformedViewportSize());
1924 IntSize WebPagePrivate::transformedContentsSize() const
1926 // mapToTransformed() functions use this method to crop their results,
1927 // so we can't make use of them here. While we want rounding inside page
1928 // boundaries to extend rectangles and round points, we need to crop the
1929 // contents size to the floored values so that we don't try to display
1930 // or report points that are not fully covered by the actual float-point
1931 // contents rectangle.
1932 const IntSize untransformedContentsSize = contentsSize();
1933 const FloatPoint transformedBottomRight = m_transformationMatrix->mapPoint(
1934 FloatPoint(untransformedContentsSize.width(), untransformedContentsSize.height()));
1935 return IntSize(floorf(transformedBottomRight.x()), floorf(transformedBottomRight.y()));
1938 IntPoint WebPagePrivate::mapFromContentsToViewport(const IntPoint& point) const
1940 return m_backingStoreClient->mapFromContentsToViewport(point);
1943 IntPoint WebPagePrivate::mapFromViewportToContents(const IntPoint& point) const
1945 return m_backingStoreClient->mapFromViewportToContents(point);
1948 IntRect WebPagePrivate::mapFromContentsToViewport(const IntRect& rect) const
1950 return m_backingStoreClient->mapFromContentsToViewport(rect);
1953 IntRect WebPagePrivate::mapFromViewportToContents(const IntRect& rect) const
1955 return m_backingStoreClient->mapFromViewportToContents(rect);
1958 IntPoint WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntPoint& point) const
1960 return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(point);
1963 IntPoint WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntPoint& point) const
1965 return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(point);
1968 IntRect WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntRect& rect) const
1970 return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(rect);
1973 IntRect WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntRect& rect) const
1975 return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(rect);
1978 // NOTE: PIXEL ROUNDING!
1979 // Accurate back-and-forth rounding is not possible with information loss
1980 // by integer points and sizes, so we always expand the resulting mapped
1981 // float rectangles to the nearest integer. For points, we always use
1982 // floor-rounding in mapToTransformed() so that we don't have to crop to
1983 // the (floor'd) transformed contents size.
1984 static inline IntPoint roundTransformedPoint(const FloatPoint &point)
1986 // Maps by rounding half towards zero.
1987 return IntPoint(static_cast<int>(floorf(point.x())), static_cast<int>(floorf(point.y())));
1990 static inline IntPoint roundUntransformedPoint(const FloatPoint &point)
1992 // Maps by rounding half away from zero.
1993 return IntPoint(static_cast<int>(ceilf(point.x())), static_cast<int>(ceilf(point.y())));
1996 IntPoint WebPagePrivate::mapToTransformed(const IntPoint& point) const
1998 return roundTransformedPoint(m_transformationMatrix->mapPoint(FloatPoint(point)));
2001 FloatPoint WebPagePrivate::mapToTransformedFloatPoint(const FloatPoint& point) const
2003 return m_transformationMatrix->mapPoint(point);
2006 IntPoint WebPagePrivate::mapFromTransformed(const IntPoint& point) const
2008 return roundUntransformedPoint(m_transformationMatrix->inverse().mapPoint(FloatPoint(point)));
2011 FloatPoint WebPagePrivate::mapFromTransformedFloatPoint(const FloatPoint& point) const
2013 return m_transformationMatrix->inverse().mapPoint(point);
2016 FloatRect WebPagePrivate::mapFromTransformedFloatRect(const FloatRect& rect) const
2018 return m_transformationMatrix->inverse().mapRect(rect);
2021 IntSize WebPagePrivate::mapToTransformed(const IntSize& size) const
2023 return mapToTransformed(IntRect(IntPoint::zero(), size)).size();
2026 IntSize WebPagePrivate::mapFromTransformed(const IntSize& size) const
2028 return mapFromTransformed(IntRect(IntPoint::zero(), size)).size();
2031 IntRect WebPagePrivate::mapToTransformed(const IntRect& rect) const
2033 return enclosingIntRect(m_transformationMatrix->mapRect(FloatRect(rect)));
2036 // Use this in conjunction with mapToTransformed(IntRect), in most cases.
2037 void WebPagePrivate::clipToTransformedContentsRect(IntRect& rect) const
2039 rect.intersect(IntRect(IntPoint::zero(), transformedContentsSize()));
2042 IntRect WebPagePrivate::mapFromTransformed(const IntRect& rect) const
2044 return enclosingIntRect(m_transformationMatrix->inverse().mapRect(FloatRect(rect)));
2047 bool WebPagePrivate::transformedPointEqualsUntransformedPoint(const IntPoint& transformedPoint, const IntPoint& untransformedPoint)
2049 // Scaling down is always more accurate than scaling up.
2050 if (m_transformationMatrix->a() > 1.0)
2051 return transformedPoint == mapToTransformed(untransformedPoint);
2053 return mapFromTransformed(transformedPoint) == untransformedPoint;
2056 void WebPagePrivate::notifyTransformChanged()
2058 notifyTransformedContentsSizeChanged();
2059 notifyTransformedScrollChanged();
2061 m_backingStore->d->transformChanged();
2064 void WebPagePrivate::notifyTransformedContentsSizeChanged()
2066 // We mark here as the last reported content size we sent to the client.
2067 m_previousContentsSize = contentsSize();
2069 const IntSize size = transformedContentsSize();
2070 m_backingStore->d->contentsSizeChanged(size);
2071 m_client->contentsSizeChanged(size);
2074 void WebPagePrivate::notifyTransformedScrollChanged()
2076 const IntPoint pos = transformedScrollPosition();
2077 m_backingStore->d->scrollChanged(pos);
2078 m_client->scrollChanged(pos);
2081 bool WebPagePrivate::setViewMode(ViewMode mode)
2083 if (!m_mainFrame->view())
2088 // If we're in the middle of a nested layout with a recursion count above
2089 // some maximum threshold, then our algorithm for finding the minimum content
2090 // width of a given page has become dependent on the visible width.
2092 // We need to find some method to ensure that we don't experience excessive
2093 // and even infinite recursion. This can even happen with valid html. The
2094 // former can happen when we run into inline text with few candidates for line
2095 // break. The latter can happen for instance if the page has a negative margin
2096 // set against the right border. Note: this is valid by spec and can lead to
2097 // a situation where there is no value for which the content width will ensure
2098 // no horizontal scrollbar.
2099 // Example: LayoutTests/css1/box_properties/margin.html
2101 // In order to address such situations when we detect a recursion above some
2102 // maximum threshold we snap our fixed layout size to a defined quantum increment.
2103 // Eventually, either the content width will be satisfied to ensure no horizontal
2104 // scrollbar or this increment will run into the maximum layout size and the
2105 // recursion will necessarily end.
2106 bool snapToIncrement = didLayoutExceedMaximumIterations();
2108 IntSize currentSize = m_mainFrame->view()->fixedLayoutSize();
2109 IntSize newSize = fixedLayoutSize(snapToIncrement);
2110 if (currentSize == newSize)
2113 // FIXME: Temp solution. We'll get back to this.
2114 if (m_nestedLayoutFinishedCount) {
2115 double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width());
2116 double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height());
2117 if (widthChange < 0.05 && heightChange < 0.05)
2121 m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
2122 m_mainFrame->view()->setFixedLayoutSize(newSize);
2123 return true; // Needs re-layout!
2126 void WebPagePrivate::setCursor(PlatformCursor handle)
2128 if (m_currentCursor.type() != handle.type()) {
2129 m_currentCursor = handle;
2130 m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot().x(), handle.hotspot().y());
2134 Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory()
2136 return m_client->networkStreamFactory();
2139 Platform::Graphics::Window* WebPagePrivate::platformWindow() const
2141 return m_client->window();
2144 void WebPagePrivate::setPreventsScreenDimming(bool keepAwake)
2147 if (!m_preventIdleDimmingCount)
2148 m_client->setPreventsScreenIdleDimming(true);
2149 m_preventIdleDimmingCount++;
2150 } else if (m_preventIdleDimmingCount > 0) {
2151 m_preventIdleDimmingCount--;
2152 if (!m_preventIdleDimmingCount)
2153 m_client->setPreventsScreenIdleDimming(false);
2155 ASSERT_NOT_REACHED(); // SetPreventsScreenIdleDimming(false) called too many times.
2158 void WebPagePrivate::showVirtualKeyboard(bool showKeyboard)
2160 m_client->showVirtualKeyboard(showKeyboard);
2163 void WebPagePrivate::ensureContentVisible(bool centerInView)
2165 m_inputHandler->ensureFocusElementVisible(centerInView);
2168 void WebPagePrivate::zoomToContentRect(const IntRect& rect)
2170 // Don't scale if the user is not supposed to scale.
2171 if (!isUserScalable())
2174 FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y());
2175 IntSize viewSize = viewportSize();
2177 // Calculate the scale required to scale that dimension to fit.
2178 double scaleH = (double)viewSize.width() / (double)rect.width();
2179 double scaleV = (double)viewSize.height() / (double)rect.height();
2181 // Choose the smaller scale factor so that all of the content is visible.
2182 zoomAboutPoint(min(scaleH, scaleV), anchor);
2185 void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister)
2188 m_pluginViews.add(plugin);
2190 m_pluginViews.remove(plugin);
2193 #define FOR_EACH_PLUGINVIEW(pluginViews) \
2194 HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \
2195 HashSet<PluginView*>::const_iterator last = pluginViews.end(); \
2196 for (; it != last; ++it)
2198 void WebPagePrivate::notifyPageOnLoad()
2200 FOR_EACH_PLUGINVIEW(m_pluginViews)
2201 (*it)->handleOnLoadEvent();
2204 bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2206 return m_client->shouldPluginEnterFullScreen();
2209 void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2211 m_fullScreenPluginView = plugin;
2212 m_client->didPluginEnterFullScreen();
2214 if (!m_client->window())
2217 Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix);
2218 m_client->window()->setSensitivityFullscreenOverride(true);
2221 void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2223 m_fullScreenPluginView = 0;
2224 m_client->didPluginExitFullScreen();
2226 if (!m_client->window())
2229 Platform::Graphics::Window::setTransparencyDiscardFilter(0);
2230 m_client->window()->setSensitivityFullscreenOverride(false);
2233 void WebPagePrivate::onPluginStartBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
2235 m_client->onPluginStartBackgroundPlay();
2238 void WebPagePrivate::onPluginStopBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
2240 m_client->onPluginStopBackgroundPlay();
2243 bool WebPagePrivate::lockOrientation(bool landscape)
2245 return m_client->lockOrientation(landscape);
2248 void WebPagePrivate::unlockOrientation()
2250 return m_client->unlockOrientation();
2253 int WebPagePrivate::orientation() const
2255 #if ENABLE(ORIENTATION_EVENTS)
2256 return m_mainFrame->orientation();
2258 #error ORIENTATION_EVENTS must be defined.
2259 // Or a copy of the orientation value will have to be stored in these objects.
2263 double WebPagePrivate::currentZoomFactor() const
2265 return currentScale();
2268 int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype)
2270 return m_client->showAlertDialog(atype);
2273 bool WebPagePrivate::isActive() const
2275 return m_client->isActive();
2278 bool WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSpace& protectionSpace, Credential& inputCredential)
2283 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
2284 if (m_dumpRenderTree)
2285 return m_dumpRenderTree->didReceiveAuthenticationChallenge(inputCredential);
2288 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2289 if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled())
2290 credentialManager().autofillAuthenticationChallenge(protectionSpace, username, password);
2293 bool isConfirmed = m_client->authenticationChallenge(protectionSpace.realm().characters(), protectionSpace.realm().length(), username, password);
2295 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2296 Credential credential(username, password, CredentialPersistencePermanent);
2297 if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled() && isConfirmed)
2298 credentialManager().saveCredentialIfConfirmed(this, CredentialTransformData(url, protectionSpace, credential));
2300 Credential credential(username, password, CredentialPersistenceNone);
2302 inputCredential = credential;
2306 PageClientBlackBerry::SaveCredentialType WebPagePrivate::notifyShouldSaveCredential(bool isNew)
2308 return static_cast<PageClientBlackBerry::SaveCredentialType>(m_client->notifyShouldSaveCredential(isNew));
2311 void WebPagePrivate::syncProxyCredential(const WebCore::Credential& credential)
2313 m_client->syncProxyCredential(credential.user().utf8().data(), credential.password().utf8().data());
2316 void WebPagePrivate::notifyPopupAutofillDialog(const Vector<String>& candidates, const WebCore::IntRect& screenRect)
2318 vector<string> textItems;
2319 for (size_t i = 0; i < candidates.size(); i++)
2320 textItems.push_back(candidates[i].utf8().data());
2321 m_client->notifyPopupAutofillDialog(textItems, screenRect);
2324 void WebPagePrivate::notifyDismissAutofillDialog()
2326 m_client->notifyDismissAutofillDialog();
2329 bool WebPagePrivate::useFixedLayout() const
2334 Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy)
2336 Platform::WebContext context;
2338 RefPtr<Node> node = contextNode(strategy);
2339 m_currentContextNode = node;
2340 if (!m_currentContextNode)
2343 // Send an onContextMenu event to the current context ndoe and get the result. Since we've already figured out
2344 // which node we want, we can send it directly to the node and not do a hit test. The onContextMenu event doesn't require
2345 // mouse positions so we just set the position at (0,0)
2346 PlatformMouseEvent mouseEvent(IntPoint(), IntPoint(), PlatformEvent::MouseMoved, 0, NoButton, TouchScreen);
2347 if (m_currentContextNode->dispatchMouseEvent(mouseEvent, eventNames().contextmenuEvent, 0)) {
2348 context.setFlag(Platform::WebContext::IsOnContextMenuPrevented);
2352 // Unpress the mouse button if we're actually getting context.
2353 EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2354 if (eventHandler->mousePressed())
2355 eventHandler->setMousePressed(false);
2357 requestLayoutIfNeeded();
2359 bool nodeAllowSelectionOverride = false;
2360 if (Node* linkNode = node->enclosingLinkEventParentOrSelf()) {
2362 if (linkNode->isLink() && linkNode->hasAttributes()) {
2363 if (Attribute* attribute = static_cast<Element*>(linkNode)->getAttributeItem(HTMLNames::hrefAttr))
2364 href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
2367 String pattern = findPatternStringForUrl(href);
2368 if (!pattern.isEmpty())
2369 context.setPattern(pattern.utf8().data());
2371 if (!href.string().isEmpty()) {
2372 context.setUrl(href.string().utf8().data());
2374 // Links are non-selectable by default, but selection should be allowed
2375 // providing the page is selectable, use the parent to determine it.
2376 if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
2377 nodeAllowSelectionOverride = true;
2381 if (node->isHTMLElement()) {
2382 HTMLImageElement* imageElement = 0;
2383 HTMLMediaElement* mediaElement = 0;
2385 if (node->hasTagName(HTMLNames::imgTag))
2386 imageElement = static_cast<HTMLImageElement*>(node.get());
2387 else if (node->hasTagName(HTMLNames::areaTag))
2388 imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement();
2390 if (static_cast<HTMLElement*>(node.get())->isMediaElement())
2391 mediaElement = static_cast<HTMLMediaElement*>(node.get());
2393 if (imageElement && imageElement->renderer()) {
2394 context.setFlag(Platform::WebContext::IsImage);
2395 // FIXME: At the mean time, we only show "Save Image" when the image data is available.
2396 if (CachedResource* cachedResource = imageElement->cachedImage()) {
2397 if (cachedResource->isLoaded() && cachedResource->data()) {
2398 String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
2399 context.setSrc(node->document()->completeURL(url).string().utf8().data());
2402 String alt = imageElement->altText();
2404 context.setAlt(alt.utf8().data());
2408 if (mediaElement->hasAudio())
2409 context.setFlag(Platform::WebContext::IsAudio);
2410 if (mediaElement->hasVideo())
2411 context.setFlag(Platform::WebContext::IsVideo);
2413 String src = stripLeadingAndTrailingHTMLSpaces(mediaElement->getAttribute(HTMLNames::srcAttr).string());
2414 context.setSrc(node->document()->completeURL(src).string().utf8().data());
2418 if (node->isTextNode()) {
2419 Text* curText = toText(node.get());
2420 if (!curText->wholeText().isEmpty())
2421 context.setText(curText->wholeText().utf8().data());
2424 bool canStartSelection = node->canStartSelection();
2426 if (node->isElementNode()) {
2427 Element* element = static_cast<Element*>(node->shadowAncestorNode());
2428 if (DOMSupport::isTextBasedContentEditableElement(element)) {
2429 if (!canStartSelection) {
2430 // Input fields host node is by spec non-editable unless the field itself has content editable enabled.
2431 // Enable selection if the shadow tree for the input field is selectable.
2432 Node* nodeUnderFinger = m_touchEventHandler->lastFatFingersResult().isValid() ? m_touchEventHandler->lastFatFingersResult().node(FatFingersResult::ShadowContentAllowed) : 0;
2433 if (nodeUnderFinger)
2434 canStartSelection = nodeUnderFinger->canStartSelection();
2436 context.setFlag(Platform::WebContext::IsInput);
2437 if (element->hasTagName(HTMLNames::inputTag))
2438 context.setFlag(Platform::WebContext::IsSingleLine);
2439 if (DOMSupport::isPasswordElement(element))
2440 context.setFlag(Platform::WebContext::IsPassword);
2442 String elementText(DOMSupport::inputElementText(element));
2443 if (!elementText.stripWhiteSpace().isEmpty())
2444 context.setText(elementText.utf8().data());
2448 if (!nodeAllowSelectionOverride && !canStartSelection)
2449 context.resetFlag(Platform::WebContext::IsSelectable);
2451 if (node->isFocusable())
2452 context.setFlag(Platform::WebContext::IsFocusable);
2457 Platform::WebContext WebPage::webContext(TargetDetectionStrategy strategy) const
2459 return d->webContext(strategy);
2462 void WebPagePrivate::updateCursor()
2465 if (m_lastMouseEvent.button() == LeftButton)
2466 buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
2467 else if (m_lastMouseEvent.button() == MiddleButton)
2468 buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
2469 else if (m_lastMouseEvent.button() == RightButton)
2470 buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
2472 BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask, mapToTransformed(m_lastMouseEvent.position()), mapToTransformed(m_lastMouseEvent.globalPosition()), 0, 0);
2473 m_webPage->mouseEvent(event);
2476 IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
2478 if (hasVirtualViewport())
2479 return IntSize(m_virtualViewportWidth, m_virtualViewportHeight);
2481 const int defaultLayoutWidth = m_defaultLayoutSize.width();
2482 const int defaultLayoutHeight = m_defaultLayoutSize.height();
2484 int minWidth = defaultLayoutWidth;
2485 int maxWidth = defaultMaxLayoutSize().width();
2486 int maxHeight = defaultMaxLayoutSize().height();
2488 // If the load state is none then we haven't actually got anything yet, but we need to layout
2489 // the entire page so that the user sees the entire page (unrendered) instead of just part of it.
2490 if (m_loadState == None)
2491 return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2493 if (m_viewMode == FixedDesktop) {
2494 int width = maxWidth;
2495 // if the defaultLayoutHeight is at minimum, it probably was set as 0
2496 // and clamped, meaning it's effectively not set. (Even if it happened
2497 // to be set exactly to the minimum, it's too small to be useful.) So
2500 if (defaultLayoutHeight <= minimumLayoutSize.height())
2503 height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2504 return IntSize(width, height);
2507 if (m_viewMode == Desktop) {
2508 // If we detect an overflow larger than the contents size then use that instead since
2509 // it'll still be clamped by the maxWidth below...
2510 int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
2511 if (m_pendingOrientation != -1 && !m_nestedLayoutFinishedCount)
2514 if (snapToIncrement) {
2515 // Snap to increments of defaultLayoutWidth / 2.0.
2516 float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
2517 factor = ceilf(factor);
2518 width = (defaultLayoutWidth / 2.0) * factor;
2521 if (width < minWidth)
2523 if (width > maxWidth)
2525 int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2526 return IntSize(width, height);
2529 ASSERT_NOT_REACHED();
2530 return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2533 BackingStoreClient* WebPagePrivate::backingStoreClientForFrame(const Frame* frame) const
2536 BackingStoreClient* backingStoreClient = 0;
2537 if (m_backingStoreClientForFrameMap.contains(frame))
2538 backingStoreClient = m_backingStoreClientForFrameMap.get(frame);
2539 return backingStoreClient;
2542 void WebPagePrivate::addBackingStoreClientForFrame(const Frame* frame, BackingStoreClient* client)
2546 m_backingStoreClientForFrameMap.add(frame, client);
2549 void WebPagePrivate::removeBackingStoreClientForFrame(const Frame* frame)
2552 if (m_backingStoreClientForFrameMap.contains(frame))
2553 m_backingStoreClientForFrameMap.remove(frame);
2557 void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
2559 ASSERT(documentGoingAway);
2560 if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
2561 m_currentContextNode = 0;
2563 if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
2564 m_currentPinchZoomNode = 0;
2566 if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
2567 m_currentBlockZoomAdjustedNode = 0;
2569 if (m_inRegionScroller->d->hasNode() && m_inRegionScroller->d->node()->document() == documentGoingAway)
2570 m_inRegionScroller->d->reset();
2572 if (documentGoingAway->frame())
2573 m_inputHandler->frameUnloaded(documentGoingAway->frame());
2575 Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
2576 if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
2577 m_touchEventHandler->resetLastFatFingersResult();
2579 // NOTE: m_fullscreenVideoNode, m_fullScreenPluginView and m_pluginViews
2580 // are cleared in other methods already.
2583 typedef bool (*PredicateFunction)(RenderLayer*);
2584 static bool isPositionedContainer(RenderLayer* layer)
2586 RenderObject* o = layer->renderer();
2587 return o->isRenderView() || o->isOutOfFlowPositioned() || o->isRelPositioned() || layer->hasTransform();
2590 static bool isFixedPositionedContainer(RenderLayer* layer)
2592 RenderObject* o = layer->renderer();
2593 return o->isRenderView() || (o->isOutOfFlowPositioned() && o->style()->position() == FixedPosition);
2596 static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
2598 RenderLayer* curr = layer;
2599 while (curr && !predicate(curr))
2600 curr = curr->parent();
2605 RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
2607 return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
2610 RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
2612 return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
2615 static inline Frame* frameForNode(Node* node)
2617 Node* origNode = node;
2618 for (; node; node = node->parentNode()) {
2619 if (RenderObject* renderer = node->renderer()) {
2620 if (renderer->isRenderView()) {
2621 if (FrameView* view = toRenderView(renderer)->frameView()) {
2622 if (Frame* frame = view->frame())
2626 if (renderer->isWidget()) {
2627 Widget* widget = toRenderWidget(renderer)->widget();
2628 if (widget && widget->isFrameView()) {
2629 if (Frame* frame = static_cast<FrameView*>(widget)->frame())
2636 for (node = origNode; node; node = node->parentNode()) {
2637 if (Document* doc = node->document()) {
2638 if (Frame* frame = doc->frame())
2646 static IntRect getNodeWindowRect(Node* node)
2648 if (Frame* frame = frameForNode(node)) {
2649 if (FrameView* view = frame->view())
2650 return view->contentsToWindow(node->getRect());
2652 ASSERT_NOT_REACHED();
2656 IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
2658 ASSERT(m_mainFrame);
2660 // Don't call this function asking to not clip the main frame providing only
2661 // the main frame. All that can be returned is the content rect which
2662 // isn't what this function is for.
2663 if (noClipOfMainFrame && view == m_mainFrame->view()) {
2664 ASSERT_NOT_REACHED();
2665 return IntRect(IntPoint::zero(), view->contentsSize());
2668 IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect(false)));
2669 if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
2670 // Intersect with parent visible rect.
2671 visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
2673 return visibleWindowRect;
2676 void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
2678 ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
2679 ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
2680 ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
2682 // First we clear the focus, since we want to focus either initial or the last
2683 // focusable element in the webpage (according to the TABINDEX), or simply clear
2687 switch (direction) {
2688 case FocusDirectionForward:
2689 case FocusDirectionBackward:
2690 m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
2692 case FocusDirectionNone:
2695 ASSERT_NOT_REACHED();
2699 void WebPage::assignFocus(Platform::FocusDirection direction)
2701 if (d->m_page->defersLoading())
2703 d->assignFocus(direction);
2706 Platform::IntRect WebPagePrivate::focusNodeRect()
2708 Frame* frame = focusedOrMainFrame();
2710 return Platform::IntRect();
2712 Document* doc = frame->document();
2713 FrameView* view = frame->view();
2714 if (!doc || !view || view->needsLayout())
2715 return Platform::IntRect();
2717 IntRect focusRect = rectForNode(doc->focusedNode());
2718 focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
2719 focusRect = mapToTransformed(focusRect);
2720 clipToTransformedContentsRect(focusRect);
2724 PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
2726 EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2727 const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
2728 bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
2730 // Check if we're using LinkToLink and the user is not touching the screen.
2731 if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
2733 node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
2735 IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
2736 if (!visibleRect.intersects(getNodeWindowRect(node.get())))
2739 return node.release();
2742 // Check for text input.
2743 if (isTouching && lastFatFingersResult.isTextInput())
2744 return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
2746 IntPoint contentPos;
2748 contentPos = lastFatFingersResult.adjustedPosition();
2750 contentPos = mapFromViewportToContents(m_lastMouseEvent.position());
2752 if (strategy == RectBased) {
2753 FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
2754 return result.node(FatFingersResult::ShadowContentNotAllowed);
2757 HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos, false /*allowShadowContent*/);
2758 return result.innerNode();
2761 static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
2763 // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709).
2764 double dx = static_cast<double>(p1.x() - p2.x());
2765 double dy = static_cast<double>(p1.y() - p2.y());
2766 return sqrt((dx * dx) + (dy * dy));
2769 Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& point)
2771 IntPoint pt = mapFromTransformed(point);
2772 IntRect clickRect(pt.x() - blockClickRadius, pt.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
2773 Node* originalNode = nodeForZoomUnderPoint(point);
2776 Node* node = bestChildNodeForClickRect(originalNode, clickRect);
2777 return node ? adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(node) : adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(originalNode);
2780 Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
2785 int bestDistance = std::numeric_limits<int>::max();
2787 Node* node = parentNode->firstChild();
2789 for (; node; node = node->nextSibling()) {
2790 IntRect rect = rectForNode(node);
2791 if (!clickRect.intersects(rect))
2794 int distance = distanceBetweenPoints(rect.center(), clickRect.center());
2795 Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
2796 if (bestChildNode) {
2797 IntRect bestChildRect = rectForNode(bestChildNode);
2798 int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
2799 if (bestChildDistance < distance && bestChildDistance < bestDistance) {
2800 bestNode = bestChildNode;
2801 bestDistance = bestChildDistance;
2803 if (distance < bestDistance) {
2805 bestDistance = distance;
2809 if (distance < bestDistance) {
2811 bestDistance = distance;
2819 double WebPagePrivate::maxBlockZoomScale() const
2821 return std::min(maximumBlockZoomScale, maximumScale());
2824 Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& point)
2829 HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromTransformed(point), false);
2831 Node* node = result.innerNonSharedNode();
2836 RenderObject* renderer = node->renderer();
2838 node = node->parentNode();
2839 renderer = node->renderer();
2845 Node* WebPagePrivate::adjustedBlockZoomNodeForZoomAndExpandingRatioLimits(Node* node)
2847 Node* initialNode = node;
2848 RenderObject* renderer = node->renderer();
2849 bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2850 IntSize actualVisibleSize = this->actualVisibleSize();
2852 while (!renderer || !acceptableNodeSize) {
2853 node = node->parentNode();
2854 IntRect nodeRect = rectForNode(node);
2856 // Don't choose a node if the width of the node size is very close to the width of the actual visible size,
2857 // as block zoom can do nothing on such kind of node.
2858 if (!node || static_cast<double>(actualVisibleSize.width() - nodeRect.width()) / actualVisibleSize.width() < minimumExpandingRatio)
2861 renderer = node->renderer();
2862 acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2868 bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
2873 return (n2 == n1) || n2->isDescendantOf(n1);
2876 double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
2879 return std::numeric_limits<double>::max();
2881 ASSERT(rect.width() + margin);
2883 double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
2888 IntRect WebPagePrivate::rectForNode(Node* node)
2893 RenderObject* renderer = node->renderer();
2898 // Return rect in un-transformed content coordinates.
2901 // FIXME: Ensure this works with iframes.
2902 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
2903 RenderBlock* renderBlock = renderer->containingBlock();
2906 while (!renderBlock->isRoot()) {
2907 xOffset += renderBlock->x();
2908 yOffset += renderBlock->y();
2909 renderBlock = renderBlock->containingBlock();
2911 const RenderText* renderText = toRenderText(renderer);
2912 IntRect linesBox = renderText->linesBoundingBox();
2913 blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height());
2915 blockRect = renderer->absoluteClippedOverflowRect();
2917 if (renderer->isText()) {
2918 RenderBlock* rb = renderer->containingBlock();
2920 // Inefficient? Way to find width when floats intersect a block.
2922 int lineCount = rb->lineCount();
2923 for (int i = 0; i < lineCount; i++)
2924 blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false));
2926 blockRect.setWidth(blockWidth);
2927 blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
2930 // Strip off padding.
2931 if (renderer->style()->hasPadding()) {
2932 blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
2933 blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
2934 blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
2935 blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
2941 IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
2945 // FIXME: This function can be called when page is being destroyed and JS triggers selection change.
2946 // We could break the call chain at upper levels, but I think it is better to check the frame pointer
2947 // here because the pointer is explicitly cleared in WebPage::destroy().
2951 // Convert 0,0 in the frame's coordinate system to window coordinates to
2952 // get the frame's global position, and return this position in the main
2953 // frame's coordinates. (So the main frame's coordinates will be 0,0.)
2954 return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
2957 IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
2962 // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames.
2963 // FIXME: can we just use frameOffset instead of this big routine?
2964 const Node* tnode = node;
2965 IntRect adjustedRect = rect;
2967 Frame* frame = tnode->document()->frame();
2971 Node* ownerNode = static_cast<Node*>(frame->ownerElement());
2973 if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
2976 iFrameRect = rectForNode(ownerNode);
2977 adjustedRect.move(iFrameRect.x(), iFrameRect.y());
2978 adjustedRect.intersect(iFrameRect);
2979 ownerNode = ownerNode->parentNode();
2980 } while (iFrameRect.isEmpty() && ownerNode);
2983 } while (tnode = tnode->parentNode());
2985 return adjustedRect;
2988 IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
2990 if (!node || contentsSize().isEmpty())
2994 m_currentBlockZoomAdjustedNode = tnode;
2996 IntRect blockRect = rectForNode(tnode);
2997 IntRect originalRect = blockRect;
2999 int originalArea = originalRect.width() * originalRect.height();
3000 int pageArea = contentsSize().width() * contentsSize().height();
3001 double blockToPageRatio = static_cast<double>(pageArea - originalArea) / pageArea;
3002 double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
3004 if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
3005 while (tnode = tnode->parentNode()) {
3007 IntRect tRect = rectForNode(tnode);
3008 int tempBlockArea = tRect.width() * tRect.height();
3009 // Don't expand the block if it will be too large relative to the content.
3010 if (static_cast<double>(pageArea - tempBlockArea) / pageArea < minimumExpandingRatio)
3012 if (tRect.isEmpty())
3013 continue; // No renderer.
3014 if (tempBlockArea < 1.1 * originalArea)
3015 continue; // The size of this parent is very close to the child, no need to go to this parent.
3016 // Don't expand the block if the parent node size is already almost the size of actual visible size.
3017 IntSize actualSize = actualVisibleSize();
3018 if (static_cast<double>(actualSize.width() - tRect.width()) / actualSize.width() < minimumExpandingRatio)
3020 if (tempBlockArea < blockExpansionRatio * originalArea) {
3022 m_currentBlockZoomAdjustedNode = tnode;
3028 blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
3029 blockRect = mapToTransformed(blockRect);
3030 clipToTransformedContentsRect(blockRect);
3032 #if DEBUG_BLOCK_ZOOM
3033 if (!m_backingStore->d->isSuspended()) {
3034 // Re-paint the backingstore to screen to erase other annotations.
3035 if (m_backingStore->d->shouldDirectRenderingToWindow())
3036 m_backingStore->d->renderVisibleContents();
3038 m_backingStore->d->blitVisibleContents();
3040 // Render a black square over the calculated block and a gray square over the original block for visual inspection.
3041 originalRect = mapToTransformed(originalRect);
3042 clipToTransformedContentsRect(originalRect);
3043 IntRect renderRect = mapFromTransformedContentsToTransformedViewport(blockRect);
3044 IntRect originalRenderRect = mapFromTransformedContentsToTransformedViewport(originalRect);
3045 IntSize viewportSize = transformedViewportSize();
3046 renderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
3047 originalRenderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
3048 m_backingStore->d->clearWindow(renderRect, 0, 0, 0);
3049 m_backingStore->d->clearWindow(originalRenderRect, 120, 120, 120);
3050 m_backingStore->d->invalidateWindow(renderRect);
3057 // This function should not be called directly.
3058 // It is called after the animation ends (see above).
3059 void WebPagePrivate::zoomBlock()
3064 IntPoint anchor(roundUntransformedPoint(mapFromTransformedFloatPoint(m_finalBlockPoint)));
3065 bool willUseTextReflow = false;
3067 #if ENABLE(VIEWPORT_REFLOW)
3068 willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
3069 toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
3073 TransformationMatrix zoom;
3074 zoom.scale(m_blockZoomFinalScale);
3075 *m_transformationMatrix = zoom;
3076 m_client->resetBitmapZoomScale(m_blockZoomFinalScale);
3077 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3078 updateViewportSize();
3080 #if ENABLE(VIEWPORT_REFLOW)
3081 requestLayoutIfNeeded();
3082 if (willUseTextReflow && m_shouldReflowBlock) {
3083 IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
3084 reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
3085 reflowedRect.move(roundTransformedPoint(m_finalBlockPointReflowOffset).x(), roundTransformedPoint(m_finalBlockPointReflowOffset).y());
3086 RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
3087 IntPoint topLeftPoint(reflowedRect.location());
3088 if (renderer && renderer->isText()) {
3089 ETextAlign textAlign = renderer->style()->textAlign();
3090 IntPoint textAnchor;
3091 switch (textAlign) {
3094 textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
3098 textAnchor = topLeftPoint;
3102 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
3107 if (renderer->style()->isLeftToRightDirection())
3108 textAnchor = topLeftPoint;
3110 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
3113 setScrollPosition(textAnchor);
3115 renderer->style()->isLeftToRightDirection()
3116 ? setScrollPosition(topLeftPoint)
3117 : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
3119 } else if (willUseTextReflow) {
3120 IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
3121 finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
3122 setScrollPosition(IntPoint(0, finalRect.y() + m_finalBlockPointReflowOffset.y()));
3126 if (!willUseTextReflow) {
3127 setScrollPosition(anchor);
3128 if (!m_shouldReflowBlock)
3132 notifyTransformChanged();
3133 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
3134 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
3137 void WebPage::blockZoomAnimationFinished()
3142 void WebPagePrivate::resetBlockZoom()
3144 m_currentBlockZoomNode = 0;
3145 m_currentBlockZoomAdjustedNode = 0;
3146 m_shouldReflowBlock = false;
3149 void WebPage::destroyWebPageCompositor()
3151 #if USE(ACCELERATED_COMPOSITING)
3152 // Destroy the layer renderer in a sync command before we destroy the backing store,
3153 // to flush any pending compositing messages on the compositing thread.
3154 // The backing store is indirectly deleted by the 'detachFromParent' call below.
3155 d->syncDestroyCompositorOnCompositingThread();
3159 void WebPage::destroy()
3161 // TODO: need to verify if this call needs to be made before calling
3162 // WebPage::destroyWebPageCompositor()
3163 d->m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3165 // Close the backforward list and release the cached pages.
3166 d->m_page->backForward()->close();
3167 pageCache()->releaseAutoreleasedPagesNow();
3169 FrameLoader* loader = d->m_mainFrame->loader();
3171 // Remove main frame's backing store client from the map
3172 // to prevent FrameLoaderClientBlackyBerry::detachFromParent2(),
3173 // which is called by loader->detachFromParent(), deleting it.
3174 // We will delete it in ~WebPagePrivate().
3175 // Reason: loader->detachFromParent() may ping back to backing store
3176 // indirectly through ChromeClientBlackBerry::invalidateContentsAndWindow().
3177 // see RIM PR #93256.
3178 d->removeBackingStoreClientForFrame(d->m_mainFrame);
3180 // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion.
3183 loader->detachFromParent();
3185 deleteGuardedObject(this);
3188 WebPageClient* WebPage::client() const
3193 int WebPage::backForwardListLength() const
3195 return d->m_page->getHistoryLength();
3198 bool WebPage::canGoBackOrForward(int delta) const
3200 return d->m_page->canGoBackOrForward(delta);
3203 bool WebPage::goBackOrForward(int delta)
3205 if (d->m_page->canGoBackOrForward(delta)) {
3206 d->m_page->goBackOrForward(delta);
3212 void WebPage::goToBackForwardEntry(BackForwardId id)
3214 HistoryItem* item = historyItemFromBackForwardId(id);
3216 d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
3219 void WebPage::reload()
3221 d->m_mainFrame->loader()->reload(/* bypassCache */ true);
3224 void WebPage::reloadFromCache()
3226 d->m_mainFrame->loader()->reload(/* bypassCache */ false);
3229 WebSettings* WebPage::settings() const
3231 return d->m_webSettings;
3234 bool WebPage::isVisible() const
3236 return d->m_visible;
3239 #if ENABLE(PAGE_VISIBILITY_API)
3240 class DeferredTaskSetPageVisibilityState: public DeferredTask<&WebPagePrivate::m_wouldSetPageVisibilityState> {
3242 explicit DeferredTaskSetPageVisibilityState(WebPagePrivate* webPagePrivate)
3243 : DeferredTaskType(webPagePrivate)
3247 virtual void performInternal(WebPagePrivate* webPagePrivate)
3249 webPagePrivate->setPageVisibilityState();
3253 void WebPagePrivate::setPageVisibilityState()
3255 if (m_page->defersLoading())
3256 m_deferredTasks.append(adoptPtr(new DeferredTaskSetPageVisibilityState(this)));
3258 DeferredTaskSetPageVisibilityState::finishOrCancel(this);
3260 static bool s_initialVisibilityState = true;
3262 m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
3263 s_initialVisibilityState = false;
3268 void WebPagePrivate::setVisible(bool visible)
3270 m_visible = visible;
3272 #if ENABLE(PAGE_VISIBILITY_API)
3273 setPageVisibilityState();
3277 void WebPage::setVisible(bool visible)
3279 if (d->m_visible == visible)
3282 d->setVisible(visible);
3285 d->suspendBackingStore();
3287 // Remove this WebPage from the visible pages list.
3288 size_t foundIndex = visibleWebPages()->find(this);
3289 if (foundIndex != WTF::notFound)
3290 visibleWebPages()->remove(foundIndex);
3292 // Return the backing store to the last visible WebPage.
3293 if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
3294 visibleWebPages()->last()->d->resumeBackingStore();
3296 #if USE(ACCELERATED_COMPOSITING)
3297 // Root layer commit is not necessary for invisible tabs.
3298 // And release layer resources can reduce memory consumption.
3299 d->suspendRootLayerCommit();
3305 #if USE(ACCELERATED_COMPOSITING)
3306 d->resumeRootLayerCommit();
3309 // Push this WebPage to the top of the visible pages list.
3310 if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
3311 size_t foundIndex = visibleWebPages()->find(this);
3312 if (foundIndex != WTF::notFound)
3313 visibleWebPages()->remove(foundIndex);
3315 visibleWebPages()->append(this);
3317 if (BackingStorePrivate::currentBackingStoreOwner()
3318 && BackingStorePrivate::currentBackingStoreOwner() != this)
3319 BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
3321 // resumeBackingStore will set the current owner to this webpage.
3322 // If we set the owner prematurely, then the tiles will not be reset.
3323 d->resumeBackingStore();
3326 void WebPagePrivate::selectionChanged(Frame* frame)
3328 m_inputHandler->selectionChanged();
3330 // FIXME: This is a hack!
3331 // To ensure the selection being changed has its frame 'focused', lets
3332 // set it as focused ourselves (PR #104724).
3333 m_page->focusController()->setFocusedFrame(frame);
3336 void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
3338 // Track a dispatched message, we don't want to flood the webkit thread.
3339 // There can be as many as one more message enqued as needed but never less.
3341 m_updateDelegatedOverlaysDispatched = false;
3342 else if (m_updateDelegatedOverlaysDispatched) {
3343 // Early return if there is message already pending on the webkit thread.
3347 if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
3348 // Must be called on the WebKit thread.
3349 if (m_selectionHandler->isSelectionActive())
3350 m_selectionHandler->selectionPositionChanged();
3351 if (m_inspectorOverlay)
3352 m_inspectorOverlay->update();
3354 } else if (m_selectionHandler->isSelectionActive()) {
3355 // Don't bother dispatching to webkit thread if selection and tap highlight are not active.
3356 m_updateDelegatedOverlaysDispatched = true;
3357 Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/));
3361 void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle style)
3365 bool WebPage::setBatchEditingActive(bool active)
3367 return d->m_inputHandler->setBatchEditingActive(active);
3370 bool WebPage::setInputSelection(unsigned start, unsigned end)
3372 if (d->m_page->defersLoading())
3374 return d->m_inputHandler->setSelection(start, end);
3377 int WebPage::inputCaretPosition() const
3379 return d->m_inputHandler->caretPosition();
3382 class DeferredTaskPopupListSelectMultiple: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectMultiple> {
3384 DeferredTaskPopupListSelectMultiple(WebPagePrivate* webPagePrivate, int size, const bool* selecteds)
3385 : DeferredTaskType(webPagePrivate)
3387 webPagePrivate->m_cachedPopupListSelecteds.append(selecteds, size);
3390 virtual void performInternal(WebPagePrivate* webPagePrivate)
3392 webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelecteds.size(), webPagePrivate->m_cachedPopupListSelecteds.data());
3396 class DeferredTaskPopupListSelectSingle: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectSingle> {
3398 explicit DeferredTaskPopupListSelectSingle(WebPagePrivate* webPagePrivate, int index)
3399 : DeferredTaskType(webPagePrivate)
3401 webPagePrivate->m_cachedPopupListSelectedIndex = index;
3404 virtual void performInternal(WebPagePrivate* webPagePrivate)
3406 webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelectedIndex);
3410 void WebPage::popupListClosed(int size, const bool* selecteds)
3412 DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3413 if (d->m_page->defersLoading()) {
3414 d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectMultiple(d, size, selecteds)));
3417 DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3418 d->m_inputHandler->setPopupListIndexes(size, selecteds);
3421 void WebPage::popupListClosed(int index)
3423 DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3424 if (d->m_page->defersLoading()) {
3425 d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectSingle(d, index)));
3428 DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3429 d->m_inputHandler->setPopupListIndex(index);
3432 class DeferredTaskSetDateTimeInput: public DeferredTask<&WebPagePrivate::m_wouldSetDateTimeInput> {
3434 explicit DeferredTaskSetDateTimeInput(WebPagePrivate* webPagePrivate, WebString value)
3435 : DeferredTaskType(webPagePrivate)
3437 webPagePrivate->m_cachedDateTimeInput = value;
3440 virtual void performInternal(WebPagePrivate* webPagePrivate)
3442 webPagePrivate->m_webPage->setDateTimeInput(webPagePrivate->m_cachedDateTimeInput);
3446 void WebPage::setDateTimeInput(const WebString& value)
3448 if (d->m_page->defersLoading()) {
3449 d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetDateTimeInput(d, value)));
3452 DeferredTaskSetDateTimeInput::finishOrCancel(d);
3453 d->m_inputHandler->setInputValue(String(value.impl()));
3456 class DeferredTaskSetColorInput: public DeferredTask<&WebPagePrivate::m_wouldSetColorInput> {
3458 explicit DeferredTaskSetColorInput(WebPagePrivate* webPagePrivate, WebString value)
3459 : DeferredTaskType(webPagePrivate)
3461 webPagePrivate->m_cachedColorInput = value;
3464 virtual void performInternal(WebPagePrivate* webPagePrivate)
3466 webPagePrivate->m_webPage->setColorInput(webPagePrivate->m_cachedColorInput);
3470 void WebPage::setColorInput(const WebString& value)
3472 if (d->m_page->defersLoading()) {
3473 d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetColorInput(d, value)));
3476 DeferredTaskSetColorInput::finishOrCancel(d);
3477 d->m_inputHandler->setInputValue(String(value.impl()));
3480 void WebPage::setVirtualViewportSize(int width, int height)
3482 d->m_virtualViewportWidth = width;
3483 d->m_virtualViewportHeight = height;
3486 void WebPage::resetVirtualViewportOnCommitted(bool reset)
3488 d->m_resetVirtualViewportOnCommitted = reset;
3491 IntSize WebPagePrivate::recomputeVirtualViewportFromViewportArguments()
3493 static const ViewportArguments defaultViewportArguments;
3494 if (m_viewportArguments == defaultViewportArguments)
3497 int desktopWidth = defaultMaxLayoutSize().width();
3498 int deviceWidth = Platform::Graphics::Screen::primaryScreen()->width();
3499 int deviceHeight = Platform::Graphics::Screen::primaryScreen()->height();
3500 ViewportAttributes result = computeViewportAttributes(m_viewportArguments, desktopWidth, deviceWidth, deviceHeight, m_webSettings->devicePixelRatio(), m_defaultLayoutSize);
3502 setUserScalable(m_webSettings->isUserScalable() && result.userScalable);
3503 if (result.initialScale > 0)
3504 setInitialScale(result.initialScale * result.devicePixelRatio);
3505 if (result.minimumScale > 0)
3506 setMinimumScale(result.minimumScale * result.devicePixelRatio);
3507 if (result.maximumScale > 0)