• 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_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