• 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         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, &param);
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, &param);
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