Unreviewed, fix iOS build with recent SDKs.
[WebKit-https.git] / Source / WebKit / UIProcess / API / Cocoa / _WKThumbnailView.mm
1 /*
2  * Copyright (C) 2014 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 "_WKThumbnailViewInternal.h"
28
29 #if PLATFORM(MAC)
30
31 #import "ImageOptions.h"
32 #import "WKAPICast.h"
33 #import "WKView.h"
34 #import "WKViewInternal.h"
35 #import "WKWebViewInternal.h"
36 #import "WebPageProxy.h"
37
38 // FIXME: Make it possible to leave a snapshot of the content presented in the WKView while the thumbnail is live.
39 // FIXME: Don't make new speculative tiles while thumbnailed.
40 // FIXME: Hide scrollbars in the thumbnail.
41 // FIXME: We should re-use existing tiles for unparented views, if we have them (we need to know if they've been purged; if so, repaint at scaled-down size).
42 // FIXME: We should switch to the low-resolution scale if a view we have high-resolution tiles for repaints.
43
44 @implementation _WKThumbnailView {
45     ALLOW_DEPRECATED_DECLARATIONS_BEGIN
46     RetainPtr<WKView> _wkView;
47     ALLOW_DEPRECATED_DECLARATIONS_END
48     RetainPtr<WKWebView> _wkWebView;
49     WebKit::WebPageProxy* _webPageProxy;
50
51     BOOL _originalMayStartMediaWhenInWindow;
52     BOOL _originalSourceViewIsInWindow;
53
54     BOOL _snapshotWasDeferred;
55     CGFloat _lastSnapshotScale;
56     CGSize _lastSnapshotMaximumSize;
57
58     RetainPtr<NSColor> _overrideBackgroundColor;
59 }
60
61 @synthesize snapshotSize=_snapshotSize;
62 @synthesize _waitingForSnapshot=_waitingForSnapshot;
63 @synthesize exclusivelyUsesSnapshot=_exclusivelyUsesSnapshot;
64 @synthesize shouldKeepSnapshotWhenRemovedFromSuperview=_shouldKeepSnapshotWhenRemovedFromSuperview;
65
66 - (instancetype)initWithFrame:(NSRect)frame
67 {
68     if (!(self = [super initWithFrame:frame]))
69         return nil;
70
71     self.wantsLayer = YES;
72     _scale = 1;
73     _lastSnapshotScale = NAN;
74     
75     return self;
76 }
77
78 ALLOW_DEPRECATED_DECLARATIONS_BEGIN
79 - (instancetype)initWithFrame:(NSRect)frame fromWKView:(WKView *)wkView
80 {
81     if (!(self = [self initWithFrame:frame]))
82         return nil;
83
84     _wkView = wkView;
85     _webPageProxy = WebKit::toImpl([_wkView pageRef]);
86     _originalMayStartMediaWhenInWindow = _webPageProxy->mayStartMediaWhenInWindow();
87     _originalSourceViewIsInWindow = !![_wkView window];
88
89     return self;
90 }
91 ALLOW_DEPRECATED_DECLARATIONS_END
92
93 - (instancetype)initWithFrame:(NSRect)frame fromWKWebView:(WKWebView *)webView
94 {
95     if (!(self = [self initWithFrame:frame]))
96         return nil;
97     
98     _wkWebView = webView;
99     _webPageProxy = [_wkWebView _page];
100     _originalMayStartMediaWhenInWindow = _webPageProxy->mayStartMediaWhenInWindow();
101     _originalSourceViewIsInWindow = !![_wkWebView window];
102     
103     return self;
104 }
105
106 - (BOOL)wantsUpdateLayer
107 {
108     return YES;
109 }
110
111 - (void)updateLayer
112 {
113     [super updateLayer];
114
115     NSColor *backgroundColor = self.overrideBackgroundColor ?: [NSColor quaternaryLabelColor];
116     self.layer.backgroundColor = backgroundColor.CGColor;
117 }
118
119 - (void)requestSnapshot
120 {
121     if (_waitingForSnapshot) {
122         _snapshotWasDeferred = YES;
123         return;
124     }
125
126     _waitingForSnapshot = YES;
127
128     RetainPtr<_WKThumbnailView> thumbnailView = self;
129     WebCore::IntRect snapshotRect(WebCore::IntPoint(), _webPageProxy->viewSize() - WebCore::IntSize(0, _webPageProxy->topContentInset()));
130     WebKit::SnapshotOptions options = WebKit::SnapshotOptionsInViewCoordinates | WebKit::SnapshotOptionsUseScreenColorSpace;
131     WebCore::IntSize bitmapSize = snapshotRect.size();
132     bitmapSize.scale(_scale * _webPageProxy->deviceScaleFactor());
133
134     if (!CGSizeEqualToSize(_maximumSnapshotSize, CGSizeZero)) {
135         double sizeConstraintScale = 1;
136         if (_maximumSnapshotSize.width)
137             sizeConstraintScale = CGFloatMin(sizeConstraintScale, _maximumSnapshotSize.width / bitmapSize.width());
138         if (_maximumSnapshotSize.height)
139             sizeConstraintScale = CGFloatMin(sizeConstraintScale, _maximumSnapshotSize.height / bitmapSize.height());
140         bitmapSize = WebCore::IntSize(CGCeiling(bitmapSize.width() * sizeConstraintScale), CGCeiling(bitmapSize.height() * sizeConstraintScale));
141     }
142
143     _lastSnapshotScale = _scale;
144     _lastSnapshotMaximumSize = _maximumSnapshotSize;
145     _webPageProxy->takeSnapshot(snapshotRect, bitmapSize, options, [thumbnailView](const WebKit::ShareableBitmap::Handle& imageHandle, WebKit::CallbackBase::Error) {
146         auto bitmap = WebKit::ShareableBitmap::create(imageHandle, WebKit::SharedMemory::Protection::ReadOnly);
147         RetainPtr<CGImageRef> cgImage = bitmap ? bitmap->makeCGImage() : nullptr;
148         [thumbnailView _didTakeSnapshot:cgImage.get()];
149     });
150 }
151
152 - (void)setOverrideBackgroundColor:(NSColor *)overrideBackgroundColor
153 {
154     if ([_overrideBackgroundColor isEqual:overrideBackgroundColor])
155         return;
156
157     _overrideBackgroundColor = overrideBackgroundColor;
158     [self setNeedsDisplay:YES];
159 }
160
161 - (NSColor *)overrideBackgroundColor
162 {
163     return _overrideBackgroundColor.get();
164 }
165
166 - (void)_viewWasUnparented
167 {
168     if (!_exclusivelyUsesSnapshot) {
169         if (_wkView) {
170             [_wkView _setThumbnailView:nil];
171             [_wkView _setIgnoresAllEvents:NO];
172         } else {
173             ASSERT(_wkWebView);
174             [_wkWebView _setThumbnailView:nil];
175             [_wkWebView _setIgnoresAllEvents:NO];
176         }
177         _webPageProxy->setMayStartMediaWhenInWindow(_originalMayStartMediaWhenInWindow);
178     }
179
180     if (_shouldKeepSnapshotWhenRemovedFromSuperview)
181         return;
182
183     self.layer.contents = nil;
184     _lastSnapshotScale = NAN;
185 }
186
187 - (void)_viewWasParented
188 {
189     if (_wkView && [_wkView _thumbnailView])
190         return;
191     if (_wkWebView && [_wkWebView _thumbnailView])
192         return;
193
194     if (!_exclusivelyUsesSnapshot && !_originalSourceViewIsInWindow)
195         _webPageProxy->setMayStartMediaWhenInWindow(false);
196
197     [self _requestSnapshotIfNeeded];
198
199     if (!_exclusivelyUsesSnapshot) {
200         if (_wkView) {
201             [_wkView _setThumbnailView:self];
202             [_wkView _setIgnoresAllEvents:YES];
203         } else {
204             ASSERT(_wkWebView);
205             [_wkWebView _setThumbnailView:self];
206             [_wkWebView _setIgnoresAllEvents:YES];
207         }
208     }
209 }
210
211 - (void)_requestSnapshotIfNeeded
212 {
213     if (self.layer.contents && _lastSnapshotScale == _scale && CGSizeEqualToSize(_lastSnapshotMaximumSize, _maximumSnapshotSize))
214         return;
215
216     [self requestSnapshot];
217 }
218
219 - (void)_didTakeSnapshot:(CGImageRef)image
220 {
221     [self willChangeValueForKey:@"snapshotSize"];
222
223     _snapshotSize = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
224     _waitingForSnapshot = NO;
225     self.layer.sublayers = @[];
226     self.layer.contentsGravity = kCAGravityResizeAspectFill;
227     self.layer.contents = (__bridge id)image;
228
229     // If we got a scale change while snapshotting, we'll take another snapshot once the first one returns.
230     if (_snapshotWasDeferred) {
231         _snapshotWasDeferred = NO;
232         [self _requestSnapshotIfNeeded];
233     }
234
235     [self didChangeValueForKey:@"snapshotSize"];
236 }
237
238 - (void)viewDidMoveToWindow
239 {
240     if (self.window)
241         [self _viewWasParented];
242     else
243         [self _viewWasUnparented];
244 }
245
246 - (void)setScale:(CGFloat)scale
247 {
248     if (_scale == scale)
249         return;
250
251     _scale = scale;
252
253     [self _requestSnapshotIfNeeded];
254
255     self.layer.sublayerTransform = CATransform3DMakeScale(_scale, _scale, 1);
256 }
257
258 - (void)setMaximumSnapshotSize:(CGSize)maximumSnapshotSize
259 {
260     if (CGSizeEqualToSize(_maximumSnapshotSize, maximumSnapshotSize))
261         return;
262
263     _maximumSnapshotSize = maximumSnapshotSize;
264
265     [self _requestSnapshotIfNeeded];
266 }
267
268 // This should be removed when all clients go away; it is always YES now.
269 - (void)setUsesSnapshot:(BOOL)usesSnapshot
270 {
271 }
272
273 - (BOOL)usesSnapshot
274 {
275     return YES;
276 }
277
278 - (void)_setThumbnailLayer:(CALayer *)layer
279 {
280     self.layer.sublayers = layer ? @[ layer ] : @[ ];
281 }
282
283 - (CALayer *)_thumbnailLayer
284 {
285     if (!self.layer.sublayers.count)
286         return nil;
287
288     return [self.layer.sublayers objectAtIndex:0];
289 }
290
291 @end
292
293 #endif // PLATFORM(MAC)