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