• 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_paragraph_builder.h"
17 
18 #include <string>
19 
20 #include "fontcollection_napi/js_fontcollection.h"
21 #include "js_native_api.h"
22 #include "line_typeset_napi/js_line_typeset.h"
23 #include "napi_common.h"
24 #include "paragraph_napi/js_paragraph.h"
25 #include "txt/text_bundle_config_parser.h"
26 #include "utils/string_util.h"
27 #include "utils/text_log.h"
28 
29 namespace OHOS::Rosen {
30 namespace {
31 const std::string CLASS_NAME = "ParagraphBuilder";
32 }
33 
34 thread_local napi_ref JsParagraphBuilder::constructor_ = nullptr;
35 
Constructor(napi_env env,napi_callback_info info)36 napi_value JsParagraphBuilder::Constructor(napi_env env, napi_callback_info info)
37 {
38     size_t argCount = ARGC_TWO;
39     napi_value jsThis = nullptr;
40     napi_value argv[ARGC_TWO] = {nullptr};
41     napi_status status = napi_get_cb_info(env, info, &argCount, argv, &jsThis, nullptr);
42     if (status != napi_ok || argCount != ARGC_TWO) {
43         TEXT_LOGE("Failed to get parameter, argc %{public}zu, ret %{public}d", argCount, status);
44         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
45     }
46     TypographyStyle typographyStyle;
47     GetParagraphStyleFromJS(env, argv[0], typographyStyle);
48     JsFontCollection* jsFontCollection = nullptr;
49     status = napi_unwrap(env, argv[1], reinterpret_cast<void**>(&jsFontCollection));
50 
51     if (jsFontCollection == nullptr) {
52         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
53     }
54     if (status != napi_ok) {
55         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Get jsFontCollection error.");
56     }
57 
58     std::shared_ptr<FontCollection> fontCollection = jsFontCollection->GetFontCollection();
59     std::unique_ptr<TypographyCreate> typographyCreate = TypographyCreate::Create(typographyStyle, fontCollection);
60     if (!typographyCreate) {
61         TEXT_LOGE("Failed to create typography creator");
62         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "TypographyCreate Create error.");
63     }
64 
65     JsParagraphBuilder* jsParagraphBuilder = new(std::nothrow) JsParagraphBuilder();
66     if (!jsParagraphBuilder) {
67         TEXT_LOGE("Failed to create paragraph builder");
68         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "JsParagraphBuilder Create error.");
69     }
70     jsParagraphBuilder->SetTypographyCreate(std::move(typographyCreate));
71 
72     status = napi_wrap(env, jsThis, jsParagraphBuilder,
73         JsParagraphBuilder::Destructor, nullptr, nullptr);
74     if (status != napi_ok) {
75         TEXT_LOGE("Failed to wrap paragraphy builder, ret %{public}d", status);
76         delete jsParagraphBuilder;
77         return nullptr;
78     }
79 
80     return jsThis;
81 }
82 
SetTypographyCreate(std::unique_ptr<TypographyCreate> typographyCreate)83 void JsParagraphBuilder::SetTypographyCreate(std::unique_ptr<TypographyCreate> typographyCreate)
84 {
85     typographyCreate_ = std::move(typographyCreate);
86 }
87 
Init(napi_env env,napi_value exportObj)88 napi_value JsParagraphBuilder::Init(napi_env env, napi_value exportObj)
89 {
90     napi_property_descriptor properties[] = {
91         DECLARE_NAPI_FUNCTION("pushStyle", JsParagraphBuilder::PushStyle),
92         DECLARE_NAPI_FUNCTION("addText", JsParagraphBuilder::AddText),
93         DECLARE_NAPI_FUNCTION("popStyle", JsParagraphBuilder::PopStyle),
94         DECLARE_NAPI_FUNCTION("addPlaceholder", JsParagraphBuilder::AddPlaceholder),
95         DECLARE_NAPI_FUNCTION("build", JsParagraphBuilder::Build),
96         DECLARE_NAPI_FUNCTION("buildLineTypeset", JsParagraphBuilder::BuildLineTypeset),
97         DECLARE_NAPI_FUNCTION("addSymbol", JsParagraphBuilder::AppendSymbol),
98     };
99 
100     napi_value constructor = nullptr;
101     napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
102         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
103     if (status != napi_ok) {
104         TEXT_LOGE("Failed to define class, ret %{public}d", status);
105         return nullptr;
106     }
107 
108     status = napi_create_reference(env, constructor, 1, &constructor_);
109     if (status != napi_ok) {
110         TEXT_LOGE("Failed to create reference");
111         return nullptr;
112     }
113 
114     status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
115     if (status != napi_ok) {
116         TEXT_LOGE("Failed to set named property, ret %{public}d", status);
117         return nullptr;
118     }
119     return exportObj;
120 }
121 
Destructor(napi_env env,void * nativeObject,void * finalize)122 void JsParagraphBuilder::Destructor(napi_env env, void* nativeObject, void* finalize)
123 {
124     (void)finalize;
125     if (nativeObject != nullptr) {
126         JsParagraphBuilder* napi = reinterpret_cast<JsParagraphBuilder *>(nativeObject);
127         delete napi;
128     }
129 }
130 
PushStyle(napi_env env,napi_callback_info info)131 napi_value JsParagraphBuilder::PushStyle(napi_env env, napi_callback_info info)
132 {
133     JsParagraphBuilder* me = CheckParamsAndGetThis<JsParagraphBuilder>(env, info);
134     return (me != nullptr) ? me->OnPushStyle(env, info) : nullptr;
135 }
136 
OnPushStyle(napi_env env,napi_callback_info info)137 napi_value JsParagraphBuilder::OnPushStyle(napi_env env, napi_callback_info info)
138 {
139     if (typographyCreate_ == nullptr) {
140         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
141     }
142     size_t argc = ARGC_ONE;
143     napi_value argv[ARGC_ONE] = {nullptr};
144     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
145     if (status != napi_ok || argc < ARGC_ONE) {
146         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
147     }
148     napi_valuetype valueType = napi_undefined;
149     if (argv[0] == nullptr || napi_typeof(env, argv[0], &valueType) != napi_ok || valueType != napi_object) {
150         return NapiGetUndefined(env);
151     }
152     TextStyle textStyle;
153     if (GetTextStyleFromJS(env, argv[0], textStyle)) {
154         typographyCreate_->PushStyle(textStyle);
155     }
156     return NapiGetUndefined(env);
157 }
158 
AddText(napi_env env,napi_callback_info info)159 napi_value JsParagraphBuilder::AddText(napi_env env, napi_callback_info info)
160 {
161     JsParagraphBuilder* me = CheckParamsAndGetThis<JsParagraphBuilder>(env, info);
162     return (me != nullptr) ? me->OnAddText(env, info) : nullptr;
163 }
OnAddText(napi_env env,napi_callback_info info)164 napi_value JsParagraphBuilder::OnAddText(napi_env env, napi_callback_info info)
165 {
166     if (typographyCreate_ == nullptr) {
167         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid typographyCreate");
168     }
169     size_t argc = ARGC_ONE;
170     napi_value argv[ARGC_ONE] = {nullptr};
171     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
172     if (status != napi_ok || argc < ARGC_ONE) {
173         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid param 0");
174     }
175     napi_valuetype valueType = napi_undefined;
176     if (argv[0] == nullptr || napi_typeof(env, argv[0], &valueType) != napi_ok) {
177         return NapiGetUndefined(env);
178     }
179 
180     if (SPText::TextBundleConfigParser::GetInstance().IsTargetApiVersion(SPText::SINCE_API18_VERSION)) {
181         size_t len = 0;
182         if (napi_get_value_string_utf16(env, argv[0], nullptr, 0, &len) != napi_ok) {
183             TEXT_LOGE("Failed to get utf16 length");
184             return NapiGetUndefined(env);
185         }
186 
187         auto buffer = std::make_unique<char16_t[]>(len + 1);
188         if (napi_get_value_string_utf16(env, argv[0], buffer.get(), len + 1, &len) != napi_ok) {
189             TEXT_LOGE("Failed to get utf16");
190             return NapiGetUndefined(env);
191         }
192         typographyCreate_->AppendText(std::u16string {buffer.get()});
193     } else {
194         std::string text = "";
195         if (ConvertFromJsValue(env, argv[0], text)) {
196             if (!IsUtf8(text.c_str(), text.size())) {
197                 TEXT_LOGE("Invalid utf-8 text");
198                 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params");
199             }
200             typographyCreate_->AppendText(Str8ToStr16(text));
201         }
202     }
203     return NapiGetUndefined(env);
204 }
205 
PopStyle(napi_env env,napi_callback_info info)206 napi_value JsParagraphBuilder::PopStyle(napi_env env, napi_callback_info info)
207 {
208     JsParagraphBuilder* me = CheckParamsAndGetThis<JsParagraphBuilder>(env, info);
209     return (me != nullptr) ? me->OnPopStyle(env, info) : nullptr;
210 }
211 
OnPopStyle(napi_env env,napi_callback_info info)212 napi_value JsParagraphBuilder::OnPopStyle(napi_env env, napi_callback_info info)
213 {
214     if (typographyCreate_ == nullptr) {
215         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
216     }
217     typographyCreate_->PopStyle();
218     return NapiGetUndefined(env);
219 }
220 
AddPlaceholder(napi_env env,napi_callback_info info)221 napi_value JsParagraphBuilder::AddPlaceholder(napi_env env, napi_callback_info info)
222 {
223     JsParagraphBuilder* me = CheckParamsAndGetThis<JsParagraphBuilder>(env, info);
224     return (me != nullptr) ? me->OnAddPlaceholder(env, info) : nullptr;
225 }
226 
OnAddPlaceholder(napi_env env,napi_callback_info info)227 napi_value JsParagraphBuilder::OnAddPlaceholder(napi_env env, napi_callback_info info)
228 {
229     if (typographyCreate_ == nullptr) {
230         TEXT_LOGE("Null typography creator");
231         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
232     }
233     size_t argc = ARGC_ONE;
234     napi_value argv[ARGC_ONE] = {nullptr};
235     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
236     if (status != napi_ok || argc < ARGC_ONE) {
237         TEXT_LOGE("Failed to get parameter, argc %{public}zu, ret %{public}d", argc, status);
238         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
239     }
240     napi_valuetype valueType = napi_undefined;
241     if (argv[0] == nullptr || napi_typeof(env, argv[0], &valueType) != napi_ok || valueType != napi_object) {
242         TEXT_LOGE("Invalid argv[0]");
243         return NapiGetUndefined(env);
244     }
245     PlaceholderSpan placeholderSpan;
246     bool res = GetPlaceholderSpanFromJS(env, argv[0], placeholderSpan);
247     if (!res) {
248         TEXT_LOGE("Failed to get placeholder");
249         return NapiGetUndefined(env);
250     }
251     typographyCreate_->AppendPlaceholder(placeholderSpan);
252     return NapiGetUndefined(env);
253 }
254 
Build(napi_env env,napi_callback_info info)255 napi_value JsParagraphBuilder::Build(napi_env env, napi_callback_info info)
256 {
257     JsParagraphBuilder* me = CheckParamsAndGetThis<JsParagraphBuilder>(env, info);
258     return (me != nullptr) ? me->OnBuild(env, info) : nullptr;
259 }
260 
OnBuild(napi_env env,napi_callback_info info)261 napi_value JsParagraphBuilder::OnBuild(napi_env env, napi_callback_info info)
262 {
263     if (typographyCreate_ == nullptr) {
264         TEXT_LOGE("Null typography builder");
265         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
266     }
267 
268     std::unique_ptr<OHOS::Rosen::Typography> typography = typographyCreate_->CreateTypography();
269     return JsParagraph::CreateJsTypography(env, std::move(typography));
270 }
271 
BuildLineTypeset(napi_env env,napi_callback_info info)272 napi_value JsParagraphBuilder::BuildLineTypeset(napi_env env, napi_callback_info info)
273 {
274     JsParagraphBuilder* me = CheckParamsAndGetThis<JsParagraphBuilder>(env, info);
275     return (me != nullptr) ? me->OnBuildLineTypeset(env, info) : nullptr;
276 }
277 
OnBuildLineTypeset(napi_env env,napi_callback_info info)278 napi_value JsParagraphBuilder::OnBuildLineTypeset(napi_env env, napi_callback_info info)
279 {
280     if (typographyCreate_ == nullptr) {
281         TEXT_LOGE("Null typography creator");
282         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
283     }
284     std::unique_ptr<OHOS::Rosen::LineTypography> lineTypography = typographyCreate_->CreateLineTypography();
285     if (lineTypography == nullptr) {
286         return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed to create line typography.");
287     }
288     return JsLineTypeset::CreateJsLineTypeset(env, std::move(lineTypography));
289 }
290 
AppendSymbol(napi_env env,napi_callback_info info)291 napi_value JsParagraphBuilder::AppendSymbol(napi_env env, napi_callback_info info)
292 {
293     JsParagraphBuilder* me = CheckParamsAndGetThis<JsParagraphBuilder>(env, info);
294     return (me != nullptr) ? me->OnAppendSymbol(env, info) : nullptr;
295 }
296 
OnAppendSymbol(napi_env env,napi_callback_info info)297 napi_value JsParagraphBuilder::OnAppendSymbol(napi_env env, napi_callback_info info)
298 {
299     if (typographyCreate_ == nullptr) {
300         TEXT_LOGE("Null typography creator");
301         return nullptr;
302     }
303     size_t argc = ARGC_ONE;
304     napi_value argv[ARGC_ONE] = {nullptr};
305     napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
306     if ((status != napi_ok) || (argc < ARGC_ONE)) {
307         TEXT_LOGE("Failed to get parameter, argc %{public}zu, ret %{public}d", argc, status);
308         return nullptr;
309     }
310 
311     uint32_t symbolId = 0;
312     if (!ConvertFromJsNumber(env, argv[0], symbolId)) {
313         TEXT_LOGE("Failed to convert symbol id");
314         return nullptr;
315     }
316     typographyCreate_->AppendSymbol(symbolId);
317     return NapiGetUndefined(env);
318 }
319 } // namespace OHOS::Rosen
320