Remote tile layers shouldn't be UIViews
[WebKit-https.git] / Source / WebKit / Shared / RemoteLayerTree / RemoteLayerTreePropertyApplier.mm
1 /*
2  * Copyright (C) 2013 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 "RemoteLayerTreePropertyApplier.h"
28
29 #import "PlatformCAAnimationRemote.h"
30 #import "PlatformCALayerRemote.h"
31 #import "RemoteLayerTreeHost.h"
32 #import <QuartzCore/QuartzCore.h>
33 #import <WebCore/PlatformCAFilters.h>
34 #import <WebCore/ScrollbarThemeMac.h>
35 #import <pal/spi/cocoa/QuartzCoreSPI.h>
36 #import <wtf/BlockObjCExceptions.h>
37
38 #if PLATFORM(IOS_FAMILY)
39 #import <UIKit/UIView.h>
40 #import <UIKitSPI.h>
41 #endif
42
43 #if PLATFORM(IOS_FAMILY)
44 @interface UIView (WKUIViewUtilities)
45 - (void)_web_setSubviews:(NSArray *)subviews;
46 @end
47
48 @implementation UIView (WKUIViewUtilities)
49
50 - (void)_web_setSubviews:(NSArray *)newSubviews
51 {
52     NSUInteger numOldSubviews = self.subviews.count;
53     NSUInteger numNewSubviews = newSubviews.count;
54
55     NSUInteger currIndex = 0;
56     for (currIndex = 0; currIndex < numNewSubviews; ++currIndex) {
57         UIView *currNewSubview = [newSubviews objectAtIndex:currIndex];
58
59         if (currIndex < numOldSubviews) {
60             UIView *existingSubview = [self.subviews objectAtIndex:currIndex];
61             if (existingSubview == currNewSubview)
62                 continue;
63         }
64
65         // New or moved subview.
66         [self insertSubview:currNewSubview atIndex:currIndex];
67     }
68
69     // Remove views at the end.
70     NSUInteger remainingSubviews = self.subviews.count;
71     for (NSUInteger i = currIndex; i < remainingSubviews; ++i)
72         [[self.subviews objectAtIndex:currIndex] removeFromSuperview];
73
74     ASSERT([self.subviews isEqualToArray:newSubviews]);
75 }
76
77 @end
78 #endif
79
80 using namespace WebCore;
81
82 namespace WebKit {
83
84 static CGColorRef cgColorFromColor(const Color& color)
85 {
86     if (!color.isValid())
87         return nil;
88
89     return cachedCGColor(color);
90 }
91
92 static NSString *toCAFilterType(PlatformCALayer::FilterType type)
93 {
94     switch (type) {
95     case PlatformCALayer::Linear:
96         return kCAFilterLinear;
97     case PlatformCALayer::Nearest:
98         return kCAFilterNearest;
99     case PlatformCALayer::Trilinear:
100         return kCAFilterTrilinear;
101     };
102     
103     ASSERT_NOT_REACHED();
104     return 0;
105 }
106
107 static void updateCustomAppearance(CALayer *layer, GraphicsLayer::CustomAppearance customAppearance)
108 {
109 #if ENABLE(RUBBER_BANDING)
110     switch (customAppearance) {
111     case GraphicsLayer::CustomAppearance::None:
112     case GraphicsLayer::CustomAppearance::DarkBackdrop:
113     case GraphicsLayer::CustomAppearance::LightBackdrop:
114         ScrollbarThemeMac::removeOverhangAreaBackground(layer);
115         ScrollbarThemeMac::removeOverhangAreaShadow(layer);
116         break;
117     case GraphicsLayer::CustomAppearance::ScrollingOverhang:
118         ScrollbarThemeMac::setUpOverhangAreaBackground(layer);
119         break;
120     case GraphicsLayer::CustomAppearance::ScrollingShadow:
121         ScrollbarThemeMac::setUpOverhangAreaShadow(layer);
122         break;
123     }
124 #else
125     UNUSED_PARAM(customAppearance);
126 #endif
127 }
128
129 void RemoteLayerTreePropertyApplier::applyPropertiesToLayer(CALayer *layer, RemoteLayerTreeHost* layerTreeHost, const RemoteLayerTreeTransaction::LayerProperties& properties, RemoteLayerBackingStore::LayerContentsType layerContentsType)
130 {
131     if (properties.changedProperties & RemoteLayerTreeTransaction::NameChanged)
132         layer.name = properties.name;
133
134     if (properties.changedProperties & RemoteLayerTreeTransaction::PositionChanged) {
135         layer.position = CGPointMake(properties.position.x(), properties.position.y());
136         layer.zPosition = properties.position.z();
137     }
138
139     if (properties.changedProperties & RemoteLayerTreeTransaction::AnchorPointChanged) {
140         layer.anchorPoint = CGPointMake(properties.anchorPoint.x(), properties.anchorPoint.y());
141         layer.anchorPointZ = properties.anchorPoint.z();
142     }
143
144     if (properties.changedProperties & RemoteLayerTreeTransaction::BoundsChanged)
145         layer.bounds = properties.bounds;
146     
147     if (properties.changedProperties & RemoteLayerTreeTransaction::BackgroundColorChanged)
148         layer.backgroundColor = cgColorFromColor(properties.backgroundColor);
149
150     if (properties.changedProperties & RemoteLayerTreeTransaction::BorderColorChanged)
151         layer.borderColor = cgColorFromColor(properties.borderColor);
152
153     if (properties.changedProperties & RemoteLayerTreeTransaction::BorderWidthChanged)
154         layer.borderWidth = properties.borderWidth;
155
156     if (properties.changedProperties & RemoteLayerTreeTransaction::OpacityChanged)
157         layer.opacity = properties.opacity;
158
159     if (properties.changedProperties & RemoteLayerTreeTransaction::TransformChanged)
160         layer.transform = properties.transform ? (CATransform3D)*properties.transform.get() : CATransform3DIdentity;
161
162     if (properties.changedProperties & RemoteLayerTreeTransaction::SublayerTransformChanged)
163         layer.sublayerTransform = properties.sublayerTransform ? (CATransform3D)*properties.sublayerTransform.get() : CATransform3DIdentity;
164
165     if (properties.changedProperties & RemoteLayerTreeTransaction::HiddenChanged)
166         layer.hidden = properties.hidden;
167
168     if (properties.changedProperties & RemoteLayerTreeTransaction::GeometryFlippedChanged)
169         layer.geometryFlipped = properties.geometryFlipped;
170
171     if (properties.changedProperties & RemoteLayerTreeTransaction::DoubleSidedChanged)
172         layer.doubleSided = properties.doubleSided;
173
174     if (properties.changedProperties & RemoteLayerTreeTransaction::MasksToBoundsChanged)
175         layer.masksToBounds = properties.masksToBounds;
176
177     if (properties.changedProperties & RemoteLayerTreeTransaction::OpaqueChanged)
178         layer.opaque = properties.opaque;
179
180     if (properties.changedProperties & RemoteLayerTreeTransaction::ContentsRectChanged)
181         layer.contentsRect = properties.contentsRect;
182
183     if (properties.changedProperties & RemoteLayerTreeTransaction::ContentsScaleChanged) {
184         layer.contentsScale = properties.contentsScale;
185         layer.rasterizationScale = properties.contentsScale;
186     }
187
188     if (properties.changedProperties & RemoteLayerTreeTransaction::CornerRadiusChanged)
189         layer.cornerRadius = properties.cornerRadius;
190
191     if (properties.changedProperties & RemoteLayerTreeTransaction::ShapeRoundedRectChanged) {
192         Path path;
193         if (properties.shapeRoundedRect)
194             path.addRoundedRect(*properties.shapeRoundedRect);
195         ASSERT([layer isKindOfClass:[CAShapeLayer class]]);
196         [(CAShapeLayer *)layer setPath:path.platformPath()];
197     }
198
199     if (properties.changedProperties & RemoteLayerTreeTransaction::ShapePathChanged) {
200         ASSERT([layer isKindOfClass:[CAShapeLayer class]]);
201         [(CAShapeLayer *)layer setPath:properties.shapePath.platformPath()];
202     }
203
204     if (properties.changedProperties & RemoteLayerTreeTransaction::MinificationFilterChanged)
205         layer.minificationFilter = toCAFilterType(properties.minificationFilter);
206
207     if (properties.changedProperties & RemoteLayerTreeTransaction::MagnificationFilterChanged)
208         layer.magnificationFilter = toCAFilterType(properties.magnificationFilter);
209
210     if (properties.changedProperties & RemoteLayerTreeTransaction::BlendModeChanged)
211         PlatformCAFilters::setBlendingFiltersOnLayer(layer, properties.blendMode);
212
213     if (properties.changedProperties & RemoteLayerTreeTransaction::WindRuleChanged) {
214         ASSERT([layer isKindOfClass:[CAShapeLayer class]]);
215         CAShapeLayer *shapeLayer = (CAShapeLayer *)layer;
216         switch (properties.windRule) {
217         case WindRule::NonZero:
218             shapeLayer.fillRule = @"non-zero";
219             break;
220         case WindRule::EvenOdd:
221             shapeLayer.fillRule = @"even-odd";
222             break;
223         }
224     }
225
226     if (properties.changedProperties & RemoteLayerTreeTransaction::SpeedChanged)
227         layer.speed = properties.speed;
228
229     if (properties.changedProperties & RemoteLayerTreeTransaction::TimeOffsetChanged)
230         layer.timeOffset = properties.timeOffset;
231
232     if (properties.changedProperties & RemoteLayerTreeTransaction::BackingStoreChanged
233         || properties.changedProperties & RemoteLayerTreeTransaction::BackingStoreAttachmentChanged)
234     {
235         RemoteLayerBackingStore* backingStore = properties.backingStore.get();
236         if (backingStore && properties.backingStoreAttached)
237             backingStore->applyBackingStoreToLayer(layer, layerContentsType);
238         else {
239             layer.contents = nil;
240             layer.contentsOpaque = NO;
241         }
242     }
243
244     if (properties.changedProperties & RemoteLayerTreeTransaction::FiltersChanged)
245         PlatformCAFilters::setFiltersOnLayer(layer, properties.filters ? *properties.filters : FilterOperations());
246
247     if (properties.changedProperties & RemoteLayerTreeTransaction::AnimationsChanged)
248         PlatformCAAnimationRemote::updateLayerAnimations(layer, layerTreeHost, properties.addedAnimations, properties.keyPathsOfAnimationsToRemove);
249
250     if (properties.changedProperties & RemoteLayerTreeTransaction::EdgeAntialiasingMaskChanged)
251         layer.edgeAntialiasingMask = properties.edgeAntialiasingMask;
252
253     if (properties.changedProperties & RemoteLayerTreeTransaction::CustomAppearanceChanged)
254         updateCustomAppearance(layer, properties.customAppearance);
255 }
256
257 void RemoteLayerTreePropertyApplier::applyProperties(RemoteLayerTreeNode& node, RemoteLayerTreeHost* layerTreeHost, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers, RemoteLayerBackingStore::LayerContentsType layerContentsType)
258 {
259     BEGIN_BLOCK_OBJC_EXCEPTIONS;
260
261     CALayer *layer = node.layer();
262
263     applyPropertiesToLayer(layer, layerTreeHost, properties, layerContentsType);
264     updateChildren(node, properties, relatedLayers);
265
266 #if PLATFORM(IOS_FAMILY)
267     applyPropertiesToUIView(node.uiView(), properties, relatedLayers);
268 #else
269     if (properties.changedProperties & RemoteLayerTreeTransaction::MaskLayerChanged) {
270         if (!properties.maskLayerID)
271             layer.mask = nullptr;
272         else {
273             CALayer *maskLayer = relatedLayers.get(properties.maskLayerID)->layer();
274             ASSERT(!maskLayer.superlayer);
275             if (!maskLayer.superlayer)
276                 layer.mask = maskLayer;
277         }
278     }
279 #endif
280     END_BLOCK_OBJC_EXCEPTIONS;
281 }
282
283 void RemoteLayerTreePropertyApplier::updateChildren(RemoteLayerTreeNode& node, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers)
284 {
285     if (!properties.changedProperties.contains(RemoteLayerTreeTransaction::ChildrenChanged))
286         return;
287
288 #if PLATFORM(IOS_FAMILY)
289     auto hasViewChildren = [&] {
290         if (node.uiView() && [[node.uiView() subviews] count])
291             return true;
292         return !properties.children.isEmpty() && relatedLayers.get(properties.children.first())->uiView();
293     };
294
295     auto contentView = [&] {
296         if (properties.customAppearance == GraphicsLayer::CustomAppearance::LightBackdrop || properties.customAppearance == GraphicsLayer::CustomAppearance::DarkBackdrop) {
297             // This is a UIBackdropView, which should have children attached to
298             // its content view, not directly on its layers.
299             return [(_UIBackdropView *)node.uiView() contentView];
300         }
301         return node.uiView();
302     };
303
304     if (hasViewChildren()) {
305         ASSERT(node.uiView());
306
307         RetainPtr<NSMutableArray> subviews = adoptNS([[NSMutableArray alloc] initWithCapacity:properties.children.size()]);
308         for (auto& child : properties.children) {
309             auto* childNode = relatedLayers.get(child);
310             ASSERT(childNode->uiView());
311             [subviews addObject:childNode->uiView()];
312         }
313
314         [contentView() _web_setSubviews:subviews.get()];
315         return;
316     }
317 #endif
318
319     RetainPtr<NSMutableArray> sublayers = adoptNS([[NSMutableArray alloc] initWithCapacity:properties.children.size()]);
320     for (auto& child : properties.children) {
321         auto* childNode = relatedLayers.get(child);
322 #if PLATFORM(IOS_FAMILY)
323         ASSERT(!childNode->uiView());
324 #endif
325         [sublayers addObject:childNode->layer()];
326     }
327
328     node.layer().sublayers = sublayers.get();
329 }
330
331 #if PLATFORM(IOS_FAMILY)
332 void RemoteLayerTreePropertyApplier::applyPropertiesToUIView(UIView *view, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers)
333 {
334     if (properties.changedProperties.contains(RemoteLayerTreeTransaction::MaskLayerChanged)) {
335         CALayer *maskOwnerLayer = view.layer;
336
337         if (properties.customAppearance == GraphicsLayer::CustomAppearance::LightBackdrop || properties.customAppearance == GraphicsLayer::CustomAppearance::DarkBackdrop) {
338             // This is a UIBackdropView, which means any mask must be applied to the CABackdropLayer rather
339             // that the view's layer. The backdrop is the first layer child.
340             if (view.layer.sublayers.count && [view.layer.sublayers[0] isKindOfClass:[CABackdropLayer class]])
341                 maskOwnerLayer = view.layer.sublayers[0];
342         }
343
344         if (!properties.maskLayerID)
345             maskOwnerLayer.mask = nullptr;
346         else {
347             UIView *maskView = relatedLayers.get(properties.maskLayerID)->uiView();
348             // FIXME: need to check that the mask view is kept alive.
349             ASSERT(!maskView.layer.superlayer);
350             if (!maskView.layer.superlayer)
351                 maskOwnerLayer.mask = maskView.layer;
352         }
353     }
354
355     if (properties.changedProperties.containsAny({ RemoteLayerTreeTransaction::ContentsHiddenChanged, RemoteLayerTreeTransaction::UserInteractionEnabledChanged }))
356         view.userInteractionEnabled = !properties.contentsHidden && properties.userInteractionEnabled;
357 }
358 #endif
359
360 } // namespace WebKit