• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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, &param);
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, &param);
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