1 /*
2 * Copyright 2020 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 "include/core/SkColorFilter.h"
9 #include "include/effects/SkImageFilters.h"
10 #include "include/private/SkColorData.h"
11 #include "modules/svg/include/SkSVGAttributeParser.h"
12 #include "modules/svg/include/SkSVGFeColorMatrix.h"
13 #include "modules/svg/include/SkSVGFilterContext.h"
14 #include "modules/svg/include/SkSVGRenderContext.h"
15 #include "modules/svg/include/SkSVGValue.h"
16
parseAndSetAttribute(const char * name,const char * value)17 bool SkSVGFeColorMatrix::parseAndSetAttribute(const char* name, const char* value) {
18 return INHERITED::parseAndSetAttribute(name, value) ||
19 this->setType(
20 SkSVGAttributeParser::parse<SkSVGFeColorMatrixType>("type", name, value)) ||
21 this->setValues(
22 SkSVGAttributeParser::parse<SkSVGFeColorMatrixValues>("values", name, value));
23 }
24
makeMatrixForType() const25 SkColorMatrix SkSVGFeColorMatrix::makeMatrixForType() const {
26 if (fValues.empty() && fType != SkSVGFeColorMatrixType::kLuminanceToAlpha) {
27 return SkColorMatrix();
28 }
29
30 switch (fType) {
31 case SkSVGFeColorMatrixType::kMatrix: {
32 if (fValues.size() < 20) {
33 return SkColorMatrix();
34 }
35 SkColorMatrix m;
36 m.setRowMajor(this->fValues.begin());
37 return m;
38 }
39 case SkSVGFeColorMatrixType::kSaturate:
40 return MakeSaturate(!fValues.empty() ? fValues[0] : 1);
41 case SkSVGFeColorMatrixType::kHueRotate:
42 return MakeHueRotate(!fValues.empty() ? fValues[0] : 0);
43 case SkSVGFeColorMatrixType::kLuminanceToAlpha:
44 return MakeLuminanceToAlpha();
45 }
46
47 SkUNREACHABLE;
48 }
49
MakeSaturate(SkSVGNumberType s)50 SkColorMatrix SkSVGFeColorMatrix::MakeSaturate(SkSVGNumberType s) {
51 SkColorMatrix m;
52 m.setSaturation(s);
53 return m;
54 }
55
MakeHueRotate(SkSVGNumberType degrees)56 SkColorMatrix SkSVGFeColorMatrix::MakeHueRotate(SkSVGNumberType degrees) {
57 const SkScalar theta = SkDegreesToRadians(degrees);
58 const SkSVGNumberType c = SkScalarCos(theta);
59 const SkSVGNumberType s = SkScalarSin(theta);
60 return SkColorMatrix(
61 0.213f + c* 0.787f + s*-0.213f,
62 0.715f + c*-0.715f + s*-0.715f,
63 0.072f + c*-0.072f + s* 0.928f,
64 0,
65 0,
66
67 0.213f + c*-0.213f + s* 0.143f,
68 0.715f + c* 0.285f + s* 0.140f,
69 0.072f + c*-0.072f + s*-0.283f,
70 0,
71 0,
72
73 0.213f + c*-0.213f + s*-0.787f,
74 0.715f + c*-0.715f + s* 0.715f,
75 0.072f + c* 0.928f + s* 0.072f,
76 0,
77 0,
78
79 0,0,0,1,0
80 );
81 }
82
MakeLuminanceToAlpha()83 SkColorMatrix SkSVGFeColorMatrix::MakeLuminanceToAlpha() {
84 return SkColorMatrix(
85 0, 0, 0, 0, 0,
86 0, 0, 0, 0, 0,
87 0, 0, 0, 0, 0,
88 SK_LUM_COEFF_R, SK_LUM_COEFF_G, SK_LUM_COEFF_B, 0, 0
89 );
90 }
91
onMakeImageFilter(const SkSVGRenderContext & ctx,const SkSVGFilterContext & fctx) const92 sk_sp<SkImageFilter> SkSVGFeColorMatrix::onMakeImageFilter(const SkSVGRenderContext& ctx,
93 const SkSVGFilterContext& fctx) const {
94 return SkImageFilters::ColorFilter(
95 SkColorFilters::Matrix(makeMatrixForType()),
96 fctx.resolveInput(ctx, this->getIn(), this->resolveColorspace(ctx, fctx)),
97 this->resolveFilterSubregion(ctx, fctx));
98 }
99
parse(SkSVGFeColorMatrixValues * values)100 template <> bool SkSVGAttributeParser::parse(SkSVGFeColorMatrixValues* values) {
101 SkSVGNumberType value;
102 if (!this->parse(&value)) {
103 return false;
104 }
105
106 values->push_back(value);
107 while (true) {
108 if (!this->parse(&value) || values->size() >= 20) {
109 break;
110 }
111 values->push_back(value);
112 }
113
114 return this->parseEOSToken();
115 }
116
parse(SkSVGFeColorMatrixType * type)117 template <> bool SkSVGAttributeParser::parse(SkSVGFeColorMatrixType* type) {
118 static constexpr std::tuple<const char*, SkSVGFeColorMatrixType> gTypeMap[] = {
119 {"matrix", SkSVGFeColorMatrixType::kMatrix},
120 {"saturate", SkSVGFeColorMatrixType::kSaturate},
121 {"hueRotate", SkSVGFeColorMatrixType::kHueRotate},
122 {"luminanceToAlpha", SkSVGFeColorMatrixType::kLuminanceToAlpha},
123 };
124
125 return this->parseEnumMap(gTypeMap, type) && this->parseEOSToken();
126 }
127