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