18a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
38a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
68a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SkColorFilter_DEFINED
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkColorFilter_DEFINED
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1171fecc32b1b4f71ef3c6467b1f5e0b55c2a12428Mike Reed#include "SkBlendMode.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColor.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFlattenable.h"
1406ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman#include "SkRefCnt.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1667e78c9e47c38a51816412a24a10f4fe2db142a3bsalomon@google.comclass GrContext;
17d3ebb48320cf1b7e969974673e4bd7743816985ebungemanclass GrFragmentProcessor;
18ac04fef619ad3939a25e66bdaef6f6b1e7f5ca50Herb Derbyclass SkArenaAlloc;
19d3ebb48320cf1b7e969974673e4bd7743816985ebungemanclass SkBitmap;
20618d304eb394d64779be0ecdc5eff898242faa8fBrian Osmanclass SkColorSpace;
219a5c47f4effba3b48a9a8c7c144b72b532d06efemtkleinclass SkRasterPipeline;
22c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com
23fb6deed66c20f86c86c105f41dbbf3f3c4a47e4creed@google.com/**
24fb6deed66c20f86c86c105f41dbbf3f3c4a47e4creed@google.com *  ColorFilters are optional objects in the drawing pipeline. When present in
25fb6deed66c20f86c86c105f41dbbf3f3c4a47e4creed@google.com *  a paint, they are called with the "src" colors, and return new colors, which
26fb6deed66c20f86c86c105f41dbbf3f3c4a47e4creed@google.com *  are then passed onto the next stage (either ImageFilter or Xfermode).
27fb6deed66c20f86c86c105f41dbbf3f3c4a47e4creed@google.com *
28fb6deed66c20f86c86c105f41dbbf3f3c4a47e4creed@google.com *  All subclasses are required to be reentrant-safe : it must be legal to share
29fb6deed66c20f86c86c105f41dbbf3f3c4a47e4creed@google.com *  the same instance between several threads.
30fb6deed66c20f86c86c105f41dbbf3f3c4a47e4creed@google.com */
318c3ff17e2cab6f7c798b9f8ff4515c4a3d3fd9d1bsalomon@google.comclass SK_API SkColorFilter : public SkFlattenable {
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
3343c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com    /**
3443c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com     *  If the filter can be represented by a source color plus Mode, this
3543c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com     *  returns true, and sets (if not NULL) the color and mode appropriately.
3643c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com     *  If not, this returns false and ignores the parameters.
3743c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com     */
38faba3715b8ddfaa0ce4df79bc8006e9bc7694e5bMike Reed    virtual bool asColorMode(SkColor* color, SkBlendMode* bmode) const;
3943c50c8c77df82c5cffb55cae2d386e59802b88freed@google.com
40e5ff3cefe007d092daf9d0bc2b03f9ff87b2c34esenorblanco@chromium.org    /**
41e5ff3cefe007d092daf9d0bc2b03f9ff87b2c34esenorblanco@chromium.org     *  If the filter can be represented by a 5x4 matrix, this
42e5ff3cefe007d092daf9d0bc2b03f9ff87b2c34esenorblanco@chromium.org     *  returns true, and sets the matrix appropriately.
43e5ff3cefe007d092daf9d0bc2b03f9ff87b2c34esenorblanco@chromium.org     *  If not, this returns false and ignores the parameter.
44e5ff3cefe007d092daf9d0bc2b03f9ff87b2c34esenorblanco@chromium.org     */
45bada64428a52b4fc1f31a0a1982c2301ec57601creed@google.com    virtual bool asColorMatrix(SkScalar matrix[20]) const;
46e5ff3cefe007d092daf9d0bc2b03f9ff87b2c34esenorblanco@chromium.org
477191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com    /**
487191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *  If the filter can be represented by per-component table, return true,
497191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *  and if table is not null, copy the bitmap containing the table into it.
507191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *
517191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *  The table bitmap will be in SkBitmap::kA8_Config. Each row corresponding
527191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *  to each component in ARGB order. e.g. row[0] == alpha, row[1] == red,
537191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *  etc. To transform a color, you (logically) perform the following:
547191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *
557191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *      a' = *table.getAddr8(a, 0);
567191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *      r' = *table.getAddr8(r, 1);
577191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *      g' = *table.getAddr8(g, 2);
587191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *      b' = *table.getAddr8(b, 3);
597191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *
607191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *  The original component value is the horizontal index for a given row,
617191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     *  and the stored value at that index is the new value for that component.
627191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com     */
63b2ad101313cfba9c06a3a4dc06531766bcbec73bbsalomon@google.com    virtual bool asComponentTable(SkBitmap* table) const;
647191840eec5ac3b5f5814e4df3cf18264b0b0a4dreed@google.com
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Called with a scanline of colors, as if there was a shader installed.
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        The implementation writes out its filtered version into result[].
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Note: shader and result may be the same buffer.
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param src      array of colors, possibly generated by a shader
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param count    the number of entries in the src[] and result[] arrays
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        @param result   written by the filter
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
7262a320c8d444cd04e4f2952c269ea4cbd58dee64reed    virtual void filterSpan(const SkPMColor src[], int count, SkPMColor result[]) const = 0;
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
746d3cef930ad19b0f55543ca40f7a07030f4fe508reed    virtual void filterSpan4f(const SkPM4f src[], int count, SkPM4f result[]) const;
756d3cef930ad19b0f55543ca40f7a07030f4fe508reed
76ac04fef619ad3939a25e66bdaef6f6b1e7f5ca50Herb Derby    bool appendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
77744908e5e81f81f34288a1b5547aa4ea990ad13dMike Klein                      bool shaderIsOpaque) const;
789a5c47f4effba3b48a9a8c7c144b72b532d06efemtklein
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum Flags {
8062a320c8d444cd04e4f2952c269ea4cbd58dee64reed        /** If set the filter methods will not change the alpha channel of the colors.
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        */
826d3cef930ad19b0f55543ca40f7a07030f4fe508reed        kAlphaUnchanged_Flag = 1 << 0,
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8562a320c8d444cd04e4f2952c269ea4cbd58dee64reed    /** Returns the flags for this filter. Override in subclasses to return custom flags.
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
87bada64428a52b4fc1f31a0a1982c2301ec57601creed@google.com    virtual uint32_t getFlags() const { return 0; }
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
896b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com    /**
908a8d841d485ff36b64d838575eb3735c1ddcf929reed     *  If this subclass can optimally createa composition with the inner filter, return it as
918a8d841d485ff36b64d838575eb3735c1ddcf929reed     *  a new filter (which the caller must unref() when it is done). If no such optimization
928a8d841d485ff36b64d838575eb3735c1ddcf929reed     *  is known, return NULL.
938a8d841d485ff36b64d838575eb3735c1ddcf929reed     *
948a8d841d485ff36b64d838575eb3735c1ddcf929reed     *  e.g. result(color) == this_filter(inner(color))
958a8d841d485ff36b64d838575eb3735c1ddcf929reed     */
96d053ce9c54d4e5937a142278359e5a4cde18095ereed    virtual sk_sp<SkColorFilter> makeComposed(sk_sp<SkColorFilter>) const { return nullptr; }
978a8d841d485ff36b64d838575eb3735c1ddcf929reed
988a8d841d485ff36b64d838575eb3735c1ddcf929reed    /**
996b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com     *  Apply this colorfilter to the specified SkColor. This routine handles
1006b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com     *  converting to SkPMColor, calling the filter, and then converting back
1016b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com     *  to SkColor. This method is not virtual, but will call filterSpan()
1026b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com     *   which is virtual.
1036b7aee387d3b4b2df5894b51fa1c0baf649c6540reed@google.com     */
104bada64428a52b4fc1f31a0a1982c2301ec57601creed@google.com    SkColor filterColor(SkColor) const;
1051447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
106f7cdb06d62bd732599c7ee407dfd76d32d671755reed    /**
107f7cdb06d62bd732599c7ee407dfd76d32d671755reed     *  Filters a single color.
108f7cdb06d62bd732599c7ee407dfd76d32d671755reed     */
109f7cdb06d62bd732599c7ee407dfd76d32d671755reed    SkColor4f filterColor4f(const SkColor4f&) const;
110f7cdb06d62bd732599c7ee407dfd76d32d671755reed
111845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com    /** Create a colorfilter that uses the specified color and mode.
112845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com        If the Mode is DST, this function will return NULL (since that
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        mode will have no effect on the result).
114845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com        @param c    The source color used with the specified mode
1157d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed        @param mode The blend that is applied to each color in
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        the colorfilter's filterSpan[16,32] methods
117845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com        @return colorfilter object that applies the src color and mode,
118845fdaca174f4675e9acc164b510e3a5ffa9053creed@android.com                    or NULL if the mode will have no effect.
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
1207d954ad797176afedb9262fdea4507d0fc60eb9dMike Reed    static sk_sp<SkColorFilter> MakeModeFilter(SkColor c, SkBlendMode mode);
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
122db873d8677a2d4ecfe38a794a5d868301bdeeabereed    /** Construct a colorfilter whose effect is to first apply the inner filter and then apply
123db873d8677a2d4ecfe38a794a5d868301bdeeabereed     *  the outer filter to the result of the inner's.
124db873d8677a2d4ecfe38a794a5d868301bdeeabereed     *  The reference counts for outer and inner are incremented.
125dc812222a7488d2a0e39b4a09c81c9f000d4b869reed     *
126dc812222a7488d2a0e39b4a09c81c9f000d4b869reed     *  Due to internal limits, it is possible that this will return NULL, so the caller must
127dc812222a7488d2a0e39b4a09c81c9f000d4b869reed     *  always check.
128db873d8677a2d4ecfe38a794a5d868301bdeeabereed     */
129d053ce9c54d4e5937a142278359e5a4cde18095ereed    static sk_sp<SkColorFilter> MakeComposeFilter(sk_sp<SkColorFilter> outer,
130d053ce9c54d4e5937a142278359e5a4cde18095ereed                                                  sk_sp<SkColorFilter> inner);
131db873d8677a2d4ecfe38a794a5d868301bdeeabereed
1328610002ff81fb5d81d1b7c312b5d0a8b05b41e13bsalomon    /** Construct a color filter that transforms a color by a 4x5 matrix. The matrix is in row-
1338610002ff81fb5d81d1b7c312b5d0a8b05b41e13bsalomon     *  major order and the translation column is specified in unnormalized, 0...255, space.
1348610002ff81fb5d81d1b7c312b5d0a8b05b41e13bsalomon     */
135d053ce9c54d4e5937a142278359e5a4cde18095ereed    static sk_sp<SkColorFilter> MakeMatrixFilterRowMajor255(const SkScalar array[20]);
136d053ce9c54d4e5937a142278359e5a4cde18095ereed
13706ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman#if SK_SUPPORT_GPU
138cff10b21a9934afc540d121b493b204335829589reed    /**
139e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon     *  A subclass may implement this factory function to work with the GPU backend. It returns
140e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon     *  a GrFragmentProcessor that implemets the color filter in GPU shader code.
141cff10b21a9934afc540d121b493b204335829589reed     *
142e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon     *  The fragment processor receives a premultiplied input color and produces a premultiplied
143e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon     *  output color.
144b7affb56bb295d52e543d6f0e45ba45acf42dcd6reed     *
145e25eea4b36a488448fb730f4e3dc5a900b0e2892bsalomon     *  A null return indicates that the color filter isn't implemented for the GPU backend.
14667e78c9e47c38a51816412a24a10f4fe2db142a3bsalomon@google.com     */
147618d304eb394d64779be0ecdc5eff898242faa8fBrian Osman    virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*,
148618d304eb394d64779be0ecdc5eff898242faa8fBrian Osman                                                           SkColorSpace* dstColorSpace) const;
14906ca8ec87cf6fab57cadd043a5ac18c4154a4129bungeman#endif
15067e78c9e47c38a51816412a24a10f4fe2db142a3bsalomon@google.com
1510abdf766d395ed3b7059511425f431589eca05f6senorblanco    bool affectsTransparentBlack() const {
1520abdf766d395ed3b7059511425f431589eca05f6senorblanco        return this->filterColor(0) != 0;
1530abdf766d395ed3b7059511425f431589eca05f6senorblanco    }
1540abdf766d395ed3b7059511425f431589eca05f6senorblanco
1550f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org    SK_TO_STRING_PUREVIRT()
1561202c2ac563cdeb07406872825706b83e335c977robertphillips@google.com
157a2ca41e3afdd8fad5e0e924dec029f33918e0a67djsollen@google.com    SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
1583b37545bc594a96de45eba62dea0ce478750f2a9mtklein    SK_DEFINE_FLATTENABLE_TYPE(SkColorFilter)
159c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected:
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkColorFilter() {}
1621447c6f7f4579942b32af6ffff1eadede40b42bctomhudson@google.com
163ac04fef619ad3939a25e66bdaef6f6b1e7f5ca50Herb Derby    virtual bool onAppendStages(SkRasterPipeline*, SkColorSpace*, SkArenaAlloc*,
164744908e5e81f81f34288a1b5547aa4ea990ad13dMike Klein                                bool shaderIsOpaque) const;
1659a5c47f4effba3b48a9a8c7c144b72b532d06efemtklein
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
167dc812222a7488d2a0e39b4a09c81c9f000d4b869reed    /*
168dc812222a7488d2a0e39b4a09c81c9f000d4b869reed     *  Returns 1 if this is a single filter (not a composition of other filters), otherwise it
169dc812222a7488d2a0e39b4a09c81c9f000d4b869reed     *  reutrns the number of leaf-node filters in a composition. This should be the same value
170dc812222a7488d2a0e39b4a09c81c9f000d4b869reed     *  as the number of GrFragmentProcessors returned by asFragmentProcessors's array parameter.
171dc812222a7488d2a0e39b4a09c81c9f000d4b869reed     *
172dc812222a7488d2a0e39b4a09c81c9f000d4b869reed     *  e.g. compose(filter, compose(compose(filter, filter), filter)) --> 4
173dc812222a7488d2a0e39b4a09c81c9f000d4b869reed     */
174dc812222a7488d2a0e39b4a09c81c9f000d4b869reed    virtual int privateComposedFilterCount() const { return 1; }
175dc812222a7488d2a0e39b4a09c81c9f000d4b869reed    friend class SkComposeColorFilter;
176dc812222a7488d2a0e39b4a09c81c9f000d4b869reed
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    typedef SkFlattenable INHERITED;
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
181