• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "js_path_iterator.h"
17 
18 #include "native_value.h"
19 
20 #include "path_napi/js_path.h"
21 
22 namespace OHOS::Rosen {
23 namespace Drawing {
24 thread_local napi_ref JsPathIterator::constructor_ = nullptr;
25 const std::string CLASS_NAME = "PathIterator";
26 
27 static const napi_property_descriptor g_properties[] = {
28     DECLARE_NAPI_FUNCTION("next", JsPathIterator::Next),
29     DECLARE_NAPI_FUNCTION("hasNext", JsPathIterator::HasNext),
30     DECLARE_NAPI_FUNCTION("peek", JsPathIterator::Peek),
31 };
32 
nextInternal()33 PathVerb JsPathIterator::nextInternal()
34 {
35     if (m_done) {
36         return PathVerb::DONE;
37     }
38     PathVerb verb = m_iter->Next(m_points);
39     if (verb == PathVerb::CONIC) {
40         float weight = m_iter->ConicWeight();
41         m_points[MAX_PAIRS_PATHVERB-1].SetX(weight);
42     } else if (verb == PathVerb::DONE) {
43         m_done = true;
44     }
45     return verb;
46 }
47 
getReturnVerb(const PathVerb & cachedVerb)48 PathVerb JsPathIterator::getReturnVerb(const PathVerb& cachedVerb)
49 {
50     switch (cachedVerb) {
51         case PathVerb::MOVE: return PathVerb::MOVE;
52         case PathVerb::LINE: return PathVerb::LINE;
53         case PathVerb::QUAD: return PathVerb::QUAD;
54         case PathVerb::CONIC: return PathVerb::CONIC;
55         case PathVerb::CUBIC: return PathVerb::CUBIC;
56         case PathVerb::CLOSE: return PathVerb::CLOSE;
57         case PathVerb::DONE: return PathVerb::DONE;
58         default: return nextInternal();
59     }
60 }
61 
Init(napi_env env,napi_value exportObj)62 napi_value JsPathIterator::Init(napi_env env, napi_value exportObj)
63 {
64     napi_value constructor = nullptr;
65     napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
66         sizeof(g_properties) / sizeof(g_properties[0]), g_properties, &constructor);
67     if (status != napi_ok) {
68         ROSEN_LOGE("Failed to define PathIterator class");
69         return nullptr;
70     }
71 
72     status = napi_create_reference(env, constructor, 1, &constructor_);
73     if (status != napi_ok) {
74         ROSEN_LOGE("Failed to create reference of constructor");
75         return nullptr;
76     }
77 
78     status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
79     if (status != napi_ok) {
80         ROSEN_LOGE("Failed to set constructor");
81         return nullptr;
82     }
83 
84     return exportObj;
85 }
86 
Constructor(napi_env env,napi_callback_info info)87 napi_value JsPathIterator::Constructor(napi_env env, napi_callback_info info)
88 {
89     size_t argc = ARGC_ONE;
90     napi_value argv[ARGC_ONE] = {nullptr};
91     napi_value jsThis = nullptr;
92     JsPathIterator* jsPathIterator = nullptr;
93     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
94     if (status != napi_ok) {
95         ROSEN_LOGE("PathIterator::Constructor Failed to napi_get_cb_info");
96         return nullptr;
97     }
98     if (argc == ARGC_ONE) {
99         napi_valuetype valueType = napi_undefined;
100         if (argv[0] == nullptr || napi_typeof(env, argv[0], &valueType) != napi_ok || valueType != napi_object) {
101             return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
102                 "JsPathIterator::Constructor Argv[0] is invalid");
103         }
104         JsPath* path = nullptr;
105         GET_UNWRAP_PARAM(ARGC_ZERO, path);
106         PathIterator* p = new PathIterator(*path->GetPath());
107         jsPathIterator = new JsPathIterator(p);
108     } else {
109         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect number of parameters.");
110     }
111     if (!jsPathIterator) {
112         ROSEN_LOGE("Failed to create JsPathIterator");
113         return nullptr;
114     }
115     status = napi_wrap(env, jsThis, jsPathIterator,
116         JsPathIterator::Destructor, nullptr, nullptr);
117     if (status != napi_ok) {
118         delete jsPathIterator;
119         ROSEN_LOGE("JsPathIterator::Constructor Failed to wrap native instance");
120         return nullptr;
121     }
122     return jsThis;
123 }
124 
Destructor(napi_env env,void * nativeObject,void * finalize)125 void JsPathIterator::Destructor(napi_env env, void *nativeObject, void *finalize)
126 {
127     (void)finalize;
128     if (nativeObject != nullptr) {
129         JsPathIterator *napi = reinterpret_cast<JsPathIterator *>(nativeObject);
130         delete napi;
131     }
132 }
133 
CreateJsPathIterator(napi_env env,PathIterator * iter)134 napi_value JsPathIterator::CreateJsPathIterator(napi_env env, PathIterator* iter)
135 {
136     napi_value constructor = nullptr;
137     napi_status status = napi_get_reference_value(env, constructor_, &constructor);
138     if (status != napi_ok) {
139         delete iter;
140         ROSEN_LOGE("JsPathIterator::CreateJsPathIterator Failed to napi_get_reference_value!");
141         return nullptr;
142     }
143     napi_value result = nullptr;
144     napi_create_object(env, &result);
145     if (result == nullptr) {
146         delete iter;
147         ROSEN_LOGE("JsPathIterator::CreateJsPath Create pathiterator object failed!");
148         return nullptr;
149     }
150     JsPathIterator* jsPathIterator = new JsPathIterator(iter);
151     status = napi_wrap(env, result, jsPathIterator, JsPathIterator::Destructor, nullptr, nullptr);
152     if (status != napi_ok) {
153         delete jsPathIterator;
154         ROSEN_LOGE("JsPathIterator::CreateJsPath failed to wrap native instance");
155         return nullptr;
156     }
157     napi_define_properties(env, result, sizeof(g_properties) / sizeof(g_properties[0]), g_properties);
158     return result;
159 }
160 
~JsPathIterator()161 JsPathIterator::~JsPathIterator()
162 {
163     if (m_iter != nullptr) {
164         delete m_iter;
165         m_iter = nullptr;
166     }
167 }
168 
Next(napi_env env,napi_callback_info info)169 napi_value JsPathIterator::Next(napi_env env, napi_callback_info info)
170 {
171     JsPathIterator* me = CheckParamsAndGetThis<JsPathIterator>(env, info);
172     return (me != nullptr) ? me->OnNext(env, info) : nullptr;
173 }
174 
HasNext(napi_env env,napi_callback_info info)175 napi_value JsPathIterator::HasNext(napi_env env, napi_callback_info info)
176 {
177     JsPathIterator* me = CheckParamsAndGetThis<JsPathIterator>(env, info);
178     return (me != nullptr) ? me->OnHasNext(env, info) : nullptr;
179 }
180 
Peek(napi_env env,napi_callback_info info)181 napi_value JsPathIterator::Peek(napi_env env, napi_callback_info info)
182 {
183     JsPathIterator* me = CheckParamsAndGetThis<JsPathIterator>(env, info);
184     return (me != nullptr) ? me->OnPeek(env, info) : nullptr;
185 }
186 
OnNext(napi_env env,napi_callback_info info)187 napi_value JsPathIterator::OnNext(napi_env env, napi_callback_info info)
188 {
189     if (m_iter == nullptr) {
190         ROSEN_LOGE("JsPathIterator::OnNext pathiterator is nullptr");
191         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
192     }
193 
194     size_t argc = ARGC_TWO;
195     napi_value argv[ARGC_TWO] = { nullptr };
196     CHECK_PARAM_NUMBER_WITH_OPTIONAL_PARAMS(argv, argc, ARGC_ONE, ARGC_TWO);
197 
198     napi_value array = argv[ARGC_ZERO];
199 
200     int32_t offset = 0;
201     if (argc == ARGC_TWO) {
202         GET_INT32_PARAM(ARGC_ONE, offset);
203         if (offset < 0) {
204             ROSEN_LOGE("JsPathIterator::OnNext offset is incorrect.");
205             return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM,
206                 "Parameter verification failed. The value of offset must be greater than or equal to 0.");
207         }
208     }
209 
210     uint32_t size = 0;
211     if (napi_get_array_length(env, array, &size) != napi_ok ||
212         size < static_cast<uint32_t>(offset) + MAX_PAIRS_PATHVERB) {
213         ROSEN_LOGE("JsPathIterator::OnNext array size is incorrect.");
214         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Incorrect array size.");
215     }
216 
217     PathVerb returnVerb = getReturnVerb(m_verb);
218     m_verb = PathVerb::UNINIT;
219 
220     for (uint32_t i = 0; i < MAX_PAIRS_PATHVERB; i++) {
221         if (napi_set_element(env, array, i + offset, ConvertPointToJsValue(env, m_points[i])) != napi_ok) {
222             ROSEN_LOGE("JsPathIterator::OnNext set array failed");
223             return nullptr;
224         }
225     }
226 
227     return CreateJsNumber(env, static_cast<uint32_t>(returnVerb));
228 }
229 
OnPeek(napi_env env,napi_callback_info info)230 napi_value JsPathIterator::OnPeek(napi_env env, napi_callback_info info)
231 {
232     if (m_iter == nullptr) {
233         ROSEN_LOGE("JsPathIterator::OnPeek pathiterator is nullptr");
234         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
235     }
236     if (m_done) {
237         return CreateJsNumber(env, static_cast<int32_t>(PathVerb::DONE));
238     }
239     return CreateJsNumber(env, static_cast<int32_t>(m_iter->Peek()));
240 }
241 
OnHasNext(napi_env env,napi_callback_info info)242 napi_value JsPathIterator::OnHasNext(napi_env env, napi_callback_info info)
243 {
244     if (m_iter == nullptr) {
245         ROSEN_LOGE("JsPathIterator::OnHasNext pathiterator is nullptr");
246         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
247     }
248     if (m_verb == PathVerb::UNINIT) {
249         m_verb = nextInternal();
250     }
251     return CreateJsValue(env, m_verb != PathVerb::DONE);
252 }
253 
GetPathIterator()254 PathIterator* JsPathIterator::GetPathIterator()
255 {
256     return m_iter;
257 }
258 } // namespace Drawing
259 } // namespace OHOS::Rosen
260