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