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_line_typeset.h"
17 #include "text_line_napi/js_text_line.h"
18 #include "utils/log.h"
19
20 namespace OHOS::Rosen {
21 namespace {
22 const std::string CLASS_NAME = "LineTypeset";
23 napi_property_descriptor g_properties[] = {
24 DECLARE_NAPI_FUNCTION("getLineBreak", JsLineTypeset::GetLineBreak),
25 DECLARE_NAPI_FUNCTION("createLine", JsLineTypeset::CreateLine),
26 };
27 }
28 std::mutex JsLineTypeset::constructorMutex_;
29 thread_local napi_ref JsLineTypeset::constructor_ = nullptr;
30
Constructor(napi_env env,napi_callback_info info)31 napi_value JsLineTypeset::Constructor(napi_env env, napi_callback_info info)
32 {
33 size_t argCount = 0;
34 napi_value jsThis = nullptr;
35 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
36 if (status != napi_ok) {
37 TEXT_LOGE("Failed to get callback info, ret %{public}d", status);
38 return nullptr;
39 }
40
41 JsLineTypeset *jsLineTypeset = new(std::nothrow) JsLineTypeset();
42 if (jsLineTypeset == nullptr) {
43 TEXT_LOGE("Failed to new JsLineTypeset");
44 return nullptr;
45 }
46
47 status = napi_wrap(env, jsThis, jsLineTypeset, JsLineTypeset::Destructor, nullptr, nullptr);
48 if (status != napi_ok) {
49 delete jsLineTypeset;
50 TEXT_LOGE("Failed to wrap native instance, ret %{public}d", status);
51 return nullptr;
52 }
53 return jsThis;
54 }
55
Destructor(napi_env env,void * nativeObject,void * finalize)56 void JsLineTypeset::Destructor(napi_env env, void *nativeObject, void *finalize)
57 {
58 (void)finalize;
59 if (nativeObject != nullptr) {
60 JsLineTypeset *napi = reinterpret_cast<JsLineTypeset *>(nativeObject);
61 delete napi;
62 }
63 }
64
JsLineTypeset(std::shared_ptr<LineTypography> lineTypography)65 JsLineTypeset::JsLineTypeset(std::shared_ptr<LineTypography> lineTypography) : lineTypography_(lineTypography)
66 {
67 }
68
JsLineTypeset()69 JsLineTypeset::JsLineTypeset()
70 {
71 }
72
~JsLineTypeset()73 JsLineTypeset::~JsLineTypeset()
74 {
75 }
76
CreateJsLineTypeset(napi_env env,std::unique_ptr<LineTypography> lineTypography)77 napi_value JsLineTypeset::CreateJsLineTypeset(napi_env env, std::unique_ptr<LineTypography> lineTypography)
78 {
79 if (!CreateConstructor(env)) {
80 TEXT_LOGE("Failed to create constructor");
81 return nullptr;
82 }
83 napi_value constructor = nullptr;
84 napi_value result = nullptr;
85 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
86 if (status == napi_ok) {
87 napi_create_object(env, &result);
88 if (result == nullptr) {
89 TEXT_LOGE("Failed to create object.");
90 return nullptr;
91 }
92 auto jsLineTypeset = new(std::nothrow) JsLineTypeset(std::move(lineTypography));
93 if (jsLineTypeset == nullptr) {
94 TEXT_LOGE("Failed to new JsLineTypeset.");
95 return nullptr;
96 }
97 status = napi_wrap(env, result, jsLineTypeset, JsLineTypeset::Destructor, nullptr, nullptr);
98 if (status != napi_ok) {
99 delete jsLineTypeset;
100 TEXT_LOGE("Failed to wrap, ret %{public}d", status);
101 return nullptr;
102 }
103 napi_define_properties(env, result, sizeof(g_properties) / sizeof(g_properties[0]), g_properties);
104 return result;
105 }
106 return result;
107 }
108
Init(napi_env env,napi_value exportObj)109 napi_value JsLineTypeset::Init(napi_env env, napi_value exportObj)
110 {
111 if (!CreateConstructor(env)) {
112 TEXT_LOGE("Failed to create constructor");
113 return nullptr;
114 }
115 napi_value constructor = nullptr;
116 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
117 if (status != napi_ok) {
118 TEXT_LOGE("Failed to get reference, ret %{public}d", status);
119 return nullptr;
120 }
121
122 status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
123 if (status != napi_ok) {
124 TEXT_LOGE("Failed to set property, ret %{public}d", status);
125 return nullptr;
126 }
127 return exportObj;
128 }
129
CreateConstructor(napi_env env)130 bool JsLineTypeset::CreateConstructor(napi_env env)
131 {
132 std::lock_guard<std::mutex> lock(constructorMutex_);
133 if (constructor_) {
134 return true;
135 }
136 napi_value constructor = nullptr;
137 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
138 sizeof(g_properties) / sizeof(g_properties[0]), g_properties, &constructor);
139 if (status != napi_ok) {
140 TEXT_LOGE("Failed to define class, status %{public}d", status);
141 return false;
142 }
143
144 status = napi_create_reference(env, constructor, 1, &constructor_);
145 if (status != napi_ok) {
146 TEXT_LOGE("Failed to create reference, status %{public}d", status);
147 return false;
148 }
149 return true;
150 }
151
GetLineBreak(napi_env env,napi_callback_info info)152 napi_value JsLineTypeset::GetLineBreak(napi_env env, napi_callback_info info)
153 {
154 JsLineTypeset* me = CheckParamsAndGetThis<JsLineTypeset>(env, info);
155 return (me != nullptr) ? me->OnGetLineBreak(env, info) : nullptr;
156 }
157
OnGetLineBreak(napi_env env,napi_callback_info info)158 napi_value JsLineTypeset::OnGetLineBreak(napi_env env, napi_callback_info info)
159 {
160 if (lineTypography_ == nullptr) {
161 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Line typography is null.");
162 }
163 size_t argc = ARGC_TWO;
164 napi_value argv[ARGC_TWO] = {nullptr};
165 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
166 if (status != napi_ok || argc < ARGC_TWO) {
167 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Argc is invalid.");
168 }
169 int64_t index = 0;
170 double width = 0.0;
171 if (!(ConvertFromJsValue(env, argv[0], index) && ConvertFromJsValue(env, argv[1], width))) {
172 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Argv convert failed.");
173 }
174 size_t limitSize = lineTypography_->GetUnicodeSize();
175 if (index < 0 || limitSize <= static_cast<size_t>(index) || width <= 0) {
176 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Params exceeds reasonable range.");
177 }
178 size_t count = static_cast<size_t>(lineTypography_->GetLineBreak(static_cast<size_t>(index), width));
179 return CreateJsNumber(env, count);
180 }
181
CreateLine(napi_env env,napi_callback_info info)182 napi_value JsLineTypeset::CreateLine(napi_env env, napi_callback_info info)
183 {
184 JsLineTypeset* me = CheckParamsAndGetThis<JsLineTypeset>(env, info);
185 return (me != nullptr) ? me->OnCreateLine(env, info) : nullptr;
186 }
187
OnCreateLine(napi_env env,napi_callback_info info)188 napi_value JsLineTypeset::OnCreateLine(napi_env env, napi_callback_info info)
189 {
190 if (lineTypography_ == nullptr) {
191 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Line typography is null.");
192 }
193 size_t argc = ARGC_TWO;
194 napi_value argv[ARGC_TWO] = {nullptr};
195 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
196 if (status != napi_ok || argc < ARGC_TWO) {
197 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Argc is invalid.");
198 }
199 int64_t index = 0;
200 int64_t count = 0;
201 if (!(ConvertFromJsValue(env, argv[0], index) && ConvertFromJsValue(env, argv[1], count))) {
202 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Argv convert failed");
203 }
204 size_t limitSize = lineTypography_->GetUnicodeSize();
205 if (index < 0 || limitSize <= static_cast<size_t>(index) || count < 0 ||
206 static_cast<size_t>(count + index) > limitSize) {
207 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Params exceeds reasonable range.");
208 }
209 auto textLineBase = lineTypography_->CreateLine(static_cast<size_t>(index), static_cast<size_t>(count));
210 if (!textLineBase) {
211 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Create line failed.");
212 }
213 std::shared_ptr<Typography> typography = lineTypography_->GetTempTypography();
214 napi_value itemObject = JsTextLine::CreateTextLine(env, info);
215 if (!itemObject) {
216 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed to create JsTextLine object.");
217 }
218 JsTextLine* jsTextLine = nullptr;
219 napi_unwrap(env, itemObject, reinterpret_cast<void**>(&jsTextLine));
220 if (!jsTextLine) {
221 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Failed to unwrap JsTextLine object.");
222 }
223 jsTextLine->SetTextLine(std::move(textLineBase));
224 jsTextLine->SetParagraph(typography);
225 return itemObject;
226 }
227
228 } // namespace OHOS::Rosen
229