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