Reviewed by Eric. Rubber stamped by Oliver.
[WebKit-https.git] / WebCore / platform / graphics / svg / cg / SVGResourceMaskerCg.mm
1 /*
2  * Copyright (C) 2005, 2006 Alexander Kellett <lypanov@kde.org>
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 COMPUTER, 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 #ifdef SVG_SUPPORT
29 #import "SVGResourceFilter.h"
30 #import "SVGResourceMasker.h"
31 #import "SVGResourceImage.h"
32 #import "SVGRenderStyle.h"
33
34 #import "GraphicsContext.h"
35 #import "CgSupport.h"
36
37 #import <QuartzCore/CoreImage.h>
38 #import <QuartzCore/CIFilter.h>
39 #
40 namespace WebCore {
41
42 static CIImage* applyLuminanceToAlphaFilter(CIImage* inputImage)
43 {
44     CIFilter* luminanceToAlpha = [CIFilter filterWithName:@"CIColorMatrix"];
45     [luminanceToAlpha setDefaults];
46     CGFloat alpha[4] = {0.2125, 0.7154, 0.0721, 0};
47     CGFloat zero[4] = {0, 0, 0, 0};
48     [luminanceToAlpha setValue:inputImage forKey:@"inputImage"];  
49     [luminanceToAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputRVector"];
50     [luminanceToAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputGVector"];
51     [luminanceToAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputBVector"];
52     [luminanceToAlpha setValue:[CIVector vectorWithValues:alpha count:4] forKey:@"inputAVector"];
53     [luminanceToAlpha setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputBiasVector"];
54     return [luminanceToAlpha valueForKey:@"outputImage"];
55 }
56
57 static CIImage* applyExpandAlphatoGrayscaleFilter(CIImage* inputImage)
58 {
59     CIFilter* alphaToGrayscale = [CIFilter filterWithName:@"CIColorMatrix"];
60     CGFloat zero[4] = {0, 0, 0, 0};
61     [alphaToGrayscale setDefaults];
62     [alphaToGrayscale setValue:inputImage forKey:@"inputImage"];
63     [alphaToGrayscale setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputRVector"];
64     [alphaToGrayscale setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputGVector"];
65     [alphaToGrayscale setValue:[CIVector vectorWithValues:zero count:4] forKey:@"inputBVector"];
66     [alphaToGrayscale setValue:[CIVector vectorWithX:0.0 Y:0.0 Z:0.0 W:1.0] forKey:@"inputAVector"];
67     [alphaToGrayscale setValue:[CIVector vectorWithX:1.0 Y:1.0 Z:1.0 W:0.0] forKey:@"inputBiasVector"];
68     return [alphaToGrayscale valueForKey:@"outputImage"];
69 }
70
71 static CIImage* transformImageIntoGrayscaleMask(CIImage* inputImage)
72 {
73     CIFilter* blackBackground = [CIFilter filterWithName:@"CIConstantColorGenerator"];
74     [blackBackground setValue:[CIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0] forKey:@"inputColor"];
75
76     CIFilter* layerOverBlack = [CIFilter filterWithName:@"CISourceOverCompositing"];
77     [layerOverBlack setValue:[blackBackground valueForKey:@"outputImage"] forKey:@"inputBackgroundImage"];  
78     [layerOverBlack setValue:inputImage forKey:@"inputImage"];  
79
80     CIImage* luminanceAlpha = applyLuminanceToAlphaFilter([layerOverBlack valueForKey:@"outputImage"]);
81     CIImage* luminanceAsGrayscale = applyExpandAlphatoGrayscaleFilter(luminanceAlpha);
82     CIImage* alphaAsGrayscale = applyExpandAlphatoGrayscaleFilter(inputImage);
83
84     CIFilter* multipliedGrayscale = [CIFilter filterWithName:@"CIMultiplyCompositing"];
85     [multipliedGrayscale setValue:luminanceAsGrayscale forKey:@"inputBackgroundImage"];  
86     [multipliedGrayscale setValue:alphaAsGrayscale forKey:@"inputImage"];  
87     return [multipliedGrayscale valueForKey:@"outputImage"];
88 }
89
90 void SVGResourceMasker::applyMask(GraphicsContext* context, const FloatRect& boundingBox) const
91 {
92     if (!m_mask)
93         return;
94     // Create grayscale bitmap context
95     int width = m_mask->size().width();
96     int height = m_mask->size().height();
97     void* imageBuffer = fastMalloc(width * height);
98     CGColorSpaceRef grayColorSpace = CGColorSpaceCreateDeviceGray();
99     CGContextRef grayscaleContext = CGBitmapContextCreate(imageBuffer, width, height, 8, width, grayColorSpace, kCGImageAlphaNone);
100     CGColorSpaceRelease(grayColorSpace);
101     CIContext* ciGrayscaleContext = [CIContext contextWithCGContext:grayscaleContext options:nil];
102
103     SVGResourceImage* maskImage = static_cast<SVGResourceImage*>(m_mask.get());
104     CIImage* grayscaleMask = transformImageIntoGrayscaleMask([CIImage imageWithCGLayer:maskImage->cgLayer()]);
105     [ciGrayscaleContext drawImage:grayscaleMask atPoint:CGPointZero fromRect:CGRectMake(0, 0, width, height)];
106
107     CGImageRef grayscaleImage = CGBitmapContextCreateImage(grayscaleContext);
108     CGContextRef cgContext = context->platformContext();
109     CGContextClipToMask(cgContext, CGRectMake(0, 0, width, height), grayscaleImage);
110
111     CGImageRelease(grayscaleImage);
112     CGContextRelease(grayscaleContext);
113     fastFree(imageBuffer);
114 }
115
116 } // namespace WebCore
117
118 #endif // SVG_SUPPORT