• 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_text_blob.h"
17 #include "../js_drawing_utils.h"
18 #include "native_value.h"
19 #include "../font_napi/js_font.h"
20 #include "../js_common.h"
21 
22 namespace OHOS::Rosen {
23 namespace Drawing {
24 const std::string CLASS_NAME = "TextBlob";
25 thread_local napi_ref JsTextBlob::constructor_ = nullptr;
26 std::shared_ptr<TextBlob> drawingTextBlob;
Init(napi_env env,napi_value exportObj)27 napi_value JsTextBlob::Init(napi_env env, napi_value exportObj)
28 {
29     napi_property_descriptor properties[] = {
30         DECLARE_NAPI_FUNCTION("bounds", JsTextBlob::Bounds),
31         DECLARE_NAPI_STATIC_FUNCTION("makeFromString", JsTextBlob::MakeFromString),
32         DECLARE_NAPI_STATIC_FUNCTION("makeFromRunBuffer", JsTextBlob::MakeFromRunBuffer),
33     };
34 
35     napi_value constructor = nullptr;
36     napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
37                                            sizeof(properties) / sizeof(properties[0]), properties, &constructor);
38     if (status != napi_ok) {
39         ROSEN_LOGE("Drawing_napi: Failed to define TextBlob class");
40         return nullptr;
41     }
42 
43     status = napi_create_reference(env, constructor, 1, &constructor_);
44     if (status != napi_ok) {
45         ROSEN_LOGE("Drawing_napi: Failed to create reference of constructor");
46         return nullptr;
47     }
48 
49     status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
50     if (status != napi_ok) {
51         ROSEN_LOGE("Drawing_napi: Failed to set constructor");
52         return nullptr;
53     }
54 
55     status = napi_define_properties(env, exportObj, sizeof(properties) / sizeof(properties[0]), properties);
56     if (status != napi_ok) {
57         ROSEN_LOGE("Drawing_napi: Failed to define static function");
58         return nullptr;
59     }
60     return exportObj;
61 }
62 
~JsTextBlob()63 JsTextBlob::~JsTextBlob()
64 {
65     m_textBlob = nullptr;
66 }
67 
Constructor(napi_env env,napi_callback_info info)68 napi_value JsTextBlob::Constructor(napi_env env, napi_callback_info info)
69 {
70     size_t argCount = 0;
71     napi_value jsThis = nullptr;
72     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
73     if (status != napi_ok) {
74         ROSEN_LOGE("failed to napi_get_cb_info");
75         return nullptr;
76     }
77 
78     JsTextBlob *jsTextBlob = new(std::nothrow) JsTextBlob(env, drawingTextBlob);
79 
80     status = napi_wrap(env, jsThis, jsTextBlob,
81                        JsTextBlob::Destructor, nullptr, nullptr);
82     if (status != napi_ok) {
83         delete jsTextBlob;
84         ROSEN_LOGE("Failed to wrap native instance");
85         return nullptr;
86     }
87     return jsThis;
88 }
89 
Destructor(napi_env env,void * nativeObject,void * finalize)90 void JsTextBlob::Destructor(napi_env env, void *nativeObject, void *finalize)
91 {
92     (void)finalize;
93     if (nativeObject != nullptr) {
94         JsTextBlob *napi = reinterpret_cast<JsTextBlob *>(nativeObject);
95         delete napi;
96     }
97 }
98 
MakeFromRunBuffer(napi_env env,napi_callback_info info)99 napi_value JsTextBlob::MakeFromRunBuffer(napi_env env, napi_callback_info info)
100 {
101     size_t argc = ARGC_THREE;
102     napi_value argv[ARGC_THREE] = {nullptr};
103     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
104     if (status != napi_ok || argc < ARGC_TWO || argc > ARGC_THREE) {
105         ROSEN_LOGE("JsTextBlob::MakeFromRunBuffer Argc is invalid: %{public}zu", argc);
106         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
107     }
108 
109     napi_value array = argv[0];
110     uint32_t size = 0;
111     napi_get_array_length(env, array, &size);
112 
113     void* pointerResult = nullptr;
114     napi_unwrap(env, argv[1], &pointerResult);
115     auto jsFont = static_cast<JsFont*>(pointerResult);
116     if (jsFont == nullptr) {
117         ROSEN_LOGE("JsTextBlob::MakeFromRunBuffer jsFont is nullptr");
118         return nullptr;
119     }
120     std::shared_ptr<Font> font = jsFont->GetFont();
121     if (font == nullptr) {
122         ROSEN_LOGE("JsTextBlob::MakeFromRunBuffer font is nullptr");
123         return nullptr;
124     }
125 
126     TextBlobBuilder::RunBuffer runBuffer;
127     std::shared_ptr<TextBlobBuilder> textBlobBuilder = std::make_shared<TextBlobBuilder>();
128     if (argc == ARGC_TWO) {
129         runBuffer = textBlobBuilder->AllocRunPos(*font, size);
130     } else {
131         Rect drawingRect;
132         napi_valuetype isRectNullptr;
133         if (!OnMakeDrawingRect(env, argv[ARGC_TWO], drawingRect, isRectNullptr)) {
134             ROSEN_LOGE("JsTextBlob::MakeFromRunBuffer Argv[2] is invalid");
135             return nullptr;
136         }
137         runBuffer = textBlobBuilder->AllocRunPos(*font, size, isRectNullptr == napi_null ? nullptr : &drawingRect);
138     }
139     if (!OnMakeRunBuffer(env, runBuffer, size, array)) {
140         ROSEN_LOGE("JsTextBlob::MakeFromRunBuffer Argv[0] is invalid");
141         return nullptr;
142     }
143 
144     std::shared_ptr<TextBlob> textBlob = textBlobBuilder->Make();
145     if (textBlob == nullptr) {
146         ROSEN_LOGE("JsTextBlob::MakeFromRunBuffer textBlob is nullptr");
147         return nullptr;
148     }
149     return JsTextBlob::CreateJsTextBlob(env, textBlob);
150 }
151 
OnMakeDrawingRect(napi_env & env,napi_value & argv,Rect & drawingRect,napi_valuetype & isRectNullptr)152 bool JsTextBlob::OnMakeDrawingRect(napi_env& env, napi_value& argv, Rect& drawingRect, napi_valuetype& isRectNullptr)
153 {
154     napi_typeof(env, argv, &isRectNullptr);
155     if (isRectNullptr != napi_null) {
156         napi_value tempValue = nullptr;
157         double left = 0.0;
158         double top = 0.0;
159         double right = 0.0;
160         double bottom = 0.0;
161         napi_get_named_property(env, argv, "left", &tempValue);
162         bool isLeftOk = ConvertFromJsValue(env, tempValue, left);
163         napi_get_named_property(env, argv, "right", &tempValue);
164         bool isRightOk = ConvertFromJsValue(env, tempValue, right);
165         napi_get_named_property(env, argv, "top", &tempValue);
166         bool isTopOk = ConvertFromJsValue(env, tempValue, top);
167         napi_get_named_property(env, argv, "bottom", &tempValue);
168         bool isBottomOk = ConvertFromJsValue(env, tempValue, bottom);
169         if (!(isLeftOk && isRightOk && isTopOk && isBottomOk)) {
170             return false;
171         }
172 
173         drawingRect.SetLeft(left);
174         drawingRect.SetRight(right);
175         drawingRect.SetTop(top);
176         drawingRect.SetBottom(bottom);
177     }
178     return true;
179 }
180 
OnMakeRunBuffer(napi_env & env,TextBlobBuilder::RunBuffer & runBuffer,uint32_t size,napi_value & array)181 bool JsTextBlob::OnMakeRunBuffer(napi_env& env, TextBlobBuilder::RunBuffer& runBuffer, uint32_t size, napi_value& array)
182 {
183     for (uint32_t i = 0; i < size; i++) {
184         napi_value tempRunBuffer = nullptr;
185         napi_get_element(env, array, i, &tempRunBuffer);
186         napi_value tempValue = nullptr;
187         uint32_t glyph = 0;
188         double positionX = 0.0;
189         double positionY = 0.0;
190         napi_get_named_property(env, tempRunBuffer, "glyph", &tempValue);
191         bool isGlyphOk = ConvertFromJsValue(env, tempValue, glyph);
192         napi_get_named_property(env, tempRunBuffer, "positionX", &tempValue);
193         bool isPositionXOk = ConvertFromJsValue(env, tempValue, positionX);
194         napi_get_named_property(env, tempRunBuffer, "positionY", &tempValue);
195         bool isPositionYOk = ConvertFromJsValue(env, tempValue, positionY);
196         if (!(isGlyphOk && isPositionXOk && isPositionYOk)) {
197             return false;
198         }
199 
200         runBuffer.glyphs[i] = (uint16_t)glyph;
201         runBuffer.pos[2 * i] = positionX; // 2: double
202         runBuffer.pos[2 * i + 1] = positionY; // 2: double
203     }
204     return true;
205 }
206 
MakeFromString(napi_env env,napi_callback_info info)207 napi_value JsTextBlob::MakeFromString(napi_env env, napi_callback_info info)
208 {
209     size_t argc = ARGC_THREE;
210     napi_value argv[ARGC_THREE] = {nullptr};
211     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
212     if (status != napi_ok || argc < ARGC_TWO || argc > ARGC_THREE) {
213         ROSEN_LOGE("JsTextBlob::MakeFromString Argc is invalid: %{public}zu", argc);
214         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
215     }
216 
217     std::string text = "";
218     if (!ConvertFromJsValue(env, argv[0], text)) {
219         ROSEN_LOGE("JsTextBlob::MakeFromString Argv[0] is invalid");
220         return nullptr;
221     }
222 
223     void* pointerResult = nullptr;
224     napi_unwrap(env, argv[1], &pointerResult);
225     auto jsFont = static_cast<JsFont*>(pointerResult);
226     if (jsFont == nullptr) {
227         ROSEN_LOGE("JsTextBlob::MakeFromString jsFont is nullptr");
228         return nullptr;
229     }
230     std::shared_ptr<Font> font = jsFont->GetFont();
231     if (font == nullptr) {
232         ROSEN_LOGE("JsTextBlob::MakeFromString font is nullptr");
233         return nullptr;
234     }
235 
236     std::shared_ptr<TextBlob> textBlob;
237     if (argc == ARGC_TWO) {
238         textBlob = TextBlob::MakeFromString(text.c_str(), *font);
239     } else {
240         TextEncoding TextEncoding = TextEncoding::UTF8;
241         if (!ConvertFromJsTextEncoding(env, TextEncoding, argv[ARGC_TWO])) {
242             ROSEN_LOGE("JsTextBlob::MakeFromString Argv[2] is invalid");
243             return nullptr;
244         }
245         textBlob = TextBlob::MakeFromString(text.c_str(), *font, TextEncoding);
246     }
247 
248     if (textBlob == nullptr) {
249         ROSEN_LOGE("JsTextBlob::MakeFromString textBlob is nullptr");
250         return nullptr;
251     }
252     napi_value jsTextBlob = JsTextBlob::CreateJsTextBlob(env, textBlob);
253     if (jsTextBlob == nullptr) {
254         ROSEN_LOGE("JsTextBlob::MakeFromString jsTextBlob is nullptr");
255         return nullptr;
256     }
257     return jsTextBlob;
258 }
259 
CreateJsTextBlob(napi_env env,const std::shared_ptr<TextBlob> textBlob)260 napi_value JsTextBlob::CreateJsTextBlob(napi_env env, const std::shared_ptr<TextBlob> textBlob)
261 {
262     napi_value constructor = nullptr;
263     napi_value result = nullptr;
264     napi_status status = napi_get_reference_value(env, constructor_, &constructor);
265     if (status == napi_ok) {
266         drawingTextBlob = textBlob;
267         status = napi_new_instance(env, constructor, 0, nullptr, &result);
268         if (status == napi_ok) {
269             return result;
270         } else {
271             ROSEN_LOGE("JsTextBlob::CreateJsTextBlob New instance could not be obtained");
272         }
273     }
274     return result;
275 }
276 
Bounds(napi_env env,napi_callback_info info)277 napi_value JsTextBlob::Bounds(napi_env env, napi_callback_info info)
278 {
279     JsTextBlob* me = CheckParamsAndGetThis<JsTextBlob>(env, info);
280     return (me != nullptr) ? me->OnBounds(env, info) : nullptr;
281 }
282 
OnBounds(napi_env env,napi_callback_info info)283 napi_value JsTextBlob::OnBounds(napi_env env, napi_callback_info info)
284 {
285     if (m_textBlob == nullptr) {
286         ROSEN_LOGE("JsTextBlob::OnBounds textBlob is nullptr");
287         return NapiThrowError(env, DrawingErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
288     }
289     std::shared_ptr<Rect> rect = m_textBlob->Bounds();
290 
291     if (!rect) {
292         ROSEN_LOGE("JsTextBlob::OnBounds rect is nullptr");
293         return nullptr;
294     }
295     return GetRectAndConvertToJsValue(env, rect);
296 }
297 
GetTextBlob()298 std::shared_ptr<TextBlob> JsTextBlob::GetTextBlob()
299 {
300     return m_textBlob;
301 }
302 } // namespace Drawing
303 } // namespace OHOS::Rosen
304