1/*
2 * Copyright (C) 2011 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 COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef FilterOperation_h
27#define FilterOperation_h
28
29#include "platform/Length.h"
30#include "platform/PlatformExport.h"
31#include "platform/graphics/Color.h"
32#include "platform/graphics/filters/Filter.h"
33#include "platform/graphics/filters/ReferenceFilter.h"
34#include "wtf/OwnPtr.h"
35#include "wtf/PassOwnPtr.h"
36#include "wtf/RefCounted.h"
37#include "wtf/text/WTFString.h"
38
39namespace blink {
40
41// CSS Filters
42
43class PLATFORM_EXPORT FilterOperation : public RefCounted<FilterOperation> {
44public:
45    enum OperationType {
46        REFERENCE, // url(#somefilter)
47        GRAYSCALE,
48        SEPIA,
49        SATURATE,
50        HUE_ROTATE,
51        INVERT,
52        OPACITY,
53        BRIGHTNESS,
54        CONTRAST,
55        BLUR,
56        DROP_SHADOW,
57        NONE
58    };
59
60    static bool canInterpolate(FilterOperation::OperationType type)
61    {
62        switch (type) {
63        case GRAYSCALE:
64        case SEPIA:
65        case SATURATE:
66        case HUE_ROTATE:
67        case INVERT:
68        case OPACITY:
69        case BRIGHTNESS:
70        case CONTRAST:
71        case BLUR:
72        case DROP_SHADOW:
73            return true;
74        case REFERENCE:
75            return false;
76        case NONE:
77            break;
78        }
79        ASSERT_NOT_REACHED();
80        return false;
81    }
82
83    virtual ~FilterOperation() { }
84
85    static PassRefPtr<FilterOperation> blend(const FilterOperation* from, const FilterOperation* to, double progress);
86    virtual bool operator==(const FilterOperation&) const = 0;
87    bool operator!=(const FilterOperation& o) const { return !(*this == o); }
88
89    OperationType type() const { return m_type; }
90    virtual bool isSameType(const FilterOperation& o) const { return o.type() == m_type; }
91
92    // True if the alpha channel of any pixel can change under this operation.
93    virtual bool affectsOpacity() const { return false; }
94    // True if the the value of one pixel can affect the value of another pixel under this operation, such as blur.
95    virtual bool movesPixels() const { return false; }
96
97protected:
98    FilterOperation(OperationType type)
99        : m_type(type)
100    {
101    }
102
103    OperationType m_type;
104
105private:
106    virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const = 0;
107};
108
109#define DEFINE_FILTER_OPERATION_TYPE_CASTS(thisType, operationType) \
110    DEFINE_TYPE_CASTS(thisType, FilterOperation, op, op->type() == FilterOperation::operationType, op.type() == FilterOperation::operationType);
111
112class PLATFORM_EXPORT ReferenceFilterOperation : public FilterOperation {
113public:
114    static PassRefPtr<ReferenceFilterOperation> create(const String& url, const AtomicString& fragment)
115    {
116        return adoptRef(new ReferenceFilterOperation(url, fragment));
117    }
118
119    virtual bool affectsOpacity() const OVERRIDE { return true; }
120    virtual bool movesPixels() const OVERRIDE { return true; }
121
122    const String& url() const { return m_url; }
123    const AtomicString& fragment() const { return m_fragment; }
124
125    ReferenceFilter* filter() const { return m_filter.get(); }
126    void setFilter(PassRefPtr<ReferenceFilter> filter) { m_filter = filter; }
127
128private:
129    virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE
130    {
131        ASSERT_NOT_REACHED();
132        return nullptr;
133    }
134
135    virtual bool operator==(const FilterOperation& o) const OVERRIDE
136    {
137        if (!isSameType(o))
138            return false;
139        const ReferenceFilterOperation* other = static_cast<const ReferenceFilterOperation*>(&o);
140        return m_url == other->m_url;
141    }
142
143    ReferenceFilterOperation(const String& url, const AtomicString& fragment)
144        : FilterOperation(REFERENCE)
145        , m_url(url)
146        , m_fragment(fragment)
147    {
148    }
149
150    String m_url;
151    AtomicString m_fragment;
152    RefPtr<ReferenceFilter> m_filter;
153};
154
155DEFINE_FILTER_OPERATION_TYPE_CASTS(ReferenceFilterOperation, REFERENCE);
156
157// GRAYSCALE, SEPIA, SATURATE and HUE_ROTATE are variations on a basic color matrix effect.
158// For HUE_ROTATE, the angle of rotation is stored in m_amount.
159class PLATFORM_EXPORT BasicColorMatrixFilterOperation : public FilterOperation {
160public:
161    static PassRefPtr<BasicColorMatrixFilterOperation> create(double amount, OperationType type)
162    {
163        return adoptRef(new BasicColorMatrixFilterOperation(amount, type));
164    }
165
166    double amount() const { return m_amount; }
167
168
169private:
170    virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE;
171    virtual bool operator==(const FilterOperation& o) const OVERRIDE
172    {
173        if (!isSameType(o))
174            return false;
175        const BasicColorMatrixFilterOperation* other = static_cast<const BasicColorMatrixFilterOperation*>(&o);
176        return m_amount == other->m_amount;
177    }
178
179    BasicColorMatrixFilterOperation(double amount, OperationType type)
180        : FilterOperation(type)
181        , m_amount(amount)
182    {
183    }
184
185    double m_amount;
186};
187
188inline bool isBasicColorMatrixFilterOperation(const FilterOperation& operation)
189{
190    FilterOperation::OperationType type = operation.type();
191    return type == FilterOperation::GRAYSCALE || type == FilterOperation::SEPIA || type == FilterOperation::SATURATE || type == FilterOperation::HUE_ROTATE;
192}
193
194DEFINE_TYPE_CASTS(BasicColorMatrixFilterOperation, FilterOperation, op, isBasicColorMatrixFilterOperation(*op), isBasicColorMatrixFilterOperation(op));
195
196// INVERT, BRIGHTNESS, CONTRAST and OPACITY are variations on a basic component transfer effect.
197class PLATFORM_EXPORT BasicComponentTransferFilterOperation : public FilterOperation {
198public:
199    static PassRefPtr<BasicComponentTransferFilterOperation> create(double amount, OperationType type)
200    {
201        return adoptRef(new BasicComponentTransferFilterOperation(amount, type));
202    }
203
204    double amount() const { return m_amount; }
205
206    virtual bool affectsOpacity() const OVERRIDE { return m_type == OPACITY; }
207
208
209private:
210    virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE;
211    virtual bool operator==(const FilterOperation& o) const OVERRIDE
212    {
213        if (!isSameType(o))
214            return false;
215        const BasicComponentTransferFilterOperation* other = static_cast<const BasicComponentTransferFilterOperation*>(&o);
216        return m_amount == other->m_amount;
217    }
218
219    BasicComponentTransferFilterOperation(double amount, OperationType type)
220        : FilterOperation(type)
221        , m_amount(amount)
222    {
223    }
224
225    double m_amount;
226};
227
228inline bool isBasicComponentTransferFilterOperation(const FilterOperation& operation)
229{
230    FilterOperation::OperationType type = operation.type();
231    return type == FilterOperation::INVERT || type == FilterOperation::OPACITY || type == FilterOperation::BRIGHTNESS || type == FilterOperation::CONTRAST;
232}
233
234DEFINE_TYPE_CASTS(BasicComponentTransferFilterOperation, FilterOperation, op, isBasicComponentTransferFilterOperation(*op), isBasicComponentTransferFilterOperation(op));
235
236class PLATFORM_EXPORT BlurFilterOperation : public FilterOperation {
237public:
238    static PassRefPtr<BlurFilterOperation> create(const Length& stdDeviation)
239    {
240        return adoptRef(new BlurFilterOperation(stdDeviation));
241    }
242
243    const Length& stdDeviation() const { return m_stdDeviation; }
244
245    virtual bool affectsOpacity() const OVERRIDE { return true; }
246    virtual bool movesPixels() const OVERRIDE { return true; }
247
248
249private:
250    virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE;
251    virtual bool operator==(const FilterOperation& o) const OVERRIDE
252    {
253        if (!isSameType(o))
254            return false;
255        const BlurFilterOperation* other = static_cast<const BlurFilterOperation*>(&o);
256        return m_stdDeviation == other->m_stdDeviation;
257    }
258
259    BlurFilterOperation(const Length& stdDeviation)
260        : FilterOperation(BLUR)
261        , m_stdDeviation(stdDeviation)
262    {
263    }
264
265    Length m_stdDeviation;
266};
267
268DEFINE_FILTER_OPERATION_TYPE_CASTS(BlurFilterOperation, BLUR);
269
270class PLATFORM_EXPORT DropShadowFilterOperation : public FilterOperation {
271public:
272    static PassRefPtr<DropShadowFilterOperation> create(const IntPoint& location, int stdDeviation, Color color)
273    {
274        return adoptRef(new DropShadowFilterOperation(location, stdDeviation, color));
275    }
276
277    int x() const { return m_location.x(); }
278    int y() const { return m_location.y(); }
279    IntPoint location() const { return m_location; }
280    int stdDeviation() const { return m_stdDeviation; }
281    Color color() const { return m_color; }
282
283    virtual bool affectsOpacity() const OVERRIDE { return true; }
284    virtual bool movesPixels() const OVERRIDE { return true; }
285
286
287private:
288    virtual PassRefPtr<FilterOperation> blend(const FilterOperation* from, double progress) const OVERRIDE;
289    virtual bool operator==(const FilterOperation& o) const OVERRIDE
290    {
291        if (!isSameType(o))
292            return false;
293        const DropShadowFilterOperation* other = static_cast<const DropShadowFilterOperation*>(&o);
294        return m_location == other->m_location && m_stdDeviation == other->m_stdDeviation && m_color == other->m_color;
295    }
296
297    DropShadowFilterOperation(const IntPoint& location, int stdDeviation, Color color)
298        : FilterOperation(DROP_SHADOW)
299        , m_location(location)
300        , m_stdDeviation(stdDeviation)
301        , m_color(color)
302    {
303    }
304
305    IntPoint m_location; // FIXME: should location be in Lengths?
306    int m_stdDeviation;
307    Color m_color;
308};
309
310DEFINE_FILTER_OPERATION_TYPE_CASTS(DropShadowFilterOperation, DROP_SHADOW);
311
312} // namespace blink
313
314
315#endif // FilterOperation_h
316