[iOS][WebKit2] Mark layer contents as being opaque if they are
[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 "PlatformCALayerRemote.h"
30 #import <QuartzCore/CALayer.h>
31 #import <WebCore/BlockExceptions.h>
32 #import <WebCore/PlatformCAFilters.h>
33 #import <WebCore/ScrollbarThemeMac.h>
34
35 #if PLATFORM(IOS)
36 #import <UIKit/UIView.h>
37 #endif
38
39 #if __has_include(<QuartzCore/CALayerPrivate.h>)
40 #import <QuartzCore/CALayerPrivate.h>
41 #endif
42
43 @interface CALayer (Details)
44 @property BOOL contentsOpaque;
45 @end
46
47 #if PLATFORM(IOS)
48 @interface UIView (WKUIViewUtilities)
49 - (void)_web_setSubviews:(NSArray *)subviews;
50 @end
51
52 @implementation UIView (WKUIViewUtilities)
53
54 - (void)_web_setSubviews:(NSArray *)subviews
55 {
56     for (UIView* subview in self.subviews)
57         [subview removeFromSuperview];
58
59     for (UIView* view in subviews)
60         [self addSubview:view];
61 }
62
63 @end
64 #endif
65
66 using namespace WebCore;
67
68 namespace WebKit {
69
70 static RetainPtr<CGColorRef> cgColorFromColor(Color color)
71 {
72     CGFloat components[4];
73     color.getRGBA(components[0], components[1], components[2], components[3]);
74
75     RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
76     return adoptCF(CGColorCreate(colorSpace.get(), components));
77 }
78
79 static NSString *toCAFilterType(PlatformCALayer::FilterType type)
80 {
81     switch (type) {
82     case PlatformCALayer::Linear:
83         return kCAFilterLinear;
84     case PlatformCALayer::Nearest:
85         return kCAFilterNearest;
86     case PlatformCALayer::Trilinear:
87         return kCAFilterTrilinear;
88     };
89     
90     ASSERT_NOT_REACHED();
91     return 0;
92 }
93
94 static void updateCustomAppearance(CALayer *layer, GraphicsLayer::CustomAppearance customAppearance)
95 {
96 #if ENABLE(RUBBER_BANDING)
97     switch (customAppearance) {
98     case GraphicsLayer::NoCustomAppearance:
99         ScrollbarThemeMac::removeOverhangAreaBackground(layer);
100         ScrollbarThemeMac::removeOverhangAreaShadow(layer);
101         break;
102     case GraphicsLayer::ScrollingOverhang:
103         ScrollbarThemeMac::setUpOverhangAreaBackground(layer);
104         break;
105     case GraphicsLayer::ScrollingShadow:
106         ScrollbarThemeMac::setUpOverhangAreaShadow(layer);
107         break;
108     }
109 #else
110     UNUSED_PARAM(customAppearance);
111 #endif
112 }
113
114 static void applyPropertiesToLayer(CALayer *layer, const RemoteLayerTreeTransaction::LayerProperties& properties)
115 {
116     if (properties.changedProperties & RemoteLayerTreeTransaction::NameChanged)
117         layer.name = properties.name;
118
119     if (properties.changedProperties & RemoteLayerTreeTransaction::PositionChanged) {
120         layer.position = CGPointMake(properties.position.x(), properties.position.y());
121         layer.zPosition = properties.position.z();
122     }
123
124     if (properties.changedProperties & RemoteLayerTreeTransaction::AnchorPointChanged) {
125         layer.anchorPoint = CGPointMake(properties.anchorPoint.x(), properties.anchorPoint.y());
126         layer.anchorPointZ = properties.anchorPoint.z();
127     }
128
129     if (properties.changedProperties & RemoteLayerTreeTransaction::SizeChanged)
130         layer.bounds = FloatRect(FloatPoint(), properties.size);
131
132     if (properties.changedProperties & RemoteLayerTreeTransaction::BackgroundColorChanged)
133         layer.backgroundColor = cgColorFromColor(properties.backgroundColor).get();
134
135     if (properties.changedProperties & RemoteLayerTreeTransaction::BorderColorChanged)
136         layer.borderColor = cgColorFromColor(properties.borderColor).get();
137
138     if (properties.changedProperties & RemoteLayerTreeTransaction::BorderWidthChanged)
139         layer.borderWidth = properties.borderWidth;
140
141     if (properties.changedProperties & RemoteLayerTreeTransaction::OpacityChanged)
142         layer.opacity = properties.opacity;
143
144     if (properties.changedProperties & RemoteLayerTreeTransaction::TransformChanged)
145         layer.transform = properties.transform ? (CATransform3D)*properties.transform.get() : CATransform3DIdentity;
146
147     if (properties.changedProperties & RemoteLayerTreeTransaction::SublayerTransformChanged)
148         layer.sublayerTransform = properties.sublayerTransform ? (CATransform3D)*properties.sublayerTransform.get() : CATransform3DIdentity;
149
150     if (properties.changedProperties & RemoteLayerTreeTransaction::HiddenChanged)
151         layer.hidden = properties.hidden;
152
153     if (properties.changedProperties & RemoteLayerTreeTransaction::GeometryFlippedChanged)
154         layer.geometryFlipped = properties.geometryFlipped;
155
156     if (properties.changedProperties & RemoteLayerTreeTransaction::DoubleSidedChanged)
157         layer.doubleSided = properties.doubleSided;
158
159     if (properties.changedProperties & RemoteLayerTreeTransaction::MasksToBoundsChanged)
160         layer.masksToBounds = properties.masksToBounds;
161
162     if (properties.changedProperties & RemoteLayerTreeTransaction::OpaqueChanged)
163         layer.opaque = properties.opaque;
164
165     if (properties.changedProperties & RemoteLayerTreeTransaction::ContentsRectChanged)
166         layer.contentsRect = properties.contentsRect;
167
168     if (properties.changedProperties & RemoteLayerTreeTransaction::ContentsScaleChanged)
169         layer.contentsScale = properties.contentsScale;
170
171     if (properties.changedProperties & RemoteLayerTreeTransaction::MinificationFilterChanged)
172         layer.minificationFilter = toCAFilterType(properties.minificationFilter);
173
174     if (properties.changedProperties & RemoteLayerTreeTransaction::MagnificationFilterChanged)
175         layer.magnificationFilter = toCAFilterType(properties.magnificationFilter);
176
177     if (properties.changedProperties & RemoteLayerTreeTransaction::SpeedChanged)
178         layer.speed = properties.speed;
179
180     if (properties.changedProperties & RemoteLayerTreeTransaction::TimeOffsetChanged)
181         layer.timeOffset = properties.timeOffset;
182
183     if (properties.changedProperties & RemoteLayerTreeTransaction::BackingStoreChanged) {
184         if (RemoteLayerBackingStore* backingStore = properties.backingStore.get())
185             backingStore->applyBackingStoreToLayer(layer);
186         else {
187             layer.contents = nil;
188             layer.contentsOpaque = NO;
189         }
190     }
191
192     if (properties.changedProperties & RemoteLayerTreeTransaction::FiltersChanged)
193         PlatformCAFilters::setFiltersOnLayer(layer, properties.filters ? *properties.filters : FilterOperations());
194
195     if (properties.changedProperties & RemoteLayerTreeTransaction::EdgeAntialiasingMaskChanged)
196         layer.edgeAntialiasingMask = properties.edgeAntialiasingMask;
197
198     if (properties.changedProperties & RemoteLayerTreeTransaction::CustomAppearanceChanged)
199         updateCustomAppearance(layer, properties.customAppearance);
200 }
201
202 void RemoteLayerTreePropertyApplier::applyProperties(CALayer *layer, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers)
203 {
204     BEGIN_BLOCK_OBJC_EXCEPTIONS;
205     applyPropertiesToLayer(layer, properties);
206
207     if (properties.changedProperties & RemoteLayerTreeTransaction::ChildrenChanged) {
208         RetainPtr<NSMutableArray> children = adoptNS([[NSMutableArray alloc] initWithCapacity:properties.children.size()]);
209         for (auto& child : properties.children) {
210             ASSERT(relatedLayers.get(child));
211             [children addObject:relatedLayers.get(child)];
212         }
213
214         layer.sublayers = children.get();
215     }
216
217     if (properties.changedProperties & RemoteLayerTreeTransaction::MaskLayerChanged) {
218         if (!properties.maskLayerID)
219             layer.mask = nullptr;
220         else {
221 #if PLATFORM(IOS)
222             UIView *maskView = relatedLayers.get(properties.maskLayerID);
223             // FIXME: need to check that the mask view is kept alive.
224             ASSERT(!maskView.layer.superlayer);
225             if (!maskView.layer.superlayer)
226                 layer.mask = maskView.layer;
227 #else
228             CALayer *maskLayer = relatedLayers.get(properties.maskLayerID);
229             ASSERT(!maskLayer.superlayer);
230             if (!maskLayer.superlayer)
231                 layer.mask = maskLayer;
232 #endif
233         }
234     }
235     END_BLOCK_OBJC_EXCEPTIONS;
236 }
237
238 #if PLATFORM(IOS)
239 void RemoteLayerTreePropertyApplier::applyProperties(UIView *view, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers)
240 {
241     BEGIN_BLOCK_OBJC_EXCEPTIONS;
242     applyPropertiesToLayer(view.layer, properties);
243
244     if (properties.changedProperties & RemoteLayerTreeTransaction::ChildrenChanged) {
245         RetainPtr<NSMutableArray> children = adoptNS([[NSMutableArray alloc] initWithCapacity:properties.children.size()]);
246         for (auto& child : properties.children) {
247             ASSERT(relatedLayers.get(child));
248             [children addObject:relatedLayers.get(child)];
249         }
250
251         [view _web_setSubviews:children.get()];
252     }
253
254     if (properties.changedProperties & RemoteLayerTreeTransaction::MaskLayerChanged) {
255         if (!properties.maskLayerID)
256             view.layer.mask = nullptr;
257         else {
258             UIView *maskView = relatedLayers.get(properties.maskLayerID);
259             // FIXME: need to check that the mask view is kept alive.
260             ASSERT(!maskView.layer.superlayer);
261             if (!maskView.layer.superlayer)
262                 view.layer.mask = maskView.layer;
263         }
264     }
265     END_BLOCK_OBJC_EXCEPTIONS;
266 }
267 #endif
268
269 } // namespace WebKit