1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkColorMatrixFilter.h"
9#include "SkColorSpace.h"
10#include "SkColorSpaceXformer.h"
11#if SK_SUPPORT_GPU
12    #include "GrFragmentProcessor.h"
13#endif
14
15static SkScalar byte_to_scale(U8CPU byte) {
16    if (0xFF == byte) {
17        // want to get this exact
18        return 1;
19    } else {
20        return byte * 0.00392156862745f;
21    }
22}
23
24// If we can't reduce to a mode filter in MakeLightingFilter(), this is the general case.
25// We operate as a matrix color filter, but remember our input colors in case we're asked
26// to onMakeColorSpace() a new filter.
27class SkLightingColorFilter : public SkColorFilter {
28public:
29    SkLightingColorFilter(SkColor mul, SkColor add) : fMul(mul), fAdd(add) {
30        SkColorMatrix matrix;
31        matrix.setScale(byte_to_scale(SkColorGetR(mul)),
32                        byte_to_scale(SkColorGetG(mul)),
33                        byte_to_scale(SkColorGetB(mul)),
34                        1);
35        matrix.postTranslate(SkIntToScalar(SkColorGetR(add)),
36                             SkIntToScalar(SkColorGetG(add)),
37                             SkIntToScalar(SkColorGetB(add)),
38                             0);
39        fMatrixFilter = SkColorFilter::MakeMatrixFilterRowMajor255(matrix.fMat);
40    }
41
42    // Overriding this method is the class' raison d'etre.
43    sk_sp<SkColorFilter> onMakeColorSpace(SkColorSpaceXformer* xformer) const override {
44        SkColor add = xformer->apply(fAdd);
45        if (add != fAdd) {
46            return sk_make_sp<SkLightingColorFilter>(fMul, add);
47        }
48        return this->INHERITED::onMakeColorSpace(xformer);
49    }
50
51    // Let fMatrixFilter handle all the other calls directly.
52
53    uint32_t getFlags() const override {
54        return fMatrixFilter->getFlags();
55    }
56    bool asColorMatrix(SkScalar matrix[20]) const override {
57        return fMatrixFilter->asColorMatrix(matrix);
58    }
59    void onAppendStages(SkRasterPipeline* p, SkColorSpace* cs, SkArenaAlloc* alloc,
60                        bool shaderIsOpaque) const override {
61        fMatrixFilter->appendStages(p, cs, alloc, shaderIsOpaque);
62    }
63
64    // TODO: might want to remember we're a lighting color filter through serialization?
65    void flatten(SkWriteBuffer& buf) const override { return fMatrixFilter->flatten(buf); }
66    Factory getFactory() const override             { return fMatrixFilter->getFactory(); }
67
68#if SK_SUPPORT_GPU
69    std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
70            GrContext* ctx, const GrColorSpaceInfo& csi) const override {
71        return fMatrixFilter->asFragmentProcessor(ctx, csi);
72    }
73#endif
74
75#ifndef SK_IGNORE_TO_STRING
76    void toString(SkString* str) const override { fMatrixFilter->toString(str); }
77#endif
78
79private:
80    SkColor              fMul, fAdd;
81    sk_sp<SkColorFilter> fMatrixFilter;
82
83    typedef SkColorFilter INHERITED;
84};
85
86sk_sp<SkColorFilter> SkColorMatrixFilter::MakeLightingFilter(SkColor mul, SkColor add) {
87    const SkColor opaqueAlphaMask = SK_ColorBLACK;
88    // omit the alpha and compare only the RGB values
89    if (0 == (add & ~opaqueAlphaMask)) {
90        return SkColorFilter::MakeModeFilter(mul | opaqueAlphaMask, SkBlendMode::kModulate);
91    }
92    return sk_make_sp<SkLightingColorFilter>(mul, add);
93}
94