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 "InputHandler.h"
75 #include "InspectorBackendDispatcher.h"
76 #include "InspectorClientBlackBerry.h"
77 #include "InspectorController.h"
78 #include "InspectorOverlay.h"
79 #include "JavaScriptDebuggerBlackBerry.h"
80 #include "LayerWebKitThread.h"
81 #include "NetworkManager.h"
82 #include "NodeRenderStyle.h"
83 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
84 #include "NotificationPresenterImpl.h"
87 #include "PageCache.h"
88 #include "PageGroup.h"
89 #include "PagePopupBlackBerry.h"
90 #include "PlatformTouchEvent.h"
91 #include "PlatformWheelEvent.h"
92 #include "PluginDatabase.h"
93 #include "PluginView.h"
94 #include "RenderLayerBacking.h"
95 #include "RenderLayerCompositor.h"
96 #if ENABLE(FULLSCREEN_API)
97 #include "RenderFullScreen.h"
99 #include "RenderText.h"
100 #include "RenderThemeBlackBerry.h"
101 #include "RenderTreeAsText.h"
102 #include "RenderView.h"
103 #include "RenderWidget.h"
104 #include "ScriptSourceCode.h"
105 #include "ScriptValue.h"
106 #include "ScrollTypes.h"
107 #include "SelectionHandler.h"
108 #include "SelectionOverlay.h"
109 #include "Settings.h"
111 #include "StorageNamespace.h"
112 #include "SurfacePool.h"
114 #include "ThreadCheck.h"
115 #include "TouchEventHandler.h"
116 #include "TransformationMatrix.h"
117 #if ENABLE(MEDIA_STREAM)
118 #include "UserMediaClientImpl.h"
120 #if ENABLE(VIBRATION)
121 #include "VibrationClientBlackBerry.h"
123 #include "VisiblePosition.h"
125 #include "WebDOMDocument.h"
127 #include "WebKitVersion.h"
128 #include "WebOverlay.h"
129 #include "WebOverlay_p.h"
130 #include "WebPageClient.h"
131 #include "WebSocket.h"
132 #include "WebViewportArguments.h"
134 #include "runtime_root.h"
137 #include "MediaPlayer.h"
138 #include "MediaPlayerPrivateBlackBerry.h"
142 #include "PlatformContextSkia.h"
145 #if USE(ACCELERATED_COMPOSITING)
146 #include "FrameLayers.h"
147 #include "WebPageCompositor_p.h"
150 #include <BlackBerryPlatformDeviceInfo.h>
151 #include <BlackBerryPlatformExecutableMessage.h>
152 #include <BlackBerryPlatformITPolicy.h>
153 #include <BlackBerryPlatformKeyboardEvent.h>
154 #include <BlackBerryPlatformMessageClient.h>
155 #include <BlackBerryPlatformMouseEvent.h>
156 #include <BlackBerryPlatformScreen.h>
157 #include <BlackBerryPlatformSettings.h>
158 #include <JavaScriptCore/APICast.h>
159 #include <JavaScriptCore/JSContextRef.h>
160 #include <JavaScriptCore/JSStringRef.h>
161 #include <SharedPointer.h>
162 #include <sys/keycodes.h>
163 #include <unicode/ustring.h> // platform ICU
165 #ifndef USER_PROCESSES
166 #include <memalloc.h>
169 #if ENABLE(ACCELERATED_2D_CANVAS)
170 #include "GrContext.h"
171 #include "SharedGraphicsContext3D.h"
174 #if ENABLE(REQUEST_ANIMATION_FRAME)
175 #include "PlatformScreen.h"
178 #define DEBUG_BLOCK_ZOOM 0
179 #define DEBUG_TOUCH_EVENTS 0
180 #define DEBUG_WEBPAGE_LOAD 0
181 #define DEBUG_AC_COMMIT 0
184 using namespace WebCore;
186 typedef const unsigned short* CUShortPtr;
188 namespace BlackBerry {
191 static Vector<WebPage*>* visibleWebPages()
193 static Vector<WebPage*>* s_visibleWebPages = 0; // Initially, no web page is visible.
194 if (!s_visibleWebPages)
195 s_visibleWebPages = new Vector<WebPage*>;
196 return s_visibleWebPages;
199 const unsigned blockZoomMargin = 3; // Add 3 pixel margin on each side.
200 static int blockClickRadius = 0;
201 static double maximumBlockZoomScale = 3; // This scale can be clamped by the maximumScale set for the page.
203 const double manualScrollInterval = 0.1; // The time interval during which we associate user action with scrolling.
205 const double delayedZoomInterval = 0;
207 const IntSize minimumLayoutSize(10, 10); // Needs to be a small size, greater than 0, that we can grow the layout from.
209 const double minimumExpandingRatio = 0.15;
211 const double minimumZoomToFitScale = 0.25;
213 // Helper function to parse a URL and fill in missing parts.
214 static KURL parseUrl(const String& url)
216 String urlString(url);
217 KURL kurl = KURL(KURL(), urlString);
218 if (kurl.protocol().isEmpty()) {
219 urlString.insert("http://", 0);
220 kurl = KURL(KURL(), urlString);
226 // Helper functions to convert to and from WebCore types.
227 static inline WebCore::PlatformEvent::Type toWebCoreMouseEventType(const BlackBerry::Platform::MouseEvent::Type type)
230 case BlackBerry::Platform::MouseEvent::MouseButtonDown:
231 return WebCore::PlatformEvent::MousePressed;
232 case Platform::MouseEvent::MouseButtonUp:
233 return WebCore::PlatformEvent::MouseReleased;
234 case Platform::MouseEvent::MouseMove:
236 return WebCore::PlatformEvent::MouseMoved;
240 static inline ResourceRequestCachePolicy toWebCoreCachePolicy(Platform::NetworkRequest::CachePolicy policy)
243 case Platform::NetworkRequest::UseProtocolCachePolicy:
244 return UseProtocolCachePolicy;
245 case Platform::NetworkRequest::ReloadIgnoringCacheData:
246 return ReloadIgnoringCacheData;
247 case Platform::NetworkRequest::ReturnCacheDataElseLoad:
248 return ReturnCacheDataElseLoad;
249 case Platform::NetworkRequest::ReturnCacheDataDontLoad:
250 return ReturnCacheDataDontLoad;
252 ASSERT_NOT_REACHED();
253 return UseProtocolCachePolicy;
257 #if ENABLE(EVENT_MODE_METATAGS)
258 static inline Platform::CursorEventMode toPlatformCursorEventMode(CursorEventMode mode)
261 case ProcessedCursorEvents:
262 return Platform::ProcessedCursorEvents;
263 case NativeCursorEvents:
264 return Platform::NativeCursorEvents;
266 ASSERT_NOT_REACHED();
267 return Platform::ProcessedCursorEvents;
271 static inline Platform::TouchEventMode toPlatformTouchEventMode(TouchEventMode mode)
274 case ProcessedTouchEvents:
275 return Platform::ProcessedTouchEvents;
276 case NativeTouchEvents:
277 return Platform::NativeTouchEvents;
278 case PureTouchEventsWithMouseConversion:
279 return Platform::PureTouchEventsWithMouseConversion;
281 ASSERT_NOT_REACHED();
282 return Platform::ProcessedTouchEvents;
287 static inline HistoryItem* historyItemFromBackForwardId(WebPage::BackForwardId id)
289 return reinterpret_cast<HistoryItem*>(id);
292 static inline WebPage::BackForwardId backForwardIdFromHistoryItem(HistoryItem* item)
294 return reinterpret_cast<WebPage::BackForwardId>(item);
297 void WebPage::setUserViewportArguments(const WebViewportArguments& viewportArguments)
299 d->m_userViewportArguments = *(viewportArguments.d);
302 void WebPage::resetUserViewportArguments()
304 d->m_userViewportArguments = ViewportArguments();
307 template <bool WebPagePrivate::* isActive>
308 class DeferredTask: public WebPagePrivate::DeferredTaskBase {
310 static void finishOrCancel(WebPagePrivate* webPagePrivate)
312 webPagePrivate->*isActive = false;
315 DeferredTask(WebPagePrivate* webPagePrivate)
316 : DeferredTaskBase(webPagePrivate, isActive)
319 typedef DeferredTask<isActive> DeferredTaskType;
322 void WebPage::autofillTextField(const string& item)
324 if (!d->m_webSettings->isFormAutofillEnabled())
327 d->m_autofillManager->autofillTextField(item.c_str());
330 WebPagePrivate::WebPagePrivate(WebPage* webPage, WebPageClient* client, const IntRect& rect)
333 , m_page(0) // Initialized by init.
334 , m_mainFrame(0) // Initialized by init.
335 , m_currentContextNode(0)
336 , m_webSettings(0) // Initialized by init.
338 , m_activationState(ActivationActive)
339 , m_shouldResetTilesWhenShown(false)
340 , m_shouldZoomToInitialScaleAfterLoadFinished(false)
341 , m_userScalable(true)
342 , m_userPerformedManualZoom(false)
343 , m_userPerformedManualScroll(false)
344 , m_contentsSizeChanged(false)
345 , m_overflowExceedsContentsSize(false)
346 , m_resetVirtualViewportOnCommitted(true)
347 , m_shouldUseFixedDesktopMode(false)
348 , m_needTouchEvents(false)
349 , m_preventIdleDimmingCount(0)
350 #if ENABLE(TOUCH_EVENTS)
351 , m_preventDefaultOnTouchStart(false)
353 , m_nestedLayoutFinishedCount(0)
354 , m_actualVisibleWidth(rect.width())
355 , m_actualVisibleHeight(rect.height())
356 , m_virtualViewportWidth(0)
357 , m_virtualViewportHeight(0)
358 , m_defaultLayoutSize(minimumLayoutSize)
359 , m_didRestoreFromPageCache(false)
360 , m_viewMode(WebPagePrivate::Desktop) // Default to Desktop mode for PB.
361 , m_loadState(WebPagePrivate::None)
362 , m_transformationMatrix(new TransformationMatrix())
363 , m_backingStore(0) // Initialized by init.
364 , m_backingStoreClient(0) // Initialized by init.
365 , m_inPageSearchManager(new InPageSearchManager(this))
366 , m_inputHandler(new InputHandler(this))
367 , m_selectionHandler(new SelectionHandler(this))
368 , m_touchEventHandler(new TouchEventHandler(this))
369 #if ENABLE(EVENT_MODE_METATAGS)
370 , m_cursorEventMode(ProcessedCursorEvents)
371 , m_touchEventMode(ProcessedTouchEvents)
372 #if ENABLE(FULLSCREEN_API)
373 , m_touchEventModePriorGoingFullScreen(ProcessedTouchEvents)
376 #if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO)
377 , m_scaleBeforeFullScreen(-1.0)
378 , m_xScrollOffsetBeforeFullScreen(-1)
380 , m_currentCursor(Platform::CursorNone)
381 , m_dumpRenderTree(0) // Lazy initialization.
382 , m_initialScale(-1.0)
383 , m_minimumScale(-1.0)
384 , m_maximumScale(-1.0)
385 , m_blockZoomFinalScale(1.0)
386 , m_anchorInNodeRectRatio(-1, -1)
387 , m_currentBlockZoomNode(0)
388 , m_currentBlockZoomAdjustedNode(0)
389 , m_shouldReflowBlock(false)
390 , m_delayedZoomTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::zoomAboutPointTimerFired)))
391 , m_lastUserEventTimestamp(0.0)
392 , m_pluginMouseButtonPressed(false)
393 , m_pluginMayOpenNewTab(false)
394 , m_inRegionScrollStartingNode(0)
395 #if USE(ACCELERATED_COMPOSITING)
396 , m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
397 , m_needsOneShotDrawingSynchronization(false)
398 , m_needsCommit(false)
399 , m_suspendRootLayerCommit(false)
401 , m_hasPendingSurfaceSizeChange(false)
402 , m_pendingOrientation(-1)
403 , m_fullscreenVideoNode(0)
404 , m_hasInRegionScrollableAreas(false)
405 , m_updateDelegatedOverlaysDispatched(false)
406 , m_deferredTasksTimer(this, &WebPagePrivate::deferredTasksTimerFired)
408 , m_autofillManager(AutofillManager::create(this))
410 static bool isInitialized = false;
411 if (!isInitialized) {
412 isInitialized = true;
413 BlackBerry::Platform::DeviceInfo::instance();
418 WebPage::WebPage(WebPageClient* client, const WebString& pageGroupName, const Platform::IntRect& rect)
421 d = new WebPagePrivate(this, client, rect);
422 d->init(pageGroupName);
425 WebPagePrivate::~WebPagePrivate()
427 // Hand the backingstore back to another owner if necessary.
428 m_webPage->setVisible(false);
429 if (BackingStorePrivate::currentBackingStoreOwner() == m_webPage)
430 BackingStorePrivate::setCurrentBackingStoreOwner(0);
432 delete m_webSettings;
435 delete m_backingStoreClient;
436 m_backingStoreClient = 0;
442 delete m_transformationMatrix;
443 m_transformationMatrix = 0;
445 delete m_inPageSearchManager;
446 m_inPageSearchManager = 0;
448 delete m_selectionHandler;
449 m_selectionHandler = 0;
451 delete m_inputHandler;
454 delete m_touchEventHandler;
455 m_touchEventHandler = 0;
457 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
458 delete m_dumpRenderTree;
459 m_dumpRenderTree = 0;
462 #if USE(ACCELERATED_COMPOSITING)
463 deleteGuardedObject(m_selectionOverlay);
464 m_selectionOverlay = 0;
470 deleteGuardedObject(d);
474 Page* WebPagePrivate::core(const WebPage* webPage)
476 return webPage->d->m_page;
479 void WebPagePrivate::init(const WebString& pageGroupName)
481 ChromeClientBlackBerry* chromeClient = new ChromeClientBlackBerry(this);
482 ContextMenuClientBlackBerry* contextMenuClient = 0;
483 #if ENABLE(CONTEXT_MENUS)
484 contextMenuClient = new ContextMenuClientBlackBerry();
486 EditorClientBlackBerry* editorClient = new EditorClientBlackBerry(this);
487 DragClientBlackBerry* dragClient = 0;
488 #if ENABLE(DRAG_SUPPORT)
489 dragClient = new DragClientBlackBerry();
491 InspectorClientBlackBerry* inspectorClient = 0;
492 #if ENABLE(INSPECTOR)
493 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 = 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);
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());
540 #if USE(ACCELERATED_COMPOSITING)
541 m_tapHighlight = DefaultTapHighlight::create(this);
542 m_selectionOverlay = SelectionOverlay::create(this);
543 m_page->settings()->setAcceleratedCompositingForFixedPositionEnabled(true);
546 // FIXME: We explicitly call setDelegate() instead of passing ourself in createFromStandardSettings()
547 // so that we only get one didChangeSettings() callback when we set the page group name. This causes us
548 // to make a copy of the WebSettings since some WebSettings method make use of the page group name.
549 // Instead, we shouldn't be storing the page group name in WebSettings.
550 m_webSettings->setDelegate(this);
551 m_webSettings->setPageGroupName(pageGroupName);
553 RefPtr<Frame> newFrame = Frame::create(m_page, /* HTMLFrameOwnerElement* */ 0, frameLoaderClient);
555 m_mainFrame = newFrame.get();
556 frameLoaderClient->setFrame(m_mainFrame, this);
560 Platform::Settings* settings = Platform::Settings::instance();
561 m_page->settings()->setWebGLEnabled(settings && settings->isWebGLSupported());
563 #if ENABLE(ACCELERATED_2D_CANVAS)
564 m_page->settings()->setCanvasUsesAcceleratedDrawing(true);
565 m_page->settings()->setAccelerated2dCanvasEnabled(true);
567 #if ENABLE(VIEWPORT_REFLOW)
568 m_page->settings()->setTextReflowEnabled(m_webSettings->textReflowMode() == WebSettings::TextReflowEnabled);
571 m_page->settings()->setInteractiveFormValidationEnabled(true);
572 m_page->settings()->setAllowUniversalAccessFromFileURLs(false);
573 m_page->settings()->setAllowFileAccessFromFileURLs(false);
574 m_page->settings()->setShouldUseCrossOriginProtocolCheck(!m_webSettings->allowCrossSiteRequests());
575 m_page->settings()->setWebSecurityEnabled(!m_webSettings->allowCrossSiteRequests());
577 m_backingStoreClient = BackingStoreClient::create(m_mainFrame, /* parent frame */ 0, m_webPage);
578 // The direct access to BackingStore is left here for convenience since it
579 // is owned by BackingStoreClient and then deleted by its destructor.
580 m_backingStore = m_backingStoreClient->backingStore();
582 m_page->settings()->setSpatialNavigationEnabled(m_webSettings->isSpatialNavigationEnabled());
583 blockClickRadius = int(roundf(0.35 * Platform::Graphics::Screen::primaryScreen()->pixelsPerInch(0).width())); // The clicked rectangle area should be a fixed unit of measurement.
585 m_page->settings()->setDelegateSelectionPaint(true);
587 #if ENABLE(REQUEST_ANIMATION_FRAME)
588 m_page->windowScreenDidChange((PlatformDisplayID)0);
591 #if ENABLE(WEB_TIMING)
592 m_page->settings()->setMemoryInfoEnabled(true);
595 #if USE(ACCELERATED_COMPOSITING)
596 // The compositor will be needed for overlay rendering, so create it
597 // unconditionally. It will allocate OpenGL objects lazily, so this incurs
598 // no overhead in the unlikely case where the compositor is not needed.
599 Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
600 createMethodCallMessage(&WebPagePrivate::createCompositor, this));
604 class DeferredTaskLoadManualScript: public DeferredTask<&WebPagePrivate::m_wouldLoadManualScript> {
606 explicit DeferredTaskLoadManualScript(WebPagePrivate* webPagePrivate, const KURL& url)
607 : DeferredTaskType(webPagePrivate)
609 webPagePrivate->m_cachedManualScript = url;
612 virtual void performInternal(WebPagePrivate* webPagePrivate)
614 webPagePrivate->m_mainFrame->script()->executeIfJavaScriptURL(webPagePrivate->m_cachedManualScript, DoNotReplaceDocumentIfJavaScriptURL);
618 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)
621 DeferredTaskLoadManualScript::finishOrCancel(this);
623 String urlString(url);
624 if (urlString.startsWith("vs:", false)) {
625 urlString = urlString.substring(3);
626 m_mainFrame->setInViewSourceMode(true);
628 m_mainFrame->setInViewSourceMode(false);
630 KURL kurl = parseUrl(urlString);
631 if (protocolIs(kurl, "javascript")) {
632 // Never run javascript while loading is deferred.
633 if (m_page->defersLoading())
634 m_deferredTasks.append(adoptPtr(new DeferredTaskLoadManualScript(this, kurl)));
636 m_mainFrame->script()->executeIfJavaScriptURL(kurl, DoNotReplaceDocumentIfJavaScriptURL);
641 NetworkManager::instance()->setInitialURL(kurl);
643 ResourceRequest request(kurl);
644 request.setToken(networkToken);
645 if (isInitial || mustHandleInternally)
646 request.setMustHandleInternally(true);
647 request.setHTTPMethod(method);
648 request.setCachePolicy(toWebCoreCachePolicy(cachePolicy));
649 if (overrideContentType)
650 request.setOverrideContentType(overrideContentType);
653 request.setHTTPBody(FormData::create(data, dataLength));
655 for (unsigned i = 0; i + 1 < headersLength; i += 2)
656 request.addHTTPHeaderField(headers[i], headers[i + 1]);
659 request.setForceDownload(true);
661 request.setSuggestedSaveName(suggestedSaveName);
663 m_mainFrame->loader()->load(request, "" /* name */, false);
666 void WebPage::load(const char* url, const char* networkToken, bool isInitial)
668 d->load(url, networkToken, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, isInitial, false);
671 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)
673 d->load(url, networkToken, method, cachePolicy, data, dataLength, headers, headersLength, false, mustHandleInternally, false, "");
676 void WebPage::loadFile(const char* path, const char* overrideContentType)
678 std::string fileUrl(path);
679 if (!fileUrl.find("/"))
680 fileUrl.insert(0, "file://");
681 else if (fileUrl.find("file:///"))
684 d->load(fileUrl.c_str(), 0, "GET", Platform::NetworkRequest::UseProtocolCachePolicy, 0, 0, 0, 0, false, false, false, overrideContentType);
687 void WebPage::download(const Platform::NetworkRequest& request)
689 vector<const char*> headers;
690 Platform::NetworkRequest::HeaderList& list = request.getHeaderListRef();
691 for (unsigned i = 0; i < list.size(); i++) {
692 headers.push_back(list[i].first.c_str());
693 headers.push_back(list[i].second.c_str());
695 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());
698 void WebPagePrivate::loadString(const char* string, const char* baseURL, const char* contentType, const char* failingURL)
700 KURL kurl = parseUrl(baseURL);
701 ResourceRequest request(kurl);
702 WTF::RefPtr<SharedBuffer> buffer
703 = SharedBuffer::create(string, strlen(string));
704 SubstituteData substituteData(buffer,
705 extractMIMETypeFromMediaType(contentType),
706 extractCharsetFromMediaType(contentType),
707 failingURL ? parseUrl(failingURL) : KURL());
708 m_mainFrame->loader()->load(request, substituteData, false);
711 void WebPage::loadString(const char* string, const char* baseURL, const char* mimeType, const char* failingURL)
713 d->loadString(string, baseURL, mimeType, failingURL);
716 bool WebPagePrivate::executeJavaScript(const char* scriptUTF8, JavaScriptDataType& returnType, WebString& returnValue)
718 String script = String::fromUTF8(scriptUTF8);
720 if (script.isNull()) {
721 returnType = JSException;
725 if (script.isEmpty()) {
726 returnType = JSUndefined;
730 ScriptValue result = m_mainFrame->script()->executeScript(script, false);
731 JSC::JSValue value = result.jsValue();
733 returnType = JSException;
737 JSC::ExecState* exec = m_mainFrame->script()->globalObject(mainThreadNormalWorld())->globalExec();
738 JSGlobalContextRef context = toGlobalRef(exec);
740 JSType type = JSValueGetType(context, toRef(exec, value));
747 returnType = JSBoolean;
750 returnType = JSNumber;
753 returnType = JSString;
756 returnType = JSObject;
758 case kJSTypeUndefined:
760 returnType = JSUndefined;
764 if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
765 String str = result.toString(exec);
766 returnValue = WebString(str.impl());
772 bool WebPage::executeJavaScript(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
774 return d->executeJavaScript(script, returnType, returnValue);
777 bool WebPagePrivate::executeJavaScriptInIsolatedWorld(const ScriptSourceCode& sourceCode, JavaScriptDataType& returnType, WebString& returnValue)
779 if (!m_isolatedWorld)
780 m_isolatedWorld = m_mainFrame->script()->createWorld();
782 // Use evaluateInWorld to avoid canExecuteScripts check.
783 ScriptValue result = m_mainFrame->script()->evaluateInWorld(sourceCode, m_isolatedWorld.get());
784 JSC::JSValue value = result.jsValue();
786 returnType = JSException;
790 JSC::ExecState* exec = m_mainFrame->script()->globalObject(m_isolatedWorld.get())->globalExec();
791 JSGlobalContextRef context = toGlobalRef(exec);
793 JSType type = JSValueGetType(context, toRef(exec, value));
800 returnType = JSBoolean;
803 returnType = JSNumber;
806 returnType = JSString;
809 returnType = JSObject;
811 case kJSTypeUndefined:
813 returnType = JSUndefined;
817 if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
818 String str = result.toString(exec);
819 returnValue = WebString(str.impl());
825 bool WebPage::executeJavaScriptInIsolatedWorld(const std::wstring& script, JavaScriptDataType& returnType, WebString& returnValue)
827 // On our platform wchar_t is unsigned int and UChar is unsigned short
828 // so we have to convert using ICU conversion function
829 int lengthCopied = 0;
830 UErrorCode error = U_ZERO_ERROR;
831 const int length = script.length() + 1 /*null termination char*/;
834 // FIXME: PR 138162 is giving U_INVALID_CHAR_FOUND error.
835 u_strFromUTF32(data, length, &lengthCopied, reinterpret_cast<const UChar32*>(script.c_str()), script.length(), &error);
836 BLACKBERRY_ASSERT(error == U_ZERO_ERROR);
837 if (error != U_ZERO_ERROR) {
838 Platform::logAlways(Platform::LogLevelCritical, "WebPage::executeJavaScriptInIsolatedWorld failed to convert UTF16 to JavaScript!");
841 String str = String(data, lengthCopied);
842 ScriptSourceCode sourceCode(str, KURL());
843 return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
846 bool WebPage::executeJavaScriptInIsolatedWorld(const char* script, JavaScriptDataType& returnType, WebString& returnValue)
848 ScriptSourceCode sourceCode(String::fromUTF8(script), KURL());
849 return d->executeJavaScriptInIsolatedWorld(sourceCode, returnType, returnValue);
852 bool WebPage::executeJavaScriptFunction(const std::vector<std::string> &function, const std::vector<std::string> &args, JavaScriptDataType& returnType, WebString& returnValue)
856 JSC::Bindings::RootObject* root = d->m_mainFrame->script()->bindingRootObject();
859 JSC::ExecState* exec = root->globalObject()->globalExec();
860 JSGlobalContextRef ctx = toGlobalRef(exec);
862 WTF::Vector<JSStringRef> argList(args.size());
863 WTF::Vector<JSValueRef> argListRef(args.size());
864 for (unsigned i = 0; i < args.size(); ++i) {
865 JSStringRef str = JSStringCreateWithUTF8CString(args[i].c_str());
867 JSValueRef strRef = JSValueMakeString(ctx, str);
868 argListRef[i] = strRef;
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);
888 for (unsigned i = 0; i < args.size(); ++i)
889 JSStringRelease(argList[i]);
891 JSC::JSValue value = toJS(exec, result);
894 returnType = JSException;
898 JSType type = JSValueGetType(ctx, result);
905 returnType = JSBoolean;
908 returnType = JSNumber;
911 returnType = JSString;
914 returnType = JSObject;
916 case kJSTypeUndefined:
918 returnType = JSUndefined;
922 if (returnType == JSBoolean || returnType == JSNumber || returnType == JSString || returnType == JSObject) {
923 JSStringRef stringRef = JSValueToStringCopy(ctx, result, 0);
924 size_t bufferSize = JSStringGetMaximumUTF8CStringSize(stringRef);
925 WTF::Vector<char> buffer(bufferSize);
926 JSStringGetUTF8CString(stringRef, buffer.data(), bufferSize);
927 returnValue = WebString::fromUtf8(buffer.data());
933 void WebPagePrivate::stopCurrentLoad()
935 // This function should contain all common code triggered by WebPage::load
936 // (which stops any load in progress before starting the new load) and
937 // WebPage::stoploading (the entry point for the client to stop the load
938 // explicitly). If it should only be done while stopping the load
939 // explicitly, it goes in WebPage::stopLoading, not here.
940 m_mainFrame->loader()->stopAllLoaders();
942 // Cancel any deferred script that hasn't been processed yet.
943 DeferredTaskLoadManualScript::finishOrCancel(this);
946 void WebPage::stopLoading()
948 d->stopCurrentLoad();
951 static void closeURLRecursively(Frame* frame)
953 // Do not create more frame please.
954 FrameLoaderClientBlackBerry* frameLoaderClient = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client());
955 frameLoaderClient->suppressChildFrameCreation();
957 frame->loader()->closeURL();
959 Vector<RefPtr<Frame>, 10> childFrames;
961 for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
962 childFrames.append(childFrame);
964 unsigned size = childFrames.size();
965 for (unsigned i = 0; i < size; i++)
966 closeURLRecursively(childFrames[i].get());
969 void WebPagePrivate::prepareToDestroy()
971 // Before the client starts tearing itself down, dispatch the unload event
972 // so it can take effect while all the client's state (e.g. scroll position)
974 closeURLRecursively(m_mainFrame);
977 void WebPage::prepareToDestroy()
979 d->prepareToDestroy();
982 static void enableCrossSiteXHRRecursively(Frame* frame)
984 frame->document()->securityOrigin()->grantUniversalAccess();
986 Vector<RefPtr<Frame>, 10> childFrames;
987 for (RefPtr<Frame> childFrame = frame->tree()->firstChild(); childFrame; childFrame = childFrame->tree()->nextSibling())
988 childFrames.append(childFrame);
990 unsigned size = childFrames.size();
991 for (unsigned i = 0; i < size; i++)
992 enableCrossSiteXHRRecursively(childFrames[i].get());
995 void WebPagePrivate::enableCrossSiteXHR()
997 enableCrossSiteXHRRecursively(m_mainFrame);
1000 void WebPage::enableCrossSiteXHR()
1002 d->enableCrossSiteXHR();
1005 void WebPagePrivate::setLoadState(LoadState state)
1007 if (m_loadState == state)
1010 bool isFirstLoad = m_loadState == None;
1012 // See RIM Bug #1068.
1013 if (state == Finished && m_mainFrame && m_mainFrame->document())
1014 m_mainFrame->document()->updateStyleIfNeeded();
1016 m_loadState = state;
1018 #if DEBUG_WEBPAGE_LOAD
1019 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::setLoadState %d", state);
1022 switch (m_loadState) {
1025 // Paints the visible backingstore as white to prevent initial checkerboard on
1027 if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
1028 m_backingStore->d->blitVisibleContents();
1033 unscheduleZoomAboutPoint();
1035 #if ENABLE(ACCELERATED_2D_CANVAS)
1036 if (m_page->settings()->canvasUsesAcceleratedDrawing()) {
1037 // Free GPU resources as we're on a new page.
1038 // This will help us to free memory pressure.
1039 SharedGraphicsContext3D::get()->makeContextCurrent();
1040 GrContext* grContext = Platform::Graphics::getGrContext();
1041 grContext->freeGpuResources();
1045 #if USE(ACCELERATED_COMPOSITING)
1046 if (isAcceleratedCompositingActive()) {
1047 Platform::userInterfaceThreadMessageClient()->dispatchSyncMessage(
1048 Platform::createMethodCallMessage(&WebPagePrivate::destroyLayerResources, this));
1051 // Suspend screen update to avoid ui thread blitting while resetting backingstore.
1052 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1054 m_previousContentsSize = IntSize();
1055 m_backingStore->d->resetRenderQueue();
1056 m_backingStore->d->resetTiles(true /* resetBackground */);
1057 m_backingStore->d->setScrollingOrZooming(false, false /* shouldBlit */);
1058 m_shouldZoomToInitialScaleAfterLoadFinished = false;
1059 m_userPerformedManualZoom = false;
1060 m_userPerformedManualScroll = false;
1061 m_shouldUseFixedDesktopMode = false;
1062 if (m_resetVirtualViewportOnCommitted) { // For DRT.
1063 m_virtualViewportWidth = 0;
1064 m_virtualViewportHeight = 0;
1066 if (m_webSettings->viewportWidth() > 0) {
1067 m_virtualViewportWidth = m_webSettings->viewportWidth();
1068 m_virtualViewportHeight = m_defaultLayoutSize.height();
1070 // Check if we have already process the meta viewport tag, this only happens on history navigation.
1071 // For back/forward history navigation, we should only keep these previous values if the document
1072 // has the meta viewport tag when the state is Committed in setLoadState.
1073 // Refreshing should keep these previous values as well.
1074 static ViewportArguments defaultViewportArguments;
1075 bool documentHasViewportArguments = false;
1076 FrameLoadType frameLoadType = FrameLoadTypeStandard;
1077 if (m_mainFrame && m_mainFrame->document() && m_mainFrame->document()->viewportArguments() != defaultViewportArguments)
1078 documentHasViewportArguments = true;
1079 if (m_mainFrame && m_mainFrame->loader())
1080 frameLoadType = m_mainFrame->loader()->loadType();
1081 if (!((m_didRestoreFromPageCache && documentHasViewportArguments) || (frameLoadType == FrameLoadTypeReload || frameLoadType == FrameLoadTypeReloadFromOrigin))) {
1082 m_viewportArguments = ViewportArguments();
1083 m_userScalable = m_webSettings->isUserScalable();
1086 // At the moment we commit a new load, set the viewport arguments
1087 // to any fallback values. If there is a meta viewport in the
1088 // content it will overwrite the fallback arguments soon.
1089 dispatchViewportPropertiesDidChange(m_userViewportArguments);
1091 IntSize virtualViewport = recomputeVirtualViewportFromViewportArguments();
1092 m_webPage->setVirtualViewportSize(virtualViewport.width(), virtualViewport.height());
1095 #if ENABLE(EVENT_MODE_METATAGS)
1096 didReceiveCursorEventMode(ProcessedCursorEvents);
1097 didReceiveTouchEventMode(ProcessedTouchEvents);
1100 // If it's a outmost SVG document, we use FixedDesktop mode, otherwise
1101 // we default to Mobile mode. For example, using FixedDesktop mode to
1102 // render http://www.croczilla.com/bits_and_pieces/svg/samples/tiger/tiger.svg
1103 // is user-experience friendly.
1104 if (m_page->mainFrame()->document()->isSVGDocument()) {
1105 setShouldUseFixedDesktopMode(true);
1106 setViewMode(FixedDesktop);
1108 setViewMode(Mobile);
1110 // Reset block zoom and reflow.
1112 #if ENABLE(VIEWPORT_REFLOW)
1113 toggleTextReflowIfEnabledForBlockZoomOnly();
1116 // Notify InputHandler of state change.
1117 m_inputHandler->setInputModeEnabled(false);
1119 // Set the scroll to origin here and notify the client since we'll be
1120 // zooming below without any real contents yet thus the contents size
1121 // we report to the client could make our current scroll position invalid.
1122 setScrollPosition(IntPoint::zero());
1123 notifyTransformedScrollChanged();
1125 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1127 // Paints the visible backingstore as white. Note it is important we do
1128 // this strictly after re-setting the scroll position to origin and resetting
1129 // the scales otherwise the visible contents calculation is wrong and we
1130 // can end up blitting artifacts instead. See: RIM Bug #401.
1131 if (m_backingStore->d->renderVisibleContents() && !m_backingStore->d->isSuspended() && !m_backingStore->d->shouldDirectRenderingToWindow())
1132 m_backingStore->d->blitVisibleContents();
1134 zoomToInitialScaleOnLoad();
1136 // Update cursor status.
1139 #if USE(ACCELERATED_COMPOSITING)
1140 // Don't render compositing contents from previous page.
1141 resetCompositingSurface();
1147 // Notify client of the initial zoom change.
1148 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1149 m_backingStore->d->updateTiles(true /* updateVisible */, false /* immediate */);
1156 double WebPagePrivate::clampedScale(double scale) const
1158 if (scale < minimumScale())
1159 return minimumScale();
1160 if (scale > maximumScale())
1161 return maximumScale();
1165 bool WebPagePrivate::shouldZoomAboutPoint(double scale, const FloatPoint&, bool enforceScaleClamping, double* clampedScale)
1167 if (!m_mainFrame->view())
1170 if (enforceScaleClamping)
1171 scale = this->clampedScale(scale);
1173 ASSERT(clampedScale);
1174 *clampedScale = scale;
1176 if (currentScale() == scale) {
1177 // Make sure backingstore updates resume from pinch zoom in the case where the final zoom level doesn't change.
1178 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1179 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1186 bool WebPagePrivate::zoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering, bool isRestoringZoomLevel)
1188 if (!isRestoringZoomLevel) {
1189 // Clear any existing block zoom. (If we are restoring a saved zoom level on page load,
1190 // there is guaranteed to be no existing block zoom and we don't want to clear m_shouldReflowBlock.)
1194 // The reflow and block zoom stuff here needs to happen regardless of
1195 // whether we shouldZoomAboutPoint.
1196 #if ENABLE(VIEWPORT_REFLOW)
1197 toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
1198 if (m_page->settings()->isTextReflowEnabled() && m_mainFrame->view())
1203 if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1204 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1205 m_currentPinchZoomNode = 0;
1206 m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1210 TransformationMatrix zoom;
1213 #if DEBUG_WEBPAGE_LOAD
1214 if (loadState() < Finished)
1215 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomAboutPoint scale %f anchor (%f, %f)", scale, anchor.x(), anchor.y());
1218 // Our current scroll position in float.
1219 FloatPoint scrollPosition = this->scrollPosition();
1221 // Anchor offset from scroll position in float.
1222 FloatPoint anchorOffset(anchor.x() - scrollPosition.x(), anchor.y() - scrollPosition.y());
1224 // The horizontal scaling factor and vertical scaling factor should be equal
1225 // to preserve aspect ratio of content.
1226 ASSERT(m_transformationMatrix->m11() == m_transformationMatrix->m22());
1228 // Need to invert the previous transform to anchor the viewport.
1229 double inverseScale = scale / m_transformationMatrix->m11();
1232 *m_transformationMatrix = zoom;
1234 // Suspend all screen updates to the backingstore.
1235 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1237 updateViewportSize();
1239 IntPoint newScrollPosition(IntPoint(max(0, static_cast<int>(roundf(anchor.x() - anchorOffset.x() / inverseScale))),
1240 max(0, static_cast<int>(roundf(anchor.y() - anchorOffset.y() / inverseScale)))));
1242 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled) {
1243 // This is a hack for email which has reflow always turned on.
1244 m_mainFrame->view()->setNeedsLayout();
1245 requestLayoutIfNeeded();
1246 if (m_currentPinchZoomNode)
1247 newScrollPosition = calculateReflowedScrollPosition(anchorOffset, scale == minimumScale() ? 1 : inverseScale);
1248 m_currentPinchZoomNode = 0;
1249 m_anchorInNodeRectRatio = FloatPoint(-1, -1);
1252 setScrollPosition(newScrollPosition);
1254 notifyTransformChanged();
1256 bool isLoading = this->isLoading();
1258 // We need to invalidate all tiles both visible and non-visible if we're loading.
1259 m_backingStore->d->updateTiles(isLoading /* updateVisible */, false /* immediate */);
1261 m_client->resetBitmapZoomScale(m_transformationMatrix->m11());
1263 bool shouldRender = !isLoading || m_userPerformedManualZoom || forceRendering;
1264 bool shouldClearVisibleZoom = isLoading && shouldRender;
1266 if (shouldClearVisibleZoom) {
1267 // If we are loading and rendering then we need to clear the render queue's
1268 // visible zoom jobs as they will be irrelevant with the render below.
1269 m_backingStore->d->clearVisibleZoom();
1272 // Clear window to make sure there are no artifacts.
1274 m_backingStore->d->clearWindow();
1275 // Resume all screen updates to the backingstore and render+blit visible contents to screen.
1276 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
1278 // Resume all screen updates to the backingstore but do not blit to the screen because we not rendering.
1279 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1282 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
1287 IntPoint WebPagePrivate::calculateReflowedScrollPosition(const FloatPoint& anchorOffset, double inverseScale)
1289 // Should only be invoked when text reflow is enabled.
1290 ASSERT(m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled);
1295 IntRect nodeRect = rectForNode(m_currentPinchZoomNode.get());
1297 if (m_currentPinchZoomNode->renderer() && m_anchorInNodeRectRatio.y() >= 0) {
1298 offsetY = nodeRect.height() * m_anchorInNodeRectRatio.y();
1299 if (m_currentPinchZoomNode->renderer()->isImage() && m_anchorInNodeRectRatio.x() > 0)
1300 offsetX = nodeRect.width() * m_anchorInNodeRectRatio.x() - anchorOffset.x() / inverseScale;
1303 IntRect reflowedRect = adjustRectOffsetForFrameOffset(nodeRect, m_currentPinchZoomNode.get());
1305 return IntPoint(max(0, static_cast<int>(roundf(reflowedRect.x() + offsetX))),
1306 max(0, static_cast<int>(roundf(reflowedRect.y() + offsetY - anchorOffset.y() / inverseScale))));
1309 bool WebPagePrivate::scheduleZoomAboutPoint(double unclampedScale, const FloatPoint& anchor, bool enforceScaleClamping, bool forceRendering)
1312 if (!shouldZoomAboutPoint(unclampedScale, anchor, enforceScaleClamping, &scale)) {
1313 // We could be back to the right zoom level before the timer has
1314 // timed out, because of wiggling back and forth. Stop the timer.
1315 unscheduleZoomAboutPoint();
1319 // For some reason, the bitmap zoom wants an anchor in backingstore coordinates!
1320 // this is different from zoomAboutPoint, which wants content coordinates.
1321 // See RIM Bug #641.
1323 FloatPoint transformedAnchor = mapToTransformedFloatPoint(anchor);
1324 FloatPoint transformedScrollPosition = mapToTransformedFloatPoint(scrollPosition());
1326 // Prohibit backingstore from updating the window overtop of the bitmap.
1327 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
1329 // Need to invert the previous transform to anchor the viewport.
1330 double zoomFraction = scale / transformationMatrix()->m11();
1332 // Anchor offset from scroll position in float.
1333 FloatPoint anchorOffset(transformedAnchor.x() - transformedScrollPosition.x(),
1334 transformedAnchor.y() - transformedScrollPosition.y());
1337 static_cast<int>(roundf(transformedAnchor.x() - anchorOffset.x() / zoomFraction)),
1338 static_cast<int>(roundf(transformedAnchor.y() - anchorOffset.y() / zoomFraction)));
1340 const IntRect viewportRect = IntRect(IntPoint::zero(), transformedViewportSize());
1341 const IntRect dstRect = viewportRect;
1343 // This is the rect to pass as the actual source rect in the backingstore
1344 // for the transform given by zoom.
1345 IntRect srcRect(srcPoint.x(),
1347 viewportRect.width() / zoomFraction,
1348 viewportRect.height() / zoomFraction);
1349 m_backingStore->d->blitContents(dstRect, srcRect);
1351 m_delayedZoomArguments.scale = scale;
1352 m_delayedZoomArguments.anchor = anchor;
1353 m_delayedZoomArguments.enforceScaleClamping = enforceScaleClamping;
1354 m_delayedZoomArguments.forceRendering = forceRendering;
1355 m_delayedZoomTimer->startOneShot(delayedZoomInterval);
1360 void WebPagePrivate::unscheduleZoomAboutPoint()
1362 if (m_delayedZoomTimer->isActive())
1363 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::None);
1365 m_delayedZoomTimer->stop();
1368 void WebPagePrivate::zoomAboutPointTimerFired(Timer<WebPagePrivate>*)
1370 zoomAboutPoint(m_delayedZoomArguments.scale, m_delayedZoomArguments.anchor, m_delayedZoomArguments.enforceScaleClamping, m_delayedZoomArguments.forceRendering);
1373 void WebPagePrivate::setNeedsLayout()
1375 FrameView* view = m_mainFrame->view();
1377 view->setNeedsLayout();
1380 void WebPagePrivate::requestLayoutIfNeeded() const
1382 FrameView* view = m_mainFrame->view();
1384 view->updateLayoutAndStyleIfNeededRecursive();
1385 ASSERT(!view->needsLayout());
1388 IntPoint WebPagePrivate::scrollPosition() const
1390 return m_backingStoreClient->scrollPosition();
1393 IntPoint WebPagePrivate::maximumScrollPosition() const
1395 return m_backingStoreClient->maximumScrollPosition();
1398 void WebPagePrivate::setScrollPosition(const IntPoint& pos)
1400 m_backingStoreClient->setScrollPosition(pos);
1403 // Setting the scroll position is in transformed coordinates.
1404 void WebPage::setScrollPosition(const Platform::IntPoint& point)
1406 if (d->transformedPointEqualsUntransformedPoint(point, d->scrollPosition()))
1409 // If the user recently performed an event, this new scroll position
1410 // could possibly be a result of that. Or not, this is just a heuristic.
1411 if (currentTime() - d->m_lastUserEventTimestamp < manualScrollInterval)
1412 d->m_userPerformedManualScroll = true;
1414 d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1416 // UI thread can call BackingStorePrivate::setScrollingOrZooming(false) before WebKit thread calls WebPage::setScrollPosition(),
1417 // in which case it will set ScrollableArea::m_constrainsScrollingToContentEdge to true earlier.
1418 // We can cache ScrollableArea::m_constrainsScrollingToContentEdge and always set it to false before we set scroll position in
1419 // WebKit thread to avoid scroll position clamping during scrolling, and restore it to what it was after that.
1420 bool constrainsScrollingToContentEdge = d->m_mainFrame->view()->constrainsScrollingToContentEdge();
1421 d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(false);
1422 d->setScrollPosition(d->mapFromTransformed(point));
1423 d->m_mainFrame->view()->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdge);
1425 d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1428 bool WebPagePrivate::shouldSendResizeEvent()
1430 if (!m_mainFrame->document())
1433 // PR#96865 : Provide an option to always send resize events, regardless of the loading
1434 // status. The scenario for this are Sapphire applications which tend to
1435 // maintain an open GET request to the server. This open GET results in
1436 // webkit thinking that content is still arriving when at the application
1437 // level it is considered fully loaded.
1439 // NOTE: Care must be exercised in the use of this option, as it bypasses
1440 // the sanity provided in 'isLoadingInAPISense()' below.
1442 static const bool unrestrictedResizeEvents = Platform::Settings::instance()->unrestrictedResizeEvents();
1443 if (unrestrictedResizeEvents)
1446 // Don't send the resize event if the document is loading. Some pages automatically reload
1447 // when the window is resized; Safari on iPhone often resizes the window while setting up its
1448 // viewport. This obviously can cause problems.
1449 DocumentLoader* documentLoader = m_mainFrame->loader()->documentLoader();
1450 if (documentLoader && documentLoader->isLoadingInAPISense())
1456 void WebPagePrivate::willDeferLoading()
1458 m_deferredTasksTimer.stop();
1459 m_client->willDeferLoading();
1462 void WebPagePrivate::didResumeLoading()
1464 if (!m_deferredTasks.isEmpty())
1465 m_deferredTasksTimer.startOneShot(0);
1466 m_client->didResumeLoading();
1469 void WebPagePrivate::deferredTasksTimerFired(WebCore::Timer<WebPagePrivate>*)
1471 ASSERT(!m_deferredTasks.isEmpty());
1472 if (!m_deferredTasks.isEmpty())
1475 OwnPtr<DeferredTaskBase> task = m_deferredTasks[0].release();
1476 m_deferredTasks.remove(0);
1478 if (!m_deferredTasks.isEmpty())
1479 m_deferredTasksTimer.startOneShot(0);
1481 task->perform(this);
1484 bool WebPagePrivate::scrollBy(int deltaX, int deltaY, bool scrollMainFrame)
1486 IntSize delta(deltaX, deltaY);
1487 if (!scrollMainFrame) {
1488 // We need to work around the fact that ::map{To,From}Transformed do not
1489 // work well with negative values, like a negative width or height of an IntSize.
1490 IntSize copiedDelta(IntSize(abs(delta.width()), abs(delta.height())));
1491 IntSize untransformedCopiedDelta = mapFromTransformed(copiedDelta);
1493 delta.width() < 0 ? -untransformedCopiedDelta.width() : untransformedCopiedDelta.width(),
1494 delta.height() < 0 ? -untransformedCopiedDelta.height(): untransformedCopiedDelta.height());
1496 if (m_inRegionScrollStartingNode) {
1497 if (scrollNodeRecursively(m_inRegionScrollStartingNode.get(), delta)) {
1498 m_selectionHandler->selectionPositionChanged();
1499 // FIXME: We have code in place to handle scrolling and clipping tap highlight
1500 // on in-region scrolling. As soon as it is fast enough (i.e. we have it backed by
1501 // a backing store), we can reliably make use of it in the real world.
1502 // m_touchEventHandler->drawTapHighlight();
1510 setScrollPosition(scrollPosition() + delta);
1514 bool WebPage::scrollBy(const Platform::IntSize& delta, bool scrollMainFrame)
1516 d->m_backingStoreClient->setIsClientGeneratedScroll(true);
1517 bool b = d->scrollBy(delta.width(), delta.height(), scrollMainFrame);
1518 d->m_backingStoreClient->setIsClientGeneratedScroll(false);
1522 void WebPagePrivate::notifyInRegionScrollStatusChanged(bool status)
1524 if (!status && m_inRegionScrollStartingNode) {
1525 enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(m_inRegionScrollStartingNode.get());
1526 m_inRegionScrollStartingNode = 0;
1530 void WebPage::notifyInRegionScrollStatusChanged(bool status)
1532 d->notifyInRegionScrollStatusChanged(status);
1535 void WebPagePrivate::enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(Node* scrolledNode)
1537 ASSERT(scrolledNode);
1538 if (scrolledNode->isDocumentNode()) {
1539 Frame* frame = static_cast<const Document*>(scrolledNode)->frame();
1543 ASSERT(frame != m_mainFrame);
1544 FrameView* view = frame->view();
1549 // #1 - Get frame rect in contents coords.
1550 // #2 - Get the clipped scrollview rect in contents coords.
1551 // #3 - Take transform into account for 1 and 2.
1552 // #4 - Subtract 2 from 1, so we know exactly which areas of the frame
1553 // are offscreen, and need async repainting.
1554 FrameView* mainFrameView = m_mainFrame->view();
1555 ASSERT(mainFrameView);
1556 IntRect frameRect = view->frameRect();
1557 frameRect = frame->tree()->parent()->view()->contentsToWindow(frameRect);
1558 frameRect = mainFrameView->windowToContents(frameRect);
1560 IntRect visibleWindowRect = getRecursiveVisibleWindowRect(view);
1561 IntRect visibleContentsRect = mainFrameView->windowToContents(visibleWindowRect);
1563 IntRect transformedFrameRect = mapToTransformed(frameRect);
1564 IntRect transformedVisibleContentsRect = mapToTransformed(visibleContentsRect);
1566 Platform::IntRectRegion offscreenRegionOfIframe
1567 = Platform::IntRectRegion::subtractRegions(Platform::IntRect(transformedFrameRect), Platform::IntRect(transformedVisibleContentsRect));
1569 if (!offscreenRegionOfIframe.isEmpty())
1570 m_backingStore->d->m_renderQueue->addToQueue(RenderQueue::RegularRender, offscreenRegionOfIframe.rects());
1574 void WebPagePrivate::setHasInRegionScrollableAreas(bool b)
1576 if (b != m_hasInRegionScrollableAreas)
1577 m_hasInRegionScrollableAreas = b;
1580 IntSize WebPagePrivate::viewportSize() const
1582 return mapFromTransformed(transformedViewportSize());
1585 IntSize WebPagePrivate::actualVisibleSize() const
1587 return mapFromTransformed(transformedActualVisibleSize());
1590 bool WebPagePrivate::hasVirtualViewport() const
1592 return m_virtualViewportWidth && m_virtualViewportHeight;
1595 void WebPagePrivate::updateViewportSize(bool setFixedReportedSize, bool sendResizeEvent)
1597 ASSERT(m_mainFrame->view());
1598 if (setFixedReportedSize)
1599 m_mainFrame->view()->setFixedReportedSize(actualVisibleSize());
1601 IntRect frameRect = IntRect(scrollPosition(), viewportSize());
1602 if (frameRect != m_mainFrame->view()->frameRect()) {
1603 m_mainFrame->view()->setFrameRect(frameRect);
1604 m_mainFrame->view()->adjustViewSize();
1606 #if ENABLE(FULLSCREEN_API)
1607 // If we are in fullscreen video mode, and we change the FrameView::viewportRect,
1608 // we need to adjust the media container to the new size.
1609 if (m_fullscreenVideoNode) {
1610 Document* document = m_fullscreenVideoNode->document();
1612 ASSERT(document->fullScreenRenderer());
1614 int width = m_mainFrame->view()->visibleContentRect().size().width();
1615 document->fullScreenRenderer()->style()->setWidth(Length(width, Fixed));
1620 // We're going to need to send a resize event to JavaScript because
1621 // innerWidth and innerHeight depend on fixed reported size.
1622 // This is how we support mobile pages where JavaScript resizes
1623 // the page in order to get around the fixed layout size, e.g.
1624 // google maps when it detects a mobile user agent.
1625 if (sendResizeEvent && shouldSendResizeEvent())
1626 m_mainFrame->eventHandler()->sendResizeEvent();
1628 // When the actual visible size changes, we also
1629 // need to reposition fixed elements.
1630 m_mainFrame->view()->repaintFixedElementsAfterScrolling();
1633 FloatPoint WebPagePrivate::centerOfVisibleContentsRect() const
1635 // The visible contents rect in float.
1636 FloatRect visibleContentsRect = this->visibleContentsRect();
1638 // The center of the visible contents rect in float.
1639 return FloatPoint(visibleContentsRect.x() + visibleContentsRect.width() / 2.0,
1640 visibleContentsRect.y() + visibleContentsRect.height() / 2.0);
1643 IntRect WebPagePrivate::visibleContentsRect() const
1645 return m_backingStoreClient->visibleContentsRect();
1648 IntSize WebPagePrivate::contentsSize() const
1650 if (!m_mainFrame->view())
1653 return m_backingStoreClient->contentsSize();
1656 IntSize WebPagePrivate::absoluteVisibleOverflowSize() const
1658 if (!m_mainFrame->contentRenderer())
1661 return IntSize(m_mainFrame->contentRenderer()->rightAbsoluteVisibleOverflow(), m_mainFrame->contentRenderer()->bottomAbsoluteVisibleOverflow());
1664 void WebPagePrivate::contentsSizeChanged(const IntSize& contentsSize)
1666 if (m_previousContentsSize == contentsSize)
1669 // This should only occur in the middle of layout so we set a flag here and
1670 // handle it at the end of the layout.
1671 m_contentsSizeChanged = true;
1673 #if DEBUG_WEBPAGE_LOAD
1674 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::contentsSizeChanged %dx%d", contentsSize.width(), contentsSize.height());
1678 void WebPagePrivate::layoutFinished()
1680 if (!m_contentsSizeChanged && !m_overflowExceedsContentsSize)
1683 m_contentsSizeChanged = false; // Toggle to turn off notification again.
1684 m_overflowExceedsContentsSize = false;
1686 if (contentsSize().isEmpty())
1689 // The call to zoomToInitialScaleOnLoad can cause recursive layout when called from
1690 // the middle of a layout, but the recursion is limited by detection code in
1691 // setViewMode() and mitigation code in fixedLayoutSize().
1692 if (didLayoutExceedMaximumIterations()) {
1693 notifyTransformedContentsSizeChanged();
1697 // Temporarily save the m_previousContentsSize here before updating it (in
1698 // notifyTransformedContentsSizeChanged()) so we can compare if our contents
1699 // shrunk afterwards.
1700 IntSize previousContentsSize = m_previousContentsSize;
1702 m_nestedLayoutFinishedCount++;
1704 if (shouldZoomToInitialScaleOnLoad()) {
1705 zoomToInitialScaleOnLoad();
1706 m_shouldZoomToInitialScaleAfterLoadFinished = false;
1707 } else if (loadState() != None)
1708 notifyTransformedContentsSizeChanged();
1710 m_nestedLayoutFinishedCount--;
1712 if (!m_nestedLayoutFinishedCount) {
1713 // When the contents shrinks, there is a risk that we
1714 // will be left at a scroll position that lies outside of the
1715 // contents rect. Since we allow overscrolling and neglect
1716 // to clamp overscroll in order to retain input focus (RIM Bug #414)
1717 // we need to clamp somewhere, and this is where we know the
1718 // contents size has changed.
1720 if (contentsSize() != previousContentsSize) {
1722 IntPoint newScrollPosition = scrollPosition();
1724 if (contentsSize().height() < previousContentsSize.height()) {
1725 IntPoint scrollPositionWithHeightShrunk = IntPoint(newScrollPosition.x(), maximumScrollPosition().y());
1726 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithHeightShrunk);
1729 if (contentsSize().width() < previousContentsSize.width()) {
1730 IntPoint scrollPositionWithWidthShrunk = IntPoint(maximumScrollPosition().x(), newScrollPosition.y());
1731 newScrollPosition = newScrollPosition.shrunkTo(scrollPositionWithWidthShrunk);
1734 if (newScrollPosition != scrollPosition()) {
1735 setScrollPosition(newScrollPosition);
1736 notifyTransformedScrollChanged();
1742 void WebPagePrivate::zoomToInitialScaleOnLoad()
1744 #if DEBUG_WEBPAGE_LOAD
1745 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad");
1748 bool needsLayout = false;
1750 // If the contents width exceeds the viewport width set to desktop mode.
1751 if (m_shouldUseFixedDesktopMode)
1752 needsLayout = setViewMode(FixedDesktop);
1754 needsLayout = setViewMode(Desktop);
1757 // This can cause recursive layout...
1761 if (contentsSize().isEmpty()) {
1762 #if DEBUG_WEBPAGE_LOAD
1763 Platform::log(Platform::LogLevelInfo, "WebPagePrivate::zoomToInitialScaleOnLoad content is empty!");
1765 requestLayoutIfNeeded();
1766 m_client->resetBitmapZoomScale(currentScale());
1767 notifyTransformedContentsSizeChanged();
1771 bool performedZoom = false;
1772 bool shouldZoom = !m_userPerformedManualZoom;
1774 // If this load should restore view state, don't zoom to initial scale
1775 // but instead let the HistoryItem's saved viewport reign supreme.
1776 if (m_mainFrame && m_mainFrame->loader() && m_mainFrame->loader()->shouldRestoreScrollPositionAndViewState())
1779 if (shouldZoom && shouldZoomToInitialScaleOnLoad()) {
1780 // Preserve at top and at left position, to avoid scrolling
1781 // to a non top-left position for web page with viewport meta tag
1782 // that specifies an initial-scale that is zoomed in.
1783 FloatPoint anchor = centerOfVisibleContentsRect();
1784 if (!scrollPosition().x())
1786 if (!scrollPosition().y())
1788 performedZoom = zoomAboutPoint(initialScale(), anchor);
1791 // zoomAboutPoint above can also toggle setNeedsLayout and cause recursive layout...
1792 requestLayoutIfNeeded();
1794 if (!performedZoom) {
1795 // We only notify if we didn't perform zoom, because zoom will notify on
1797 m_client->resetBitmapZoomScale(currentScale());
1798 notifyTransformedContentsSizeChanged();
1802 double WebPagePrivate::zoomToFitScale() const
1804 int contentWidth = contentsSize().width();
1805 int contentHeight = contentsSize().height();
1806 double zoomToFitScale = contentWidth > 0.0 ? static_cast<double>(m_actualVisibleWidth) / contentWidth : 1.0;
1807 if (contentHeight * zoomToFitScale < static_cast<double>(m_defaultLayoutSize.height()))
1808 zoomToFitScale = contentHeight > 0 ? static_cast<double>(m_defaultLayoutSize.height()) / contentHeight : 1.0;
1810 return std::max(zoomToFitScale, minimumZoomToFitScale);
1813 double WebPage::zoomToFitScale() const
1815 return d->zoomToFitScale();
1818 double WebPagePrivate::initialScale() const
1820 if (m_initialScale > 0.0)
1821 return m_initialScale;
1823 if (m_webSettings->isZoomToFitOnLoad())
1824 return zoomToFitScale();
1829 double WebPage::initialScale() const
1831 return d->initialScale();
1834 void WebPage::initializeIconDataBase()
1836 IconDatabaseClientBlackBerry::getInstance()->initIconDatabase(d->m_webSettings);
1839 bool WebPage::isUserScalable() const
1841 return d->isUserScalable();
1844 void WebPage::setUserScalable(bool userScalable)
1846 d->setUserScalable(userScalable);
1849 double WebPage::currentScale() const
1851 return d->currentScale();
1854 void WebPage::setInitialScale(double initialScale)
1856 d->setInitialScale(initialScale);
1859 double WebPage::minimumScale() const
1861 return d->minimumScale();
1864 void WebPage::setMinimumScale(double minimumScale)
1866 d->setMinimumScale(minimumScale);
1869 void WebPage::setMaximumScale(double maximumScale)
1871 d->setMaximumScale(maximumScale);
1874 double WebPagePrivate::maximumScale() const
1876 if (m_maximumScale >= zoomToFitScale() && m_maximumScale >= m_minimumScale)
1877 return m_maximumScale;
1879 return hasVirtualViewport() ? std::max<double>(zoomToFitScale(), 4.0) : 4.0;
1882 double WebPage::maximumScale() const
1884 return d->maximumScale();
1887 void WebPagePrivate::resetScales()
1889 TransformationMatrix identity;
1890 *m_transformationMatrix = identity;
1891 m_initialScale = m_webSettings->initialScale() > 0 ? m_webSettings->initialScale() : -1.0;
1892 m_minimumScale = -1.0;
1893 m_maximumScale = -1.0;
1895 // We have to let WebCore know about updated framerect now that we've
1896 // reset our scales. See: RIM Bug #401.
1897 updateViewportSize();
1900 IntPoint WebPagePrivate::transformedScrollPosition() const
1902 return m_backingStoreClient->transformedScrollPosition();
1905 // Returned scroll position is in transformed coordinates.
1906 Platform::IntPoint WebPage::scrollPosition() const
1908 return d->transformedScrollPosition();
1911 IntPoint WebPagePrivate::transformedMaximumScrollPosition() const
1913 return m_backingStoreClient->transformedMaximumScrollPosition();
1916 IntSize WebPagePrivate::transformedActualVisibleSize() const
1918 return IntSize(m_actualVisibleWidth, m_actualVisibleHeight);
1921 Platform::IntSize WebPage::viewportSize() const
1923 return d->transformedActualVisibleSize();
1926 IntSize WebPagePrivate::transformedViewportSize() const
1928 return Platform::Graphics::Screen::primaryScreen()->size();
1931 IntRect WebPagePrivate::transformedVisibleContentsRect() const
1933 // Usually this would be mapToTransformed(visibleContentsRect()), but
1934 // that results in rounding errors because we already set the WebCore
1935 // viewport size from our original transformedViewportSize().
1936 // Instead, we only transform the scroll position and take the
1937 // viewport size as it is, which ensures that e.g. blitting operations
1938 // always cover the whole widget/screen.
1939 return IntRect(transformedScrollPosition(), transformedViewportSize());
1942 IntSize WebPagePrivate::transformedContentsSize() const
1944 // mapToTransformed() functions use this method to crop their results,
1945 // so we can't make use of them here. While we want rounding inside page
1946 // boundaries to extend rectangles and round points, we need to crop the
1947 // contents size to the floored values so that we don't try to display
1948 // or report points that are not fully covered by the actual float-point
1949 // contents rectangle.
1950 const IntSize untransformedContentsSize = contentsSize();
1951 const FloatPoint transformedBottomRight = m_transformationMatrix->mapPoint(
1952 FloatPoint(untransformedContentsSize.width(), untransformedContentsSize.height()));
1953 return IntSize(floorf(transformedBottomRight.x()), floorf(transformedBottomRight.y()));
1956 IntPoint WebPagePrivate::mapFromContentsToViewport(const IntPoint& point) const
1958 return m_backingStoreClient->mapFromContentsToViewport(point);
1961 IntPoint WebPagePrivate::mapFromViewportToContents(const IntPoint& point) const
1963 return m_backingStoreClient->mapFromViewportToContents(point);
1966 IntRect WebPagePrivate::mapFromContentsToViewport(const IntRect& rect) const
1968 return m_backingStoreClient->mapFromContentsToViewport(rect);
1971 IntRect WebPagePrivate::mapFromViewportToContents(const IntRect& rect) const
1973 return m_backingStoreClient->mapFromViewportToContents(rect);
1976 IntPoint WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntPoint& point) const
1978 return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(point);
1981 IntPoint WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntPoint& point) const
1983 return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(point);
1986 IntRect WebPagePrivate::mapFromTransformedContentsToTransformedViewport(const IntRect& rect) const
1988 return m_backingStoreClient->mapFromTransformedContentsToTransformedViewport(rect);
1991 IntRect WebPagePrivate::mapFromTransformedViewportToTransformedContents(const IntRect& rect) const
1993 return m_backingStoreClient->mapFromTransformedViewportToTransformedContents(rect);
1996 // NOTE: PIXEL ROUNDING!
1997 // Accurate back-and-forth rounding is not possible with information loss
1998 // by integer points and sizes, so we always expand the resulting mapped
1999 // float rectangles to the nearest integer. For points, we always use
2000 // floor-rounding in mapToTransformed() so that we don't have to crop to
2001 // the (floor'd) transformed contents size.
2002 static inline IntPoint roundTransformedPoint(const FloatPoint &point)
2004 // Maps by rounding half towards zero.
2005 return IntPoint(static_cast<int>(floorf(point.x())), static_cast<int>(floorf(point.y())));
2008 static inline IntPoint roundUntransformedPoint(const FloatPoint &point)
2010 // Maps by rounding half away from zero.
2011 return IntPoint(static_cast<int>(ceilf(point.x())), static_cast<int>(ceilf(point.y())));
2014 IntPoint WebPagePrivate::mapToTransformed(const IntPoint& point) const
2016 return roundTransformedPoint(m_transformationMatrix->mapPoint(FloatPoint(point)));
2019 FloatPoint WebPagePrivate::mapToTransformedFloatPoint(const FloatPoint& point) const
2021 return m_transformationMatrix->mapPoint(point);
2024 IntPoint WebPagePrivate::mapFromTransformed(const IntPoint& point) const
2026 return roundUntransformedPoint(m_transformationMatrix->inverse().mapPoint(FloatPoint(point)));
2029 FloatPoint WebPagePrivate::mapFromTransformedFloatPoint(const FloatPoint& point) const
2031 return m_transformationMatrix->inverse().mapPoint(point);
2034 FloatRect WebPagePrivate::mapFromTransformedFloatRect(const FloatRect& rect) const
2036 return m_transformationMatrix->inverse().mapRect(rect);
2039 IntSize WebPagePrivate::mapToTransformed(const IntSize& size) const
2041 return mapToTransformed(IntRect(IntPoint::zero(), size)).size();
2044 IntSize WebPagePrivate::mapFromTransformed(const IntSize& size) const
2046 return mapFromTransformed(IntRect(IntPoint::zero(), size)).size();
2049 IntRect WebPagePrivate::mapToTransformed(const IntRect& rect) const
2051 return enclosingIntRect(m_transformationMatrix->mapRect(FloatRect(rect)));
2054 // Use this in conjunction with mapToTransformed(IntRect), in most cases.
2055 void WebPagePrivate::clipToTransformedContentsRect(IntRect& rect) const
2057 rect.intersect(IntRect(IntPoint::zero(), transformedContentsSize()));
2060 IntRect WebPagePrivate::mapFromTransformed(const IntRect& rect) const
2062 return enclosingIntRect(m_transformationMatrix->inverse().mapRect(FloatRect(rect)));
2065 bool WebPagePrivate::transformedPointEqualsUntransformedPoint(const IntPoint& transformedPoint, const IntPoint& untransformedPoint)
2067 // Scaling down is always more accurate than scaling up.
2068 if (m_transformationMatrix->a() > 1.0)
2069 return transformedPoint == mapToTransformed(untransformedPoint);
2071 return mapFromTransformed(transformedPoint) == untransformedPoint;
2074 void WebPagePrivate::notifyTransformChanged()
2076 notifyTransformedContentsSizeChanged();
2077 notifyTransformedScrollChanged();
2079 m_backingStore->d->transformChanged();
2082 void WebPagePrivate::notifyTransformedContentsSizeChanged()
2084 // We mark here as the last reported content size we sent to the client.
2085 m_previousContentsSize = contentsSize();
2087 const IntSize size = transformedContentsSize();
2088 m_backingStore->d->contentsSizeChanged(size);
2089 m_client->contentsSizeChanged(size);
2090 m_selectionHandler->selectionPositionChanged();
2093 void WebPagePrivate::notifyTransformedScrollChanged()
2095 const IntPoint pos = transformedScrollPosition();
2096 m_backingStore->d->scrollChanged(pos);
2097 m_client->scrollChanged(pos);
2100 bool WebPagePrivate::setViewMode(ViewMode mode)
2102 if (!m_mainFrame->view())
2107 // If we're in the middle of a nested layout with a recursion count above
2108 // some maximum threshold, then our algorithm for finding the minimum content
2109 // width of a given page has become dependent on the visible width.
2111 // We need to find some method to ensure that we don't experience excessive
2112 // and even infinite recursion. This can even happen with valid html. The
2113 // former can happen when we run into inline text with few candidates for line
2114 // break. The latter can happen for instance if the page has a negative margin
2115 // set against the right border. Note: this is valid by spec and can lead to
2116 // a situation where there is no value for which the content width will ensure
2117 // no horizontal scrollbar.
2118 // Example: LayoutTests/css1/box_properties/margin.html
2120 // In order to address such situations when we detect a recursion above some
2121 // maximum threshold we snap our fixed layout size to a defined quantum increment.
2122 // Eventually, either the content width will be satisfied to ensure no horizontal
2123 // scrollbar or this increment will run into the maximum layout size and the
2124 // recursion will necessarily end.
2125 bool snapToIncrement = didLayoutExceedMaximumIterations();
2127 IntSize currentSize = m_mainFrame->view()->fixedLayoutSize();
2128 IntSize newSize = fixedLayoutSize(snapToIncrement);
2129 if (currentSize == newSize)
2132 // FIXME: Temp solution. We'll get back to this.
2133 if (m_nestedLayoutFinishedCount) {
2134 double widthChange = fabs(double(newSize.width() - currentSize.width()) / currentSize.width());
2135 double heightChange = fabs(double(newSize.height() - currentSize.height()) / currentSize.height());
2136 if (widthChange < 0.05 && heightChange < 0.05)
2140 m_mainFrame->view()->setUseFixedLayout(useFixedLayout());
2141 m_mainFrame->view()->setFixedLayoutSize(newSize);
2142 return true; // Needs re-layout!
2145 void WebPagePrivate::setCursor(PlatformCursor handle)
2147 if (m_currentCursor.type() != handle.type()) {
2148 m_currentCursor = handle;
2149 m_client->cursorChanged(handle.type(), handle.url().c_str(), handle.hotspot().x(), handle.hotspot().y());
2153 Platform::NetworkStreamFactory* WebPagePrivate::networkStreamFactory()
2155 return m_client->networkStreamFactory();
2158 Platform::Graphics::Window* WebPagePrivate::platformWindow() const
2160 return m_client->window();
2163 void WebPagePrivate::setPreventsScreenDimming(bool keepAwake)
2166 if (!m_preventIdleDimmingCount)
2167 m_client->setPreventsScreenIdleDimming(true);
2168 m_preventIdleDimmingCount++;
2169 } else if (m_preventIdleDimmingCount > 0) {
2170 m_preventIdleDimmingCount--;
2171 if (!m_preventIdleDimmingCount)
2172 m_client->setPreventsScreenIdleDimming(false);
2174 ASSERT_NOT_REACHED(); // SetPreventsScreenIdleDimming(false) called too many times.
2177 void WebPagePrivate::showVirtualKeyboard(bool showKeyboard)
2179 m_client->showVirtualKeyboard(showKeyboard);
2182 void WebPagePrivate::ensureContentVisible(bool centerInView)
2184 m_inputHandler->ensureFocusElementVisible(centerInView);
2187 void WebPagePrivate::zoomToContentRect(const IntRect& rect)
2189 // Don't scale if the user is not supposed to scale.
2190 if (!isUserScalable())
2193 FloatPoint anchor = FloatPoint(rect.width() / 2.0 + rect.x(), rect.height() / 2.0 + rect.y());
2194 IntSize viewSize = viewportSize();
2196 // Calculate the scale required to scale that dimension to fit.
2197 double scaleH = (double)viewSize.width() / (double)rect.width();
2198 double scaleV = (double)viewSize.height() / (double)rect.height();
2200 // Choose the smaller scale factor so that all of the content is visible.
2201 zoomAboutPoint(min(scaleH, scaleV), anchor);
2204 void WebPagePrivate::registerPlugin(PluginView* plugin, bool shouldRegister)
2207 m_pluginViews.add(plugin);
2209 m_pluginViews.remove(plugin);
2212 #define FOR_EACH_PLUGINVIEW(pluginViews) \
2213 HashSet<PluginView*>::const_iterator it = pluginViews.begin(); \
2214 HashSet<PluginView*>::const_iterator last = pluginViews.end(); \
2215 for (; it != last; ++it)
2217 void WebPagePrivate::notifyPageOnLoad()
2219 FOR_EACH_PLUGINVIEW(m_pluginViews)
2220 (*it)->handleOnLoadEvent();
2223 bool WebPagePrivate::shouldPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2225 return m_client->shouldPluginEnterFullScreen();
2228 void WebPagePrivate::didPluginEnterFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2230 m_fullScreenPluginView = plugin;
2231 m_client->didPluginEnterFullScreen();
2233 if (!m_client->window())
2236 Platform::Graphics::Window::setTransparencyDiscardFilter(windowUniquePrefix);
2237 m_client->window()->setSensitivityFullscreenOverride(true);
2240 void WebPagePrivate::didPluginExitFullScreen(PluginView* plugin, const char* windowUniquePrefix)
2242 m_fullScreenPluginView = 0;
2243 m_client->didPluginExitFullScreen();
2245 if (!m_client->window())
2248 Platform::Graphics::Window::setTransparencyDiscardFilter(0);
2249 m_client->window()->setSensitivityFullscreenOverride(false);
2252 void WebPagePrivate::onPluginStartBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
2254 m_client->onPluginStartBackgroundPlay();
2257 void WebPagePrivate::onPluginStopBackgroundPlay(PluginView* plugin, const char* windowUniquePrefix)
2259 m_client->onPluginStopBackgroundPlay();
2262 bool WebPagePrivate::lockOrientation(bool landscape)
2264 return m_client->lockOrientation(landscape);
2267 void WebPagePrivate::unlockOrientation()
2269 return m_client->unlockOrientation();
2272 int WebPagePrivate::orientation() const
2274 #if ENABLE(ORIENTATION_EVENTS)
2275 return m_mainFrame->orientation();
2277 #error ORIENTATION_EVENTS must be defined.
2278 // Or a copy of the orientation value will have to be stored in these objects.
2282 double WebPagePrivate::currentZoomFactor() const
2284 return currentScale();
2287 int WebPagePrivate::showAlertDialog(WebPageClient::AlertType atype)
2289 return m_client->showAlertDialog(atype);
2292 bool WebPagePrivate::isActive() const
2294 return m_client->isActive();
2297 bool WebPagePrivate::authenticationChallenge(const KURL& url, const ProtectionSpace& protectionSpace, Credential& inputCredential)
2302 #if !defined(PUBLIC_BUILD) || !PUBLIC_BUILD
2303 if (m_dumpRenderTree)
2304 return m_dumpRenderTree->didReceiveAuthenticationChallenge(inputCredential);
2307 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2308 if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled())
2309 credentialManager().autofillAuthenticationChallenge(protectionSpace, username, password);
2312 bool isConfirmed = m_client->authenticationChallenge(protectionSpace.realm().characters(), protectionSpace.realm().length(), username, password);
2314 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
2315 Credential credential(username, password, CredentialPersistencePermanent);
2316 if (m_webSettings->isCredentialAutofillEnabled() && !m_webSettings->isPrivateBrowsingEnabled() && isConfirmed)
2317 credentialManager().saveCredentialIfConfirmed(this, CredentialTransformData(url, protectionSpace, credential));
2319 Credential credential(username, password, CredentialPersistenceNone);
2321 inputCredential = credential;
2325 PageClientBlackBerry::SaveCredentialType WebPagePrivate::notifyShouldSaveCredential(bool isNew)
2327 return static_cast<PageClientBlackBerry::SaveCredentialType>(m_client->notifyShouldSaveCredential(isNew));
2330 void WebPagePrivate::syncProxyCredential(const WebCore::Credential& credential)
2332 m_client->syncProxyCredential(credential.user().utf8().data(), credential.password().utf8().data());
2335 void WebPagePrivate::notifyPopupAutofillDialog(const Vector<String>& candidates, const WebCore::IntRect& screenRect)
2337 vector<string> textItems;
2338 for (size_t i = 0; i < candidates.size(); i++)
2339 textItems.push_back(candidates[i].utf8().data());
2340 m_client->notifyPopupAutofillDialog(textItems, screenRect);
2343 void WebPagePrivate::notifyDismissAutofillDialog()
2345 m_client->notifyDismissAutofillDialog();
2348 bool WebPagePrivate::useFixedLayout() const
2353 Platform::WebContext WebPagePrivate::webContext(TargetDetectionStrategy strategy)
2355 Platform::WebContext context;
2357 RefPtr<Node> node = contextNode(strategy);
2358 m_currentContextNode = node;
2359 if (!m_currentContextNode)
2362 requestLayoutIfNeeded();
2364 bool nodeAllowSelectionOverride = false;
2365 if (Node* linkNode = node->enclosingLinkEventParentOrSelf()) {
2367 if (linkNode->isLink() && linkNode->hasAttributes()) {
2368 if (Attribute* attribute = static_cast<Element*>(linkNode)->getAttributeItem(HTMLNames::hrefAttr))
2369 href = linkNode->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(attribute->value()));
2372 String pattern = findPatternStringForUrl(href);
2373 if (!pattern.isEmpty())
2374 context.setPattern(pattern.utf8().data());
2376 if (!href.string().isEmpty()) {
2377 context.setUrl(href.string().utf8().data());
2379 // Links are non-selectable by default, but selection should be allowed
2380 // providing the page is selectable, use the parent to determine it.
2381 if (linkNode->parentNode() && linkNode->parentNode()->canStartSelection())
2382 nodeAllowSelectionOverride = true;
2386 if (node->isHTMLElement()) {
2387 HTMLImageElement* imageElement = 0;
2388 HTMLMediaElement* mediaElement = 0;
2390 if (node->hasTagName(HTMLNames::imgTag))
2391 imageElement = static_cast<HTMLImageElement*>(node.get());
2392 else if (node->hasTagName(HTMLNames::areaTag))
2393 imageElement = static_cast<HTMLAreaElement*>(node.get())->imageElement();
2395 if (static_cast<HTMLElement*>(node.get())->isMediaElement())
2396 mediaElement = static_cast<HTMLMediaElement*>(node.get());
2398 if (imageElement && imageElement->renderer()) {
2399 context.setFlag(Platform::WebContext::IsImage);
2400 // FIXME: At the mean time, we only show "Save Image" when the image data is available.
2401 if (CachedResource* cachedResource = imageElement->cachedImage()) {
2402 if (cachedResource->isLoaded() && cachedResource->data()) {
2403 String url = stripLeadingAndTrailingHTMLSpaces(imageElement->getAttribute(HTMLNames::srcAttr).string());
2404 context.setSrc(node->document()->completeURL(url).string().utf8().data());
2407 String alt = imageElement->altText();
2409 context.setAlt(alt.utf8().data());
2413 if (mediaElement->hasAudio())
2414 context.setFlag(Platform::WebContext::IsAudio);
2415 if (mediaElement->hasVideo())
2416 context.setFlag(Platform::WebContext::IsVideo);
2418 String src = stripLeadingAndTrailingHTMLSpaces(mediaElement->getAttribute(HTMLNames::srcAttr).string());
2419 context.setSrc(node->document()->completeURL(src).string().utf8().data());
2423 if (node->isTextNode()) {
2424 Text* curText = toText(node.get());
2425 if (!curText->wholeText().isEmpty())
2426 context.setText(curText->wholeText().utf8().data());
2429 bool canStartSelection = node->canStartSelection();
2431 if (node->isElementNode()) {
2432 Element* element = static_cast<Element*>(node->shadowAncestorNode());
2433 if (DOMSupport::isTextBasedContentEditableElement(element)) {
2434 if (!canStartSelection) {
2435 // Input fields host node is by spec non-editable unless the field itself has content editable enabled.
2436 // Enable selection if the shadow tree for the input field is selectable.
2437 Node* nodeUnderFinger = m_touchEventHandler->lastFatFingersResult().isValid() ? m_touchEventHandler->lastFatFingersResult().node(FatFingersResult::ShadowContentAllowed) : 0;
2438 if (nodeUnderFinger)
2439 canStartSelection = nodeUnderFinger->canStartSelection();
2441 context.setFlag(Platform::WebContext::IsInput);
2442 if (element->hasTagName(HTMLNames::inputTag))
2443 context.setFlag(Platform::WebContext::IsSingleLine);
2444 if (DOMSupport::isPasswordElement(element))
2445 context.setFlag(Platform::WebContext::IsPassword);
2447 String elementText(DOMSupport::inputElementText(element));
2448 if (!elementText.stripWhiteSpace().isEmpty())
2449 context.setText(elementText.utf8().data());
2453 if (!nodeAllowSelectionOverride && !canStartSelection)
2454 context.resetFlag(Platform::WebContext::IsSelectable);
2456 if (node->isFocusable())
2457 context.setFlag(Platform::WebContext::IsFocusable);
2462 Platform::WebContext WebPage::webContext(TargetDetectionStrategy strategy) const
2464 return d->webContext(strategy);
2467 void WebPagePrivate::updateCursor()
2470 if (m_lastMouseEvent.button() == LeftButton)
2471 buttonMask = Platform::MouseEvent::ScreenLeftMouseButton;
2472 else if (m_lastMouseEvent.button() == MiddleButton)
2473 buttonMask = Platform::MouseEvent::ScreenMiddleMouseButton;
2474 else if (m_lastMouseEvent.button() == RightButton)
2475 buttonMask = Platform::MouseEvent::ScreenRightMouseButton;
2477 BlackBerry::Platform::MouseEvent event(buttonMask, buttonMask, mapToTransformed(m_lastMouseEvent.position()), mapToTransformed(m_lastMouseEvent.globalPosition()), 0, 0);
2478 m_webPage->mouseEvent(event);
2481 IntSize WebPagePrivate::fixedLayoutSize(bool snapToIncrement) const
2483 if (hasVirtualViewport())
2484 return IntSize(m_virtualViewportWidth, m_virtualViewportHeight);
2486 const int defaultLayoutWidth = m_defaultLayoutSize.width();
2487 const int defaultLayoutHeight = m_defaultLayoutSize.height();
2489 int minWidth = defaultLayoutWidth;
2490 int maxWidth = defaultMaxLayoutSize().width();
2491 int maxHeight = defaultMaxLayoutSize().height();
2493 // If the load state is none then we haven't actually got anything yet, but we need to layout
2494 // the entire page so that the user sees the entire page (unrendered) instead of just part of it.
2495 if (m_loadState == None)
2496 return IntSize(defaultLayoutWidth, defaultLayoutHeight);
2498 if (m_viewMode == FixedDesktop) {
2499 int width = maxWidth;
2500 // if the defaultLayoutHeight is at minimum, it probably was set as 0
2501 // and clamped, meaning it's effectively not set. (Even if it happened
2502 // to be set exactly to the minimum, it's too small to be useful.) So
2505 if (defaultLayoutHeight <= minimumLayoutSize.height())
2508 height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2509 return IntSize(width, height);
2512 if (m_viewMode == Desktop) {
2513 // If we detect an overflow larger than the contents size then use that instead since
2514 // it'll still be clamped by the maxWidth below...
2515 int width = std::max(absoluteVisibleOverflowSize().width(), contentsSize().width());
2517 if (snapToIncrement) {
2518 // Snap to increments of defaultLayoutWidth / 2.0.
2519 float factor = static_cast<float>(width) / (defaultLayoutWidth / 2.0);
2520 factor = ceilf(factor);
2521 width = (defaultLayoutWidth / 2.0) * factor;
2524 if (width < minWidth)
2526 if (width > maxWidth)
2528 int height = ceilf(static_cast<float>(width) / static_cast<float>(defaultLayoutWidth) * static_cast<float>(defaultLayoutHeight));
2529 return IntSize(width, height);
2532 if (m_webSettings->isZoomToFitOnLoad()) {
2533 // We need to clamp the layout width to the minimum of the layout
2534 // width or the content width. This is important under rotation for mobile
2535 // websites. We want the page to remain layouted at the same width which
2536 // it was loaded with, and instead change the zoom level to fit to screen.
2537 // The height is welcome to adapt to the height used in the new orientation,
2538 // otherwise we will get a grey bar below the web page.
2539 if (m_mainFrame->view() && !contentsSize().isEmpty())
2540 minWidth = contentsSize().width();
2542 // If there is no contents width, use the minimum of screen width
2543 // and layout width to shape the first layout to a contents width
2544 // that we could reasonably zoom to fit, in a manner that takes
2545 // orientation into account and still respects a small default
2547 #if ENABLE(ORIENTATION_EVENTS)
2548 minWidth = m_mainFrame->orientation() % 180
2549 ? Platform::Graphics::Screen::primaryScreen()->height()
2550 : Platform::Graphics::Screen::primaryScreen()->width();
2552 minWidth = Platform::Graphics::Screen::primaryScreen()->width();
2557 return IntSize(std::min(minWidth, defaultLayoutWidth), defaultLayoutHeight);
2560 BackingStoreClient* WebPagePrivate::backingStoreClientForFrame(const Frame* frame) const
2563 BackingStoreClient* backingStoreClient = 0;
2564 if (m_backingStoreClientForFrameMap.contains(frame))
2565 backingStoreClient = m_backingStoreClientForFrameMap.get(frame);
2566 return backingStoreClient;
2569 void WebPagePrivate::addBackingStoreClientForFrame(const Frame* frame, BackingStoreClient* client)
2573 m_backingStoreClientForFrameMap.add(frame, client);
2576 void WebPagePrivate::removeBackingStoreClientForFrame(const Frame* frame)
2579 if (m_backingStoreClientForFrameMap.contains(frame))
2580 m_backingStoreClientForFrameMap.remove(frame);
2584 void WebPagePrivate::clearDocumentData(const Document* documentGoingAway)
2586 ASSERT(documentGoingAway);
2587 if (m_currentContextNode && m_currentContextNode->document() == documentGoingAway)
2588 m_currentContextNode = 0;
2590 if (m_currentPinchZoomNode && m_currentPinchZoomNode->document() == documentGoingAway)
2591 m_currentPinchZoomNode = 0;
2593 if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
2594 m_currentBlockZoomAdjustedNode = 0;
2596 if (m_inRegionScrollStartingNode && m_inRegionScrollStartingNode->document() == documentGoingAway)
2597 m_inRegionScrollStartingNode = 0;
2599 if (documentGoingAway->frame())
2600 m_inputHandler->frameUnloaded(documentGoingAway->frame());
2602 Node* nodeUnderFatFinger = m_touchEventHandler->lastFatFingersResult().node();
2603 if (nodeUnderFatFinger && nodeUnderFatFinger->document() == documentGoingAway)
2604 m_touchEventHandler->resetLastFatFingersResult();
2606 // NOTE: m_fullscreenVideoNode, m_fullScreenPluginView and m_pluginViews
2607 // are cleared in other methods already.
2610 typedef bool (*PredicateFunction)(RenderLayer*);
2611 static bool isPositionedContainer(RenderLayer* layer)
2613 RenderObject* o = layer->renderer();
2614 return o->isRenderView() || o->isOutOfFlowPositioned() || o->isRelPositioned() || layer->hasTransform();
2617 static bool isNonRenderViewFixedPositionedContainer(RenderLayer* layer)
2619 RenderObject* o = layer->renderer();
2620 if (o->isRenderView())
2623 return o->isOutOfFlowPositioned() && o->style()->position() == FixedPosition;
2626 static bool isFixedPositionedContainer(RenderLayer* layer)
2628 RenderObject* o = layer->renderer();
2629 return o->isRenderView() || (o->isOutOfFlowPositioned() && o->style()->position() == FixedPosition);
2632 static RenderLayer* findAncestorOrSelfNotMatching(PredicateFunction predicate, RenderLayer* layer)
2634 RenderLayer* curr = layer;
2635 while (curr && !predicate(curr))
2636 curr = curr->parent();
2641 RenderLayer* WebPagePrivate::enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(RenderLayer* layer)
2643 return findAncestorOrSelfNotMatching(&isFixedPositionedContainer, layer);
2646 RenderLayer* WebPagePrivate::enclosingPositionedAncestorOrSelfIfPositioned(RenderLayer* layer)
2648 return findAncestorOrSelfNotMatching(&isPositionedContainer, layer);
2651 static inline Frame* frameForNode(Node* node)
2653 Node* origNode = node;
2654 for (; node; node = node->parentNode()) {
2655 if (RenderObject* renderer = node->renderer()) {
2656 if (renderer->isRenderView()) {
2657 if (FrameView* view = toRenderView(renderer)->frameView()) {
2658 if (Frame* frame = view->frame())
2662 if (renderer->isWidget()) {
2663 Widget* widget = toRenderWidget(renderer)->widget();
2664 if (widget && widget->isFrameView()) {
2665 if (Frame* frame = static_cast<FrameView*>(widget)->frame())
2672 for (node = origNode; node; node = node->parentNode()) {
2673 if (Document* doc = node->document()) {
2674 if (Frame* frame = doc->frame())
2682 static IntRect getNodeWindowRect(Node* node)
2684 if (Frame* frame = frameForNode(node)) {
2685 if (FrameView* view = frame->view())
2686 return view->contentsToWindow(node->getRect());
2688 ASSERT_NOT_REACHED();
2692 IntRect WebPagePrivate::getRecursiveVisibleWindowRect(ScrollView* view, bool noClipOfMainFrame)
2694 ASSERT(m_mainFrame);
2696 // Don't call this function asking to not clip the main frame providing only
2697 // the main frame. All that can be returned is the content rect which
2698 // isn't what this function is for.
2699 if (noClipOfMainFrame && view == m_mainFrame->view()) {
2700 ASSERT_NOT_REACHED();
2701 return IntRect(IntPoint::zero(), view->contentsSize());
2704 IntRect visibleWindowRect(view->contentsToWindow(view->visibleContentRect(false)));
2705 if (view->parent() && !(noClipOfMainFrame && view->parent() == m_mainFrame->view())) {
2706 // Intersect with parent visible rect.
2707 visibleWindowRect.intersect(getRecursiveVisibleWindowRect(view->parent(), noClipOfMainFrame));
2709 return visibleWindowRect;
2712 void WebPagePrivate::assignFocus(Platform::FocusDirection direction)
2714 ASSERT((int) Platform::FocusDirectionNone == (int) FocusDirectionNone);
2715 ASSERT((int) Platform::FocusDirectionForward == (int) FocusDirectionForward);
2716 ASSERT((int) Platform::FocusDirectionBackward == (int) FocusDirectionBackward);
2718 // First we clear the focus, since we want to focus either initial or the last
2719 // focusable element in the webpage (according to the TABINDEX), or simply clear
2723 switch (direction) {
2724 case FocusDirectionForward:
2725 case FocusDirectionBackward:
2726 m_page->focusController()->setInitialFocus((FocusDirection) direction, 0);
2728 case FocusDirectionNone:
2731 ASSERT_NOT_REACHED();
2735 void WebPage::assignFocus(Platform::FocusDirection direction)
2737 if (d->m_page->defersLoading())
2739 d->assignFocus(direction);
2742 Platform::IntRect WebPagePrivate::focusNodeRect()
2744 Frame* frame = focusedOrMainFrame();
2746 return Platform::IntRect();
2748 Document* doc = frame->document();
2749 FrameView* view = frame->view();
2750 if (!doc || !view || view->needsLayout())
2751 return Platform::IntRect();
2753 IntRect focusRect = rectForNode(doc->focusedNode());
2754 focusRect = adjustRectOffsetForFrameOffset(focusRect, doc->focusedNode());
2755 focusRect = mapToTransformed(focusRect);
2756 clipToTransformedContentsRect(focusRect);
2760 PassRefPtr<Node> WebPagePrivate::contextNode(TargetDetectionStrategy strategy)
2762 EventHandler* eventHandler = focusedOrMainFrame()->eventHandler();
2763 const FatFingersResult lastFatFingersResult = m_touchEventHandler->lastFatFingersResult();
2764 bool isTouching = lastFatFingersResult.isValid() && strategy == RectBased;
2766 // Unpress the mouse button always.
2767 if (eventHandler->mousePressed())
2768 eventHandler->setMousePressed(false);
2770 // Check if we're using LinkToLink and the user is not touching the screen.
2771 if (m_webSettings->doesGetFocusNodeContext() && !isTouching) {
2773 node = m_page->focusController()->focusedOrMainFrame()->document()->focusedNode();
2775 IntRect visibleRect = IntRect(IntPoint(), actualVisibleSize());
2776 if (!visibleRect.intersects(getNodeWindowRect(node.get())))
2779 return node.release();
2782 // Check for text input.
2783 if (isTouching && lastFatFingersResult.isTextInput())
2784 return lastFatFingersResult.node(FatFingersResult::ShadowContentNotAllowed);
2786 IntPoint contentPos;
2788 contentPos = lastFatFingersResult.adjustedPosition();
2790 contentPos = mapFromViewportToContents(m_lastMouseEvent.position());
2792 if (strategy == RectBased) {
2793 FatFingersResult result = FatFingers(this, lastFatFingersResult.adjustedPosition(), FatFingers::Text).findBestPoint();
2794 return result.node(FatFingersResult::ShadowContentNotAllowed);
2797 HitTestResult result = eventHandler->hitTestResultAtPoint(contentPos, false /*allowShadowContent*/);
2798 return result.innerNode();
2801 static inline int distanceBetweenPoints(IntPoint p1, IntPoint p2)
2803 // Change int to double, because (dy * dy) can cause int overflow in reality, e.g, (-46709 * -46709).
2804 double dx = static_cast<double>(p1.x() - p2.x());
2805 double dy = static_cast<double>(p1.y() - p2.y());
2806 return sqrt((dx * dx) + (dy * dy));
2809 Node* WebPagePrivate::bestNodeForZoomUnderPoint(const IntPoint& point)
2811 IntPoint pt = mapFromTransformed(point);
2812 IntRect clickRect(pt.x() - blockClickRadius, pt.y() - blockClickRadius, 2 * blockClickRadius, 2 * blockClickRadius);
2813 Node* originalNode = nodeForZoomUnderPoint(point);
2816 Node* node = bestChildNodeForClickRect(originalNode, clickRect);
2817 return node ? adjustedBlockZoomNodeForZoomLimits(node) : adjustedBlockZoomNodeForZoomLimits(originalNode);
2820 Node* WebPagePrivate::bestChildNodeForClickRect(Node* parentNode, const IntRect& clickRect)
2825 int bestDistance = std::numeric_limits<int>::max();
2827 Node* node = parentNode->firstChild();
2829 for (; node; node = node->nextSibling()) {
2830 IntRect rect = rectForNode(node);
2831 if (!clickRect.intersects(rect))
2834 int distance = distanceBetweenPoints(rect.center(), clickRect.center());
2835 Node* bestChildNode = bestChildNodeForClickRect(node, clickRect);
2836 if (bestChildNode) {
2837 IntRect bestChildRect = rectForNode(bestChildNode);
2838 int bestChildDistance = distanceBetweenPoints(bestChildRect.center(), clickRect.center());
2839 if (bestChildDistance < distance && bestChildDistance < bestDistance) {
2840 bestNode = bestChildNode;
2841 bestDistance = bestChildDistance;
2843 if (distance < bestDistance) {
2845 bestDistance = distance;
2849 if (distance < bestDistance) {
2851 bestDistance = distance;
2859 double WebPagePrivate::maxBlockZoomScale() const
2861 return std::min(maximumBlockZoomScale, maximumScale());
2864 Node* WebPagePrivate::nodeForZoomUnderPoint(const IntPoint& point)
2869 HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromTransformed(point), false);
2871 Node* node = result.innerNonSharedNode();
2876 RenderObject* renderer = node->renderer();
2878 node = node->parentNode();
2879 renderer = node->renderer();
2885 Node* WebPagePrivate::adjustedBlockZoomNodeForZoomLimits(Node* node)
2887 Node* initialNode = node;
2888 RenderObject* renderer = node->renderer();
2889 bool acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2891 while (!renderer || !acceptableNodeSize) {
2892 node = node->parentNode();
2897 renderer = node->renderer();
2898 acceptableNodeSize = newScaleForBlockZoomRect(rectForNode(node), 1.0, 0) < maxBlockZoomScale();
2901 // Don't use a node if it is too close to the size of the actual contents.
2902 if (initialNode != node) {
2903 IntRect nodeRect = rectForNode(node);
2904 nodeRect = adjustRectOffsetForFrameOffset(nodeRect, node);
2905 nodeRect.intersect(IntRect(IntPoint::zero(), contentsSize()));
2906 int nodeArea = nodeRect.width() * nodeRect.height();
2907 int pageArea = contentsSize().width() * contentsSize().height();
2908 if (static_cast<double>(pageArea - nodeArea) / pageArea < minimumExpandingRatio)
2915 bool WebPagePrivate::compareNodesForBlockZoom(Node* n1, Node* n2)
2920 return (n2 == n1) || n2->isDescendantOf(n1);
2923 double WebPagePrivate::newScaleForBlockZoomRect(const IntRect& rect, double oldScale, double margin)
2926 return std::numeric_limits<double>::max();
2928 ASSERT(rect.width() + margin);
2930 double newScale = oldScale * static_cast<double>(transformedActualVisibleSize().width()) / (rect.width() + margin);
2935 IntRect WebPagePrivate::rectForNode(Node* node)
2940 RenderObject* renderer = node->renderer();
2945 // Return rect in un-transformed content coordinates.
2948 // FIXME: Ensure this works with iframes.
2949 if (m_webPage->settings()->textReflowMode() == WebSettings::TextReflowEnabled && renderer->isText()) {
2950 RenderBlock* renderBlock = renderer->containingBlock();
2953 while (!renderBlock->isRoot()) {
2954 xOffset += renderBlock->x();
2955 yOffset += renderBlock->y();
2956 renderBlock = renderBlock->containingBlock();
2958 const RenderText* renderText = toRenderText(renderer);
2959 IntRect linesBox = renderText->linesBoundingBox();
2960 blockRect = IntRect(xOffset + linesBox.x(), yOffset + linesBox.y(), linesBox.width(), linesBox.height());
2962 blockRect = renderer->absoluteClippedOverflowRect();
2964 if (renderer->isText()) {
2965 RenderBlock* rb = renderer->containingBlock();
2967 // Inefficient? Way to find width when floats intersect a block.
2969 int lineCount = rb->lineCount();
2970 for (int i = 0; i < lineCount; i++)
2971 blockWidth = max(blockWidth, rb->availableLogicalWidthForLine(i, false));
2973 blockRect.setWidth(blockWidth);
2974 blockRect.setX(blockRect.x() + rb->logicalLeftOffsetForLine(1, false));
2977 // Strip off padding.
2978 if (renderer->style()->hasPadding()) {
2979 blockRect.setX(blockRect.x() + renderer->style()->paddingLeft().value());
2980 blockRect.setY(blockRect.y() + renderer->style()->paddingTop().value());
2981 blockRect.setWidth(blockRect.width() - renderer->style()->paddingRight().value());
2982 blockRect.setHeight(blockRect.height() - renderer->style()->paddingBottom().value());
2988 IntPoint WebPagePrivate::frameOffset(const Frame* frame) const
2992 // FIXME: This function can be called when page is being destroyed and JS triggers selection change.
2993 // We could break the call chain at upper levels, but I think it is better to check the frame pointer
2994 // here because the pointer is explicitly cleared in WebPage::destroy().
2998 // Convert 0,0 in the frame's coordinate system to window coordinates to
2999 // get the frame's global position, and return this position in the main
3000 // frame's coordinates. (So the main frame's coordinates will be 0,0.)
3001 return mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint::zero()));
3004 IntRect WebPagePrivate::adjustRectOffsetForFrameOffset(const IntRect& rect, const Node* node)
3009 // Adjust the offset of the rect if it is in an iFrame/frame or set of iFrames/frames.
3010 // FIXME: can we just use frameOffset instead of this big routine?
3011 const Node* tnode = node;
3012 IntRect adjustedRect = rect;
3014 Frame* frame = tnode->document()->frame();
3018 Node* ownerNode = static_cast<Node*>(frame->ownerElement());
3020 if (ownerNode && (ownerNode->hasTagName(HTMLNames::iframeTag) || ownerNode->hasTagName(HTMLNames::frameTag))) {
3023 iFrameRect = rectForNode(ownerNode);
3024 adjustedRect.move(iFrameRect.x(), iFrameRect.y());
3025 adjustedRect.intersect(iFrameRect);
3026 ownerNode = ownerNode->parentNode();
3027 } while (iFrameRect.isEmpty() && ownerNode);
3030 } while (tnode = tnode->parentNode());
3032 return adjustedRect;
3035 IntRect WebPagePrivate::blockZoomRectForNode(Node* node)
3037 if (!node || contentsSize().isEmpty())
3041 m_currentBlockZoomAdjustedNode = tnode;
3043 IntRect blockRect = rectForNode(tnode);
3044 IntRect originalRect = blockRect;
3046 int originalArea = originalRect.width() * originalRect.height();
3047 int pageArea = contentsSize().width() * contentsSize().height();
3048 double blockToPageRatio = static_cast<double>(pageArea - originalArea) / pageArea;
3049 double blockExpansionRatio = 5.0 * blockToPageRatio * blockToPageRatio;
3051 if (!tnode->hasTagName(HTMLNames::imgTag) && !tnode->hasTagName(HTMLNames::inputTag) && !tnode->hasTagName(HTMLNames::textareaTag)) {
3052 while (tnode = tnode->parentNode()) {
3054 IntRect tRect = rectForNode(tnode);
3055 int tempBlockArea = tRect.width() * tRect.height();
3056 // Don't expand the block if it will be too large relative to the content.
3057 if (static_cast<double>(pageArea - tempBlockArea) / pageArea < minimumExpandingRatio)
3059 if (tRect.isEmpty())
3060 continue; // No renderer.
3061 if (tempBlockArea < 1.1 * originalArea)
3062 continue; // The size of this parent is very close to the child, no need to go to this parent.
3063 // Don't expand the block if the parent node size is already almost the size of actual visible size.
3064 IntSize actualSize = actualVisibleSize();
3065 if (static_cast<double>(actualSize.width() - tRect.width()) / actualSize.width() < minimumExpandingRatio)
3067 if (tempBlockArea < blockExpansionRatio * originalArea) {
3069 m_currentBlockZoomAdjustedNode = tnode;
3075 blockRect = adjustRectOffsetForFrameOffset(blockRect, node);
3076 blockRect = mapToTransformed(blockRect);
3077 clipToTransformedContentsRect(blockRect);
3079 #if DEBUG_BLOCK_ZOOM
3080 // Re-paint the backingstore to screen to erase other annotations.
3081 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::Blit);
3083 // Render a black square over the calculated block and a gray square over the original block for visual inspection.
3084 originalRect = mapToTransformed(originalRect);
3085 clipToTransformedContentsRect(originalRect);
3086 IntRect renderRect = mapFromTransformedContentsToTransformedViewport(blockRect);
3087 IntRect originalRenderRect = mapFromTransformedContentsToTransformedViewport(originalRect);
3088 IntSize viewportSize = transformedViewportSize();
3089 renderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
3090 originalRenderRect.intersect(IntRect(0, 0, viewportSize.width(), viewportSize.height()));
3091 m_backingStore->d->clearWindow(renderRect, 0, 0, 0);
3092 m_backingStore->d->clearWindow(originalRenderRect, 120, 120, 120);
3093 m_backingStore->d->invalidateWindow(renderRect);
3099 // This function should not be called directly.
3100 // It is called after the animation ends (see above).
3101 void WebPagePrivate::zoomBlock()
3106 IntPoint anchor(roundUntransformedPoint(mapFromTransformedFloatPoint(m_finalBlockPoint)));
3107 bool willUseTextReflow = false;
3109 #if ENABLE(VIEWPORT_REFLOW)
3110 willUseTextReflow = m_webPage->settings()->textReflowMode() != WebSettings::TextReflowDisabled;
3111 toggleTextReflowIfEnabledForBlockZoomOnly(m_shouldReflowBlock);
3115 TransformationMatrix zoom;
3116 zoom.scale(m_blockZoomFinalScale);
3117 *m_transformationMatrix = zoom;
3118 m_client->resetBitmapZoomScale(m_blockZoomFinalScale);
3119 m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3120 updateViewportSize();
3122 #if ENABLE(VIEWPORT_REFLOW)
3123 requestLayoutIfNeeded();
3124 if (willUseTextReflow && m_shouldReflowBlock) {
3125 IntRect reflowedRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
3126 reflowedRect = adjustRectOffsetForFrameOffset(reflowedRect, m_currentBlockZoomAdjustedNode.get());
3127 reflowedRect.move(roundTransformedPoint(m_finalBlockPointReflowOffset).x(), roundTransformedPoint(m_finalBlockPointReflowOffset).y());
3128 RenderObject* renderer = m_currentBlockZoomAdjustedNode->renderer();
3129 IntPoint topLeftPoint(reflowedRect.location());
3130 if (renderer && renderer->isText()) {
3131 ETextAlign textAlign = renderer->style()->textAlign();
3132 IntPoint textAnchor;
3133 switch (textAlign) {
3136 textAnchor = IntPoint(reflowedRect.x() + (reflowedRect.width() - actualVisibleSize().width()) / 2, topLeftPoint.y());
3140 textAnchor = topLeftPoint;
3144 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
3149 if (renderer->style()->isLeftToRightDirection())
3150 textAnchor = topLeftPoint;
3152 textAnchor = IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y());
3155 setScrollPosition(textAnchor);
3157 renderer->style()->isLeftToRightDirection()
3158 ? setScrollPosition(topLeftPoint)
3159 : setScrollPosition(IntPoint(reflowedRect.x() + reflowedRect.width() - actualVisibleSize().width(), topLeftPoint.y()));
3161 } else if (willUseTextReflow) {
3162 IntRect finalRect = rectForNode(m_currentBlockZoomAdjustedNode.get());
3163 finalRect = adjustRectOffsetForFrameOffset(finalRect, m_currentBlockZoomAdjustedNode.get());
3164 setScrollPosition(IntPoint(0, finalRect.y() + m_finalBlockPointReflowOffset.y()));
3168 if (!willUseTextReflow) {
3169 setScrollPosition(anchor);
3170 if (!m_shouldReflowBlock)
3174 notifyTransformChanged();
3175 m_backingStore->d->clearWindow();
3176 m_backingStore->d->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
3177 m_client->zoomChanged(m_webPage->isMinZoomed(), m_webPage->isMaxZoomed(), !shouldZoomOnEscape(), currentScale());
3180 void WebPage::blockZoomAnimationFinished()
3185 void WebPagePrivate::resetBlockZoom()
3187 m_currentBlockZoomNode = 0;
3188 m_currentBlockZoomAdjustedNode = 0;
3189 m_shouldReflowBlock = false;
3192 void WebPage::destroyWebPageCompositor()
3194 #if USE(ACCELERATED_COMPOSITING)
3195 // Destroy the layer renderer in a sync command before we destroy the backing store,
3196 // to flush any pending compositing messages on the compositing thread.
3197 // The backing store is indirectly deleted by the 'detachFromParent' call below.
3198 d->syncDestroyCompositorOnCompositingThread();
3202 void WebPage::destroy()
3204 // TODO: need to verify if this call needs to be made before calling
3205 // WebPage::destroyWebPageCompositor()
3206 d->m_backingStore->d->suspendScreenAndBackingStoreUpdates();
3208 // Close the backforward list and release the cached pages.
3209 d->m_page->backForward()->close();
3210 pageCache()->releaseAutoreleasedPagesNow();
3212 FrameLoader* loader = d->m_mainFrame->loader();
3214 // Remove main frame's backing store client from the map
3215 // to prevent FrameLoaderClientBlackyBerry::detachFromParent2(),
3216 // which is called by loader->detachFromParent(), deleting it.
3217 // We will delete it in ~WebPagePrivate().
3218 // Reason: loader->detachFromParent() may ping back to backing store
3219 // indirectly through ChromeClientBlackBerry::invalidateContentsAndWindow().
3220 // see RIM PR #93256.
3221 d->removeBackingStoreClientForFrame(d->m_mainFrame);
3223 // Set m_mainFrame to 0 to avoid calls back in to the backingstore during webpage deletion.
3226 loader->detachFromParent();
3228 deleteGuardedObject(this);
3231 WebPageClient* WebPage::client() const
3236 int WebPage::backForwardListLength() const
3238 return d->m_page->getHistoryLength();
3241 bool WebPage::canGoBackOrForward(int delta) const
3243 return d->m_page->canGoBackOrForward(delta);
3246 bool WebPage::goBackOrForward(int delta)
3248 if (d->m_page->canGoBackOrForward(delta)) {
3249 d->m_page->goBackOrForward(delta);
3255 void WebPage::goToBackForwardEntry(BackForwardId id)
3257 HistoryItem* item = historyItemFromBackForwardId(id);
3259 d->m_page->goToItem(item, FrameLoadTypeIndexedBackForward);
3262 void WebPage::reload()
3264 d->m_mainFrame->loader()->reload(/* bypassCache */ true);
3267 void WebPage::reloadFromCache()
3269 d->m_mainFrame->loader()->reload(/* bypassCache */ false);
3272 WebSettings* WebPage::settings() const
3274 return d->m_webSettings;
3277 bool WebPage::isVisible() const
3279 return d->m_visible;
3282 #if ENABLE(PAGE_VISIBILITY_API)
3283 class DeferredTaskSetPageVisibilityState: public DeferredTask<&WebPagePrivate::m_wouldSetPageVisibilityState> {
3285 explicit DeferredTaskSetPageVisibilityState(WebPagePrivate* webPagePrivate)
3286 : DeferredTaskType(webPagePrivate)
3290 virtual void performInternal(WebPagePrivate* webPagePrivate)
3292 webPagePrivate->setPageVisibilityState();
3296 void WebPagePrivate::setPageVisibilityState()
3298 if (m_page->defersLoading())
3299 m_deferredTasks.append(adoptPtr(new DeferredTaskSetPageVisibilityState(this)));
3301 DeferredTaskSetPageVisibilityState::finishOrCancel(this);
3303 static bool s_initialVisibilityState = true;
3305 m_page->setVisibilityState(m_visible && m_activationState == ActivationActive ? PageVisibilityStateVisible : PageVisibilityStateHidden, s_initialVisibilityState);
3306 s_initialVisibilityState = false;
3311 void WebPagePrivate::setVisible(bool visible)
3313 m_visible = visible;
3315 #if ENABLE(PAGE_VISIBILITY_API)
3316 setPageVisibilityState();
3320 void WebPage::setVisible(bool visible)
3322 if (d->m_visible == visible)
3325 d->setVisible(visible);
3328 d->suspendBackingStore();
3330 // Remove this WebPage from the visible pages list.
3331 size_t foundIndex = visibleWebPages()->find(this);
3332 if (foundIndex != WTF::notFound)
3333 visibleWebPages()->remove(foundIndex);
3335 // Return the backing store to the last visible WebPage.
3336 if (BackingStorePrivate::currentBackingStoreOwner() == this && !visibleWebPages()->isEmpty())
3337 visibleWebPages()->last()->d->resumeBackingStore();
3339 #if USE(ACCELERATED_COMPOSITING)
3340 // Root layer commit is not necessary for invisible tabs.
3341 // And release layer resources can reduce memory consumption.
3342 d->suspendRootLayerCommit();
3348 #if USE(ACCELERATED_COMPOSITING)
3349 d->resumeRootLayerCommit();
3352 // Push this WebPage to the top of the visible pages list.
3353 if (!visibleWebPages()->isEmpty() && visibleWebPages()->last() != this) {
3354 size_t foundIndex = visibleWebPages()->find(this);
3355 if (foundIndex != WTF::notFound)
3356 visibleWebPages()->remove(foundIndex);
3358 visibleWebPages()->append(this);
3360 if (BackingStorePrivate::currentBackingStoreOwner()
3361 && BackingStorePrivate::currentBackingStoreOwner() != this)
3362 BackingStorePrivate::currentBackingStoreOwner()->d->suspendBackingStore();
3364 // resumeBackingStore will set the current owner to this webpage.
3365 // If we set the owner prematurely, then the tiles will not be reset.
3366 d->resumeBackingStore();
3369 void WebPagePrivate::selectionChanged(Frame* frame)
3371 m_inputHandler->selectionChanged();
3373 // FIXME: This is a hack!
3374 // To ensure the selection being changed has its frame 'focused', lets
3375 // set it as focused ourselves (PR #104724).
3376 m_page->focusController()->setFocusedFrame(frame);
3379 void WebPagePrivate::updateDelegatedOverlays(bool dispatched)
3381 // Track a dispatched message, we don't want to flood the webkit thread.
3382 // There can be as many as one more message enqued as needed but never less.
3384 m_updateDelegatedOverlaysDispatched = false;
3385 else if (m_updateDelegatedOverlaysDispatched) {
3386 // Early return if there is message already pending on the webkit thread.
3390 if (Platform::webKitThreadMessageClient()->isCurrentThread()) {
3391 // Must be called on the WebKit thread.
3392 if (m_selectionHandler->isSelectionActive())
3393 m_selectionHandler->selectionPositionChanged(true /* visualChangeOnly */);
3394 if (m_inspectorOverlay)
3395 m_inspectorOverlay->update();
3397 } else if (m_selectionHandler->isSelectionActive()) {
3398 // Don't bother dispatching to webkit thread if selection and tap highlight are not active.
3399 m_updateDelegatedOverlaysDispatched = true;
3400 Platform::webKitThreadMessageClient()->dispatchMessage(Platform::createMethodCallMessage(&WebPagePrivate::updateDelegatedOverlays, this, true /*dispatched*/));
3404 void WebPage::setCaretHighlightStyle(Platform::CaretHighlightStyle style)
3408 bool WebPage::setBatchEditingActive(bool active)
3410 return d->m_inputHandler->setBatchEditingActive(active);
3413 bool WebPage::setInputSelection(unsigned start, unsigned end)
3415 if (d->m_page->defersLoading())
3417 return d->m_inputHandler->setSelection(start, end);
3420 int WebPage::inputCaretPosition() const
3422 return d->m_inputHandler->caretPosition();
3425 class DeferredTaskPopupListSelectMultiple: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectMultiple> {
3427 DeferredTaskPopupListSelectMultiple(WebPagePrivate* webPagePrivate, int size, const bool* selecteds)
3428 : DeferredTaskType(webPagePrivate)
3430 webPagePrivate->m_cachedPopupListSelecteds.append(selecteds, size);
3433 virtual void performInternal(WebPagePrivate* webPagePrivate)
3435 webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelecteds.size(), webPagePrivate->m_cachedPopupListSelecteds.data());
3439 class DeferredTaskPopupListSelectSingle: public DeferredTask<&WebPagePrivate::m_wouldPopupListSelectSingle> {
3441 explicit DeferredTaskPopupListSelectSingle(WebPagePrivate* webPagePrivate, int index)
3442 : DeferredTaskType(webPagePrivate)
3444 webPagePrivate->m_cachedPopupListSelectedIndex = index;
3447 virtual void performInternal(WebPagePrivate* webPagePrivate)
3449 webPagePrivate->m_webPage->popupListClosed(webPagePrivate->m_cachedPopupListSelectedIndex);
3453 void WebPage::popupListClosed(int size, const bool* selecteds)
3455 DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3456 if (d->m_page->defersLoading()) {
3457 d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectMultiple(d, size, selecteds)));
3460 DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3461 d->m_inputHandler->setPopupListIndexes(size, selecteds);
3464 void WebPage::popupListClosed(int index)
3466 DeferredTaskPopupListSelectMultiple::finishOrCancel(d);
3467 if (d->m_page->defersLoading()) {
3468 d->m_deferredTasks.append(adoptPtr(new DeferredTaskPopupListSelectSingle(d, index)));
3471 DeferredTaskPopupListSelectSingle::finishOrCancel(d);
3472 d->m_inputHandler->setPopupListIndex(index);
3475 class DeferredTaskSetDateTimeInput: public DeferredTask<&WebPagePrivate::m_wouldSetDateTimeInput> {
3477 explicit DeferredTaskSetDateTimeInput(WebPagePrivate* webPagePrivate, WebString value)
3478 : DeferredTaskType(webPagePrivate)
3480 webPagePrivate->m_cachedDateTimeInput = value;
3483 virtual void performInternal(WebPagePrivate* webPagePrivate)
3485 webPagePrivate->m_webPage->setDateTimeInput(webPagePrivate->m_cachedDateTimeInput);
3489 void WebPage::setDateTimeInput(const WebString& value)
3491 if (d->m_page->defersLoading()) {
3492 d->m_deferredTasks.append(adoptPtr(new DeferredTaskSetDateTimeInput(d, value)));
3495 DeferredTaskSetDateTimeInput::finishOrCancel(d);
3496 d->m_inputHandler->setInputValue(String(value.impl()));
3499 class DeferredTaskSetColorInput: public DeferredTask<&WebPagePrivate::m_wouldSetColorInput> {