1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/svg/parse/svg_fe_color_matrix.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/components/declaration/svg/svg_declaration.h"
20 #include "core/components/declaration/svg/svg_fe_colormatrix_declaration.h"
21 
22 namespace OHOS::Ace::NG {
23 
24 static constexpr float HUE_R = 0.213f;
25 static constexpr float HUE_G = 0.715f;
26 static constexpr float HUE_B = 0.072f;
27 
28 static constexpr float LUM_COEFF_R = 0.2126f;
29 static constexpr float LUM_COEFF_G = 0.7152f;
30 static constexpr float LUM_COEFF_B = 0.0722f;
31 
DegreesToRadians(float degrees)32 inline float DegreesToRadians(float degrees)
33 {
34     return (degrees) * (M_PI / 180.0f);
35 }
36 
37 const std::vector<float> luminanceMatrix_ = {
38     0, 0, 0, 0, 0,
39     0, 0, 0, 0, 0,
40     0, 0, 0, 0, 0,
41     LUM_COEFF_R, LUM_COEFF_G, LUM_COEFF_B, 0, 0
42 };
43 
SetRow(float * row,float r,float g,float b)44 static void SetRow(float* row, float r, float g, float b)
45 {
46     row[0] = r;
47     row[1] = g;
48     row[2] = b;
49 }
50 
Create()51 RefPtr<SvgNode> SvgFeColorMatrix::Create()
52 {
53     return AceType::MakeRefPtr<SvgFeColorMatrix>();
54 }
55 
SvgFeColorMatrix()56 SvgFeColorMatrix::SvgFeColorMatrix() : SvgFe() {}
57 
MakeMatrix(const std::string & value)58 void SvgFeColorMatrix::MakeMatrix(const std::string& value)
59 {
60     std::vector<float> matrix;
61     if (!StringUtils::ParseStringToArray(value, matrix)) {
62         return;
63     }
64     // when matrix length not equal 20, then return
65     if (matrix.size() != matrix_.size()) {
66         return;
67     }
68     matrix_ = matrix;
69 }
70 
MakeHueRotate(const std::string & value)71 void SvgFeColorMatrix::MakeHueRotate(const std::string& value)
72 {
73     float theta = DegreesToRadians(std::stof(value));
74     const float cosValue = cos(theta);
75     const float sinValue = sin(theta);
76 
77     // The source of the formula is this website: https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveSubRegion
78     matrix_ = {
79         0.213f + cosValue*0.787f + sinValue*-0.213f,
80         0.715f + cosValue*-0.715f + sinValue*-0.715f,
81         0.072f + cosValue*-0.072f + sinValue* 0.928f,
82         0,
83         0,
84 
85         0.213f + cosValue*-0.213f + sinValue* 0.143f,
86         0.715f + cosValue* 0.285f + sinValue* 0.140f,
87         0.072f + cosValue*-0.072f + sinValue*-0.283f,
88         0,
89         0,
90 
91         0.213f + cosValue*-0.213f + sinValue*-0.787f,
92         0.715f + cosValue*-0.715f + sinValue* 0.715f,
93         0.072f + cosValue* 0.928f + sinValue* 0.072f,
94         0,
95         0,
96 
97         0, 0, 0, 1, 0
98     };
99 }
100 
MakeSaturate(const std::string & value)101 void SvgFeColorMatrix::MakeSaturate(const std::string& value)
102 {
103     float satValue = std::stof(value);
104 
105     const float RValue = HUE_R * (1 - satValue);
106     const float GValue = HUE_G * (1 - satValue);
107     const float BValue = HUE_B * (1 - satValue);
108 
109     SetRow(matrix_.data() +  0, RValue + satValue, GValue, BValue);
110     SetRow(matrix_.data() +  5, RValue, GValue + satValue, BValue);
111     SetRow(matrix_.data() + 10, RValue, GValue, BValue + satValue);
112 }
113 
MakeLuminanceToAlpha()114 void SvgFeColorMatrix::MakeLuminanceToAlpha()
115 {
116     matrix_ = luminanceMatrix_;
117 }
118 
OnInitStyle()119 void SvgFeColorMatrix::OnInitStyle()
120 {
121     auto type = matrixAttr_.type;
122     switch (type) {
123         case SvgFeColorMatrixType::SATURATE:
124             MakeSaturate(matrixAttr_.values);
125             break;
126         case SvgFeColorMatrixType::HUE_ROTATE:
127             MakeHueRotate(matrixAttr_.values);
128             break;
129         case SvgFeColorMatrixType::LUMINACE_TO_ALPHA:
130             MakeLuminanceToAlpha();
131             break;
132         default:
133             MakeMatrix(matrixAttr_.values);
134             break;
135     }
136 }
137 
OnAsImageFilter(std::shared_ptr<RSImageFilter> & imageFilter,const SvgColorInterpolationType & srcColor,SvgColorInterpolationType & currentColor,std::unordered_map<std::string,std::shared_ptr<RSImageFilter>> & resultHash) const138 void SvgFeColorMatrix::OnAsImageFilter(std::shared_ptr<RSImageFilter>& imageFilter,
139     const SvgColorInterpolationType& srcColor, SvgColorInterpolationType& currentColor,
140     std::unordered_map<std::string, std::shared_ptr<RSImageFilter>>& resultHash) const
141 {
142     imageFilter = MakeImageFilter(feAttr_.in, imageFilter, resultHash);
143 
144     RSColorMatrix colorMatrix;
145     colorMatrix.SetArray(matrix_.data());
146     auto colorFilter = RSRecordingColorFilter::CreateMatrixColorFilter(colorMatrix);
147     CHECK_NULL_VOID(colorFilter);
148 
149     imageFilter = RSRecordingImageFilter::CreateColorFilterImageFilter(*colorFilter, imageFilter);
150     ConverImageFilterColor(imageFilter, srcColor, currentColor);
151     RegisterResult(feAttr_.result, imageFilter, resultHash);
152 }
153 
ParseAndSetSpecializedAttr(const std::string & name,const std::string & value)154 bool SvgFeColorMatrix::ParseAndSetSpecializedAttr(const std::string& name, const std::string& value)
155 {
156     static const LinearMapNode<void (*)(const std::string&, SvgFeColorMatrixAttribute&)> attrs[] = {
157         { DOM_SVG_FE_TYPE,
158             [](const std::string& type, SvgFeColorMatrixAttribute& attr) {
159                 if (type == "saturate") {
160                     attr.type = SvgFeColorMatrixType::SATURATE;
161                 } else if (type == "hueRotate") {
162                     attr.type = SvgFeColorMatrixType::HUE_ROTATE;
163                 } else if (type == "luminanceToAlpha") {
164                     attr.type = SvgFeColorMatrixType::LUMINACE_TO_ALPHA;
165                 }
166             } },
167         { DOM_SVG_FE_VALUES,
168             [](const std::string& val, SvgFeColorMatrixAttribute& attr) {
169                 attr.values = val;
170             } },
171     };
172     auto attrIter = BinarySearchFindIndex(attrs, ArraySize(attrs), name.c_str());
173     if (attrIter != -1) {
174         attrs[attrIter].value(value, matrixAttr_);
175         return true;
176     }
177     return SvgFe::ParseAndSetSpecializedAttr(name, value);
178 }
179 
180 } // namespace OHOS::Ace::NG
181