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