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 "canvas_napi/js_canvas.h"
17 #include "js_text_line.h"
18 #include "recording/recording_canvas.h"
19 #include "run_napi/js_run.h"
20 #include "utils/text_log.h"
21
22 namespace OHOS::Rosen {
23 namespace {
24 const std::string CLASS_NAME = "TextLine";
25 }
26 thread_local napi_ref JsTextLine::constructor_ = nullptr;
27
Constructor(napi_env env,napi_callback_info info)28 napi_value JsTextLine::Constructor(napi_env env, napi_callback_info info)
29 {
30 size_t argCount = 0;
31 napi_value jsThis = nullptr;
32 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
33 if (status != napi_ok) {
34 TEXT_LOGE("failed to napi_get_cb_info");
35 return nullptr;
36 }
37 JsTextLine *jsTextLineBase = new(std::nothrow) JsTextLine();
38 if (!jsTextLineBase) {
39 TEXT_LOGE("failed to create JsTextLine");
40 return nullptr;
41 }
42 status = napi_wrap(env, jsThis, jsTextLineBase,
43 JsTextLine::Destructor, nullptr, nullptr);
44 if (status != napi_ok) {
45 delete jsTextLineBase;
46 TEXT_LOGE("JsTextLine::Constructor Failed to wrap native instance");
47 return nullptr;
48 }
49 return jsThis;
50 }
51
52
Init(napi_env env,napi_value exportObj)53 napi_value JsTextLine::Init(napi_env env, napi_value exportObj)
54 {
55 napi_property_descriptor properties[] = {
56 DECLARE_NAPI_FUNCTION("getGlyphCount", JsTextLine::GetGlyphCount),
57 DECLARE_NAPI_FUNCTION("getGlyphRuns", JsTextLine::GetGlyphRuns),
58 DECLARE_NAPI_FUNCTION("getTextRange", JsTextLine::GetTextRange),
59 DECLARE_NAPI_FUNCTION("paint", JsTextLine::Paint),
60 };
61
62 napi_value constructor = nullptr;
63 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
64 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
65 if (status != napi_ok) {
66 TEXT_LOGE("Failed to define TextLine class");
67 return nullptr;
68 }
69
70 status = napi_create_reference(env, constructor, 1, &constructor_);
71 if (status != napi_ok) {
72 TEXT_LOGE("Failed to create reference of constructor");
73 return nullptr;
74 }
75 status = napi_set_named_property(env, exportObj, CLASS_NAME.c_str(), constructor);
76 if (status != napi_ok) {
77 TEXT_LOGE("Failed to set constructor");
78 return nullptr;
79 }
80 return exportObj;
81 }
82
Destructor(napi_env env,void * nativeObject,void * finalize)83 void JsTextLine::Destructor(napi_env env, void *nativeObject, void *finalize)
84 {
85 (void)finalize;
86 if (nativeObject != nullptr) {
87 JsTextLine *napi = reinterpret_cast<JsTextLine *>(nativeObject);
88 delete napi;
89 }
90 }
91
CreateTextLine(napi_env env,napi_callback_info info)92 napi_value JsTextLine::CreateTextLine(napi_env env, napi_callback_info info)
93 {
94 napi_value result = nullptr;
95 napi_value constructor = nullptr;
96 napi_status status = napi_get_reference_value(env, constructor_, &constructor);
97 if (status != napi_ok) {
98 TEXT_LOGE("Failed to get the representation of constructor object");
99 return nullptr;
100 }
101
102 status = napi_new_instance(env, constructor, 0, nullptr, &result);
103 if (status != napi_ok) {
104 TEXT_LOGE("Failed to instantiate JavaScript font instance");
105 return nullptr;
106 }
107 return result;
108 }
109
JsTextLine()110 JsTextLine::JsTextLine()
111 {
112 }
113
SetTextLine(std::unique_ptr<TextLineBase> textLine)114 void JsTextLine::SetTextLine(std::unique_ptr<TextLineBase> textLine)
115 {
116 textLine_ = std::move(textLine);
117 }
118
GetGlyphCount(napi_env env,napi_callback_info info)119 napi_value JsTextLine::GetGlyphCount(napi_env env, napi_callback_info info)
120 {
121 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
122 return (me != nullptr) ? me->OnGetGlyphCount(env, info) : nullptr;
123 }
124
GetGlyphRuns(napi_env env,napi_callback_info info)125 napi_value JsTextLine::GetGlyphRuns(napi_env env, napi_callback_info info)
126 {
127 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
128 return (me != nullptr) ? me->OnGetGlyphRuns(env, info) : nullptr;
129 }
130
GetTextRange(napi_env env,napi_callback_info info)131 napi_value JsTextLine::GetTextRange(napi_env env, napi_callback_info info)
132 {
133 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
134 return (me != nullptr) ? me->OnGetTextRange(env, info) : nullptr;
135 }
136
Paint(napi_env env,napi_callback_info info)137 napi_value JsTextLine::Paint(napi_env env, napi_callback_info info)
138 {
139 JsTextLine* me = CheckParamsAndGetThis<JsTextLine>(env, info);
140 return (me != nullptr) ? me->OnPaint(env, info) : nullptr;
141 }
142
OnGetGlyphCount(napi_env env,napi_callback_info info)143 napi_value JsTextLine::OnGetGlyphCount(napi_env env, napi_callback_info info)
144 {
145 if (textLine_ == nullptr) {
146 TEXT_LOGE("JsTextLine::OnGetGlyphCount textLine_ is nullptr");
147 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
148 }
149
150 uint32_t textSize = textLine_->GetGlyphCount();
151 return CreateJsValue(env, textSize);
152 }
153
OnGetGlyphRuns(napi_env env,napi_callback_info info)154 napi_value JsTextLine::OnGetGlyphRuns(napi_env env, napi_callback_info info)
155 {
156 if (textLine_ == nullptr) {
157 TEXT_LOGE("JsTextLine::OnGetGlyphRuns TextLine is nullptr");
158 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
159 }
160 std::vector<std::unique_ptr<Run>> runs = textLine_->GetGlyphRuns();
161 if (runs.empty()) {
162 TEXT_LOGE("JsTextLine::OnGetGlyphRuns runs is empty");
163 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
164 }
165 napi_value array = nullptr;
166 NAPI_CALL(env, napi_create_array(env, &array));
167 uint32_t index = 0;
168 for (std::unique_ptr<Run>& item : runs) {
169 napi_value itemObject = JsRun::CreateRun(env, info);
170 if (!itemObject) {
171 TEXT_LOGE("JsTextLine::OnGetGlyphRuns itemObject is null");
172 continue;
173 }
174 JsRun* jsRun = nullptr;
175 napi_unwrap(env, itemObject, reinterpret_cast<void**>(&jsRun));
176 if (!jsRun) {
177 TEXT_LOGE("JsTextLine::OnGetGlyphRuns napi_unwrap jsRun is null");
178 continue;
179 }
180 jsRun->SetRun(std::move(item));
181 jsRun->SetParagraph(paragraph_);
182 napi_set_element(env, array, index++, itemObject);
183 }
184 return array;
185 }
186
OnGetTextRange(napi_env env,napi_callback_info info)187 napi_value JsTextLine::OnGetTextRange(napi_env env, napi_callback_info info)
188 {
189 if (textLine_ == nullptr) {
190 TEXT_LOGE("JsTextLine::OnGetTextRange TextLine is nullptr");
191 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
192 }
193
194 Boundary boundary = textLine_->GetTextRange();
195 napi_value objValue = nullptr;
196 napi_create_object(env, &objValue);
197 if (objValue != nullptr) {
198 napi_set_named_property(env, objValue, "start", CreateJsNumber(env, boundary.leftIndex));
199 napi_set_named_property(env, objValue, "end", CreateJsNumber(env, boundary.rightIndex));
200 }
201 return objValue;
202 }
203
OnPaint(napi_env env,napi_callback_info info)204 napi_value JsTextLine::OnPaint(napi_env env, napi_callback_info info)
205 {
206 if (textLine_ == nullptr) {
207 TEXT_LOGE("JsTextLine::OnPaint TextLine is nullptr");
208 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
209 }
210 size_t argc = ARGC_THREE;
211 napi_value argv[ARGC_THREE] = {nullptr};
212 napi_status status = napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
213 if (status != napi_ok || argc < ARGC_THREE) {
214 TEXT_LOGE("JsTextLine::OnPaint Argc is invalid: %{public}zu", argc);
215 return NapiThrowError(env, TextErrorCode::ERROR_INVALID_PARAM, "Invalid params.");
216 }
217 if (argv[0] == nullptr) {
218 TEXT_LOGE("JsTextLine::OnPaint argv[0] is invalid");
219 return NapiGetUndefined(env);
220 }
221 Drawing::JsCanvas* jsCanvas = nullptr;
222 napi_unwrap(env, argv[0], reinterpret_cast<void**>(&jsCanvas));
223 if (!jsCanvas || !jsCanvas->GetCanvas()) {
224 TEXT_LOGE("JsTextLine::OnPaint jsCanvas is nullptr");
225 return NapiGetUndefined(env);
226 }
227 double x = 0.0;
228 double y = 0.0;
229 if (!(argv[ARGC_ONE] != nullptr && ConvertFromJsValue(env, argv[ARGC_ONE], x) &&
230 argv[ARGC_TWO] != nullptr && ConvertFromJsValue(env, argv[ARGC_TWO], y))) {
231 return NapiGetUndefined(env);
232 }
233 textLine_->Paint(jsCanvas->GetCanvas(), x, y);
234
235 return NapiGetUndefined(env);
236 }
237
GetTextLineBase()238 std::unique_ptr<TextLineBase> JsTextLine::GetTextLineBase()
239 {
240 return std::move(textLine_);
241 }
242
SetParagraph(std::shared_ptr<Typography> paragraph)243 void JsTextLine::SetParagraph(std::shared_ptr<Typography> paragraph)
244 {
245 paragraph_ = paragraph;
246 }
247 } // namespace OHOS::Rosen