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