8d0b9089c83356fb14d7a6fc7b626313add2035c
[WebKit-https.git] / Source / WebKit2 / UIProcess / ios / WKContentView.mm
1 /*
2  * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "WKContentViewInteraction.h"
28
29 #if PLATFORM(IOS)
30
31 #import "APIPageConfiguration.h"
32 #import "AccessibilityIOS.h"
33 #import "ApplicationStateTracker.h"
34 #import "PageClientImplIOS.h"
35 #import "PrintInfo.h"
36 #import "RemoteLayerTreeDrawingAreaProxy.h"
37 #import "RemoteScrollingCoordinatorProxy.h"
38 #import "SmartMagnificationController.h"
39 #import "UIKitSPI.h"
40 #import "WKBrowsingContextControllerInternal.h"
41 #import "WKBrowsingContextGroupPrivate.h"
42 #import "WKInspectorHighlightView.h"
43 #import "WKPreferencesInternal.h"
44 #import "WKProcessGroupPrivate.h"
45 #import "WKWebViewConfiguration.h"
46 #import "WKWebViewInternal.h"
47 #import "WebFrameProxy.h"
48 #import "WebKit2Initialize.h"
49 #import "WebPageGroup.h"
50 #import "WebProcessPool.h"
51 #import "WebSystemInterface.h"
52 #import "_WKFrameHandleInternal.h"
53 #import "_WKWebViewPrintFormatterInternal.h"
54 #import <CoreGraphics/CoreGraphics.h>
55 #import <WebCore/FloatQuad.h>
56 #import <WebCore/FrameView.h>
57 #import <WebCore/InspectorOverlay.h>
58 #import <WebCore/NotImplemented.h>
59 #import <WebCore/PlatformScreen.h>
60 #import <WebCore/QuartzCoreSPI.h>
61 #import <wtf/CurrentTime.h>
62 #import <wtf/RetainPtr.h>
63
64 using namespace WebCore;
65 using namespace WebKit;
66
67 namespace WebKit {
68 class HistoricalVelocityData {
69 public:
70     struct VelocityData {
71         VelocityData()
72             : horizontalVelocity(0)
73             , verticalVelocity(0)
74             , scaleChangeRate(0)
75         {
76         }
77
78         VelocityData(double horizontalVelocity, double verticalVelocity, double scaleChangeRate)
79             : horizontalVelocity(horizontalVelocity)
80             , verticalVelocity(verticalVelocity)
81             , scaleChangeRate(scaleChangeRate)
82         {
83         }
84
85         double horizontalVelocity;
86         double verticalVelocity;
87         double scaleChangeRate;
88     };
89
90     HistoricalVelocityData()
91         : m_historySize(0)
92         , m_latestDataIndex(0)
93         , m_lastAppendTimestamp(0)
94     {
95     }
96
97     VelocityData velocityForNewData(CGPoint newPosition, double scale, double timestamp)
98     {
99         // Due to all the source of rect update, the input is very noisy. To smooth the output, we accumulate all changes
100         // within 1 frame as a single update. No speed computation is ever done on data within the same frame.
101         const double filteringThreshold = 1 / 60.;
102
103         VelocityData velocityData;
104         if (m_historySize > 0) {
105             unsigned oldestDataIndex;
106             unsigned distanceToLastHistoricalData = m_historySize - 1;
107             if (distanceToLastHistoricalData <= m_latestDataIndex)
108                 oldestDataIndex = m_latestDataIndex - distanceToLastHistoricalData;
109             else
110                 oldestDataIndex = m_historySize - (distanceToLastHistoricalData - m_latestDataIndex);
111
112             double timeDelta = timestamp - m_history[oldestDataIndex].timestamp;
113             if (timeDelta > filteringThreshold) {
114                 Data& oldestData = m_history[oldestDataIndex];
115                 velocityData = VelocityData((newPosition.x - oldestData.position.x) / timeDelta, (newPosition.y - oldestData.position.y) / timeDelta, (scale - oldestData.scale) / timeDelta);
116             }
117         }
118
119         double timeSinceLastAppend = timestamp - m_lastAppendTimestamp;
120         if (timeSinceLastAppend > filteringThreshold)
121             append(newPosition, scale, timestamp);
122         else
123             m_history[m_latestDataIndex] = { timestamp, newPosition, scale };
124         return velocityData;
125     }
126
127     void clear() { m_historySize = 0; }
128
129 private:
130     void append(CGPoint newPosition, double scale, double timestamp)
131     {
132         m_latestDataIndex = (m_latestDataIndex + 1) % maxHistoryDepth;
133         m_history[m_latestDataIndex] = { timestamp, newPosition, scale };
134
135         unsigned size = m_historySize + 1;
136         if (size <= maxHistoryDepth)
137             m_historySize = size;
138
139         m_lastAppendTimestamp = timestamp;
140     }
141
142
143     static const unsigned maxHistoryDepth = 3;
144
145     unsigned m_historySize;
146     unsigned m_latestDataIndex;
147     double m_lastAppendTimestamp;
148
149     struct Data {
150         double timestamp;
151         CGPoint position;
152         double scale;
153     } m_history[maxHistoryDepth];
154 };
155 } // namespace WebKit
156
157 @interface WKInspectorIndicationView : UIView
158 @end
159
160 @implementation WKInspectorIndicationView
161
162 - (instancetype)initWithFrame:(CGRect)frame
163 {
164     if (!(self = [super initWithFrame:frame]))
165         return nil;
166     self.userInteractionEnabled = NO;
167     self.backgroundColor = [UIColor colorWithRed:(111.0 / 255.0) green:(168.0 / 255.0) blue:(220.0 / 255.0) alpha:0.66f];
168     return self;
169 }
170
171 @end
172
173 @implementation WKContentView {
174     std::unique_ptr<PageClientImpl> _pageClient;
175     RetainPtr<WKBrowsingContextController> _browsingContextController;
176
177     RetainPtr<UIView> _rootContentView;
178     RetainPtr<UIView> _fixedClippingView;
179     RetainPtr<WKInspectorIndicationView> _inspectorIndicationView;
180     RetainPtr<WKInspectorHighlightView> _inspectorHighlightView;
181
182     HistoricalVelocityData _historicalKinematicData;
183
184     RetainPtr<NSUndoManager> _undoManager;
185
186     std::unique_ptr<ApplicationStateTracker> _applicationStateTracker;
187
188     BOOL _isPrintingToPDF;
189     RetainPtr<CGPDFDocumentRef> _printedDocument;
190 }
191
192 - (instancetype)_commonInitializationWithProcessPool:(WebKit::WebProcessPool&)processPool configuration:(Ref<API::PageConfiguration>&&)configuration
193 {
194     ASSERT(_pageClient);
195
196     _page = processPool.createWebPage(*_pageClient, WTFMove(configuration));
197     _page->initializeWebPage();
198     _page->setIntrinsicDeviceScaleFactor(screenScaleFactor([UIScreen mainScreen]));
199     _page->setUseFixedLayout(true);
200     _page->setDelegatesScrolling(true);
201
202     WebProcessPool::statistics().wkViewCount++;
203
204     _rootContentView = adoptNS([[UIView alloc] init]);
205     [_rootContentView layer].masksToBounds = NO;
206     [_rootContentView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
207
208     _fixedClippingView = adoptNS([[UIView alloc] init]);
209     [_fixedClippingView layer].masksToBounds = YES;
210     [_fixedClippingView layer].anchorPoint = CGPointZero;
211 #ifndef NDEBUG
212     [[_fixedClippingView layer] setName:@"Fixed clipping"];
213 #endif
214
215     [self addSubview:_fixedClippingView.get()];
216     [_fixedClippingView addSubview:_rootContentView.get()];
217
218     [self setupInteraction];
219     [self setUserInteractionEnabled:YES];
220
221     self.layer.hitTestsAsOpaque = YES;
222
223     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:[UIApplication sharedApplication]];
224     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:[UIApplication sharedApplication]];
225
226     return self;
227 }
228
229 - (instancetype)initWithFrame:(CGRect)frame processPool:(WebKit::WebProcessPool&)processPool configuration:(Ref<API::PageConfiguration>&&)configuration webView:(WKWebView *)webView
230 {
231     if (!(self = [super initWithFrame:frame]))
232         return nil;
233
234     InitializeWebKit2();
235
236     _pageClient = std::make_unique<PageClientImpl>(self, webView);
237     _webView = webView;
238
239     return [self _commonInitializationWithProcessPool:processPool configuration:WTFMove(configuration)];
240 }
241
242 - (void)dealloc
243 {
244     [self cleanupInteraction];
245
246     [[NSNotificationCenter defaultCenter] removeObserver:self];
247
248     _page->close();
249
250     WebProcessPool::statistics().wkViewCount--;
251
252     [super dealloc];
253 }
254
255 - (WebPageProxy*)page
256 {
257     return _page.get();
258 }
259
260 - (void)willMoveToWindow:(UIWindow *)newWindow
261 {
262     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
263     UIWindow *window = self.window;
264
265     if (window) {
266         [defaultCenter removeObserver:self name:UIWindowDidMoveToScreenNotification object:window];
267
268         if (!newWindow) {
269             ASSERT(_applicationStateTracker);
270             _applicationStateTracker = nullptr;
271         }
272     }
273
274     if (newWindow) {
275         [defaultCenter addObserver:self selector:@selector(_windowDidMoveToScreenNotification:) name:UIWindowDidMoveToScreenNotification object:newWindow];
276
277         [self _updateForScreen:newWindow.screen];
278     }
279 }
280
281 - (void)didMoveToWindow
282 {
283     if (!self.window)
284         return;
285
286     ASSERT(!_applicationStateTracker);
287     _applicationStateTracker = std::make_unique<ApplicationStateTracker>(self, @selector(_applicationDidEnterBackground), @selector(_applicationDidCreateWindowContext), @selector(_applicationDidFinishSnapshottingAfterEnteringBackground), @selector(_applicationWillEnterForeground));
288 }
289
290 - (WKBrowsingContextController *)browsingContextController
291 {
292     if (!_browsingContextController)
293         _browsingContextController = adoptNS([[WKBrowsingContextController alloc] _initWithPageRef:toAPI(_page.get())]);
294
295     return _browsingContextController.get();
296 }
297
298 - (WKPageRef)_pageRef
299 {
300     return toAPI(_page.get());
301 }
302
303 - (BOOL)isAssistingNode
304 {
305     return [self isEditable];
306 }
307
308 - (BOOL)isBackground
309 {
310     if (!_applicationStateTracker)
311         return YES;
312
313     return _applicationStateTracker->isInBackground();
314 }
315
316 - (void)_showInspectorHighlight:(const WebCore::Highlight&)highlight
317 {
318     if (!_inspectorHighlightView) {
319         _inspectorHighlightView = adoptNS([[WKInspectorHighlightView alloc] initWithFrame:CGRectZero]);
320         [self insertSubview:_inspectorHighlightView.get() aboveSubview:_rootContentView.get()];
321     }
322
323     [_inspectorHighlightView update:highlight];
324 }
325
326 - (void)_hideInspectorHighlight
327 {
328     if (_inspectorHighlightView) {
329         [_inspectorHighlightView removeFromSuperview];
330         _inspectorHighlightView = nil;
331     }
332 }
333
334 - (BOOL)isShowingInspectorIndication
335 {
336     return !!_inspectorIndicationView;
337 }
338
339 - (void)setShowingInspectorIndication:(BOOL)show
340 {
341     if (show) {
342         if (!_inspectorIndicationView) {
343             _inspectorIndicationView = adoptNS([[WKInspectorIndicationView alloc] initWithFrame:[self bounds]]);
344             [_inspectorIndicationView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
345             [self insertSubview:_inspectorIndicationView.get() aboveSubview:_rootContentView.get()];
346         }
347     } else {
348         if (_inspectorIndicationView) {
349             [_inspectorIndicationView removeFromSuperview];
350             _inspectorIndicationView = nil;
351         }
352     }
353 }
354
355 - (void)updateFixedClippingView:(FloatRect)fixedPositionRectForUI
356 {
357     FloatRect clippingBounds = [self bounds];
358     clippingBounds.unite(fixedPositionRectForUI);
359
360     [_fixedClippingView setCenter:clippingBounds.location()]; // Not really the center since we set an anchor point.
361     [_fixedClippingView setBounds:clippingBounds];
362 }
363
364 - (void)didUpdateVisibleRect:(CGRect)visibleRect unobscuredRect:(CGRect)unobscuredRect unobscuredRectInScrollViewCoordinates:(CGRect)unobscuredRectInScrollViewCoordinates
365     obscuredInset:(CGSize)obscuredInset scale:(CGFloat)zoomScale minimumScale:(CGFloat)minimumScale inStableState:(BOOL)isStableState isChangingObscuredInsetsInteractively:(BOOL)isChangingObscuredInsetsInteractively enclosedInScrollableAncestorView:(BOOL)enclosedInScrollableAncestorView
366 {
367     auto drawingArea = _page->drawingArea();
368     if (!drawingArea)
369         return;
370
371     double timestamp = monotonicallyIncreasingTime();
372     HistoricalVelocityData::VelocityData velocityData;
373     if (!isStableState)
374         velocityData = _historicalKinematicData.velocityForNewData(visibleRect.origin, zoomScale, timestamp);
375     else
376         _historicalKinematicData.clear();
377
378     FloatRect fixedPositionRectForLayout = _page->computeCustomFixedPositionRect(unobscuredRect, zoomScale, WebPageProxy::UnobscuredRectConstraint::ConstrainedToDocumentRect);
379
380     VisibleContentRectUpdateInfo visibleContentRectUpdateInfo(
381         visibleRect,
382         unobscuredRect,
383         unobscuredRectInScrollViewCoordinates,
384         fixedPositionRectForLayout,
385         WebCore::FloatSize(obscuredInset),
386         zoomScale,
387         isStableState,
388         isChangingObscuredInsetsInteractively,
389         _webView._allowsViewportShrinkToFit,
390         enclosedInScrollableAncestorView,
391         timestamp,
392         velocityData.horizontalVelocity,
393         velocityData.verticalVelocity,
394         velocityData.scaleChangeRate,
395         downcast<RemoteLayerTreeDrawingAreaProxy>(*drawingArea).lastCommittedLayerTreeTransactionID());
396
397     _page->updateVisibleContentRects(visibleContentRectUpdateInfo);
398
399     RemoteScrollingCoordinatorProxy* scrollingCoordinator = _page->scrollingCoordinatorProxy();
400     FloatRect fixedPositionRect = _page->computeCustomFixedPositionRect(_page->unobscuredContentRect(), zoomScale);
401     scrollingCoordinator->viewportChangedViaDelegatedScrolling(scrollingCoordinator->rootScrollingNodeID(), fixedPositionRect, zoomScale);
402
403     drawingArea->updateDebugIndicator();
404     
405     [self updateFixedClippingView:fixedPositionRect];
406 }
407
408 - (void)didFinishScrolling
409 {
410     [self _didEndScrollingOrZooming];
411 }
412
413 - (void)didInterruptScrolling
414 {
415     _historicalKinematicData.clear();
416 }
417
418 - (void)willStartZoomOrScroll
419 {
420     [self _willStartScrollingOrZooming];
421 }
422
423 - (void)didZoomToScale:(CGFloat)scale
424 {
425     [self _didEndScrollingOrZooming];
426 }
427
428 - (NSUndoManager *)undoManager
429 {
430     if (!_undoManager)
431         _undoManager = adoptNS([[NSUndoManager alloc] init]);
432
433     return _undoManager.get();
434 }
435
436 #pragma mark Internal
437
438 - (void)_windowDidMoveToScreenNotification:(NSNotification *)notification
439 {
440     ASSERT(notification.object == self.window);
441
442     UIScreen *screen = notification.userInfo[UIWindowNewScreenUserInfoKey];
443     [self _updateForScreen:screen];
444 }
445
446 - (void)_updateForScreen:(UIScreen *)screen
447 {
448     ASSERT(screen);
449     _page->setIntrinsicDeviceScaleFactor(screenScaleFactor(screen));
450     [self _accessibilityRegisterUIProcessTokens];
451 }
452
453 - (void)_setAccessibilityWebProcessToken:(NSData *)data
454 {
455     // This means the web process has checked in and we should send information back to that process.
456     [self _accessibilityRegisterUIProcessTokens];
457 }
458
459 static void storeAccessibilityRemoteConnectionInformation(id element, pid_t pid, mach_port_t sendPort, NSUUID *uuid)
460 {
461     // The accessibility bundle needs to know the uuid, pid and mach_port that this object will refer to.
462     objc_setAssociatedObject(element, (void*)[@"ax-uuid" hash], uuid, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
463     objc_setAssociatedObject(element, (void*)[@"ax-pid" hash], @(pid), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
464     objc_setAssociatedObject(element, (void*)[@"ax-machport" hash], @(sendPort), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
465 }
466
467 - (void)_accessibilityRegisterUIProcessTokens
468 {
469     auto uuid = [NSUUID UUID];
470     NSData *remoteElementToken = newAccessibilityRemoteToken(uuid);
471
472     // Store information about the WebProcess that can later be retrieved by the iOS Accessibility runtime.
473     if (_page->process().state() == WebProcessProxy::State::Running) {
474         IPC::Connection* connection = _page->process().connection();
475         storeAccessibilityRemoteConnectionInformation(self, _page->process().processIdentifier(), connection->identifier().port, uuid);
476
477         IPC::DataReference elementToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteElementToken bytes]), [remoteElementToken length]);
478         _page->registerUIProcessAccessibilityTokens(elementToken, elementToken);
479     }
480 }
481
482 - (void)_webViewDestroyed
483 {
484     _webView = nil;
485 }
486
487 #pragma mark PageClientImpl methods
488
489 - (std::unique_ptr<DrawingAreaProxy>)_createDrawingAreaProxy
490 {
491     return std::make_unique<RemoteLayerTreeDrawingAreaProxy>(*_page);
492 }
493
494 - (void)_processDidExit
495 {
496     [self cleanupInteraction];
497
498     [self setShowingInspectorIndication:NO];
499     [self _hideInspectorHighlight];
500 }
501
502 - (void)_didRelaunchProcess
503 {
504     [self _accessibilityRegisterUIProcessTokens];
505     [self setupInteraction];
506 }
507
508 - (void)_didCommitLoadForMainFrame
509 {
510     [self _stopAssistingNode];
511     [self _cancelLongPressGestureRecognizer];
512     [_webView _didCommitLoadForMainFrame];
513 }
514
515 - (void)_didCommitLayerTree:(const WebKit::RemoteLayerTreeTransaction&)layerTreeTransaction
516 {
517     CGSize contentsSize = layerTreeTransaction.contentsSize();
518     CGPoint scrollOrigin = -layerTreeTransaction.scrollOrigin();
519     CGRect contentBounds = { scrollOrigin, contentsSize };
520
521     BOOL boundsChanged = !CGRectEqualToRect([self bounds], contentBounds);
522     if (boundsChanged)
523         [self setBounds:contentBounds];
524
525     [_webView _didCommitLayerTree:layerTreeTransaction];
526
527     if (_interactionViewsContainerView) {
528         FloatPoint scaledOrigin = layerTreeTransaction.scrollOrigin();
529         float scale = [[_webView scrollView] zoomScale];
530         scaledOrigin.scale(scale, scale);
531         [_interactionViewsContainerView setFrame:CGRectMake(scaledOrigin.x(), scaledOrigin.y(), 0, 0)];
532     }
533     
534     if (boundsChanged) {
535         FloatRect fixedPositionRect = _page->computeCustomFixedPositionRect(_page->unobscuredContentRect(), [[_webView scrollView] zoomScale]);
536         [self updateFixedClippingView:fixedPositionRect];
537
538         // We need to push the new content bounds to the webview to update fixed position rects.
539         [_webView _updateVisibleContentRects];
540     }
541     
542     // Updating the selection requires a full editor state. If the editor state is missing post layout
543     // data then it means there is a layout pending and we're going to be called again after the layout
544     // so we delay the selection update.
545     if (!_page->editorState().isMissingPostLayoutData)
546         [self _updateChangedSelection];
547 }
548
549 - (void)_layerTreeCommitComplete
550 {
551     [_webView _layerTreeCommitComplete];
552 }
553
554 - (void)_setAcceleratedCompositingRootView:(UIView *)rootView
555 {
556     for (UIView* subview in [_rootContentView subviews])
557         [subview removeFromSuperview];
558
559     [_rootContentView addSubview:rootView];
560 }
561
562 - (BOOL)_scrollToRect:(CGRect)targetRect withOrigin:(CGPoint)origin minimumScrollDistance:(CGFloat)minimumScrollDistance
563 {
564     return [_webView _scrollToRect:targetRect origin:origin minimumScrollDistance:minimumScrollDistance];
565 }
566
567 - (void)_zoomToFocusRect:(CGRect)rectToFocus selectionRect:(CGRect)selectionRect fontSize:(float)fontSize minimumScale:(double)minimumScale maximumScale:(double)maximumScale allowScaling:(BOOL)allowScaling forceScroll:(BOOL)forceScroll
568 {
569     [_webView _zoomToFocusRect:rectToFocus
570                  selectionRect:selectionRect
571                       fontSize:fontSize
572                   minimumScale:minimumScale
573                   maximumScale:maximumScale
574               allowScaling:allowScaling
575                    forceScroll:forceScroll];
576 }
577
578 - (BOOL)_zoomToRect:(CGRect)targetRect withOrigin:(CGPoint)origin fitEntireRect:(BOOL)fitEntireRect minimumScale:(double)minimumScale maximumScale:(double)maximumScale minimumScrollDistance:(CGFloat)minimumScrollDistance
579 {
580     return [_webView _zoomToRect:targetRect withOrigin:origin fitEntireRect:fitEntireRect minimumScale:minimumScale maximumScale:maximumScale minimumScrollDistance:minimumScrollDistance];
581 }
582
583 - (void)_zoomOutWithOrigin:(CGPoint)origin
584 {
585     return [_webView _zoomOutWithOrigin:origin animated:YES];
586 }
587
588 - (void)_zoomToInitialScaleWithOrigin:(CGPoint)origin
589 {
590     return [_webView _zoomToInitialScaleWithOrigin:origin animated:YES];
591 }
592
593 - (void)_applicationWillResignActive:(NSNotification*)notification
594 {
595     _page->applicationWillResignActive();
596 }
597
598 - (void)_applicationDidEnterBackground
599 {
600     _page->applicationDidEnterBackground();
601     _page->viewStateDidChange(ViewState::AllFlags & ~ViewState::IsInWindow);
602 }
603
604 - (void)_applicationDidCreateWindowContext
605 {
606     if (auto drawingArea = _page->drawingArea())
607         drawingArea->hideContentUntilAnyUpdate();
608 }
609
610 - (void)_applicationDidFinishSnapshottingAfterEnteringBackground
611 {
612     _page->applicationDidFinishSnapshottingAfterEnteringBackground();
613 }
614
615 - (void)_applicationWillEnterForeground
616 {
617     _page->applicationWillEnterForeground();
618     _page->viewStateDidChange(ViewState::AllFlags & ~ViewState::IsInWindow, true, WebPageProxy::ViewStateChangeDispatchMode::Immediate);
619 }
620
621 - (void)_applicationDidBecomeActive:(NSNotification*)notification
622 {
623     _page->applicationDidBecomeActive();
624 }
625
626 @end
627
628 #pragma mark Printing
629
630 @interface WKContentView (_WKWebViewPrintFormatter) <_WKWebViewPrintProvider>
631 @end
632
633 @implementation WKContentView (_WKWebViewPrintFormatter)
634
635 - (NSUInteger)_wk_pageCountForPrintFormatter:(_WKWebViewPrintFormatter *)printFormatter
636 {
637     if (_isPrintingToPDF)
638         return 0;
639
640     uint64_t frameID;
641     if (_WKFrameHandle *handle = printFormatter.frameToPrint)
642         frameID = handle._frameID;
643     else if (auto mainFrame = _page->mainFrame())
644         frameID = mainFrame->frameID();
645     else
646         return 0;
647
648     // The first page can have a smaller content rect than subsequent pages if a top content inset
649     // is specified. Since WebKit requires a uniform content rect for each page during layout, use
650     // the intersection of the first and non-first page rects.
651     // FIXME: Teach WebCore::PrintContext to accept an initial content offset when paginating.
652     CGRect printingRect = CGRectIntersection([printFormatter _pageContentRect:YES], [printFormatter _pageContentRect:NO]);
653     if (CGRectIsEmpty(printingRect))
654         return 0;
655
656     PrintInfo printInfo;
657     printInfo.pageSetupScaleFactor = 1;
658     printInfo.availablePaperWidth = CGRectGetWidth(printingRect);
659     printInfo.availablePaperHeight = CGRectGetHeight(printingRect);
660
661     _isPrintingToPDF = YES;
662     auto retainedSelf = retainPtr(self);
663     return _page->computePagesForPrintingAndDrawToPDF(frameID, printInfo, [retainedSelf](const IPC::DataReference& pdfData, CallbackBase::Error error) {
664         retainedSelf->_isPrintingToPDF = NO;
665         if (error != CallbackBase::Error::None)
666             return;
667
668         auto data = adoptCF(CFDataCreate(kCFAllocatorDefault, pdfData.data(), pdfData.size()));
669         auto dataProvider = adoptCF(CGDataProviderCreateWithCFData(data.get()));
670         retainedSelf->_printedDocument = adoptCF(CGPDFDocumentCreateWithProvider(dataProvider.get()));
671     });
672 }
673
674 - (CGPDFDocumentRef)_wk_printedDocument
675 {
676     if (_isPrintingToPDF) {
677         if (!_page->process().connection()->waitForAndDispatchImmediately<Messages::WebPageProxy::DrawToPDFCallback>(_page->pageID(), std::chrono::milliseconds::max())) {
678             ASSERT_NOT_REACHED();
679             return nullptr;
680         }
681         ASSERT(!_isPrintingToPDF);
682     }
683
684     return _printedDocument.autorelease();
685 }
686
687 @end
688
689 #endif // PLATFORM(IOS)