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