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 "frameworks/bridge/declarative_frontend/style_string/js_span_string.h"
17
18 #include <unordered_set>
19 #include "securec.h"
20
21 #include "base/utils/utils.h"
22 #include "core/common/ace_engine.h"
23 #include "core/common/container.h"
24 #include "core/common/container_scope.h"
25 #include "core/components_ng/pattern/text/span/mutable_span_string.h"
26 #include "core/components_ng/pattern/text/span/span_object.h"
27 #include "core/text/html_utils.h"
28 #include "frameworks/bridge/common/utils/engine_helper.h"
29 #include "frameworks/bridge/common/utils/utils.h"
30 #include "frameworks/bridge/declarative_frontend/engine/js_converter.h"
31 #include "frameworks/bridge/declarative_frontend/engine/functions/js_function.h"
32 #include "frameworks/bridge/declarative_frontend/jsview/js_image.h"
33 #include "frameworks/bridge/declarative_frontend/jsview/js_view_abstract.h"
34 #include "frameworks/bridge/declarative_frontend/style_string/js_span_object.h"
35
36 namespace OHOS::Ace::Framework {
37 namespace {
38 struct HtmlConverterAsyncCtx {
39 napi_env env = nullptr;
40 napi_deferred deferred = nullptr;
41 int32_t errCode = -1;
42 int32_t instanceId = -1;
43 };
44 struct AsyncContext {
45 napi_env env = nullptr;
46 napi_deferred deferred = nullptr;
47 napi_async_work asyncWork;
48 std::vector<uint8_t> buffer;
49 RefPtr<SpanString> spanString;
50 RefPtr<JsFunction> jsFunc;
51 JSExecutionContext execContext;
52 int32_t instanceId = -1;
53 int32_t status = -1;
54 };
55
56 std::unordered_map<int32_t, std::string> ASYNC_ERROR_MAP = {
57 { ERROR_CODE_FROM_HTML_CONVERT_ERROR, "Convert error." },
58 { ERROR_CODE_STYLED_STRING_CONVERT_ERROR, "Styled string decode error."},
59 { ERROR_CODE_PARAM_INVALID, "Parameter error. Possible causes: 1. Mandatory parameters are left unspecified;"
60 "2. Incorrect parameter types; 3. Parameter verification failed." }
61 };
62
CreateErrorValue(napi_env env,int32_t errCode,const std::string & errMsg="")63 napi_value CreateErrorValue(napi_env env, int32_t errCode, const std::string& errMsg = "")
64 {
65 napi_value code = nullptr;
66 std::string codeStr = std::to_string(errCode);
67 napi_create_string_utf8(env, codeStr.c_str(), codeStr.length(), &code);
68 napi_value msg = nullptr;
69 napi_create_string_utf8(env, errMsg.c_str(), errMsg.length(), &msg);
70 napi_value error = nullptr;
71 napi_create_error(env, code, msg, &error);
72 return error;
73 }
74
ProcessPromiseCallback(std::shared_ptr<HtmlConverterAsyncCtx> asyncContext,int32_t callbackCode,napi_value spanStr=nullptr)75 void ProcessPromiseCallback(std::shared_ptr<HtmlConverterAsyncCtx> asyncContext,
76 int32_t callbackCode, napi_value spanStr = nullptr)
77 {
78 CHECK_NULL_VOID(asyncContext);
79 CHECK_NULL_VOID(asyncContext->env);
80 CHECK_NULL_VOID(asyncContext->deferred);
81 napi_handle_scope scope = nullptr;
82 auto status = napi_open_handle_scope(asyncContext->env, &scope);
83 if (status != napi_ok) {
84 return;
85 }
86 CHECK_NULL_VOID(scope);
87 if (callbackCode == ERROR_CODE_NO_ERROR) {
88 napi_resolve_deferred(asyncContext->env, asyncContext->deferred, spanStr);
89 } else {
90 napi_value error = CreateErrorValue(asyncContext->env, callbackCode, ASYNC_ERROR_MAP[callbackCode]);
91 napi_reject_deferred(asyncContext->env, asyncContext->deferred, error);
92 }
93 napi_close_handle_scope(asyncContext->env, scope);
94 }
95
ReturnPromise(const JSCallbackInfo & info,int32_t errCode)96 void ReturnPromise(const JSCallbackInfo& info, int32_t errCode)
97 {
98 auto engine = EngineHelper::GetCurrentEngine();
99 CHECK_NULL_VOID(engine);
100 NativeEngine* nativeEngine = engine->GetNativeEngine();
101 auto env = reinterpret_cast<napi_env>(nativeEngine);
102 napi_deferred deferred = nullptr;
103 napi_value promise = nullptr;
104 napi_create_promise(env, &deferred, &promise);
105
106 if (errCode != ERROR_CODE_NO_ERROR) {
107 napi_value result = CreateErrorValue(env, errCode, ASYNC_ERROR_MAP[errCode]);
108 napi_reject_deferred(env, deferred, result);
109 } else {
110 napi_value result = nullptr;
111 napi_get_undefined(env, &result);
112 napi_resolve_deferred(env, deferred, result);
113 }
114 CHECK_NULL_VOID(promise);
115 auto jsPromise = JsConverter::ConvertNapiValueToJsVal(promise);
116 if (!jsPromise->IsObject()) {
117 TAG_LOGE(AceLogTag::ACE_TEXT, "Return promise failed.");
118 return;
119 }
120 info.SetReturnValue(JSRef<JSObject>::Cast(jsPromise));
121 }
122
123 static std::atomic<int32_t> gestureStyleStoreIndex_;
124 static std::atomic<int32_t> spanStringStoreIndex_;
125 };
126
127 const std::unordered_set<SpanType> types = { SpanType::Font, SpanType::Gesture, SpanType::BaselineOffset,
128 SpanType::Decoration, SpanType::LetterSpacing, SpanType::TextShadow, SpanType::LineHeight, SpanType::Image,
129 SpanType::CustomSpan, SpanType::ParagraphStyle, SpanType::ExtSpan, SpanType::BackgroundColor, SpanType::Url };
130
131 const std::unordered_map<SpanType, std::function<JSRef<JSObject>(const RefPtr<SpanBase>&)>> spanCreators = {
132 { SpanType::Font, JSSpanString::CreateJsFontSpan }, { SpanType::Decoration, JSSpanString::CreateJsDecorationSpan },
133 { SpanType::BaselineOffset, JSSpanString::CreateJsBaselineOffsetSpan },
134 { SpanType::LetterSpacing, JSSpanString::CreateJsLetterSpacingSpan },
135 { SpanType::Gesture, JSSpanString::CreateJsGestureSpan },
136 { SpanType::TextShadow, JSSpanString::CreateJsTextShadowSpan },
137 { SpanType::BackgroundColor, JSSpanString::CreateJSBackgroundColorSpan },
138 { SpanType::LineHeight, JSSpanString::CreateJsLineHeightSpan },
139 { SpanType::Image, JSSpanString::CreateJsImageSpan },
140 { SpanType::ParagraphStyle, JSSpanString::CreateJsParagraphStyleSpan },
141 { SpanType::Url, JSSpanString::CreateJsUrlSpan },
142 };
143
Constructor(const JSCallbackInfo & args)144 void JSSpanString::Constructor(const JSCallbackInfo& args)
145 {
146 auto jsSpanString = Referenced::MakeRefPtr<JSSpanString>();
147 jsSpanString->IncRefCount();
148 std::u16string data;
149 RefPtr<SpanString> spanString;
150 if (args.Length() == 0) {
151 spanString = AceType::MakeRefPtr<SpanString>(data);
152 } else {
153 if (args[0]->IsString()) {
154 JSViewAbstract::ParseJsString(args[0], data);
155 spanString = AceType::MakeRefPtr<SpanString>(data);
156 if (args.Length() > 1) {
157 auto thisObj = args.This();
158 auto spanBases = JSSpanString::ParseJsSpanBaseVector(args[1], data.length(), thisObj);
159 spanString->BindWithSpans(spanBases);
160 }
161 } else {
162 auto* base = JSRef<JSObject>::Cast(args[0])->Unwrap<AceType>();
163 auto* imageAttachment = AceType::DynamicCast<JSImageAttachment>(base);
164 if (imageAttachment) {
165 auto attachment = JSSpanString::ParseJsImageAttachment(args[0]);
166 spanString = AceType::MakeRefPtr<SpanString>(attachment);
167 } else {
168 RefPtr<CustomSpan> customSpan = JSSpanString::ParseJsCustomSpan(args);
169 spanString = AceType::MakeRefPtr<SpanString>(customSpan);
170 }
171 if (args.Length() > 1) {
172 TAG_LOGW(ACE_TEXT, "initialization of styledstring with image or custom span will only use first arg");
173 }
174 }
175 }
176 jsSpanString->SetController(spanString);
177 args.SetReturnValue(Referenced::RawPtr(jsSpanString));
178 }
179
Destructor(JSSpanString * spanString)180 void JSSpanString::Destructor(JSSpanString* spanString)
181 {
182 if (spanString != nullptr) {
183 spanString->DecRefCount();
184 }
185 }
186
JSBind(BindingTarget globalObj)187 void JSSpanString::JSBind(BindingTarget globalObj)
188 {
189 JSClass<JSSpanString>::Declare("StyledString");
190 JSClass<JSSpanString>::CustomMethod("getString", &JSSpanString::GetString);
191 JSClass<JSSpanString>::CustomProperty("length", &JSSpanString::GetLength, &JSSpanString::SetLength);
192 JSClass<JSSpanString>::CustomMethod("equals", &JSSpanString::IsEqualToSpanString);
193 JSClass<JSSpanString>::CustomMethod("subStyledString", &JSSpanString::GetSubSpanString);
194 JSClass<JSSpanString>::CustomMethod("getStyles", &JSSpanString::GetSpans);
195 JSClass<JSSpanString>::StaticMethod("fromHtml", &JSSpanString::FromHtml);
196 JSClass<JSSpanString>::StaticMethod("toHtml", &JSSpanString::ToHtml);
197 JSClass<JSSpanString>::StaticMethod("marshalling", &JSSpanString::Marshalling);
198 JSClass<JSSpanString>::StaticMethod("unmarshalling", &JSSpanString::Unmarshalling);
199 JSClass<JSSpanString>::Bind(globalObj, JSSpanString::Constructor, JSSpanString::Destructor);
200 }
201
GetString(const JSCallbackInfo & info)202 void JSSpanString::GetString(const JSCallbackInfo& info)
203 {
204 auto ret = JSRef<JSVal>::Make(JSVal(ToJSValue(spanString_->GetString())));
205 info.SetReturnValue(ret);
206 }
207
GetLength(const JSCallbackInfo & info)208 void JSSpanString::GetLength(const JSCallbackInfo& info)
209 {
210 auto ret = JSRef<JSVal>::Make(JSVal(ToJSValue(spanString_->GetLength())));
211 info.SetReturnValue(ret);
212 }
213
SetLength(const JSCallbackInfo & info)214 void JSSpanString::SetLength(const JSCallbackInfo& info) {}
215
IsEqualToSpanString(const JSCallbackInfo & info)216 void JSSpanString::IsEqualToSpanString(const JSCallbackInfo& info)
217 {
218 if (info.Length() != 1 || !info[0]->IsObject()) {
219 info.SetReturnValue(JSRef<JSVal>::Make(JSVal(ToJSValue(false))));
220 return;
221 }
222 auto jsSpanString = JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>();
223 if (!jsSpanString || !jsSpanString->GetController()) {
224 info.SetReturnValue(JSRef<JSVal>::Make(JSVal(ToJSValue(false))));
225 return;
226 }
227 auto spanString = jsSpanString->GetController();
228 auto ret = JSRef<JSVal>::Make(JSVal(ToJSValue(spanString_->IsEqualToSpanString(spanString))));
229 info.SetReturnValue(ret);
230 }
231
GetSubSpanString(const JSCallbackInfo & info)232 void JSSpanString::GetSubSpanString(const JSCallbackInfo& info)
233 {
234 if (info.Length() < 1 || !info[0]->IsNumber() || (info.Length() == 2 && !info[1]->IsNumber())) {
235 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
236 return;
237 }
238 auto start = info[0]->ToNumber<int32_t>();
239 auto length = spanString_->GetLength() - start;
240 if (info.Length() == 2) {
241 length = info[1]->ToNumber<int32_t>();
242 }
243 if (!CheckParameters(start, length)) {
244 return;
245 }
246 auto spanString = spanString_->GetSubSpanString(start, length);
247 CHECK_NULL_VOID(spanString);
248 JSRef<JSObject> obj = JSClass<JSSpanString>::NewInstance();
249 auto jsSpanString = Referenced::Claim(obj->Unwrap<JSSpanString>());
250 jsSpanString->SetController(spanString);
251 info.SetReturnValue(obj);
252 }
253
GetSpans(const JSCallbackInfo & info)254 void JSSpanString::GetSpans(const JSCallbackInfo& info)
255 {
256 if (info.Length() < 2 || !info[0]->IsNumber() || !info[1]->IsNumber() ||
257 (info.Length() == 3 && !info[2]->IsNumber())) {
258 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
259 return;
260 }
261 auto start = info[0]->ToNumber<int32_t>();
262 auto length = info[1]->ToNumber<int32_t>();
263 if (!CheckParameters(start, length)) {
264 return;
265 }
266 std::vector<RefPtr<SpanBase>> spans;
267 if (info.Length() >= 3) {
268 auto spanType = info[2]->ToNumber<int32_t>();
269 if (!CheckSpanType(spanType)) {
270 return;
271 }
272 auto type = static_cast<SpanType>(spanType);
273 spans = spanString_->GetSpans(start, length, type);
274 } else {
275 spans = spanString_->GetSpans(start, length);
276 }
277
278 JSRef<JSArray> spanObjectArray = JSRef<JSArray>::New();
279 uint32_t idx = 0;
280 for (const RefPtr<SpanBase>& spanObject : spans) {
281 auto decorationSpan = AceType::DynamicCast<DecorationSpan>(spanObject);
282 if (decorationSpan) {
283 auto types = decorationSpan->GetTextDecorationTypes();
284 for (TextDecoration type : types) {
285 auto tempSpan = decorationSpan->GetSubSpan(
286 decorationSpan->GetStartIndex(), decorationSpan->GetEndIndex());
287 auto tempDecorationSpan = AceType::DynamicCast<DecorationSpan>(tempSpan);
288 tempDecorationSpan->SetTextDecorationTypes({type});
289 spanObjectArray->SetValueAt(idx++, CreateJsSpanBaseObject(tempSpan));
290 }
291 } else {
292 spanObjectArray->SetValueAt(idx++, CreateJsSpanBaseObject(spanObject));
293 }
294 }
295 info.SetReturnValue(JSRef<JSVal>::Cast(spanObjectArray));
296 }
297
CreateJsSpanBaseObject(const RefPtr<SpanBase> & spanObject)298 JSRef<JSObject> JSSpanString::CreateJsSpanBaseObject(const RefPtr<SpanBase>& spanObject)
299 {
300 JSRef<JSObject> resultObj = JSRef<JSObject>::New();
301 resultObj->SetProperty<int32_t>("start", spanObject->GetStartIndex());
302 resultObj->SetProperty<int32_t>("length", spanObject->GetLength());
303 resultObj->SetProperty<int32_t>("styledKey", static_cast<int32_t>(spanObject->GetSpanType()));
304 JSRef<JSObject> obj = CreateJsSpanObject(spanObject);
305 resultObj->SetPropertyObject("styledValue", obj);
306 return resultObj;
307 }
308
CreateJsSpanObject(const RefPtr<SpanBase> & spanObject)309 JSRef<JSObject> JSSpanString::CreateJsSpanObject(const RefPtr<SpanBase>& spanObject)
310 {
311 JSRef<JSObject> obj;
312 auto type = spanObject->GetSpanType();
313 auto it = spanCreators.find(type);
314 if (it != spanCreators.end()) {
315 obj = it->second(spanObject);
316 } else if (type == SpanType::CustomSpan) {
317 obj = AceType::DynamicCast<JSCustomSpan>(spanObject)->GetJsCustomSpanObject();
318 } else if (type == SpanType::ExtSpan) {
319 obj = AceType::DynamicCast<JSExtSpan>(spanObject)->GetJsExtSpanObject();
320 }
321 return obj;
322 }
323
CreateJsParagraphStyleSpan(const RefPtr<SpanBase> & spanObject)324 JSRef<JSObject> JSSpanString::CreateJsParagraphStyleSpan(const RefPtr<SpanBase>& spanObject)
325 {
326 auto span = AceType::DynamicCast<ParagraphStyleSpan>(spanObject);
327 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
328 JSRef<JSObject> obj = JSClass<JSParagraphStyleSpan>::NewInstance();
329 auto paragraphSpan = Referenced::Claim(obj->Unwrap<JSParagraphStyleSpan>());
330 paragraphSpan->SetParagraphStyleSpan(span);
331 return obj;
332 }
333
CreateJsUrlSpan(const RefPtr<SpanBase> & spanObject)334 JSRef<JSObject> JSSpanString::CreateJsUrlSpan(const RefPtr<SpanBase>& spanObject)
335 {
336 auto span = AceType::DynamicCast<UrlSpan>(spanObject);
337 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
338 JSRef<JSObject> obj = JSClass<JSUrlSpan>::NewInstance();
339 auto urlSpan = Referenced::Claim(obj->Unwrap<JSUrlSpan>());
340 urlSpan->SetUrlSpan(span);
341 return obj;
342 }
343
CreateJsFontSpan(const RefPtr<SpanBase> & spanObject)344 JSRef<JSObject> JSSpanString::CreateJsFontSpan(const RefPtr<SpanBase>& spanObject)
345 {
346 auto span = AceType::DynamicCast<FontSpan>(spanObject);
347 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
348 JSRef<JSObject> obj = JSClass<JSFontSpan>::NewInstance();
349 auto fontSpan = Referenced::Claim(obj->Unwrap<JSFontSpan>());
350 fontSpan->SetFontSpan(span);
351 return obj;
352 }
353
CreateJsDecorationSpan(const RefPtr<SpanBase> & spanObject)354 JSRef<JSObject> JSSpanString::CreateJsDecorationSpan(const RefPtr<SpanBase>& spanObject)
355 {
356 auto span = AceType::DynamicCast<DecorationSpan>(spanObject);
357 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
358 JSRef<JSObject> obj = JSClass<JSDecorationSpan>::NewInstance();
359 auto decorationSpan = Referenced::Claim(obj->Unwrap<JSDecorationSpan>());
360 decorationSpan->SetDecorationSpan(span);
361 return obj;
362 }
363
CreateJsBaselineOffsetSpan(const RefPtr<SpanBase> & spanObject)364 JSRef<JSObject> JSSpanString::CreateJsBaselineOffsetSpan(const RefPtr<SpanBase>& spanObject)
365 {
366 auto span = AceType::DynamicCast<BaselineOffsetSpan>(spanObject);
367 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
368 JSRef<JSObject> obj = JSClass<JSBaselineOffsetSpan>::NewInstance();
369 auto baselineOffsetSpan = Referenced::Claim(obj->Unwrap<JSBaselineOffsetSpan>());
370 baselineOffsetSpan->SetBaselineOffsetSpan(span);
371 return obj;
372 }
373
CreateJsLetterSpacingSpan(const RefPtr<SpanBase> & spanObject)374 JSRef<JSObject> JSSpanString::CreateJsLetterSpacingSpan(const RefPtr<SpanBase>& spanObject)
375 {
376 auto span = AceType::DynamicCast<LetterSpacingSpan>(spanObject);
377 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
378 JSRef<JSObject> obj = JSClass<JSLetterSpacingSpan>::NewInstance();
379 auto letterSpacingSpan = Referenced::Claim(obj->Unwrap<JSLetterSpacingSpan>());
380 letterSpacingSpan->SetLetterSpacingSpan(span);
381 return obj;
382 }
383
CreateJsGestureSpan(const RefPtr<SpanBase> & spanObject)384 JSRef<JSObject> JSSpanString::CreateJsGestureSpan(const RefPtr<SpanBase>& spanObject)
385 {
386 auto span = AceType::DynamicCast<GestureSpan>(spanObject);
387 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
388 JSRef<JSObject> obj = JSClass<JSGestureSpan>::NewInstance();
389 auto gestureSpan = Referenced::Claim(obj->Unwrap<JSGestureSpan>());
390 gestureSpan->SetGestureSpan(span);
391 return obj;
392 }
393
CreateJsTextShadowSpan(const RefPtr<SpanBase> & spanObject)394 JSRef<JSObject> JSSpanString::CreateJsTextShadowSpan(const RefPtr<SpanBase>& spanObject)
395 {
396 auto span = AceType::DynamicCast<TextShadowSpan>(spanObject);
397 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
398 JSRef<JSObject> obj = JSClass<JSTextShadowSpan>::NewInstance();
399 auto textShadowSpan = Referenced::Claim(obj->Unwrap<JSTextShadowSpan>());
400 textShadowSpan->SetTextShadowSpan(span);
401 return obj;
402 }
403
CreateJSBackgroundColorSpan(const RefPtr<SpanBase> & spanObject)404 JSRef<JSObject> JSSpanString::CreateJSBackgroundColorSpan(const RefPtr<SpanBase>& spanObject)
405 {
406 auto span = AceType::DynamicCast<BackgroundColorSpan>(spanObject);
407 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
408 JSRef<JSObject> obj = JSClass<JSBackgroundColorSpan>::NewInstance();
409 auto backgroundColorSpan = Referenced::Claim(obj->Unwrap<JSBackgroundColorSpan>());
410 backgroundColorSpan->SetBackgroundColorSpan(span);
411 return obj;
412 }
413
CreateJsLineHeightSpan(const RefPtr<SpanBase> & spanObject)414 JSRef<JSObject> JSSpanString::CreateJsLineHeightSpan(const RefPtr<SpanBase>& spanObject)
415 {
416 auto span = AceType::DynamicCast<LineHeightSpan>(spanObject);
417 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
418 JSRef<JSObject> obj = JSClass<JSLineHeightSpan>::NewInstance();
419 auto lineHeightSpan = Referenced::Claim(obj->Unwrap<JSLineHeightSpan>());
420 lineHeightSpan->SetLineHeightSpan(span);
421 return obj;
422 }
423
CreateJsImageSpan(const RefPtr<SpanBase> & spanObject)424 JSRef<JSObject> JSSpanString::CreateJsImageSpan(const RefPtr<SpanBase>& spanObject)
425 {
426 auto span = AceType::DynamicCast<ImageSpan>(spanObject);
427 CHECK_NULL_RETURN(span, JSRef<JSObject>::New());
428 JSRef<JSObject> obj = JSClass<JSImageAttachment>::NewInstance();
429 auto imageSpan = Referenced::Claim(obj->Unwrap<JSImageAttachment>());
430 imageSpan->SetImageSpan(span);
431 return obj;
432 }
433
ParseJsSpanBaseWithoutSpecialSpan(int32_t start,int32_t length,SpanType type,const JSRef<JSObject> & obj,const JSCallbackInfo & info)434 RefPtr<SpanBase> JSSpanString::ParseJsSpanBaseWithoutSpecialSpan(
435 int32_t start, int32_t length, SpanType type, const JSRef<JSObject>& obj, const JSCallbackInfo& info)
436 {
437 if (type == SpanType::CustomSpan) {
438 return ParseJsCustomSpan(start, length, info);
439 }
440 return JSSpanString::ParseJsSpanBase(start, length, type, obj);
441 }
442
ParseJsSpanBase(int32_t start,int32_t length,SpanType type,const JSRef<JSObject> & obj)443 RefPtr<SpanBase> JSSpanString::ParseJsSpanBase(int32_t start, int32_t length, SpanType type, const JSRef<JSObject>& obj)
444 {
445 switch (type) {
446 case SpanType::Font:
447 return ParseJsFontSpan(start, length, obj);
448 case SpanType::Decoration:
449 return ParseJsDecorationSpan(start, length, obj);
450 case SpanType::LetterSpacing:
451 return ParseJsLetterSpacingSpan(start, length, obj);
452 case SpanType::BaselineOffset:
453 return ParseJsBaselineOffsetSpan(start, length, obj);
454 case SpanType::Gesture:
455 return ParseJsGestureSpan(start, length, obj);
456 case SpanType::TextShadow:
457 return ParseJsTextShadowSpan(start, length, obj);
458 case SpanType::LineHeight:
459 return ParseJsLineHeightSpan(start, length, obj);
460 case SpanType::Image:
461 return GetImageAttachment(start, length, obj);
462 case SpanType::ParagraphStyle:
463 return ParseJsParagraphStyleSpan(start, length, obj);
464 case SpanType::ExtSpan:
465 return ParseJsExtSpan(start, length, obj);
466 case SpanType::BackgroundColor:
467 return ParseJSBackgroundColorSpan(start, length, obj);
468 case SpanType::Url:
469 return ParseJsUrlSpan(start, length, obj);
470 default:
471 break;
472 }
473 return nullptr;
474 }
475
ParseJsFontSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)476 RefPtr<SpanBase> JSSpanString::ParseJsFontSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
477 {
478 auto* base = obj->Unwrap<AceType>();
479 auto* fontSpan = AceType::DynamicCast<JSFontSpan>(base);
480 if (fontSpan && fontSpan->GetFontSpan()) {
481 return AceType::MakeRefPtr<FontSpan>(fontSpan->GetFontSpan()->GetFont(), start, start + length);
482 }
483 return nullptr;
484 }
485
ParseJsParagraphStyleSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)486 RefPtr<SpanBase> JSSpanString::ParseJsParagraphStyleSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
487 {
488 auto* base = obj->Unwrap<AceType>();
489 auto* paragraphStyleSpan = AceType::DynamicCast<JSParagraphStyleSpan>(base);
490 if (paragraphStyleSpan && paragraphStyleSpan->GetParagraphStyleSpan()) {
491 return AceType::MakeRefPtr<ParagraphStyleSpan>(
492 paragraphStyleSpan->GetParagraphStyleSpan()->GetParagraphStyle(), start, start + length);
493 }
494 return nullptr;
495 }
496
ParseJsDecorationSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)497 RefPtr<SpanBase> JSSpanString::ParseJsDecorationSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
498 {
499 auto* base = obj->Unwrap<AceType>();
500 auto* decorationSpan = AceType::DynamicCast<JSDecorationSpan>(base);
501 if (decorationSpan && decorationSpan->GetDecorationSpan()) {
502 return AceType::MakeRefPtr<DecorationSpan>(
503 decorationSpan->GetDecorationSpan()->GetTextDecorationTypes(),
504 decorationSpan->GetDecorationSpan()->GetColor(),
505 decorationSpan->GetDecorationSpan()->GetTextDecorationStyle(),
506 decorationSpan->GetDecorationSpan()->GetLineThicknessScale(),
507 decorationSpan->GetDecorationSpan()->GetTextDecorationOptions(),
508 start, start + length);
509 }
510 return nullptr;
511 }
512
ParseJsBaselineOffsetSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)513 RefPtr<SpanBase> JSSpanString::ParseJsBaselineOffsetSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
514 {
515 auto* base = obj->Unwrap<AceType>();
516 auto* baselineOffsetSpan = AceType::DynamicCast<JSBaselineOffsetSpan>(base);
517 if (baselineOffsetSpan && baselineOffsetSpan->GetBaselineOffsetSpan()) {
518 return AceType::MakeRefPtr<BaselineOffsetSpan>(
519 baselineOffsetSpan->GetBaselineOffsetSpan()->GetBaselineOffset(), start, start + length);
520 }
521 return nullptr;
522 }
523
ParseJsLetterSpacingSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)524 RefPtr<SpanBase> JSSpanString::ParseJsLetterSpacingSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
525 {
526 auto* base = obj->Unwrap<AceType>();
527 auto* letterSpacingSpan = AceType::DynamicCast<JSLetterSpacingSpan>(base);
528 if (letterSpacingSpan && letterSpacingSpan->GetLetterSpacingSpan()) {
529 return AceType::MakeRefPtr<LetterSpacingSpan>(
530 letterSpacingSpan->GetLetterSpacingSpan()->GetLetterSpacing(), start, start + length);
531 }
532 return nullptr;
533 }
534
ParseJsGestureSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)535 RefPtr<SpanBase> JSSpanString::ParseJsGestureSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
536 {
537 auto* base = obj->Unwrap<AceType>();
538 auto* gestureSpan = AceType::DynamicCast<JSGestureSpan>(base);
539 if (gestureSpan && gestureSpan->GetGestureSpan()) {
540 return AceType::MakeRefPtr<GestureSpan>(
541 gestureSpan->GetGestureSpan()->GetGestureStyle(), start, start + length);
542 }
543 return nullptr;
544 }
545
ParseJsTextShadowSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)546 RefPtr<SpanBase> JSSpanString::ParseJsTextShadowSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
547 {
548 auto* base = obj->Unwrap<AceType>();
549 auto* textShadowSpan = AceType::DynamicCast<JSTextShadowSpan>(base);
550 if (textShadowSpan && textShadowSpan->GetTextShadowSpan()) {
551 return AceType::MakeRefPtr<TextShadowSpan>(
552 textShadowSpan->GetTextShadowSpan()->GetTextShadow(), start, start + length);
553 }
554 return nullptr;
555 }
556
ParseJSBackgroundColorSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)557 RefPtr<SpanBase> JSSpanString::ParseJSBackgroundColorSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
558 {
559 auto* base = obj->Unwrap<AceType>();
560 auto* backgroundColorSpan = AceType::DynamicCast<JSBackgroundColorSpan>(base);
561 if (backgroundColorSpan && backgroundColorSpan->GetBackgroundColorSpan()) {
562 return AceType::MakeRefPtr<BackgroundColorSpan>(
563 backgroundColorSpan->GetBackgroundColorSpan()->GetBackgroundColor(), start, start + length);
564 }
565 return nullptr;
566 }
567
ParseJsLineHeightSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)568 RefPtr<SpanBase> JSSpanString::ParseJsLineHeightSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
569 {
570 auto* base = obj->Unwrap<AceType>();
571 auto* lineHeightSpan = AceType::DynamicCast<JSLineHeightSpan>(base);
572 if (lineHeightSpan && lineHeightSpan->GetLineHeightSpan()) {
573 return AceType::MakeRefPtr<LineHeightSpan>(
574 lineHeightSpan->GetLineHeightSpan()->GetLineHeight(), start, start + length);
575 }
576 return nullptr;
577 }
578
GetImageAttachment(int32_t start,int32_t length,const JSRef<JSObject> & obj)579 RefPtr<SpanBase> JSSpanString::GetImageAttachment(int32_t start, int32_t length, const JSRef<JSObject>& obj)
580 {
581 auto* base = obj->Unwrap<AceType>();
582 auto* imageAttachment = AceType::DynamicCast<JSImageAttachment>(base);
583 if (imageAttachment && imageAttachment->GetImageSpan()) {
584 auto imageSpan = imageAttachment->GetImageSpan();
585 imageSpan->UpdateStartIndex(start);
586 imageSpan->UpdateEndIndex(start + length);
587 return imageSpan;
588 }
589 return nullptr;
590 }
591
ParseJsCustomSpan(int32_t start,int32_t length,const JSCallbackInfo & args)592 RefPtr<SpanBase> JSSpanString::ParseJsCustomSpan(int32_t start, int32_t length, const JSCallbackInfo& args)
593 {
594 if (args.Length() == 0) {
595 return nullptr;
596 }
597 auto paramObj = args[0];
598 if (paramObj->IsUndefined()) {
599 return nullptr;
600 }
601 if (!paramObj->IsObject()) {
602 return nullptr;
603 }
604 auto styledValueObj = JSRef<JSObject>::Cast(paramObj)->GetProperty("styledValue");
605 if (!styledValueObj->IsObject()) {
606 return nullptr;
607 }
608 auto styleStringValue = JSRef<JSObject>::Cast(styledValueObj);
609 if (styleStringValue->IsUndefined()) {
610 return nullptr;
611 }
612 auto typeObj = styleStringValue->GetProperty("type_");
613 if (!typeObj->IsString() || typeObj->ToString() != "CustomSpan") {
614 return nullptr;
615 }
616 auto spanBase = AceType::MakeRefPtr<JSCustomSpan>(JSRef<JSObject>(styleStringValue), args);
617 spanBase->UpdateStartIndex(start);
618 spanBase->UpdateEndIndex(start + length);
619 return spanBase;
620 }
621
ParseJsExtSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)622 RefPtr<SpanBase> JSSpanString::ParseJsExtSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
623 {
624 auto typeObj = obj->GetProperty("type_");
625 if (!typeObj->IsString() || typeObj->ToString() != "ExtSpan") {
626 return nullptr;
627 }
628 auto spanBase = AceType::MakeRefPtr<JSExtSpan>(obj, start, start + length);
629 return spanBase;
630 }
631
ParseJsUrlSpan(int32_t start,int32_t length,const JSRef<JSObject> & obj)632 RefPtr<SpanBase> JSSpanString::ParseJsUrlSpan(int32_t start, int32_t length, const JSRef<JSObject>& obj)
633 {
634 auto* base = obj->Unwrap<AceType>();
635 auto* urlSpan = AceType::DynamicCast<JSUrlSpan>(base);
636 if (urlSpan && urlSpan->GetUrlSpan()) {
637 return AceType::MakeRefPtr<UrlSpan>(
638 urlSpan->GetUrlSpan()->GetUrlSpanAddress(), start, start + length);
639 }
640 return nullptr;
641 }
642
CheckSpanType(int32_t spanType)643 bool JSSpanString::CheckSpanType(int32_t spanType)
644 {
645 if (types.find(static_cast<SpanType>(spanType)) == types.end()) {
646 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "CheckSpanType failed: Ilegal span type");
647 return false;
648 }
649 return true;
650 }
651
CheckParameters(int32_t start,int32_t length)652 bool JSSpanString::CheckParameters(int32_t start, int32_t length)
653 {
654 // The input parameter must not cross the boundary.
655 if (!spanString_->CheckRange(start, length)) {
656 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s start:%d length:%d", "CheckBoundary failed:", start, length);
657 return false;
658 }
659 return true;
660 }
661
ParseJsSpanBaseVector(const JSRef<JSObject> & obj,int32_t maxLength,JsiRef<JsiObject> thisObj)662 std::vector<RefPtr<SpanBase>> JSSpanString::ParseJsSpanBaseVector(const JSRef<JSObject>& obj, int32_t maxLength,
663 JsiRef<JsiObject> thisObj)
664 {
665 std::vector<RefPtr<SpanBase>> spanBaseVector;
666 auto arrays = JSRef<JSArray>::Cast(obj);
667 for (size_t i = 0; i < arrays->Length(); i++) {
668 JSRef<JSVal> value = arrays->GetValueAt(i);
669 if (value->IsNull() || value->IsUndefined() || (!value->IsObject())) {
670 continue;
671 }
672 auto valueObj = JSRef<JSObject>::Cast(value);
673 auto startProperty = valueObj->GetProperty("start");
674 auto lengthProperty = valueObj->GetProperty("length");
675 int32_t start = 0;
676 if (!startProperty->IsNull() && startProperty->IsNumber()) {
677 start = startProperty->ToNumber<int32_t>();
678 start = start < 0 || start >= maxLength ? 0 : start;
679 }
680 int32_t length = maxLength - start;
681 if (!lengthProperty->IsNull() && lengthProperty->IsNumber()) {
682 length = lengthProperty->ToNumber<int32_t>();
683 length = length > maxLength - start || length <= 0 ? maxLength - start : length;
684 }
685 auto styleKey = valueObj->GetProperty("styledKey");
686 if (styleKey->IsNull() || !styleKey->IsNumber()) {
687 continue;
688 }
689 auto styleStringValue = valueObj->GetProperty("styledValue");
690 if (!styleStringValue->IsObject()) {
691 continue;
692 }
693 auto type = static_cast<SpanType>(styleKey->ToNumber<int32_t>());
694 if (type == SpanType::Image || type == SpanType::CustomSpan) {
695 continue;
696 }
697 if (type == SpanType::Gesture) {
698 auto newIndex = gestureStyleStoreIndex_.fetch_add(1);
699 std::string key = "STYLED_STRING_GESTURESTYLE_STORE_" + std::to_string(newIndex);
700 thisObj->SetPropertyObject(key.c_str(), styleStringValue);
701 }
702 auto spanBase = ParseJsSpanBase(start, length, type, JSRef<JSObject>::Cast(styleStringValue));
703 if (spanBase) {
704 spanBaseVector.emplace_back(spanBase);
705 }
706 }
707 return spanBaseVector;
708 }
709
GetController()710 const RefPtr<SpanString>& JSSpanString::GetController()
711 {
712 return spanString_;
713 }
714
SetController(const RefPtr<SpanString> & spanString)715 void JSSpanString::SetController(const RefPtr<SpanString>& spanString)
716 {
717 spanString_ = spanString;
718 }
719
ParseJsImageAttachment(const JSRef<JSObject> & info)720 ImageSpanOptions JSSpanString::ParseJsImageAttachment(const JSRef<JSObject>& info)
721 {
722 ImageSpanOptions options;
723 auto* base = info->Unwrap<AceType>();
724 auto* imageAttachment = AceType::DynamicCast<JSImageAttachment>(base);
725 if (!imageAttachment) {
726 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Parse JsImageAttachment Failed");
727 return options;
728 }
729 return imageAttachment->GetImageOptions();
730 }
731
ParseJsCustomSpan(const JSCallbackInfo & args)732 RefPtr<CustomSpan> JSSpanString::ParseJsCustomSpan(const JSCallbackInfo& args)
733 {
734 return AceType::MakeRefPtr<JSCustomSpan>(args[0], args);
735 }
736
FromHtml(const JSCallbackInfo & info)737 void JSSpanString::FromHtml(const JSCallbackInfo& info)
738 {
739 ContainerScope scope(Container::CurrentIdSafely());
740 if (info.Length() != 1 || !info[0]->IsString()) {
741 ReturnPromise(info, ERROR_CODE_PARAM_INVALID);
742 return;
743 }
744 std::string arg = info[0]->ToString();
745 auto container = Container::CurrentSafely();
746 if (!container) {
747 ReturnPromise(info, ERROR_CODE_PARAM_INVALID);
748 return;
749 }
750 auto taskExecutor = container->GetTaskExecutor();
751 CHECK_NULL_VOID(taskExecutor);
752 auto engine = EngineHelper::GetCurrentEngine();
753 CHECK_NULL_VOID(engine);
754 NativeEngine* nativeEngine = engine->GetNativeEngine();
755 CHECK_NULL_VOID(nativeEngine);
756 auto asyncContext = std::make_shared<HtmlConverterAsyncCtx>();
757 asyncContext->instanceId = Container::CurrentIdSafely();
758 asyncContext->env = reinterpret_cast<napi_env>(nativeEngine);
759 napi_value result = nullptr;
760 napi_create_promise(asyncContext->env, &asyncContext->deferred, &result);
761 taskExecutor->PostTask(
762 [htmlStr = arg, asyncContext]() mutable {
763 ContainerScope scope(asyncContext->instanceId);
764 // FromHtml may cost much time because of pixelmap.
765 // Therefore this function should be called in Background thread.
766 auto styledString = HtmlUtils::FromHtml(htmlStr);
767 auto container = AceEngine::Get().GetContainer(asyncContext->instanceId);
768 CHECK_NULL_VOID(container);
769 auto taskExecutor = container->GetTaskExecutor();
770 taskExecutor->PostTask([styledString, asyncContext]() mutable {
771 ContainerScope scope(asyncContext->instanceId);
772 if (!styledString) {
773 ProcessPromiseCallback(asyncContext, ERROR_CODE_FROM_HTML_CONVERT_ERROR);
774 return;
775 }
776 if (SystemProperties::GetDebugEnabled()) {
777 TAG_LOGD(ACE_TEXT, "Get StyledString From Html: %{public}s", styledString->ToString().c_str());
778 }
779 JSRef<JSObject> obj = JSClass<JSSpanString>::NewInstance();
780 auto jsSpanString = Referenced::Claim(obj->Unwrap<JSSpanString>());
781 jsSpanString->SetController(styledString);
782 auto spanStrNapi = JsConverter::ConvertJsValToNapiValue(obj);
783 ProcessPromiseCallback(asyncContext, ERROR_CODE_NO_ERROR, spanStrNapi);
784 }, TaskExecutor::TaskType::UI, "FromHtmlReturnPromise", PriorityType::VIP);
785 }, TaskExecutor::TaskType::BACKGROUND, "FromHtml", PriorityType::IMMEDIATE);
786 auto jsPromise = JsConverter::ConvertNapiValueToJsVal(result);
787 CHECK_NULL_VOID(jsPromise->IsObject());
788 info.SetReturnValue(JSRef<JSObject>::Cast(jsPromise));
789 }
790
ToHtml(const JSCallbackInfo & info)791 void JSSpanString::ToHtml(const JSCallbackInfo& info)
792 {
793 if (info.Length() != 1 || !info[0]->IsObject()) {
794 ReturnPromise(info, ERROR_CODE_PARAM_INVALID);
795 return;
796 }
797 auto arg = info[0];
798
799 auto* spanString = JSRef<JSObject>::Cast(arg)->Unwrap<JSSpanString>();
800 CHECK_NULL_VOID(spanString);
801 auto spanStringController = spanString->GetController();
802 CHECK_NULL_VOID(spanStringController);
803 auto html = HtmlUtils::ToHtml(Referenced::RawPtr(spanStringController));
804 if (SystemProperties::GetDebugEnabled()) {
805 TAG_LOGD(ACE_TEXT, "Transfer StyledString %{public}s To Html", spanStringController->ToString().c_str());
806 }
807 auto ret = JSRef<JSVal>::Make(JSVal(ToJSValue(html)));
808 info.SetReturnValue(ret);
809 }
810
Marshalling(const JSCallbackInfo & info)811 void JSSpanString::Marshalling(const JSCallbackInfo& info)
812 {
813 if ((info.Length() != 1 && info.Length() != 2) || !info[0]->IsObject()) {
814 // marshalling only support one or two params
815 ReturnPromise(info, ERROR_CODE_PARAM_INVALID);
816 return;
817 }
818 auto* spanString = JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>();
819 CHECK_NULL_VOID(spanString);
820 auto spanStringController = spanString->GetController();
821 CHECK_NULL_VOID(spanStringController);
822 std::vector<uint8_t> buff;
823 spanStringController->EncodeTlv(buff);
824
825 MarshallingExtSpan(info, buff);
826
827 size_t bufferSize = buff.size();
828 JSRef<JSArrayBuffer> arrayBuffer = JSRef<JSArrayBuffer>::New(bufferSize);
829 auto* buffer = static_cast<uint8_t*>(arrayBuffer->GetBuffer());
830 if (memcpy_s(buffer, bufferSize, buff.data(), bufferSize) != 0) {
831 return;
832 }
833 info.SetReturnValue(arrayBuffer);
834 }
835
MarshallingExtSpan(const JSCallbackInfo & info,std::vector<uint8_t> & buff)836 void JSSpanString::MarshallingExtSpan(const JSCallbackInfo& info, std::vector<uint8_t>& buff)
837 {
838 if (info.Length() != 2 || !info[1]->IsFunction() || !info[0]->IsObject()) {
839 // marshalling only support two params: spanString and callback function
840 return;
841 }
842 auto jsVal = info[0];
843 if (!jsVal->IsObject()) {
844 return;
845 }
846 auto* spanString = JSRef<JSObject>::Cast(jsVal)->Unwrap<JSSpanString>();
847 CHECK_NULL_VOID(spanString);
848 auto spanStringController = spanString->GetController();
849 CHECK_NULL_VOID(spanStringController);
850 auto jsFunction = AceType::MakeRefPtr<JsFunction>(Framework::JSRef<Framework::JSObject>(),
851 JSRef<JSFunc>::Cast(info[1]));
852 auto marshallCallback = [execCtx = info.GetExecutionContext(), func = std::move(jsFunction)]
853 (JSRef<JSObject> spanObj) -> std::vector<uint8_t> {
854 std::vector<uint8_t> arrBuff;
855 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, arrBuff);
856 JSRef<JSVal> param = JSRef<JSObject>::Cast(spanObj);
857 auto ret = func->ExecuteJS(1, ¶m);
858 if (ret->IsArrayBuffer()) {
859 JsiRef<JsiArrayBuffer> retJSBuf = JsiRef<JsiArrayBuffer>::Cast(ret);
860 int32_t bufferSize = retJSBuf->ByteLength();
861 auto* retBuf = static_cast<uint8_t*>(retJSBuf->GetBuffer());
862 std::vector<uint8_t> resBuf(retBuf, retBuf + bufferSize);
863 return resBuf;
864 }
865 return arrBuff;
866 };
867 auto spans = spanStringController->GetSpans(0, spanStringController->GetLength(), SpanType::ExtSpan);
868 for (const RefPtr<SpanBase>& spanObject : spans) {
869 auto obj = CreateJsSpanObject(spanObject);
870 auto arrBuff = marshallCallback(obj);
871 std::vector<uint8_t> spanInfo;
872 TLVUtil::WriteInt32(spanInfo, spanObject->GetStartIndex());
873 TLVUtil::WriteInt32(spanInfo, spanObject->GetLength());
874 TLVUtil::WriteUint8(buff, TLV_CUSTOM_MARSHALL_BUFFER_START);
875 TLVUtil::WriteInt32(buff, static_cast<int32_t>(arrBuff.size()) + static_cast<int32_t>(spanInfo.size()));
876 buff.insert(buff.end(), spanInfo.begin(), spanInfo.end());
877 buff.insert(buff.end(), arrBuff.begin(), arrBuff.end());
878 }
879 TLVUtil::WriteUint8(buff, TLV_END);
880 }
881
UnmarshallingExec(napi_env env,void * data)882 void JSSpanString::UnmarshallingExec(napi_env env, void *data)
883 {
884 CHECK_NULL_VOID(data);
885 auto asyncContext = static_cast<AsyncContext*>(data);
886 std::function<RefPtr<ExtSpan>(const std::vector<uint8_t>&, int32_t, int32_t)> unmarshallCallback;
887 if (asyncContext->jsFunc) {
888 ContainerScope scope(asyncContext->instanceId);
889 unmarshallCallback = [instanceId = asyncContext->instanceId, execCtx = asyncContext->execContext,
890 func = std::move(asyncContext->jsFunc)]
891 (const std::vector<uint8_t>& buff, int32_t spanStart, int32_t spanLength) -> RefPtr<ExtSpan> {
892 RefPtr<ExtSpan> extSpan;
893 ContainerScope scope(instanceId);
894 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, extSpan);
895 size_t bufferSize = buff.size();
896 JSRef<JSArrayBuffer> arrayBuffer = JSRef<JSArrayBuffer>::New(bufferSize);
897 auto* buffer = static_cast<uint8_t*>(arrayBuffer->GetBuffer());
898 if (memcpy_s(buffer, bufferSize, buff.data(), bufferSize) != 0) {
899 return extSpan;
900 }
901 JSRef<JSVal> param = JSRef<JSObject>::Cast(arrayBuffer);
902 auto ret = func->ExecuteJS(1, ¶m);
903 if (ret->IsObject()) {
904 auto retJSObj = JSRef<JSObject>::Cast(ret);
905 RefPtr<ExtSpan> retSpan = MakeRefPtr<JSExtSpan>(retJSObj, spanStart, spanLength);
906 return retSpan;
907 }
908 return extSpan;
909 };
910 }
911 asyncContext->spanString = SpanString::DecodeTlv(asyncContext->buffer, std::move(unmarshallCallback),
912 asyncContext->instanceId);
913 CHECK_NULL_VOID(asyncContext->spanString);
914 asyncContext->status = napi_ok;
915 }
916
UnmarshallingComplete(napi_env env,napi_status status,void * data)917 void JSSpanString::UnmarshallingComplete(napi_env env, napi_status status, void *data)
918 {
919 CHECK_NULL_VOID(data);
920 auto asyncContext = static_cast<AsyncContext*>(data);
921 JSRef<JSObject> obj = JSClass<JSSpanString>::NewInstance();
922 auto jsSpanString = Referenced::Claim(obj->Unwrap<JSSpanString>());
923 CHECK_NULL_VOID(jsSpanString);
924 jsSpanString->SetController(asyncContext->spanString);
925 auto spanStrNapi = JsConverter::ConvertJsValToNapiValue(obj);
926
927 if (status == napi_ok && asyncContext->status == napi_ok) {
928 napi_resolve_deferred(env, asyncContext->deferred, spanStrNapi);
929 } else {
930 napi_value error = CreateErrorValue(asyncContext->env, ERROR_CODE_STYLED_STRING_CONVERT_ERROR,
931 ASYNC_ERROR_MAP[ERROR_CODE_STYLED_STRING_CONVERT_ERROR]);
932 napi_reject_deferred(env, asyncContext->deferred, error);
933 }
934 delete asyncContext;
935 }
936
Unmarshalling(const JSCallbackInfo & info)937 void JSSpanString::Unmarshalling(const JSCallbackInfo& info)
938 {
939 auto arg = info[0];
940 if (info.Length() == 0 || info.Length() > 2 || !arg->IsArrayBuffer()) {
941 // unmarshalling only support one or two params
942 ReturnPromise(info, ERROR_CODE_PARAM_INVALID);
943 return;
944 }
945 auto instanceId = Container::CurrentIdSafely();
946 ContainerScope scope(instanceId);
947 JSRef<JSArrayBuffer> arrayBuffer = JSRef<JSArrayBuffer>::Cast(arg);
948 size_t bufferSize = static_cast<size_t>(arrayBuffer->ByteLength());
949 void* buffer = arrayBuffer->GetBuffer();
950 std::vector<uint8_t> buff(static_cast<uint8_t*>(buffer), static_cast<uint8_t*>(buffer) + bufferSize);
951 auto asyncContext = new AsyncContext();
952 asyncContext->buffer = buff;
953 asyncContext->instanceId = instanceId;
954 if (info.Length() != 1 && info[1]->IsFunction()) {
955 asyncContext->jsFunc = AceType::MakeRefPtr<JsFunction>(Framework::JSRef<Framework::JSObject>(),
956 JSRef<JSFunc>::Cast(info[1]));
957 asyncContext->execContext = info.GetExecutionContext();
958 }
959 auto engine = EngineHelper::GetCurrentEngineSafely();
960 if (!engine) {
961 free(asyncContext);
962 return;
963 }
964 NativeEngine* nativeEngine = engine->GetNativeEngine();
965 if (!nativeEngine) {
966 free(asyncContext);
967 return;
968 }
969 asyncContext->env = reinterpret_cast<napi_env>(nativeEngine);
970 napi_value promise = nullptr;
971 napi_create_promise(asyncContext->env, &asyncContext->deferred, &promise);
972 napi_value resourceName = nullptr;
973 napi_create_string_utf8(asyncContext->env, "ArkUISpanStringUnmarshalling", NAPI_AUTO_LENGTH, &resourceName);
974 napi_create_async_work(asyncContext->env, nullptr, resourceName, UnmarshallingExec, UnmarshallingComplete,
975 asyncContext, &asyncContext->asyncWork);
976 napi_queue_async_work(asyncContext->env, asyncContext->asyncWork);
977
978 auto jsPromise = JsConverter::ConvertNapiValueToJsVal(promise);
979 CHECK_NULL_VOID(jsPromise->IsObject());
980 info.SetReturnValue(JSRef<JSObject>::Cast(jsPromise));
981 }
982
983 // JSMutableSpanString
Constructor(const JSCallbackInfo & args)984 void JSMutableSpanString::Constructor(const JSCallbackInfo& args)
985 {
986 auto jsSpanString = Referenced::MakeRefPtr<JSMutableSpanString>();
987 jsSpanString->IncRefCount();
988 std::u16string data;
989
990 RefPtr<MutableSpanString> spanString;
991 if (args.Length() == 0) {
992 spanString = AceType::MakeRefPtr<MutableSpanString>(data);
993 } else {
994 if (args[0]->IsString()) {
995 JSViewAbstract::ParseJsString(args[0], data);
996 spanString = AceType::MakeRefPtr<MutableSpanString>(data);
997 if (args.Length() > 1) {
998 auto thisObj = args.This();
999 auto spanBases = JSSpanString::ParseJsSpanBaseVector(args[1], data.length(), thisObj);
1000 spanString->BindWithSpans(spanBases);
1001 }
1002 } else {
1003 if (!args[0]->IsObject()) {
1004 return;
1005 }
1006 auto* base = JSRef<JSObject>::Cast(args[0])->Unwrap<AceType>();
1007 auto* imageAttachment = AceType::DynamicCast<JSImageAttachment>(base);
1008 if (imageAttachment) {
1009 auto attachment = JSSpanString::ParseJsImageAttachment(args[0]);
1010 spanString = AceType::MakeRefPtr<MutableSpanString>(attachment);
1011 } else {
1012 RefPtr<CustomSpan> customSpan = JSSpanString::ParseJsCustomSpan(args);
1013 spanString = AceType::MakeRefPtr<MutableSpanString>(customSpan);
1014 }
1015 }
1016 }
1017 jsSpanString->SetController(spanString);
1018 jsSpanString->SetMutableController(spanString);
1019 args.SetReturnValue(Referenced::RawPtr(jsSpanString));
1020 }
1021
Destructor(JSMutableSpanString * spanString)1022 void JSMutableSpanString::Destructor(JSMutableSpanString* spanString)
1023 {
1024 if (spanString != nullptr) {
1025 spanString->DecRefCount();
1026 }
1027 }
1028
JSBind(BindingTarget globalObj)1029 void JSMutableSpanString::JSBind(BindingTarget globalObj)
1030 {
1031 JSClass<JSMutableSpanString>::Declare("MutableStyledString");
1032 JSClass<JSMutableSpanString>::CustomMethod("getString", &JSSpanString::GetString);
1033 JSClass<JSMutableSpanString>::CustomProperty("length", &JSSpanString::GetLength, &JSSpanString::SetLength);
1034 JSClass<JSMutableSpanString>::CustomMethod("equals", &JSSpanString::IsEqualToSpanString);
1035 JSClass<JSMutableSpanString>::CustomMethod("subStyledString", &JSSpanString::GetSubSpanString);
1036 JSClass<JSMutableSpanString>::CustomMethod("getStyles", &JSSpanString::GetSpans);
1037
1038 JSClass<JSMutableSpanString>::CustomMethod("replaceString", &JSMutableSpanString::ReplaceString);
1039 JSClass<JSMutableSpanString>::CustomMethod("insertString", &JSMutableSpanString::InsertString);
1040 JSClass<JSMutableSpanString>::CustomMethod("removeString", &JSMutableSpanString::RemoveString);
1041 JSClass<JSMutableSpanString>::CustomMethod("replaceStyle", &JSMutableSpanString::ReplaceSpan);
1042 JSClass<JSMutableSpanString>::CustomMethod("setStyle", &JSMutableSpanString::AddSpan);
1043 JSClass<JSMutableSpanString>::CustomMethod("removeStyle", &JSMutableSpanString::RemoveSpan);
1044 JSClass<JSMutableSpanString>::CustomMethod("removeStyles", &JSMutableSpanString::RemoveSpans);
1045 JSClass<JSMutableSpanString>::Method("clearStyles", &JSMutableSpanString::ClearAllSpans);
1046 JSClass<JSMutableSpanString>::CustomMethod("replaceStyledString", &JSMutableSpanString::ReplaceSpanString);
1047 JSClass<JSMutableSpanString>::CustomMethod("insertStyledString", &JSMutableSpanString::InsertSpanString);
1048 JSClass<JSMutableSpanString>::CustomMethod("appendStyledString", &JSMutableSpanString::AppendSpanString);
1049 JSClass<JSMutableSpanString>::Bind(globalObj, JSMutableSpanString::Constructor, JSMutableSpanString::Destructor);
1050 }
1051
ReplaceString(const JSCallbackInfo & info)1052 void JSMutableSpanString::ReplaceString(const JSCallbackInfo& info)
1053 {
1054 if (info.Length() != 3 || !info[0]->IsNumber() || !info[1]->IsNumber() || !info[2]->IsString()) {
1055 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1056 return;
1057 }
1058 int32_t start = info[0]->ToNumber<int32_t>();
1059 int32_t length = info[1]->ToNumber<int32_t>();
1060 auto controller = GetMutableController().Upgrade();
1061 CHECK_NULL_VOID(controller);
1062 if (!CheckParameters(start, length)) {
1063 return;
1064 }
1065 std::u16string data = info[2]->ToU16String();
1066 controller->ReplaceString(start, length, data);
1067 }
1068
InsertString(const JSCallbackInfo & info)1069 void JSMutableSpanString::InsertString(const JSCallbackInfo& info)
1070 {
1071 if (info.Length() != 2 || !info[0]->IsNumber() || !info[1]->IsString()) {
1072 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1073 return;
1074 }
1075 auto start = info[0]->ToNumber<int32_t>();
1076 std::u16string data = info[1]->ToU16String();
1077 auto controller = GetMutableController().Upgrade();
1078 CHECK_NULL_VOID(controller);
1079 // The input parameter must not cross the boundary.
1080 auto characterLength = controller->GetLength();
1081 if (start < 0 || start > characterLength) {
1082 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s start: %d StyledStringLength: %d",
1083 "Out of bounds", start, characterLength);
1084 return;
1085 }
1086 controller->InsertString(start, data);
1087 }
1088
RemoveString(const JSCallbackInfo & info)1089 void JSMutableSpanString::RemoveString(const JSCallbackInfo& info)
1090 {
1091 if (info.Length() != 2 || !info[0]->IsNumber() || !info[1]->IsNumber()) {
1092 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1093 return;
1094 }
1095 auto start = info[0]->ToNumber<int32_t>();
1096 auto length = info[1]->ToNumber<int32_t>();
1097 auto controller = GetMutableController().Upgrade();
1098 CHECK_NULL_VOID(controller);
1099 if (!CheckParameters(start, length)) {
1100 return;
1101 }
1102 controller->RemoveString(start, length);
1103 }
1104
IsImageNode(int32_t location)1105 bool JSMutableSpanString::IsImageNode(int32_t location)
1106 {
1107 auto mutableSpanString = mutableSpanString_.Upgrade();
1108 CHECK_NULL_RETURN(mutableSpanString, false);
1109 return mutableSpanString->IsSpeicalNode(location, SpanType::Image);
1110 }
1111
IsCustomSpanNode(int32_t location)1112 bool JSMutableSpanString::IsCustomSpanNode(int32_t location)
1113 {
1114 auto mutableSpanString = mutableSpanString_.Upgrade();
1115 CHECK_NULL_RETURN(mutableSpanString, false);
1116 return mutableSpanString->IsSpeicalNode(location, SpanType::CustomSpan);
1117 }
1118
VerifyImageParameters(int32_t start,int32_t length)1119 bool JSMutableSpanString::VerifyImageParameters(int32_t start, int32_t length)
1120 {
1121 if (length != 1) {
1122 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "VerifyImageParameters failed: length should be one");
1123 return false;
1124 }
1125 if (!IsImageNode(start)) {
1126 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "VerifyCustomSpanParameters failed: Not ImageNode");
1127 return false;
1128 }
1129 return true;
1130 }
1131
VerifyCustomSpanParameters(int32_t start,int32_t length)1132 bool JSMutableSpanString::VerifyCustomSpanParameters(int32_t start, int32_t length)
1133 {
1134 if (length != 1) {
1135 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "VerifyCustomSpanParameters failed: length should be one");
1136 return false;
1137 }
1138 if (!IsCustomSpanNode(start)) {
1139 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "VerifyCustomSpanParameters failed: Not CustomSpanNode");
1140 return false;
1141 }
1142 return true;
1143 }
1144
ReplaceSpan(const JSCallbackInfo & info)1145 void JSMutableSpanString::ReplaceSpan(const JSCallbackInfo& info)
1146 {
1147 if (info.Length() != 1 || !info[0]->IsObject()) {
1148 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1149 return;
1150 }
1151 auto paramObject = JSRef<JSObject>::Cast(info[0]);
1152 auto startObj = paramObject->GetProperty("start");
1153 auto lengthObj = paramObject->GetProperty("length");
1154 auto styleKeyObj = paramObject->GetProperty("styledKey");
1155 auto styleValueObj = paramObject->GetProperty("styledValue");
1156 if (!startObj->IsNumber() || !lengthObj->IsNumber() || !styleKeyObj->IsNumber() || !styleValueObj->IsObject()) {
1157 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1158 return;
1159 }
1160 auto spanType = styleKeyObj->ToNumber<int32_t>();
1161 if (!CheckSpanType(spanType)) {
1162 return;
1163 }
1164 auto start = startObj->ToNumber<int32_t>();
1165 auto length = lengthObj->ToNumber<int32_t>();
1166 auto type = static_cast<SpanType>(spanType);
1167 if (type == SpanType::Image && !VerifyImageParameters(start, length)) {
1168 return;
1169 }
1170 if (type == SpanType::CustomSpan && !VerifyCustomSpanParameters(start, length)) {
1171 return;
1172 }
1173 if (!styleValueObj->IsObject()) {
1174 return;
1175 }
1176 auto spanBase = ParseJsSpanBaseWithoutSpecialSpan(start, length, type, JSRef<JSObject>::Cast(styleValueObj), info);
1177 if (!spanBase) {
1178 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s",
1179 "ReplaceSpan failed: maybe styledKey & corresponding value not match");
1180 return;
1181 }
1182 auto controller = GetMutableController().Upgrade();
1183 CHECK_NULL_VOID(controller);
1184 if (!CheckParameters(start, length)) {
1185 return;
1186 }
1187 if (type == SpanType::Gesture) {
1188 auto thisObj = info.This();
1189 auto newIndex = gestureStyleStoreIndex_.fetch_add(1);
1190 std::string key = "STYLED_STRING_GESTURESTYLE_STORE_" + std::to_string(newIndex);
1191 thisObj->SetPropertyObject(key.c_str(), styleValueObj);
1192 }
1193 controller->ReplaceSpan(start, length, spanBase);
1194 }
1195
AddSpan(const JSCallbackInfo & info)1196 void JSMutableSpanString::AddSpan(const JSCallbackInfo& info)
1197 {
1198 if (info.Length() != 1 || !info[0]->IsObject()) {
1199 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1200 return;
1201 }
1202 auto paramObject = JSRef<JSObject>::Cast(info[0]);
1203 auto startObj = paramObject->GetProperty("start");
1204 auto lengthObj = paramObject->GetProperty("length");
1205 auto styleKeyObj = paramObject->GetProperty("styledKey");
1206 auto styleValueObj = paramObject->GetProperty("styledValue");
1207 if (!startObj->IsNumber() || !lengthObj->IsNumber() || !styleKeyObj->IsNumber() || !styleValueObj->IsObject()) {
1208 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1209 return;
1210 }
1211 auto spanType = styleKeyObj->ToNumber<int32_t>();
1212 CHECK_NULL_VOID(CheckSpanType(spanType));
1213 auto start = startObj->ToNumber<int32_t>();
1214 auto length = lengthObj->ToNumber<int32_t>();
1215 auto type = static_cast<SpanType>(spanType);
1216 if (type == SpanType::Image && !VerifyImageParameters(start, length)) {
1217 return;
1218 }
1219 if (type == SpanType::CustomSpan && !VerifyCustomSpanParameters(start, length)) {
1220 return;
1221 }
1222 CHECK_NULL_VOID(styleValueObj->IsObject());
1223 auto spanBase = ParseJsSpanBaseWithoutSpecialSpan(start, length, type, JSRef<JSObject>::Cast(styleValueObj), info);
1224 if (!spanBase) {
1225 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s",
1226 "AddSpan failed: maybe styledKey & corresponding value not match");
1227 return;
1228 }
1229 auto controller = GetMutableController().Upgrade();
1230 CHECK_NULL_VOID(controller);
1231 if (!CheckParameters(start, length)) {
1232 return;
1233 }
1234 if (type == SpanType::Image) {
1235 controller->RemoveSpan(start, length, SpanType::Image);
1236 } else if (type == SpanType::CustomSpan) {
1237 controller->RemoveSpan(start, length, SpanType::CustomSpan);
1238 } else if (type == SpanType::Gesture) {
1239 auto thisObj = info.This();
1240 auto newIndex = gestureStyleStoreIndex_.fetch_add(1);
1241 std::string key = "STYLED_STRING_GESTURESTYLE_STORE_" + std::to_string(newIndex);
1242 thisObj->SetPropertyObject(key.c_str(), styleValueObj);
1243 }
1244 controller->AddSpan(spanBase);
1245 }
1246
RemoveSpan(const JSCallbackInfo & info)1247 void JSMutableSpanString::RemoveSpan(const JSCallbackInfo& info)
1248 {
1249 if (info.Length() != 3 || !info[0]->IsNumber() || !info[1]->IsNumber() || !info[2]->IsNumber()) {
1250 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1251 return;
1252 }
1253 auto start = info[0]->ToNumber<int32_t>();
1254 auto length = info[1]->ToNumber<int32_t>();
1255 auto spanType = info[2]->ToNumber<int32_t>();
1256 if (!CheckSpanType(spanType)) {
1257 return;
1258 }
1259 auto type = static_cast<SpanType>(spanType);
1260 auto controller = GetMutableController().Upgrade();
1261 CHECK_NULL_VOID(controller);
1262 if (!CheckParameters(start, length)) {
1263 return;
1264 }
1265 controller->RemoveSpan(start, length, type);
1266 }
1267
RemoveSpans(const JSCallbackInfo & info)1268 void JSMutableSpanString::RemoveSpans(const JSCallbackInfo& info)
1269 {
1270 if (info.Length() != 2 || !info[0]->IsNumber() || !info[1]->IsNumber()) {
1271 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1272 return;
1273 }
1274 auto controller = GetMutableController().Upgrade();
1275 CHECK_NULL_VOID(controller);
1276 auto start = info[0]->ToNumber<int32_t>();
1277 auto length = info[1]->ToNumber<int32_t>();
1278 if (!CheckParameters(start, length)) {
1279 return;
1280 }
1281 controller->RemoveSpans(start, length);
1282 }
1283
ClearAllSpans()1284 void JSMutableSpanString::ClearAllSpans()
1285 {
1286 auto controller = GetMutableController().Upgrade();
1287 CHECK_NULL_VOID(controller);
1288 controller->ClearAllSpans();
1289 }
1290
ReplaceSpanString(const JSCallbackInfo & info)1291 void JSMutableSpanString::ReplaceSpanString(const JSCallbackInfo& info)
1292 {
1293 if (info.Length() != 3 || !info[0]->IsNumber() || !info[1]->IsNumber() || !info[2]->IsObject()) {
1294 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1295 return;
1296 }
1297 auto start = info[0]->ToNumber<int32_t>();
1298 auto length = info[1]->ToNumber<int32_t>();
1299 auto* spanString = JSRef<JSObject>::Cast(info[2])->Unwrap<JSSpanString>();
1300 if (!spanString) {
1301 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Failed To Parse StyledString");
1302 return;
1303 }
1304 auto spanStringController = spanString->GetController();
1305 CHECK_NULL_VOID(spanStringController);
1306 auto controller = GetMutableController().Upgrade();
1307 CHECK_NULL_VOID(controller);
1308 if (!CheckParameters(start, length)) {
1309 return;
1310 }
1311 auto thisObj = info.This();
1312 auto newIndex = spanStringStoreIndex_.fetch_add(1);
1313 std::string key = "STYLED_STRING_SPANSTRING_STORE_" + std::to_string(newIndex);
1314 thisObj->SetPropertyObject(key.c_str(), info[2]);
1315 controller->ReplaceSpanString(start, length, spanStringController);
1316 }
1317
InsertSpanString(const JSCallbackInfo & info)1318 void JSMutableSpanString::InsertSpanString(const JSCallbackInfo& info)
1319 {
1320 if (info.Length() != 2 || !info[0]->IsNumber() || !info[1]->IsObject()) {
1321 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1322 return;
1323 }
1324 auto start = info[0]->ToNumber<int32_t>();
1325 auto* spanString = JSRef<JSObject>::Cast(info[1])->Unwrap<JSSpanString>();
1326 if (!spanString) {
1327 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Failed To Parse StyledString");
1328 return;
1329 }
1330 auto spanStringController = spanString->GetController();
1331 CHECK_NULL_VOID(spanStringController);
1332 auto controller = GetMutableController().Upgrade();
1333 CHECK_NULL_VOID(controller);
1334 // The input parameter must not cross the boundary.
1335 auto characterLength = controller->GetLength();
1336 if (start < 0 || start > characterLength) {
1337 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s start: %d StyledStringLength: %d",
1338 "Out of bounds", start, characterLength);
1339 return;
1340 }
1341 auto thisObj = info.This();
1342 auto newIndex = spanStringStoreIndex_.fetch_add(1);
1343 std::string key = "STYLED_STRING_SPANSTRING_STORE_" + std::to_string(newIndex);
1344 thisObj->SetPropertyObject(key.c_str(), info[1]);
1345 controller->InsertSpanString(start, spanStringController);
1346 }
1347
AppendSpanString(const JSCallbackInfo & info)1348 void JSMutableSpanString::AppendSpanString(const JSCallbackInfo& info)
1349 {
1350 if (info.Length() != 1 || !info[0]->IsObject()) {
1351 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Input parameter check failed.");
1352 return;
1353 }
1354 auto* spanString = JSRef<JSObject>::Cast(info[0])->Unwrap<JSSpanString>();
1355 if (!spanString) {
1356 JSException::Throw(ERROR_CODE_PARAM_INVALID, "%s", "Failed To Parse StyledString");
1357 return;
1358 }
1359 auto spanStringController = spanString->GetController();
1360 CHECK_NULL_VOID(spanStringController);
1361 auto controller = GetMutableController().Upgrade();
1362 CHECK_NULL_VOID(controller);
1363 auto thisObj = info.This();
1364 auto newIndex = spanStringStoreIndex_.fetch_add(1);
1365 std::string key = "STYLED_STRING_SPANSTRING_STORE_" + std::to_string(newIndex);
1366 thisObj->SetPropertyObject(key.c_str(), info[0]);
1367 controller->AppendSpanString(spanStringController);
1368 }
1369
GetMutableController()1370 WeakPtr<MutableSpanString>& JSMutableSpanString::GetMutableController()
1371 {
1372 return mutableSpanString_;
1373 }
1374
SetMutableController(const RefPtr<MutableSpanString> & mutableSpanString)1375 void JSMutableSpanString::SetMutableController(const RefPtr<MutableSpanString>& mutableSpanString)
1376 {
1377 mutableSpanString_ = mutableSpanString;
1378 }
1379
1380 } // namespace OHOS::Ace::Framework