[CSS Blending] Remove support for non-separable blend modes from mix-blend-mode
[WebKit-https.git] / Source / WebCore / platform / graphics / ca / mac / PlatformCAFiltersMac.mm
1 /*
2  * Copyright (C) 2013 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 #if ENABLE(CSS_FILTERS)
29
30 #import "PlatformCAFilters.h"
31 #import "BlockExceptions.h"
32 #import "FloatConversion.h"
33 #import "LengthFunctions.h" // This is a layering violation.
34 #import "PlatformCAFiltersMac.h"
35 #import "PlatformCALayerMac.h"
36 #import <QuartzCore/QuartzCore.h>
37
38 using namespace WebCore;
39
40 // FIXME: Should share these values with FilterEffectRenderer::build() (https://bugs.webkit.org/show_bug.cgi?id=76008).
41 static const double sepiaFullConstants[3][3] = {
42     { 0.393, 0.769, 0.189 },
43     { 0.349, 0.686, 0.168 },
44     { 0.272, 0.534, 0.131 }
45 };
46
47 static const double sepiaNoneConstants[3][3] = {
48     { 1, 0, 0 },
49     { 0, 1, 0 },
50     { 0, 0, 1 }
51 };
52
53 void PlatformCAFilters::setFiltersOnLayer(PlatformLayer* layer, const FilterOperations& filters)
54 {
55     if (!filters.size()) {
56         BEGIN_BLOCK_OBJC_EXCEPTIONS
57         [layer setFilters:nil];
58         // FIXME: this adds shadow properties to the layer even when it had none.
59         [layer setShadowOffset:CGSizeZero];
60         [layer setShadowColor:nil];
61         [layer setShadowRadius:0];
62         [layer setShadowOpacity:0];
63         END_BLOCK_OBJC_EXCEPTIONS
64         return;
65     }
66     
67     // Assume filtersCanBeComposited was called and it returned true.
68     ASSERT(PlatformCALayerMac::filtersCanBeComposited(filters));
69     
70     BEGIN_BLOCK_OBJC_EXCEPTIONS
71     
72     RetainPtr<NSMutableArray> array = adoptNS([[NSMutableArray alloc] init]);
73     
74     for (unsigned i = 0; i < filters.size(); ++i) {
75         String filterName = String::format("filter_%d", i);
76         const FilterOperation* filterOperation = filters.at(i);
77         switch (filterOperation->type()) {
78         case FilterOperation::DEFAULT:
79             ASSERT_NOT_REACHED();
80             break;
81         case FilterOperation::DROP_SHADOW: {
82             // FIXME: For now assume drop shadow is the last filter, put it on the layer.
83             // <rdar://problem/10959969> Handle case where drop-shadow is not the last filter.
84             const DropShadowFilterOperation* op = toDropShadowFilterOperation(filterOperation);
85             [layer setShadowOffset:CGSizeMake(op->x(), op->y())];
86
87             CGFloat components[4];
88             op->color().getRGBA(components[0], components[1], components[2], components[3]);
89             RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
90             RetainPtr<CGColorRef> color = adoptCF(CGColorCreate(colorSpace.get(), components));
91             [layer setShadowColor:color.get()];
92             [layer setShadowRadius:op->stdDeviation()];
93             [layer setShadowOpacity:1];
94             break;
95         }
96 #if USE_CA_FILTERS
97         case FilterOperation::GRAYSCALE: {
98             const BasicColorMatrixFilterOperation* op = toBasicColorMatrixFilterOperation(filterOperation);
99             CAFilter *filter = [CAFilter filterWithType:kCAFilterColorMonochrome];
100             [filter setValue:[NSNumber numberWithFloat:op->amount()] forKey:@"inputAmount"];
101             [filter setName:filterName];
102             [array.get() addObject:filter];
103             break;
104         }
105         case FilterOperation::SEPIA: {
106             RetainPtr<NSValue> colorMatrixValue = PlatformCAFilters::colorMatrixValueForFilter(filterOperation->type(), filterOperation);
107             CAFilter *filter = [CAFilter filterWithType:kCAFilterColorMatrix];
108             [filter setValue:colorMatrixValue.get() forKey:@"inputColorMatrix"];
109             [filter setName:filterName];
110             [array.get() addObject:filter];
111             break;
112         }
113         case FilterOperation::SATURATE: {
114             const BasicColorMatrixFilterOperation* op = toBasicColorMatrixFilterOperation(filterOperation);
115             CAFilter *filter = [CAFilter filterWithType:kCAFilterColorSaturate];
116             [filter setValue:[NSNumber numberWithFloat:op->amount()] forKey:@"inputAmount"];
117             [filter setName:filterName];
118             [array.get() addObject:filter];
119             break;
120         }
121         case FilterOperation::HUE_ROTATE: {
122             const BasicColorMatrixFilterOperation* op = toBasicColorMatrixFilterOperation(filterOperation);
123             CAFilter *filter = [CAFilter filterWithType:kCAFilterColorHueRotate];
124             [filter setValue:[NSNumber numberWithFloat:deg2rad(op->amount())] forKey:@"inputAngle"];
125             [filter setName:@"hueRotate"];
126             [filter setName:filterName];
127             [array.get() addObject:filter];
128             break;
129         }
130         case FilterOperation::INVERT: {
131             RetainPtr<NSValue> colorMatrixValue = PlatformCAFilters::colorMatrixValueForFilter(filterOperation->type(), filterOperation);
132             CAFilter *filter = [CAFilter filterWithType:kCAFilterColorMatrix];
133             [filter setValue:colorMatrixValue.get() forKey:@"inputColorMatrix"];
134             [filter setName:filterName];
135             [array.get() addObject:filter];
136             break;
137         }
138         case FilterOperation::OPACITY: {
139             RetainPtr<NSValue> colorMatrixValue = PlatformCAFilters::colorMatrixValueForFilter(filterOperation->type(), filterOperation);
140             CAFilter *filter = [CAFilter filterWithType:kCAFilterColorMatrix];
141             [filter setValue:colorMatrixValue.get() forKey:@"inputColorMatrix"];
142             [filter setName:filterName];
143             [array.get() addObject:filter];
144             break;
145         }
146         case FilterOperation::BRIGHTNESS: {
147             RetainPtr<NSValue> colorMatrixValue = PlatformCAFilters::colorMatrixValueForFilter(filterOperation->type(), filterOperation);
148             CAFilter *filter = [CAFilter filterWithType:kCAFilterColorMatrix];
149             [filter setValue:colorMatrixValue.get() forKey:@"inputColorMatrix"];
150             [filter setName:filterName];
151             [array.get() addObject:filter];
152             break;
153         }
154         case FilterOperation::CONTRAST: {
155             RetainPtr<NSValue> colorMatrixValue = PlatformCAFilters::colorMatrixValueForFilter(filterOperation->type(), filterOperation);
156             CAFilter *filter = [CAFilter filterWithType:kCAFilterColorMatrix];
157             [filter setValue:colorMatrixValue.get() forKey:@"inputColorMatrix"];
158             [filter setName:filterName];
159             [array.get() addObject:filter];
160             break;
161         }
162         case FilterOperation::BLUR: {
163             const BlurFilterOperation* op = toBlurFilterOperation(filterOperation);
164             CAFilter *filter = [CAFilter filterWithType:kCAFilterGaussianBlur];
165             [filter setValue:[NSNumber numberWithFloat:floatValueForLength(op->stdDeviation(), 0)] forKey:@"inputRadius"];
166             [filter setName:filterName];
167             [array.get() addObject:filter];
168             break;
169         }
170 #else
171         case FilterOperation::GRAYSCALE: {
172             const BasicColorMatrixFilterOperation* op = toBasicColorMatrixFilterOperation(filterOperation);
173             CIFilter* filter = [CIFilter filterWithName:@"CIColorMonochrome"];
174             [filter setDefaults];
175             [filter setValue:[NSNumber numberWithFloat:op->amount()] forKey:@"inputIntensity"];
176             [filter setValue:[CIColor colorWithRed:0.67 green:0.67 blue:0.67] forKey:@"inputColor"]; // Color derived empirically to match zero saturation levels.
177             [filter setName:filterName];
178             [array.get() addObject:filter];
179             break;
180         }
181         case FilterOperation::SEPIA: {
182             const BasicColorMatrixFilterOperation* op = toBasicColorMatrixFilterOperation(filterOperation);
183             CIFilter* filter = [CIFilter filterWithName:@"CIColorMatrix"];
184             [filter setDefaults];
185
186             double t = op->amount();
187             t = std::min(std::max(0.0, t), 1.0);
188             // FIXME: results don't match the software filter.
189             [filter setValue:[CIVector vectorWithX:WebCore::blend(sepiaNoneConstants[0][0], sepiaFullConstants[0][0], t)
190                                                  Y:WebCore::blend(sepiaNoneConstants[0][1], sepiaFullConstants[0][1], t)
191                                                  Z:WebCore::blend(sepiaNoneConstants[0][2], sepiaFullConstants[0][2], t) W:0] forKey:@"inputRVector"];
192             [filter setValue:[CIVector vectorWithX:WebCore::blend(sepiaNoneConstants[1][0], sepiaFullConstants[1][0], t)
193                                                  Y:WebCore::blend(sepiaNoneConstants[1][1], sepiaFullConstants[1][1], t)
194                                                  Z:WebCore::blend(sepiaNoneConstants[1][2], sepiaFullConstants[1][2], t) W:0] forKey:@"inputGVector"];
195             [filter setValue:[CIVector vectorWithX:WebCore::blend(sepiaNoneConstants[2][0], sepiaFullConstants[2][0], t)
196                                                  Y:WebCore::blend(sepiaNoneConstants[2][1], sepiaFullConstants[2][1], t)
197                                                  Z:WebCore::blend(sepiaNoneConstants[2][2], sepiaFullConstants[2][2], t) W:0] forKey:@"inputBVector"];
198             [filter setName:filterName];
199             [array.get() addObject:filter];
200             break;
201         }
202         case FilterOperation::SATURATE: {
203             const BasicColorMatrixFilterOperation* op = toBasicColorMatrixFilterOperation(filterOperation);
204             CIFilter* filter = [CIFilter filterWithName:@"CIColorControls"];
205             [filter setDefaults];
206             [filter setValue:[NSNumber numberWithFloat:op->amount()] forKey:@"inputSaturation"];
207             [filter setName:filterName];
208             [array.get() addObject:filter];
209             break;
210         }
211         case FilterOperation::HUE_ROTATE: {
212             const BasicColorMatrixFilterOperation* op = toBasicColorMatrixFilterOperation(filterOperation);
213             CIFilter* filter = [CIFilter filterWithName:@"CIHueAdjust"];
214             [filter setDefaults];
215
216             [filter setValue:[NSNumber numberWithFloat:deg2rad(op->amount())] forKey:@"inputAngle"];
217             [filter setName:filterName];
218             [array.get() addObject:filter];
219             break;
220         }
221         case FilterOperation::INVERT: {
222             const BasicComponentTransferFilterOperation* op = toBasicComponentTransferFilterOperation(filterOperation);
223             CIFilter* filter = [CIFilter filterWithName:@"CIColorMatrix"];
224             [filter setDefaults];
225
226             double multiplier = 1 - op->amount() * 2;
227
228             // FIXME: the results of this filter look wrong.
229             [filter setValue:[CIVector vectorWithX:multiplier Y:0 Z:0 W:0] forKey:@"inputRVector"];
230             [filter setValue:[CIVector vectorWithX:0 Y:multiplier Z:0 W:0] forKey:@"inputGVector"];
231             [filter setValue:[CIVector vectorWithX:0 Y:0 Z:multiplier W:0] forKey:@"inputBVector"];
232             [filter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:1] forKey:@"inputAVector"];
233             [filter setValue:[CIVector vectorWithX:op->amount() Y:op->amount() Z:op->amount() W:0] forKey:@"inputBiasVector"];
234             [filter setName:filterName];
235             [array.get() addObject:filter];
236             break;
237         }
238         case FilterOperation::OPACITY: {
239             const BasicComponentTransferFilterOperation* op = toBasicComponentTransferFilterOperation(filterOperation);
240             CIFilter* filter = [CIFilter filterWithName:@"CIColorMatrix"];
241             [filter setDefaults];
242
243             [filter setValue:[CIVector vectorWithX:1 Y:0 Z:0 W:0] forKey:@"inputRVector"];
244             [filter setValue:[CIVector vectorWithX:0 Y:1 Z:0 W:0] forKey:@"inputGVector"];
245             [filter setValue:[CIVector vectorWithX:0 Y:0 Z:1 W:0] forKey:@"inputBVector"];
246             [filter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:op->amount()] forKey:@"inputAVector"];
247             [filter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:0] forKey:@"inputBiasVector"];
248             [filter setName:filterName];
249             [array.get() addObject:filter];
250             break;
251         }
252         case FilterOperation::BRIGHTNESS: {
253             const BasicComponentTransferFilterOperation* op = toBasicComponentTransferFilterOperation(filterOperation);
254             CIFilter* filter = [CIFilter filterWithName:@"CIColorMatrix"];
255             [filter setDefaults];
256             double amount = op->amount();
257
258             [filter setValue:[CIVector vectorWithX:amount Y:0 Z:0 W:0] forKey:@"inputRVector"];
259             [filter setValue:[CIVector vectorWithX:0 Y:amount Z:0 W:0] forKey:@"inputGVector"];
260             [filter setValue:[CIVector vectorWithX:0 Y:0 Z:amount W:0] forKey:@"inputBVector"];
261             [filter setName:filterName];
262             [array.get() addObject:filter];
263             break;
264         }
265         case FilterOperation::CONTRAST: {
266             const BasicComponentTransferFilterOperation* op = toBasicComponentTransferFilterOperation(filterOperation);
267             CIFilter* filter = [CIFilter filterWithName:@"CIColorControls"];
268             [filter setDefaults];
269             [filter setValue:[NSNumber numberWithFloat:op->amount()] forKey:@"inputContrast"];
270             [filter setName:filterName];
271             [array.get() addObject:filter];
272             break;
273         }
274         case FilterOperation::BLUR: {
275             // FIXME: For now we ignore stdDeviationY.
276             const BlurFilterOperation* op = toBlurFilterOperation(filterOperation);
277             CIFilter* filter = [CIFilter filterWithName:@"CIGaussianBlur"];
278             [filter setDefaults];
279             [filter setValue:[NSNumber numberWithFloat:floatValueForLength(op->stdDeviation(), 0)] forKey:@"inputRadius"];
280             [filter setName:filterName];
281             [array.get() addObject:filter];
282             break;
283         }
284 #endif
285         case FilterOperation::PASSTHROUGH:
286             break;
287         default:
288             ASSERT(0);
289             break;
290         }
291     }
292
293     if ([array.get() count] > 0)
294         [layer setFilters:array.get()];
295     
296     END_BLOCK_OBJC_EXCEPTIONS
297 }
298
299 RetainPtr<NSValue> PlatformCAFilters::filterValueForOperation(const FilterOperation* operation, int internalFilterPropertyIndex)
300 {
301 #if USE_CA_FILTERS
302     UNUSED_PARAM(internalFilterPropertyIndex);
303 #endif
304     FilterOperation::OperationType type = operation->type();
305     RetainPtr<id> value;
306     
307     if (type == FilterOperation::DEFAULT) {
308         type = toDefaultFilterOperation(operation)->representedType();
309         operation = nullptr;
310     }
311     
312     switch (type) {
313     case FilterOperation::DEFAULT:
314         ASSERT_NOT_REACHED();
315         break;
316     case FilterOperation::GRAYSCALE: {
317         // CIFilter: inputIntensity
318         // CAFilter: inputAmount
319         double amount = 0;
320         if (operation)
321             amount = toBasicColorMatrixFilterOperation(operation)->amount();
322         
323         value = [NSNumber numberWithDouble:amount];
324         break;
325     }
326     case FilterOperation::SEPIA: {
327 #if USE_CA_FILTERS
328         // CAFilter: inputColorMatrix
329         value = PlatformCAFilters::colorMatrixValueForFilter(type, operation);
330 #else
331         // CIFilter: inputRVector, inputGVector, inputBVector
332         double amount = 0;
333         if (operation) {
334             const BasicColorMatrixFilterOperation* op = toBasicColorMatrixFilterOperation(operation);
335             amount = op->amount();
336         }
337
338         CIVector* rowVector = 0;
339         switch (internalFilterPropertyIndex) {
340         case 0: rowVector = [[CIVector alloc] initWithX:WebCore::blend(sepiaNoneConstants[0][0], sepiaFullConstants[0][0], amount)
341                                                       Y:WebCore::blend(sepiaNoneConstants[0][1], sepiaFullConstants[0][1], amount)
342                                                       Z:WebCore::blend(sepiaNoneConstants[0][2], sepiaFullConstants[0][2], amount) W:0]; break; // inputRVector
343         case 1: rowVector = [[CIVector alloc] initWithX:WebCore::blend(sepiaNoneConstants[1][0], sepiaFullConstants[1][0], amount)
344                                                       Y:WebCore::blend(sepiaNoneConstants[1][1], sepiaFullConstants[1][1], amount)
345                                                       Z:WebCore::blend(sepiaNoneConstants[1][2], sepiaFullConstants[1][2], amount) W:0]; break; // inputGVector
346         case 2: rowVector = [[CIVector alloc] initWithX:WebCore::blend(sepiaNoneConstants[2][0], sepiaFullConstants[2][0], amount)
347                                                       Y:WebCore::blend(sepiaNoneConstants[2][1], sepiaFullConstants[2][1], amount)
348                                                       Z:WebCore::blend(sepiaNoneConstants[2][2], sepiaFullConstants[2][2], amount) W:0]; break; // inputBVector
349         }
350         value = adoptNS(rowVector);
351 #endif
352         break;
353     }
354     case FilterOperation::SATURATE: {
355         // CIFilter: inputSaturation
356         // CAFilter: inputAmount
357         double amount = 1;
358         if (operation)
359             amount = toBasicColorMatrixFilterOperation(operation)->amount();
360         
361         value = [NSNumber numberWithDouble:amount];
362         break;
363     }
364     case FilterOperation::HUE_ROTATE: {
365         // Hue rotate CIFilter: inputAngle
366         // Hue rotate CAFilter: inputAngle
367         double amount = 0;
368         if (operation)
369             amount = toBasicColorMatrixFilterOperation(operation)->amount();
370         
371         amount = deg2rad(amount);
372         value = [NSNumber numberWithDouble:amount];
373         break;
374     }
375     case FilterOperation::INVERT: {
376 #if USE_CA_FILTERS
377         // CAFilter: inputColorMatrix
378         value = PlatformCAFilters::colorMatrixValueForFilter(type, operation);
379 #else
380         // CIFilter: inputRVector, inputGVector, inputBVector, inputBiasVector
381         double amount = 0;
382         if (operation)
383             amount = toBasicComponentTransferFilterOperation(operation)->amount();
384         
385         double multiplier = 1 - amount * 2;
386
387         // The color matrix animation for invert does a scale of each color component by a value that goes from 
388         // 1 (when amount is 0) to -1 (when amount is 1). Then the color values are offset by amount. This has the
389         // effect of performing the operation: c' = c * -1 + 1, which inverts the color.
390         CIVector* rowVector = 0;
391         switch (internalFilterPropertyIndex) {
392         case 0: rowVector = [[CIVector alloc] initWithX:multiplier Y:0 Z:0 W:0]; break; // inputRVector
393         case 1: rowVector = [[CIVector alloc] initWithX:0 Y:multiplier Z:0 W:0]; break; // inputGVector
394         case 2: rowVector = [[CIVector alloc] initWithX:0 Y:0 Z:multiplier W:0]; break; // inputBVector
395         case 3: rowVector = [[CIVector alloc] initWithX:amount Y:amount Z:amount W:0]; break; // inputBiasVector
396         }
397         value = adoptNS(rowVector);
398 #endif
399         break;
400     }
401     case FilterOperation::OPACITY: {
402 #if USE_CA_FILTERS
403         // Opacity CAFilter: inputColorMatrix
404         value = PlatformCAFilters::colorMatrixValueForFilter(type, operation);
405 #else
406         // Opacity CIFilter: inputAVector
407         double amount = 1;
408         if (operation)
409             amount = toBasicComponentTransferFilterOperation(operation)->amount();
410         
411         value = adoptNS([[CIVector alloc] initWithX:0 Y:0 Z:0 W:amount]);
412 #endif
413         break;
414     }
415     
416     case FilterOperation::BRIGHTNESS: {
417 #if USE_CA_FILTERS
418         // Brightness CAFilter: inputColorMatrix
419         value = PlatformCAFilters::colorMatrixValueForFilter(type, operation);
420 #else
421         // Brightness CIFilter: inputColorMatrix
422         double amount = 1;
423         if (operation)
424             amount = toBasicComponentTransferFilterOperation(operation)->amount();
425         
426         CIVector* rowVector = 0;
427         switch (internalFilterPropertyIndex) {
428         case 0: rowVector = [[CIVector alloc] initWithX:amount Y:0 Z:0 W:0]; break; // inputRVector
429         case 1: rowVector = [[CIVector alloc] initWithX:0 Y:amount Z:0 W:0]; break; // inputGVector
430         case 2: rowVector = [[CIVector alloc] initWithX:0 Y:0 Z:amount W:0]; break; // inputBVector
431         }
432         value = adoptNS(rowVector);
433 #endif
434         break;
435     }
436
437     case FilterOperation::CONTRAST: {
438 #if USE_CA_FILTERS
439         // Contrast CAFilter: inputColorMatrix
440         value = PlatformCAFilters::colorMatrixValueForFilter(type, operation);
441 #else
442         // Contrast CIFilter: inputContrast
443         double amount = 1;
444         if (operation)
445             amount = toBasicComponentTransferFilterOperation(operation)->amount();
446         
447         value = [NSNumber numberWithDouble:amount];
448 #endif
449         break;
450     }
451     case FilterOperation::BLUR: {
452         // CIFilter: inputRadius
453         // CAFilter: inputRadius
454         double amount = 0;
455         if (operation)
456             amount = floatValueForLength(toBlurFilterOperation(operation)->stdDeviation(), 0);
457         
458         value = [NSNumber numberWithDouble:amount];
459         break;
460     }
461     default:
462         break;
463     }
464     
465     return value;
466 }
467
468 #if USE_CA_FILTERS
469 RetainPtr<NSValue> PlatformCAFilters::colorMatrixValueForFilter(FilterOperation::OperationType type, const FilterOperation* filterOperation)
470 {
471     switch (type) {
472     case FilterOperation::SEPIA: {
473         double t = filterOperation ? toBasicColorMatrixFilterOperation(filterOperation)->amount() : 0;
474         t = std::min(std::max(0.0, t), 1.0);
475         CAColorMatrix colorMatrix = {
476             static_cast<float>(WebCore::blend(sepiaNoneConstants[0][0], sepiaFullConstants[0][0], t)),
477             static_cast<float>(WebCore::blend(sepiaNoneConstants[0][1], sepiaFullConstants[0][1], t)),
478             static_cast<float>(WebCore::blend(sepiaNoneConstants[0][2], sepiaFullConstants[0][2], t)), 0, 0,
479             
480             static_cast<float>(WebCore::blend(sepiaNoneConstants[1][0], sepiaFullConstants[1][0], t)),
481             static_cast<float>(WebCore::blend(sepiaNoneConstants[1][1], sepiaFullConstants[1][1], t)),
482             static_cast<float>(WebCore::blend(sepiaNoneConstants[1][2], sepiaFullConstants[1][2], t)), 0, 0,
483             
484             static_cast<float>(WebCore::blend(sepiaNoneConstants[2][0], sepiaFullConstants[2][0], t)),
485             static_cast<float>(WebCore::blend(sepiaNoneConstants[2][1], sepiaFullConstants[2][1], t)),
486             static_cast<float>(WebCore::blend(sepiaNoneConstants[2][2], sepiaFullConstants[2][2], t)), 0, 0,
487             0, 0, 0, 1, 0
488         };
489         return [NSValue valueWithCAColorMatrix:colorMatrix];
490     }
491     case FilterOperation::INVERT: {
492         float amount = filterOperation ? toBasicComponentTransferFilterOperation(filterOperation)->amount() : 0;
493         float multiplier = 1 - amount * 2;
494         CAColorMatrix colorMatrix = {
495             multiplier, 0, 0, 0, amount,
496             0, multiplier, 0, 0, amount,
497             0, 0, multiplier, 0, amount,
498             0, 0, 0, 1, 0
499         };
500         return [NSValue valueWithCAColorMatrix:colorMatrix];
501     }
502     case FilterOperation::OPACITY: {
503         float amount = filterOperation ? toBasicComponentTransferFilterOperation(filterOperation)->amount() : 1;
504         CAColorMatrix colorMatrix = {
505             1, 0, 0, 0, 0,
506             0, 1, 0, 0, 0,
507             0, 0, 1, 0, 0,
508             0, 0, 0, amount, 0
509         };
510         return [NSValue valueWithCAColorMatrix:colorMatrix];
511     }
512     case FilterOperation::CONTRAST: {
513         float amount = filterOperation ? toBasicComponentTransferFilterOperation(filterOperation)->amount() : 1;
514         float intercept = -0.5 * amount + 0.5;
515         CAColorMatrix colorMatrix = {
516             amount, 0, 0, 0, intercept,
517             0, amount, 0, 0, intercept,
518             0, 0, amount, 0, intercept,
519             0, 0, 0, 1, 0
520         };
521         return [NSValue valueWithCAColorMatrix:colorMatrix];
522     }
523     case FilterOperation::BRIGHTNESS: {
524         float amount = filterOperation ? toBasicComponentTransferFilterOperation(filterOperation)->amount() : 1;
525         CAColorMatrix colorMatrix = {
526             amount, 0, 0, 0, 0,
527             0, amount, 0, 0, 0,
528             0, 0, amount, 0, 0,
529             0, 0, 0, 1, 0
530         };
531         return [NSValue valueWithCAColorMatrix:colorMatrix];
532     }
533     default:
534         ASSERT_NOT_REACHED();
535         return 0;
536     }
537 }
538 #endif
539
540 void PlatformCAFilters::setBlendingFiltersOnLayer(PlatformLayer* layer, const BlendMode blendMode)
541 {
542 #if USE_CA_FILTERS
543     BEGIN_BLOCK_OBJC_EXCEPTIONS
544
545     CAFilter* filter = nil;
546
547     switch (blendMode) {
548         case BlendModeNormal:
549             // No need to set an actual filter object in this case.
550             break;
551         case BlendModeOverlay:
552             filter = [CAFilter filterWithType:kCAFilterOverlayBlendMode];
553             break;
554         case BlendModeColorDodge:
555             filter = [CAFilter filterWithType:kCAFilterColorDodgeBlendMode];
556             break;
557         case BlendModeColorBurn:
558             filter = [CAFilter filterWithType:kCAFilterColorBurnBlendMode];
559             break;
560         case BlendModeDarken:
561             filter = [CAFilter filterWithType:kCAFilterDarkenBlendMode];
562             break;
563         case BlendModeDifference:
564             filter = [CAFilter filterWithType:kCAFilterDifferenceBlendMode];
565             break;
566         case BlendModeExclusion:
567             filter = [CAFilter filterWithType:kCAFilterExclusionBlendMode];
568             break;
569         case BlendModeHardLight:
570             filter = [CAFilter filterWithType:kCAFilterHardLightBlendMode];
571             break;
572         case BlendModeMultiply:
573             filter = [CAFilter filterWithType:kCAFilterMultiplyBlendMode];
574             break;
575         case BlendModeLighten:
576             filter = [CAFilter filterWithType:kCAFilterLightenBlendMode];
577             break;
578         case BlendModeSoftLight:
579             filter = [CAFilter filterWithType:kCAFilterSoftLightBlendMode];
580             break;
581         case BlendModeScreen:
582             filter = [CAFilter filterWithType:kCAFilterScreenBlendMode];
583             break;
584         default:
585             ASSERT_NOT_REACHED();
586     }
587
588     [layer setCompositingFilter:filter];
589
590     END_BLOCK_OBJC_EXCEPTIONS
591 #else
592     UNUSED_PARAM(layer);
593     UNUSED_PARAM(blendMode);
594 #endif
595 }
596
597 int PlatformCAFilters::numAnimatedFilterProperties(FilterOperation::OperationType type)
598 {
599 #if USE_CA_FILTERS
600     switch (type) {
601     case FilterOperation::GRAYSCALE: return 1;
602     case FilterOperation::SEPIA: return 1;
603     case FilterOperation::SATURATE: return 1;
604     case FilterOperation::HUE_ROTATE: return 1;
605     case FilterOperation::INVERT: return 1;
606     case FilterOperation::OPACITY: return 1;
607     case FilterOperation::BRIGHTNESS: return 1;
608     case FilterOperation::CONTRAST: return 1;
609     case FilterOperation::BLUR: return 1;
610     default: return 0;
611     }
612 #else
613     switch (type) {
614     case FilterOperation::GRAYSCALE: return 1;
615     case FilterOperation::SEPIA: return 3;
616     case FilterOperation::SATURATE: return 1;
617     case FilterOperation::HUE_ROTATE: return 1;
618     case FilterOperation::INVERT: return 4;
619     case FilterOperation::OPACITY: return 1;
620     case FilterOperation::BRIGHTNESS: return 3;
621     case FilterOperation::CONTRAST: return 1;
622     case FilterOperation::BLUR: return 1;
623     default: return 0;
624     }
625 #endif
626 }
627
628 const char* PlatformCAFilters::animatedFilterPropertyName(FilterOperation::OperationType type, int internalFilterPropertyIndex)
629 {
630 #if USE_CA_FILTERS
631     UNUSED_PARAM(internalFilterPropertyIndex);
632     switch (type) {
633     case FilterOperation::GRAYSCALE: return "inputAmount";
634     case FilterOperation::SEPIA:return "inputColorMatrix";
635     case FilterOperation::SATURATE: return "inputAmount";
636     case FilterOperation::HUE_ROTATE: return "inputAngle";
637     case FilterOperation::INVERT: return "inputColorMatrix";
638     case FilterOperation::OPACITY: return "inputColorMatrix";
639     case FilterOperation::BRIGHTNESS: return "inputColorMatrix";
640     case FilterOperation::CONTRAST: return "inputColorMatrix";
641     case FilterOperation::BLUR: return "inputRadius";
642     default: return "";
643     }
644 #else
645     switch (type) {
646     case FilterOperation::GRAYSCALE: return "inputIntensity";
647     case FilterOperation::SEPIA:
648     case FilterOperation::BRIGHTNESS:
649         switch (internalFilterPropertyIndex) {
650         case 0: return "inputRVector";
651         case 1: return "inputGVector";
652         case 2: return "inputBVector";
653         default: return "";
654         }
655     case FilterOperation::SATURATE: return "inputSaturation";
656     case FilterOperation::HUE_ROTATE: return "inputAngle";
657     case FilterOperation::INVERT:
658         switch (internalFilterPropertyIndex) {
659         case 0: return "inputRVector";
660         case 1: return "inputGVector";
661         case 2: return "inputBVector";
662         case 3: return "inputBiasVector";
663         default: return "";
664         }
665     case FilterOperation::OPACITY: return "inputAVector";
666     case FilterOperation::CONTRAST: return "inputContrast";
667     case FilterOperation::BLUR: return "inputRadius";
668     default: return "";
669     }
670 #endif
671 }
672
673 #endif // ENABLE(CSS_FILTERS)