1/*
2 * Copyright (C) 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Corporation. All rights reserved.
4 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 * THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "config.h"
29#include "WebPage.h"
30
31#include "Arguments.h"
32#include "DataReference.h"
33#include "DragControllerAction.h"
34#include "DrawingArea.h"
35#include "DrawingAreaMessages.h"
36#include "EditingRange.h"
37#include "EditorState.h"
38#include "EventDispatcher.h"
39#include "InjectedBundle.h"
40#include "InjectedBundleBackForwardList.h"
41#include "InjectedBundleUserMessageCoders.h"
42#include "LayerTreeHost.h"
43#include "Logging.h"
44#include "NetscapePlugin.h"
45#include "NotificationPermissionRequestManager.h"
46#include "PageBanner.h"
47#include "PluginProcessAttributes.h"
48#include "PluginProxy.h"
49#include "PluginView.h"
50#include "PrintInfo.h"
51#include "ServicesOverlayController.h"
52#include "SessionState.h"
53#include "SessionStateConversion.h"
54#include "SessionTracker.h"
55#include "ShareableBitmap.h"
56#include "VisitedLinkTableController.h"
57#include "WKBundleAPICast.h"
58#include "WKRetainPtr.h"
59#include "WKSharedAPICast.h"
60#include "WebAlternativeTextClient.h"
61#include "WebBackForwardListItem.h"
62#include "WebBackForwardListProxy.h"
63#include "WebChromeClient.h"
64#include "WebColorChooser.h"
65#include "WebContextMenu.h"
66#include "WebContextMenuClient.h"
67#include "WebContextMessages.h"
68#include "WebCoreArgumentCoders.h"
69#include "WebDocumentLoader.h"
70#include "WebDragClient.h"
71#include "WebEditorClient.h"
72#include "WebEvent.h"
73#include "WebEventConversion.h"
74#include "WebFrame.h"
75#include "WebFrameLoaderClient.h"
76#include "WebFullScreenManager.h"
77#include "WebFullScreenManagerMessages.h"
78#include "WebGeolocationClient.h"
79#include "WebImage.h"
80#include "WebInspector.h"
81#include "WebInspectorClient.h"
82#include "WebInspectorMessages.h"
83#include "WebNotificationClient.h"
84#include "WebOpenPanelResultListener.h"
85#include "WebPageCreationParameters.h"
86#include "WebPageGroupProxy.h"
87#include "WebPageMessages.h"
88#include "WebPageProxyMessages.h"
89#include "WebPlugInClient.h"
90#include "WebPopupMenu.h"
91#include "WebPreferencesDefinitions.h"
92#include "WebPreferencesKeys.h"
93#include "WebPreferencesStore.h"
94#include "WebProcess.h"
95#include "WebProcessProxyMessages.h"
96#include "WebProgressTrackerClient.h"
97#include "WebUndoStep.h"
98#include "WebUserContentController.h"
99#include <JavaScriptCore/APICast.h>
100#include <WebCore/ArchiveResource.h>
101#include <WebCore/Chrome.h>
102#include <WebCore/ContextMenuController.h>
103#include <WebCore/DatabaseManager.h>
104#include <WebCore/DocumentFragment.h>
105#include <WebCore/DocumentLoader.h>
106#include <WebCore/DocumentMarkerController.h>
107#include <WebCore/DragController.h>
108#include <WebCore/DragData.h>
109#include <WebCore/ElementIterator.h>
110#include <WebCore/EventHandler.h>
111#include <WebCore/FocusController.h>
112#include <WebCore/FormState.h>
113#include <WebCore/FrameLoadRequest.h>
114#include <WebCore/FrameLoaderTypes.h>
115#include <WebCore/FrameView.h>
116#include <WebCore/HTMLFormElement.h>
117#include <WebCore/HTMLInputElement.h>
118#include <WebCore/HTMLPlugInElement.h>
119#include <WebCore/HTMLPlugInImageElement.h>
120#include <WebCore/HistoryController.h>
121#include <WebCore/HistoryItem.h>
122#include <WebCore/HitTestResult.h>
123#include <WebCore/JSDOMWindow.h>
124#include <WebCore/KeyboardEvent.h>
125#include <WebCore/MIMETypeRegistry.h>
126#include <WebCore/MainFrame.h>
127#include <WebCore/MouseEvent.h>
128#include <WebCore/Page.h>
129#include <WebCore/PageThrottler.h>
130#include <WebCore/PlatformKeyboardEvent.h>
131#include <WebCore/PluginDocument.h>
132#include <WebCore/PrintContext.h>
133#include <WebCore/Range.h>
134#include <WebCore/RenderLayer.h>
135#include <WebCore/RenderTreeAsText.h>
136#include <WebCore/RenderView.h>
137#include <WebCore/ResourceBuffer.h>
138#include <WebCore/ResourceRequest.h>
139#include <WebCore/ResourceResponse.h>
140#include <WebCore/RuntimeEnabledFeatures.h>
141#include <WebCore/SchemeRegistry.h>
142#include <WebCore/ScriptController.h>
143#include <WebCore/SerializedScriptValue.h>
144#include <WebCore/SessionID.h>
145#include <WebCore/Settings.h>
146#include <WebCore/ShadowRoot.h>
147#include <WebCore/SharedBuffer.h>
148#include <WebCore/SubframeLoader.h>
149#include <WebCore/SubstituteData.h>
150#include <WebCore/TextIterator.h>
151#include <WebCore/UserInputBridge.h>
152#include <WebCore/VisiblePosition.h>
153#include <WebCore/VisibleUnits.h>
154#include <WebCore/markup.h>
155#include <bindings/ScriptValue.h>
156#include <profiler/ProfilerDatabase.h>
157#include <runtime/JSCInlines.h>
158#include <runtime/JSCJSValue.h>
159#include <runtime/JSLock.h>
160#include <wtf/RunLoop.h>
161
162#if ENABLE(MHTML)
163#include <WebCore/MHTMLArchive.h>
164#endif
165
166#if ENABLE(BATTERY_STATUS)
167#include "WebBatteryClient.h"
168#endif
169
170#if ENABLE(VIBRATION)
171#include "WebVibrationClient.h"
172#endif
173
174#if ENABLE(PROXIMITY_EVENTS)
175#include "WebDeviceProximityClient.h"
176#endif
177
178#if PLATFORM(COCOA)
179#include "PDFPlugin.h"
180#include "RemoteLayerTreeTransaction.h"
181#include "WKStringCF.h"
182#include <WebCore/LegacyWebArchive.h>
183#endif
184
185#if PLATFORM(GTK)
186#include <gtk/gtk.h>
187#include "DataObjectGtk.h"
188#include "WebPrintOperationGtk.h"
189#endif
190
191#if PLATFORM(IOS)
192#include "RemoteLayerTreeDrawingArea.h"
193#include "WebVideoFullscreenManager.h"
194#include <CoreGraphics/CoreGraphics.h>
195#include <CoreText/CTFontDescriptorPriv.h>
196#include <CoreText/CTFontPriv.h>
197#include <WebCore/Icon.h>
198#endif
199
200#ifndef NDEBUG
201#include <wtf/RefCountedLeakCounter.h>
202#endif
203
204#if USE(COORDINATED_GRAPHICS)
205#include "CoordinatedLayerTreeHostMessages.h"
206#endif
207
208using namespace JSC;
209using namespace WebCore;
210
211namespace WebKit {
212
213class SendStopResponsivenessTimer {
214public:
215    SendStopResponsivenessTimer(WebPage* page)
216        : m_page(page)
217    {
218    }
219
220    ~SendStopResponsivenessTimer()
221    {
222        m_page->send(Messages::WebPageProxy::StopResponsivenessTimer());
223    }
224
225private:
226    WebPage* m_page;
227};
228
229DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageCounter, ("WebPage"));
230
231PassRefPtr<WebPage> WebPage::create(uint64_t pageID, const WebPageCreationParameters& parameters)
232{
233    RefPtr<WebPage> page = adoptRef(new WebPage(pageID, parameters));
234
235    if (page->pageGroup()->isVisibleToInjectedBundle() && WebProcess::shared().injectedBundle())
236        WebProcess::shared().injectedBundle()->didCreatePage(page.get());
237
238    return page.release();
239}
240
241WebPage::WebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
242    : m_pageID(pageID)
243    , m_viewSize(parameters.viewSize)
244    , m_hasSeenPlugin(false)
245    , m_useFixedLayout(false)
246    , m_drawsBackground(true)
247    , m_drawsTransparentBackground(false)
248    , m_isInRedo(false)
249    , m_isClosed(false)
250    , m_tabToLinks(false)
251    , m_asynchronousPluginInitializationEnabled(false)
252    , m_asynchronousPluginInitializationEnabledForAllPlugins(false)
253    , m_artificialPluginInitializationDelayEnabled(false)
254    , m_scrollingPerformanceLoggingEnabled(false)
255    , m_mainFrameIsScrollable(true)
256#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
257    , m_readyToFindPrimarySnapshottedPlugin(false)
258    , m_didFindPrimarySnapshottedPlugin(false)
259    , m_numberOfPrimarySnapshotDetectionAttempts(0)
260    , m_determinePrimarySnapshottedPlugInTimer(RunLoop::main(), this, &WebPage::determinePrimarySnapshottedPlugInTimerFired)
261#endif
262#if ENABLE(SERVICE_CONTROLS)
263    , m_serviceControlsEnabled(false)
264#endif
265    , m_layerHostingMode(parameters.layerHostingMode)
266#if PLATFORM(COCOA)
267    , m_pdfPluginEnabled(false)
268    , m_hasCachedWindowFrame(false)
269    , m_viewGestureGeometryCollector(*this)
270#elif PLATFORM(GTK) && HAVE(ACCESSIBILITY)
271    , m_accessibilityObject(0)
272#endif
273    , m_setCanStartMediaTimer(RunLoop::main(), this, &WebPage::setCanStartMediaTimerFired)
274    , m_formClient(std::make_unique<API::InjectedBundle::FormClient>())
275    , m_uiClient(std::make_unique<API::InjectedBundle::PageUIClient>())
276    , m_findController(this)
277#if ENABLE(INPUT_TYPE_COLOR)
278    , m_activeColorChooser(0)
279#endif
280    , m_userContentController(parameters.userContentControllerID ? WebUserContentController::getOrCreate(parameters.userContentControllerID) : nullptr)
281#if ENABLE(GEOLOCATION)
282    , m_geolocationPermissionRequestManager(this)
283#endif
284    , m_canRunBeforeUnloadConfirmPanel(parameters.canRunBeforeUnloadConfirmPanel)
285    , m_canRunModal(parameters.canRunModal)
286    , m_isRunningModal(false)
287    , m_cachedMainFrameIsPinnedToLeftSide(true)
288    , m_cachedMainFrameIsPinnedToRightSide(true)
289    , m_cachedMainFrameIsPinnedToTopSide(true)
290    , m_cachedMainFrameIsPinnedToBottomSide(true)
291    , m_canShortCircuitHorizontalWheelEvents(false)
292    , m_numWheelEventHandlers(0)
293    , m_cachedPageCount(0)
294    , m_autoSizingShouldExpandToViewHeight(false)
295#if ENABLE(CONTEXT_MENUS)
296    , m_isShowingContextMenu(false)
297#endif
298#if PLATFORM(IOS)
299    , m_firstLayerTreeTransactionIDAfterDidCommitLoad(0)
300    , m_hasReceivedVisibleContentRectsAfterDidCommitLoad(false)
301    , m_scaleWasSetByUIProcess(false)
302    , m_userHasChangedPageScaleFactor(false)
303    , m_hasStablePageScaleFactor(true)
304    , m_userIsInteracting(false)
305    , m_hasPendingBlurNotification(false)
306    , m_useTestingViewportConfiguration(false)
307    , m_isInStableState(true)
308    , m_oldestNonStableUpdateVisibleContentRectsTimestamp(std::chrono::milliseconds::zero())
309    , m_estimatedLatency(std::chrono::milliseconds::zero())
310    , m_screenSize(parameters.screenSize)
311    , m_availableScreenSize(parameters.availableScreenSize)
312    , m_deviceOrientation(0)
313    , m_inDynamicSizeUpdate(false)
314#endif
315    , m_inspectorClient(0)
316    , m_backgroundColor(Color::white)
317    , m_maximumRenderingSuppressionToken(0)
318    , m_scrollPinningBehavior(DoNotPin)
319    , m_useAsyncScrolling(false)
320    , m_viewState(parameters.viewState)
321    , m_processSuppressionDisabledByWebPreference("Process suppression is disabled.")
322    , m_pendingNavigationID(0)
323#if ENABLE(WEBGL)
324    , m_systemWebGLPolicy(WebGLAllowCreation)
325#endif
326    , m_pageOverlayController(*this)
327{
328    ASSERT(m_pageID);
329    // FIXME: This is a non-ideal location for this Setting and
330    // 4ms should be adopted project-wide now, https://bugs.webkit.org/show_bug.cgi?id=61214
331    Settings::setDefaultMinDOMTimerInterval(0.004);
332
333#if PLATFORM(IOS)
334    Settings::setShouldManageAudioSessionCategory(true);
335#endif
336
337    Page::PageClients pageClients;
338    pageClients.chromeClient = new WebChromeClient(this);
339#if ENABLE(CONTEXT_MENUS)
340    pageClients.contextMenuClient = new WebContextMenuClient(this);
341#endif
342    pageClients.editorClient = new WebEditorClient(this);
343#if ENABLE(DRAG_SUPPORT)
344    pageClients.dragClient = new WebDragClient(this);
345#endif
346    pageClients.backForwardClient = WebBackForwardListProxy::create(this);
347#if ENABLE(INSPECTOR)
348    m_inspectorClient = new WebInspectorClient(this);
349    pageClients.inspectorClient = m_inspectorClient;
350#endif
351#if USE(AUTOCORRECTION_PANEL)
352    pageClients.alternativeTextClient = new WebAlternativeTextClient(this);
353#endif
354    pageClients.plugInClient = new WebPlugInClient(this);
355    pageClients.loaderClientForMainFrame = new WebFrameLoaderClient;
356    pageClients.progressTrackerClient = new WebProgressTrackerClient(*this);
357
358    pageClients.userContentController = m_userContentController ? &m_userContentController->userContentController() : nullptr;
359    pageClients.visitedLinkStore = VisitedLinkTableController::getOrCreate(parameters.visitedLinkTableID);
360
361    m_page = std::make_unique<Page>(pageClients);
362
363    m_drawingArea = DrawingArea::create(*this, parameters);
364    m_drawingArea->setPaintingEnabled(false);
365    m_pageOverlayController.initialize();
366
367#if ENABLE(ASYNC_SCROLLING)
368    m_useAsyncScrolling = parameters.store.getBoolValueForKey(WebPreferencesKey::threadedScrollingEnabledKey());
369    if (!m_drawingArea->supportsAsyncScrolling())
370        m_useAsyncScrolling = false;
371    m_page->settings().setScrollingCoordinatorEnabled(m_useAsyncScrolling);
372#endif
373
374    m_mainFrame = WebFrame::createWithCoreMainFrame(this, &m_page->mainFrame());
375
376#if ENABLE(BATTERY_STATUS)
377    WebCore::provideBatteryTo(m_page.get(), new WebBatteryClient(this));
378#endif
379#if ENABLE(GEOLOCATION)
380    WebCore::provideGeolocationTo(m_page.get(), new WebGeolocationClient(this));
381#endif
382#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
383    WebCore::provideNotification(m_page.get(), new WebNotificationClient(this));
384#endif
385#if ENABLE(VIBRATION)
386    WebCore::provideVibrationTo(m_page.get(), new WebVibrationClient(this));
387#endif
388#if ENABLE(PROXIMITY_EVENTS)
389    WebCore::provideDeviceProximityTo(m_page.get(), new WebDeviceProximityClient(this));
390#endif
391
392#if ENABLE(REMOTE_INSPECTOR)
393    m_page->setRemoteInspectionAllowed(true);
394#endif
395
396    m_page->setCanStartMedia(false);
397    m_mayStartMediaWhenInWindow = parameters.mayStartMediaWhenInWindow;
398
399    m_pageGroup = WebProcess::shared().webPageGroup(parameters.pageGroupData);
400    m_page->setGroupName(m_pageGroup->identifier());
401    m_page->setDeviceScaleFactor(parameters.deviceScaleFactor);
402#if PLATFORM(IOS)
403    m_page->setTextAutosizingWidth(parameters.textAutosizingWidth);
404#endif
405
406    updatePreferences(parameters.store);
407    platformInitialize();
408
409    setUseFixedLayout(parameters.useFixedLayout);
410
411    setDrawsBackground(parameters.drawsBackground);
412    setDrawsTransparentBackground(parameters.drawsTransparentBackground);
413
414    setUnderlayColor(parameters.underlayColor);
415
416    setPaginationMode(parameters.paginationMode);
417    setPaginationBehavesLikeColumns(parameters.paginationBehavesLikeColumns);
418    setPageLength(parameters.pageLength);
419    setGapBetweenPages(parameters.gapBetweenPages);
420
421    // If the page is created off-screen, its visibilityState should be prerender.
422    m_page->setViewState(m_viewState);
423    if (!isVisible())
424        m_page->setIsPrerender();
425    m_page->createPageThrottler();
426
427    updateIsInWindow(true);
428
429    setMinimumLayoutSize(parameters.minimumLayoutSize);
430    setAutoSizingShouldExpandToViewHeight(parameters.autoSizingShouldExpandToViewHeight);
431
432    setScrollPinningBehavior(parameters.scrollPinningBehavior);
433    setBackgroundExtendsBeyondPage(parameters.backgroundExtendsBeyondPage);
434
435    setTopContentInset(parameters.topContentInset);
436
437    m_userAgent = parameters.userAgent;
438
439    WebBackForwardListProxy::setHighestItemIDFromUIProcess(parameters.highestUsedBackForwardItemID);
440
441    if (!parameters.itemStates.isEmpty())
442        restoreSession(parameters.itemStates);
443
444    if (parameters.sessionID.isValid())
445        setSessionID(parameters.sessionID);
446
447    m_drawingArea->setPaintingEnabled(true);
448
449    setMediaVolume(parameters.mediaVolume);
450
451    // We use the DidFirstVisuallyNonEmptyLayout milestone to determine when to unfreeze the layer tree.
452    m_page->addLayoutMilestones(DidFirstLayout | DidFirstVisuallyNonEmptyLayout);
453
454    WebProcess::shared().addMessageReceiver(Messages::WebPage::messageReceiverName(), m_pageID, *this);
455
456    // FIXME: This should be done in the object constructors, and the objects themselves should be message receivers.
457    WebProcess::shared().addMessageReceiver(Messages::DrawingArea::messageReceiverName(), m_pageID, *this);
458#if USE(COORDINATED_GRAPHICS)
459    WebProcess::shared().addMessageReceiver(Messages::CoordinatedLayerTreeHost::messageReceiverName(), m_pageID, *this);
460#endif
461#if ENABLE(INSPECTOR)
462    WebProcess::shared().addMessageReceiver(Messages::WebInspector::messageReceiverName(), m_pageID, *this);
463#endif
464#if ENABLE(FULLSCREEN_API)
465    WebProcess::shared().addMessageReceiver(Messages::WebFullScreenManager::messageReceiverName(), m_pageID, *this);
466#endif
467
468#ifndef NDEBUG
469    webPageCounter.increment();
470#endif
471
472#if ENABLE(ASYNC_SCROLLING)
473    if (m_useAsyncScrolling)
474        WebProcess::shared().eventDispatcher().addScrollingTreeForPage(this);
475#endif
476
477    for (auto& mimeType : parameters.mimeTypesWithCustomContentProviders)
478        m_mimeTypesWithCustomContentProviders.add(mimeType);
479}
480
481void WebPage::reinitializeWebPage(const WebPageCreationParameters& parameters)
482{
483    if (m_viewState != parameters.viewState)
484        setViewState(parameters.viewState);
485    if (m_layerHostingMode != parameters.layerHostingMode)
486        setLayerHostingMode(static_cast<unsigned>(parameters.layerHostingMode));
487}
488
489WebPage::~WebPage()
490{
491    if (m_backForwardList)
492        m_backForwardList->detach();
493
494    ASSERT(!m_page);
495
496#if ENABLE(ASYNC_SCROLLING)
497    if (m_useAsyncScrolling)
498        WebProcess::shared().eventDispatcher().removeScrollingTreeForPage(this);
499#endif
500
501    m_sandboxExtensionTracker.invalidate();
502
503    for (auto* pluginView : m_pluginViews)
504        pluginView->webPageDestroyed();
505
506#if !PLATFORM(IOS)
507    if (m_headerBanner)
508        m_headerBanner->detachFromPage();
509    if (m_footerBanner)
510        m_footerBanner->detachFromPage();
511#endif // !PLATFORM(IOS)
512
513    WebProcess::shared().removeMessageReceiver(Messages::WebPage::messageReceiverName(), m_pageID);
514
515    // FIXME: This should be done in the object destructors, and the objects themselves should be message receivers.
516    WebProcess::shared().removeMessageReceiver(Messages::DrawingArea::messageReceiverName(), m_pageID);
517#if USE(COORDINATED_GRAPHICS)
518    WebProcess::shared().removeMessageReceiver(Messages::CoordinatedLayerTreeHost::messageReceiverName(), m_pageID);
519#endif
520#if ENABLE(INSPECTOR)
521    WebProcess::shared().removeMessageReceiver(Messages::WebInspector::messageReceiverName(), m_pageID);
522#endif
523#if ENABLE(FULLSCREEN_API)
524    WebProcess::shared().removeMessageReceiver(Messages::WebFullScreenManager::messageReceiverName(), m_pageID);
525#endif
526
527#ifndef NDEBUG
528    webPageCounter.decrement();
529#endif
530}
531
532void WebPage::dummy(bool&)
533{
534}
535
536IPC::Connection* WebPage::messageSenderConnection()
537{
538    return WebProcess::shared().parentProcessConnection();
539}
540
541uint64_t WebPage::messageSenderDestinationID()
542{
543    return pageID();
544}
545
546#if ENABLE(CONTEXT_MENUS)
547void WebPage::initializeInjectedBundleContextMenuClient(WKBundlePageContextMenuClientBase* client)
548{
549    m_contextMenuClient.initialize(client);
550}
551#endif
552
553void WebPage::initializeInjectedBundleEditorClient(WKBundlePageEditorClientBase* client)
554{
555    m_editorClient.initialize(client);
556}
557
558void WebPage::setInjectedBundleFormClient(std::unique_ptr<API::InjectedBundle::FormClient> formClient)
559{
560    if (!formClient) {
561        m_formClient = std::make_unique<API::InjectedBundle::FormClient>();
562        return;
563    }
564
565    m_formClient = WTF::move(formClient);
566}
567
568void WebPage::initializeInjectedBundleLoaderClient(WKBundlePageLoaderClientBase* client)
569{
570    m_loaderClient.initialize(client);
571
572    // It would be nice to get rid of this code and transition all clients to using didLayout instead of
573    // didFirstLayoutInFrame and didFirstVisuallyNonEmptyLayoutInFrame. In the meantime, this is required
574    // for backwards compatibility.
575    LayoutMilestones milestones = 0;
576    if (client) {
577        if (m_loaderClient.client().didFirstLayoutForFrame)
578            milestones |= WebCore::DidFirstLayout;
579        if (m_loaderClient.client().didFirstVisuallyNonEmptyLayoutForFrame)
580            milestones |= WebCore::DidFirstVisuallyNonEmptyLayout;
581    }
582
583    if (milestones)
584        listenForLayoutMilestones(milestones);
585}
586
587void WebPage::initializeInjectedBundlePolicyClient(WKBundlePagePolicyClientBase* client)
588{
589    m_policyClient.initialize(client);
590}
591
592void WebPage::initializeInjectedBundleResourceLoadClient(WKBundlePageResourceLoadClientBase* client)
593{
594    m_resourceLoadClient.initialize(client);
595}
596
597void WebPage::setInjectedBundleUIClient(std::unique_ptr<API::InjectedBundle::PageUIClient> uiClient)
598{
599    if (!uiClient) {
600        m_uiClient = std::make_unique<API::InjectedBundle::PageUIClient>();
601        return;
602    }
603
604    m_uiClient = WTF::move(uiClient);
605}
606
607#if ENABLE(FULLSCREEN_API)
608void WebPage::initializeInjectedBundleFullScreenClient(WKBundlePageFullScreenClientBase* client)
609{
610    m_fullScreenClient.initialize(client);
611}
612#endif
613
614void WebPage::initializeInjectedBundleDiagnosticLoggingClient(WKBundlePageDiagnosticLoggingClientBase* client)
615{
616    m_logDiagnosticMessageClient.initialize(client);
617}
618
619#if ENABLE(NETSCAPE_PLUGIN_API)
620PassRefPtr<Plugin> WebPage::createPlugin(WebFrame* frame, HTMLPlugInElement* pluginElement, const Plugin::Parameters& parameters, String& newMIMEType)
621{
622    String frameURLString = frame->coreFrame()->loader().documentLoader()->responseURL().string();
623    String pageURLString = m_page->mainFrame().loader().documentLoader()->responseURL().string();
624
625#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
626    HTMLPlugInImageElement& pluginImageElement = toHTMLPlugInImageElement(*pluginElement);
627    unsigned pluginArea = 0;
628    PluginProcessType processType = pluginElement->displayState() == HTMLPlugInElement::WaitingForSnapshot && !(plugInIsPrimarySize(pluginImageElement, pluginArea) && !plugInIntersectsSearchRect(pluginImageElement)) ? PluginProcessTypeSnapshot : PluginProcessTypeNormal;
629#else
630    PluginProcessType processType = pluginElement->displayState() == HTMLPlugInElement::WaitingForSnapshot ? PluginProcessTypeSnapshot : PluginProcessTypeNormal;
631#endif
632
633    bool allowOnlyApplicationPlugins = !frame->coreFrame()->loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin);
634
635    uint64_t pluginProcessToken;
636    uint32_t pluginLoadPolicy;
637    String unavailabilityDescription;
638    if (!sendSync(Messages::WebPageProxy::FindPlugin(parameters.mimeType, static_cast<uint32_t>(processType), parameters.url.string(), frameURLString, pageURLString, allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription)))
639        return nullptr;
640
641    bool isBlockedPlugin = static_cast<PluginModuleLoadPolicy>(pluginLoadPolicy) == PluginModuleBlocked;
642
643    if (isBlockedPlugin || !pluginProcessToken) {
644#if ENABLE(PDFKIT_PLUGIN)
645        String path = parameters.url.path();
646        if (shouldUsePDFPlugin() && (MIMETypeRegistry::isPDFOrPostScriptMIMEType(parameters.mimeType) || (parameters.mimeType.isEmpty() && (path.endsWith(".pdf", false) || path.endsWith(".ps", false))))) {
647            RefPtr<PDFPlugin> pdfPlugin = PDFPlugin::create(frame);
648            return pdfPlugin.release();
649        }
650#else
651        UNUSED_PARAM(frame);
652#endif
653    }
654
655    if (isBlockedPlugin) {
656        bool replacementObscured = false;
657        if (pluginElement->renderer()->isEmbeddedObject()) {
658            RenderEmbeddedObject* renderObject = toRenderEmbeddedObject(pluginElement->renderer());
659            renderObject->setPluginUnavailabilityReasonWithDescription(RenderEmbeddedObject::InsecurePluginVersion, unavailabilityDescription);
660            replacementObscured = renderObject->isReplacementObscured();
661            renderObject->setUnavailablePluginIndicatorIsHidden(replacementObscured);
662        }
663
664        send(Messages::WebPageProxy::DidBlockInsecurePluginVersion(parameters.mimeType, parameters.url.string(), frameURLString, pageURLString, replacementObscured));
665        return nullptr;
666    }
667
668    if (!pluginProcessToken)
669        return nullptr;
670
671    bool isRestartedProcess = (pluginElement->displayState() == HTMLPlugInElement::Restarting || pluginElement->displayState() == HTMLPlugInElement::RestartingWithPendingMouseClick);
672    return PluginProxy::create(pluginProcessToken, isRestartedProcess);
673}
674
675#endif // ENABLE(NETSCAPE_PLUGIN_API)
676
677#if ENABLE(WEBGL) && !PLATFORM(COCOA)
678WebCore::WebGLLoadPolicy WebPage::webGLPolicyForURL(WebFrame*, const String& /* url */)
679{
680    return WebGLAllowCreation;
681}
682
683WebCore::WebGLLoadPolicy WebPage::resolveWebGLPolicyForURL(WebFrame*, const String& /* url */)
684{
685    return WebGLAllowCreation;
686}
687#endif
688
689EditorState WebPage::editorState() const
690{
691    Frame& frame = m_page->focusController().focusedOrMainFrame();
692
693    EditorState result;
694
695    if (PluginView* pluginView = focusedPluginViewForFrame(frame)) {
696        if (!pluginView->getSelectionString().isNull()) {
697            result.selectionIsNone = false;
698            result.selectionIsRange = true;
699            result.isInPlugin = true;
700            return result;
701        }
702    }
703
704    const VisibleSelection& selection = frame.selection().selection();
705
706    result.selectionIsNone = selection.isNone();
707    result.selectionIsRange = selection.isRange();
708    result.isContentEditable = selection.isContentEditable();
709    result.isContentRichlyEditable = selection.isContentRichlyEditable();
710    result.isInPasswordField = selection.isInPasswordField();
711    result.hasComposition = frame.editor().hasComposition();
712    result.shouldIgnoreCompositionSelectionChange = frame.editor().ignoreCompositionSelectionChange();
713
714#if PLATFORM(IOS)
715    if (frame.editor().hasComposition()) {
716        RefPtr<Range> compositionRange = frame.editor().compositionRange();
717        Vector<WebCore::SelectionRect> compositionRects;
718        compositionRange->collectSelectionRects(compositionRects);
719        if (compositionRects.size())
720            result.firstMarkedRect = compositionRects[0].rect();
721        if (compositionRects.size() > 1)
722            result.lastMarkedRect = compositionRects.last().rect();
723        else
724            result.lastMarkedRect = result.firstMarkedRect;
725        result.markedText = plainTextReplacingNoBreakSpace(compositionRange.get());
726    }
727    FrameView* view = frame.view();
728    if (selection.isCaret()) {
729        result.caretRectAtStart = view->contentsToRootView(frame.selection().absoluteCaretBounds());
730        result.caretRectAtEnd = result.caretRectAtStart;
731        // FIXME: The following check should take into account writing direction.
732        result.isReplaceAllowed = result.isContentEditable && atBoundaryOfGranularity(selection.start(), WordGranularity, DirectionForward);
733        result.wordAtSelection = plainTextReplacingNoBreakSpace(wordRangeFromPosition(selection.start()).get());
734        if (selection.isContentEditable()) {
735            charactersAroundPosition(selection.start(), result.characterAfterSelection, result.characterBeforeSelection, result.twoCharacterBeforeSelection);
736            Node* root = selection.rootEditableElement();
737            result.hasContent = root && root->hasChildNodes() && !isEndOfEditableOrNonEditableContent(firstPositionInNode(root));
738        }
739    } else if (selection.isRange()) {
740        result.caretRectAtStart = view->contentsToRootView(VisiblePosition(selection.start()).absoluteCaretBounds());
741        result.caretRectAtEnd = view->contentsToRootView(VisiblePosition(selection.end()).absoluteCaretBounds());
742        RefPtr<Range> selectedRange = selection.toNormalizedRange();
743        selectedRange->collectSelectionRects(result.selectionRects);
744        convertSelectionRectsToRootView(view, result.selectionRects);
745        String selectedText = plainTextReplacingNoBreakSpace(selectedRange.get(), TextIteratorDefaultBehavior, true);
746        // FIXME: We should disallow replace when the string contains only CJ characters.
747        result.isReplaceAllowed = result.isContentEditable && !result.isInPasswordField && !selectedText.containsOnlyWhitespace();
748        result.selectedTextLength = selectedText.length();
749        const int maxSelectedTextLength = 200;
750        if (selectedText.length() <= maxSelectedTextLength)
751            result.wordAtSelection = selectedText;
752    }
753    if (!selection.isNone()) {
754        Node* nodeToRemove;
755        if (RenderStyle* style = Editor::styleForSelectionStart(&frame, nodeToRemove)) {
756            CTFontRef font = style->font().primaryFont()->getCTFont();
757            CTFontSymbolicTraits traits = font ? CTFontGetSymbolicTraits(font) : 0;
758
759            if (traits & kCTFontTraitBold)
760                result.typingAttributes |= AttributeBold;
761            if (traits & kCTFontTraitItalic)
762                result.typingAttributes |= AttributeItalics;
763
764            if (style->textDecorationsInEffect() & TextDecorationUnderline)
765                result.typingAttributes |= AttributeUnderline;
766
767            if (nodeToRemove)
768                nodeToRemove->remove(ASSERT_NO_EXCEPTION);
769        }
770    }
771#endif
772
773#if PLATFORM(GTK)
774    result.cursorRect = frame.selection().absoluteCaretBounds();
775#endif
776
777    return result;
778}
779
780String WebPage::renderTreeExternalRepresentation() const
781{
782    return externalRepresentation(m_mainFrame->coreFrame(), RenderAsTextBehaviorNormal);
783}
784
785String WebPage::renderTreeExternalRepresentationForPrinting() const
786{
787    return externalRepresentation(m_mainFrame->coreFrame(), RenderAsTextPrintingMode);
788}
789
790uint64_t WebPage::renderTreeSize() const
791{
792    if (!m_page)
793        return 0;
794    return m_page->renderTreeSize();
795}
796
797void WebPage::setTracksRepaints(bool trackRepaints)
798{
799    if (FrameView* view = mainFrameView())
800        view->setTracksRepaints(trackRepaints);
801}
802
803bool WebPage::isTrackingRepaints() const
804{
805    if (FrameView* view = mainFrameView())
806        return view->isTrackingRepaints();
807
808    return false;
809}
810
811void WebPage::resetTrackedRepaints()
812{
813    if (FrameView* view = mainFrameView())
814        view->resetTrackedRepaints();
815}
816
817PassRefPtr<API::Array> WebPage::trackedRepaintRects()
818{
819    FrameView* view = mainFrameView();
820    if (!view)
821        return API::Array::create();
822
823    Vector<RefPtr<API::Object>> repaintRects;
824    repaintRects.reserveInitialCapacity(view->trackedRepaintRects().size());
825
826    for (const auto& repaintRect : view->trackedRepaintRects())
827        repaintRects.uncheckedAppend(API::Rect::create(toAPI(repaintRect)));
828
829    return API::Array::create(WTF::move(repaintRects));
830}
831
832PluginView* WebPage::focusedPluginViewForFrame(Frame& frame)
833{
834    if (!frame.document()->isPluginDocument())
835        return 0;
836
837    PluginDocument* pluginDocument = static_cast<PluginDocument*>(frame.document());
838
839    if (pluginDocument->focusedElement() != pluginDocument->pluginElement())
840        return 0;
841
842    PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
843    return pluginView;
844}
845
846PluginView* WebPage::pluginViewForFrame(Frame* frame)
847{
848    if (!frame->document()->isPluginDocument())
849        return 0;
850
851    PluginDocument* pluginDocument = static_cast<PluginDocument*>(frame->document());
852    PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
853    return pluginView;
854}
855
856void WebPage::executeEditingCommand(const String& commandName, const String& argument)
857{
858    Frame& frame = m_page->focusController().focusedOrMainFrame();
859
860    if (PluginView* pluginView = focusedPluginViewForFrame(frame)) {
861        pluginView->handleEditingCommand(commandName, argument);
862        return;
863    }
864
865    frame.editor().command(commandName).execute(argument);
866}
867
868bool WebPage::isEditingCommandEnabled(const String& commandName)
869{
870    Frame& frame = m_page->focusController().focusedOrMainFrame();
871
872    if (PluginView* pluginView = focusedPluginViewForFrame(frame))
873        return pluginView->isEditingCommandEnabled(commandName);
874
875    Editor::Command command = frame.editor().command(commandName);
876    return command.isSupported() && command.isEnabled();
877}
878
879void WebPage::clearMainFrameName()
880{
881    if (Frame* frame = mainFrame())
882        frame->tree().clearName();
883}
884
885void WebPage::enterAcceleratedCompositingMode(GraphicsLayer* layer)
886{
887    m_drawingArea->setRootCompositingLayer(layer);
888}
889
890void WebPage::exitAcceleratedCompositingMode()
891{
892    m_drawingArea->setRootCompositingLayer(0);
893}
894
895void WebPage::close()
896{
897    if (m_isClosed)
898        return;
899
900    m_isClosed = true;
901
902    // If there is still no URL, then we never loaded anything in this page, so nothing to report.
903    if (!mainWebFrame()->url().isEmpty())
904        reportUsedFeatures();
905
906    if (pageGroup()->isVisibleToInjectedBundle() && WebProcess::shared().injectedBundle())
907        WebProcess::shared().injectedBundle()->willDestroyPage(this);
908
909#if ENABLE(INSPECTOR)
910    m_inspector = 0;
911#endif
912#if ENABLE(FULLSCREEN_API)
913    m_fullScreenManager = 0;
914#endif
915
916    if (m_activePopupMenu) {
917        m_activePopupMenu->disconnectFromPage();
918        m_activePopupMenu = 0;
919    }
920
921    if (m_activeOpenPanelResultListener) {
922        m_activeOpenPanelResultListener->disconnectFromPage();
923        m_activeOpenPanelResultListener = 0;
924    }
925
926#if ENABLE(INPUT_TYPE_COLOR)
927    if (m_activeColorChooser) {
928        m_activeColorChooser->disconnectFromPage();
929        m_activeColorChooser = 0;
930    }
931#endif
932
933#if PLATFORM(GTK)
934    if (m_printOperation) {
935        m_printOperation->disconnectFromPage();
936        m_printOperation = nullptr;
937    }
938#endif
939
940    m_sandboxExtensionTracker.invalidate();
941
942#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
943    m_determinePrimarySnapshottedPlugInTimer.stop();
944#endif
945
946#if ENABLE(CONTEXT_MENUS)
947    m_contextMenuClient.initialize(0);
948#endif
949    m_editorClient.initialize(0);
950    m_formClient = std::make_unique<API::InjectedBundle::FormClient>();
951    m_loaderClient.initialize(0);
952    m_policyClient.initialize(0);
953    m_resourceLoadClient.initialize(0);
954    m_uiClient = std::make_unique<API::InjectedBundle::PageUIClient>();
955#if ENABLE(FULLSCREEN_API)
956    m_fullScreenClient.initialize(0);
957#endif
958    m_logDiagnosticMessageClient.initialize(0);
959
960    m_printContext = nullptr;
961    m_mainFrame->coreFrame()->loader().detachFromParent();
962    m_page = nullptr;
963    m_drawingArea = nullptr;
964
965    bool isRunningModal = m_isRunningModal;
966    m_isRunningModal = false;
967
968    // The WebPage can be destroyed by this call.
969    WebProcess::shared().removeWebPage(m_pageID);
970
971    if (isRunningModal)
972        RunLoop::main().stop();
973}
974
975void WebPage::tryClose()
976{
977    SendStopResponsivenessTimer stopper(this);
978
979    if (!corePage()->userInputBridge().tryClosePage()) {
980        send(Messages::WebPageProxy::StopResponsivenessTimer());
981        return;
982    }
983
984    send(Messages::WebPageProxy::ClosePage(true));
985}
986
987void WebPage::sendClose()
988{
989    send(Messages::WebPageProxy::ClosePage(false));
990}
991
992void WebPage::loadURLInFrame(const String& url, uint64_t frameID)
993{
994    WebFrame* frame = WebProcess::shared().webFrame(frameID);
995    if (!frame)
996        return;
997
998    frame->coreFrame()->loader().load(FrameLoadRequest(frame->coreFrame(), ResourceRequest(URL(URL(), url))));
999}
1000
1001void WebPage::loadRequest(uint64_t navigationID, const ResourceRequest& request, const SandboxExtension::Handle& sandboxExtensionHandle, IPC::MessageDecoder& decoder)
1002{
1003    SendStopResponsivenessTimer stopper(this);
1004
1005    RefPtr<API::Object> userData;
1006    InjectedBundleUserMessageDecoder userMessageDecoder(userData);
1007    if (!decoder.decode(userMessageDecoder))
1008        return;
1009
1010    m_pendingNavigationID = navigationID;
1011
1012    m_sandboxExtensionTracker.beginLoad(m_mainFrame.get(), sandboxExtensionHandle);
1013
1014    // Let the InjectedBundle know we are about to start the load, passing the user data from the UIProcess
1015    // to all the client to set up any needed state.
1016    m_loaderClient.willLoadURLRequest(this, request, userData.get());
1017
1018    // Initate the load in WebCore.
1019    corePage()->userInputBridge().loadRequest(FrameLoadRequest(m_mainFrame->coreFrame(), request));
1020
1021    ASSERT(!m_pendingNavigationID);
1022}
1023
1024void WebPage::loadDataImpl(uint64_t navigationID, PassRefPtr<SharedBuffer> sharedBuffer, const String& MIMEType, const String& encodingName, const URL& baseURL, const URL& unreachableURL, IPC::MessageDecoder& decoder)
1025{
1026    SendStopResponsivenessTimer stopper(this);
1027
1028    RefPtr<API::Object> userData;
1029    InjectedBundleUserMessageDecoder userMessageDecoder(userData);
1030    if (!decoder.decode(userMessageDecoder))
1031        return;
1032
1033    m_pendingNavigationID = navigationID;
1034
1035    ResourceRequest request(baseURL);
1036    SubstituteData substituteData(sharedBuffer, MIMEType, encodingName, unreachableURL);
1037
1038    // Let the InjectedBundle know we are about to start the load, passing the user data from the UIProcess
1039    // to all the client to set up any needed state.
1040    m_loaderClient.willLoadDataRequest(this, request, const_cast<SharedBuffer*>(substituteData.content()), substituteData.mimeType(), substituteData.textEncoding(), substituteData.failingURL(), userData.get());
1041
1042    // Initate the load in WebCore.
1043    m_mainFrame->coreFrame()->loader().load(FrameLoadRequest(m_mainFrame->coreFrame(), request, substituteData));
1044}
1045
1046void WebPage::loadString(uint64_t navigationID, const String& htmlString, const String& MIMEType, const URL& baseURL, const URL& unreachableURL, IPC::MessageDecoder& decoder)
1047{
1048    if (!htmlString.isNull() && htmlString.is8Bit()) {
1049        RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(htmlString.characters8()), htmlString.length() * sizeof(LChar));
1050        loadDataImpl(navigationID, sharedBuffer, MIMEType, ASCIILiteral("latin1"), baseURL, unreachableURL, decoder);
1051    } else {
1052        RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(htmlString.characters16()), htmlString.length() * sizeof(UChar));
1053        loadDataImpl(navigationID, sharedBuffer, MIMEType, ASCIILiteral("utf-16"), baseURL, unreachableURL, decoder);
1054    }
1055}
1056
1057void WebPage::loadData(const IPC::DataReference& data, const String& MIMEType, const String& encodingName, const String& baseURLString, IPC::MessageDecoder& decoder)
1058{
1059    RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(data.data()), data.size());
1060    URL baseURL = baseURLString.isEmpty() ? blankURL() : URL(URL(), baseURLString);
1061    loadDataImpl(0, sharedBuffer, MIMEType, encodingName, baseURL, URL(), decoder);
1062}
1063
1064void WebPage::loadHTMLString(uint64_t navigationID, const String& htmlString, const String& baseURLString, IPC::MessageDecoder& decoder)
1065{
1066    URL baseURL = baseURLString.isEmpty() ? blankURL() : URL(URL(), baseURLString);
1067    loadString(navigationID, htmlString, ASCIILiteral("text/html"), baseURL, URL(), decoder);
1068}
1069
1070void WebPage::loadAlternateHTMLString(const String& htmlString, const String& baseURLString, const String& unreachableURLString, IPC::MessageDecoder& decoder)
1071{
1072    URL baseURL = baseURLString.isEmpty() ? blankURL() : URL(URL(), baseURLString);
1073    URL unreachableURL = unreachableURLString.isEmpty() ? URL() : URL(URL(), unreachableURLString);
1074    loadString(0, htmlString, ASCIILiteral("text/html"), baseURL, unreachableURL, decoder);
1075}
1076
1077void WebPage::loadPlainTextString(const String& string, IPC::MessageDecoder& decoder)
1078{
1079    loadString(0, string, ASCIILiteral("text/plain"), blankURL(), URL(), decoder);
1080}
1081
1082void WebPage::loadWebArchiveData(const IPC::DataReference& webArchiveData, IPC::MessageDecoder& decoder)
1083{
1084    RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(reinterpret_cast<const char*>(webArchiveData.data()), webArchiveData.size() * sizeof(uint8_t));
1085    loadDataImpl(0, sharedBuffer, ASCIILiteral("application/x-webarchive"), ASCIILiteral("utf-16"), blankURL(), URL(), decoder);
1086}
1087
1088void WebPage::stopLoadingFrame(uint64_t frameID)
1089{
1090    WebFrame* frame = WebProcess::shared().webFrame(frameID);
1091    if (!frame)
1092        return;
1093
1094    corePage()->userInputBridge().stopLoadingFrame(frame->coreFrame());
1095}
1096
1097void WebPage::stopLoading()
1098{
1099    SendStopResponsivenessTimer stopper(this);
1100
1101    corePage()->userInputBridge().stopLoadingFrame(m_mainFrame->coreFrame());
1102}
1103
1104bool WebPage::defersLoading() const
1105{
1106    return m_page->defersLoading();
1107}
1108
1109void WebPage::setDefersLoading(bool defersLoading)
1110{
1111    m_page->setDefersLoading(defersLoading);
1112}
1113
1114void WebPage::reload(uint64_t navigationID, bool reloadFromOrigin, const SandboxExtension::Handle& sandboxExtensionHandle)
1115{
1116    SendStopResponsivenessTimer stopper(this);
1117
1118    ASSERT(!m_pendingNavigationID);
1119    m_pendingNavigationID = navigationID;
1120
1121    m_sandboxExtensionTracker.beginLoad(m_mainFrame.get(), sandboxExtensionHandle);
1122    corePage()->userInputBridge().reloadFrame(m_mainFrame->coreFrame(), reloadFromOrigin);
1123}
1124
1125void WebPage::goForward(uint64_t navigationID, uint64_t backForwardItemID)
1126{
1127    SendStopResponsivenessTimer stopper(this);
1128
1129    HistoryItem* item = WebBackForwardListProxy::itemForID(backForwardItemID);
1130    ASSERT(item);
1131    if (!item)
1132        return;
1133
1134    ASSERT(!m_pendingNavigationID);
1135    if (!item->isInPageCache())
1136        m_pendingNavigationID = navigationID;
1137
1138    m_page->goToItem(item, FrameLoadType::Forward);
1139}
1140
1141void WebPage::goBack(uint64_t navigationID, uint64_t backForwardItemID)
1142{
1143    SendStopResponsivenessTimer stopper(this);
1144
1145    HistoryItem* item = WebBackForwardListProxy::itemForID(backForwardItemID);
1146    ASSERT(item);
1147    if (!item)
1148        return;
1149
1150    ASSERT(!m_pendingNavigationID);
1151    if (!item->isInPageCache())
1152        m_pendingNavigationID = navigationID;
1153
1154    m_page->goToItem(item, FrameLoadType::Back);
1155}
1156
1157void WebPage::goToBackForwardItem(uint64_t navigationID, uint64_t backForwardItemID)
1158{
1159    SendStopResponsivenessTimer stopper(this);
1160
1161    HistoryItem* item = WebBackForwardListProxy::itemForID(backForwardItemID);
1162    ASSERT(item);
1163    if (!item)
1164        return;
1165
1166    ASSERT(!m_pendingNavigationID);
1167    if (!item->isInPageCache())
1168        m_pendingNavigationID = navigationID;
1169
1170    m_page->goToItem(item, FrameLoadType::IndexedBackForward);
1171}
1172
1173void WebPage::tryRestoreScrollPosition()
1174{
1175    m_page->mainFrame().loader().history().restoreScrollPositionAndViewState();
1176}
1177
1178void WebPage::layoutIfNeeded()
1179{
1180    if (m_mainFrame->coreFrame()->view())
1181        m_mainFrame->coreFrame()->view()->updateLayoutAndStyleIfNeededRecursive();
1182}
1183
1184WebPage* WebPage::fromCorePage(Page* page)
1185{
1186    return static_cast<WebChromeClient&>(page->chrome().client()).page();
1187}
1188
1189void WebPage::setSize(const WebCore::IntSize& viewSize)
1190{
1191    if (m_viewSize == viewSize)
1192        return;
1193
1194    FrameView* view = m_page->mainFrame().view();
1195    view->resize(viewSize);
1196    m_drawingArea->setNeedsDisplay();
1197
1198    m_viewSize = viewSize;
1199
1200#if USE(TILED_BACKING_STORE)
1201    if (view->useFixedLayout())
1202        sendViewportAttributesChanged();
1203#endif
1204
1205    m_pageOverlayController.didChangeViewSize();
1206}
1207
1208#if USE(TILED_BACKING_STORE)
1209void WebPage::setFixedVisibleContentRect(const IntRect& rect)
1210{
1211    ASSERT(m_useFixedLayout);
1212
1213    m_page->mainFrame().view()->setFixedVisibleContentRect(rect);
1214}
1215
1216void WebPage::sendViewportAttributesChanged()
1217{
1218    ASSERT(m_useFixedLayout);
1219
1220    // Viewport properties have no impact on zero sized fixed viewports.
1221    if (m_viewSize.isEmpty())
1222        return;
1223
1224    // Recalculate the recommended layout size, when the available size (device pixel) changes.
1225    Settings& settings = m_page->settings();
1226
1227    int minimumLayoutFallbackWidth = std::max(settings.layoutFallbackWidth(), m_viewSize.width());
1228
1229    // If unset  we use the viewport dimensions. This fits with the behavior of desktop browsers.
1230    int deviceWidth = (settings.deviceWidth() > 0) ? settings.deviceWidth() : m_viewSize.width();
1231    int deviceHeight = (settings.deviceHeight() > 0) ? settings.deviceHeight() : m_viewSize.height();
1232
1233    ViewportAttributes attr = computeViewportAttributes(m_page->viewportArguments(), minimumLayoutFallbackWidth, deviceWidth, deviceHeight, 1, m_viewSize);
1234
1235    FrameView* view = m_page->mainFrame().view();
1236
1237    // If no layout was done yet set contentFixedOrigin to (0,0).
1238    IntPoint contentFixedOrigin = view->didFirstLayout() ? view->fixedVisibleContentRect().location() : IntPoint();
1239
1240    // Put the width and height to the viewport width and height. In css units however.
1241    // Use FloatSize to avoid truncated values during scale.
1242    FloatSize contentFixedSize = m_viewSize;
1243
1244#if ENABLE(CSS_DEVICE_ADAPTATION)
1245    // CSS viewport descriptors might be applied to already affected viewport size
1246    // if the page enables/disables stylesheets, so need to keep initial viewport size.
1247    view->setInitialViewportSize(roundedIntSize(contentFixedSize));
1248#endif
1249
1250    contentFixedSize.scale(1 / attr.initialScale);
1251    setFixedVisibleContentRect(IntRect(contentFixedOrigin, roundedIntSize(contentFixedSize)));
1252
1253    attr.initialScale = m_page->viewportArguments().zoom; // Resets auto (-1) if no value was set by user.
1254
1255    // This also takes care of the relayout.
1256    setFixedLayoutSize(roundedIntSize(attr.layoutSize));
1257
1258    send(Messages::WebPageProxy::DidChangeViewportProperties(attr));
1259}
1260#endif
1261
1262void WebPage::scrollMainFrameIfNotAtMaxScrollPosition(const IntSize& scrollOffset)
1263{
1264    FrameView* frameView = m_page->mainFrame().view();
1265
1266    IntPoint scrollPosition = frameView->scrollPosition();
1267    IntPoint maximumScrollPosition = frameView->maximumScrollPosition();
1268
1269    // If the current scroll position in a direction is the max scroll position
1270    // we don't want to scroll at all.
1271    IntSize newScrollOffset;
1272    if (scrollPosition.x() < maximumScrollPosition.x())
1273        newScrollOffset.setWidth(scrollOffset.width());
1274    if (scrollPosition.y() < maximumScrollPosition.y())
1275        newScrollOffset.setHeight(scrollOffset.height());
1276
1277    if (newScrollOffset.isZero())
1278        return;
1279
1280    frameView->setScrollPosition(frameView->scrollPosition() + newScrollOffset);
1281}
1282
1283void WebPage::drawRect(GraphicsContext& graphicsContext, const IntRect& rect)
1284{
1285    GraphicsContextStateSaver stateSaver(graphicsContext);
1286    graphicsContext.clip(rect);
1287
1288    m_mainFrame->coreFrame()->view()->paint(&graphicsContext, rect);
1289}
1290
1291double WebPage::textZoomFactor() const
1292{
1293    Frame* frame = m_mainFrame->coreFrame();
1294    if (!frame)
1295        return 1;
1296    return frame->textZoomFactor();
1297}
1298
1299void WebPage::setTextZoomFactor(double zoomFactor)
1300{
1301    PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1302    if (pluginView && pluginView->handlesPageScaleFactor())
1303        return;
1304
1305    Frame* frame = m_mainFrame->coreFrame();
1306    if (!frame)
1307        return;
1308    frame->setTextZoomFactor(static_cast<float>(zoomFactor));
1309}
1310
1311double WebPage::pageZoomFactor() const
1312{
1313    PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1314    if (pluginView && pluginView->handlesPageScaleFactor())
1315        return pluginView->pageScaleFactor();
1316
1317    Frame* frame = m_mainFrame->coreFrame();
1318    if (!frame)
1319        return 1;
1320    return frame->pageZoomFactor();
1321}
1322
1323void WebPage::setPageZoomFactor(double zoomFactor)
1324{
1325    PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1326    if (pluginView && pluginView->handlesPageScaleFactor()) {
1327        pluginView->setPageScaleFactor(zoomFactor, IntPoint());
1328        return;
1329    }
1330
1331    Frame* frame = m_mainFrame->coreFrame();
1332    if (!frame)
1333        return;
1334    frame->setPageZoomFactor(static_cast<float>(zoomFactor));
1335}
1336
1337void WebPage::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor)
1338{
1339    PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1340    if (pluginView && pluginView->handlesPageScaleFactor()) {
1341        pluginView->setPageScaleFactor(pageZoomFactor, IntPoint());
1342        return;
1343    }
1344
1345    Frame* frame = m_mainFrame->coreFrame();
1346    if (!frame)
1347        return;
1348    return frame->setPageAndTextZoomFactors(static_cast<float>(pageZoomFactor), static_cast<float>(textZoomFactor));
1349}
1350
1351void WebPage::windowScreenDidChange(uint64_t displayID)
1352{
1353    m_page->chrome().windowScreenDidChange(static_cast<PlatformDisplayID>(displayID));
1354}
1355
1356void WebPage::scalePage(double scale, const IntPoint& origin)
1357{
1358    bool willChangeScaleFactor = scale != pageScaleFactor();
1359
1360#if PLATFORM(IOS)
1361    if (willChangeScaleFactor) {
1362        if (!m_inDynamicSizeUpdate)
1363            m_dynamicSizeUpdateHistory.clear();
1364        m_scaleWasSetByUIProcess = false;
1365    }
1366#endif
1367    PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1368    if (pluginView && pluginView->handlesPageScaleFactor()) {
1369        pluginView->setPageScaleFactor(scale, origin);
1370        return;
1371    }
1372
1373    m_page->setPageScaleFactor(scale, origin);
1374
1375    // We can't early return before setPageScaleFactor because the origin might be different.
1376    if (!willChangeScaleFactor)
1377        return;
1378
1379    for (auto* pluginView : m_pluginViews)
1380        pluginView->pageScaleFactorDidChange();
1381
1382    if (m_drawingArea->layerTreeHost())
1383        m_drawingArea->layerTreeHost()->deviceOrPageScaleFactorChanged();
1384
1385    send(Messages::WebPageProxy::PageScaleFactorDidChange(scale));
1386}
1387
1388void WebPage::scalePageInViewCoordinates(double scale, IntPoint centerInViewCoordinates)
1389{
1390    if (scale == pageScaleFactor())
1391        return;
1392
1393    IntPoint scrollPositionAtNewScale = mainFrameView()->rootViewToContents(-centerInViewCoordinates);
1394    double scaleRatio = scale / pageScaleFactor();
1395    scrollPositionAtNewScale.scale(scaleRatio, scaleRatio);
1396    scalePage(scale, scrollPositionAtNewScale);
1397}
1398
1399double WebPage::pageScaleFactor() const
1400{
1401    PluginView* pluginView = pluginViewForFrame(&m_page->mainFrame());
1402    if (pluginView && pluginView->handlesPageScaleFactor())
1403        return pluginView->pageScaleFactor();
1404
1405    return m_page->pageScaleFactor();
1406}
1407
1408void WebPage::setDeviceScaleFactor(float scaleFactor)
1409{
1410    if (scaleFactor == m_page->deviceScaleFactor())
1411        return;
1412
1413    m_page->setDeviceScaleFactor(scaleFactor);
1414
1415    // Tell all our plug-in views that the device scale factor changed.
1416#if PLATFORM(MAC)
1417    for (auto* pluginView : m_pluginViews)
1418        pluginView->setDeviceScaleFactor(scaleFactor);
1419
1420    updateHeaderAndFooterLayersForDeviceScaleChange(scaleFactor);
1421#endif
1422
1423    if (m_findController.isShowingOverlay()) {
1424        // We must have updated layout to get the selection rects right.
1425        layoutIfNeeded();
1426        m_findController.deviceScaleFactorDidChange();
1427    }
1428
1429    if (m_drawingArea->layerTreeHost())
1430        m_drawingArea->layerTreeHost()->deviceOrPageScaleFactorChanged();
1431
1432    m_pageOverlayController.didChangeDeviceScaleFactor();
1433}
1434
1435float WebPage::deviceScaleFactor() const
1436{
1437    return m_page->deviceScaleFactor();
1438}
1439
1440void WebPage::setUseFixedLayout(bool fixed)
1441{
1442    // Do not overwrite current settings if initially setting it to false.
1443    if (m_useFixedLayout == fixed)
1444        return;
1445    m_useFixedLayout = fixed;
1446
1447#if !PLATFORM(IOS)
1448    m_page->settings().setFixedElementsLayoutRelativeToFrame(fixed);
1449#endif
1450#if USE(COORDINATED_GRAPHICS)
1451    m_page->settings().setAcceleratedCompositingForFixedPositionEnabled(fixed);
1452    m_page->settings().setFixedPositionCreatesStackingContext(fixed);
1453    m_page->settings().setDelegatesPageScaling(fixed);
1454    m_page->settings().setScrollingCoordinatorEnabled(fixed);
1455#endif
1456
1457#if USE(TILED_BACKING_STORE) && ENABLE(SMOOTH_SCROLLING)
1458    // Delegated scrolling will be enabled when the FrameView is created if fixed layout is enabled.
1459    // Ensure we don't do animated scrolling in the WebProcess in that case.
1460    m_page->settings().setScrollAnimatorEnabled(!fixed);
1461#endif
1462
1463    FrameView* view = mainFrameView();
1464    if (!view)
1465        return;
1466
1467#if USE(TILED_BACKING_STORE)
1468    view->setDelegatesScrolling(fixed);
1469    view->setPaintsEntireContents(fixed);
1470#endif
1471    view->setUseFixedLayout(fixed);
1472    if (!fixed)
1473        setFixedLayoutSize(IntSize());
1474}
1475
1476void WebPage::setFixedLayoutSize(const IntSize& size)
1477{
1478    FrameView* view = mainFrameView();
1479    if (!view || view->fixedLayoutSize() == size)
1480        return;
1481
1482    view->setFixedLayoutSize(size);
1483}
1484
1485void WebPage::listenForLayoutMilestones(uint32_t milestones)
1486{
1487    if (!m_page)
1488        return;
1489    m_page->addLayoutMilestones(static_cast<LayoutMilestones>(milestones));
1490}
1491
1492void WebPage::setSuppressScrollbarAnimations(bool suppressAnimations)
1493{
1494    m_page->setShouldSuppressScrollbarAnimations(suppressAnimations);
1495}
1496
1497void WebPage::setEnableVerticalRubberBanding(bool enableVerticalRubberBanding)
1498{
1499    m_page->setVerticalScrollElasticity(enableVerticalRubberBanding ? ScrollElasticityAllowed : ScrollElasticityNone);
1500}
1501
1502void WebPage::setEnableHorizontalRubberBanding(bool enableHorizontalRubberBanding)
1503{
1504    m_page->setHorizontalScrollElasticity(enableHorizontalRubberBanding ? ScrollElasticityAllowed : ScrollElasticityNone);
1505}
1506
1507void WebPage::setBackgroundExtendsBeyondPage(bool backgroundExtendsBeyondPage)
1508{
1509    if (m_page->settings().backgroundShouldExtendBeyondPage() != backgroundExtendsBeyondPage)
1510        m_page->settings().setBackgroundShouldExtendBeyondPage(backgroundExtendsBeyondPage);
1511}
1512
1513void WebPage::setPaginationMode(uint32_t mode)
1514{
1515    Pagination pagination = m_page->pagination();
1516    pagination.mode = static_cast<Pagination::Mode>(mode);
1517    m_page->setPagination(pagination);
1518}
1519
1520void WebPage::setPaginationBehavesLikeColumns(bool behavesLikeColumns)
1521{
1522    Pagination pagination = m_page->pagination();
1523    pagination.behavesLikeColumns = behavesLikeColumns;
1524    m_page->setPagination(pagination);
1525}
1526
1527void WebPage::setPageLength(double pageLength)
1528{
1529    Pagination pagination = m_page->pagination();
1530    pagination.pageLength = pageLength;
1531    m_page->setPagination(pagination);
1532}
1533
1534void WebPage::setGapBetweenPages(double gap)
1535{
1536    Pagination pagination = m_page->pagination();
1537    pagination.gap = gap;
1538    m_page->setPagination(pagination);
1539}
1540
1541void WebPage::postInjectedBundleMessage(const String& messageName, IPC::MessageDecoder& decoder)
1542{
1543    InjectedBundle* injectedBundle = WebProcess::shared().injectedBundle();
1544    if (!injectedBundle)
1545        return;
1546
1547    RefPtr<API::Object> messageBody;
1548    InjectedBundleUserMessageDecoder messageBodyDecoder(messageBody);
1549    if (!decoder.decode(messageBodyDecoder))
1550        return;
1551
1552    injectedBundle->didReceiveMessageToPage(this, messageName, messageBody.get());
1553}
1554
1555void WebPage::installPageOverlay(PassRefPtr<PageOverlay> pageOverlay, PageOverlay::FadeMode fadeMode)
1556{
1557    m_pageOverlayController.installPageOverlay(pageOverlay, fadeMode);
1558}
1559
1560void WebPage::uninstallPageOverlay(PageOverlay* pageOverlay, PageOverlay::FadeMode fadeMode)
1561{
1562    m_pageOverlayController.uninstallPageOverlay(pageOverlay, fadeMode);
1563}
1564
1565#if !PLATFORM(IOS)
1566void WebPage::setHeaderPageBanner(PassRefPtr<PageBanner> pageBanner)
1567{
1568    if (m_headerBanner)
1569        m_headerBanner->detachFromPage();
1570
1571    m_headerBanner = pageBanner;
1572
1573    if (m_headerBanner)
1574        m_headerBanner->addToPage(PageBanner::Header, this);
1575}
1576
1577PageBanner* WebPage::headerPageBanner()
1578{
1579    return m_headerBanner.get();
1580}
1581
1582void WebPage::setFooterPageBanner(PassRefPtr<PageBanner> pageBanner)
1583{
1584    if (m_footerBanner)
1585        m_footerBanner->detachFromPage();
1586
1587    m_footerBanner = pageBanner;
1588
1589    if (m_footerBanner)
1590        m_footerBanner->addToPage(PageBanner::Footer, this);
1591}
1592
1593PageBanner* WebPage::footerPageBanner()
1594{
1595    return m_footerBanner.get();
1596}
1597
1598void WebPage::hidePageBanners()
1599{
1600    if (m_headerBanner)
1601        m_headerBanner->hide();
1602    if (m_footerBanner)
1603        m_footerBanner->hide();
1604}
1605
1606void WebPage::showPageBanners()
1607{
1608    if (m_headerBanner)
1609        m_headerBanner->showIfHidden();
1610    if (m_footerBanner)
1611        m_footerBanner->showIfHidden();
1612}
1613#endif // !PLATFORM(IOS)
1614
1615void WebPage::takeSnapshot(IntRect snapshotRect, IntSize bitmapSize, uint32_t options, uint64_t callbackID)
1616{
1617    SnapshotOptions snapshotOptions = static_cast<SnapshotOptions>(options);
1618    snapshotOptions |= SnapshotOptionsShareable;
1619
1620    RefPtr<WebImage> image = snapshotAtSize(snapshotRect, bitmapSize, snapshotOptions);
1621
1622    ShareableBitmap::Handle handle;
1623    if (image)
1624        image->bitmap()->createHandle(handle, SharedMemory::ReadOnly);
1625
1626    send(Messages::WebPageProxy::ImageCallback(handle, callbackID));
1627}
1628
1629PassRefPtr<WebImage> WebPage::scaledSnapshotWithOptions(const IntRect& rect, double additionalScaleFactor, SnapshotOptions options)
1630{
1631    IntRect snapshotRect = rect;
1632    IntSize bitmapSize = snapshotRect.size();
1633    double scaleFactor = additionalScaleFactor;
1634    if (!(options & SnapshotOptionsExcludeDeviceScaleFactor))
1635        scaleFactor *= corePage()->deviceScaleFactor();
1636    bitmapSize.scale(scaleFactor);
1637
1638    return snapshotAtSize(rect, bitmapSize, options);
1639}
1640
1641PassRefPtr<WebImage> WebPage::snapshotAtSize(const IntRect& rect, const IntSize& bitmapSize, SnapshotOptions options)
1642{
1643    Frame* coreFrame = m_mainFrame->coreFrame();
1644    if (!coreFrame)
1645        return nullptr;
1646
1647    FrameView* frameView = coreFrame->view();
1648    if (!frameView)
1649        return nullptr;
1650
1651    IntRect snapshotRect = rect;
1652    float horizontalScaleFactor = static_cast<float>(bitmapSize.width()) / rect.width();
1653    float verticalScaleFactor = static_cast<float>(bitmapSize.height()) / rect.height();
1654    float scaleFactor = std::max(horizontalScaleFactor, verticalScaleFactor);
1655
1656    RefPtr<WebImage> snapshot = WebImage::create(bitmapSize, snapshotOptionsToImageOptions(options));
1657    if (!snapshot->bitmap())
1658        return nullptr;
1659
1660    auto graphicsContext = snapshot->bitmap()->createGraphicsContext();
1661
1662    graphicsContext->fillRect(IntRect(IntPoint(), bitmapSize), frameView->baseBackgroundColor(), ColorSpaceDeviceRGB);
1663
1664    if (!(options & SnapshotOptionsExcludeDeviceScaleFactor)) {
1665        double deviceScaleFactor = corePage()->deviceScaleFactor();
1666        graphicsContext->applyDeviceScaleFactor(deviceScaleFactor);
1667        scaleFactor /= deviceScaleFactor;
1668    }
1669
1670    graphicsContext->scale(FloatSize(scaleFactor, scaleFactor));
1671    graphicsContext->translate(-snapshotRect.x(), -snapshotRect.y());
1672
1673    FrameView::SelectionInSnapshot shouldPaintSelection = FrameView::IncludeSelection;
1674    if (options & SnapshotOptionsExcludeSelectionHighlighting)
1675        shouldPaintSelection = FrameView::ExcludeSelection;
1676
1677    FrameView::CoordinateSpaceForSnapshot coordinateSpace = FrameView::DocumentCoordinates;
1678    if (options & SnapshotOptionsInViewCoordinates)
1679        coordinateSpace = FrameView::ViewCoordinates;
1680
1681    frameView->paintContentsForSnapshot(graphicsContext.get(), snapshotRect, shouldPaintSelection, coordinateSpace);
1682
1683    if (options & SnapshotOptionsPaintSelectionRectangle) {
1684        FloatRect selectionRectangle = m_mainFrame->coreFrame()->selection().selectionBounds();
1685        graphicsContext->setStrokeColor(Color(0xFF, 0, 0), ColorSpaceDeviceRGB);
1686        graphicsContext->strokeRect(selectionRectangle, 1);
1687    }
1688
1689    return snapshot.release();
1690}
1691
1692PassRefPtr<WebImage> WebPage::snapshotNode(WebCore::Node& node, SnapshotOptions options, unsigned maximumPixelCount)
1693{
1694    Frame* coreFrame = m_mainFrame->coreFrame();
1695    if (!coreFrame)
1696        return nullptr;
1697
1698    FrameView* frameView = coreFrame->view();
1699    if (!frameView)
1700        return nullptr;
1701
1702    if (!node.renderer())
1703        return nullptr;
1704
1705    LayoutRect topLevelRect;
1706    IntRect snapshotRect = pixelSnappedIntRect(node.renderer()->paintingRootRect(topLevelRect));
1707
1708    double scaleFactor = 1;
1709    IntSize snapshotSize = snapshotRect.size();
1710    unsigned maximumHeight = maximumPixelCount / snapshotSize.width();
1711    if (maximumHeight < static_cast<unsigned>(snapshotSize.height())) {
1712        scaleFactor = static_cast<double>(maximumHeight) / snapshotSize.height();
1713        snapshotSize = IntSize(snapshotSize.width() * scaleFactor, maximumHeight);
1714    }
1715
1716    RefPtr<WebImage> snapshot = WebImage::create(snapshotSize, snapshotOptionsToImageOptions(options));
1717    if (!snapshot->bitmap())
1718        return nullptr;
1719
1720    auto graphicsContext = snapshot->bitmap()->createGraphicsContext();
1721
1722    if (!(options & SnapshotOptionsExcludeDeviceScaleFactor)) {
1723        double deviceScaleFactor = corePage()->deviceScaleFactor();
1724        graphicsContext->applyDeviceScaleFactor(deviceScaleFactor);
1725        scaleFactor /= deviceScaleFactor;
1726    }
1727
1728    graphicsContext->scale(FloatSize(scaleFactor, scaleFactor));
1729    graphicsContext->translate(-snapshotRect.x(), -snapshotRect.y());
1730
1731    Color savedBackgroundColor = frameView->baseBackgroundColor();
1732    frameView->setBaseBackgroundColor(Color::transparent);
1733    frameView->setNodeToDraw(&node);
1734
1735    frameView->paintContentsForSnapshot(graphicsContext.get(), snapshotRect, FrameView::ExcludeSelection, FrameView::DocumentCoordinates);
1736
1737    frameView->setBaseBackgroundColor(savedBackgroundColor);
1738    frameView->setNodeToDraw(nullptr);
1739
1740    return snapshot.release();
1741}
1742
1743void WebPage::pageDidScroll()
1744{
1745#if PLATFORM(IOS)
1746    if (!m_inDynamicSizeUpdate)
1747        m_dynamicSizeUpdateHistory.clear();
1748#endif
1749    m_uiClient->pageDidScroll(this);
1750
1751    send(Messages::WebPageProxy::PageDidScroll());
1752}
1753
1754#if USE(TILED_BACKING_STORE)
1755void WebPage::pageDidRequestScroll(const IntPoint& point)
1756{
1757    send(Messages::WebPageProxy::PageDidRequestScroll(point));
1758}
1759#endif
1760
1761#if ENABLE(CONTEXT_MENUS)
1762WebContextMenu* WebPage::contextMenu()
1763{
1764    if (!m_contextMenu)
1765        m_contextMenu = WebContextMenu::create(this);
1766    return m_contextMenu.get();
1767}
1768
1769WebContextMenu* WebPage::contextMenuAtPointInWindow(const IntPoint& point)
1770{
1771    corePage()->contextMenuController().clearContextMenu();
1772
1773    // Simulate a mouse click to generate the correct menu.
1774    PlatformMouseEvent mouseEvent(point, point, RightButton, PlatformEvent::MousePressed, 1, false, false, false, false, currentTime());
1775    bool handled = corePage()->userInputBridge().handleContextMenuEvent(mouseEvent, &corePage()->mainFrame());
1776    if (!handled)
1777        return 0;
1778
1779    return contextMenu();
1780}
1781#endif
1782
1783// Events
1784
1785static const WebEvent* g_currentEvent = 0;
1786
1787// FIXME: WebPage::currentEvent is used by the plug-in code to avoid having to convert from DOM events back to
1788// WebEvents. When we get the event handling sorted out, this should go away and the Widgets should get the correct
1789// platform events passed to the event handler code.
1790const WebEvent* WebPage::currentEvent()
1791{
1792    return g_currentEvent;
1793}
1794
1795class CurrentEvent {
1796public:
1797    explicit CurrentEvent(const WebEvent& event)
1798        : m_previousCurrentEvent(g_currentEvent)
1799    {
1800        g_currentEvent = &event;
1801    }
1802
1803    ~CurrentEvent()
1804    {
1805        g_currentEvent = m_previousCurrentEvent;
1806    }
1807
1808private:
1809    const WebEvent* m_previousCurrentEvent;
1810};
1811
1812#if ENABLE(CONTEXT_MENUS)
1813static bool isContextClick(const PlatformMouseEvent& event)
1814{
1815    if (event.button() == WebCore::RightButton)
1816        return true;
1817
1818#if PLATFORM(COCOA)
1819    // FIXME: this really should be about OSX-style UI, not about the Mac port
1820    if (event.button() == WebCore::LeftButton && event.ctrlKey())
1821        return true;
1822#endif
1823
1824    return false;
1825}
1826
1827static bool handleContextMenuEvent(const PlatformMouseEvent& platformMouseEvent, WebPage* page)
1828{
1829    IntPoint point = page->corePage()->mainFrame().view()->windowToContents(platformMouseEvent.position());
1830    HitTestResult result = page->corePage()->mainFrame().eventHandler().hitTestResultAtPoint(point);
1831
1832    Frame* frame = &page->corePage()->mainFrame();
1833    if (result.innerNonSharedNode())
1834        frame = result.innerNonSharedNode()->document().frame();
1835
1836    bool handled = page->corePage()->userInputBridge().handleContextMenuEvent(platformMouseEvent, frame);
1837    if (handled)
1838        page->contextMenu()->show();
1839
1840    return handled;
1841}
1842#endif
1843
1844static bool handleMouseEvent(const WebMouseEvent& mouseEvent, WebPage* page, bool onlyUpdateScrollbars)
1845{
1846    Frame& frame = page->corePage()->mainFrame();
1847    if (!frame.view())
1848        return false;
1849
1850    PlatformMouseEvent platformMouseEvent = platform(mouseEvent);
1851
1852    switch (platformMouseEvent.type()) {
1853        case PlatformEvent::MousePressed: {
1854#if ENABLE(CONTEXT_MENUS)
1855            if (isContextClick(platformMouseEvent))
1856                page->corePage()->contextMenuController().clearContextMenu();
1857#endif
1858
1859            bool handled = page->corePage()->userInputBridge().handleMousePressEvent(platformMouseEvent);
1860#if ENABLE(CONTEXT_MENUS)
1861            if (isContextClick(platformMouseEvent))
1862                handled = handleContextMenuEvent(platformMouseEvent, page);
1863#endif
1864            return handled;
1865        }
1866        case PlatformEvent::MouseReleased:
1867            return page->corePage()->userInputBridge().handleMouseReleaseEvent(platformMouseEvent);
1868
1869        case PlatformEvent::MouseMoved:
1870            if (onlyUpdateScrollbars)
1871                return page->corePage()->userInputBridge().handleMouseMoveOnScrollbarEvent(platformMouseEvent);
1872            return page->corePage()->userInputBridge().handleMouseMoveEvent(platformMouseEvent);
1873        default:
1874            ASSERT_NOT_REACHED();
1875            return false;
1876    }
1877}
1878
1879void WebPage::mouseEvent(const WebMouseEvent& mouseEvent)
1880{
1881    ASSERT(m_page->pageThrottler());
1882    m_page->pageThrottler()->didReceiveUserInput();
1883
1884#if ENABLE(CONTEXT_MENUS)
1885    // Don't try to handle any pending mouse events if a context menu is showing.
1886    if (m_isShowingContextMenu) {
1887        send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(mouseEvent.type()), false));
1888        return;
1889    }
1890#endif
1891    bool handled = m_pageOverlayController.handleMouseEvent(mouseEvent);
1892
1893#if !PLATFORM(IOS)
1894    if (!handled && m_headerBanner)
1895        handled = m_headerBanner->mouseEvent(mouseEvent);
1896    if (!handled && m_footerBanner)
1897        handled = m_footerBanner->mouseEvent(mouseEvent);
1898#endif // !PLATFORM(IOS)
1899
1900    if (!handled && canHandleUserEvents()) {
1901        CurrentEvent currentEvent(mouseEvent);
1902
1903        // We need to do a full, normal hit test during this mouse event if the page is active or if a mouse
1904        // button is currently pressed. It is possible that neither of those things will be true since on
1905        // Lion when legacy scrollbars are enabled, WebKit receives mouse events all the time. If it is one
1906        // of those cases where the page is not active and the mouse is not pressed, then we can fire a more
1907        // efficient scrollbars-only version of the event.
1908        bool onlyUpdateScrollbars = !(m_page->focusController().isActive() || (mouseEvent.button() != WebMouseEvent::NoButton));
1909        handled = handleMouseEvent(mouseEvent, this, onlyUpdateScrollbars);
1910    }
1911
1912    send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(mouseEvent.type()), handled));
1913}
1914
1915void WebPage::mouseEventSyncForTesting(const WebMouseEvent& mouseEvent, bool& handled)
1916{
1917    handled = m_pageOverlayController.handleMouseEvent(mouseEvent);
1918#if !PLATFORM(IOS)
1919    if (!handled && m_headerBanner)
1920        handled = m_headerBanner->mouseEvent(mouseEvent);
1921    if (!handled && m_footerBanner)
1922        handled = m_footerBanner->mouseEvent(mouseEvent);
1923#endif // !PLATFORM(IOS)
1924
1925    if (!handled) {
1926        CurrentEvent currentEvent(mouseEvent);
1927
1928        // We need to do a full, normal hit test during this mouse event if the page is active or if a mouse
1929        // button is currently pressed. It is possible that neither of those things will be true since on
1930        // Lion when legacy scrollbars are enabled, WebKit receives mouse events all the time. If it is one
1931        // of those cases where the page is not active and the mouse is not pressed, then we can fire a more
1932        // efficient scrollbars-only version of the event.
1933        bool onlyUpdateScrollbars = !(m_page->focusController().isActive() || (mouseEvent.button() != WebMouseEvent::NoButton));
1934        handled = handleMouseEvent(mouseEvent, this, onlyUpdateScrollbars);
1935    }
1936}
1937
1938static bool handleWheelEvent(const WebWheelEvent& wheelEvent, Page* page)
1939{
1940    Frame& frame = page->mainFrame();
1941    if (!frame.view())
1942        return false;
1943
1944    PlatformWheelEvent platformWheelEvent = platform(wheelEvent);
1945    return page->userInputBridge().handleWheelEvent(platformWheelEvent);
1946}
1947
1948void WebPage::wheelEvent(const WebWheelEvent& wheelEvent)
1949{
1950    ASSERT(m_page->pageThrottler());
1951    m_page->pageThrottler()->didReceiveUserInput();
1952
1953    bool handled = false;
1954
1955    if (canHandleUserEvents()) {
1956        CurrentEvent currentEvent(wheelEvent);
1957
1958        handled = handleWheelEvent(wheelEvent, m_page.get());
1959    }
1960    send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(wheelEvent.type()), handled));
1961}
1962
1963void WebPage::wheelEventSyncForTesting(const WebWheelEvent& wheelEvent, bool& handled)
1964{
1965    CurrentEvent currentEvent(wheelEvent);
1966
1967    if (ScrollingCoordinator* scrollingCoordinator = m_page->scrollingCoordinator())
1968        scrollingCoordinator->commitTreeStateIfNeeded();
1969
1970    handled = handleWheelEvent(wheelEvent, m_page.get());
1971}
1972
1973static bool handleKeyEvent(const WebKeyboardEvent& keyboardEvent, Page* page)
1974{
1975    if (!page->mainFrame().view())
1976        return false;
1977
1978    if (keyboardEvent.type() == WebEvent::Char && keyboardEvent.isSystemKey())
1979        return page->userInputBridge().handleAccessKeyEvent(platform(keyboardEvent));
1980    return page->userInputBridge().handleKeyEvent(platform(keyboardEvent));
1981}
1982
1983void WebPage::keyEvent(const WebKeyboardEvent& keyboardEvent)
1984{
1985    ASSERT(m_page->pageThrottler());
1986    m_page->pageThrottler()->didReceiveUserInput();
1987
1988    bool handled = false;
1989
1990    if (canHandleUserEvents()) {
1991        CurrentEvent currentEvent(keyboardEvent);
1992
1993        handled = handleKeyEvent(keyboardEvent, m_page.get());
1994        // FIXME: Platform default behaviors should be performed during normal DOM event dispatch (in most cases, in default keydown event handler).
1995        if (!handled)
1996            handled = performDefaultBehaviorForKeyEvent(keyboardEvent);
1997    }
1998    send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(keyboardEvent.type()), handled));
1999}
2000
2001void WebPage::keyEventSyncForTesting(const WebKeyboardEvent& keyboardEvent, bool& handled)
2002{
2003    CurrentEvent currentEvent(keyboardEvent);
2004
2005    Frame& frame = m_page->focusController().focusedOrMainFrame();
2006    frame.document()->updateStyleIfNeeded();
2007
2008    handled = handleKeyEvent(keyboardEvent, m_page.get());
2009    if (!handled)
2010        handled = performDefaultBehaviorForKeyEvent(keyboardEvent);
2011}
2012
2013void WebPage::validateCommand(const String& commandName, uint64_t callbackID)
2014{
2015    bool isEnabled = false;
2016    int32_t state = 0;
2017    Frame& frame = m_page->focusController().focusedOrMainFrame();
2018    if (PluginView* pluginView = focusedPluginViewForFrame(frame))
2019        isEnabled = pluginView->isEditingCommandEnabled(commandName);
2020    else {
2021        Editor::Command command = frame.editor().command(commandName);
2022        state = command.state();
2023        isEnabled = command.isSupported() && command.isEnabled();
2024    }
2025
2026    send(Messages::WebPageProxy::ValidateCommandCallback(commandName, isEnabled, state, callbackID));
2027}
2028
2029void WebPage::executeEditCommand(const String& commandName)
2030{
2031    executeEditingCommand(commandName, String());
2032}
2033
2034void WebPage::restoreSession(const Vector<BackForwardListItemState>& itemStates)
2035{
2036    for (const auto& itemState : itemStates)
2037        WebBackForwardListProxy::addItemFromUIProcess(itemState.identifier, toHistoryItem(itemState.pageState), m_pageID);
2038}
2039
2040#if ENABLE(TOUCH_EVENTS)
2041static bool handleTouchEvent(const WebTouchEvent& touchEvent, Page* page)
2042{
2043    if (!page->mainFrame().view())
2044        return false;
2045
2046    return page->mainFrame().eventHandler().handleTouchEvent(platform(touchEvent));
2047}
2048#endif
2049
2050#if ENABLE(IOS_TOUCH_EVENTS)
2051void WebPage::dispatchTouchEvent(const WebTouchEvent& touchEvent, bool& handled)
2052{
2053    RefPtr<Frame> oldFocusedFrame = m_page->focusController().focusedFrame();
2054    RefPtr<Element> oldFocusedElement = oldFocusedFrame ? oldFocusedFrame->document()->focusedElement() : nullptr;
2055    m_userIsInteracting = true;
2056
2057    m_lastInteractionLocation = touchEvent.position();
2058    CurrentEvent currentEvent(touchEvent);
2059    handled = handleTouchEvent(touchEvent, m_page.get());
2060
2061    RefPtr<Frame> newFocusedFrame = m_page->focusController().focusedFrame();
2062    RefPtr<Element> newFocusedElement = newFocusedFrame ? newFocusedFrame->document()->focusedElement() : nullptr;
2063
2064    // If the focus has not changed, we need to notify the client anyway, since it might be
2065    // necessary to start assisting the node.
2066    // If the node has been focused by JavaScript without user interaction, the
2067    // keyboard is not on screen.
2068    if (newFocusedElement && newFocusedElement == oldFocusedElement)
2069        elementDidFocus(newFocusedElement.get());
2070
2071    m_userIsInteracting = false;
2072}
2073
2074void WebPage::touchEventSync(const WebTouchEvent& touchEvent, bool& handled)
2075{
2076    EventDispatcher::TouchEventQueue queuedEvents;
2077    WebProcess::shared().eventDispatcher().getQueuedTouchEventsForPage(*this, queuedEvents);
2078    dispatchAsynchronousTouchEvents(queuedEvents);
2079
2080    dispatchTouchEvent(touchEvent, handled);
2081}
2082#elif ENABLE(TOUCH_EVENTS)
2083void WebPage::touchEvent(const WebTouchEvent& touchEvent)
2084{
2085
2086    bool handled = false;
2087    if (canHandleUserEvents()) {
2088        CurrentEvent currentEvent(touchEvent);
2089
2090        handled = handleTouchEvent(touchEvent, m_page.get());
2091    }
2092    send(Messages::WebPageProxy::DidReceiveEvent(static_cast<uint32_t>(touchEvent.type()), handled));
2093}
2094
2095void WebPage::touchEventSyncForTesting(const WebTouchEvent& touchEvent, bool& handled)
2096{
2097    CurrentEvent currentEvent(touchEvent);
2098    handled = handleTouchEvent(touchEvent, m_page.get());
2099}
2100#endif
2101
2102bool WebPage::scroll(Page* page, ScrollDirection direction, ScrollGranularity granularity)
2103{
2104    return page->userInputBridge().scrollRecursively(direction, granularity);
2105}
2106
2107bool WebPage::logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity)
2108{
2109    return page->userInputBridge().logicalScrollRecursively(direction, granularity);
2110}
2111
2112bool WebPage::scrollBy(uint32_t scrollDirection, uint32_t scrollGranularity)
2113{
2114    return scroll(m_page.get(), static_cast<ScrollDirection>(scrollDirection), static_cast<ScrollGranularity>(scrollGranularity));
2115}
2116
2117void WebPage::centerSelectionInVisibleArea()
2118{
2119    Frame& frame = m_page->focusController().focusedOrMainFrame();
2120    frame.selection().revealSelection(ScrollAlignment::alignCenterAlways);
2121    m_findController.showFindIndicatorInSelection();
2122}
2123
2124#if ENABLE(REMOTE_INSPECTOR)
2125void WebPage::setAllowsRemoteInspection(bool allow)
2126{
2127    m_page->setRemoteInspectionAllowed(allow);
2128}
2129#endif
2130
2131void WebPage::setDrawsBackground(bool drawsBackground)
2132{
2133    if (m_drawsBackground == drawsBackground)
2134        return;
2135
2136    m_drawsBackground = drawsBackground;
2137
2138    for (Frame* coreFrame = m_mainFrame->coreFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext()) {
2139        if (FrameView* view = coreFrame->view())
2140            view->setTransparent(!drawsBackground);
2141    }
2142
2143    m_drawingArea->pageBackgroundTransparencyChanged();
2144    m_drawingArea->setNeedsDisplay();
2145}
2146
2147void WebPage::setDrawsTransparentBackground(bool drawsTransparentBackground)
2148{
2149    if (m_drawsTransparentBackground == drawsTransparentBackground)
2150        return;
2151
2152    m_drawsTransparentBackground = drawsTransparentBackground;
2153
2154    Color backgroundColor = drawsTransparentBackground ? Color::transparent : Color::white;
2155    for (Frame* coreFrame = m_mainFrame->coreFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext()) {
2156        if (FrameView* view = coreFrame->view())
2157            view->setBaseBackgroundColor(backgroundColor);
2158    }
2159
2160    m_drawingArea->pageBackgroundTransparencyChanged();
2161    m_drawingArea->setNeedsDisplay();
2162}
2163
2164void WebPage::setTopContentInset(float contentInset)
2165{
2166    if (contentInset == m_page->topContentInset())
2167        return;
2168
2169    m_page->setTopContentInset(contentInset);
2170
2171    for (auto* pluginView : m_pluginViews)
2172        pluginView->topContentInsetDidChange();
2173}
2174
2175void WebPage::viewWillStartLiveResize()
2176{
2177    if (!m_page)
2178        return;
2179
2180    // FIXME: This should propagate to all ScrollableAreas.
2181    Frame& frame = m_page->focusController().focusedOrMainFrame();
2182    if (FrameView* view = frame.view())
2183        view->willStartLiveResize();
2184}
2185
2186void WebPage::viewWillEndLiveResize()
2187{
2188    if (!m_page)
2189        return;
2190
2191    // FIXME: This should propagate to all ScrollableAreas.
2192    Frame& frame = m_page->focusController().focusedOrMainFrame();
2193    if (FrameView* view = frame.view())
2194        view->willEndLiveResize();
2195}
2196
2197void WebPage::setInitialFocus(bool forward, bool isKeyboardEventValid, const WebKeyboardEvent& event)
2198{
2199    if (!m_page)
2200        return;
2201
2202    Frame& frame = m_page->focusController().focusedOrMainFrame();
2203    frame.document()->setFocusedElement(0);
2204
2205    if (isKeyboardEventValid && event.type() == WebEvent::KeyDown) {
2206        PlatformKeyboardEvent platformEvent(platform(event));
2207        platformEvent.disambiguateKeyDownEvent(PlatformEvent::RawKeyDown);
2208        m_page->focusController().setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, KeyboardEvent::create(platformEvent, frame.document()->defaultView()).get());
2209        return;
2210    }
2211
2212    m_page->focusController().setInitialFocus(forward ? FocusDirectionForward : FocusDirectionBackward, 0);
2213}
2214
2215void WebPage::setWindowResizerSize(const IntSize& windowResizerSize)
2216{
2217    if (m_windowResizerSize == windowResizerSize)
2218        return;
2219
2220    m_windowResizerSize = windowResizerSize;
2221
2222    for (Frame* coreFrame = m_mainFrame->coreFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext()) {
2223        FrameView* view = coreFrame->view();
2224        if (view)
2225            view->windowResizerRectChanged();
2226    }
2227}
2228
2229void WebPage::setCanStartMediaTimerFired()
2230{
2231    if (m_page)
2232        m_page->setCanStartMedia(true);
2233}
2234
2235inline bool WebPage::canHandleUserEvents() const
2236{
2237#if USE(TILED_BACKING_STORE)
2238    // Should apply only if the area was frozen by didStartPageTransition().
2239    return !m_drawingArea->layerTreeStateIsFrozen();
2240#endif
2241    return true;
2242}
2243
2244void WebPage::updateIsInWindow(bool isInitialState)
2245{
2246    bool isInWindow = m_viewState & WebCore::ViewState::IsInWindow;
2247
2248    if (!isInWindow) {
2249        m_setCanStartMediaTimer.stop();
2250        m_page->setCanStartMedia(false);
2251
2252        // The WebProcess does not yet know about this page; no need to tell it we're leaving the window.
2253        if (!isInitialState)
2254            WebProcess::shared().pageWillLeaveWindow(m_pageID);
2255    } else {
2256        // Defer the call to Page::setCanStartMedia() since it ends up sending a synchronous message to the UI process
2257        // in order to get plug-in connections, and the UI process will be waiting for the Web process to update the backing
2258        // store after moving the view into a window, until it times out and paints white. See <rdar://problem/9242771>.
2259        if (m_mayStartMediaWhenInWindow)
2260            m_setCanStartMediaTimer.startOneShot(0);
2261
2262        WebProcess::shared().pageDidEnterWindow(m_pageID);
2263    }
2264
2265    if (isInWindow)
2266        layoutIfNeeded();
2267}
2268
2269void WebPage::setViewState(ViewState::Flags viewState, bool wantsDidUpdateViewState)
2270{
2271    ViewState::Flags changed = m_viewState ^ viewState;
2272    m_viewState = viewState;
2273
2274    m_page->setViewState(viewState);
2275    for (auto* pluginView : m_pluginViews)
2276        pluginView->viewStateDidChange(changed);
2277
2278    m_drawingArea->viewStateDidChange(changed, wantsDidUpdateViewState);
2279
2280    if (changed & ViewState::IsInWindow)
2281        updateIsInWindow();
2282}
2283
2284void WebPage::setLayerHostingMode(unsigned layerHostingMode)
2285{
2286    m_layerHostingMode = static_cast<LayerHostingMode>(layerHostingMode);
2287
2288    m_drawingArea->setLayerHostingMode(m_layerHostingMode);
2289
2290    for (auto* pluginView : m_pluginViews)
2291        pluginView->setLayerHostingMode(m_layerHostingMode);
2292}
2293
2294void WebPage::setSessionID(SessionID sessionID)
2295{
2296    if (sessionID.isEphemeral())
2297        WebProcess::shared().ensurePrivateBrowsingSession(sessionID);
2298    m_page->setSessionID(sessionID);
2299}
2300
2301void WebPage::didReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, uint32_t policyAction, uint64_t navigationID, uint64_t downloadID)
2302{
2303    WebFrame* frame = WebProcess::shared().webFrame(frameID);
2304    if (!frame)
2305        return;
2306    frame->didReceivePolicyDecision(listenerID, static_cast<PolicyAction>(policyAction), navigationID, downloadID);
2307}
2308
2309void WebPage::didStartPageTransition()
2310{
2311    m_drawingArea->setLayerTreeStateIsFrozen(true);
2312}
2313
2314void WebPage::didCompletePageTransition()
2315{
2316#if USE(TILED_BACKING_STORE)
2317    // m_mainFrame can be null since r170163.
2318    if (m_mainFrame && m_mainFrame->coreFrame()->view()->delegatesScrolling()) {
2319        // Wait until the UI process sent us the visible rect it wants rendered.
2320        send(Messages::WebPageProxy::PageTransitionViewportReady());
2321    } else
2322#endif
2323
2324    m_drawingArea->setLayerTreeStateIsFrozen(false);
2325}
2326
2327void WebPage::show()
2328{
2329    send(Messages::WebPageProxy::ShowPage());
2330}
2331
2332String WebPage::userAgent(const URL& webCoreURL) const
2333{
2334    return userAgent(nullptr, webCoreURL);
2335}
2336
2337String WebPage::userAgent(WebFrame* frame, const URL& webcoreURL) const
2338{
2339    if (frame && m_loaderClient.client().userAgentForURL) {
2340        RefPtr<API::URL> url = API::URL::create(webcoreURL);
2341
2342        API::String* apiString = m_loaderClient.userAgentForURL(frame, url.get());
2343        if (apiString)
2344            return apiString->string();
2345    }
2346
2347    String userAgent = platformUserAgent(webcoreURL);
2348    if (!userAgent.isEmpty())
2349        return userAgent;
2350    return m_userAgent;
2351}
2352
2353void WebPage::setUserAgent(const String& userAgent)
2354{
2355    m_userAgent = userAgent;
2356}
2357
2358void WebPage::suspendActiveDOMObjectsAndAnimations()
2359{
2360    m_page->suspendActiveDOMObjectsAndAnimations();
2361}
2362
2363void WebPage::resumeActiveDOMObjectsAndAnimations()
2364{
2365    m_page->resumeActiveDOMObjectsAndAnimations();
2366}
2367
2368IntPoint WebPage::screenToRootView(const IntPoint& point)
2369{
2370    IntPoint windowPoint;
2371    sendSync(Messages::WebPageProxy::ScreenToRootView(point), Messages::WebPageProxy::ScreenToRootView::Reply(windowPoint));
2372    return windowPoint;
2373}
2374
2375IntRect WebPage::rootViewToScreen(const IntRect& rect)
2376{
2377    IntRect screenRect;
2378    sendSync(Messages::WebPageProxy::RootViewToScreen(rect), Messages::WebPageProxy::RootViewToScreen::Reply(screenRect));
2379    return screenRect;
2380}
2381
2382#if PLATFORM(IOS)
2383IntPoint WebPage::accessibilityScreenToRootView(const IntPoint& point)
2384{
2385    IntPoint windowPoint;
2386    sendSync(Messages::WebPageProxy::AccessibilityScreenToRootView(point), Messages::WebPageProxy::AccessibilityScreenToRootView::Reply(windowPoint));
2387    return windowPoint;
2388}
2389
2390IntRect WebPage::rootViewToAccessibilityScreen(const IntRect& rect)
2391{
2392    IntRect screenRect;
2393    sendSync(Messages::WebPageProxy::RootViewToAccessibilityScreen(rect), Messages::WebPageProxy::RootViewToAccessibilityScreen::Reply(screenRect));
2394    return screenRect;
2395}
2396#endif
2397
2398IntRect WebPage::windowResizerRect() const
2399{
2400    if (m_windowResizerSize.isEmpty())
2401        return IntRect();
2402
2403    IntSize frameViewSize;
2404    if (Frame* coreFrame = m_mainFrame->coreFrame()) {
2405        if (FrameView* view = coreFrame->view())
2406            frameViewSize = view->size();
2407    }
2408
2409    return IntRect(frameViewSize.width() - m_windowResizerSize.width(), frameViewSize.height() - m_windowResizerSize.height(),
2410                   m_windowResizerSize.width(), m_windowResizerSize.height());
2411}
2412
2413KeyboardUIMode WebPage::keyboardUIMode()
2414{
2415    bool fullKeyboardAccessEnabled = WebProcess::shared().fullKeyboardAccessEnabled();
2416    return static_cast<KeyboardUIMode>((fullKeyboardAccessEnabled ? KeyboardAccessFull : KeyboardAccessDefault) | (m_tabToLinks ? KeyboardAccessTabsToLinks : 0));
2417}
2418
2419void WebPage::runJavaScriptInMainFrame(const String& script, uint64_t callbackID)
2420{
2421    // NOTE: We need to be careful when running scripts that the objects we depend on don't
2422    // disappear during script execution.
2423
2424    // Retain the SerializedScriptValue at this level so it (and the internal data) lives
2425    // long enough for the DataReference to be encoded by the sent message.
2426    RefPtr<SerializedScriptValue> serializedResultValue;
2427    IPC::DataReference dataReference;
2428
2429    JSLockHolder lock(JSDOMWindow::commonVM());
2430    if (JSValue resultValue = m_mainFrame->coreFrame()->script().executeScript(script, true).jsValue()) {
2431        if ((serializedResultValue = SerializedScriptValue::create(m_mainFrame->jsContext(), toRef(m_mainFrame->coreFrame()->script().globalObject(mainThreadNormalWorld())->globalExec(), resultValue), 0)))
2432            dataReference = serializedResultValue->data();
2433    }
2434
2435    send(Messages::WebPageProxy::ScriptValueCallback(dataReference, callbackID));
2436}
2437
2438void WebPage::getContentsAsString(uint64_t callbackID)
2439{
2440    String resultString = m_mainFrame->contentsAsString();
2441    send(Messages::WebPageProxy::StringCallback(resultString, callbackID));
2442}
2443
2444#if ENABLE(MHTML)
2445void WebPage::getContentsAsMHTMLData(uint64_t callbackID, bool useBinaryEncoding)
2446{
2447    IPC::DataReference dataReference;
2448
2449    RefPtr<SharedBuffer> buffer = useBinaryEncoding
2450        ? MHTMLArchive::generateMHTMLDataUsingBinaryEncoding(m_page.get())
2451        : MHTMLArchive::generateMHTMLData(m_page.get());
2452
2453    if (buffer)
2454        dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size());
2455
2456    send(Messages::WebPageProxy::DataCallback(dataReference, callbackID));
2457}
2458#endif
2459
2460void WebPage::getRenderTreeExternalRepresentation(uint64_t callbackID)
2461{
2462    String resultString = renderTreeExternalRepresentation();
2463    send(Messages::WebPageProxy::StringCallback(resultString, callbackID));
2464}
2465
2466static Frame* frameWithSelection(Page* page)
2467{
2468    for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
2469        if (frame->selection().isRange())
2470            return frame;
2471    }
2472
2473    return 0;
2474}
2475
2476void WebPage::getSelectionAsWebArchiveData(uint64_t callbackID)
2477{
2478    IPC::DataReference dataReference;
2479
2480#if PLATFORM(COCOA)
2481    RefPtr<LegacyWebArchive> archive;
2482    RetainPtr<CFDataRef> data;
2483
2484    Frame* frame = frameWithSelection(m_page.get());
2485    if (frame) {
2486        archive = LegacyWebArchive::createFromSelection(frame);
2487        data = archive->rawDataRepresentation();
2488        dataReference = IPC::DataReference(CFDataGetBytePtr(data.get()), CFDataGetLength(data.get()));
2489    }
2490#endif
2491
2492    send(Messages::WebPageProxy::DataCallback(dataReference, callbackID));
2493}
2494
2495void WebPage::getSelectionOrContentsAsString(uint64_t callbackID)
2496{
2497    String resultString = m_mainFrame->selectionAsString();
2498    if (resultString.isEmpty())
2499        resultString = m_mainFrame->contentsAsString();
2500    send(Messages::WebPageProxy::StringCallback(resultString, callbackID));
2501}
2502
2503void WebPage::getSourceForFrame(uint64_t frameID, uint64_t callbackID)
2504{
2505    String resultString;
2506    if (WebFrame* frame = WebProcess::shared().webFrame(frameID))
2507       resultString = frame->source();
2508
2509    send(Messages::WebPageProxy::StringCallback(resultString, callbackID));
2510}
2511
2512void WebPage::getMainResourceDataOfFrame(uint64_t frameID, uint64_t callbackID)
2513{
2514    IPC::DataReference dataReference;
2515
2516    RefPtr<ResourceBuffer> buffer;
2517    RefPtr<SharedBuffer> pdfResource;
2518    if (WebFrame* frame = WebProcess::shared().webFrame(frameID)) {
2519        if (PluginView* pluginView = pluginViewForFrame(frame->coreFrame())) {
2520            if ((pdfResource = pluginView->liveResourceData()))
2521                dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(pdfResource->data()), pdfResource->size());
2522        }
2523
2524        if (dataReference.isEmpty()) {
2525            if (DocumentLoader* loader = frame->coreFrame()->loader().documentLoader()) {
2526                if ((buffer = loader->mainResourceData()))
2527                    dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size());
2528            }
2529        }
2530    }
2531
2532    send(Messages::WebPageProxy::DataCallback(dataReference, callbackID));
2533}
2534
2535static PassRefPtr<SharedBuffer> resourceDataForFrame(Frame* frame, const URL& resourceURL)
2536{
2537    DocumentLoader* loader = frame->loader().documentLoader();
2538    if (!loader)
2539        return 0;
2540
2541    RefPtr<ArchiveResource> subresource = loader->subresource(resourceURL);
2542    if (!subresource)
2543        return 0;
2544
2545    return subresource->data();
2546}
2547
2548void WebPage::getResourceDataFromFrame(uint64_t frameID, const String& resourceURLString, uint64_t callbackID)
2549{
2550    IPC::DataReference dataReference;
2551    URL resourceURL(URL(), resourceURLString);
2552
2553    RefPtr<SharedBuffer> buffer;
2554    if (WebFrame* frame = WebProcess::shared().webFrame(frameID)) {
2555        buffer = resourceDataForFrame(frame->coreFrame(), resourceURL);
2556        if (!buffer) {
2557            // Try to get the resource data from the cache.
2558            buffer = cachedResponseDataForURL(resourceURL);
2559        }
2560
2561        if (buffer)
2562            dataReference = IPC::DataReference(reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size());
2563    }
2564
2565    send(Messages::WebPageProxy::DataCallback(dataReference, callbackID));
2566}
2567
2568void WebPage::getWebArchiveOfFrame(uint64_t frameID, uint64_t callbackID)
2569{
2570    IPC::DataReference dataReference;
2571
2572#if PLATFORM(COCOA)
2573    RetainPtr<CFDataRef> data;
2574    if (WebFrame* frame = WebProcess::shared().webFrame(frameID)) {
2575        if ((data = frame->webArchiveData(0, 0)))
2576            dataReference = IPC::DataReference(CFDataGetBytePtr(data.get()), CFDataGetLength(data.get()));
2577    }
2578#else
2579    UNUSED_PARAM(frameID);
2580#endif
2581
2582    send(Messages::WebPageProxy::DataCallback(dataReference, callbackID));
2583}
2584
2585void WebPage::forceRepaintWithoutCallback()
2586{
2587    m_drawingArea->forceRepaint();
2588}
2589
2590void WebPage::forceRepaint(uint64_t callbackID)
2591{
2592    if (m_drawingArea->forceRepaintAsync(callbackID))
2593        return;
2594
2595    forceRepaintWithoutCallback();
2596    send(Messages::WebPageProxy::VoidCallback(callbackID));
2597}
2598
2599void WebPage::preferencesDidChange(const WebPreferencesStore& store)
2600{
2601    WebPreferencesStore::removeTestRunnerOverrides();
2602    updatePreferences(store);
2603}
2604
2605void WebPage::updatePreferences(const WebPreferencesStore& store)
2606{
2607    Settings& settings = m_page->settings();
2608
2609    m_tabToLinks = store.getBoolValueForKey(WebPreferencesKey::tabsToLinksKey());
2610    m_asynchronousPluginInitializationEnabled = store.getBoolValueForKey(WebPreferencesKey::asynchronousPluginInitializationEnabledKey());
2611    m_asynchronousPluginInitializationEnabledForAllPlugins = store.getBoolValueForKey(WebPreferencesKey::asynchronousPluginInitializationEnabledForAllPluginsKey());
2612    m_artificialPluginInitializationDelayEnabled = store.getBoolValueForKey(WebPreferencesKey::artificialPluginInitializationDelayEnabledKey());
2613
2614    m_scrollingPerformanceLoggingEnabled = store.getBoolValueForKey(WebPreferencesKey::scrollingPerformanceLoggingEnabledKey());
2615
2616#if PLATFORM(COCOA)
2617    m_pdfPluginEnabled = store.getBoolValueForKey(WebPreferencesKey::pdfPluginEnabledKey());
2618#endif
2619
2620#if ENABLE(SERVICE_CONTROLS)
2621    m_serviceControlsEnabled = store.getBoolValueForKey(WebPreferencesKey::serviceControlsEnabledKey());
2622#endif
2623
2624    // FIXME: This should be generated from macro expansion for all preferences,
2625    // but we currently don't match the naming of WebCore exactly so we are
2626    // handrolling the boolean and integer preferences until that is fixed.
2627
2628#define INITIALIZE_SETTINGS(KeyUpper, KeyLower, TypeName, Type, DefaultValue) settings.set##KeyUpper(store.get##TypeName##ValueForKey(WebPreferencesKey::KeyLower##Key()));
2629
2630    FOR_EACH_WEBKIT_STRING_PREFERENCE(INITIALIZE_SETTINGS)
2631
2632#undef INITIALIZE_SETTINGS
2633
2634    settings.setScriptEnabled(store.getBoolValueForKey(WebPreferencesKey::javaScriptEnabledKey()));
2635    settings.setScriptMarkupEnabled(store.getBoolValueForKey(WebPreferencesKey::javaScriptMarkupEnabledKey()));
2636    settings.setLoadsImagesAutomatically(store.getBoolValueForKey(WebPreferencesKey::loadsImagesAutomaticallyKey()));
2637    settings.setLoadsSiteIconsIgnoringImageLoadingSetting(store.getBoolValueForKey(WebPreferencesKey::loadsSiteIconsIgnoringImageLoadingPreferenceKey()));
2638    settings.setPluginsEnabled(store.getBoolValueForKey(WebPreferencesKey::pluginsEnabledKey()));
2639    settings.setJavaEnabled(store.getBoolValueForKey(WebPreferencesKey::javaEnabledKey()));
2640    settings.setJavaEnabledForLocalFiles(store.getBoolValueForKey(WebPreferencesKey::javaEnabledForLocalFilesKey()));
2641    settings.setOfflineWebApplicationCacheEnabled(store.getBoolValueForKey(WebPreferencesKey::offlineWebApplicationCacheEnabledKey()));
2642    settings.setLocalStorageEnabled(store.getBoolValueForKey(WebPreferencesKey::localStorageEnabledKey()));
2643    settings.setXSSAuditorEnabled(store.getBoolValueForKey(WebPreferencesKey::xssAuditorEnabledKey()));
2644    settings.setFrameFlatteningEnabled(store.getBoolValueForKey(WebPreferencesKey::frameFlatteningEnabledKey()));
2645    if (store.getBoolValueForKey(WebPreferencesKey::privateBrowsingEnabledKey()) && !usesEphemeralSession())
2646        setSessionID(SessionID::legacyPrivateSessionID());
2647    else if (!store.getBoolValueForKey(WebPreferencesKey::privateBrowsingEnabledKey()) && sessionID() == SessionID::legacyPrivateSessionID())
2648        setSessionID(SessionID::defaultSessionID());
2649    settings.setDeveloperExtrasEnabled(store.getBoolValueForKey(WebPreferencesKey::developerExtrasEnabledKey()));
2650    settings.setJavaScriptExperimentsEnabled(store.getBoolValueForKey(WebPreferencesKey::javaScriptExperimentsEnabledKey()));
2651    settings.setTextAreasAreResizable(store.getBoolValueForKey(WebPreferencesKey::textAreasAreResizableKey()));
2652    settings.setNeedsSiteSpecificQuirks(store.getBoolValueForKey(WebPreferencesKey::needsSiteSpecificQuirksKey()));
2653    settings.setJavaScriptCanOpenWindowsAutomatically(store.getBoolValueForKey(WebPreferencesKey::javaScriptCanOpenWindowsAutomaticallyKey()));
2654    settings.setForceFTPDirectoryListings(store.getBoolValueForKey(WebPreferencesKey::forceFTPDirectoryListingsKey()));
2655    settings.setDNSPrefetchingEnabled(store.getBoolValueForKey(WebPreferencesKey::dnsPrefetchingEnabledKey()));
2656#if ENABLE(WEB_ARCHIVE)
2657    settings.setWebArchiveDebugModeEnabled(store.getBoolValueForKey(WebPreferencesKey::webArchiveDebugModeEnabledKey()));
2658#endif
2659    settings.setLocalFileContentSniffingEnabled(store.getBoolValueForKey(WebPreferencesKey::localFileContentSniffingEnabledKey()));
2660    settings.setUsesPageCache(store.getBoolValueForKey(WebPreferencesKey::usesPageCacheKey()));
2661    settings.setPageCacheSupportsPlugins(store.getBoolValueForKey(WebPreferencesKey::pageCacheSupportsPluginsKey()));
2662    settings.setAuthorAndUserStylesEnabled(store.getBoolValueForKey(WebPreferencesKey::authorAndUserStylesEnabledKey()));
2663    settings.setPaginateDuringLayoutEnabled(store.getBoolValueForKey(WebPreferencesKey::paginateDuringLayoutEnabledKey()));
2664    settings.setDOMPasteAllowed(store.getBoolValueForKey(WebPreferencesKey::domPasteAllowedKey()));
2665    settings.setJavaScriptCanAccessClipboard(store.getBoolValueForKey(WebPreferencesKey::javaScriptCanAccessClipboardKey()));
2666    settings.setShouldPrintBackgrounds(store.getBoolValueForKey(WebPreferencesKey::shouldPrintBackgroundsKey()));
2667    settings.setWebSecurityEnabled(store.getBoolValueForKey(WebPreferencesKey::webSecurityEnabledKey()));
2668    settings.setAllowUniversalAccessFromFileURLs(store.getBoolValueForKey(WebPreferencesKey::allowUniversalAccessFromFileURLsKey()));
2669    settings.setAllowFileAccessFromFileURLs(store.getBoolValueForKey(WebPreferencesKey::allowFileAccessFromFileURLsKey()));
2670
2671    settings.setMinimumFontSize(store.getDoubleValueForKey(WebPreferencesKey::minimumFontSizeKey()));
2672    settings.setMinimumLogicalFontSize(store.getDoubleValueForKey(WebPreferencesKey::minimumLogicalFontSizeKey()));
2673    settings.setDefaultFontSize(store.getDoubleValueForKey(WebPreferencesKey::defaultFontSizeKey()));
2674    settings.setDefaultFixedFontSize(store.getDoubleValueForKey(WebPreferencesKey::defaultFixedFontSizeKey()));
2675    settings.setScreenFontSubstitutionEnabled(store.getBoolValueForKey(WebPreferencesKey::screenFontSubstitutionEnabledKey())
2676#if PLATFORM(COCOA)
2677        || WebProcess::shared().shouldForceScreenFontSubstitution()
2678#endif
2679    );
2680    settings.setLayoutFallbackWidth(store.getUInt32ValueForKey(WebPreferencesKey::layoutFallbackWidthKey()));
2681    settings.setDeviceWidth(store.getUInt32ValueForKey(WebPreferencesKey::deviceWidthKey()));
2682    settings.setDeviceHeight(store.getUInt32ValueForKey(WebPreferencesKey::deviceHeightKey()));
2683    settings.setEditableLinkBehavior(static_cast<WebCore::EditableLinkBehavior>(store.getUInt32ValueForKey(WebPreferencesKey::editableLinkBehaviorKey())));
2684    settings.setShowsToolTipOverTruncatedText(store.getBoolValueForKey(WebPreferencesKey::showsToolTipOverTruncatedTextKey()));
2685
2686    settings.setAcceleratedCompositingForOverflowScrollEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedCompositingForOverflowScrollEnabledKey()));
2687    settings.setAcceleratedCompositingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedCompositingEnabledKey()));
2688    settings.setAcceleratedDrawingEnabled(store.getBoolValueForKey(WebPreferencesKey::acceleratedDrawingEnabledKey()));
2689    settings.setCanvasUsesAcceleratedDrawing(store.getBoolValueForKey(WebPreferencesKey::canvasUsesAcceleratedDrawingKey()));
2690    settings.setShowDebugBorders(store.getBoolValueForKey(WebPreferencesKey::compositingBordersVisibleKey()));
2691    settings.setShowRepaintCounter(store.getBoolValueForKey(WebPreferencesKey::compositingRepaintCountersVisibleKey()));
2692    settings.setShowTiledScrollingIndicator(store.getBoolValueForKey(WebPreferencesKey::tiledScrollingIndicatorVisibleKey()));
2693    settings.setAggressiveTileRetentionEnabled(store.getBoolValueForKey(WebPreferencesKey::aggressiveTileRetentionEnabledKey()));
2694    settings.setTemporaryTileCohortRetentionEnabled(store.getBoolValueForKey(WebPreferencesKey::temporaryTileCohortRetentionEnabledKey()));
2695    RuntimeEnabledFeatures::sharedFeatures().setCSSRegionsEnabled(store.getBoolValueForKey(WebPreferencesKey::cssRegionsEnabledKey()));
2696    RuntimeEnabledFeatures::sharedFeatures().setCSSCompositingEnabled(store.getBoolValueForKey(WebPreferencesKey::cssCompositingEnabledKey()));
2697    settings.setWebGLEnabled(store.getBoolValueForKey(WebPreferencesKey::webGLEnabledKey()));
2698    settings.setMultithreadedWebGLEnabled(store.getBoolValueForKey(WebPreferencesKey::multithreadedWebGLEnabledKey()));
2699    settings.setForceSoftwareWebGLRendering(store.getBoolValueForKey(WebPreferencesKey::forceSoftwareWebGLRenderingKey()));
2700    settings.setAccelerated2dCanvasEnabled(store.getBoolValueForKey(WebPreferencesKey::accelerated2dCanvasEnabledKey()));
2701    settings.setMediaPlaybackRequiresUserGesture(store.getBoolValueForKey(WebPreferencesKey::mediaPlaybackRequiresUserGestureKey()));
2702    settings.setMediaPlaybackAllowsInline(store.getBoolValueForKey(WebPreferencesKey::mediaPlaybackAllowsInlineKey()));
2703    settings.setMockScrollbarsEnabled(store.getBoolValueForKey(WebPreferencesKey::mockScrollbarsEnabledKey()));
2704    settings.setHyperlinkAuditingEnabled(store.getBoolValueForKey(WebPreferencesKey::hyperlinkAuditingEnabledKey()));
2705    settings.setRequestAnimationFrameEnabled(store.getBoolValueForKey(WebPreferencesKey::requestAnimationFrameEnabledKey()));
2706#if ENABLE(SMOOTH_SCROLLING)
2707    settings.setScrollAnimatorEnabled(store.getBoolValueForKey(WebPreferencesKey::scrollAnimatorEnabledKey()));
2708#endif
2709    settings.setForceUpdateScrollbarsOnMainThreadForPerformanceTesting(store.getBoolValueForKey(WebPreferencesKey::forceUpdateScrollbarsOnMainThreadForPerformanceTestingKey()));
2710    settings.setInteractiveFormValidationEnabled(store.getBoolValueForKey(WebPreferencesKey::interactiveFormValidationEnabledKey()));
2711    settings.setSpatialNavigationEnabled(store.getBoolValueForKey(WebPreferencesKey::spatialNavigationEnabledKey()));
2712
2713#if ENABLE(SQL_DATABASE)
2714    DatabaseManager::manager().setIsAvailable(store.getBoolValueForKey(WebPreferencesKey::databasesEnabledKey()));
2715#endif
2716
2717#if ENABLE(FULLSCREEN_API)
2718    settings.setFullScreenEnabled(store.getBoolValueForKey(WebPreferencesKey::fullScreenEnabledKey()));
2719#endif
2720
2721#if USE(AVFOUNDATION)
2722    settings.setAVFoundationEnabled(store.getBoolValueForKey(WebPreferencesKey::isAVFoundationEnabledKey()));
2723#endif
2724
2725#if PLATFORM(COCOA)
2726    settings.setQTKitEnabled(store.getBoolValueForKey(WebPreferencesKey::isQTKitEnabledKey()));
2727#endif
2728
2729#if PLATFORM(IOS)
2730    settings.setAVKitEnabled(true);
2731#endif
2732
2733#if ENABLE(IOS_TEXT_AUTOSIZING)
2734    settings.setMinimumZoomFontSize(store.getDoubleValueForKey(WebPreferencesKey::minimumZoomFontSizeKey()));
2735#endif
2736
2737#if ENABLE(WEB_AUDIO)
2738    settings.setWebAudioEnabled(store.getBoolValueForKey(WebPreferencesKey::webAudioEnabledKey()));
2739#endif
2740
2741#if ENABLE(MEDIA_STREAM)
2742    settings.setMediaStreamEnabled(store.getBoolValueForKey(WebPreferencesKey::mediaStreamEnabledKey()));
2743#endif
2744
2745#if ENABLE(SERVICE_CONTROLS)
2746    settings.setImageControlsEnabled(store.getBoolValueForKey(WebPreferencesKey::imageControlsEnabledKey()));
2747#endif
2748
2749#if ENABLE(IOS_AIRPLAY)
2750    settings.setMediaPlaybackAllowsAirPlay(store.getBoolValueForKey(WebPreferencesKey::mediaPlaybackAllowsAirPlayKey()));
2751#endif
2752
2753    settings.setApplicationChromeMode(store.getBoolValueForKey(WebPreferencesKey::applicationChromeModeKey()));
2754    settings.setSuppressesIncrementalRendering(store.getBoolValueForKey(WebPreferencesKey::suppressesIncrementalRenderingKey()));
2755    settings.setIncrementalRenderingSuppressionTimeoutInSeconds(store.getDoubleValueForKey(WebPreferencesKey::incrementalRenderingSuppressionTimeoutKey()));
2756    settings.setBackspaceKeyNavigationEnabled(store.getBoolValueForKey(WebPreferencesKey::backspaceKeyNavigationEnabledKey()));
2757    settings.setWantsBalancedSetDefersLoadingBehavior(store.getBoolValueForKey(WebPreferencesKey::wantsBalancedSetDefersLoadingBehaviorKey()));
2758    settings.setCaretBrowsingEnabled(store.getBoolValueForKey(WebPreferencesKey::caretBrowsingEnabledKey()));
2759
2760#if ENABLE(VIDEO_TRACK)
2761    settings.setShouldDisplaySubtitles(store.getBoolValueForKey(WebPreferencesKey::shouldDisplaySubtitlesKey()));
2762    settings.setShouldDisplayCaptions(store.getBoolValueForKey(WebPreferencesKey::shouldDisplayCaptionsKey()));
2763    settings.setShouldDisplayTextDescriptions(store.getBoolValueForKey(WebPreferencesKey::shouldDisplayTextDescriptionsKey()));
2764#endif
2765
2766#if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
2767    settings.setNotificationsEnabled(store.getBoolValueForKey(WebPreferencesKey::notificationsEnabledKey()));
2768#endif
2769
2770    settings.setShouldRespectImageOrientation(store.getBoolValueForKey(WebPreferencesKey::shouldRespectImageOrientationKey()));
2771    settings.setStorageBlockingPolicy(static_cast<SecurityOrigin::StorageBlockingPolicy>(store.getUInt32ValueForKey(WebPreferencesKey::storageBlockingPolicyKey())));
2772    settings.setCookieEnabled(store.getBoolValueForKey(WebPreferencesKey::cookieEnabledKey()));
2773
2774    settings.setDiagnosticLoggingEnabled(store.getBoolValueForKey(WebPreferencesKey::diagnosticLoggingEnabledKey()));
2775
2776    settings.setScrollingPerformanceLoggingEnabled(m_scrollingPerformanceLoggingEnabled);
2777
2778    settings.setPlugInSnapshottingEnabled(store.getBoolValueForKey(WebPreferencesKey::plugInSnapshottingEnabledKey()));
2779    settings.setSnapshotAllPlugIns(store.getBoolValueForKey(WebPreferencesKey::snapshotAllPlugInsKey()));
2780    settings.setAutostartOriginPlugInSnapshottingEnabled(store.getBoolValueForKey(WebPreferencesKey::autostartOriginPlugInSnapshottingEnabledKey()));
2781    settings.setPrimaryPlugInSnapshotDetectionEnabled(store.getBoolValueForKey(WebPreferencesKey::primaryPlugInSnapshotDetectionEnabledKey()));
2782    settings.setUsesEncodingDetector(store.getBoolValueForKey(WebPreferencesKey::usesEncodingDetectorKey()));
2783
2784#if ENABLE(TEXT_AUTOSIZING)
2785    settings.setTextAutosizingEnabled(store.getBoolValueForKey(WebPreferencesKey::textAutosizingEnabledKey()));
2786#endif
2787
2788    settings.setLogsPageMessagesToSystemConsoleEnabled(store.getBoolValueForKey(WebPreferencesKey::logsPageMessagesToSystemConsoleEnabledKey()));
2789    settings.setAsynchronousSpellCheckingEnabled(store.getBoolValueForKey(WebPreferencesKey::asynchronousSpellCheckingEnabledKey()));
2790
2791    settings.setSmartInsertDeleteEnabled(store.getBoolValueForKey(WebPreferencesKey::smartInsertDeleteEnabledKey()));
2792    settings.setSelectTrailingWhitespaceEnabled(store.getBoolValueForKey(WebPreferencesKey::selectTrailingWhitespaceEnabledKey()));
2793    settings.setShowsURLsInToolTips(store.getBoolValueForKey(WebPreferencesKey::showsURLsInToolTipsEnabledKey()));
2794
2795#if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING)
2796    settings.setHiddenPageDOMTimerThrottlingEnabled(store.getBoolValueForKey(WebPreferencesKey::hiddenPageDOMTimerThrottlingEnabledKey()));
2797#endif
2798
2799    settings.setHiddenPageCSSAnimationSuspensionEnabled(store.getBoolValueForKey(WebPreferencesKey::hiddenPageCSSAnimationSuspensionEnabledKey()));
2800    settings.setLowPowerVideoAudioBufferSizeEnabled(store.getBoolValueForKey(WebPreferencesKey::lowPowerVideoAudioBufferSizeEnabledKey()));
2801    settings.setSimpleLineLayoutEnabled(store.getBoolValueForKey(WebPreferencesKey::simpleLineLayoutEnabledKey()));
2802    settings.setSimpleLineLayoutDebugBordersEnabled(store.getBoolValueForKey(WebPreferencesKey::simpleLineLayoutDebugBordersEnabledKey()));
2803
2804    settings.setSubpixelCSSOMElementMetricsEnabled(store.getBoolValueForKey(WebPreferencesKey::subpixelCSSOMElementMetricsEnabledKey()));
2805
2806    settings.setUseLegacyTextAlignPositionedElementBehavior(store.getBoolValueForKey(WebPreferencesKey::useLegacyTextAlignPositionedElementBehaviorKey()));
2807
2808#if ENABLE(MEDIA_SOURCE)
2809    settings.setMediaSourceEnabled(store.getBoolValueForKey(WebPreferencesKey::mediaSourceEnabledKey()));
2810#endif
2811
2812    settings.setShouldConvertPositionStyleOnCopy(store.getBoolValueForKey(WebPreferencesKey::shouldConvertPositionStyleOnCopyKey()));
2813
2814    settings.setStandalone(store.getBoolValueForKey(WebPreferencesKey::standaloneKey()));
2815    settings.setTelephoneNumberParsingEnabled(store.getBoolValueForKey(WebPreferencesKey::telephoneNumberParsingEnabledKey()));
2816    settings.setAlwaysUseBaselineOfPrimaryFont(store.getBoolValueForKey(WebPreferencesKey::alwaysUseBaselineOfPrimaryFontKey()));
2817    settings.setAllowMultiElementImplicitSubmission(store.getBoolValueForKey(WebPreferencesKey::allowMultiElementImplicitSubmissionKey()));
2818    settings.setAlwaysUseAcceleratedOverflowScroll(store.getBoolValueForKey(WebPreferencesKey::alwaysUseAcceleratedOverflowScrollKey()));
2819
2820    settings.setPasswordEchoEnabled(store.getBoolValueForKey(WebPreferencesKey::passwordEchoEnabledKey()));
2821    settings.setPasswordEchoDurationInSeconds(store.getDoubleValueForKey(WebPreferencesKey::passwordEchoDurationKey()));
2822
2823    settings.setLayoutInterval(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::duration<double>(store.getDoubleValueForKey(WebPreferencesKey::layoutIntervalKey()))));
2824    settings.setMaxParseDuration(store.getDoubleValueForKey(WebPreferencesKey::maxParseDurationKey()));
2825
2826    settings.setEnableInheritURIQueryComponent(store.getBoolValueForKey(WebPreferencesKey::enableInheritURIQueryComponentKey()));
2827
2828    settings.setShouldDispatchJavaScriptWindowOnErrorEvents(true);
2829
2830#if PLATFORM(IOS)
2831    settings.setUseImageDocumentForSubframePDF(true);
2832#endif
2833
2834#if ENABLE(GAMEPAD)
2835    RuntimeEnabledFeatures::sharedFeatures().setGamepadsEnabled(store.getBoolValueForKey(WebPreferencesKey::gamepadsEnabledKey()));
2836#endif
2837
2838    if (store.getBoolValueForKey(WebPreferencesKey::pageVisibilityBasedProcessSuppressionEnabledKey()))
2839        m_processSuppressionDisabledByWebPreference.stop();
2840    else
2841        m_processSuppressionDisabledByWebPreference.start();
2842
2843    platformPreferencesDidChange(store);
2844
2845    if (m_drawingArea)
2846        m_drawingArea->updatePreferences(store);
2847
2848    m_pageOverlayController.didChangePreferences();
2849}
2850
2851#if PLATFORM(COCOA)
2852void WebPage::willCommitLayerTree(RemoteLayerTreeTransaction& layerTransaction)
2853{
2854    layerTransaction.setContentsSize(corePage()->mainFrame().view()->contentsSize());
2855    layerTransaction.setPageScaleFactor(corePage()->pageScaleFactor());
2856    layerTransaction.setRenderTreeSize(corePage()->renderTreeSize());
2857    layerTransaction.setPageExtendedBackgroundColor(corePage()->pageExtendedBackgroundColor());
2858#if PLATFORM(IOS)
2859    layerTransaction.setScaleWasSetByUIProcess(scaleWasSetByUIProcess());
2860    layerTransaction.setMinimumScaleFactor(m_viewportConfiguration.minimumScale());
2861    layerTransaction.setMaximumScaleFactor(m_viewportConfiguration.maximumScale());
2862    layerTransaction.setAllowsUserScaling(allowsUserScaling());
2863#endif
2864}
2865
2866void WebPage::didFlushLayerTreeAtTime(std::chrono::milliseconds timestamp)
2867{
2868#if PLATFORM(IOS)
2869    if (m_oldestNonStableUpdateVisibleContentRectsTimestamp != std::chrono::milliseconds::zero()) {
2870        std::chrono::milliseconds elapsed = timestamp - m_oldestNonStableUpdateVisibleContentRectsTimestamp;
2871        m_oldestNonStableUpdateVisibleContentRectsTimestamp = std::chrono::milliseconds::zero();
2872
2873        m_estimatedLatency = std::chrono::milliseconds(static_cast<std::chrono::milliseconds::rep>(m_estimatedLatency.count() * 0.80 + elapsed.count() * 0.20));
2874    }
2875#else
2876    UNUSED_PARAM(timestamp);
2877#endif
2878}
2879#endif
2880
2881
2882#if ENABLE(INSPECTOR)
2883WebInspector* WebPage::inspector()
2884{
2885    if (m_isClosed)
2886        return 0;
2887    if (!m_inspector)
2888        m_inspector = WebInspector::create(this, m_inspectorClient);
2889    return m_inspector.get();
2890}
2891#endif
2892
2893#if PLATFORM(IOS)
2894WebVideoFullscreenManager* WebPage::videoFullscreenManager()
2895{
2896    if (!m_videoFullscreenManager)
2897        m_videoFullscreenManager = WebVideoFullscreenManager::create(this);
2898    return m_videoFullscreenManager.get();
2899}
2900#endif
2901
2902#if ENABLE(FULLSCREEN_API)
2903WebFullScreenManager* WebPage::fullScreenManager()
2904{
2905    if (!m_fullScreenManager)
2906        m_fullScreenManager = WebFullScreenManager::create(this);
2907    return m_fullScreenManager.get();
2908}
2909#endif
2910
2911NotificationPermissionRequestManager* WebPage::notificationPermissionRequestManager()
2912{
2913    if (m_notificationPermissionRequestManager)
2914        return m_notificationPermissionRequestManager.get();
2915
2916    m_notificationPermissionRequestManager = NotificationPermissionRequestManager::create(this);
2917    return m_notificationPermissionRequestManager.get();
2918}
2919
2920#if !PLATFORM(GTK) && !PLATFORM(COCOA)
2921bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* evt)
2922{
2923    Node* node = evt->target()->toNode();
2924    ASSERT(node);
2925    Frame* frame = node->document().frame();
2926    ASSERT(frame);
2927
2928    const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
2929    if (!keyEvent)
2930        return false;
2931
2932    Editor::Command command = frame->editor().command(interpretKeyEvent(evt));
2933
2934    if (keyEvent->type() == PlatformEvent::RawKeyDown) {
2935        // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
2936        // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
2937        // (e.g. Tab that inserts a Tab character, or Enter).
2938        return !command.isTextInsertion() && command.execute(evt);
2939    }
2940
2941    if (command.execute(evt))
2942        return true;
2943
2944    // Don't allow text insertion for nodes that cannot edit.
2945    if (!frame->editor().canEdit())
2946        return false;
2947
2948    // Don't insert null or control characters as they can result in unexpected behaviour
2949    if (evt->charCode() < ' ')
2950        return false;
2951
2952    return frame->editor().insertText(evt->keyEvent()->text(), evt);
2953}
2954#endif
2955
2956#if ENABLE(DRAG_SUPPORT)
2957
2958#if PLATFORM(GTK)
2959void WebPage::performDragControllerAction(uint64_t action, WebCore::DragData dragData)
2960{
2961    if (!m_page) {
2962        send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, false, 0));
2963        DataObjectGtk* data = const_cast<DataObjectGtk*>(dragData.platformData());
2964        data->deref();
2965        return;
2966    }
2967
2968    switch (action) {
2969    case DragControllerActionEntered: {
2970        DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
2971        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted()));
2972        break;
2973    }
2974    case DragControllerActionUpdated: {
2975        DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
2976        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted()));
2977        break;
2978    }
2979    case DragControllerActionExited:
2980        m_page->dragController().dragExited(dragData);
2981        break;
2982
2983    case DragControllerActionPerformDragOperation: {
2984        m_page->dragController().performDragOperation(dragData);
2985        break;
2986    }
2987
2988    default:
2989        ASSERT_NOT_REACHED();
2990    }
2991    // DragData does not delete its platformData so we need to do that here.
2992    DataObjectGtk* data = const_cast<DataObjectGtk*>(dragData.platformData());
2993    data->deref();
2994}
2995
2996#else
2997void WebPage::performDragControllerAction(uint64_t action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t draggingSourceOperationMask, const String& dragStorageName, uint32_t flags, const SandboxExtension::Handle& sandboxExtensionHandle, const SandboxExtension::HandleArray& sandboxExtensionsHandleArray)
2998{
2999    if (!m_page) {
3000        send(Messages::WebPageProxy::DidPerformDragControllerAction(DragOperationNone, false, 0));
3001        return;
3002    }
3003
3004    DragData dragData(dragStorageName, clientPosition, globalPosition, static_cast<DragOperation>(draggingSourceOperationMask), static_cast<DragApplicationFlags>(flags));
3005    switch (action) {
3006    case DragControllerActionEntered: {
3007        DragOperation resolvedDragOperation = m_page->dragController().dragEntered(dragData);
3008        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted()));
3009        break;
3010
3011    }
3012    case DragControllerActionUpdated: {
3013        DragOperation resolvedDragOperation = m_page->dragController().dragUpdated(dragData);
3014        send(Messages::WebPageProxy::DidPerformDragControllerAction(resolvedDragOperation, m_page->dragController().mouseIsOverFileInput(), m_page->dragController().numberOfItemsToBeAccepted()));
3015        break;
3016    }
3017    case DragControllerActionExited:
3018        m_page->dragController().dragExited(dragData);
3019        break;
3020
3021    case DragControllerActionPerformDragOperation: {
3022        ASSERT(!m_pendingDropSandboxExtension);
3023
3024        m_pendingDropSandboxExtension = SandboxExtension::create(sandboxExtensionHandle);
3025        for (size_t i = 0; i < sandboxExtensionsHandleArray.size(); i++) {
3026            if (RefPtr<SandboxExtension> extension = SandboxExtension::create(sandboxExtensionsHandleArray[i]))
3027                m_pendingDropExtensionsForFileUpload.append(extension);
3028        }
3029
3030        m_page->dragController().performDragOperation(dragData);
3031
3032        // If we started loading a local file, the sandbox extension tracker would have adopted this
3033        // pending drop sandbox extension. If not, we'll play it safe and clear it.
3034        m_pendingDropSandboxExtension = nullptr;
3035
3036        m_pendingDropExtensionsForFileUpload.clear();
3037        break;
3038    }
3039
3040    default:
3041        ASSERT_NOT_REACHED();
3042    }
3043}
3044#endif
3045
3046void WebPage::dragEnded(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, uint64_t operation)
3047{
3048    IntPoint adjustedClientPosition(clientPosition.x() + m_page->dragController().dragOffset().x(), clientPosition.y() + m_page->dragController().dragOffset().y());
3049    IntPoint adjustedGlobalPosition(globalPosition.x() + m_page->dragController().dragOffset().x(), globalPosition.y() + m_page->dragController().dragOffset().y());
3050
3051    m_page->dragController().dragEnded();
3052    FrameView* view = m_page->mainFrame().view();
3053    if (!view)
3054        return;
3055    // FIXME: These are fake modifier keys here, but they should be real ones instead.
3056    PlatformMouseEvent event(adjustedClientPosition, adjustedGlobalPosition, LeftButton, PlatformEvent::MouseMoved, 0, false, false, false, false, currentTime());
3057    m_page->mainFrame().eventHandler().dragSourceEndedAt(event, (DragOperation)operation);
3058}
3059
3060void WebPage::willPerformLoadDragDestinationAction()
3061{
3062    m_sandboxExtensionTracker.willPerformLoadDragDestinationAction(m_pendingDropSandboxExtension.release());
3063}
3064
3065void WebPage::mayPerformUploadDragDestinationAction()
3066{
3067    for (size_t i = 0; i < m_pendingDropExtensionsForFileUpload.size(); i++)
3068        m_pendingDropExtensionsForFileUpload[i]->consumePermanently();
3069    m_pendingDropExtensionsForFileUpload.clear();
3070}
3071
3072#endif // ENABLE(DRAG_SUPPORT)
3073
3074WebUndoStep* WebPage::webUndoStep(uint64_t stepID)
3075{
3076    return m_undoStepMap.get(stepID);
3077}
3078
3079void WebPage::addWebUndoStep(uint64_t stepID, WebUndoStep* entry)
3080{
3081    m_undoStepMap.set(stepID, entry);
3082}
3083
3084void WebPage::removeWebEditCommand(uint64_t stepID)
3085{
3086    m_undoStepMap.remove(stepID);
3087}
3088
3089void WebPage::unapplyEditCommand(uint64_t stepID)
3090{
3091    WebUndoStep* step = webUndoStep(stepID);
3092    if (!step)
3093        return;
3094
3095    step->step()->unapply();
3096}
3097
3098void WebPage::reapplyEditCommand(uint64_t stepID)
3099{
3100    WebUndoStep* step = webUndoStep(stepID);
3101    if (!step)
3102        return;
3103
3104    m_isInRedo = true;
3105    step->step()->reapply();
3106    m_isInRedo = false;
3107}
3108
3109void WebPage::didRemoveEditCommand(uint64_t commandID)
3110{
3111    removeWebEditCommand(commandID);
3112}
3113
3114void WebPage::setActivePopupMenu(WebPopupMenu* menu)
3115{
3116    m_activePopupMenu = menu;
3117}
3118
3119#if ENABLE(INPUT_TYPE_COLOR)
3120void WebPage::setActiveColorChooser(WebColorChooser* colorChooser)
3121{
3122    m_activeColorChooser = colorChooser;
3123}
3124
3125void WebPage::didEndColorPicker()
3126{
3127    m_activeColorChooser->didEndChooser();
3128}
3129
3130void WebPage::didChooseColor(const WebCore::Color& color)
3131{
3132    m_activeColorChooser->didChooseColor(color);
3133}
3134#endif
3135
3136void WebPage::setActiveOpenPanelResultListener(PassRefPtr<WebOpenPanelResultListener> openPanelResultListener)
3137{
3138    m_activeOpenPanelResultListener = openPanelResultListener;
3139}
3140
3141bool WebPage::findStringFromInjectedBundle(const String& target, FindOptions options)
3142{
3143    return m_page->findString(target, options);
3144}
3145
3146void WebPage::findString(const String& string, uint32_t options, uint32_t maxMatchCount)
3147{
3148    m_findController.findString(string, static_cast<FindOptions>(options), maxMatchCount);
3149}
3150
3151void WebPage::findStringMatches(const String& string, uint32_t options, uint32_t maxMatchCount)
3152{
3153    m_findController.findStringMatches(string, static_cast<FindOptions>(options), maxMatchCount);
3154}
3155
3156void WebPage::getImageForFindMatch(uint32_t matchIndex)
3157{
3158    m_findController.getImageForFindMatch(matchIndex);
3159}
3160
3161void WebPage::selectFindMatch(uint32_t matchIndex)
3162{
3163    m_findController.selectFindMatch(matchIndex);
3164}
3165
3166void WebPage::hideFindUI()
3167{
3168    m_findController.hideFindUI();
3169}
3170
3171void WebPage::countStringMatches(const String& string, uint32_t options, uint32_t maxMatchCount)
3172{
3173    m_findController.countStringMatches(string, static_cast<FindOptions>(options), maxMatchCount);
3174}
3175
3176void WebPage::didChangeSelectedIndexForActivePopupMenu(int32_t newIndex)
3177{
3178    changeSelectedIndex(newIndex);
3179    m_activePopupMenu = 0;
3180}
3181
3182void WebPage::changeSelectedIndex(int32_t index)
3183{
3184    if (!m_activePopupMenu)
3185        return;
3186
3187    m_activePopupMenu->didChangeSelectedIndex(index);
3188}
3189
3190#if PLATFORM(IOS)
3191void WebPage::didChooseFilesForOpenPanelWithDisplayStringAndIcon(const Vector<String>& files, const String& displayString, const IPC::DataReference& iconData)
3192{
3193    if (!m_activeOpenPanelResultListener)
3194        return;
3195
3196    RefPtr<Icon> icon;
3197    if (!iconData.isEmpty()) {
3198        RetainPtr<CFDataRef> dataRef = adoptCF(CFDataCreate(nullptr, iconData.data(), iconData.size()));
3199        RetainPtr<CGDataProviderRef> imageProviderRef = adoptCF(CGDataProviderCreateWithCFData(dataRef.get()));
3200        RetainPtr<CGImageRef> imageRef = adoptCF(CGImageCreateWithJPEGDataProvider(imageProviderRef.get(), nullptr, true, kCGRenderingIntentDefault));
3201        icon = Icon::createIconForImage(imageRef.get());
3202    }
3203
3204    m_activeOpenPanelResultListener->didChooseFilesWithDisplayStringAndIcon(files, displayString, icon.get());
3205    m_activeOpenPanelResultListener = nullptr;
3206}
3207#endif
3208
3209void WebPage::didChooseFilesForOpenPanel(const Vector<String>& files)
3210{
3211    if (!m_activeOpenPanelResultListener)
3212        return;
3213
3214    m_activeOpenPanelResultListener->didChooseFiles(files);
3215    m_activeOpenPanelResultListener = 0;
3216}
3217
3218void WebPage::didCancelForOpenPanel()
3219{
3220    m_activeOpenPanelResultListener = 0;
3221}
3222
3223#if ENABLE(SANDBOX_EXTENSIONS)
3224void WebPage::extendSandboxForFileFromOpenPanel(const SandboxExtension::Handle& handle)
3225{
3226    SandboxExtension::create(handle)->consumePermanently();
3227}
3228#endif
3229
3230#if ENABLE(GEOLOCATION)
3231void WebPage::didReceiveGeolocationPermissionDecision(uint64_t geolocationID, bool allowed)
3232{
3233    m_geolocationPermissionRequestManager.didReceiveGeolocationPermissionDecision(geolocationID, allowed);
3234}
3235#endif
3236
3237void WebPage::didReceiveNotificationPermissionDecision(uint64_t notificationID, bool allowed)
3238{
3239    notificationPermissionRequestManager()->didReceiveNotificationPermissionDecision(notificationID, allowed);
3240}
3241
3242#if !PLATFORM(IOS)
3243void WebPage::advanceToNextMisspelling(bool startBeforeSelection)
3244{
3245    Frame& frame = m_page->focusController().focusedOrMainFrame();
3246    frame.editor().advanceToNextMisspelling(startBeforeSelection);
3247}
3248#endif
3249
3250void WebPage::changeSpellingToWord(const String& word)
3251{
3252    replaceSelectionWithText(&m_page->focusController().focusedOrMainFrame(), word);
3253}
3254
3255void WebPage::unmarkAllMisspellings()
3256{
3257    for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
3258        if (Document* document = frame->document())
3259            document->markers().removeMarkers(DocumentMarker::Spelling);
3260    }
3261}
3262
3263void WebPage::unmarkAllBadGrammar()
3264{
3265    for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
3266        if (Document* document = frame->document())
3267            document->markers().removeMarkers(DocumentMarker::Grammar);
3268    }
3269}
3270
3271#if USE(APPKIT)
3272void WebPage::uppercaseWord()
3273{
3274    m_page->focusController().focusedOrMainFrame().editor().uppercaseWord();
3275}
3276
3277void WebPage::lowercaseWord()
3278{
3279    m_page->focusController().focusedOrMainFrame().editor().lowercaseWord();
3280}
3281
3282void WebPage::capitalizeWord()
3283{
3284    m_page->focusController().focusedOrMainFrame().editor().capitalizeWord();
3285}
3286#endif
3287
3288void WebPage::setTextForActivePopupMenu(int32_t index)
3289{
3290    if (!m_activePopupMenu)
3291        return;
3292
3293    m_activePopupMenu->setTextForIndex(index);
3294}
3295
3296#if PLATFORM(GTK)
3297void WebPage::failedToShowPopupMenu()
3298{
3299    if (!m_activePopupMenu)
3300        return;
3301
3302    m_activePopupMenu->client()->popupDidHide();
3303}
3304#endif
3305
3306#if ENABLE(CONTEXT_MENUS)
3307void WebPage::didSelectItemFromActiveContextMenu(const WebContextMenuItemData& item)
3308{
3309    if (!m_contextMenu)
3310        return;
3311
3312    m_contextMenu->itemSelected(item);
3313    m_contextMenu = 0;
3314}
3315#endif
3316
3317void WebPage::replaceSelectionWithText(Frame* frame, const String& text)
3318{
3319    bool selectReplacement = true;
3320    bool smartReplace = false;
3321    return frame->editor().replaceSelectionWithText(text, selectReplacement, smartReplace);
3322}
3323
3324#if !PLATFORM(IOS)
3325void WebPage::clearSelection()
3326{
3327    m_page->focusController().focusedOrMainFrame().selection().clear();
3328}
3329#endif
3330
3331bool WebPage::mainFrameHasCustomContentProvider() const
3332{
3333    if (Frame* frame = mainFrame()) {
3334        WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(frame->loader().client());
3335        ASSERT(webFrameLoaderClient);
3336        return webFrameLoaderClient->frameHasCustomContentProvider();
3337    }
3338
3339    return false;
3340}
3341
3342void WebPage::addMIMETypeWithCustomContentProvider(const String& mimeType)
3343{
3344    m_mimeTypesWithCustomContentProviders.add(mimeType);
3345}
3346
3347void WebPage::updateMainFrameScrollOffsetPinning()
3348{
3349    Frame& frame = m_page->mainFrame();
3350    IntPoint scrollPosition = frame.view()->scrollPosition();
3351    IntPoint maximumScrollPosition = frame.view()->maximumScrollPosition();
3352    IntPoint minimumScrollPosition = frame.view()->minimumScrollPosition();
3353
3354    bool isPinnedToLeftSide = (scrollPosition.x() <= minimumScrollPosition.x());
3355    bool isPinnedToRightSide = (scrollPosition.x() >= maximumScrollPosition.x());
3356    bool isPinnedToTopSide = (scrollPosition.y() <= minimumScrollPosition.y());
3357    bool isPinnedToBottomSide = (scrollPosition.y() >= maximumScrollPosition.y());
3358
3359    if (isPinnedToLeftSide != m_cachedMainFrameIsPinnedToLeftSide || isPinnedToRightSide != m_cachedMainFrameIsPinnedToRightSide || isPinnedToTopSide != m_cachedMainFrameIsPinnedToTopSide || isPinnedToBottomSide != m_cachedMainFrameIsPinnedToBottomSide) {
3360        send(Messages::WebPageProxy::DidChangeScrollOffsetPinningForMainFrame(isPinnedToLeftSide, isPinnedToRightSide, isPinnedToTopSide, isPinnedToBottomSide));
3361
3362        m_cachedMainFrameIsPinnedToLeftSide = isPinnedToLeftSide;
3363        m_cachedMainFrameIsPinnedToRightSide = isPinnedToRightSide;
3364        m_cachedMainFrameIsPinnedToTopSide = isPinnedToTopSide;
3365        m_cachedMainFrameIsPinnedToBottomSide = isPinnedToBottomSide;
3366    }
3367}
3368
3369void WebPage::mainFrameDidLayout()
3370{
3371    unsigned pageCount = m_page->pageCount();
3372    if (pageCount != m_cachedPageCount) {
3373        send(Messages::WebPageProxy::DidChangePageCount(pageCount));
3374        m_cachedPageCount = pageCount;
3375    }
3376
3377#if USE(TILED_BACKING_STORE)
3378    if (m_drawingArea && m_drawingArea->layerTreeHost()) {
3379        double red, green, blue, alpha;
3380        m_mainFrame->getDocumentBackgroundColor(&red, &green, &blue, &alpha);
3381        RGBA32 rgba = makeRGBA32FromFloats(red, green, blue, alpha);
3382        if (m_backgroundColor.rgb() != rgba) {
3383            m_backgroundColor.setRGB(rgba);
3384            m_drawingArea->layerTreeHost()->setBackgroundColor(m_backgroundColor);
3385        }
3386    }
3387#endif
3388
3389#if PLATFORM(MAC)
3390    m_viewGestureGeometryCollector.mainFrameDidLayout();
3391#endif
3392#if PLATFORM(IOS)
3393    if (FrameView* frameView = mainFrameView()) {
3394        IntSize newContentSize = frameView->contentsSize();
3395        if (m_viewportConfiguration.contentsSize() != newContentSize) {
3396            m_viewportConfiguration.setContentsSize(newContentSize);
3397            viewportConfigurationChanged();
3398        }
3399    }
3400#endif
3401}
3402
3403void WebPage::addPluginView(PluginView* pluginView)
3404{
3405    ASSERT(!m_pluginViews.contains(pluginView));
3406
3407    m_pluginViews.add(pluginView);
3408    m_hasSeenPlugin = true;
3409#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
3410    LOG(Plugins, "Primary Plug-In Detection: triggering detection from addPluginView(%p)", pluginView);
3411    m_determinePrimarySnapshottedPlugInTimer.startOneShot(0);
3412#endif
3413}
3414
3415void WebPage::removePluginView(PluginView* pluginView)
3416{
3417    ASSERT(m_pluginViews.contains(pluginView));
3418
3419    m_pluginViews.remove(pluginView);
3420#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
3421    LOG(Plugins, "Primary Plug-In Detection: removePluginView(%p)", pluginView);
3422#endif
3423}
3424
3425void WebPage::sendSetWindowFrame(const FloatRect& windowFrame)
3426{
3427#if PLATFORM(COCOA)
3428    m_hasCachedWindowFrame = false;
3429#endif
3430    send(Messages::WebPageProxy::SetWindowFrame(windowFrame));
3431}
3432
3433#if PLATFORM(COCOA)
3434void WebPage::windowAndViewFramesChanged(const FloatRect& windowFrameInScreenCoordinates, const FloatRect& windowFrameInUnflippedScreenCoordinates, const FloatRect& viewFrameInWindowCoordinates, const FloatPoint& accessibilityViewCoordinates)
3435{
3436    m_windowFrameInScreenCoordinates = windowFrameInScreenCoordinates;
3437    m_windowFrameInUnflippedScreenCoordinates = windowFrameInUnflippedScreenCoordinates;
3438    m_viewFrameInWindowCoordinates = viewFrameInWindowCoordinates;
3439    m_accessibilityPosition = accessibilityViewCoordinates;
3440
3441    // Tell all our plug-in views that the window and view frames have changed.
3442    for (auto* pluginView : m_pluginViews)
3443        pluginView->windowAndViewFramesChanged(enclosingIntRect(windowFrameInScreenCoordinates), enclosingIntRect(viewFrameInWindowCoordinates));
3444
3445    m_hasCachedWindowFrame = !m_windowFrameInUnflippedScreenCoordinates.isEmpty();
3446}
3447#endif
3448
3449void WebPage::setMainFrameIsScrollable(bool isScrollable)
3450{
3451    m_mainFrameIsScrollable = isScrollable;
3452    m_drawingArea->mainFrameScrollabilityChanged(isScrollable);
3453
3454    if (FrameView* frameView = m_mainFrame->coreFrame()->view()) {
3455        frameView->setCanHaveScrollbars(isScrollable);
3456        frameView->setProhibitsScrolling(!isScrollable);
3457    }
3458}
3459
3460bool WebPage::windowIsFocused() const
3461{
3462    return m_page->focusController().isActive();
3463}
3464
3465bool WebPage::windowAndWebPageAreFocused() const
3466{
3467    if (!isVisible())
3468        return false;
3469
3470    return m_page->focusController().isFocused() && m_page->focusController().isActive();
3471}
3472
3473void WebPage::didReceiveMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder)
3474{
3475    if (decoder.messageReceiverName() == Messages::DrawingArea::messageReceiverName()) {
3476        if (m_drawingArea)
3477            m_drawingArea->didReceiveDrawingAreaMessage(connection, decoder);
3478        return;
3479    }
3480
3481#if USE(TILED_BACKING_STORE)
3482    if (decoder.messageReceiverName() == Messages::CoordinatedLayerTreeHost::messageReceiverName()) {
3483        if (m_drawingArea)
3484            m_drawingArea->didReceiveCoordinatedLayerTreeHostMessage(connection, decoder);
3485        return;
3486    }
3487#endif
3488
3489#if ENABLE(INSPECTOR)
3490    if (decoder.messageReceiverName() == Messages::WebInspector::messageReceiverName()) {
3491        if (WebInspector* inspector = this->inspector())
3492            inspector->didReceiveWebInspectorMessage(connection, decoder);
3493        return;
3494    }
3495#endif
3496
3497#if ENABLE(FULLSCREEN_API)
3498    if (decoder.messageReceiverName() == Messages::WebFullScreenManager::messageReceiverName()) {
3499        fullScreenManager()->didReceiveMessage(connection, decoder);
3500        return;
3501    }
3502#endif
3503
3504    didReceiveWebPageMessage(connection, decoder);
3505}
3506
3507void WebPage::didReceiveSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
3508{
3509    didReceiveSyncWebPageMessage(connection, decoder, replyEncoder);
3510}
3511
3512InjectedBundleBackForwardList* WebPage::backForwardList()
3513{
3514    if (!m_backForwardList)
3515        m_backForwardList = InjectedBundleBackForwardList::create(this);
3516    return m_backForwardList.get();
3517}
3518
3519#if ENABLE(ASYNC_SCROLLING)
3520ScrollingCoordinator* WebPage::scrollingCoordinator() const
3521{
3522    return m_page->scrollingCoordinator();
3523}
3524#endif
3525
3526WebPage::SandboxExtensionTracker::~SandboxExtensionTracker()
3527{
3528    invalidate();
3529}
3530
3531void WebPage::SandboxExtensionTracker::invalidate()
3532{
3533    m_pendingProvisionalSandboxExtension = nullptr;
3534
3535    if (m_provisionalSandboxExtension) {
3536        m_provisionalSandboxExtension->revoke();
3537        m_provisionalSandboxExtension = nullptr;
3538    }
3539
3540    if (m_committedSandboxExtension) {
3541        m_committedSandboxExtension->revoke();
3542        m_committedSandboxExtension = nullptr;
3543    }
3544}
3545
3546void WebPage::SandboxExtensionTracker::willPerformLoadDragDestinationAction(PassRefPtr<SandboxExtension> pendingDropSandboxExtension)
3547{
3548    setPendingProvisionalSandboxExtension(pendingDropSandboxExtension);
3549}
3550
3551void WebPage::SandboxExtensionTracker::beginLoad(WebFrame* frame, const SandboxExtension::Handle& handle)
3552{
3553    ASSERT_UNUSED(frame, frame->isMainFrame());
3554
3555    setPendingProvisionalSandboxExtension(SandboxExtension::create(handle));
3556}
3557
3558void WebPage::SandboxExtensionTracker::setPendingProvisionalSandboxExtension(PassRefPtr<SandboxExtension> pendingProvisionalSandboxExtension)
3559{
3560    m_pendingProvisionalSandboxExtension = pendingProvisionalSandboxExtension;
3561}
3562
3563static bool shouldReuseCommittedSandboxExtension(WebFrame* frame)
3564{
3565    ASSERT(frame->isMainFrame());
3566
3567    FrameLoader& frameLoader = frame->coreFrame()->loader();
3568    FrameLoadType frameLoadType = frameLoader.loadType();
3569
3570    // If the page is being reloaded, it should reuse whatever extension is committed.
3571    if (frameLoadType == FrameLoadType::Reload || frameLoadType == FrameLoadType::ReloadFromOrigin)
3572        return true;
3573
3574    DocumentLoader* documentLoader = frameLoader.documentLoader();
3575    DocumentLoader* provisionalDocumentLoader = frameLoader.provisionalDocumentLoader();
3576    if (!documentLoader || !provisionalDocumentLoader)
3577        return false;
3578
3579    if (documentLoader->url().isLocalFile() && provisionalDocumentLoader->url().isLocalFile())
3580        return true;
3581
3582    return false;
3583}
3584
3585void WebPage::SandboxExtensionTracker::didStartProvisionalLoad(WebFrame* frame)
3586{
3587    if (!frame->isMainFrame())
3588        return;
3589
3590    // We should only reuse the commited sandbox extension if it is not null. It can be
3591    // null if the last load was for an error page.
3592    if (m_committedSandboxExtension && shouldReuseCommittedSandboxExtension(frame))
3593        m_pendingProvisionalSandboxExtension = m_committedSandboxExtension;
3594
3595    ASSERT(!m_provisionalSandboxExtension);
3596
3597    m_provisionalSandboxExtension = m_pendingProvisionalSandboxExtension.release();
3598    if (!m_provisionalSandboxExtension)
3599        return;
3600
3601    ASSERT(!m_provisionalSandboxExtension || frame->coreFrame()->loader().provisionalDocumentLoader()->url().isLocalFile());
3602
3603    m_provisionalSandboxExtension->consume();
3604}
3605
3606void WebPage::SandboxExtensionTracker::didCommitProvisionalLoad(WebFrame* frame)
3607{
3608    if (!frame->isMainFrame())
3609        return;
3610
3611    if (m_committedSandboxExtension)
3612        m_committedSandboxExtension->revoke();
3613
3614    m_committedSandboxExtension = m_provisionalSandboxExtension.release();
3615
3616    // We can also have a non-null m_pendingProvisionalSandboxExtension if a new load is being started.
3617    // This extension is not cleared, because it does not pertain to the failed load, and will be needed.
3618}
3619
3620void WebPage::SandboxExtensionTracker::didFailProvisionalLoad(WebFrame* frame)
3621{
3622    if (!frame->isMainFrame())
3623        return;
3624
3625    if (!m_provisionalSandboxExtension)
3626        return;
3627
3628    m_provisionalSandboxExtension->revoke();
3629    m_provisionalSandboxExtension = nullptr;
3630
3631    // We can also have a non-null m_pendingProvisionalSandboxExtension if a new load is being started
3632    // (notably, if the current one fails because the new one cancels it). This extension is not cleared,
3633    // because it does not pertain to the failed load, and will be needed.
3634}
3635
3636bool WebPage::hasLocalDataForURL(const URL& url)
3637{
3638    if (url.isLocalFile())
3639        return true;
3640
3641    DocumentLoader* documentLoader = m_page->mainFrame().loader().documentLoader();
3642    if (documentLoader && documentLoader->subresource(url))
3643        return true;
3644
3645    return platformHasLocalDataForURL(url);
3646}
3647
3648void WebPage::setCustomTextEncodingName(const String& encoding)
3649{
3650    m_page->mainFrame().loader().reloadWithOverrideEncoding(encoding);
3651}
3652
3653void WebPage::didRemoveBackForwardItem(uint64_t itemID)
3654{
3655    WebBackForwardListProxy::removeItem(itemID);
3656}
3657
3658#if PLATFORM(COCOA)
3659
3660bool WebPage::isSpeaking()
3661{
3662    bool result;
3663    return sendSync(Messages::WebPageProxy::GetIsSpeaking(), Messages::WebPageProxy::GetIsSpeaking::Reply(result)) && result;
3664}
3665
3666void WebPage::speak(const String& string)
3667{
3668    send(Messages::WebPageProxy::Speak(string));
3669}
3670
3671void WebPage::stopSpeaking()
3672{
3673    send(Messages::WebPageProxy::StopSpeaking());
3674}
3675
3676#endif
3677
3678#if PLATFORM(MAC)
3679RetainPtr<PDFDocument> WebPage::pdfDocumentForPrintingFrame(Frame* coreFrame)
3680{
3681    Document* document = coreFrame->document();
3682    if (!document)
3683        return 0;
3684
3685    if (!document->isPluginDocument())
3686        return 0;
3687
3688    PluginView* pluginView = static_cast<PluginView*>(toPluginDocument(document)->pluginWidget());
3689    if (!pluginView)
3690        return 0;
3691
3692    return pluginView->pdfDocumentForPrinting();
3693}
3694#endif // PLATFORM(MAC)
3695
3696void WebPage::beginPrinting(uint64_t frameID, const PrintInfo& printInfo)
3697{
3698    WebFrame* frame = WebProcess::shared().webFrame(frameID);
3699    if (!frame)
3700        return;
3701
3702    Frame* coreFrame = frame->coreFrame();
3703    if (!coreFrame)
3704        return;
3705
3706#if PLATFORM(MAC)
3707    if (pdfDocumentForPrintingFrame(coreFrame))
3708        return;
3709#endif // PLATFORM(MAC)
3710
3711    if (!m_printContext)
3712        m_printContext = std::make_unique<PrintContext>(coreFrame);
3713
3714    drawingArea()->setLayerTreeStateIsFrozen(true);
3715    m_printContext->begin(printInfo.availablePaperWidth, printInfo.availablePaperHeight);
3716
3717    float fullPageHeight;
3718    m_printContext->computePageRects(FloatRect(0, 0, printInfo.availablePaperWidth, printInfo.availablePaperHeight), 0, 0, printInfo.pageSetupScaleFactor, fullPageHeight, true);
3719
3720#if PLATFORM(GTK)
3721    if (!m_printOperation)
3722        m_printOperation = WebPrintOperationGtk::create(this, printInfo);
3723#endif
3724}
3725
3726void WebPage::endPrinting()
3727{
3728    drawingArea()->setLayerTreeStateIsFrozen(false);
3729    m_printContext = nullptr;
3730}
3731
3732void WebPage::computePagesForPrinting(uint64_t frameID, const PrintInfo& printInfo, uint64_t callbackID)
3733{
3734    Vector<IntRect> resultPageRects;
3735    double resultTotalScaleFactorForPrinting = 1;
3736    computePagesForPrintingImpl(frameID, printInfo, resultPageRects, resultTotalScaleFactorForPrinting);
3737    send(Messages::WebPageProxy::ComputedPagesCallback(resultPageRects, resultTotalScaleFactorForPrinting, callbackID));
3738}
3739
3740void WebPage::computePagesForPrintingImpl(uint64_t frameID, const PrintInfo& printInfo, Vector<WebCore::IntRect>& resultPageRects, double& resultTotalScaleFactorForPrinting)
3741{
3742    ASSERT(resultPageRects.isEmpty());
3743
3744    beginPrinting(frameID, printInfo);
3745
3746    if (m_printContext) {
3747        resultPageRects = m_printContext->pageRects();
3748        resultTotalScaleFactorForPrinting = m_printContext->computeAutomaticScaleFactor(FloatSize(printInfo.availablePaperWidth, printInfo.availablePaperHeight)) * printInfo.pageSetupScaleFactor;
3749    }
3750#if PLATFORM(COCOA)
3751    else
3752        computePagesForPrintingPDFDocument(frameID, printInfo, resultPageRects);
3753#endif // PLATFORM(COCOA)
3754
3755    // If we're asked to print, we should actually print at least a blank page.
3756    if (resultPageRects.isEmpty())
3757        resultPageRects.append(IntRect(0, 0, 1, 1));
3758}
3759
3760#if PLATFORM(COCOA)
3761void WebPage::drawRectToImage(uint64_t frameID, const PrintInfo& printInfo, const IntRect& rect, const WebCore::IntSize& imageSize, uint64_t callbackID)
3762{
3763    WebFrame* frame = WebProcess::shared().webFrame(frameID);
3764    Frame* coreFrame = frame ? frame->coreFrame() : 0;
3765
3766    RefPtr<WebImage> image;
3767
3768#if USE(CG)
3769    if (coreFrame) {
3770#if PLATFORM(MAC)
3771        ASSERT(coreFrame->document()->printing() || pdfDocumentForPrintingFrame(coreFrame));
3772#else
3773        ASSERT(coreFrame->document()->printing());
3774#endif
3775
3776        RefPtr<ShareableBitmap> bitmap = ShareableBitmap::createShareable(imageSize, ShareableBitmap::SupportsAlpha);
3777        auto graphicsContext = bitmap->createGraphicsContext();
3778
3779        float printingScale = static_cast<float>(imageSize.width()) / rect.width();
3780        graphicsContext->scale(FloatSize(printingScale, printingScale));
3781
3782#if PLATFORM(MAC)
3783        if (RetainPtr<PDFDocument> pdfDocument = pdfDocumentForPrintingFrame(coreFrame)) {
3784            ASSERT(!m_printContext);
3785            graphicsContext->scale(FloatSize(1, -1));
3786            graphicsContext->translate(0, -rect.height());
3787            drawPDFDocument(graphicsContext->platformContext(), pdfDocument.get(), printInfo, rect);
3788        } else
3789#endif
3790        {
3791            m_printContext->spoolRect(*graphicsContext, rect);
3792        }
3793
3794        image = WebImage::create(bitmap.release());
3795    }
3796#endif
3797
3798    ShareableBitmap::Handle handle;
3799
3800    if (image)
3801        image->bitmap()->createHandle(handle, SharedMemory::ReadOnly);
3802
3803    send(Messages::WebPageProxy::ImageCallback(handle, callbackID));
3804}
3805
3806void WebPage::drawPagesToPDF(uint64_t frameID, const PrintInfo& printInfo, uint32_t first, uint32_t count, uint64_t callbackID)
3807{
3808    RetainPtr<CFMutableDataRef> pdfPageData;
3809    drawPagesToPDFImpl(frameID, printInfo, first, count, pdfPageData);
3810    send(Messages::WebPageProxy::DataCallback(IPC::DataReference(CFDataGetBytePtr(pdfPageData.get()), CFDataGetLength(pdfPageData.get())), callbackID));
3811}
3812
3813void WebPage::drawPagesToPDFImpl(uint64_t frameID, const PrintInfo& printInfo, uint32_t first, uint32_t count, RetainPtr<CFMutableDataRef>& pdfPageData)
3814{
3815    WebFrame* frame = WebProcess::shared().webFrame(frameID);
3816    Frame* coreFrame = frame ? frame->coreFrame() : 0;
3817
3818    pdfPageData = adoptCF(CFDataCreateMutable(0, 0));
3819
3820#if USE(CG)
3821    if (coreFrame) {
3822
3823#if PLATFORM(MAC)
3824        ASSERT(coreFrame->document()->printing() || pdfDocumentForPrintingFrame(coreFrame));
3825#else
3826        ASSERT(coreFrame->document()->printing());
3827#endif
3828
3829        // FIXME: Use CGDataConsumerCreate with callbacks to avoid copying the data.
3830        RetainPtr<CGDataConsumerRef> pdfDataConsumer = adoptCF(CGDataConsumerCreateWithCFData(pdfPageData.get()));
3831
3832        CGRect mediaBox = (m_printContext && m_printContext->pageCount()) ? m_printContext->pageRect(0) : CGRectMake(0, 0, printInfo.availablePaperWidth, printInfo.availablePaperHeight);
3833        RetainPtr<CGContextRef> context = adoptCF(CGPDFContextCreate(pdfDataConsumer.get(), &mediaBox, 0));
3834
3835#if PLATFORM(MAC)
3836        if (RetainPtr<PDFDocument> pdfDocument = pdfDocumentForPrintingFrame(coreFrame)) {
3837            ASSERT(!m_printContext);
3838            drawPagesToPDFFromPDFDocument(context.get(), pdfDocument.get(), printInfo, first, count);
3839        } else
3840#endif
3841        {
3842            size_t pageCount = m_printContext->pageCount();
3843            for (uint32_t page = first; page < first + count; ++page) {
3844                if (page >= pageCount)
3845                    break;
3846
3847                RetainPtr<CFDictionaryRef> pageInfo = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
3848                CGPDFContextBeginPage(context.get(), pageInfo.get());
3849
3850                GraphicsContext ctx(context.get());
3851                ctx.scale(FloatSize(1, -1));
3852                ctx.translate(0, -m_printContext->pageRect(page).height());
3853                m_printContext->spoolPage(ctx, page, m_printContext->pageRect(page).width());
3854
3855                CGPDFContextEndPage(context.get());
3856            }
3857        }
3858        CGPDFContextClose(context.get());
3859    }
3860#endif
3861}
3862
3863#elif PLATFORM(GTK)
3864void WebPage::drawPagesForPrinting(uint64_t frameID, const PrintInfo& printInfo, uint64_t callbackID)
3865{
3866    beginPrinting(frameID, printInfo);
3867    if (m_printContext && m_printOperation) {
3868        m_printOperation->startPrint(m_printContext.get(), callbackID);
3869        return;
3870    }
3871
3872    send(Messages::WebPageProxy::VoidCallback(callbackID));
3873}
3874
3875void WebPage::didFinishPrintOperation(const WebCore::ResourceError& error, uint64_t callbackID)
3876{
3877    send(Messages::WebPageProxy::PrintFinishedCallback(error, callbackID));
3878    m_printOperation = nullptr;
3879}
3880#endif
3881
3882void WebPage::savePDFToFileInDownloadsFolder(const String& suggestedFilename, const String& originatingURLString, const uint8_t* data, unsigned long size)
3883{
3884    send(Messages::WebPageProxy::SavePDFToFileInDownloadsFolder(suggestedFilename, originatingURLString, IPC::DataReference(data, size)));
3885}
3886
3887#if PLATFORM(COCOA)
3888void WebPage::savePDFToTemporaryFolderAndOpenWithNativeApplication(const String& suggestedFilename, const String& originatingURLString, const uint8_t* data, unsigned long size, const String& pdfUUID)
3889{
3890    send(Messages::WebPageProxy::SavePDFToTemporaryFolderAndOpenWithNativeApplication(suggestedFilename, originatingURLString, IPC::DataReference(data, size), pdfUUID));
3891}
3892#endif
3893
3894void WebPage::addResourceRequest(unsigned long identifier, const WebCore::ResourceRequest& request)
3895{
3896    if (!request.url().protocolIsInHTTPFamily())
3897        return;
3898
3899    ASSERT(!m_networkResourceRequestIdentifiers.contains(identifier));
3900    bool wasEmpty = m_networkResourceRequestIdentifiers.isEmpty();
3901    m_networkResourceRequestIdentifiers.add(identifier);
3902    if (wasEmpty)
3903        send(Messages::WebPageProxy::SetNetworkRequestsInProgress(true));
3904}
3905
3906void WebPage::removeResourceRequest(unsigned long identifier)
3907{
3908    if (!m_networkResourceRequestIdentifiers.remove(identifier))
3909        return;
3910
3911    if (m_networkResourceRequestIdentifiers.isEmpty())
3912        send(Messages::WebPageProxy::SetNetworkRequestsInProgress(false));
3913}
3914
3915void WebPage::setMediaVolume(float volume)
3916{
3917    m_page->setMediaVolume(volume);
3918}
3919
3920void WebPage::setMayStartMediaWhenInWindow(bool mayStartMedia)
3921{
3922    if (mayStartMedia == m_mayStartMediaWhenInWindow)
3923        return;
3924
3925    m_mayStartMediaWhenInWindow = mayStartMedia;
3926    if (m_mayStartMediaWhenInWindow && m_page->isInWindow())
3927        m_setCanStartMediaTimer.startOneShot(0);
3928}
3929
3930void WebPage::runModal()
3931{
3932    if (m_isClosed)
3933        return;
3934    if (m_isRunningModal)
3935        return;
3936
3937    m_isRunningModal = true;
3938    send(Messages::WebPageProxy::RunModal());
3939#if !ASSERT_DISABLED
3940    Ref<WebPage> protector(*this);
3941#endif
3942    RunLoop::run();
3943    ASSERT(!m_isRunningModal);
3944}
3945
3946bool WebPage::canHandleRequest(const WebCore::ResourceRequest& request)
3947{
3948    if (SchemeRegistry::shouldLoadURLSchemeAsEmptyDocument(request.url().protocol()))
3949        return true;
3950
3951    if (request.url().protocolIs("blob"))
3952        return true;
3953
3954    return platformCanHandleRequest(request);
3955}
3956
3957#if USE(TILED_BACKING_STORE)
3958void WebPage::commitPageTransitionViewport()
3959{
3960    m_drawingArea->setLayerTreeStateIsFrozen(false);
3961}
3962#endif
3963
3964#if PLATFORM(COCOA)
3965void WebPage::handleAlternativeTextUIResult(const String& result)
3966{
3967    Frame& frame = m_page->focusController().focusedOrMainFrame();
3968    frame.editor().handleAlternativeTextUIResult(result);
3969}
3970#endif
3971
3972void WebPage::simulateMouseDown(int button, WebCore::IntPoint position, int clickCount, WKEventModifiers modifiers, double time)
3973{
3974    mouseEvent(WebMouseEvent(WebMouseEvent::MouseDown, static_cast<WebMouseEvent::Button>(button), position, position, 0, 0, 0, clickCount, static_cast<WebMouseEvent::Modifiers>(modifiers), time));
3975}
3976
3977void WebPage::simulateMouseUp(int button, WebCore::IntPoint position, int clickCount, WKEventModifiers modifiers, double time)
3978{
3979    mouseEvent(WebMouseEvent(WebMouseEvent::MouseUp, static_cast<WebMouseEvent::Button>(button), position, position, 0, 0, 0, clickCount, static_cast<WebMouseEvent::Modifiers>(modifiers), time));
3980}
3981
3982void WebPage::simulateMouseMotion(WebCore::IntPoint position, double time)
3983{
3984    mouseEvent(WebMouseEvent(WebMouseEvent::MouseMove, WebMouseEvent::NoButton, position, position, 0, 0, 0, 0, WebMouseEvent::Modifiers(), time));
3985}
3986
3987void WebPage::setCompositionForTesting(const String& compositionString, uint64_t from, uint64_t length)
3988{
3989    Frame& frame = m_page->focusController().focusedOrMainFrame();
3990    if (!frame.editor().canEdit())
3991        return;
3992
3993    Vector<CompositionUnderline> underlines;
3994    underlines.append(CompositionUnderline(0, compositionString.length(), Color(Color::black), false));
3995    frame.editor().setComposition(compositionString, underlines, from, from + length);
3996}
3997
3998bool WebPage::hasCompositionForTesting()
3999{
4000    Frame& frame = m_page->focusController().focusedOrMainFrame();
4001    return frame.editor().hasComposition();
4002}
4003
4004void WebPage::confirmCompositionForTesting(const String& compositionString)
4005{
4006    Frame& frame = m_page->focusController().focusedOrMainFrame();
4007    if (!frame.editor().canEdit())
4008        return;
4009
4010    if (compositionString.isNull())
4011        frame.editor().confirmComposition();
4012    frame.editor().confirmComposition(compositionString);
4013}
4014
4015void WebPage::numWheelEventHandlersChanged(unsigned numWheelEventHandlers)
4016{
4017    if (m_numWheelEventHandlers == numWheelEventHandlers)
4018        return;
4019
4020    m_numWheelEventHandlers = numWheelEventHandlers;
4021    recomputeShortCircuitHorizontalWheelEventsState();
4022}
4023
4024static bool hasEnabledHorizontalScrollbar(ScrollableArea* scrollableArea)
4025{
4026    if (Scrollbar* scrollbar = scrollableArea->horizontalScrollbar())
4027        return scrollbar->enabled();
4028
4029    return false;
4030}
4031
4032static bool pageContainsAnyHorizontalScrollbars(Frame* mainFrame)
4033{
4034    if (FrameView* frameView = mainFrame->view()) {
4035        if (hasEnabledHorizontalScrollbar(frameView))
4036            return true;
4037    }
4038
4039    for (Frame* frame = mainFrame; frame; frame = frame->tree().traverseNext()) {
4040        FrameView* frameView = frame->view();
4041        if (!frameView)
4042            continue;
4043
4044        const HashSet<ScrollableArea*>* scrollableAreas = frameView->scrollableAreas();
4045        if (!scrollableAreas)
4046            continue;
4047
4048        for (HashSet<ScrollableArea*>::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
4049            ScrollableArea* scrollableArea = *it;
4050            if (!scrollableArea->scrollbarsCanBeActive())
4051                continue;
4052
4053            if (hasEnabledHorizontalScrollbar(scrollableArea))
4054                return true;
4055        }
4056    }
4057
4058    return false;
4059}
4060
4061void WebPage::recomputeShortCircuitHorizontalWheelEventsState()
4062{
4063    bool canShortCircuitHorizontalWheelEvents = !m_numWheelEventHandlers;
4064
4065    if (canShortCircuitHorizontalWheelEvents) {
4066        // Check if we have any horizontal scroll bars on the page.
4067        if (pageContainsAnyHorizontalScrollbars(mainFrame()))
4068            canShortCircuitHorizontalWheelEvents = false;
4069    }
4070
4071    if (m_canShortCircuitHorizontalWheelEvents == canShortCircuitHorizontalWheelEvents)
4072        return;
4073
4074    m_canShortCircuitHorizontalWheelEvents = canShortCircuitHorizontalWheelEvents;
4075    send(Messages::WebPageProxy::SetCanShortCircuitHorizontalWheelEvents(m_canShortCircuitHorizontalWheelEvents));
4076}
4077
4078Frame* WebPage::mainFrame() const
4079{
4080    return m_page ? &m_page->mainFrame() : nullptr;
4081}
4082
4083FrameView* WebPage::mainFrameView() const
4084{
4085    if (Frame* frame = mainFrame())
4086        return frame->view();
4087
4088    return nullptr;
4089}
4090
4091void WebPage::setScrollingPerformanceLoggingEnabled(bool enabled)
4092{
4093    m_scrollingPerformanceLoggingEnabled = enabled;
4094
4095    FrameView* frameView = m_mainFrame->coreFrame()->view();
4096    if (!frameView)
4097        return;
4098
4099    frameView->setScrollingPerformanceLoggingEnabled(enabled);
4100}
4101
4102bool WebPage::canPluginHandleResponse(const ResourceResponse& response)
4103{
4104#if ENABLE(NETSCAPE_PLUGIN_API)
4105    uint32_t pluginLoadPolicy;
4106    bool allowOnlyApplicationPlugins = !m_mainFrame->coreFrame()->loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin);
4107
4108    uint64_t pluginProcessToken;
4109    String newMIMEType;
4110    String unavailabilityDescription;
4111    if (!sendSync(Messages::WebPageProxy::FindPlugin(response.mimeType(), PluginProcessTypeNormal, response.url().string(), response.url().string(), response.url().string(), allowOnlyApplicationPlugins), Messages::WebPageProxy::FindPlugin::Reply(pluginProcessToken, newMIMEType, pluginLoadPolicy, unavailabilityDescription)))
4112        return false;
4113
4114    return pluginLoadPolicy != PluginModuleBlocked && pluginProcessToken;
4115#else
4116    UNUSED_PARAM(response);
4117    return false;
4118#endif
4119}
4120
4121bool WebPage::shouldUseCustomContentProviderForResponse(const ResourceResponse& response)
4122{
4123    // If a plug-in exists that claims to support this response, it should take precedence over the custom content provider.
4124    return m_mimeTypesWithCustomContentProviders.contains(response.mimeType()) && !canPluginHandleResponse(response);
4125}
4126
4127#if PLATFORM(COCOA)
4128
4129void WebPage::insertTextAsync(const String& text, const EditingRange& replacementEditingRange, bool registerUndoGroup)
4130{
4131    Frame& frame = m_page->focusController().focusedOrMainFrame();
4132
4133    if (replacementEditingRange.location != notFound) {
4134        RefPtr<Range> replacementRange = rangeFromEditingRange(frame, replacementEditingRange);
4135        if (replacementRange)
4136            frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
4137    }
4138
4139    if (registerUndoGroup)
4140        send(Messages::WebPageProxy::RegisterInsertionUndoGrouping());
4141
4142    if (!frame.editor().hasComposition()) {
4143        // An insertText: might be handled by other responders in the chain if we don't handle it.
4144        // One example is space bar that results in scrolling down the page.
4145        frame.editor().insertText(text, nullptr);
4146    } else
4147        frame.editor().confirmComposition(text);
4148}
4149
4150void WebPage::getMarkedRangeAsync(uint64_t callbackID)
4151{
4152    Frame& frame = m_page->focusController().focusedOrMainFrame();
4153
4154    RefPtr<Range> range = frame.editor().compositionRange();
4155    size_t location;
4156    size_t length;
4157    if (!range || !TextIterator::getLocationAndLengthFromRange(frame.selection().rootEditableElementOrDocumentElement(), range.get(), location, length)) {
4158        location = notFound;
4159        length = 0;
4160    }
4161
4162    send(Messages::WebPageProxy::EditingRangeCallback(EditingRange(location, length), callbackID));
4163}
4164
4165void WebPage::getSelectedRangeAsync(uint64_t callbackID)
4166{
4167    Frame& frame = m_page->focusController().focusedOrMainFrame();
4168
4169    size_t location;
4170    size_t length;
4171    RefPtr<Range> range = frame.selection().toNormalizedRange();
4172    if (!range || !TextIterator::getLocationAndLengthFromRange(frame.selection().rootEditableElementOrDocumentElement(), range.get(), location, length)) {
4173        location = notFound;
4174        length = 0;
4175    }
4176
4177    send(Messages::WebPageProxy::EditingRangeCallback(EditingRange(location, length), callbackID));
4178}
4179
4180void WebPage::characterIndexForPointAsync(const WebCore::IntPoint& point, uint64_t callbackID)
4181{
4182    uint64_t index = notFound;
4183
4184    HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(point);
4185    Frame* frame = result.innerNonSharedNode() ? result.innerNodeFrame() : &m_page->focusController().focusedOrMainFrame();
4186
4187    RefPtr<Range> range = frame->rangeForPoint(result.roundedPointInInnerNodeFrame());
4188    if (range) {
4189        size_t location;
4190        size_t length;
4191        if (TextIterator::getLocationAndLengthFromRange(frame->selection().rootEditableElementOrDocumentElement(), range.get(), location, length))
4192            index = static_cast<uint64_t>(location);
4193    }
4194
4195    send(Messages::WebPageProxy::UnsignedCallback(index, callbackID));
4196}
4197
4198void WebPage::firstRectForCharacterRangeAsync(const EditingRange& editingRange, uint64_t callbackID)
4199{
4200    Frame& frame = m_page->focusController().focusedOrMainFrame();
4201    IntRect result(IntPoint(0, 0), IntSize(0, 0));
4202
4203    RefPtr<Range> range = rangeFromEditingRange(frame, editingRange);
4204    if (!range) {
4205        send(Messages::WebPageProxy::RectForCharacterRangeCallback(result, EditingRange(notFound, 0), callbackID));
4206        return;
4207    }
4208
4209    ASSERT(range->startContainer());
4210    ASSERT(range->endContainer());
4211
4212    result = frame.view()->contentsToWindow(frame.editor().firstRectForRange(range.get()));
4213
4214    // FIXME: Update actualRange to match the range of first rect.
4215    send(Messages::WebPageProxy::RectForCharacterRangeCallback(result, editingRange, callbackID));
4216}
4217
4218void WebPage::setCompositionAsync(const String& text, Vector<CompositionUnderline> underlines, const EditingRange& selection, const EditingRange& replacementEditingRange)
4219{
4220    Frame& frame = m_page->focusController().focusedOrMainFrame();
4221
4222    if (frame.selection().selection().isContentEditable()) {
4223        RefPtr<Range> replacementRange;
4224        if (replacementEditingRange.location != notFound) {
4225            replacementRange = rangeFromEditingRange(frame, replacementEditingRange);
4226            frame.selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
4227        }
4228
4229        frame.editor().setComposition(text, underlines, selection.location, selection.location + selection.length);
4230    }
4231}
4232
4233void WebPage::confirmCompositionAsync()
4234{
4235    Frame& frame = m_page->focusController().focusedOrMainFrame();
4236    frame.editor().confirmComposition();
4237}
4238
4239#endif // PLATFORM(COCOA)
4240
4241#if PLATFORM(GTK)
4242static Frame* targetFrameForEditing(WebPage* page)
4243{
4244    Frame& targetFrame = page->corePage()->focusController().focusedOrMainFrame();
4245
4246    Editor& editor = targetFrame.editor();
4247    if (!editor.canEdit())
4248        return 0;
4249
4250    if (editor.hasComposition()) {
4251        // We should verify the parent node of this IME composition node are
4252        // editable because JavaScript may delete a parent node of the composition
4253        // node. In this case, WebKit crashes while deleting texts from the parent
4254        // node, which doesn't exist any longer.
4255        if (PassRefPtr<Range> range = editor.compositionRange()) {
4256            Node* node = range->startContainer();
4257            if (!node || !node->isContentEditable())
4258                return 0;
4259        }
4260    }
4261    return &targetFrame;
4262}
4263
4264void WebPage::confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength)
4265{
4266    Frame* targetFrame = targetFrameForEditing(this);
4267    if (!targetFrame) {
4268        send(Messages::WebPageProxy::EditorStateChanged(editorState()));
4269        return;
4270    }
4271
4272    targetFrame->editor().confirmComposition(compositionString);
4273
4274    if (selectionStart == -1) {
4275        send(Messages::WebPageProxy::EditorStateChanged(editorState()));
4276        return;
4277    }
4278
4279    Element* scope = targetFrame->selection().selection().rootEditableElement();
4280    RefPtr<Range> selectionRange = TextIterator::rangeFromLocationAndLength(scope, selectionStart, selectionLength);
4281    ASSERT_WITH_MESSAGE(selectionRange, "Invalid selection: [%lld:%lld] in text of length %d", static_cast<long long>(selectionStart), static_cast<long long>(selectionLength), scope->innerText().length());
4282
4283    if (selectionRange) {
4284        VisibleSelection selection(selectionRange.get(), SEL_DEFAULT_AFFINITY);
4285        targetFrame->selection().setSelection(selection);
4286    }
4287    send(Messages::WebPageProxy::EditorStateChanged(editorState()));
4288}
4289
4290void WebPage::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, uint64_t selectionStart, uint64_t selectionLength, uint64_t replacementStart, uint64_t replacementLength)
4291{
4292    Frame* targetFrame = targetFrameForEditing(this);
4293    if (!targetFrame || !targetFrame->selection().selection().isContentEditable()) {
4294        send(Messages::WebPageProxy::EditorStateChanged(editorState()));
4295        return;
4296    }
4297
4298    if (replacementLength > 0) {
4299        // The layout needs to be uptodate before setting a selection
4300        targetFrame->document()->updateLayout();
4301
4302        Element* scope = targetFrame->selection().selection().rootEditableElement();
4303        RefPtr<Range> replacementRange = TextIterator::rangeFromLocationAndLength(scope, replacementStart, replacementLength);
4304        targetFrame->editor().setIgnoreCompositionSelectionChange(true);
4305        targetFrame->selection().setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
4306        targetFrame->editor().setIgnoreCompositionSelectionChange(false);
4307    }
4308
4309    targetFrame->editor().setComposition(text, underlines, selectionStart, selectionStart + selectionLength);
4310    send(Messages::WebPageProxy::EditorStateChanged(editorState()));
4311}
4312
4313void WebPage::cancelComposition()
4314{
4315    if (Frame* targetFrame = targetFrameForEditing(this))
4316        targetFrame->editor().cancelComposition();
4317    send(Messages::WebPageProxy::EditorStateChanged(editorState()));
4318}
4319#endif
4320
4321void WebPage::didChangeSelection()
4322{
4323#if (PLATFORM(MAC) && USE(ASYNC_NSTEXTINPUTCLIENT))
4324    Frame& frame = m_page->focusController().focusedOrMainFrame();
4325    // Abandon the current inline input session if selection changed for any other reason but an input method direct action.
4326    // FIXME: Many changes that affect composition node do not go through didChangeSelection(). We need to do something when DOM manipulation affects the composition, because otherwise input method's idea about it will be different from Editor's.
4327    // FIXME: We can't cancel composition when selection changes to NoSelection, but we probably should.
4328    if (frame.editor().hasComposition() && !frame.editor().ignoreCompositionSelectionChange() && !frame.selection().isNone()) {
4329        frame.editor().cancelComposition();
4330        send(Messages::WebPageProxy::CompositionWasCanceled(editorState()));
4331    } else
4332#endif
4333        send(Messages::WebPageProxy::EditorStateChanged(editorState()));
4334
4335#if PLATFORM(IOS)
4336    m_drawingArea->scheduleCompositingLayerFlush();
4337#endif
4338}
4339
4340void WebPage::setMinimumLayoutSize(const IntSize& minimumLayoutSize)
4341{
4342    if (m_minimumLayoutSize == minimumLayoutSize)
4343        return;
4344
4345    m_minimumLayoutSize = minimumLayoutSize;
4346    if (minimumLayoutSize.width() <= 0) {
4347        corePage()->mainFrame().view()->enableAutoSizeMode(false, IntSize(), IntSize());
4348        return;
4349    }
4350
4351    int minimumLayoutWidth = minimumLayoutSize.width();
4352    int minimumLayoutHeight = std::max(minimumLayoutSize.height(), 1);
4353
4354    int maximumSize = std::numeric_limits<int>::max();
4355
4356    corePage()->mainFrame().view()->enableAutoSizeMode(true, IntSize(minimumLayoutWidth, minimumLayoutHeight), IntSize(maximumSize, maximumSize));
4357}
4358
4359void WebPage::setAutoSizingShouldExpandToViewHeight(bool shouldExpand)
4360{
4361    if (m_autoSizingShouldExpandToViewHeight == shouldExpand)
4362        return;
4363
4364    m_autoSizingShouldExpandToViewHeight = shouldExpand;
4365
4366    corePage()->mainFrame().view()->setAutoSizeFixedMinimumHeight(shouldExpand ? m_viewSize.height() : 0);
4367}
4368
4369bool WebPage::isSmartInsertDeleteEnabled()
4370{
4371    return m_page->settings().smartInsertDeleteEnabled();
4372}
4373
4374void WebPage::setSmartInsertDeleteEnabled(bool enabled)
4375{
4376    if (m_page->settings().smartInsertDeleteEnabled() != enabled) {
4377        m_page->settings().setSmartInsertDeleteEnabled(enabled);
4378        setSelectTrailingWhitespaceEnabled(!enabled);
4379    }
4380}
4381
4382bool WebPage::isSelectTrailingWhitespaceEnabled()
4383{
4384    return m_page->settings().selectTrailingWhitespaceEnabled();
4385}
4386
4387void WebPage::setSelectTrailingWhitespaceEnabled(bool enabled)
4388{
4389    if (m_page->settings().selectTrailingWhitespaceEnabled() != enabled) {
4390        m_page->settings().setSelectTrailingWhitespaceEnabled(enabled);
4391        setSmartInsertDeleteEnabled(!enabled);
4392    }
4393}
4394
4395bool WebPage::canShowMIMEType(const String& MIMEType) const
4396{
4397    if (MIMETypeRegistry::canShowMIMEType(MIMEType))
4398        return true;
4399
4400    if (m_mimeTypesWithCustomContentProviders.contains(MIMEType))
4401        return true;
4402
4403    const PluginData& pluginData = m_page->pluginData();
4404    if (pluginData.supportsMimeType(MIMEType, PluginData::AllPlugins) && corePage()->mainFrame().loader().subframeLoader().allowPlugins(NotAboutToInstantiatePlugin))
4405        return true;
4406
4407    // We can use application plugins even if plugins aren't enabled.
4408    if (pluginData.supportsMimeType(MIMEType, PluginData::OnlyApplicationPlugins))
4409        return true;
4410
4411    return false;
4412}
4413
4414void WebPage::addTextCheckingRequest(uint64_t requestID, PassRefPtr<TextCheckingRequest> request)
4415{
4416    m_pendingTextCheckingRequestMap.add(requestID, request);
4417}
4418
4419void WebPage::didFinishCheckingText(uint64_t requestID, const Vector<TextCheckingResult>& result)
4420{
4421    RefPtr<TextCheckingRequest> request = m_pendingTextCheckingRequestMap.take(requestID);
4422    if (!request)
4423        return;
4424
4425    request->didSucceed(result);
4426}
4427
4428void WebPage::didCancelCheckingText(uint64_t requestID)
4429{
4430    RefPtr<TextCheckingRequest> request = m_pendingTextCheckingRequestMap.take(requestID);
4431    if (!request)
4432        return;
4433
4434    request->didCancel();
4435}
4436
4437void WebPage::didCommitLoad(WebFrame* frame)
4438{
4439    if (!frame->isMainFrame())
4440        return;
4441
4442    // If previous URL is invalid, then it's not a real page that's being navigated away from.
4443    // Most likely, this is actually the first load to be committed in this page.
4444    if (frame->coreFrame()->loader().previousURL().isValid())
4445        reportUsedFeatures();
4446
4447    // Only restore the scale factor for standard frame loads (of the main frame).
4448    if (frame->coreFrame()->loader().loadType() == FrameLoadType::Standard) {
4449        Page* page = frame->coreFrame()->page();
4450
4451        if (page && page->pageScaleFactor() != 1)
4452            scalePage(1, IntPoint());
4453    }
4454#if PLATFORM(IOS)
4455    m_hasReceivedVisibleContentRectsAfterDidCommitLoad = false;
4456    m_scaleWasSetByUIProcess = false;
4457    m_firstLayerTreeTransactionIDAfterDidCommitLoad = toRemoteLayerTreeDrawingArea(*m_drawingArea).nextTransactionID();
4458    m_userHasChangedPageScaleFactor = false;
4459    m_estimatedLatency = std::chrono::milliseconds(1000 / 60);
4460
4461    WebProcess::shared().eventDispatcher().clearQueuedTouchEventsForPage(*this);
4462
4463    resetViewportDefaultConfiguration(frame);
4464    m_viewportConfiguration.resetMinimalUI();
4465    const Frame* coreFrame = frame->coreFrame();
4466    m_viewportConfiguration.setContentsSize(coreFrame->view()->contentsSize());
4467    m_viewportConfiguration.setViewportArguments(coreFrame->document()->viewportArguments());
4468    viewportConfigurationChanged();
4469#endif
4470
4471#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
4472    resetPrimarySnapshottedPlugIn();
4473#endif
4474
4475    WebProcess::shared().updateActivePages();
4476
4477    updateMainFrameScrollOffsetPinning();
4478}
4479
4480void WebPage::didFinishDocumentLoad(WebFrame* frame)
4481{
4482#if PLATFORM(IOS)
4483    if (!frame->isMainFrame())
4484        return;
4485
4486    m_viewportConfiguration.didFinishDocumentLoad();
4487#else
4488    UNUSED_PARAM(frame);
4489#endif // PLATFORM(IOS)
4490}
4491
4492void WebPage::didFinishLoad(WebFrame* frame)
4493{
4494#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
4495    if (!frame->isMainFrame())
4496        return;
4497
4498    m_readyToFindPrimarySnapshottedPlugin = true;
4499    LOG(Plugins, "Primary Plug-In Detection: triggering detection from didFinishLoad (marking as ready to detect).");
4500    m_determinePrimarySnapshottedPlugInTimer.startOneShot(0);
4501#else
4502    UNUSED_PARAM(frame);
4503#endif
4504}
4505
4506#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
4507static int primarySnapshottedPlugInSearchLimit = 3000;
4508static float primarySnapshottedPlugInSearchBucketSize = 1.1;
4509static int primarySnapshottedPlugInMinimumWidth = 400;
4510static int primarySnapshottedPlugInMinimumHeight = 300;
4511static unsigned maxPrimarySnapshottedPlugInDetectionAttempts = 2;
4512static int deferredPrimarySnapshottedPlugInDetectionDelay = 3;
4513static float overlappingImageBoundsScale = 1.1;
4514static float minimumOverlappingImageToPluginDimensionScale = .9;
4515
4516#if ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
4517void WebPage::determinePrimarySnapshottedPlugInTimerFired()
4518{
4519    if (!m_page)
4520        return;
4521
4522    Settings& settings = m_page->settings();
4523    if (!settings.snapshotAllPlugIns() && settings.primaryPlugInSnapshotDetectionEnabled())
4524        determinePrimarySnapshottedPlugIn();
4525}
4526#endif
4527
4528void WebPage::determinePrimarySnapshottedPlugIn()
4529{
4530    if (!m_page->settings().plugInSnapshottingEnabled())
4531        return;
4532
4533    LOG(Plugins, "Primary Plug-In Detection: began.");
4534
4535    if (!m_readyToFindPrimarySnapshottedPlugin) {
4536        LOG(Plugins, "Primary Plug-In Detection: exiting - not ready to find plugins.");
4537        return;
4538    }
4539
4540    if (!m_hasSeenPlugin) {
4541        LOG(Plugins, "Primary Plug-In Detection: exiting - we never saw a plug-in get added to the page.");
4542        return;
4543    }
4544
4545    if (m_didFindPrimarySnapshottedPlugin) {
4546        LOG(Plugins, "Primary Plug-In Detection: exiting - we've already found a primary plug-in.");
4547        return;
4548    }
4549
4550    ++m_numberOfPrimarySnapshotDetectionAttempts;
4551
4552    MainFrame& mainFrame = corePage()->mainFrame();
4553    if (!mainFrame.view())
4554        return;
4555    if (!mainFrame.view()->renderView())
4556        return;
4557    RenderView& mainRenderView = *mainFrame.view()->renderView();
4558
4559    IntRect searchRect = IntRect(IntPoint(), corePage()->mainFrame().view()->contentsSize());
4560    searchRect.intersect(IntRect(IntPoint(), IntSize(primarySnapshottedPlugInSearchLimit, primarySnapshottedPlugInSearchLimit)));
4561
4562    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::AllowChildFrameContent | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent);
4563
4564    HTMLPlugInImageElement* candidatePlugIn = nullptr;
4565    unsigned candidatePlugInArea = 0;
4566
4567    for (Frame* frame = &mainFrame; frame; frame = frame->tree().traverseNext()) {
4568        if (!frame->loader().subframeLoader().containsPlugins())
4569            continue;
4570        if (!frame->document() || !frame->view())
4571            continue;
4572        for (auto& plugInImageElement : descendantsOfType<HTMLPlugInImageElement>(*frame->document())) {
4573            if (plugInImageElement.displayState() == HTMLPlugInElement::Playing)
4574                continue;
4575
4576            auto pluginRenderer = plugInImageElement.renderer();
4577            if (!pluginRenderer || !pluginRenderer->isBox())
4578                continue;
4579            auto& pluginRenderBox = toRenderBox(*pluginRenderer);
4580            if (!plugInIntersectsSearchRect(plugInImageElement))
4581                continue;
4582
4583            IntRect plugInRectRelativeToView = plugInImageElement.clientRect();
4584            IntSize scrollOffset = mainFrame.view()->documentScrollOffsetRelativeToViewOrigin();
4585            IntRect plugInRectRelativeToTopDocument(plugInRectRelativeToView.location() + scrollOffset, plugInRectRelativeToView.size());
4586            HitTestResult hitTestResult(plugInRectRelativeToTopDocument.center());
4587            mainRenderView.hitTest(request, hitTestResult);
4588
4589            Element* element = hitTestResult.innerElement();
4590            if (!element)
4591                continue;
4592
4593            IntRect elementRectRelativeToView = element->clientRect();
4594            IntRect elementRectRelativeToTopDocument(elementRectRelativeToView.location() + scrollOffset, elementRectRelativeToView.size());
4595            LayoutRect inflatedPluginRect = plugInRectRelativeToTopDocument;
4596            LayoutUnit xOffset = (inflatedPluginRect.width() * overlappingImageBoundsScale - inflatedPluginRect.width()) / 2;
4597            LayoutUnit yOffset = (inflatedPluginRect.height() * overlappingImageBoundsScale - inflatedPluginRect.height()) / 2;
4598            inflatedPluginRect.inflateX(xOffset);
4599            inflatedPluginRect.inflateY(yOffset);
4600
4601            if (element != &plugInImageElement) {
4602                if (!(isHTMLImageElement(element)
4603                    && inflatedPluginRect.contains(elementRectRelativeToTopDocument)
4604                    && elementRectRelativeToTopDocument.width() > pluginRenderBox.width() * minimumOverlappingImageToPluginDimensionScale
4605                    && elementRectRelativeToTopDocument.height() > pluginRenderBox.height() * minimumOverlappingImageToPluginDimensionScale))
4606                    continue;
4607                LOG(Plugins, "Primary Plug-In Detection: Plug-in is hidden by an image that is roughly aligned with it, autoplaying regardless of whether or not it's actually the primary plug-in.");
4608                plugInImageElement.restartSnapshottedPlugIn();
4609            }
4610
4611            if (plugInIsPrimarySize(plugInImageElement, candidatePlugInArea))
4612                candidatePlugIn = &plugInImageElement;
4613        }
4614    }
4615    if (!candidatePlugIn) {
4616        LOG(Plugins, "Primary Plug-In Detection: fail - did not find a candidate plug-in.");
4617        if (m_numberOfPrimarySnapshotDetectionAttempts < maxPrimarySnapshottedPlugInDetectionAttempts) {
4618            LOG(Plugins, "Primary Plug-In Detection: will attempt again in %ds.", deferredPrimarySnapshottedPlugInDetectionDelay);
4619            m_determinePrimarySnapshottedPlugInTimer.startOneShot(deferredPrimarySnapshottedPlugInDetectionDelay);
4620        }
4621        return;
4622    }
4623
4624    LOG(Plugins, "Primary Plug-In Detection: success - found a candidate plug-in - inform it.");
4625    m_didFindPrimarySnapshottedPlugin = true;
4626    m_primaryPlugInPageOrigin = m_page->mainFrame().document()->baseURL().host();
4627    m_primaryPlugInOrigin = candidatePlugIn->loadedUrl().host();
4628    m_primaryPlugInMimeType = candidatePlugIn->loadedMimeType();
4629
4630    candidatePlugIn->setIsPrimarySnapshottedPlugIn(true);
4631}
4632
4633void WebPage::resetPrimarySnapshottedPlugIn()
4634{
4635    m_readyToFindPrimarySnapshottedPlugin = false;
4636    m_didFindPrimarySnapshottedPlugin = false;
4637    m_numberOfPrimarySnapshotDetectionAttempts = 0;
4638    m_hasSeenPlugin = false;
4639}
4640
4641bool WebPage::matchesPrimaryPlugIn(const String& pageOrigin, const String& pluginOrigin, const String& mimeType) const
4642{
4643    if (!m_didFindPrimarySnapshottedPlugin)
4644        return false;
4645
4646    return (pageOrigin == m_primaryPlugInPageOrigin && pluginOrigin == m_primaryPlugInOrigin && mimeType == m_primaryPlugInMimeType);
4647}
4648
4649bool WebPage::plugInIntersectsSearchRect(HTMLPlugInImageElement& plugInImageElement)
4650{
4651    MainFrame& mainFrame = corePage()->mainFrame();
4652    if (!mainFrame.view())
4653        return false;
4654    if (!mainFrame.view()->renderView())
4655        return false;
4656
4657    IntRect searchRect = IntRect(IntPoint(), corePage()->mainFrame().view()->contentsSize());
4658    searchRect.intersect(IntRect(IntPoint(), IntSize(primarySnapshottedPlugInSearchLimit, primarySnapshottedPlugInSearchLimit)));
4659
4660    IntRect plugInRectRelativeToView = plugInImageElement.clientRect();
4661    if (plugInRectRelativeToView.isEmpty())
4662        return false;
4663    IntSize scrollOffset = mainFrame.view()->documentScrollOffsetRelativeToViewOrigin();
4664    IntRect plugInRectRelativeToTopDocument(plugInRectRelativeToView.location() + scrollOffset, plugInRectRelativeToView.size());
4665
4666    return plugInRectRelativeToTopDocument.intersects(searchRect);
4667}
4668
4669bool WebPage::plugInIsPrimarySize(WebCore::HTMLPlugInImageElement& plugInImageElement, unsigned& candidatePlugInArea)
4670{
4671    auto& pluginRenderBox = toRenderBox(*(plugInImageElement.renderer()));
4672    if (pluginRenderBox.contentWidth() < primarySnapshottedPlugInMinimumWidth || pluginRenderBox.contentHeight() < primarySnapshottedPlugInMinimumHeight)
4673        return false;
4674
4675    LayoutUnit contentArea = pluginRenderBox.contentWidth() * pluginRenderBox.contentHeight();
4676    if (contentArea > candidatePlugInArea * primarySnapshottedPlugInSearchBucketSize) {
4677        candidatePlugInArea = contentArea;
4678        return true;
4679    }
4680    return false;
4681}
4682#endif // ENABLE(PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
4683
4684PassRefPtr<Range> WebPage::currentSelectionAsRange()
4685{
4686    Frame* frame = frameWithSelection(m_page.get());
4687    if (!frame)
4688        return 0;
4689
4690    return frame->selection().toNormalizedRange();
4691}
4692
4693void WebPage::reportUsedFeatures()
4694{
4695    Vector<String> namedFeatures;
4696    m_loaderClient.featuresUsedInPage(this, namedFeatures);
4697}
4698
4699unsigned WebPage::extendIncrementalRenderingSuppression()
4700{
4701    unsigned token = m_maximumRenderingSuppressionToken + 1;
4702    while (!HashSet<unsigned>::isValidValue(token) || m_activeRenderingSuppressionTokens.contains(token))
4703        token++;
4704
4705    m_activeRenderingSuppressionTokens.add(token);
4706    m_page->mainFrame().view()->setVisualUpdatesAllowedByClient(false);
4707
4708    m_maximumRenderingSuppressionToken = token;
4709
4710    return token;
4711}
4712
4713void WebPage::stopExtendingIncrementalRenderingSuppression(unsigned token)
4714{
4715    if (!m_activeRenderingSuppressionTokens.remove(token))
4716        return;
4717
4718    m_page->mainFrame().view()->setVisualUpdatesAllowedByClient(!shouldExtendIncrementalRenderingSuppression());
4719}
4720
4721void WebPage::setScrollPinningBehavior(uint32_t pinning)
4722{
4723    m_scrollPinningBehavior = static_cast<ScrollPinningBehavior>(pinning);
4724    m_page->mainFrame().view()->setScrollPinningBehavior(m_scrollPinningBehavior);
4725}
4726
4727PassRefPtr<DocumentLoader> WebPage::createDocumentLoader(Frame& frame, const ResourceRequest& request, const SubstituteData& substituteData)
4728{
4729    RefPtr<WebDocumentLoader> documentLoader = WebDocumentLoader::create(request, substituteData);
4730
4731    if (m_pendingNavigationID && frame.isMainFrame()) {
4732        documentLoader->setNavigationID(m_pendingNavigationID);
4733        m_pendingNavigationID = 0;
4734    }
4735
4736    return documentLoader.release();
4737}
4738
4739void WebPage::getBytecodeProfile(uint64_t callbackID)
4740{
4741    ASSERT(JSDOMWindow::commonVM().m_perBytecodeProfiler);
4742    if (!JSDOMWindow::commonVM().m_perBytecodeProfiler)
4743        send(Messages::WebPageProxy::StringCallback(String(), callbackID));
4744    String result = JSDOMWindow::commonVM().m_perBytecodeProfiler->toJSON();
4745    ASSERT(result.length());
4746    send(Messages::WebPageProxy::StringCallback(result, callbackID));
4747}
4748
4749PassRefPtr<WebCore::Range> WebPage::rangeFromEditingRange(WebCore::Frame& frame, const EditingRange& range)
4750{
4751    ASSERT(range.location != notFound);
4752
4753    // Sanitize the input, because TextIterator::rangeFromLocationAndLength takes signed integers.
4754    if (range.location > INT_MAX)
4755        return 0;
4756    int length;
4757    if (range.length <= INT_MAX && range.location + range.length <= INT_MAX)
4758        length = static_cast<int>(range.length);
4759    else
4760        length = INT_MAX - range.location;
4761
4762    // Our critical assumption is that we are only called by input methods that
4763    // concentrate on a given area containing the selection.
4764    // We have to do this because of text fields and textareas. The DOM for those is not
4765    // directly in the document DOM, so serialization is problematic. Our solution is
4766    // to use the root editable element of the selection start as the positional base.
4767    // That fits with AppKit's idea of an input context.
4768    return TextIterator::rangeFromLocationAndLength(frame.selection().rootEditableElementOrDocumentElement(), static_cast<int>(range.location), length);
4769}
4770
4771bool WebPage::synchronousMessagesShouldSpinRunLoop()
4772{
4773#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000
4774    return WebCore::AXObjectCache::accessibilityEnabled();
4775#endif
4776    return false;
4777}
4778
4779#if ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION)
4780ServicesOverlayController& WebPage::servicesOverlayController()
4781{
4782    if (!m_servicesOverlayController)
4783        m_servicesOverlayController = std::make_unique<ServicesOverlayController>(*this);
4784
4785    return *m_servicesOverlayController;
4786}
4787#endif
4788
4789void WebPage::didChangeScrollOffsetForFrame(Frame* frame)
4790{
4791    m_pageOverlayController.didScrollFrame(frame);
4792
4793    if (!frame->isMainFrame())
4794        return;
4795
4796    // If this is called when tearing down a FrameView, the WebCore::Frame's
4797    // current FrameView will be null.
4798    if (!frame->view())
4799        return;
4800
4801    updateMainFrameScrollOffsetPinning();
4802}
4803
4804void WebPage::willChangeCurrentHistoryItemForMainFrame()
4805{
4806    send(Messages::WebPageProxy::WillChangeCurrentHistoryItemForMainFrame());
4807}
4808
4809} // namespace WebKit
4810