2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #import "RemoteLayerTreePropertyApplier.h"
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>
39 #import <UIKit/UIView.h>
44 @interface UIView (WKUIViewUtilities)
45 - (void)_web_setSubviews:(NSArray *)subviews;
48 @implementation UIView (WKUIViewUtilities)
50 - (void)_web_setSubviews:(NSArray *)newSubviews
52 NSUInteger numOldSubviews = self.subviews.count;
53 NSUInteger numNewSubviews = newSubviews.count;
55 NSUInteger currIndex = 0;
56 for (currIndex = 0; currIndex < numNewSubviews; ++currIndex) {
57 UIView *currNewSubview = [newSubviews objectAtIndex:currIndex];
59 if (currIndex < numOldSubviews) {
60 UIView *existingSubview = [self.subviews objectAtIndex:currIndex];
61 if (existingSubview == currNewSubview)
65 // New or moved subview.
66 [self insertSubview:currNewSubview atIndex:currIndex];
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];
74 ASSERT([self.subviews isEqualToArray:newSubviews]);
80 using namespace WebCore;
84 static CGColorRef cgColorFromColor(const Color& color)
89 return cachedCGColor(color);
92 static NSString *toCAFilterType(PlatformCALayer::FilterType type)
95 case PlatformCALayer::Linear:
96 return kCAFilterLinear;
97 case PlatformCALayer::Nearest:
98 return kCAFilterNearest;
99 case PlatformCALayer::Trilinear:
100 return kCAFilterTrilinear;
103 ASSERT_NOT_REACHED();
107 static void updateCustomAppearance(CALayer *layer, GraphicsLayer::CustomAppearance customAppearance)
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);
117 case GraphicsLayer::CustomAppearance::ScrollingOverhang:
118 ScrollbarThemeMac::setUpOverhangAreaBackground(layer);
120 case GraphicsLayer::CustomAppearance::ScrollingShadow:
121 ScrollbarThemeMac::setUpOverhangAreaShadow(layer);
125 UNUSED_PARAM(customAppearance);
129 static void applyPropertiesToLayer(CALayer *layer, RemoteLayerTreeHost* layerTreeHost, const RemoteLayerTreeTransaction::LayerProperties& properties, RemoteLayerBackingStore::LayerContentsType layerContentsType)
131 if (properties.changedProperties & RemoteLayerTreeTransaction::NameChanged)
132 layer.name = properties.name;
134 if (properties.changedProperties & RemoteLayerTreeTransaction::PositionChanged) {
135 layer.position = CGPointMake(properties.position.x(), properties.position.y());
136 layer.zPosition = properties.position.z();
139 if (properties.changedProperties & RemoteLayerTreeTransaction::AnchorPointChanged) {
140 layer.anchorPoint = CGPointMake(properties.anchorPoint.x(), properties.anchorPoint.y());
141 layer.anchorPointZ = properties.anchorPoint.z();
144 if (properties.changedProperties & RemoteLayerTreeTransaction::BoundsChanged)
145 layer.bounds = properties.bounds;
147 if (properties.changedProperties & RemoteLayerTreeTransaction::BackgroundColorChanged)
148 layer.backgroundColor = cgColorFromColor(properties.backgroundColor);
150 if (properties.changedProperties & RemoteLayerTreeTransaction::BorderColorChanged)
151 layer.borderColor = cgColorFromColor(properties.borderColor);
153 if (properties.changedProperties & RemoteLayerTreeTransaction::BorderWidthChanged)
154 layer.borderWidth = properties.borderWidth;
156 if (properties.changedProperties & RemoteLayerTreeTransaction::OpacityChanged)
157 layer.opacity = properties.opacity;
159 if (properties.changedProperties & RemoteLayerTreeTransaction::TransformChanged)
160 layer.transform = properties.transform ? (CATransform3D)*properties.transform.get() : CATransform3DIdentity;
162 if (properties.changedProperties & RemoteLayerTreeTransaction::SublayerTransformChanged)
163 layer.sublayerTransform = properties.sublayerTransform ? (CATransform3D)*properties.sublayerTransform.get() : CATransform3DIdentity;
165 if (properties.changedProperties & RemoteLayerTreeTransaction::HiddenChanged)
166 layer.hidden = properties.hidden;
168 if (properties.changedProperties & RemoteLayerTreeTransaction::GeometryFlippedChanged)
169 layer.geometryFlipped = properties.geometryFlipped;
171 if (properties.changedProperties & RemoteLayerTreeTransaction::DoubleSidedChanged)
172 layer.doubleSided = properties.doubleSided;
174 if (properties.changedProperties & RemoteLayerTreeTransaction::MasksToBoundsChanged)
175 layer.masksToBounds = properties.masksToBounds;
177 if (properties.changedProperties & RemoteLayerTreeTransaction::OpaqueChanged)
178 layer.opaque = properties.opaque;
180 if (properties.changedProperties & RemoteLayerTreeTransaction::ContentsRectChanged)
181 layer.contentsRect = properties.contentsRect;
183 if (properties.changedProperties & RemoteLayerTreeTransaction::ContentsScaleChanged) {
184 layer.contentsScale = properties.contentsScale;
185 layer.rasterizationScale = properties.contentsScale;
188 if (properties.changedProperties & RemoteLayerTreeTransaction::CornerRadiusChanged)
189 layer.cornerRadius = properties.cornerRadius;
191 if (properties.changedProperties & RemoteLayerTreeTransaction::ShapeRoundedRectChanged) {
193 if (properties.shapeRoundedRect)
194 path.addRoundedRect(*properties.shapeRoundedRect);
195 ASSERT([layer isKindOfClass:[CAShapeLayer class]]);
196 [(CAShapeLayer *)layer setPath:path.platformPath()];
199 if (properties.changedProperties & RemoteLayerTreeTransaction::ShapePathChanged) {
200 ASSERT([layer isKindOfClass:[CAShapeLayer class]]);
201 [(CAShapeLayer *)layer setPath:properties.shapePath.platformPath()];
204 if (properties.changedProperties & RemoteLayerTreeTransaction::MinificationFilterChanged)
205 layer.minificationFilter = toCAFilterType(properties.minificationFilter);
207 if (properties.changedProperties & RemoteLayerTreeTransaction::MagnificationFilterChanged)
208 layer.magnificationFilter = toCAFilterType(properties.magnificationFilter);
210 if (properties.changedProperties & RemoteLayerTreeTransaction::BlendModeChanged)
211 PlatformCAFilters::setBlendingFiltersOnLayer(layer, properties.blendMode);
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";
220 case WindRule::EvenOdd:
221 shapeLayer.fillRule = @"even-odd";
226 if (properties.changedProperties & RemoteLayerTreeTransaction::SpeedChanged)
227 layer.speed = properties.speed;
229 if (properties.changedProperties & RemoteLayerTreeTransaction::TimeOffsetChanged)
230 layer.timeOffset = properties.timeOffset;
232 if (properties.changedProperties & RemoteLayerTreeTransaction::BackingStoreChanged
233 || properties.changedProperties & RemoteLayerTreeTransaction::BackingStoreAttachmentChanged)
235 RemoteLayerBackingStore* backingStore = properties.backingStore.get();
236 if (backingStore && properties.backingStoreAttached)
237 backingStore->applyBackingStoreToLayer(layer, layerContentsType);
239 layer.contents = nil;
240 layer.contentsOpaque = NO;
244 if (properties.changedProperties & RemoteLayerTreeTransaction::FiltersChanged)
245 PlatformCAFilters::setFiltersOnLayer(layer, properties.filters ? *properties.filters : FilterOperations());
247 if (properties.changedProperties & RemoteLayerTreeTransaction::AnimationsChanged)
248 PlatformCAAnimationRemote::updateLayerAnimations(layer, layerTreeHost, properties.addedAnimations, properties.keyPathsOfAnimationsToRemove);
250 if (properties.changedProperties & RemoteLayerTreeTransaction::EdgeAntialiasingMaskChanged)
251 layer.edgeAntialiasingMask = properties.edgeAntialiasingMask;
253 if (properties.changedProperties & RemoteLayerTreeTransaction::CustomAppearanceChanged)
254 updateCustomAppearance(layer, properties.customAppearance);
257 void RemoteLayerTreePropertyApplier::applyProperties(CALayer *layer, RemoteLayerTreeHost* layerTreeHost, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers, RemoteLayerBackingStore::LayerContentsType layerContentsType)
259 BEGIN_BLOCK_OBJC_EXCEPTIONS;
260 applyPropertiesToLayer(layer, layerTreeHost, properties, layerContentsType);
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:(__bridge id)relatedLayers.get(child)];
269 layer.sublayers = children.get();
272 if (properties.changedProperties & RemoteLayerTreeTransaction::MaskLayerChanged) {
273 if (!properties.maskLayerID)
274 layer.mask = nullptr;
277 UIView *maskView = (__bridge UIView *)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;
283 CALayer *maskLayer = (__bridge CALayer *)relatedLayers.get(properties.maskLayerID);
284 ASSERT(!maskLayer.superlayer);
285 if (!maskLayer.superlayer)
286 layer.mask = maskLayer;
290 END_BLOCK_OBJC_EXCEPTIONS;
294 void RemoteLayerTreePropertyApplier::applyProperties(UIView *view, RemoteLayerTreeHost* layerTreeHost, const RemoteLayerTreeTransaction::LayerProperties& properties, const RelatedLayerMap& relatedLayers, RemoteLayerBackingStore::LayerContentsType layerContentsType)
296 BEGIN_BLOCK_OBJC_EXCEPTIONS;
297 applyPropertiesToLayer(view.layer, layerTreeHost, properties, layerContentsType);
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:(__bridge id)relatedLayers.get(child)];
306 if (properties.customAppearance == GraphicsLayer::CustomAppearance::LightBackdrop || properties.customAppearance == GraphicsLayer::CustomAppearance::DarkBackdrop) {
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()];
311 [view _web_setSubviews:children.get()];
314 if (properties.changedProperties & RemoteLayerTreeTransaction::MaskLayerChanged) {
315 CALayer *maskOwnerLayer = view.layer;
317 if (properties.customAppearance == GraphicsLayer::CustomAppearance::LightBackdrop || properties.customAppearance == GraphicsLayer::CustomAppearance::DarkBackdrop) {
318 // This is a UIBackdropView, which means any mask must be applied to the CABackdropLayer rather
319 // that the view's layer. The backdrop is the first layer child.
320 if (view.layer.sublayers.count && [view.layer.sublayers[0] isKindOfClass:[CABackdropLayer class]])
321 maskOwnerLayer = view.layer.sublayers[0];
324 if (!properties.maskLayerID)
325 maskOwnerLayer.mask = nullptr;
327 UIView *maskView = (__bridge UIView *)relatedLayers.get(properties.maskLayerID);
328 // FIXME: need to check that the mask view is kept alive.
329 ASSERT(!maskView.layer.superlayer);
330 if (!maskView.layer.superlayer)
331 maskOwnerLayer.mask = maskView.layer;
335 if (properties.changedProperties.containsAny({ RemoteLayerTreeTransaction::ContentsHiddenChanged, RemoteLayerTreeTransaction::UserInteractionEnabledChanged }))
336 view.userInteractionEnabled = !properties.contentsHidden && properties.userInteractionEnabled;
338 END_BLOCK_OBJC_EXCEPTIONS;
342 } // namespace WebKit