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