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