• 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 
Init(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)72 shared_ptr<JsValue> Init(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("PagePush args count is invalid");
77         return runtime->NewNull();
78     }
79 
80     int32_t length = argv[0]->GetArrayLength(runtime);
81     if (length != MATRIX_LENGTH) {
82         LOGE("matrix init array length %d not equal %d", length, MATRIX_LENGTH);
83         return runtime->NewNull();
84     }
85 
86     auto matrix = ConvertToMatrix(runtime, argv[0]);
87     thisObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
88     return thisObj;
89 }
90 
Combine(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)91 shared_ptr<JsValue> Combine(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
92     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
93 {
94     if (argc != 1) {
95         LOGE("Combine failed, argc != 1");
96         return runtime->NewNull();
97     }
98     if (!argv[0]->IsObject(runtime)) {
99         LOGE("Combine failed, argv[0] is not object");
100         return runtime->NewNull();
101     }
102 
103     auto objA = argv[0]->GetProperty(runtime, MATRIX_4X4);
104     auto objB = thisObj->GetProperty(runtime, MATRIX_4X4);
105     auto matrixA = ConvertToMatrix(runtime, objA);
106     auto matrixB = ConvertToMatrix(runtime, objB);
107     auto newArrayJSValue = ConvertToJSValue(runtime, matrixA * matrixB);
108     thisObj->SetProperty(runtime, MATRIX_4X4, newArrayJSValue);
109     return thisObj;
110 }
111 
Invert(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)112 shared_ptr<JsValue> Invert(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
113     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
114 {
115     auto matrixArray = thisObj->GetProperty(runtime, MATRIX_4X4);
116     auto matrix = ConvertToMatrix(runtime, matrixArray);
117     matrix = Matrix4::Invert(matrix);
118     matrixArray = ConvertToJSValue(runtime, matrix);
119     thisObj->SetProperty(runtime, MATRIX_4X4, matrixArray);
120     return thisObj;
121 }
122 
Translate(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)123 shared_ptr<JsValue> Translate(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
124     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
125 {
126     if (argc != 1) {
127         LOGE("Translate failed, argc != 1");
128         return runtime->NewNull();
129     }
130     if (!argv[0]->IsObject(runtime)) {
131         LOGE("Translate failed, argv[0] is not object");
132         return runtime->NewNull();
133     }
134 
135     auto matrixArray = thisObj->GetProperty(runtime, MATRIX_4X4);
136     auto matrix = ConvertToMatrix(runtime, matrixArray);
137     auto dxJSValue = argv[0]->GetProperty(runtime, "x");
138     double dx = ConvertToDouble(runtime, dxJSValue, 0.0);
139     auto dyJSValue = argv[0]->GetProperty(runtime, "y");
140     double dy = ConvertToDouble(runtime, dyJSValue, 0.0);
141     auto dzJSValue = argv[0]->GetProperty(runtime, "z");
142     double dz = ConvertToDouble(runtime, dzJSValue, 0.0);
143 
144     matrix = Matrix4::CreateTranslate(static_cast<float>(dx), static_cast<float>(dy), static_cast<float>(dz)) * matrix;
145     thisObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
146     return thisObj;
147 }
148 
Scale(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)149 shared_ptr<JsValue> Scale(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
150     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
151 {
152     if (argc != 1) {
153         LOGE("Scale failed, argc != 1");
154         return runtime->NewNull();
155     }
156     if (!argv[0]->IsObject(runtime)) {
157         LOGE("Scale failed, argv[0] is not object");
158         return runtime->NewNull();
159     }
160 
161     auto matrixArray = thisObj->GetProperty(runtime, MATRIX_4X4);
162     auto matrix = ConvertToMatrix(runtime, matrixArray);
163     auto dxJSValue = argv[0]->GetProperty(runtime, "x");
164     double dx = ConvertToDouble(runtime, dxJSValue, 1.0);
165     auto dyJSValue = argv[0]->GetProperty(runtime, "y");
166     double dy = ConvertToDouble(runtime, dyJSValue, 1.0);
167     auto dzJSValue = argv[0]->GetProperty(runtime, "z");
168     double dz = ConvertToDouble(runtime, dzJSValue, 1.0);
169     auto centerXJSValue = argv[0]->GetProperty(runtime, "centerX");
170     double centerX = ConvertToDouble(runtime, centerXJSValue, 0.0);
171     auto centerYJSValue = argv[0]->GetProperty(runtime, "centerY");
172     double centerY = ConvertToDouble(runtime, centerYJSValue, 0.0);
173 
174     auto scaleMatrix = Matrix4::CreateScale(dx, dy, dz);
175     if (!NearZero(centerX) || !NearZero(centerY)) {
176         auto translate1 = Matrix4::CreateTranslate(centerX, centerY, 0.0);
177         auto translate2 = Matrix4::CreateTranslate(-centerX, -centerY, 0.0);
178         scaleMatrix = scaleMatrix * translate2;
179         scaleMatrix = translate1 * scaleMatrix;
180     }
181     matrix = scaleMatrix * matrix;
182     thisObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
183     return thisObj;
184 }
185 
Rotate(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)186 shared_ptr<JsValue> Rotate(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
187     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
188 {
189     if (argc != 1) {
190         LOGE("Rotate failed, argc != 1");
191         return runtime->NewNull();
192     }
193     if (!argv[0]->IsObject(runtime)) {
194         LOGE("Rotate failed, argv[0] is not object");
195         return runtime->NewNull();
196     }
197 
198     auto matrixArray = thisObj->GetProperty(runtime, MATRIX_4X4);
199     auto matrix = ConvertToMatrix(runtime, matrixArray);
200     auto dxJSValue = argv[0]->GetProperty(runtime, "x");
201     double dx = ConvertToDouble(runtime, dxJSValue, 0.0);
202     auto dyJSValue = argv[0]->GetProperty(runtime, "y");
203     double dy = ConvertToDouble(runtime, dyJSValue, 0.0);
204     auto dzJSValue = argv[0]->GetProperty(runtime, "z");
205     double dz = ConvertToDouble(runtime, dzJSValue, 0.0);
206     auto angleJSValue = argv[0]->GetProperty(runtime, "angle");
207     double angle = ConvertToDouble(runtime, angleJSValue, 0.0);
208     auto centerXJSValue = argv[0]->GetProperty(runtime, "centerX");
209     double centerX = ConvertToDouble(runtime, centerXJSValue, 0.0);
210     auto centerYJSValue = argv[0]->GetProperty(runtime, "centerY");
211     double centerY = ConvertToDouble(runtime, centerYJSValue, 0.0);
212 
213     auto rotateMatrix = Matrix4::CreateRotate(angle, dx, dy, dz);
214     if (!NearZero(centerX) || !NearZero(centerY)) {
215         auto translate1 = Matrix4::CreateTranslate(centerX, centerY, 0.0);
216         auto translate2 = Matrix4::CreateTranslate(-centerX, -centerY, 0.0);
217         rotateMatrix = rotateMatrix * translate2;
218         rotateMatrix = translate1 * rotateMatrix;
219     }
220     matrix = rotateMatrix * matrix;
221     matrixArray = ConvertToJSValue(runtime, matrix);
222     thisObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
223     return thisObj;
224 }
225 
TransformPoint(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)226 shared_ptr<JsValue> TransformPoint(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
227     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
228 {
229     if (argc != 1) {
230         LOGE("TransformPoint failed, argc != 1");
231         return runtime->NewNull();
232     }
233     if (!argv[0]->IsArray(runtime) || argv[0]->GetArrayLength(runtime) != 2) {
234         LOGE("TransformPoint failed, argv[0] is not array or length != 2");
235         return runtime->NewNull();
236     }
237     auto matrix = ConvertToMatrix(runtime, thisObj->GetProperty(runtime, MATRIX_4X4));
238 
239     auto pointXJSValue = argv[0]->GetProperty(runtime, 0);
240     double pointX = ConvertToDouble(runtime, pointXJSValue, 0.0);
241 
242     auto pointYJSValue = argv[0]->GetProperty(runtime, 1);
243     double pointY = ConvertToDouble(runtime, pointYJSValue, 0.0);
244 
245     Point point { pointX, pointY };
246     Point target = matrix * point;
247     shared_ptr<JsValue> result = runtime->NewArray();
248     result->SetProperty(runtime, runtime->NewInt32(0), runtime->NewNumber(target.GetX()));
249     result->SetProperty(runtime, runtime->NewInt32(1), runtime->NewNumber(target.GetY()));
250     return result;
251 }
252 
Copy(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)253 shared_ptr<JsValue> Copy(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
254     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
255 {
256     auto matrix = ConvertToMatrix(runtime, thisObj->GetProperty(runtime, MATRIX_4X4));
257     // create new object
258     shared_ptr<JsValue> other = runtime->NewObject();
259     // init functions
260     InitMatrix4Module(runtime, other);
261     // update matrix4x4
262     other->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, matrix));
263     other->SetProperty(runtime, MATRIX_COPY, runtime->NewFunction(Copy));
264     other->SetProperty(runtime, MATRIX_COMBINE, runtime->NewFunction(Combine));
265     other->SetProperty(runtime, MATRIX_INVERT, runtime->NewFunction(Invert));
266     other->SetProperty(runtime, MATRIX_TRANSLATE, runtime->NewFunction(Translate));
267     other->SetProperty(runtime, MATRIX_SCALE, runtime->NewFunction(Scale));
268     other->SetProperty(runtime, MATRIX_ROTATE, runtime->NewFunction(Rotate));
269     other->SetProperty(runtime, MATRIX_TRANSFORM_POINT, runtime->NewFunction(TransformPoint));
270     return other;
271 }
272 
Identity(const shared_ptr<JsRuntime> & runtime,const shared_ptr<JsValue> & thisObj,const std::vector<shared_ptr<JsValue>> & argv,int32_t argc)273 shared_ptr<JsValue> Identity(const shared_ptr<JsRuntime>& runtime, const shared_ptr<JsValue>& thisObj,
274     const std::vector<shared_ptr<JsValue>>& argv, int32_t argc)
275 {
276     shared_ptr<JsValue> matrixObj = runtime->NewObject();
277     matrixObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, Matrix4::CreateIdentity()));
278     matrixObj->SetProperty(runtime, MATRIX_COPY, runtime->NewFunction(Copy));
279     matrixObj->SetProperty(runtime, MATRIX_COMBINE, runtime->NewFunction(Combine));
280     matrixObj->SetProperty(runtime, MATRIX_INVERT, runtime->NewFunction(Invert));
281     matrixObj->SetProperty(runtime, MATRIX_TRANSLATE, runtime->NewFunction(Translate));
282     matrixObj->SetProperty(runtime, MATRIX_SCALE, runtime->NewFunction(Scale));
283     matrixObj->SetProperty(runtime, MATRIX_ROTATE, runtime->NewFunction(Rotate));
284     matrixObj->SetProperty(runtime, MATRIX_TRANSFORM_POINT, runtime->NewFunction(TransformPoint));
285     return matrixObj;
286 }
287 
InitMatrix4Module(const shared_ptr<JsRuntime> & runtime,shared_ptr<JsValue> & moduleObj)288 void InitMatrix4Module(const shared_ptr<JsRuntime>& runtime, shared_ptr<JsValue>& moduleObj)
289 {
290     moduleObj->SetProperty(runtime, MATRIX_4X4, ConvertToJSValue(runtime, Matrix4::CreateIdentity()));
291     moduleObj->SetProperty(runtime, MATRIX_INIT, runtime->NewFunction(Init));
292     moduleObj->SetProperty(runtime, MATRIX_IDENTITY, runtime->NewFunction(Identity));
293 }
294 
295 } // namespace OHOS::Ace::Framework
296