1/*
2 * Copyright (C) 2009 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 COMPUTER, 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#if USE(ACCELERATED_COMPOSITING)
29
30#import "WebLayer.h"
31
32#import "GraphicsContext.h"
33#import "GraphicsLayerCA.h"
34#import "PlatformCALayer.h"
35#import <objc/objc-runtime.h>
36#import <QuartzCore/QuartzCore.h>
37#import <wtf/UnusedParam.h>
38
39using namespace WebCore;
40
41@implementation WebLayer
42
43void drawLayerContents(CGContextRef context, CALayer *layer, WebCore::PlatformCALayer* platformLayer)
44{
45    WebCore::PlatformCALayerClient* layerContents = platformLayer->owner();
46    if (!layerContents)
47        return;
48
49    CGContextSaveGState(context);
50
51    CGRect layerBounds = [layer bounds];
52    if (layerContents->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesBottomUp) {
53        CGContextScaleCTM(context, 1, -1);
54        CGContextTranslateCTM(context, 0, -layerBounds.size.height);
55    }
56
57    [NSGraphicsContext saveGraphicsState];
58
59    // Set up an NSGraphicsContext for the context, so that parts of AppKit that rely on
60    // the current NSGraphicsContext (e.g. NSCell drawing) get the right one.
61    NSGraphicsContext* layerContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:YES];
62    [NSGraphicsContext setCurrentContext:layerContext];
63
64    GraphicsContext graphicsContext(context);
65    graphicsContext.setIsCALayerContext(true);
66    graphicsContext.setIsAcceleratedContext(platformLayer->acceleratesDrawing());
67
68    if (!layerContents->platformCALayerContentsOpaque()) {
69        // Turn off font smoothing to improve the appearance of text rendered onto a transparent background.
70        graphicsContext.setShouldSmoothFonts(false);
71    }
72
73    // It's important to get the clip from the context, because it may be significantly
74    // smaller than the layer bounds (e.g. tiled layers)
75    CGRect clipBounds = CGContextGetClipBoundingBox(context);
76    IntRect clip(enclosingIntRect(clipBounds));
77    layerContents->platformCALayerPaintContents(graphicsContext, clip);
78
79    [NSGraphicsContext restoreGraphicsState];
80
81    if (layerContents->platformCALayerShowRepaintCounter()) {
82        bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]];
83
84        char text[16]; // that's a lot of repaints
85        snprintf(text, sizeof(text), "%d", layerContents->platformCALayerIncrementRepaintCount());
86
87        CGContextSaveGState(context);
88        if (isTiledLayer)
89            CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 0.8f);
90        else
91            CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f);
92
93        CGRect aBounds = layerBounds;
94
95        aBounds.size.width = 10 + 12 * strlen(text);
96        aBounds.size.height = 25;
97        CGContextFillRect(context, aBounds);
98
99        CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f);
100
101        CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f));
102        CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman);
103        CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text));
104
105        CGContextRestoreGState(context);
106    }
107
108    CGContextRestoreGState(context);
109}
110
111void setLayerNeedsDisplayInRect(CALayer *layer, WebCore::PlatformCALayerClient* layerContents, CGRect rect)
112{
113    if (layerContents && layerContents->platformCALayerDrawsContent()) {
114        struct objc_super layerSuper = { layer, class_getSuperclass(object_getClass(layer)) };
115#if defined(BUILDING_ON_LEOPARD)
116        rect = CGRectApplyAffineTransform(rect, [layer contentsTransform]);
117#else
118        if (layerContents->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesBottomUp)
119            rect.origin.y = [layer bounds].size.height - rect.origin.y - rect.size.height;
120#endif
121        objc_msgSendSuper(&layerSuper, @selector(setNeedsDisplayInRect:), rect);
122
123#ifndef NDEBUG
124        if (layerContents->platformCALayerShowRepaintCounter()) {
125            CGRect bounds = [layer bounds];
126            CGRect indicatorRect = CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25);
127#if defined(BUILDING_ON_LEOPARD)
128            indicatorRect = CGRectApplyAffineTransform(indicatorRect, [layer contentsTransform]);
129#else
130            if (layerContents->platformCALayerContentsOrientation() == WebCore::GraphicsLayer::CompositingCoordinatesBottomUp)
131                indicatorRect.origin.y = [layer bounds].size.height - indicatorRect.origin.y - indicatorRect.size.height;
132#endif
133            objc_msgSendSuper(&layerSuper, @selector(setNeedsDisplayInRect:), indicatorRect);
134        }
135#endif
136    }
137}
138
139// Disable default animations
140- (id<CAAction>)actionForKey:(NSString *)key
141{
142    UNUSED_PARAM(key);
143    return nil;
144}
145
146- (void)setNeedsDisplay
147{
148    PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
149    if (layer && layer->owner() && layer->owner()->platformCALayerDrawsContent())
150        [super setNeedsDisplay];
151}
152
153- (void)setNeedsDisplayInRect:(CGRect)dirtyRect
154{
155    PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
156    if (layer)
157        setLayerNeedsDisplayInRect(self, layer->owner(), dirtyRect);
158}
159
160- (void)display
161{
162    [super display];
163    PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
164    if (layer && layer->owner())
165        layer->owner()->platformCALayerLayerDidDisplay(self);
166}
167
168- (void)drawInContext:(CGContextRef)context
169{
170    PlatformCALayer* layer = PlatformCALayer::platformCALayer(self);
171    if (layer)
172        drawLayerContents(context, self, layer);
173}
174
175@end // implementation WebLayer
176
177// MARK: -
178
179#ifndef NDEBUG
180
181@implementation CALayer(ExtendedDescription)
182
183- (NSString*)_descriptionWithPrefix:(NSString*)inPrefix
184{
185    CGRect aBounds = [self bounds];
186    CGPoint aPos = [self position];
187
188    NSString* selfString = [NSString stringWithFormat:@"%@<%@ 0x%08x> \"%@\" bounds(%.1f, %.1f, %.1f, %.1f) pos(%.1f, %.1f), sublayers=%d masking=%d",
189            inPrefix,
190            [self class],
191            self,
192            [self name],
193            aBounds.origin.x, aBounds.origin.y, aBounds.size.width, aBounds.size.height,
194            aPos.x, aPos.y,
195            [[self sublayers] count],
196            [self masksToBounds]];
197
198    NSMutableString* curDesc = [NSMutableString stringWithString:selfString];
199
200    if ([[self sublayers] count] > 0)
201        [curDesc appendString:@"\n"];
202
203    NSString* sublayerPrefix = [inPrefix stringByAppendingString:@"\t"];
204
205    NSEnumerator* sublayersEnum = [[self sublayers] objectEnumerator];
206    CALayer* curLayer;
207    while ((curLayer = [sublayersEnum nextObject]))
208        [curDesc appendString:[curLayer _descriptionWithPrefix:sublayerPrefix]];
209
210    if ([[self sublayers] count] == 0)
211        [curDesc appendString:@"\n"];
212
213    return curDesc;
214}
215
216- (NSString*)extendedDescription
217{
218    return [self _descriptionWithPrefix:@""];
219}
220
221@end  // implementation WebLayer(ExtendedDescription)
222
223#endif // NDEBUG
224
225#endif // USE(ACCELERATED_COMPOSITING)
226