• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "frameworks/bridge/declarative_frontend/engine/jsi/modules/jsi_matrix4_module.h"
17 
18 #include "base/geometry/matrix4.h"
19 #include "base/log/log.h"
20 #include "frameworks/bridge/js_frontend/engine/common/js_constants.h"
21 
22 namespace OHOS::Ace::Framework {
23 
24 namespace {
25 
26 constexpr int32_t MATRIX_LENGTH = 16;
27 
ConvertToMatrix(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value)28 Matrix4 ConvertToMatrix(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value)
29 {
30     Matrix4 result = Matrix4::CreateIdentity();
31     if (value->GetArrayLength(runtime) != MATRIX_LENGTH) {
32         LOGE("ConvertToMatrix failed, JSValueConst length != %d", MATRIX_LENGTH);
33         return result;
34     }
35     // in column order
36     for (int32_t i = 0; i < Matrix4::DIMENSION; i++) {
37         for (int32_t j = 0; j < Matrix4::DIMENSION; j++) {
38             auto index = i * Matrix4::DIMENSION + j;
39             auto itemJSValue = value->GetProperty(runtime, index);
40             if (!itemJSValue->IsNumber(runtime)) {
41                 LOGE("ConvertToMatrix failed, %s is not number", itemJSValue->ToString(runtime).c_str());
42                 return result;
43             }
44             result.Set(j, i, static_cast<float>(itemJSValue->ToDouble(runtime)));
45         }
46     }
47     return result;
48 }
49 
ConvertToJSValue(const shared_ptr<JsRuntime> & runtime,const Matrix4 & matrix)50 shared_ptr<JsValue> ConvertToJSValue(const shared_ptr<JsRuntime>& runtime, const Matrix4& matrix)
51 {
52     shared_ptr<JsValue> result = runtime->NewArray();
53     for (int32_t i = 0; i < Matrix4::DIMENSION; i++) {
54         for (int32_t j = 0; j < Matrix4::DIMENSION; j++) {
55             int32_t index = i * Matrix4::DIMENSION + j;
56             result->SetProperty(runtime, runtime->NewInt32(index), runtime->NewNumber(matrix.Get(j, i)));
57         }
58     }
59     return result;
60 }
61 
ConvertToDouble(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & value,double defaultValue)62 double ConvertToDouble(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& value, double defaultValue)
63 {
64     if (value == nullptr || !value->IsNumber(runtime)) {
65         return defaultValue;
66     }
67     return value->ToDouble(runtime);
68 }
69 
70 }
71 
Combine(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)72 shared_ptr<JsValue> Combine(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
73     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
74 {
75     if (argc != 1) {
76         LOGE("Combine failed, argc != 1");
77         return runtime->NewNull();
78     }
79     if (!argv[0]->IsObject(runtime)) {
80         LOGE("Combine failed, argv[0] is not object");
81         return runtime->NewNull();
82     }
83 
84     auto objA = argv[0]->GetProperty(runtime, MATRIX_4X4);
85     auto objB = thisObj->GetProperty(runtime, MATRIX_4X4);
86     auto matrixA = ConvertToMatrix(runtime, objA);
87     auto matrixB = ConvertToMatrix(runtime, objB);
88     auto newArrayJSValue = ConvertToJSValue(runtime, matrixA * matrixB);
89     thisObj->SetProperty(runtime, MATRIX_4X4, newArrayJSValue);
90     return thisObj;
91 }
92 
Invert(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)93 shared_ptr<JsValue> Invert(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
94     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
95 {
96     auto matrixArray = thisObj->GetProperty(runtime, MATRIX_4X4);
97     auto matrix = ConvertToMatrix(runtime, matrixArray);
98     matrix = Matrix4::Invert(matrix);
99     matrixArray = ConvertToJSValue(runtime, matrix);
100     thisObj->SetProperty(runtime, MATRIX_4X4, matrixArray);
101     return thisObj;
102 }
103 
Translate(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)104 shared_ptr<JsValue> Translate(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
105     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
106 {
107     if (argc != 1) {
108         LOGE("Translate failed, argc != 1");
109         return runtime->NewNull();
110     }
111     if (!argv[0]->IsObject(runtime)) {
112         LOGE("Translate failed, argv[0] is not object");
113         return runtime->NewNull();
114     }
115 
116     auto matrixArray = thisObj->GetProperty(runtime, MATRIX_4X4);
117     auto matrix = ConvertToMatrix(runtime, matrixArray);
118     auto dxJSValue = argv[0]->GetProperty(runtime, "x");
119     double dx = ConvertToDouble(runtime, dxJSValue, 0.0);
120     auto dyJSValue = argv[0]->GetProperty(runtime, "y");
121     double dy = ConvertToDouble(runtime, dyJSValue, 0.0);
122     auto dzJSValue = argv[0]->GetProperty(runtime, "z");
123     double dz = ConvertToDouble(runtime, dzJSValue, 0.0);
124 
125     matrix = Matrix4::CreateTranslate(static_cast<float>(dx), static_cast<float>(dy), static_cast<float>(dz)) * matrix;
126     thisObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
127     return thisObj;
128 }
129 
Scale(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)130 shared_ptr<JsValue> Scale(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
131     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
132 {
133     if (argc != 1) {
134         LOGE("Scale failed, argc != 1");
135         return runtime->NewNull();
136     }
137     if (!argv[0]->IsObject(runtime)) {
138         LOGE("Scale failed, argv[0] is not object");
139         return runtime->NewNull();
140     }
141 
142     auto matrixArray = thisObj->GetProperty(runtime, MATRIX_4X4);
143     auto matrix = ConvertToMatrix(runtime, matrixArray);
144     auto dxJSValue = argv[0]->GetProperty(runtime, "x");
145     double dx = ConvertToDouble(runtime, dxJSValue, 1.0);
146     auto dyJSValue = argv[0]->GetProperty(runtime, "y");
147     double dy = ConvertToDouble(runtime, dyJSValue, 1.0);
148     auto dzJSValue = argv[0]->GetProperty(runtime, "z");
149     double dz = ConvertToDouble(runtime, dzJSValue, 1.0);
150     auto centerXJSValue = argv[0]->GetProperty(runtime, "centerX");
151     double centerX = ConvertToDouble(runtime, centerXJSValue, 0.0);
152     auto centerYJSValue = argv[0]->GetProperty(runtime, "centerY");
153     double centerY = ConvertToDouble(runtime, centerYJSValue, 0.0);
154 
155     auto scaleMatrix = Matrix4::CreateScale(dx, dy, dz);
156     if (!NearZero(centerX) || !NearZero(centerY)) {
157         auto translate1 = Matrix4::CreateTranslate(centerX, centerY, 0.0);
158         auto translate2 = Matrix4::CreateTranslate(-centerX, -centerY, 0.0);
159         scaleMatrix = scaleMatrix * translate2;
160         scaleMatrix = translate1 * scaleMatrix;
161     }
162     matrix = scaleMatrix * matrix;
163     thisObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
164     return thisObj;
165 }
166 
Rotate(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)167 shared_ptr<JsValue> Rotate(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
168     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
169 {
170     if (argc != 1) {
171         LOGE("Rotate failed, argc != 1");
172         return runtime->NewNull();
173     }
174     if (!argv[0]->IsObject(runtime)) {
175         LOGE("Rotate failed, argv[0] is not object");
176         return runtime->NewNull();
177     }
178 
179     auto matrixArray = thisObj->GetProperty(runtime, MATRIX_4X4);
180     auto matrix = ConvertToMatrix(runtime, matrixArray);
181     auto dxJSValue = argv[0]->GetProperty(runtime, "x");
182     double dx = ConvertToDouble(runtime, dxJSValue, 0.0);
183     auto dyJSValue = argv[0]->GetProperty(runtime, "y");
184     double dy = ConvertToDouble(runtime, dyJSValue, 0.0);
185     auto dzJSValue = argv[0]->GetProperty(runtime, "z");
186     double dz = ConvertToDouble(runtime, dzJSValue, 0.0);
187     auto angleJSValue = argv[0]->GetProperty(runtime, "angle");
188     double angle = ConvertToDouble(runtime, angleJSValue, 0.0);
189     auto centerXJSValue = argv[0]->GetProperty(runtime, "centerX");
190     double centerX = ConvertToDouble(runtime, centerXJSValue, 0.0);
191     auto centerYJSValue = argv[0]->GetProperty(runtime, "centerY");
192     double centerY = ConvertToDouble(runtime, centerYJSValue, 0.0);
193 
194     auto rotateMatrix = Matrix4::CreateRotate(angle, dx, dy, dz);
195     if (!NearZero(centerX) || !NearZero(centerY)) {
196         auto translate1 = Matrix4::CreateTranslate(centerX, centerY, 0.0);
197         auto translate2 = Matrix4::CreateTranslate(-centerX, -centerY, 0.0);
198         rotateMatrix = rotateMatrix * translate2;
199         rotateMatrix = translate1 * rotateMatrix;
200     }
201     matrix = rotateMatrix * matrix;
202     matrixArray = ConvertToJSValue(runtime, matrix);
203     thisObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
204     return thisObj;
205 }
206 
TransformPoint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)207 shared_ptr<JsValue> TransformPoint(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
208     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
209 {
210     if (argc != 1) {
211         LOGE("TransformPoint failed, argc != 1");
212         return runtime->NewNull();
213     }
214     if (!argv[0]->IsArray(runtime) || argv[0]->GetArrayLength(runtime) != 2) {
215         LOGE("TransformPoint failed, argv[0] is not array or length != 2");
216         return runtime->NewNull();
217     }
218     auto matrix = ConvertToMatrix(runtime, thisObj->GetProperty(runtime, MATRIX_4X4));
219 
220     auto pointXJSValue = argv[0]->GetProperty(runtime, 0);
221     double pointX = ConvertToDouble(runtime, pointXJSValue, 0.0);
222 
223     auto pointYJSValue = argv[0]->GetProperty(runtime, 1);
224     double pointY = ConvertToDouble(runtime, pointYJSValue, 0.0);
225 
226     Point point { pointX, pointY };
227     Point target = matrix * point;
228     shared_ptr<JsValue> result = runtime->NewArray();
229     result->SetProperty(runtime, runtime->NewInt32(0), runtime->NewNumber(target.GetX()));
230     result->SetProperty(runtime, runtime->NewInt32(1), runtime->NewNumber(target.GetY()));
231     return result;
232 }
233 
234 shared_ptr<JsValue> Copy(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
235     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc);
236 
AddCommonMatrixProperties(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & obj)237 void AddCommonMatrixProperties(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& obj)
238 {
239     obj->SetProperty(runtime, MATRIX_COPY, runtime->NewFunction(Copy));
240     obj->SetProperty(runtime, MATRIX_COMBINE, runtime->NewFunction(Combine));
241     obj->SetProperty(runtime, MATRIX_INVERT, runtime->NewFunction(Invert));
242     obj->SetProperty(runtime, MATRIX_TRANSLATE, runtime->NewFunction(Translate));
243     obj->SetProperty(runtime, MATRIX_SCALE, runtime->NewFunction(Scale));
244     obj->SetProperty(runtime, MATRIX_ROTATE, runtime->NewFunction(Rotate));
245     obj->SetProperty(runtime, MATRIX_TRANSFORM_POINT, runtime->NewFunction(TransformPoint));
246 }
247 
Copy(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)248 shared_ptr<JsValue> Copy(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
249     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
250 {
251     auto matrix = ConvertToMatrix(runtime, thisObj->GetProperty(runtime, MATRIX_4X4));
252     // create new object
253     shared_ptr<JsValue> other = runtime->NewObject();
254     // init functions
255     InitMatrix4Module(runtime, other);
256     // update matrix4x4
257     other->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
258     AddCommonMatrixProperties(runtime, other);
259     return other;
260 }
261 
Init(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)262 shared_ptr<JsValue> Init(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
263     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
264 {
265     if (argc != 1) {
266         LOGE("PagePush args count is invalid");
267         return runtime->NewNull();
268     }
269 
270     auto matrix = ConvertToMatrix(runtime, argv[0]);
271     shared_ptr<JsValue> matrixObj = runtime->NewObject();
272     matrixObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
273     AddCommonMatrixProperties(runtime, matrixObj);
274     return matrixObj;
275 }
276 
Identity(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)277 shared_ptr<JsValue> Identity(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
278     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
279 {
280     shared_ptr<JsValue> matrixObj = runtime->NewObject();
281     matrixObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, Matrix4::CreateIdentity()));
282     AddCommonMatrixProperties(runtime, matrixObj);
283     return matrixObj;
284 }
285 
InitMatrix4Module(const shared_ptr<JsRuntime> & runtime,shared_ptr<JsValue> & moduleObj)286 void InitMatrix4Module(const shared_ptr<JsRuntime>& runtime, shared_ptr<JsValue>& moduleObj)
287 {
288     moduleObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, Matrix4::CreateIdentity()));
289     moduleObj->SetProperty(runtime, MATRIX_INIT, runtime->NewFunction(Init));
290     moduleObj->SetProperty(runtime, MATRIX_IDENTITY, runtime->NewFunction(Identity));
291 }
292 
293 } // namespace OHOS::Ace::Framework
294