1 /*
2  * Copyright (c) 2021-2023 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 "bridge/declarative_frontend/jsview/canvas/js_matrix2d.h"
17 
18 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
19 #include "core/components/common/properties/paint_state.h"
20 #include "core/components_ng/render/adapter/matrix2d.h"
21 
22 namespace OHOS::Ace::Framework {
23 constexpr int JS_MATRIX2D_PARAMETER_COUNTS_0 = 0;
24 constexpr int JS_MATRIX2D_PARAMETER_COUNTS_1 = 1;
25 constexpr int JS_MATRIX2D_PARAMETER_COUNTS_2 = 2;
26 constexpr int JS_MATRIX2D_PARAMETER_COUNTS_3 = 3;
27 
Constructor(const JSCallbackInfo & info)28 void JSMatrix2d::Constructor(const JSCallbackInfo& info)
29 {
30     auto matrix2d = Referenced::MakeRefPtr<JSMatrix2d>();
31     matrix2d->IncRefCount();
32     info.SetReturnValue(Referenced::RawPtr(matrix2d));
33     int32_t unit = 0;
34     if (info.GetInt32Arg(0, unit) && (static_cast<CanvasUnit>(unit) == CanvasUnit::PX)) {
35         matrix2d->SetUnit(CanvasUnit::PX);
36     }
37 }
38 
Destructor(JSMatrix2d * matrix2d)39 void JSMatrix2d::Destructor(JSMatrix2d* matrix2d)
40 {
41     if (matrix2d != nullptr) {
42         matrix2d->DecRefCount();
43     }
44 }
45 
GetTransformInfo(const JSRef<JSObject> & obj)46 TransformParam JSMatrix2d::GetTransformInfo(const JSRef<JSObject>& obj)
47 {
48     auto scaleXVal = obj->GetProperty("scaleX");
49     auto rotateXVal = obj->GetProperty("rotateX");
50     auto rotateYVal = obj->GetProperty("rotateY");
51     auto scaleYVal = obj->GetProperty("scaleY");
52     auto translateXVal = obj->GetProperty("translateX");
53     auto translateYVal = obj->GetProperty("translateY");
54 
55     TransformParam param;
56     JSViewAbstract::ParseJsDouble(scaleXVal, param.scaleX);
57     JSViewAbstract::ParseJsDouble(rotateXVal, param.skewX);
58     JSViewAbstract::ParseJsDouble(rotateYVal, param.skewY);
59     JSViewAbstract::ParseJsDouble(scaleYVal, param.scaleY);
60     JSViewAbstract::ParseJsDouble(translateXVal, param.translateX);
61     JSViewAbstract::ParseJsDouble(translateYVal, param.translateY);
62     return param;
63 }
64 
JSBind(BindingTarget globalObj)65 void JSMatrix2d::JSBind(BindingTarget globalObj)
66 {
67     JSClass<JSMatrix2d>::Declare("Matrix2D");
68     JSClass<JSMatrix2d>::CustomProperty("scaleX", &JSMatrix2d::JsGetScaleX, &JSMatrix2d::JsSetScaleX);
69     JSClass<JSMatrix2d>::CustomProperty("rotateY", &JSMatrix2d::JsGetRotateY, &JSMatrix2d::JsSetRotateY);
70     JSClass<JSMatrix2d>::CustomProperty("rotateX", &JSMatrix2d::JsGetRotateX, &JSMatrix2d::JsSetRotateX);
71     JSClass<JSMatrix2d>::CustomProperty("scaleY", &JSMatrix2d::JsGetScaleY, &JSMatrix2d::JsSetScaleY);
72     JSClass<JSMatrix2d>::CustomProperty("translateX", &JSMatrix2d::JsGetTranslateX, &JSMatrix2d::JsSetTranslateX);
73     JSClass<JSMatrix2d>::CustomProperty("translateY", &JSMatrix2d::JsGetTranslateY, &JSMatrix2d::JsSetTranslateY);
74     JSClass<JSMatrix2d>::CustomMethod("identity", &JSMatrix2d::JsIdentity);
75     JSClass<JSMatrix2d>::CustomMethod("invert", &JSMatrix2d::JsInvert);
76     JSClass<JSMatrix2d>::CustomMethod("rotate", &JSMatrix2d::JsRotate);
77     JSClass<JSMatrix2d>::CustomMethod("translate", &JSMatrix2d::JsTranslate);
78     JSClass<JSMatrix2d>::CustomMethod("scale", &JSMatrix2d::JsScale);
79     JSClass<JSMatrix2d>::CustomMethod("multiply", &JSMatrix2d::JSMultiply);
80 
81     JSClass<JSMatrix2d>::Bind(globalObj, JSMatrix2d::Constructor, JSMatrix2d::Destructor);
82 }
83 
JsSetScaleX(const JSCallbackInfo & info)84 void JSMatrix2d::JsSetScaleX(const JSCallbackInfo& info)
85 {
86     if (info.Length() != JS_MATRIX2D_PARAMETER_COUNTS_1) {
87         return;
88     }
89     if (info[JS_MATRIX2D_PARAMETER_COUNTS_0]->IsNumber()) {
90         double scaleX = 0;
91         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_0], scaleX);
92         transform_.scaleX = scaleX;
93     }
94 }
95 
JsSetRotateY(const JSCallbackInfo & info)96 void JSMatrix2d::JsSetRotateY(const JSCallbackInfo& info)
97 {
98     if (info.Length() != JS_MATRIX2D_PARAMETER_COUNTS_1) {
99         return;
100     }
101     if (info[JS_MATRIX2D_PARAMETER_COUNTS_0]->IsNumber()) {
102         double rotateY = 0;
103         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_0], rotateY);
104         transform_.skewY = rotateY;
105     }
106 }
107 
JsSetRotateX(const JSCallbackInfo & info)108 void JSMatrix2d::JsSetRotateX(const JSCallbackInfo& info)
109 {
110     if (info.Length() != JS_MATRIX2D_PARAMETER_COUNTS_1) {
111         return;
112     }
113     if (info[JS_MATRIX2D_PARAMETER_COUNTS_0]->IsNumber()) {
114         double rotateX = 0;
115         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_0], rotateX);
116         transform_.skewX = rotateX;
117     }
118 }
119 
JsSetScaleY(const JSCallbackInfo & info)120 void JSMatrix2d::JsSetScaleY(const JSCallbackInfo& info)
121 {
122     if (info.Length() != JS_MATRIX2D_PARAMETER_COUNTS_1) {
123         return;
124     }
125     if (info[JS_MATRIX2D_PARAMETER_COUNTS_0]->IsNumber()) {
126         double scaleY = 0;
127         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_0], scaleY);
128         transform_.scaleY = scaleY;
129     }
130 }
131 
JsSetTranslateX(const JSCallbackInfo & info)132 void JSMatrix2d::JsSetTranslateX(const JSCallbackInfo& info)
133 {
134     if (info.Length() != JS_MATRIX2D_PARAMETER_COUNTS_1) {
135         return;
136     }
137     if (info[JS_MATRIX2D_PARAMETER_COUNTS_0]->IsNumber()) {
138         double translateX = 0;
139         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_0], translateX);
140         double density = GetDensity();
141         translateX *= density;
142         transform_.translateX = translateX;
143     }
144 }
145 
JsSetTranslateY(const JSCallbackInfo & info)146 void JSMatrix2d::JsSetTranslateY(const JSCallbackInfo& info)
147 {
148     if (info.Length() != JS_MATRIX2D_PARAMETER_COUNTS_1) {
149         return;
150     }
151     if (info[JS_MATRIX2D_PARAMETER_COUNTS_0]->IsNumber()) {
152         double translateY = 0;
153         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_0], translateY);
154         double density = GetDensity();
155         translateY *= density;
156         transform_.translateY = translateY;
157     }
158 }
159 
JsGetScaleX(const JSCallbackInfo & info)160 void JSMatrix2d::JsGetScaleX(const JSCallbackInfo& info)
161 {
162     auto returnValue = JSVal(ToJSValue(transform_.scaleX));
163     auto returnPtr = JSRef<JSVal>::Make(returnValue);
164     info.SetReturnValue(returnPtr);
165 }
166 
JsGetRotateY(const JSCallbackInfo & info)167 void JSMatrix2d::JsGetRotateY(const JSCallbackInfo& info)
168 {
169     auto returnValue = JSVal(ToJSValue(transform_.skewY));
170     auto returnPtr = JSRef<JSVal>::Make(returnValue);
171     info.SetReturnValue(returnPtr);
172 }
173 
JsGetRotateX(const JSCallbackInfo & info)174 void JSMatrix2d::JsGetRotateX(const JSCallbackInfo& info)
175 {
176     auto returnValue = JSVal(ToJSValue(transform_.skewX));
177     auto returnPtr = JSRef<JSVal>::Make(returnValue);
178     info.SetReturnValue(returnPtr);
179 }
180 
JsGetScaleY(const JSCallbackInfo & info)181 void JSMatrix2d::JsGetScaleY(const JSCallbackInfo& info)
182 {
183     auto returnValue = JSVal(ToJSValue(transform_.scaleY));
184     auto returnPtr = JSRef<JSVal>::Make(returnValue);
185     info.SetReturnValue(returnPtr);
186 }
187 
JsGetTranslateX(const JSCallbackInfo & info)188 void JSMatrix2d::JsGetTranslateX(const JSCallbackInfo& info)
189 {
190     double translateX = transform_.translateX;
191     double density = GetDensity();
192     translateX /= density;
193     auto returnValue = JSVal(ToJSValue(translateX));
194     auto returnPtr = JSRef<JSVal>::Make(returnValue);
195     info.SetReturnValue(returnPtr);
196 }
197 
JsGetTranslateY(const JSCallbackInfo & info)198 void JSMatrix2d::JsGetTranslateY(const JSCallbackInfo& info)
199 {
200     double translateY = transform_.translateY;
201     double density = GetDensity();
202     translateY /= density;
203     auto returnValue = JSVal(ToJSValue(translateY));
204     auto returnPtr = JSRef<JSVal>::Make(returnValue);
205     info.SetReturnValue(returnPtr);
206 }
207 
JsIdentity(const JSCallbackInfo & info)208 void JSMatrix2d::JsIdentity(const JSCallbackInfo& info)
209 {
210     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_0) {
211         return;
212     }
213     NG::Matrix2D::Identity(transform_);
214     info.SetReturnValue(info.This());
215 }
216 
JsInvert(const JSCallbackInfo & info)217 void JSMatrix2d::JsInvert(const JSCallbackInfo& info)
218 {
219     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_0) {
220         return;
221     }
222     bool retValue = NG::Matrix2D::Invert(transform_);
223     if (!retValue) {
224         transform_.scaleX = NAN;
225         transform_.scaleY = NAN;
226         transform_.skewX = NAN;
227         transform_.skewY = NAN;
228         transform_.translateX = NAN;
229         transform_.translateY = NAN;
230     }
231     info.SetReturnValue(info.This());
232 }
233 
JsRotate(const JSCallbackInfo & info)234 void JSMatrix2d::JsRotate(const JSCallbackInfo& info)
235 {
236     if (info.Length() < JS_MATRIX2D_PARAMETER_COUNTS_1 || info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_3) {
237         return;
238     }
239     double degree = 0;
240     double rx = 0;
241     double ry = 0;
242     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_0 && info[JS_MATRIX2D_PARAMETER_COUNTS_0]->IsNumber()) {
243         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_0], degree);
244     }
245     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_1 && info[JS_MATRIX2D_PARAMETER_COUNTS_1]->IsNumber()) {
246         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_1], rx);
247     }
248     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_2 && info[JS_MATRIX2D_PARAMETER_COUNTS_2]->IsNumber()) {
249         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_2], ry);
250     }
251     double density = GetDensity();
252     rx *= density;
253     ry *= density;
254     NG::Matrix2D::Rotate(transform_, degree, rx, ry);
255     info.SetReturnValue(info.This());
256 }
257 
JsTranslate(const JSCallbackInfo & info)258 void JSMatrix2d::JsTranslate(const JSCallbackInfo& info)
259 {
260     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_2) {
261         return;
262     }
263     double tx = 0;
264     double ty = 0;
265     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_0 && info[JS_MATRIX2D_PARAMETER_COUNTS_0]->IsNumber()) {
266         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_0], tx);
267     }
268     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_1 && info[JS_MATRIX2D_PARAMETER_COUNTS_1]->IsNumber()) {
269         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_1], ty);
270     }
271     double density = GetDensity();
272     tx *= density;
273     ty *= density;
274     NG::Matrix2D::Translate(transform_, tx, ty);
275     info.SetReturnValue(info.This());
276 }
277 
JsScale(const JSCallbackInfo & info)278 void JSMatrix2d::JsScale(const JSCallbackInfo& info)
279 {
280     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_2) {
281         return;
282     }
283     double sx = 1.0f;
284     double sy = 1.0f;
285     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_0 && info[JS_MATRIX2D_PARAMETER_COUNTS_0]->IsNumber()) {
286         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_0], sx);
287     }
288     if (info.Length() > JS_MATRIX2D_PARAMETER_COUNTS_1 && info[JS_MATRIX2D_PARAMETER_COUNTS_1]->IsNumber()) {
289         JSViewAbstract::ParseJsDouble(info[JS_MATRIX2D_PARAMETER_COUNTS_1], sy);
290     }
291     NG::Matrix2D::Scale(transform_, sx, sy);
292     info.SetReturnValue(info.This());
293 }
294 
ToString() const295 std::string JSMatrix2d::ToString() const
296 {
297     auto jsonValue = JsonUtil::Create(true);
298     jsonValue->Put("scaleX", transform_.scaleX);
299     jsonValue->Put("scaleY", transform_.scaleY);
300     jsonValue->Put("skewX", transform_.skewX);
301     jsonValue->Put("skewY", transform_.skewY);
302     jsonValue->Put("translateX", transform_.translateX);
303     jsonValue->Put("translateY", transform_.translateY);
304     return jsonValue->ToString();
305 }
306 } // namespace OHOS::Ace::Framework
307