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