2d3cb45633d4170c9d075316e5e3cc44d524c673
[WebKit-https.git] / Source / WebKit2 / Shared / mac / 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/BlockExceptions.h>
34 #import <WebCore/PlatformCAFilters.h>
35 #import <WebCore/QuartzCoreSPI.h>
36 #import <WebCore/ScrollbarThemeMac.h>
37
38 #if PLATFORM(IOS)
39 #import <UIKit/UIView.h>
40 #import <UIKitSPI.h>
41 #endif
42
43 #if PLATFORM(IOS)
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::NoCustomAppearance:
112     case GraphicsLayer::DarkBackdropAppearance:
113     case GraphicsLayer::LightBackdropAppearance:
114         ScrollbarThemeMac::removeOverhangAreaBackground(layer);
115         ScrollbarThemeMac::removeOverhangAreaShadow(layer);
116         break;
117     case GraphicsLayer::ScrollingOverhang:
118         ScrollbarThemeMac::setUpOverhangAreaBackground(layer);
119         break;
120     case GraphicsLayer::ScrollingShadow:
121         ScrollbarThemeMac::setUpOverhangAreaShadow(layer);
122         break;
123     }
124 #else
125     UNUSED_PARAM(customAppearance);
126 #endif
127 }
128
129 static void applyPropertiesToLayer(CALayer *layer, RemoteLayerTreeHost* layerTreeHost, const RemoteLayerTreeTransaction::LayerProperties& properties)
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 RULE_NONZERO:
218             shapeLayer.fillRule = @"non-zero";
219             break;
220         case RULE_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);
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(CALayer *layer, RemoteLayerTreeHost* layerTreeHost, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers)
258 {
259     BEGIN_BLOCK_OBJC_EXCEPTIONS;
260     applyPropertiesToLayer(layer, layerTreeHost, properties);
261
262     if (properties.changedProperties & RemoteLayerTreeTransaction::ChildrenChanged) {
263         RetainPtr<NSMutableArray> children = adoptNS([[NSMutableArray alloc] initWithCapacity:properties.children.size()]);
264         for (auto& child : properties.children) {
265             ASSERT(relatedLayers.get(child));
266             [children addObject:relatedLayers.get(child)];
267         }
268
269         layer.sublayers = children.get();
270     }
271
272     if (properties.changedProperties & RemoteLayerTreeTransaction::MaskLayerChanged) {
273         if (!properties.maskLayerID)
274             layer.mask = nullptr;
275         else {
276 #if PLATFORM(IOS)
277             UIView *maskView = relatedLayers.get(properties.maskLayerID);
278             // FIXME: need to check that the mask view is kept alive.
279             ASSERT(!maskView.layer.superlayer);
280             if (!maskView.layer.superlayer)
281                 layer.mask = maskView.layer;
282 #else
283             CALayer *maskLayer = relatedLayers.get(properties.maskLayerID);
284             ASSERT(!maskLayer.superlayer);
285             if (!maskLayer.superlayer)
286                 layer.mask = maskLayer;
287 #endif
288         }
289     }
290     END_BLOCK_OBJC_EXCEPTIONS;
291 }
292
293 #if PLATFORM(IOS)
294 void RemoteLayerTreePropertyApplier::applyProperties(UIView *view, RemoteLayerTreeHost* layerTreeHost, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers)
295 {
296     BEGIN_BLOCK_OBJC_EXCEPTIONS;
297     applyPropertiesToLayer(view.layer, layerTreeHost, properties);
298
299     if (properties.changedProperties & RemoteLayerTreeTransaction::ChildrenChanged) {
300         RetainPtr<NSMutableArray> children = adoptNS([[NSMutableArray alloc] initWithCapacity:properties.children.size()]);
301         for (auto& child : properties.children) {
302             ASSERT(relatedLayers.get(child));
303             [children addObject:relatedLayers.get(child)];
304         }
305
306         if (properties.customAppearance == GraphicsLayer::LightBackdropAppearance || properties.customAppearance == GraphicsLayer::DarkBackdropAppearance) {
307             // This is a UIBackdropView, which should have children attached to
308             // its content view, not directly on its layers.
309             [[(_UIBackdropView*)view contentView] _web_setSubviews:children.get()];
310         } else
311             [view _web_setSubviews:children.get()];
312     }
313
314     if (properties.changedProperties & RemoteLayerTreeTransaction::MaskLayerChanged) {
315         if (!properties.maskLayerID)
316             view.layer.mask = nullptr;
317         else {
318             UIView *maskView = relatedLayers.get(properties.maskLayerID);
319             // FIXME: need to check that the mask view is kept alive.
320             ASSERT(!maskView.layer.superlayer);
321             if (!maskView.layer.superlayer)
322                 view.layer.mask = maskView.layer;
323         }
324     }
325     END_BLOCK_OBJC_EXCEPTIONS;
326 }
327 #endif
328
329 } // namespace WebKit