AVPlayerLayer isn't available on every system
[WebKit-https.git] / Source / WebCore / platform / graphics / ca / cocoa / PlatformCALayerCocoa.mm
1 /*
2  * Copyright (C) 2010, 2015 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #import "PlatformCALayerCocoa.h"
28
29 #import "AnimationUtilities.h"
30 #import "GraphicsContext.h"
31 #import "GraphicsLayerCA.h"
32 #import "LengthFunctions.h"
33 #import "PlatformCAAnimationCocoa.h"
34 #import "PlatformCAFilters.h"
35 #import "PlatformScreen.h"
36 #import "QuartzCoreSPI.h"
37 #import "ScrollbarThemeMac.h"
38 #import "SoftLinking.h"
39 #import "TileController.h"
40 #import "TiledBacking.h"
41 #import "WebActionDisablingCALayerDelegate.h"
42 #import "WebCoreCALayerExtras.h"
43 #import "WebGLLayer.h"
44 #import "WebLayer.h"
45 #import "WebSystemBackdropLayer.h"
46 #import "WebTiledBackingLayer.h"
47 #import <AVFoundation/AVFoundation.h>
48 #import <QuartzCore/QuartzCore.h>
49 #import <objc/runtime.h>
50 #import <wtf/BlockObjCExceptions.h>
51 #import <wtf/CurrentTime.h>
52 #import <wtf/RetainPtr.h>
53
54 #if PLATFORM(IOS)
55 #import "FontAntialiasingStateSaver.h"
56 #import "WAKWindow.h"
57 #import "WKGraphics.h"
58 #import "WebCoreThread.h"
59 #else
60 #import "ThemeMac.h"
61 #endif
62
63 SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
64
65 SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVPlayerLayer)
66
67 using namespace WebCore;
68
69 PassRefPtr<PlatformCALayer> PlatformCALayerCocoa::create(LayerType layerType, PlatformCALayerClient* owner)
70 {
71     return adoptRef(new PlatformCALayerCocoa(layerType, owner));
72 }
73
74 PassRefPtr<PlatformCALayer> PlatformCALayerCocoa::create(void* platformLayer, PlatformCALayerClient* owner)
75 {
76     return adoptRef(new PlatformCALayerCocoa(static_cast<PlatformLayer*>(platformLayer), owner));
77 }
78
79 static NSString * const platformCALayerPointer = @"WKPlatformCALayer";
80 PlatformCALayer* PlatformCALayer::platformCALayer(void* platformLayer)
81 {
82     if (!platformLayer)
83         return 0;
84
85     // Pointer to PlatformCALayer is kept in a key of the CALayer
86     PlatformCALayer* platformCALayer = nil;
87     BEGIN_BLOCK_OBJC_EXCEPTIONS
88     platformCALayer = static_cast<PlatformCALayer*>([[static_cast<CALayer*>(platformLayer) valueForKey:platformCALayerPointer] pointerValue]);
89     END_BLOCK_OBJC_EXCEPTIONS
90     return platformCALayer;
91 }
92
93 static double mediaTimeToCurrentTime(CFTimeInterval t)
94 {
95     return monotonicallyIncreasingTime() + t - CACurrentMediaTime();
96 }
97
98 // Delegate for animationDidStart callback
99 @interface WebAnimationDelegate : NSObject {
100     PlatformCALayer* m_owner;
101 }
102
103 - (void)animationDidStart:(CAAnimation *)anim;
104 - (void)setOwner:(PlatformCALayer*)owner;
105
106 @end
107
108 @implementation WebAnimationDelegate
109
110 - (void)animationDidStart:(CAAnimation *)animation
111 {
112 #if PLATFORM(IOS)
113     WebThreadLock();
114 #endif
115     if (!m_owner)
116         return;
117
118     CFTimeInterval startTime;
119     if (hasExplicitBeginTime(animation)) {
120         // We don't know what time CA used to commit the animation, so just use the current time
121         // (even though this will be slightly off).
122         startTime = mediaTimeToCurrentTime(CACurrentMediaTime());
123     } else
124         startTime = mediaTimeToCurrentTime([animation beginTime]);
125
126     CALayer *layer = m_owner->platformLayer();
127
128     String animationKey;
129     for (NSString *key in [layer animationKeys]) {
130         if ([layer animationForKey:key] == animation) {
131             animationKey = key;
132             break;
133         }
134     }
135
136     if (!animationKey.isEmpty())
137         m_owner->animationStarted(animationKey, startTime);
138 }
139
140 - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished
141 {
142 #if PLATFORM(IOS)
143     WebThreadLock();
144 #endif
145     UNUSED_PARAM(finished);
146
147     if (!m_owner)
148         return;
149     
150     CALayer *layer = m_owner->platformLayer();
151
152     String animationKey;
153     for (NSString *key in [layer animationKeys]) {
154         if ([layer animationForKey:key] == animation) {
155             animationKey = key;
156             break;
157         }
158     }
159
160     if (!animationKey.isEmpty())
161         m_owner->animationEnded(animationKey);
162 }
163
164 - (void)setOwner:(PlatformCALayer*)owner
165 {
166     m_owner = owner;
167 }
168
169 @end
170
171 void PlatformCALayerCocoa::setOwner(PlatformCALayerClient* owner)
172 {
173     PlatformCALayer::setOwner(owner);
174     
175     // Change the delegate's owner if needed
176     if (m_delegate)
177         [static_cast<WebAnimationDelegate*>(m_delegate.get()) setOwner:this];        
178 }
179
180 static NSString *toCAFilterType(PlatformCALayer::FilterType type)
181 {
182     switch (type) {
183     case PlatformCALayer::Linear: return kCAFilterLinear;
184     case PlatformCALayer::Nearest: return kCAFilterNearest;
185     case PlatformCALayer::Trilinear: return kCAFilterTrilinear;
186     default: return 0;
187     }
188 }
189
190 PlatformCALayer::LayerType PlatformCALayerCocoa::layerTypeForPlatformLayer(PlatformLayer* layer)
191 {
192     if ([layer isKindOfClass:getAVPlayerLayerClass()] || [layer isKindOfClass:objc_getClass("WebVideoContainerLayer")])
193         return LayerTypeAVPlayerLayer;
194
195     if ([layer isKindOfClass:[WebGLLayer class]])
196         return LayerTypeWebGLLayer;
197
198     return LayerTypeCustom;
199 }
200
201 PlatformCALayerCocoa::PlatformCALayerCocoa(LayerType layerType, PlatformCALayerClient* owner)
202     : PlatformCALayer(layerType, owner)
203     , m_customAppearance(GraphicsLayer::NoCustomAppearance)
204 {
205     Class layerClass = Nil;
206     switch (layerType) {
207     case LayerTypeLayer:
208     case LayerTypeRootLayer:
209         layerClass = [CALayer class];
210         break;
211     case LayerTypeScrollingLayer:
212         // Scrolling layers only have special behavior with PlatformCALayerRemote.
213         // fallthrough
214     case LayerTypeWebLayer:
215         layerClass = [WebLayer class];
216         break;
217     case LayerTypeSimpleLayer:
218     case LayerTypeTiledBackingTileLayer:
219         layerClass = [WebSimpleLayer class];
220         break;
221     case LayerTypeTransformLayer:
222         layerClass = [CATransformLayer class];
223         break;
224 #if ENABLE(FILTERS_LEVEL_2)
225     case LayerTypeBackdropLayer:
226         layerClass = [CABackdropLayer class];
227         break;
228     case LayerTypeLightSystemBackdropLayer:
229         layerClass = [WebLightSystemBackdropLayer class];
230         break;
231     case LayerTypeDarkSystemBackdropLayer:
232         layerClass = [WebDarkSystemBackdropLayer class];
233         break;
234 #else
235     case LayerTypeBackdropLayer:
236     case LayerTypeLightSystemBackdropLayer:
237     case LayerTypeDarkSystemBackdropLayer:
238         ASSERT_NOT_REACHED();
239         layerClass = [CALayer class];
240         break;
241 #endif
242     case LayerTypeWebTiledLayer:
243         ASSERT_NOT_REACHED();
244         break;
245     case LayerTypeTiledBackingLayer:
246     case LayerTypePageTiledBackingLayer:
247         layerClass = [WebTiledBackingLayer class];
248         break;
249     case LayerTypeAVPlayerLayer:
250         layerClass = getAVPlayerLayerClass();
251         break;
252     case LayerTypeWebGLLayer:
253         // We don't create PlatformCALayerCocoas wrapped around WebGLLayers.
254         ASSERT_NOT_REACHED();
255         break;
256     case LayerTypeShapeLayer:
257         layerClass = [CAShapeLayer class];
258         // fillColor defaults to opaque black.
259         break;
260     case LayerTypeCustom:
261         break;
262     }
263
264     if (layerClass)
265         m_layer = adoptNS([(CALayer *)[layerClass alloc] init]);
266
267 #if ENABLE(FILTERS_LEVEL_2) && PLATFORM(MAC)
268     if (layerType == LayerTypeBackdropLayer)
269         [(CABackdropLayer*)m_layer.get() setWindowServerAware:NO];
270 #endif
271
272     commonInit();
273 }
274
275 PlatformCALayerCocoa::PlatformCALayerCocoa(PlatformLayer* layer, PlatformCALayerClient* owner)
276     : PlatformCALayer(layerTypeForPlatformLayer(layer), owner)
277     , m_customAppearance(GraphicsLayer::NoCustomAppearance)
278 {
279     m_layer = layer;
280     commonInit();
281 }
282
283 void PlatformCALayerCocoa::commonInit()
284 {
285     BEGIN_BLOCK_OBJC_EXCEPTIONS
286     // Save a pointer to 'this' in the CALayer
287     [m_layer setValue:[NSValue valueWithPointer:this] forKey:platformCALayerPointer];
288     
289     // Clear all the implicit animations on the CALayer
290     if (m_layerType == LayerTypeAVPlayerLayer || m_layerType == LayerTypeWebGLLayer || m_layerType == LayerTypeScrollingLayer || m_layerType == LayerTypeCustom)
291         [m_layer web_disableAllActions];
292     else
293         [m_layer setDelegate:[WebActionDisablingCALayerDelegate shared]];
294
295     if (m_layerType == LayerTypeWebLayer || m_layerType == LayerTypeTiledBackingTileLayer) {
296 #if PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90300
297         if (screenSupportsExtendedColor())
298             [m_layer setContentsFormat:kCAContentsFormatRGBA10XR];
299 #endif
300     }
301
302     // So that the scrolling thread's performance logging code can find all the tiles, mark this as being a tile.
303     if (m_layerType == LayerTypeTiledBackingTileLayer)
304         [m_layer setValue:@YES forKey:@"isTile"];
305
306     if (usesTiledBackingLayer()) {
307         WebTiledBackingLayer* tiledBackingLayer = static_cast<WebTiledBackingLayer*>(m_layer.get());
308         TileController* tileController = [tiledBackingLayer createTileController:this];
309
310         m_customSublayers = std::make_unique<PlatformCALayerList>(tileController->containerLayers());
311     }
312
313     END_BLOCK_OBJC_EXCEPTIONS
314 }
315
316 PassRefPtr<PlatformCALayer> PlatformCALayerCocoa::clone(PlatformCALayerClient* owner) const
317 {
318     LayerType type;
319     switch (layerType()) {
320     case LayerTypeTransformLayer:
321         type = LayerTypeTransformLayer;
322         break;
323     case LayerTypeAVPlayerLayer:
324         type = LayerTypeAVPlayerLayer;
325         break;
326     case LayerTypeShapeLayer:
327         type = LayerTypeShapeLayer;
328         break;
329     case LayerTypeBackdropLayer:
330         type = LayerTypeBackdropLayer;
331         break;
332     case LayerTypeLayer:
333     default:
334         type = LayerTypeLayer;
335         break;
336     };
337     RefPtr<PlatformCALayer> newLayer = PlatformCALayerCocoa::create(type, owner);
338     
339     newLayer->setPosition(position());
340     newLayer->setBounds(bounds());
341     newLayer->setAnchorPoint(anchorPoint());
342     newLayer->setTransform(transform());
343     newLayer->setSublayerTransform(sublayerTransform());
344     newLayer->setContents(contents());
345     newLayer->setMasksToBounds(masksToBounds());
346     newLayer->setDoubleSided(isDoubleSided());
347     newLayer->setOpaque(isOpaque());
348     newLayer->setBackgroundColor(backgroundColor());
349     newLayer->setContentsScale(contentsScale());
350     newLayer->setCornerRadius(cornerRadius());
351     newLayer->copyFiltersFrom(*this);
352     newLayer->updateCustomAppearance(customAppearance());
353
354     if (type == LayerTypeAVPlayerLayer) {
355         ASSERT([newLayer->platformLayer() isKindOfClass:getAVPlayerLayerClass()]);
356
357         AVPlayerLayer *destinationPlayerLayer = static_cast<PlatformCALayerCocoa *>(newLayer.get())->avPlayerLayer();
358         AVPlayerLayer *sourcePlayerLayer = avPlayerLayer();
359         ASSERT(sourcePlayerLayer);
360
361         dispatch_async(dispatch_get_main_queue(), ^{
362             [destinationPlayerLayer setPlayer:[sourcePlayerLayer player]];
363         });
364     }
365     
366     if (type == LayerTypeShapeLayer)
367         newLayer->setShapeRoundedRect(shapeRoundedRect());
368
369     return newLayer;
370 }
371
372 PlatformCALayerCocoa::~PlatformCALayerCocoa()
373 {
374     [m_layer setValue:nil forKey:platformCALayerPointer];
375     
376     // Remove the owner pointer from the delegate in case there is a pending animationStarted event.
377     [static_cast<WebAnimationDelegate*>(m_delegate.get()) setOwner:nil];
378
379     if (usesTiledBackingLayer())
380         [static_cast<WebTiledBackingLayer *>(m_layer.get()) invalidate];
381 }
382
383 void PlatformCALayerCocoa::animationStarted(const String& animationKey, CFTimeInterval beginTime)
384 {
385     if (m_owner)
386         m_owner->platformCALayerAnimationStarted(animationKey, beginTime);
387 }
388
389 void PlatformCALayerCocoa::animationEnded(const String& animationKey)
390 {
391     if (m_owner)
392         m_owner->platformCALayerAnimationEnded(animationKey);
393 }
394
395 void PlatformCALayerCocoa::setNeedsDisplay()
396 {
397     BEGIN_BLOCK_OBJC_EXCEPTIONS
398     [m_layer setNeedsDisplay];
399     END_BLOCK_OBJC_EXCEPTIONS
400 }
401
402 void PlatformCALayerCocoa::setNeedsDisplayInRect(const FloatRect& dirtyRect)
403 {
404     BEGIN_BLOCK_OBJC_EXCEPTIONS
405     [m_layer setNeedsDisplayInRect:dirtyRect];
406     END_BLOCK_OBJC_EXCEPTIONS
407 }
408
409 void PlatformCALayerCocoa::copyContentsFromLayer(PlatformCALayer* layer)
410 {
411     BEGIN_BLOCK_OBJC_EXCEPTIONS
412     CALayer* caLayer = layer->m_layer.get();
413     if ([m_layer contents] != [caLayer contents])
414         [m_layer setContents:[caLayer contents]];
415     else
416         [m_layer setContentsChanged];
417     END_BLOCK_OBJC_EXCEPTIONS
418 }
419
420 PlatformCALayer* PlatformCALayerCocoa::superlayer() const
421 {
422     return platformCALayer([m_layer superlayer]);
423 }
424
425 void PlatformCALayerCocoa::removeFromSuperlayer()
426 {
427     BEGIN_BLOCK_OBJC_EXCEPTIONS
428     [m_layer removeFromSuperlayer];
429     END_BLOCK_OBJC_EXCEPTIONS
430 }
431
432 void PlatformCALayerCocoa::setSublayers(const PlatformCALayerList& list)
433 {
434     // Short circuiting here avoids the allocation of the array below.
435     if (!list.size()) {
436         removeAllSublayers();
437         return;
438     }
439
440     BEGIN_BLOCK_OBJC_EXCEPTIONS
441     NSMutableArray* sublayers = [[NSMutableArray alloc] init];
442     for (size_t i = 0; i < list.size(); ++i)
443         [sublayers addObject:list[i]->m_layer.get()];
444
445     [m_layer setSublayers:sublayers];
446     [sublayers release];
447     END_BLOCK_OBJC_EXCEPTIONS
448 }
449
450 void PlatformCALayerCocoa::removeAllSublayers()
451 {
452     BEGIN_BLOCK_OBJC_EXCEPTIONS
453     [m_layer setSublayers:nil];
454     END_BLOCK_OBJC_EXCEPTIONS
455 }
456
457 void PlatformCALayerCocoa::appendSublayer(PlatformCALayer& layer)
458 {
459     BEGIN_BLOCK_OBJC_EXCEPTIONS
460     ASSERT(m_layer != layer.m_layer);
461     [m_layer addSublayer:layer.m_layer.get()];
462     END_BLOCK_OBJC_EXCEPTIONS
463 }
464
465 void PlatformCALayerCocoa::insertSublayer(PlatformCALayer& layer, size_t index)
466 {
467     BEGIN_BLOCK_OBJC_EXCEPTIONS
468     ASSERT(m_layer != layer.m_layer);
469     [m_layer insertSublayer:layer.m_layer.get() atIndex:index];
470     END_BLOCK_OBJC_EXCEPTIONS
471 }
472
473 void PlatformCALayerCocoa::replaceSublayer(PlatformCALayer& reference, PlatformCALayer& layer)
474 {
475     BEGIN_BLOCK_OBJC_EXCEPTIONS
476     ASSERT(m_layer != layer.m_layer);
477     [m_layer replaceSublayer:reference.m_layer.get() with:layer.m_layer.get()];
478     END_BLOCK_OBJC_EXCEPTIONS
479 }
480
481 void PlatformCALayerCocoa::adoptSublayers(PlatformCALayer& source)
482 {
483     BEGIN_BLOCK_OBJC_EXCEPTIONS
484     [m_layer setSublayers:[source.m_layer.get() sublayers]];
485     END_BLOCK_OBJC_EXCEPTIONS
486 }
487
488 void PlatformCALayerCocoa::addAnimationForKey(const String& key, PlatformCAAnimation& animation)
489 {
490     // Add the delegate
491     if (!m_delegate) {
492         WebAnimationDelegate* webAnimationDelegate = [[WebAnimationDelegate alloc] init];
493         m_delegate = adoptNS(webAnimationDelegate);
494         [webAnimationDelegate setOwner:this];
495     }
496     
497     CAPropertyAnimation* propertyAnimation = static_cast<CAPropertyAnimation*>(downcast<PlatformCAAnimationCocoa>(animation).platformAnimation());
498     if (![propertyAnimation delegate])
499         [propertyAnimation setDelegate:static_cast<id>(m_delegate.get())];
500
501     BEGIN_BLOCK_OBJC_EXCEPTIONS
502     [m_layer addAnimation:propertyAnimation forKey:key];
503     END_BLOCK_OBJC_EXCEPTIONS
504 }
505
506 void PlatformCALayerCocoa::removeAnimationForKey(const String& key)
507 {
508     BEGIN_BLOCK_OBJC_EXCEPTIONS
509     [m_layer removeAnimationForKey:key];
510     END_BLOCK_OBJC_EXCEPTIONS
511 }
512
513 PassRefPtr<PlatformCAAnimation> PlatformCALayerCocoa::animationForKey(const String& key)
514 {
515     CAPropertyAnimation* propertyAnimation = static_cast<CAPropertyAnimation*>([m_layer animationForKey:key]);
516     if (!propertyAnimation)
517         return 0;
518     return PlatformCAAnimationCocoa::create(propertyAnimation);
519 }
520
521 void PlatformCALayerCocoa::setMask(PlatformCALayer* layer)
522 {
523     BEGIN_BLOCK_OBJC_EXCEPTIONS
524     [m_layer setMask:layer ? layer->platformLayer() : nil];
525     END_BLOCK_OBJC_EXCEPTIONS
526 }
527
528 bool PlatformCALayerCocoa::isOpaque() const
529 {
530     return [m_layer isOpaque];
531 }
532
533 void PlatformCALayerCocoa::setOpaque(bool value)
534 {
535     BEGIN_BLOCK_OBJC_EXCEPTIONS
536     [m_layer setOpaque:value];
537     END_BLOCK_OBJC_EXCEPTIONS
538 }
539
540 FloatRect PlatformCALayerCocoa::bounds() const
541 {
542     return [m_layer bounds];
543 }
544
545 void PlatformCALayerCocoa::setBounds(const FloatRect& value)
546 {
547     BEGIN_BLOCK_OBJC_EXCEPTIONS
548     [m_layer setBounds:value];
549     
550     if (requiresCustomAppearanceUpdateOnBoundsChange())
551         updateCustomAppearance(m_customAppearance);
552
553     END_BLOCK_OBJC_EXCEPTIONS
554 }
555
556 FloatPoint3D PlatformCALayerCocoa::position() const
557 {
558     CGPoint point = [m_layer position];
559     return FloatPoint3D(point.x, point.y, [m_layer zPosition]);
560 }
561
562 void PlatformCALayerCocoa::setPosition(const FloatPoint3D& value)
563 {
564     BEGIN_BLOCK_OBJC_EXCEPTIONS
565     [m_layer setPosition:CGPointMake(value.x(), value.y())];
566     [m_layer setZPosition:value.z()];
567     END_BLOCK_OBJC_EXCEPTIONS
568 }
569
570 FloatPoint3D PlatformCALayerCocoa::anchorPoint() const
571 {
572     CGPoint point = [m_layer anchorPoint];
573     float z = 0;
574     z = [m_layer anchorPointZ];
575     return FloatPoint3D(point.x, point.y, z);
576 }
577
578 void PlatformCALayerCocoa::setAnchorPoint(const FloatPoint3D& value)
579 {
580     BEGIN_BLOCK_OBJC_EXCEPTIONS
581     [m_layer setAnchorPoint:CGPointMake(value.x(), value.y())];
582     [m_layer setAnchorPointZ:value.z()];
583     END_BLOCK_OBJC_EXCEPTIONS
584 }
585
586 TransformationMatrix PlatformCALayerCocoa::transform() const
587 {
588     return [m_layer transform];
589 }
590
591 void PlatformCALayerCocoa::setTransform(const TransformationMatrix& value)
592 {
593     BEGIN_BLOCK_OBJC_EXCEPTIONS
594     [m_layer setTransform:value];
595     END_BLOCK_OBJC_EXCEPTIONS
596 }
597
598 TransformationMatrix PlatformCALayerCocoa::sublayerTransform() const
599 {
600     return [m_layer sublayerTransform];
601 }
602
603 void PlatformCALayerCocoa::setSublayerTransform(const TransformationMatrix& value)
604 {
605     BEGIN_BLOCK_OBJC_EXCEPTIONS
606     [m_layer setSublayerTransform:value];
607     END_BLOCK_OBJC_EXCEPTIONS
608 }
609
610 bool PlatformCALayerCocoa::isHidden() const
611 {
612     return [m_layer isHidden];
613 }
614
615 void PlatformCALayerCocoa::setHidden(bool value)
616 {
617     BEGIN_BLOCK_OBJC_EXCEPTIONS
618     [m_layer setHidden:value];
619     END_BLOCK_OBJC_EXCEPTIONS
620 }
621
622 bool PlatformCALayerCocoa::contentsHidden() const
623 {
624     return false;
625 }
626
627 void PlatformCALayerCocoa::setContentsHidden(bool)
628 {
629 }
630
631 bool PlatformCALayerCocoa::userInteractionEnabled() const
632 {
633     return true;
634 }
635
636 void PlatformCALayerCocoa::setUserInteractionEnabled(bool)
637 {
638 }
639
640 void PlatformCALayerCocoa::setBackingStoreAttached(bool)
641 {
642     // We could throw away backing store here with setContents:nil.
643 }
644
645 bool PlatformCALayerCocoa::backingStoreAttached() const
646 {
647     return true;
648 }
649
650 bool PlatformCALayerCocoa::geometryFlipped() const
651 {
652     return [m_layer isGeometryFlipped];
653 }
654
655 void PlatformCALayerCocoa::setGeometryFlipped(bool value)
656 {
657     BEGIN_BLOCK_OBJC_EXCEPTIONS
658     [m_layer setGeometryFlipped:value];
659     END_BLOCK_OBJC_EXCEPTIONS
660 }
661
662 bool PlatformCALayerCocoa::isDoubleSided() const
663 {
664     return [m_layer isDoubleSided];
665 }
666
667 void PlatformCALayerCocoa::setDoubleSided(bool value)
668 {
669     BEGIN_BLOCK_OBJC_EXCEPTIONS
670     [m_layer setDoubleSided:value];
671     END_BLOCK_OBJC_EXCEPTIONS
672 }
673
674 bool PlatformCALayerCocoa::masksToBounds() const
675 {
676     return [m_layer masksToBounds];
677 }
678
679 void PlatformCALayerCocoa::setMasksToBounds(bool value)
680 {
681     BEGIN_BLOCK_OBJC_EXCEPTIONS
682     [m_layer setMasksToBounds:value];
683     END_BLOCK_OBJC_EXCEPTIONS
684 }
685
686 bool PlatformCALayerCocoa::acceleratesDrawing() const
687 {
688     return [m_layer acceleratesDrawing];
689 }
690
691 void PlatformCALayerCocoa::setAcceleratesDrawing(bool acceleratesDrawing)
692 {
693     BEGIN_BLOCK_OBJC_EXCEPTIONS
694     [m_layer setAcceleratesDrawing:acceleratesDrawing];
695     END_BLOCK_OBJC_EXCEPTIONS
696 }
697
698 CFTypeRef PlatformCALayerCocoa::contents() const
699 {
700     return [m_layer contents];
701 }
702
703 void PlatformCALayerCocoa::setContents(CFTypeRef value)
704 {
705     BEGIN_BLOCK_OBJC_EXCEPTIONS
706     [m_layer setContents:static_cast<id>(const_cast<void*>(value))];
707     END_BLOCK_OBJC_EXCEPTIONS
708 }
709
710 void PlatformCALayerCocoa::setContentsRect(const FloatRect& value)
711 {
712     BEGIN_BLOCK_OBJC_EXCEPTIONS
713     [m_layer setContentsRect:value];
714     END_BLOCK_OBJC_EXCEPTIONS
715 }
716
717 void PlatformCALayerCocoa::setMinificationFilter(FilterType value)
718 {
719     BEGIN_BLOCK_OBJC_EXCEPTIONS
720     [m_layer setMinificationFilter:toCAFilterType(value)];
721     END_BLOCK_OBJC_EXCEPTIONS
722 }
723
724 void PlatformCALayerCocoa::setMagnificationFilter(FilterType value)
725 {
726     BEGIN_BLOCK_OBJC_EXCEPTIONS
727     [m_layer setMagnificationFilter:toCAFilterType(value)];
728     END_BLOCK_OBJC_EXCEPTIONS
729 }
730
731 Color PlatformCALayerCocoa::backgroundColor() const
732 {
733     return [m_layer backgroundColor];
734 }
735
736 void PlatformCALayerCocoa::setBackgroundColor(const Color& value)
737 {
738     BEGIN_BLOCK_OBJC_EXCEPTIONS
739     [m_layer setBackgroundColor:cachedCGColor(value)];
740     END_BLOCK_OBJC_EXCEPTIONS
741 }
742
743 void PlatformCALayerCocoa::setBorderWidth(float value)
744 {
745     BEGIN_BLOCK_OBJC_EXCEPTIONS
746     [m_layer setBorderWidth:value];
747     END_BLOCK_OBJC_EXCEPTIONS
748 }
749
750 void PlatformCALayerCocoa::setBorderColor(const Color& value)
751 {
752     if (value.isValid()) {
753         BEGIN_BLOCK_OBJC_EXCEPTIONS
754         [m_layer setBorderColor:cachedCGColor(value)];
755         END_BLOCK_OBJC_EXCEPTIONS
756     } else {
757         BEGIN_BLOCK_OBJC_EXCEPTIONS
758         [m_layer setBorderColor:nil];
759         END_BLOCK_OBJC_EXCEPTIONS
760     }
761 }
762
763 float PlatformCALayerCocoa::opacity() const
764 {
765     return [m_layer opacity];
766 }
767
768 void PlatformCALayerCocoa::setOpacity(float value)
769 {
770     BEGIN_BLOCK_OBJC_EXCEPTIONS
771     [m_layer setOpacity:value];
772     END_BLOCK_OBJC_EXCEPTIONS
773 }
774
775 void PlatformCALayerCocoa::setFilters(const FilterOperations& filters)
776 {
777     PlatformCAFilters::setFiltersOnLayer(platformLayer(), filters);
778 }
779
780 void PlatformCALayerCocoa::copyFiltersFrom(const PlatformCALayer& sourceLayer)
781 {
782     BEGIN_BLOCK_OBJC_EXCEPTIONS
783     [m_layer setFilters:[sourceLayer.platformLayer() filters]];
784     END_BLOCK_OBJC_EXCEPTIONS
785 }
786
787 bool PlatformCALayerCocoa::filtersCanBeComposited(const FilterOperations& filters)
788 {
789     // Return false if there are no filters to avoid needless work
790     if (!filters.size())
791         return false;
792     
793     for (unsigned i = 0; i < filters.size(); ++i) {
794         const FilterOperation* filterOperation = filters.at(i);
795         switch (filterOperation->type()) {
796         case FilterOperation::REFERENCE:
797             return false;
798         case FilterOperation::DROP_SHADOW:
799             // FIXME: For now we can only handle drop-shadow is if it's last in the list
800             if (i < (filters.size() - 1))
801                 return false;
802             break;
803         default:
804             break;
805         }
806     }
807
808     return true;
809 }
810
811 #if ENABLE(CSS_COMPOSITING)
812 void PlatformCALayerCocoa::setBlendMode(BlendMode blendMode)
813 {
814     PlatformCAFilters::setBlendingFiltersOnLayer(platformLayer(), blendMode);
815 }
816 #endif
817
818 void PlatformCALayerCocoa::setName(const String& value)
819 {
820     BEGIN_BLOCK_OBJC_EXCEPTIONS
821     [m_layer setName:value];
822     END_BLOCK_OBJC_EXCEPTIONS
823 }
824
825 void PlatformCALayerCocoa::setSpeed(float value)
826 {
827     BEGIN_BLOCK_OBJC_EXCEPTIONS
828     [m_layer setSpeed:value];
829     END_BLOCK_OBJC_EXCEPTIONS
830 }
831
832 void PlatformCALayerCocoa::setTimeOffset(CFTimeInterval value)
833 {
834     BEGIN_BLOCK_OBJC_EXCEPTIONS
835     [m_layer setTimeOffset:value];
836     END_BLOCK_OBJC_EXCEPTIONS
837 }
838
839 float PlatformCALayerCocoa::contentsScale() const
840 {
841     return [m_layer contentsScale];
842 }
843
844 void PlatformCALayerCocoa::setContentsScale(float value)
845 {
846     BEGIN_BLOCK_OBJC_EXCEPTIONS
847     [m_layer setContentsScale:value];
848 #if PLATFORM(IOS)
849     [m_layer setRasterizationScale:value];
850 #endif
851     END_BLOCK_OBJC_EXCEPTIONS
852 }
853
854 float PlatformCALayerCocoa::cornerRadius() const
855 {
856     return [m_layer cornerRadius];
857 }
858
859 void PlatformCALayerCocoa::setCornerRadius(float value)
860 {
861     BEGIN_BLOCK_OBJC_EXCEPTIONS
862     [m_layer setCornerRadius:value];
863     END_BLOCK_OBJC_EXCEPTIONS
864 }
865
866 void PlatformCALayerCocoa::setEdgeAntialiasingMask(unsigned mask)
867 {
868     BEGIN_BLOCK_OBJC_EXCEPTIONS
869     [m_layer setEdgeAntialiasingMask:mask];
870     END_BLOCK_OBJC_EXCEPTIONS
871 }
872
873 FloatRoundedRect PlatformCALayerCocoa::shapeRoundedRect() const
874 {
875     ASSERT(m_layerType == LayerTypeShapeLayer);
876     if (m_shapeRoundedRect)
877         return *m_shapeRoundedRect;
878
879     return FloatRoundedRect();
880 }
881
882 void PlatformCALayerCocoa::setShapeRoundedRect(const FloatRoundedRect& roundedRect)
883 {
884     ASSERT(m_layerType == LayerTypeShapeLayer);
885     m_shapeRoundedRect = std::make_unique<FloatRoundedRect>(roundedRect);
886
887     BEGIN_BLOCK_OBJC_EXCEPTIONS
888     Path shapePath;
889     shapePath.addRoundedRect(roundedRect);
890     [(CAShapeLayer *)m_layer setPath:shapePath.platformPath()];
891     END_BLOCK_OBJC_EXCEPTIONS
892 }
893
894 WindRule PlatformCALayerCocoa::shapeWindRule() const
895 {
896     ASSERT(m_layerType == LayerTypeShapeLayer);
897
898     NSString *fillRule = [(CAShapeLayer *)m_layer fillRule];
899     if ([fillRule isEqualToString:@"even-odd"])
900         return RULE_EVENODD;
901
902     return RULE_NONZERO;
903 }
904
905 void PlatformCALayerCocoa::setShapeWindRule(WindRule windRule)
906 {
907     ASSERT(m_layerType == LayerTypeShapeLayer);
908
909     switch (windRule) {
910     case RULE_NONZERO:
911         [(CAShapeLayer *)m_layer setFillRule:@"non-zero"];
912         break;
913     case RULE_EVENODD:
914         [(CAShapeLayer *)m_layer setFillRule:@"even-odd"];
915         break;
916     }
917 }
918
919 Path PlatformCALayerCocoa::shapePath() const
920 {
921     ASSERT(m_layerType == LayerTypeShapeLayer);
922
923     BEGIN_BLOCK_OBJC_EXCEPTIONS
924     return Path(CGPathCreateMutableCopy([(CAShapeLayer *)m_layer path]));
925     END_BLOCK_OBJC_EXCEPTIONS
926 }
927
928 void PlatformCALayerCocoa::setShapePath(const Path& path)
929 {
930     ASSERT(m_layerType == LayerTypeShapeLayer);
931
932     BEGIN_BLOCK_OBJC_EXCEPTIONS
933     [(CAShapeLayer *)m_layer setPath:path.platformPath()];
934     END_BLOCK_OBJC_EXCEPTIONS
935 }
936
937 bool PlatformCALayerCocoa::requiresCustomAppearanceUpdateOnBoundsChange() const
938 {
939     return m_customAppearance == GraphicsLayer::ScrollingShadow;
940 }
941
942 void PlatformCALayerCocoa::updateCustomAppearance(GraphicsLayer::CustomAppearance appearance)
943 {
944     if (m_customAppearance == appearance)
945         return;
946
947     m_customAppearance = appearance;
948
949 #if ENABLE(RUBBER_BANDING)
950     switch (appearance) {
951     case GraphicsLayer::NoCustomAppearance:
952     case GraphicsLayer::LightBackdropAppearance:
953     case GraphicsLayer::DarkBackdropAppearance:
954         ScrollbarThemeMac::removeOverhangAreaBackground(platformLayer());
955         ScrollbarThemeMac::removeOverhangAreaShadow(platformLayer());
956         break;
957     case GraphicsLayer::ScrollingOverhang:
958         ScrollbarThemeMac::setUpOverhangAreaBackground(platformLayer());
959         break;
960     case GraphicsLayer::ScrollingShadow:
961         ScrollbarThemeMac::setUpOverhangAreaShadow(platformLayer());
962         break;
963     }
964 #endif
965 }
966
967 TiledBacking* PlatformCALayerCocoa::tiledBacking()
968 {
969     if (!usesTiledBackingLayer())
970         return nullptr;
971
972     WebTiledBackingLayer *tiledBackingLayer = static_cast<WebTiledBackingLayer *>(m_layer.get());
973     return [tiledBackingLayer tiledBacking];
974 }
975
976 #if PLATFORM(IOS)
977 bool PlatformCALayer::isWebLayer()
978 {
979     BOOL result = NO;
980     BEGIN_BLOCK_OBJC_EXCEPTIONS
981     result = [m_layer isKindOfClass:[WebLayer self]];
982     END_BLOCK_OBJC_EXCEPTIONS
983     return result;
984 }
985
986 void PlatformCALayer::setBoundsOnMainThread(CGRect bounds)
987 {
988     CALayer *layer = m_layer.get();
989     dispatch_async(dispatch_get_main_queue(), ^{
990         BEGIN_BLOCK_OBJC_EXCEPTIONS
991         [layer setBounds:bounds];
992         END_BLOCK_OBJC_EXCEPTIONS
993     });
994 }
995
996 void PlatformCALayer::setPositionOnMainThread(CGPoint position)
997 {
998     CALayer *layer = m_layer.get();
999     dispatch_async(dispatch_get_main_queue(), ^{
1000         BEGIN_BLOCK_OBJC_EXCEPTIONS
1001         [layer setPosition:position];
1002         END_BLOCK_OBJC_EXCEPTIONS
1003     });
1004 }
1005
1006 void PlatformCALayer::setAnchorPointOnMainThread(FloatPoint3D value)
1007 {
1008     CALayer *layer = m_layer.get();
1009     dispatch_async(dispatch_get_main_queue(), ^{
1010         BEGIN_BLOCK_OBJC_EXCEPTIONS
1011         [layer setAnchorPoint:CGPointMake(value.x(), value.y())];
1012         [layer setAnchorPointZ:value.z()];
1013         END_BLOCK_OBJC_EXCEPTIONS
1014     });
1015 }
1016 #endif // PLATFORM(IOS)
1017
1018 PlatformCALayer::RepaintRectList PlatformCALayer::collectRectsToPaint(CGContextRef context, PlatformCALayer* platformCALayer)
1019 {
1020     __block double totalRectArea = 0;
1021     __block unsigned rectCount = 0;
1022     __block RepaintRectList dirtyRects;
1023     
1024     platformCALayer->enumerateRectsBeingDrawn(context, ^(CGRect rect) {
1025         if (++rectCount > webLayerMaxRectsToPaint)
1026             return;
1027         
1028         totalRectArea += rect.size.width * rect.size.height;
1029         dirtyRects.append(rect);
1030     });
1031     
1032     FloatRect clipBounds = CGContextGetClipBoundingBox(context);
1033     double clipArea = clipBounds.width() * clipBounds.height();
1034     
1035     if (rectCount >= webLayerMaxRectsToPaint || totalRectArea >= clipArea * webLayerWastedSpaceThreshold) {
1036         dirtyRects.clear();
1037         dirtyRects.append(clipBounds);
1038     }
1039     
1040     return dirtyRects;
1041 }
1042
1043 void PlatformCALayer::drawLayerContents(CGContextRef context, WebCore::PlatformCALayer* platformCALayer, RepaintRectList& dirtyRects)
1044 {
1045     WebCore::PlatformCALayerClient* layerContents = platformCALayer->owner();
1046     if (!layerContents)
1047         return;
1048     
1049 #if PLATFORM(IOS)
1050     WKSetCurrentGraphicsContext(context);
1051 #endif
1052     
1053     CGContextSaveGState(context);
1054     
1055     // We never use CompositingCoordinatesBottomUp on Mac.
1056     ASSERT(layerContents->platformCALayerContentsOrientation() == GraphicsLayer::CompositingCoordinatesTopDown);
1057     
1058 #if PLATFORM(IOS)
1059     FontAntialiasingStateSaver fontAntialiasingState(context, [platformCALayer->platformLayer() isOpaque]);
1060     fontAntialiasingState.setup([WAKWindow hasLandscapeOrientation]);
1061 #else
1062     [NSGraphicsContext saveGraphicsState];
1063     
1064     // Set up an NSGraphicsContext for the context, so that parts of AppKit that rely on
1065     // the current NSGraphicsContext (e.g. NSCell drawing) get the right one.
1066     NSGraphicsContext* layerContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:YES];
1067     [NSGraphicsContext setCurrentContext:layerContext];
1068 #endif
1069     
1070     {
1071         GraphicsContext graphicsContext(context);
1072         graphicsContext.setIsCALayerContext(true);
1073         graphicsContext.setIsAcceleratedContext(platformCALayer->acceleratesDrawing());
1074         
1075         if (!layerContents->platformCALayerContentsOpaque()) {
1076             // Turn off font smoothing to improve the appearance of text rendered onto a transparent background.
1077             graphicsContext.setShouldSmoothFonts(false);
1078         }
1079         
1080 #if PLATFORM(MAC)
1081         // It's important to get the clip from the context, because it may be significantly
1082         // smaller than the layer bounds (e.g. tiled layers)
1083         ThemeMac::setFocusRingClipRect(CGContextGetClipBoundingBox(context));
1084 #endif
1085         
1086         for (const auto& rect : dirtyRects) {
1087             GraphicsContextStateSaver stateSaver(graphicsContext);
1088             graphicsContext.clip(rect);
1089             
1090             layerContents->platformCALayerPaintContents(platformCALayer, graphicsContext, rect);
1091         }
1092         
1093 #if PLATFORM(IOS)
1094         fontAntialiasingState.restore();
1095 #else
1096         ThemeMac::setFocusRingClipRect(FloatRect());
1097         
1098         [NSGraphicsContext restoreGraphicsState];
1099 #endif
1100     }
1101
1102     CGContextRestoreGState(context);
1103
1104     // Re-fetch the layer owner, since <rdar://problem/9125151> indicates that it might have been destroyed during painting.
1105     layerContents = platformCALayer->owner();
1106     ASSERT(layerContents);
1107     
1108     // Always update the repaint count so that it's accurate even if the count itself is not shown. This will be useful
1109     // for the Web Inspector feeding this information through the LayerTreeAgent.
1110     int repaintCount = layerContents->platformCALayerIncrementRepaintCount(platformCALayer);
1111
1112     if (!platformCALayer->usesTiledBackingLayer() && layerContents && layerContents->platformCALayerShowRepaintCounter(platformCALayer))
1113         drawRepaintIndicator(context, platformCALayer, repaintCount, nullptr);
1114 }
1115
1116 CGRect PlatformCALayer::frameForLayer(const PlatformLayer* tileLayer)
1117 {
1118     return [tileLayer frame];
1119 }
1120
1121 PassRefPtr<PlatformCALayer> PlatformCALayerCocoa::createCompatibleLayer(PlatformCALayer::LayerType layerType, PlatformCALayerClient* client) const
1122 {
1123     return PlatformCALayerCocoa::create(layerType, client);
1124 }
1125
1126 void PlatformCALayerCocoa::enumerateRectsBeingDrawn(CGContextRef context, void (^block)(CGRect))
1127 {
1128     wkCALayerEnumerateRectsBeingDrawnWithBlock(m_layer.get(), context, block);
1129 }
1130
1131 AVPlayerLayer *PlatformCALayerCocoa::avPlayerLayer() const
1132 {
1133     if (layerType() != LayerTypeAVPlayerLayer)
1134         return nil;
1135
1136     if ([platformLayer() isKindOfClass:getAVPlayerLayerClass()])
1137         return static_cast<AVPlayerLayer *>(platformLayer());
1138
1139     if ([platformLayer() isKindOfClass:objc_getClass("WebVideoContainerLayer")]) {
1140         ASSERT([platformLayer() sublayers].count == 1);
1141         ASSERT([[platformLayer() sublayers][0] isKindOfClass:getAVPlayerLayerClass()]);
1142         return static_cast<AVPlayerLayer *>([platformLayer() sublayers][0]);
1143     }
1144
1145     ASSERT_NOT_REACHED();
1146     return nil;
1147 }