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