• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-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 "bridge/declarative_frontend/jsview/js_richeditor.h"
17 
18 #include <optional>
19 #include <string>
20 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
21 
22 #include "base/geometry/dimension.h"
23 #include "base/geometry/ng/size_t.h"
24 #include "base/log/ace_scoring_log.h"
25 #include "bridge/common/utils/utils.h"
26 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
27 #include "bridge/declarative_frontend/engine/functions/js_function.h"
28 #include "bridge/declarative_frontend/engine/functions/js_hover_function.h"
29 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
30 #include "bridge/declarative_frontend/engine/js_types.h"
31 #include "bridge/declarative_frontend/engine/jsi/jsi_types.h"
32 #include "bridge/declarative_frontend/jsview/js_container_base.h"
33 #include "bridge/declarative_frontend/jsview/js_image.h"
34 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
35 #include "bridge/declarative_frontend/jsview/js_layout_manager.h"
36 #include "bridge/declarative_frontend/jsview/js_shape_abstract.h"
37 #include "bridge/declarative_frontend/jsview/js_textfield.h"
38 #include "bridge/declarative_frontend/jsview/js_utils.h"
39 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
40 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
41 #include "bridge/declarative_frontend/jsview/models/richeditor_model_impl.h"
42 #include "bridge/declarative_frontend/style_string/js_span_string.h"
43 #include "core/common/resource/resource_object.h"
44 #include "core/components/common/properties/text_style.h"
45 #include "core/components/common/properties/text_style_parser.h"
46 #include "core/components/text/text_theme.h"
47 #include "core/components_ng/base/view_stack_model.h"
48 #include "core/components_ng/pattern/rich_editor/color_mode_processor.h"
49 #include "core/components_ng/pattern/rich_editor/rich_editor_base_controller.h"
50 #include "core/components_ng/pattern/rich_editor/rich_editor_model.h"
51 #include "core/components_ng/pattern/rich_editor/rich_editor_theme.h"
52 #include "frameworks/bridge/declarative_frontend/jsview/js_container_span.h"
53 #include "frameworks/bridge/declarative_frontend/jsview/js_text.h"
54 
55 namespace OHOS::Ace {
56 std::unique_ptr<RichEditorModel> RichEditorModel::instance_ = nullptr;
57 std::mutex RichEditorModel::mutex_;
58 constexpr int32_t SYSTEM_SYMBOL_BOUNDARY = 0XFFFFF;
59 const std::string DEFAULT_SYMBOL_FONTFAMILY = "HM Symbol";
60 
GetInstance()61 RichEditorModel* RichEditorModel::GetInstance()
62 {
63     if (!instance_) {
64         std::lock_guard<std::mutex> lock(mutex_);
65         if (!instance_) {
66 #ifdef NG_BUILD
67             instance_.reset(new NG::RichEditorModelNG());
68 #else
69             if (Container::IsCurrentUseNewPipeline()) {
70                 instance_.reset(new NG::RichEditorModelNG());
71             } else {
72                 // empty implementation
73                 instance_.reset(new Framework::RichEditorModelImpl());
74             }
75 #endif
76         }
77     }
78     return instance_.get();
79 }
80 } // namespace OHOS::Ace
81 
82 namespace OHOS::Ace::Framework {
83 enum class RenderingStrategy {
84     SINGLE = 0,
85     MULTIPLE_COLOR,
86     MULTIPLE_OPACITY
87 };
88 
ParseLengthMetrics(const JSRef<JSObject> & obj)89 CalcDimension JSRichEditor::ParseLengthMetrics(const JSRef<JSObject>& obj)
90 {
91     CalcDimension size;
92     auto value = 0.0;
93     auto valueObj = obj->GetProperty("value");
94     if (!valueObj->IsNull() && valueObj->IsNumber()) {
95         value = valueObj->ToNumber<float>();
96     }
97     auto unit = DimensionUnit::VP;
98     auto unitObj = obj->GetProperty("unit");
99     if (!unitObj->IsNull() && unitObj->IsNumber()) {
100         unit = static_cast<DimensionUnit>(unitObj->ToNumber<int32_t>());
101     }
102     if (value >= 0 && unit != DimensionUnit::PERCENT) {
103         size = CalcDimension(value, unit);
104     }
105     return size;
106 }
ParseMarginAttr(JsiRef<JSVal> marginAttr)107 std::optional<NG::MarginProperty> JSRichEditor::ParseMarginAttr(JsiRef<JSVal> marginAttr)
108 {
109     std::optional<NG::MarginProperty> marginProp = std::nullopt;
110     CalcDimension length;
111     if (!marginAttr->IsObject() && !marginAttr->IsNumber() && !marginAttr->IsString()) {
112         length.Reset();
113         marginProp = NG::ConvertToCalcPaddingProperty(length, length, length, length);
114         return marginProp;
115     }
116     if (JSViewAbstract::ParseJsDimensionVp(marginAttr, length)) {
117         marginProp = NG::ConvertToCalcPaddingProperty(length, length, length, length);
118     } else if (marginAttr->IsObject()) {
119         auto marginObj = JSRef<JSObject>::Cast(marginAttr);
120         if (marginObj->HasProperty("value")) {
121             length = ParseLengthMetrics(marginObj);
122             marginProp = NG::ConvertToCalcPaddingProperty(length, length, length, length);
123             return marginProp;
124         }
125         std::optional<CalcDimension> left;
126         std::optional<CalcDimension> right;
127         std::optional<CalcDimension> top;
128         std::optional<CalcDimension> bottom;
129         JSViewAbstract::ParseMarginOrPaddingCorner(marginObj, top, bottom, left, right);
130         marginProp = NG::ConvertToCalcPaddingProperty(top, bottom, left, right);
131     }
132     return marginProp;
133 }
134 
ParseBorderRadiusAttr(JsiRef<JSVal> args)135 std::optional<NG::BorderRadiusProperty> JSRichEditor::ParseBorderRadiusAttr(JsiRef<JSVal> args)
136 {
137     std::optional<NG::BorderRadiusProperty> prop = std::nullopt;
138     CalcDimension radiusDim;
139     if (!args->IsObject() && !args->IsNumber() && !args->IsString()) {
140         radiusDim.Reset();
141         NG::BorderRadiusProperty borderRadius;
142         borderRadius.SetRadius(radiusDim);
143         borderRadius.multiValued = false;
144         prop = borderRadius;
145         return prop;
146     }
147     if (JSViewAbstract::ParseJsDimensionVp(args, radiusDim)) {
148         if (radiusDim.Unit() == DimensionUnit::PERCENT) {
149             radiusDim.Reset();
150         }
151         NG::BorderRadiusProperty borderRadius;
152         borderRadius.SetRadius(radiusDim);
153         borderRadius.multiValued = false;
154         prop = borderRadius;
155     } else if (args->IsObject()) {
156         JSRef<JSObject> object = JSRef<JSObject>::Cast(args);
157         if (object->HasProperty("value")) {
158             NG::BorderRadiusProperty borderRadius;
159             borderRadius.SetRadius(ParseLengthMetrics(object));
160             borderRadius.multiValued = false;
161             prop = borderRadius;
162             return prop;
163         }
164         CalcDimension topLeft;
165         CalcDimension topRight;
166         CalcDimension bottomLeft;
167         CalcDimension bottomRight;
168         JSViewAbstract::ParseAllBorderRadiuses(object, topLeft, topRight, bottomLeft, bottomRight);
169         NG::BorderRadiusProperty borderRadius;
170         borderRadius.radiusTopLeft = topLeft;
171         borderRadius.radiusTopRight = topRight;
172         borderRadius.radiusBottomLeft = bottomLeft;
173         borderRadius.radiusBottomRight = bottomRight;
174         borderRadius.multiValued = true;
175         prop = borderRadius;
176     }
177     return prop;
178 }
179 
Create(const JSCallbackInfo & info)180 void JSRichEditor::Create(const JSCallbackInfo& info)
181 {
182     JSRichEditorBaseController* jsBaseController = nullptr;
183     if (info[0]->IsObject()) {
184         auto paramObject = JSRef<JSObject>::Cast(info[0]);
185         auto controllerObj = paramObject->GetProperty("controller");
186         if (!controllerObj->IsUndefined() && !controllerObj->IsNull() && controllerObj->IsObject()) {
187             jsBaseController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSRichEditorBaseController>();
188         }
189     }
190     bool isStyledStringMode = jsBaseController && jsBaseController->IsStyledStringMode();
191     RichEditorModel::GetInstance()->Create(isStyledStringMode);
192     RefPtr<RichEditorBaseControllerBase> controller = RichEditorModel::GetInstance()->GetRichEditorController();
193     if (jsBaseController) {
194         jsBaseController->SetInstanceId(Container::CurrentId());
195         jsBaseController->SetController(controller);
196     }
197 }
198 
SetOnReady(const JSCallbackInfo & args)199 void JSRichEditor::SetOnReady(const JSCallbackInfo& args)
200 {
201     if (!args[0]->IsFunction()) {
202         return;
203     }
204     JsEventCallback<void()> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
205     RichEditorModel::GetInstance()->SetOnReady(callback);
206 }
207 
CreateJSTextStyleResult(const TextStyleResult & textStyleResult)208 JSRef<JSObject> JSRichEditor::CreateJSTextStyleResult(const TextStyleResult& textStyleResult)
209 {
210     JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
211     textStyleObj->SetProperty<std::string>("fontColor", textStyleResult.fontColor);
212     textStyleObj->SetProperty<double>("fontSize", textStyleResult.fontSize);
213     textStyleObj->SetProperty<int32_t>("fontStyle", textStyleResult.fontStyle);
214     textStyleObj->SetProperty<int32_t>("fontWeight", textStyleResult.fontWeight);
215     textStyleObj->SetProperty<std::string>("fontFamily", textStyleResult.fontFamily);
216 
217     JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
218     decorationObj->SetProperty<int32_t>("type", textStyleResult.decorationType);
219     decorationObj->SetProperty<std::string>("color", textStyleResult.decorationColor);
220     decorationObj->SetProperty<int32_t>("style", textStyleResult.decorationStyle);
221     textStyleObj->SetPropertyObject("decoration", decorationObj);
222 
223     textStyleObj->SetProperty<double>("lineHeight", textStyleResult.lineHeight);
224     textStyleObj->SetProperty<bool>("halfLeading", textStyleResult.halfLeading);
225     textStyleObj->SetProperty<double>("letterSpacing", textStyleResult.letterSpacing);
226     textStyleObj->SetProperty<std::string>("fontFeature", UnParseFontFeatureSetting(textStyleResult.fontFeature));
227     textStyleObj->SetPropertyObject("textShadow", CreateJsTextShadowObjectArray(textStyleResult));
228     SetJsTextBackgroundStyle(textStyleObj, textStyleResult);
229 
230     return textStyleObj;
231 }
232 
CreateJsTextShadowObjectArray(const TextStyleResult & textSpanResult)233 JSRef<JSArray> JSRichEditor::CreateJsTextShadowObjectArray(const TextStyleResult& textSpanResult)
234 {
235     return CreateJsTextShadowObjectArray(textSpanResult.textShadows);
236 }
237 
CreateJsTextShadowObjectArray(const std::vector<Shadow> & textShadows)238 JSRef<JSArray> JSRichEditor::CreateJsTextShadowObjectArray(const std::vector<Shadow>& textShadows)
239 {
240     JSRef<JSArray> textShadowArray = JSRef<JSArray>::New();
241     int32_t index = 0;
242     for (const auto& it : textShadows) {
243         JSRef<JSObject> textShadowObj = JSRef<JSObject>::New();
244         textShadowObj->SetProperty<double>("radius", it.GetBlurRadius());
245         textShadowObj->SetProperty<std::string>("color", it.GetColor().ToString());
246         textShadowObj->SetProperty<double>("offsetX", it.GetOffset().GetX());
247         textShadowObj->SetProperty<double>("offsetY", it.GetOffset().GetY());
248         textShadowArray->SetValueAt(index, textShadowObj);
249         index++;
250     }
251     return textShadowArray;
252 }
253 
SetJsTextBackgroundStyle(JSRef<JSObject> & textStyleObj,const TextStyleResult & textSpanResult)254 void JSRichEditor::SetJsTextBackgroundStyle(JSRef<JSObject>& textStyleObj, const TextStyleResult& textSpanResult)
255 {
256     auto textBackgroundStyle = textSpanResult.textBackgroundStyle;
257     CHECK_NULL_VOID(textBackgroundStyle.has_value());
258     textStyleObj->SetPropertyObject("textBackgroundStyle", CreateJsTextBackgroundStyle(textBackgroundStyle.value()));
259 }
260 
CreateJsTextBackgroundStyle(const TextBackgroundStyle & style)261 JSRef<JSObject> JSRichEditor::CreateJsTextBackgroundStyle(const TextBackgroundStyle& style)
262 {
263     JSRef<JSObject> textBackgroundStyleObj = JSRef<JSObject>::New();
264     textBackgroundStyleObj->SetProperty<std::string>("color", style.backgroundColor->ColorToString());
265     textBackgroundStyleObj->SetProperty<std::string>("radius", style.backgroundRadius->ToString());
266     return textBackgroundStyleObj;
267 }
268 
CreateJSParagraphStyle(const TextStyleResult & textStyleResult)269 JSRef<JSObject> JSRichEditor::CreateJSParagraphStyle(const TextStyleResult& textStyleResult)
270 {
271     JSRef<JSObject> paragraphStyleObj = JSRef<JSObject>::New();
272     paragraphStyleObj->SetProperty<int32_t>("textAlign", textStyleResult.textAlign);
273     JSRef<JSArray> leadingMarginArray = JSRef<JSArray>::New();
274     leadingMarginArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textStyleResult.leadingMarginSize[0])));
275     leadingMarginArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(textStyleResult.leadingMarginSize[1])));
276     paragraphStyleObj->SetPropertyObject("leadingMargin", leadingMarginArray);
277     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
278         paragraphStyleObj->SetProperty<int32_t>("wordBreak", textStyleResult.wordBreak);
279         paragraphStyleObj->SetProperty<int32_t>("lineBreakStrategy", textStyleResult.lineBreakStrategy);
280     }
281     if (textStyleResult.paragraphSpacing.has_value()) {
282         paragraphStyleObj->SetProperty<double>("paragraphSpacing",
283             textStyleResult.paragraphSpacing.value().ConvertToFp());
284     }
285     return paragraphStyleObj;
286 }
287 
SetJSUrlStyle(const std::u16string & urlAddress,JSRef<JSObject> & resultObj)288 void JSRichEditor::SetJSUrlStyle(const std::u16string& urlAddress, JSRef<JSObject>& resultObj)
289 {
290     CHECK_NULL_VOID(!urlAddress.empty());
291     JSRef<JSObject> urlStyleObj = JSRef<JSObject>::New();
292     urlStyleObj->SetProperty<std::u16string>("url", urlAddress);
293     resultObj->SetPropertyObject("urlStyle", urlStyleObj);
294 }
295 
CreateJSSymbolSpanStyleResult(const SymbolSpanStyle & symbolSpanStyle)296 JSRef<JSObject> JSRichEditor::CreateJSSymbolSpanStyleResult(const SymbolSpanStyle& symbolSpanStyle)
297 {
298     JSRef<JSObject> symbolSpanStyleObj = JSRef<JSObject>::New();
299     symbolSpanStyleObj->SetProperty<std::string>("fontColor", symbolSpanStyle.symbolColor);
300     symbolSpanStyleObj->SetProperty<NG::FONT_FEATURES_LIST>("fontFeature", symbolSpanStyle.fontFeature);
301     symbolSpanStyleObj->SetProperty<double>("fontSize", symbolSpanStyle.fontSize);
302     symbolSpanStyleObj->SetProperty<double>("lineHeight", symbolSpanStyle.lineHeight);
303     symbolSpanStyleObj->SetProperty<double>("letterSpacing", symbolSpanStyle.letterSpacing);
304     symbolSpanStyleObj->SetProperty<int32_t>("fontWeight", symbolSpanStyle.fontWeight);
305     symbolSpanStyleObj->SetProperty<uint32_t>("renderingStrategy", symbolSpanStyle.renderingStrategy);
306     symbolSpanStyleObj->SetProperty<uint32_t>("effectStrategy", symbolSpanStyle.effectStrategy);
307 
308     return symbolSpanStyleObj;
309 }
310 
CreateJSValueResource(const RefPtr<ResourceObject> & valueResource)311 JSRef<JSObject> JSRichEditor::CreateJSValueResource(const RefPtr<ResourceObject>& valueResource)
312 {
313     JSRef<JSObject> valueResourceObj = JSRef<JSObject>::New();
314     CHECK_NULL_RETURN(valueResource, valueResourceObj);
315     valueResourceObj->SetProperty<std::string>("bundleName", valueResource->GetBundleName());
316     valueResourceObj->SetProperty<std::string>("moduleName", valueResource->GetModuleName());
317     valueResourceObj->SetProperty<uint32_t>("id", valueResource->GetId());
318     valueResourceObj->SetProperty<std::vector<ResourceObjectParams>>("params", valueResource->GetParams());
319     valueResourceObj->SetProperty<uint32_t>("type", valueResource->GetType());
320 
321     return valueResourceObj;
322 }
323 
CreateJSLayoutStyle(const ImageStyleResult & imageStyleResult)324 JSRef<JSObject> JSRichEditor::CreateJSLayoutStyle(const ImageStyleResult& imageStyleResult)
325 {
326     JSRef<JSObject> layoutStyleObj = JSRef<JSObject>::New();
327 
328     layoutStyleObj->SetProperty<std::string>("borderRadius", imageStyleResult.borderRadius);
329     layoutStyleObj->SetProperty<std::string>("margin", imageStyleResult.margin);
330 
331     return layoutStyleObj;
332 }
333 
CreateJSImageStyleResult(const ImageStyleResult & imageStyleResult)334 JSRef<JSObject> JSRichEditor::CreateJSImageStyleResult(const ImageStyleResult& imageStyleResult)
335 {
336     JSRef<JSObject> imageSpanStyleObj = JSRef<JSObject>::New();
337 
338     JSRef<JSArray> sizeArray = JSRef<JSArray>::New();
339     sizeArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(imageStyleResult.size[0])));
340     sizeArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(imageStyleResult.size[1])));
341     imageSpanStyleObj->SetPropertyObject("size", sizeArray);
342     imageSpanStyleObj->SetProperty<int32_t>("verticalAlign", imageStyleResult.verticalAlign);
343     imageSpanStyleObj->SetProperty<int32_t>("objectFit", imageStyleResult.objectFit);
344     imageSpanStyleObj->SetPropertyObject("layoutStyle", CreateJSLayoutStyle(imageStyleResult));
345 
346     return imageSpanStyleObj;
347 }
348 
CreateParagraphStyleResult(const ParagraphInfo & info)349 JSRef<JSObject> JSRichEditor::CreateParagraphStyleResult(const ParagraphInfo& info)
350 {
351     auto obj = JSRef<JSObject>::New();
352     obj->SetProperty<int32_t>("textAlign", info.textAlign);
353     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
354         obj->SetProperty<int32_t>("wordBreak", info.wordBreak);
355         obj->SetProperty<int32_t>("lineBreakStrategy", info.lineBreakStrategy);
356     }
357 
358     auto lmObj = JSRef<JSObject>::New();
359     auto size = JSRef<JSArray>::New();
360     size->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(info.leadingMarginSize[0])));
361     size->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(info.leadingMarginSize[1])));
362     lmObj->SetPropertyObject("size", size);
363 #ifdef PIXEL_MAP_SUPPORTED
364     if (info.leadingMarginPixmap) {
365         lmObj->SetPropertyObject("pixelMap", ConvertPixmap(info.leadingMarginPixmap));
366     }
367 #endif
368     obj->SetPropertyObject("leadingMargin", lmObj);
369     if (info.paragraphSpacing.has_value()) {
370         obj->SetProperty<double>("paragraphSpacing", info.paragraphSpacing.value());
371     }
372     return obj;
373 }
374 
CreateJSSpanResultObject(const ResultObject & resultObject)375 JSRef<JSObject> JSRichEditor::CreateJSSpanResultObject(const ResultObject& resultObject)
376 {
377     JSRef<JSArray> offsetArray = JSRef<JSArray>::New();
378     JSRef<JSArray> spanRangeArray = JSRef<JSArray>::New();
379     JSRef<JSObject> resultObj = JSRef<JSObject>::New();
380     JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
381     offsetArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(resultObject.offsetInSpan[0])));
382     offsetArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(resultObject.offsetInSpan[1])));
383     spanRangeArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(resultObject.spanPosition.spanRange[0])));
384     spanRangeArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(resultObject.spanPosition.spanRange[1])));
385     spanPositionObj->SetProperty<int32_t>("spanIndex", resultObject.spanPosition.spanIndex);
386     spanPositionObj->SetPropertyObject("spanRange", spanRangeArray);
387     resultObj->SetPropertyObject("offsetInSpan", offsetArray);
388     resultObj->SetPropertyObject("spanPosition", spanPositionObj);
389     SetJSSpanResultObject(resultObj, resultObject);
390     return resultObj;
391 }
392 
SetJSSpanResultObject(JSRef<JSObject> & resultObj,const ResultObject & resultObject)393 void JSRichEditor::SetJSSpanResultObject(JSRef<JSObject>& resultObj, const ResultObject& resultObject)
394 {
395     if (resultObject.type == SelectSpanType::TYPESPAN) {
396         resultObj->SetProperty<std::u16string>("value", resultObject.valueString);
397         resultObj->SetProperty<std::u16string>("previewText", resultObject.previewText);
398         resultObj->SetPropertyObject("textStyle", CreateJSTextStyleResult(resultObject.textStyle));
399         resultObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(resultObject.textStyle));
400         SetJSUrlStyle(resultObject.urlAddress, resultObj);
401     } else if (resultObject.type == SelectSpanType::TYPESYMBOLSPAN) {
402         resultObj->SetProperty<std::u16string>("value", resultObject.valueString);
403         resultObj->SetPropertyObject("symbolSpanStyle", CreateJSSymbolSpanStyleResult(resultObject.symbolSpanStyle));
404         resultObj->SetPropertyObject("valueResource", CreateJSValueResource(resultObject.valueResource));
405     } else if (resultObject.type == SelectSpanType::TYPEIMAGE) {
406         if (resultObject.valuePixelMap) {
407 #ifdef PIXEL_MAP_SUPPORTED
408             auto jsPixmap = ConvertPixmap(resultObject.valuePixelMap);
409             if (!jsPixmap->IsUndefined()) {
410                 resultObj->SetPropertyObject("valuePixelMap", jsPixmap);
411             }
412 #endif
413         } else {
414             resultObj->SetProperty<std::u16string>("valueResourceStr", resultObject.valueString);
415         }
416         resultObj->SetPropertyObject("imageStyle", CreateJSImageStyleResult(resultObject.imageStyle));
417     }
418 }
419 
CreateJSSelection(const SelectionInfo & selectInfo)420 JSRef<JSVal> JSRichEditor::CreateJSSelection(const SelectionInfo& selectInfo)
421 {
422     uint32_t idx = 0;
423 
424     JSRef<JSArray> selectionArray = JSRef<JSArray>::New();
425     JSRef<JSArray> spanObjectArray = JSRef<JSArray>::New();
426     JSRef<JSObject> selectionObject = JSRef<JSObject>::New();
427 
428     const std::list<ResultObject>& spanObjectList = selectInfo.GetSelection().resultObjects;
429     for (const ResultObject& spanObject : spanObjectList) {
430         spanObjectArray->SetValueAt(idx++, CreateJSSpanResultObject(spanObject));
431     }
432 
433     selectionArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[0])));
434     selectionArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[1])));
435 
436     selectionObject->SetPropertyObject("selection", selectionArray);
437     selectionObject->SetPropertyObject("spans", spanObjectArray);
438     return JSRef<JSVal>::Cast(selectionObject);
439 }
440 
SetOnSelect(const JSCallbackInfo & args)441 void JSRichEditor::SetOnSelect(const JSCallbackInfo& args)
442 {
443     if (!args[0]->IsFunction()) {
444         return;
445     }
446     auto jsSelectFunc =
447         AceType::MakeRefPtr<JsEventFunction<SelectionInfo, 1>>(JSRef<JSFunc>::Cast(args[0]), CreateJSSelection);
448     auto onSelect = [execCtx = args.GetExecutionContext(), func = std::move(jsSelectFunc)](const BaseEventInfo* info) {
449         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
450         const auto* eventInfo = TypeInfoHelper::DynamicCast<SelectionInfo>(info);
451         func->Execute(*eventInfo);
452     };
453     NG::RichEditorModelNG::GetInstance()->SetOnSelect(std::move(onSelect));
454 }
455 
SetOnEditingChange(const JSCallbackInfo & args)456 void JSRichEditor::SetOnEditingChange(const JSCallbackInfo& args)
457 {
458     if (!args[0]->IsFunction()) {
459         return;
460     }
461     JsEventCallback<void(bool)> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
462     NG::RichEditorModelNG::GetInstance()->SetOnEditingChange(std::move(callback));
463 }
464 
CreateJSSelectionRange(const SelectionRangeInfo & selectRange)465 JSRef<JSVal> JSRichEditor::CreateJSSelectionRange(const SelectionRangeInfo& selectRange)
466 {
467     JSRef<JSObject> selectionRangeObject = JSRef<JSObject>::New();
468 
469     JSRef<JSVal> start = JSRef<JSVal>::Make(ToJSValue(selectRange.start_));
470     JSRef<JSVal> end = JSRef<JSVal>::Make(ToJSValue(selectRange.end_));
471 
472     selectionRangeObject->SetPropertyObject("start", start);
473     selectionRangeObject->SetPropertyObject("end", end);
474     return JSRef<JSVal>::Cast(selectionRangeObject);
475 }
476 
SetOnSelectionChange(const JSCallbackInfo & args)477 void JSRichEditor::SetOnSelectionChange(const JSCallbackInfo& args)
478 {
479     if (args.Length() < 1 || !args[0]->IsFunction()) {
480         return;
481     }
482     auto jsSelectFunc =
483         AceType::MakeRefPtr<JsEventFunction<SelectionRangeInfo, 1>>(JSRef<JSFunc>::Cast(args[0]),
484         CreateJSSelectionRange);
485     auto onSelectionChange =
486         [execCtx = args.GetExecutionContext(), func = std::move(jsSelectFunc)](const BaseEventInfo* info) {
487         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
488         const auto* eventInfo = TypeInfoHelper::DynamicCast<SelectionRangeInfo>(info);
489         func->Execute(*eventInfo);
490     };
491     NG::RichEditorModelNG::GetInstance()->SetOnSelectionChange(std::move(onSelectionChange));
492 }
493 
SetAboutToIMEInput(const JSCallbackInfo & args)494 void JSRichEditor::SetAboutToIMEInput(const JSCallbackInfo& args)
495 {
496     if (!args[0]->IsFunction()) {
497         return;
498     }
499     auto jsAboutToIMEInputFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorInsertValue, 1>>(
500         JSRef<JSFunc>::Cast(args[0]), CreateJsAboutToIMEInputObj);
501     auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
502                         const NG::RichEditorInsertValue& insertValue) -> bool {
503         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
504         auto ret = func->ExecuteWithValue(insertValue);
505         if (ret->IsBoolean()) {
506             return ret->ToBoolean();
507         }
508         return true;
509     };
510     RichEditorModel::GetInstance()->SetAboutToIMEInput(std::move(callback));
511 }
512 
SetOnIMEInputComplete(const JSCallbackInfo & args)513 void JSRichEditor::SetOnIMEInputComplete(const JSCallbackInfo& args)
514 {
515     if (!args[0]->IsFunction()) {
516         return;
517     }
518     auto jsOnIMEInputCompleteFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorAbstractSpanResult, 1>>(
519         JSRef<JSFunc>::Cast(args[0]), CreateJsOnIMEInputComplete);
520     auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnIMEInputCompleteFunc)](
521                         const NG::RichEditorAbstractSpanResult& textSpanResult) {
522         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
523         func->Execute(textSpanResult);
524         UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onIMEInputComplete");
525     };
526     RichEditorModel::GetInstance()->SetOnIMEInputComplete(std::move(callback));
527 }
528 
SetOnDidIMEInput(const JSCallbackInfo & args)529 void JSRichEditor::SetOnDidIMEInput(const JSCallbackInfo& args)
530 {
531     CHECK_NULL_VOID(args[0]->IsFunction());
532     auto jsOnDidIMEInputFunc =
533         AceType::MakeRefPtr<JsEventFunction<TextRange, 1>>(JSRef<JSFunc>::Cast(args[0]), CreateJsOnDidIMEInput);
534     auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnDidIMEInputFunc)](
535                         const TextRange& textRange) {
536         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
537         func->Execute(textRange);
538         UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onDidIMEInput");
539     };
540     RichEditorModel::GetInstance()->SetOnDidIMEInput(std::move(callback));
541 }
542 
SetAboutToDelete(const JSCallbackInfo & args)543 void JSRichEditor::SetAboutToDelete(const JSCallbackInfo& args)
544 {
545     if (!args[0]->IsFunction()) {
546         return;
547     }
548     auto jsAboutToDeleteFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorDeleteValue, 1>>(
549         JSRef<JSFunc>::Cast(args[0]), CreateJsAboutToDelet);
550     auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsAboutToDeleteFunc)](
551                         const NG::RichEditorDeleteValue& deleteValue) -> bool {
552         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
553         auto ret = func->ExecuteWithValue(deleteValue);
554         if (ret->IsBoolean()) {
555             return ret->ToBoolean();
556         }
557         return true;
558     };
559     RichEditorModel::GetInstance()->SetAboutToDelete(std::move(callback));
560 }
561 
SetOnDeleteComplete(const JSCallbackInfo & args)562 void JSRichEditor::SetOnDeleteComplete(const JSCallbackInfo& args)
563 {
564     if (!args[0]->IsFunction()) {
565         return;
566     }
567     JsEventCallback<void()> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
568     RichEditorModel::GetInstance()->SetOnDeleteComplete(callback);
569 }
570 
SetOnWillChange(const JSCallbackInfo & info)571 void JSRichEditor::SetOnWillChange(const JSCallbackInfo& info)
572 {
573     if (!info[0]->IsFunction()) {
574         return;
575     }
576     auto jsOnWillChangeFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorChangeValue, 1>>(
577         JSRef<JSFunc>::Cast(info[0]), CreateJsOnWillChange);
578     auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsOnWillChangeFunc)](
579                         const NG::RichEditorChangeValue& changeValue) -> bool {
580         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
581         auto ret = func->ExecuteWithValue(changeValue);
582         if (ret->IsBoolean()) {
583             return ret->ToBoolean();
584         }
585         return true;
586     };
587     RichEditorModel::GetInstance()->SetOnWillChange(std::move(callback));
588 }
589 
SetOnDidChange(const JSCallbackInfo & info)590 void JSRichEditor::SetOnDidChange(const JSCallbackInfo& info)
591 {
592     if (!info[0]->IsFunction()) {
593         return;
594     }
595     auto JsEventCallback =
596         AceType::MakeRefPtr<JsCommonEventFunction<NG::RichEditorChangeValue, 2>>(JSRef<JSFunc>::Cast(info[0]));
597     auto callback = [execCtx = info.GetExecutionContext(), func = std::move(JsEventCallback)](
598                         const NG::RichEditorChangeValue& changeValue) {
599         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
600         const auto& rangeBefore = changeValue.GetRangeBefore();
601         JSRef<JSObject> rangeBeforeObj = JSRef<JSObject>::New();
602         rangeBeforeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeBefore.start)));
603         rangeBeforeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeBefore.end)));
604 
605         const auto& rangeAfter = changeValue.GetRangeAfter();
606         JSRef<JSObject> rangeAfterObj = JSRef<JSObject>::New();
607         rangeAfterObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeAfter.start)));
608         rangeAfterObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeAfter.end)));
609 
610         JSRef<JSVal> param[2] = { JSRef<JSVal>::Cast(rangeBeforeObj), JSRef<JSVal>::Cast(rangeAfterObj) };
611         func->Execute(param);
612     };
613     RichEditorModel::GetInstance()->SetOnDidChange(std::move(callback));
614 }
615 
SetOnCut(const JSCallbackInfo & info)616 void JSRichEditor::SetOnCut(const JSCallbackInfo& info)
617 {
618     CHECK_NULL_VOID(info[0]->IsFunction());
619     auto jsTextFunc = AceType::MakeRefPtr<JsCitedEventFunction<NG::TextCommonEvent, 1>>(
620         JSRef<JSFunc>::Cast(info[0]), CreateJSTextCommonEvent);
621     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
622     auto onCut = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](
623                      NG::TextCommonEvent& info) {
624         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
625         ACE_SCORING_EVENT("onCut");
626         PipelineContext::SetCallBackNode(node);
627         func->Execute(info);
628     };
629     RichEditorModel::GetInstance()->SetOnCut(std::move(onCut));
630 }
631 
SetOnCopy(const JSCallbackInfo & info)632 void JSRichEditor::SetOnCopy(const JSCallbackInfo& info)
633 {
634     CHECK_NULL_VOID(info[0]->IsFunction());
635     auto jsTextFunc = AceType::MakeRefPtr<JsCitedEventFunction<NG::TextCommonEvent, 1>>(
636         JSRef<JSFunc>::Cast(info[0]), CreateJSTextCommonEvent);
637     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
638     auto onCopy = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](
639                       NG::TextCommonEvent& info) {
640         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
641         ACE_SCORING_EVENT("onCopy");
642         PipelineContext::SetCallBackNode(node);
643         func->Execute(info);
644     };
645     RichEditorModel::GetInstance()->SetOnCopy(std::move(onCopy));
646 }
647 
EditMenuOptions(const JSCallbackInfo & info)648 void JSRichEditor::EditMenuOptions(const JSCallbackInfo& info)
649 {
650     NG::OnCreateMenuCallback onCreateMenuCallback;
651     NG::OnMenuItemClickCallback onMenuItemClick;
652     JSViewAbstract::ParseEditMenuOptions(info, onCreateMenuCallback, onMenuItemClick);
653     RichEditorModel::GetInstance()->SetSelectionMenuOptions(
654         std::move(onCreateMenuCallback), std::move(onMenuItemClick));
655 }
656 
SetOnShare(const JSCallbackInfo & info)657 void JSRichEditor::SetOnShare(const JSCallbackInfo& info)
658 {
659     CHECK_NULL_VOID(info[0]->IsFunction());
660     auto jsTextFunc = AceType::MakeRefPtr<JsCitedEventFunction<NG::TextCommonEvent, 1>>(
661         JSRef<JSFunc>::Cast(info[0]), CreateJSTextCommonEvent);
662     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
663     auto onShare = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](
664                         NG::TextCommonEvent& info) {
665         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
666         ACE_SCORING_EVENT("onShare");
667         PipelineContext::SetCallBackNode(node);
668         func->Execute(info);
669     };
670     RichEditorModel::GetInstance()->SetOnShare(std::move(onShare));
671 }
672 
SetCustomKeyboard(const JSCallbackInfo & args)673 void JSRichEditor::SetCustomKeyboard(const JSCallbackInfo& args)
674 {
675     if (args.Length() > 0 && (args[0]->IsUndefined() || args[0]->IsNull())) {
676         RichEditorModel::GetInstance()->SetCustomKeyboard(nullptr);
677         return;
678     }
679     if (!args[0]->IsObject()) {
680         return;
681     }
682     bool supportAvoidance = false;
683     if (args.Length() == 2 && args[1]->IsObject()) {  //  2 here refers to the number of parameters
684         auto paramObject = JSRef<JSObject>::Cast(args[1]);
685         auto isSupportAvoidance = paramObject->GetProperty("supportAvoidance");
686         if (!isSupportAvoidance->IsNull() && isSupportAvoidance->IsBoolean()) {
687             supportAvoidance = isSupportAvoidance->ToBoolean();
688         }
689     }
690     std::function<void()> buildFunc;
691     if (JSTextField::ParseJsCustomKeyboardBuilder(args, 0, buildFunc)) {
692         RichEditorModel::GetInstance()->SetCustomKeyboard(std::move(buildFunc), supportAvoidance);
693     }
694 }
695 
CreateJsAboutToIMEInputObj(const NG::RichEditorInsertValue & insertValue)696 JSRef<JSVal> JSRichEditor::CreateJsAboutToIMEInputObj(const NG::RichEditorInsertValue& insertValue)
697 {
698     JSRef<JSObject> aboutToIMEInputObj = JSRef<JSObject>::New();
699     aboutToIMEInputObj->SetProperty<int32_t>("insertOffset", insertValue.GetInsertOffset());
700     aboutToIMEInputObj->SetProperty<std::u16string>("insertValue", insertValue.GetInsertValue());
701     aboutToIMEInputObj->SetProperty<std::u16string>("previewText", insertValue.GetPreviewText());
702     return JSRef<JSVal>::Cast(aboutToIMEInputObj);
703 }
704 
CreateJsOnIMEInputComplete(const NG::RichEditorAbstractSpanResult & textSpanResult)705 JSRef<JSVal> JSRichEditor::CreateJsOnIMEInputComplete(const NG::RichEditorAbstractSpanResult& textSpanResult)
706 {
707     JSRef<JSObject> onIMEInputCompleteObj = JSRef<JSObject>::New();
708     JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
709     JSRef<JSArray> spanRange = JSRef<JSArray>::New();
710     JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
711     JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
712     JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
713     spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textSpanResult.GetSpanRangeStart())));
714     spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(textSpanResult.GetSpanRangeEnd())));
715     offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textSpanResult.OffsetInSpan())));
716     offsetInSpan->SetValueAt(
717         1, JSRef<JSVal>::Make(ToJSValue(textSpanResult.OffsetInSpan() + textSpanResult.GetEraseLength())));
718     spanPositionObj->SetPropertyObject("spanRange", spanRange);
719     spanPositionObj->SetProperty<int32_t>("spanIndex", textSpanResult.GetSpanIndex());
720     decorationObj->SetProperty<int32_t>("type", static_cast<int32_t>(textSpanResult.GetTextDecoration()));
721     decorationObj->SetProperty<std::string>("color", textSpanResult.GetColor());
722     decorationObj->SetProperty<int32_t>("style", static_cast<int32_t>(textSpanResult.GetTextDecorationStyle()));
723     textStyleObj->SetProperty<std::string>("fontColor", textSpanResult.GetFontColor());
724     textStyleObj->SetProperty<std::string>("fontFeature", UnParseFontFeatureSetting(textSpanResult.GetFontFeatures()));
725     textStyleObj->SetProperty<double>("fontSize", textSpanResult.GetFontSize());
726     textStyleObj->SetProperty<double>("lineHeight", textSpanResult.GetTextStyle().lineHeight);
727     textStyleObj->SetProperty<bool>("halfLeading", textSpanResult.GetTextStyle().halfLeading);
728     textStyleObj->SetProperty<double>("letterSpacing", textSpanResult.GetTextStyle().letterSpacing);
729     textStyleObj->SetProperty<int32_t>("fontStyle", static_cast<int32_t>(textSpanResult.GetFontStyle()));
730     textStyleObj->SetProperty<int32_t>("fontWeight", textSpanResult.GetFontWeight());
731     textStyleObj->SetProperty<std::string>("fontFamily", textSpanResult.GetFontFamily());
732     textStyleObj->SetPropertyObject("decoration", decorationObj);
733     textStyleObj->SetPropertyObject("textShadow", CreateJsTextShadowObjectArray(textSpanResult.GetTextStyle()));
734     SetJsTextBackgroundStyle(textStyleObj, textSpanResult.GetTextStyle());
735     onIMEInputCompleteObj->SetPropertyObject("spanPosition", spanPositionObj);
736     onIMEInputCompleteObj->SetProperty<std::u16string>("value", textSpanResult.GetValue());
737     onIMEInputCompleteObj->SetProperty<std::u16string>("previewText", textSpanResult.GetPreviewText());
738     onIMEInputCompleteObj->SetPropertyObject("textStyle", textStyleObj);
739     onIMEInputCompleteObj->SetPropertyObject("offsetInSpan", offsetInSpan);
740     onIMEInputCompleteObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(textSpanResult.GetTextStyle()));
741     SetJSUrlStyle(textSpanResult.GetUrlAddress(), onIMEInputCompleteObj);
742     return JSRef<JSVal>::Cast(onIMEInputCompleteObj);
743 }
744 
CreateJsOnDidIMEInput(const TextRange & range)745 JSRef<JSVal> JSRichEditor::CreateJsOnDidIMEInput(const TextRange& range)
746 {
747     JSRef<JSObject> rangeObj = JSRef<JSObject>::New();
748     rangeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(range.start)));
749     rangeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(range.end)));
750     return JSRef<JSVal>::Cast(rangeObj);
751 }
752 
CreateJsAboutToDelet(const NG::RichEditorDeleteValue & deleteValue)753 JSRef<JSVal> JSRichEditor::CreateJsAboutToDelet(const NG::RichEditorDeleteValue& deleteValue)
754 {
755     JSRef<JSObject> AboutToDeletObj = JSRef<JSObject>::New();
756     AboutToDeletObj->SetProperty<int32_t>("offset", deleteValue.GetOffset());
757     AboutToDeletObj->SetProperty<int32_t>(
758         "direction", static_cast<int32_t>(deleteValue.GetRichEditorDeleteDirection()));
759     AboutToDeletObj->SetProperty<int32_t>("length", deleteValue.GetLength());
760     AboutToDeletObj->SetPropertyObject("richEditorDeleteSpans", CreateJSDeleteSpans(deleteValue));
761     return JSRef<JSVal>::Cast(AboutToDeletObj);
762 }
763 
CreateJSDeleteSpans(const NG::RichEditorDeleteValue & deleteValue)764 JSRef<JSArray> JSRichEditor::CreateJSDeleteSpans(const NG::RichEditorDeleteValue& deleteValue)
765 {
766     JSRef<JSArray> richEditorDeleteSpans = JSRef<JSArray>::New();
767     int32_t index = 0;
768     auto list = deleteValue.GetRichEditorDeleteSpans();
769     for (const auto& it : list) {
770         JSRef<JSObject> spanResultObj = JSRef<JSObject>::New();
771         JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
772         JSRef<JSArray> spanRange = JSRef<JSArray>::New();
773         JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
774         spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeStart())));
775         spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeEnd())));
776         offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan())));
777         offsetInSpan->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan() + it.GetEraseLength())));
778         spanPositionObj->SetPropertyObject("spanRange", spanRange);
779         spanPositionObj->SetProperty<int32_t>("spanIndex", it.GetSpanIndex());
780         spanResultObj->SetPropertyObject("spanPosition", spanPositionObj);
781         spanResultObj->SetPropertyObject("offsetInSpan", offsetInSpan);
782         SetJSDeleteSpan(spanResultObj, it);
783         richEditorDeleteSpans->SetValueAt(index++, spanResultObj);
784     }
785     return richEditorDeleteSpans;
786 }
787 
SetJSDeleteSpan(JSRef<JSObject> & spanResultObj,const NG::RichEditorAbstractSpanResult & it)788 void JSRichEditor::SetJSDeleteSpan(JSRef<JSObject>& spanResultObj, const NG::RichEditorAbstractSpanResult& it)
789 {
790     switch (it.GetType()) {
791         case NG::SpanResultType::TEXT: {
792             JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
793             CreateTextStyleObj(textStyleObj, it);
794             spanResultObj->SetProperty<std::u16string>("value", it.GetValue());
795             spanResultObj->SetProperty<std::u16string>("previewText", it.GetPreviewText());
796             spanResultObj->SetPropertyObject("textStyle", textStyleObj);
797             spanResultObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(it.GetTextStyle()));
798             SetJSUrlStyle(it.GetUrlAddress(), spanResultObj);
799             break;
800         }
801         case NG::SpanResultType::IMAGE: {
802             JSRef<JSObject> imageStyleObj = JSRef<JSObject>::New();
803             CreateImageStyleObj(imageStyleObj, spanResultObj, it);
804             JSRef<JSObject> layoutStyleObj = JSRef<JSObject>::New();
805             layoutStyleObj->SetProperty<std::string>("borderRadius", it.GetBorderRadius());
806             layoutStyleObj->SetProperty<std::string>("margin", it.GetMargin());
807             imageStyleObj->SetPropertyObject("layoutStyle", layoutStyleObj);
808             spanResultObj->SetPropertyObject("imageStyle", imageStyleObj);
809             break;
810         }
811         case NG::SpanResultType::SYMBOL: {
812             spanResultObj->SetProperty<std::string>("value", it.GetValueString());
813             spanResultObj->SetPropertyObject(
814                 "symbolSpanStyle", CreateJSSymbolSpanStyleResult(it.GetSymbolSpanStyle()));
815             spanResultObj->SetPropertyObject("valueResource", CreateJSValueResource(it.GetValueResource()));
816             break;
817         }
818         default:
819             break;
820     }
821 }
822 
SetChangeTextSpans(JSRef<JSArray> & jsArray,const std::vector<NG::RichEditorAbstractSpanResult> & spanList)823 void JSRichEditor::SetChangeTextSpans(
824     JSRef<JSArray>& jsArray, const std::vector<NG::RichEditorAbstractSpanResult>& spanList)
825 {
826     int32_t index = 0;
827     for (const auto& it : spanList) {
828         JSRef<JSObject> spanResultObj = JSRef<JSObject>::New();
829         JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
830         JSRef<JSArray> spanRange = JSRef<JSArray>::New();
831         JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
832         spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeStart())));
833         spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeEnd())));
834         offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan())));
835         offsetInSpan->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan() + it.GetEraseLength())));
836         spanPositionObj->SetPropertyObject("spanRange", spanRange);
837         spanPositionObj->SetProperty<int32_t>("spanIndex", it.GetSpanIndex());
838         spanResultObj->SetPropertyObject("spanPosition", spanPositionObj);
839         spanResultObj->SetPropertyObject("offsetInSpan", offsetInSpan);
840         switch (it.GetType()) {
841             case NG::SpanResultType::TEXT:
842                 SetTextChangeSpanResult(spanResultObj, it);
843                 break;
844             case NG::SpanResultType::IMAGE:
845                 SetImageChangeSpanResult(spanResultObj, it);
846                 break;
847             case NG::SpanResultType::SYMBOL:
848                 SetSymbolChangeSpanResult(spanResultObj, it);
849                 break;
850             default:
851                 break;
852         }
853         jsArray->SetValueAt(index++, spanResultObj);
854     }
855 }
856 
SetTextChangeSpanResult(JSRef<JSObject> & resultObj,const NG::RichEditorAbstractSpanResult & spanResult)857 void JSRichEditor::SetTextChangeSpanResult(JSRef<JSObject>& resultObj,
858     const NG::RichEditorAbstractSpanResult& spanResult)
859 {
860     JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
861     CreateTextStyleObj(textStyleObj, spanResult);
862     resultObj->SetProperty<std::u16string>("value", spanResult.GetValue());
863     resultObj->SetProperty<std::u16string>("previewText", spanResult.GetPreviewText());
864     resultObj->SetPropertyObject("textStyle", textStyleObj);
865     resultObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(spanResult.GetTextStyle()));
866     SetJSUrlStyle(spanResult.GetUrlAddress(), resultObj);
867 }
868 
SetSymbolChangeSpanResult(JSRef<JSObject> & resultObj,const NG::RichEditorAbstractSpanResult & spanResult)869 void JSRichEditor::SetSymbolChangeSpanResult(JSRef<JSObject>& resultObj,
870     const NG::RichEditorAbstractSpanResult& spanResult)
871 {
872     resultObj->SetProperty<std::string>("value", spanResult.GetValueString());
873     resultObj->SetPropertyObject("symbolSpanStyle", CreateJSSymbolSpanStyleResult(spanResult.GetSymbolSpanStyle()));
874     resultObj->SetPropertyObject("valueResource", CreateJSValueResource(spanResult.GetValueResource()));
875     resultObj->SetPropertyObject("paragraphStyle", CreateJSParagraphStyle(spanResult.GetTextStyle()));
876 }
877 
SetImageChangeSpanResult(JSRef<JSObject> & resultObj,const NG::RichEditorAbstractSpanResult & spanResult)878 void JSRichEditor::SetImageChangeSpanResult(JSRef<JSObject>& resultObj,
879     const NG::RichEditorAbstractSpanResult& spanResult)
880 {
881     auto valuePixelMap = spanResult.GetValuePixelMap();
882     auto returnWidth = spanResult.GetSizeWidth();
883     auto returnHeight = spanResult.GetSizeHeight();
884     if (valuePixelMap) {
885 #ifdef PIXEL_MAP_SUPPORTED
886         if (NearZero(returnWidth) || NearZero(returnHeight)) {
887             returnWidth = valuePixelMap->GetWidth();
888             returnHeight = valuePixelMap->GetHeight();
889         }
890         auto jsPixmap = ConvertPixmap(valuePixelMap);
891         if (!jsPixmap->IsUndefined()) {
892             resultObj->SetPropertyObject("valuePixelMap", jsPixmap);
893         }
894 #endif
895     } else {
896         resultObj->SetProperty<std::string>("valueResourceStr", spanResult.GetValueResourceStr());
897     }
898     ImageStyleResult imageStyleResult;
899     imageStyleResult.size[0] = static_cast<double>(returnWidth);
900     imageStyleResult.size[1] = static_cast<double>(returnHeight);
901     imageStyleResult.verticalAlign = static_cast<int32_t>(spanResult.GetVerticalAlign());
902     imageStyleResult.objectFit = static_cast<int32_t>(spanResult.GetObjectFit());
903     imageStyleResult.borderRadius = spanResult.GetBorderRadius();
904     imageStyleResult.margin = spanResult.GetMargin();
905     resultObj->SetPropertyObject("imageStyle", CreateJSImageStyleResult(imageStyleResult));
906 }
907 
CreateJsOnWillChange(const NG::RichEditorChangeValue & changeValue)908 JSRef<JSVal> JSRichEditor::CreateJsOnWillChange(const NG::RichEditorChangeValue& changeValue)
909 {
910     JSRef<JSObject> OnWillChangeObj = JSRef<JSObject>::New();
911 
912     const auto& rangeBefore = changeValue.GetRangeBefore();
913     JSRef<JSObject> rangeBeforeObj = JSRef<JSObject>::New();
914     rangeBeforeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeBefore.start)));
915     rangeBeforeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeBefore.end)));
916     OnWillChangeObj->SetPropertyObject("rangeBefore", rangeBeforeObj);
917 
918     JSRef<JSArray> replacedSpans = JSRef<JSArray>::New();
919     SetChangeTextSpans(replacedSpans, changeValue.GetRichEditorReplacedSpans());
920     OnWillChangeObj->SetPropertyObject("replacedSpans", replacedSpans);
921 
922     JSRef<JSArray> replacedImageSpans = JSRef<JSArray>::New();
923     SetChangeTextSpans(replacedImageSpans, changeValue.GetRichEditorReplacedImageSpans());
924     OnWillChangeObj->SetPropertyObject("replacedImageSpans", replacedImageSpans);
925 
926     JSRef<JSArray> replacedSymbolSpans = JSRef<JSArray>::New();
927     SetChangeTextSpans(replacedSymbolSpans, changeValue.GetRichEditorReplacedSymbolSpans());
928     OnWillChangeObj->SetPropertyObject("replacedSymbolSpans", replacedSymbolSpans);
929 
930     return JSRef<JSVal>::Cast(OnWillChangeObj);
931 }
932 
CreateJsOnDidChange(const std::vector<NG::RichEditorAbstractSpanResult> & spanList)933 JSRef<JSVal> JSRichEditor::CreateJsOnDidChange(const std::vector<NG::RichEditorAbstractSpanResult>& spanList)
934 {
935     JSRef<JSArray> richEditorReplacedSpans = JSRef<JSArray>::New();
936     SetChangeTextSpans(richEditorReplacedSpans, spanList);
937     return JSRef<JSVal>::Cast(richEditorReplacedSpans);
938 }
939 
CreateTextStyleObj(JSRef<JSObject> & textStyleObj,const NG::RichEditorAbstractSpanResult & spanResult)940 void JSRichEditor::CreateTextStyleObj(JSRef<JSObject>& textStyleObj, const NG::RichEditorAbstractSpanResult& spanResult)
941 {
942     JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
943     decorationObj->SetProperty<int32_t>("type", (int32_t)(spanResult.GetTextDecoration()));
944     decorationObj->SetProperty<std::string>("color", spanResult.GetColor());
945     decorationObj->SetProperty<int32_t>("style", (int32_t)(spanResult.GetTextDecorationStyle()));
946     textStyleObj->SetProperty<std::string>("fontColor", spanResult.GetFontColor());
947     textStyleObj->SetProperty<std::string>("fontFeature", UnParseFontFeatureSetting(spanResult.GetFontFeatures()));
948     textStyleObj->SetProperty<double>("fontSize", spanResult.GetFontSize());
949     textStyleObj->SetProperty<double>("lineHeight", spanResult.GetTextStyle().lineHeight);
950     textStyleObj->SetProperty<bool>("halfLeading", spanResult.GetTextStyle().halfLeading);
951     textStyleObj->SetProperty<double>("letterSpacing", spanResult.GetTextStyle().letterSpacing);
952     textStyleObj->SetProperty<int32_t>("fontStyle", static_cast<int32_t>(spanResult.GetFontStyle()));
953     textStyleObj->SetProperty<int32_t>("fontWeight", spanResult.GetFontWeight());
954     textStyleObj->SetProperty<std::string>("fontFamily", spanResult.GetFontFamily());
955     textStyleObj->SetPropertyObject("decoration", decorationObj);
956     textStyleObj->SetPropertyObject("textShadow", CreateJsTextShadowObjectArray(spanResult.GetTextStyle()));
957     SetJsTextBackgroundStyle(textStyleObj, spanResult.GetTextStyle());
958 }
959 
CreateImageStyleObj(JSRef<JSObject> & imageStyleObj,JSRef<JSObject> & spanResultObj,const NG::RichEditorAbstractSpanResult & spanResult)960 void JSRichEditor::CreateImageStyleObj(
961     JSRef<JSObject>& imageStyleObj, JSRef<JSObject>& spanResultObj, const NG::RichEditorAbstractSpanResult& spanResult)
962 {
963     JSRef<JSArray> imageSize = JSRef<JSArray>::New();
964     imageSize->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(spanResult.GetSizeWidth())));
965     imageSize->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(spanResult.GetSizeHeight())));
966     imageStyleObj->SetPropertyObject("size", imageSize);
967     imageStyleObj->SetProperty<int32_t>("verticalAlign", static_cast<int32_t>(spanResult.GetVerticalAlign()));
968     imageStyleObj->SetProperty<int32_t>("objectFit", static_cast<int32_t>(spanResult.GetObjectFit()));
969     if (spanResult.GetValuePixelMap()) {
970 #ifdef PIXEL_MAP_SUPPORTED
971         auto jsPixmap = ConvertPixmap(spanResult.GetValuePixelMap());
972         if (!jsPixmap->IsUndefined()) {
973             spanResultObj->SetPropertyObject("value", jsPixmap);
974         }
975 #endif
976     } else {
977         spanResultObj->SetProperty<std::string>("valueResourceStr", spanResult.GetValueResourceStr());
978     }
979 }
980 
JsClip(const JSCallbackInfo & info)981 void JSRichEditor::JsClip(const JSCallbackInfo& info)
982 {
983     if (info[0]->IsUndefined()) {
984         ViewAbstractModel::GetInstance()->SetClipEdge(true);
985         return;
986     }
987     if (info[0]->IsObject()) {
988         JSShapeAbstract* clipShape = JSRef<JSObject>::Cast(info[0])->Unwrap<JSShapeAbstract>();
989         if (clipShape == nullptr) {
990             return;
991         }
992         ViewAbstractModel::GetInstance()->SetClipShape(clipShape->GetBasicShape());
993     } else if (info[0]->IsBoolean()) {
994         ViewAbstractModel::GetInstance()->SetClipEdge(info[0]->ToBoolean());
995     }
996 }
997 
JsFocusable(const JSCallbackInfo & info)998 void JSRichEditor::JsFocusable(const JSCallbackInfo& info)
999 {
1000     if (info.Length() != 1 || !info[0]->IsBoolean()) {
1001         return;
1002     }
1003     JSInteractableView::SetFocusable(info[0]->ToBoolean());
1004     JSInteractableView::SetFocusNode(false);
1005 }
1006 
SetCopyOptions(const JSCallbackInfo & info)1007 void JSRichEditor::SetCopyOptions(const JSCallbackInfo& info)
1008 {
1009     if (info.Length() == 0) {
1010         return;
1011     }
1012     auto copyOptions = CopyOptions::Distributed;
1013     auto tmpInfo = info[0];
1014     if (tmpInfo->IsNumber()) {
1015         auto emunNumber = tmpInfo->ToNumber<int>();
1016         copyOptions = static_cast<CopyOptions>(emunNumber);
1017     }
1018     RichEditorModel::GetInstance()->SetCopyOption(copyOptions);
1019 }
1020 
BindSelectionMenu(const JSCallbackInfo & info)1021 void JSRichEditor::BindSelectionMenu(const JSCallbackInfo& info)
1022 {
1023     NG::TextSpanType editorType = NG::TextSpanType::NONE;
1024     if (info.Length() >= 1 && info[0]->IsUndefined()) {
1025         editorType = NG::TextSpanType::TEXT;
1026     }
1027     if (info.Length() >= 1 && info[0]->IsNumber()) {
1028         auto spanType = info[0]->ToNumber<int32_t>();
1029         editorType = static_cast<NG::TextSpanType>(spanType);
1030     }
1031 
1032     // Builder
1033     if (info.Length() < 2 || !info[1]->IsObject()) {
1034         return;
1035     }
1036 
1037     JSRef<JSObject> menuObj = JSRef<JSObject>::Cast(info[1]);
1038     auto builder = menuObj->GetProperty("builder");
1039     if (!builder->IsFunction()) {
1040         return;
1041     }
1042     auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
1043     CHECK_NULL_VOID(builderFunc);
1044 
1045     // responseType
1046     NG::TextResponseType responseType = NG::TextResponseType::LONG_PRESS;
1047     if (info.Length() >= 3 && info[2]->IsNumber()) {
1048         auto response = info[2]->ToNumber<int32_t>();
1049         responseType = static_cast<NG::TextResponseType>(response);
1050     }
1051     std::function<void()> buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc)]() {
1052         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1053         ACE_SCORING_EVENT("BindSelectionMenu");
1054         func->Execute();
1055     };
1056     NG::SelectMenuParam menuParam;
1057     const int32_t requiredParamCount = 3;
1058     if (info.Length() > requiredParamCount && info[requiredParamCount]->IsObject()) {
1059         JSRef<JSObject> menuOptions = info[requiredParamCount];
1060         JSText::ParseMenuParam(info, menuOptions, menuParam);
1061         auto menuType = menuOptions->GetProperty("menuType");
1062         bool isPreviewMenu = menuType->IsNumber() && menuType->ToNumber<int32_t>() == 1;
1063         bool bindImagePreviewMenu = isPreviewMenu && responseType == NG::TextResponseType::LONG_PRESS;
1064         if (bindImagePreviewMenu) {
1065             RichEditorModel::GetInstance()->SetPreviewMenuParam(editorType, buildFunc, menuParam);
1066             return;
1067         }
1068     }
1069     RichEditorModel::GetInstance()->BindSelectionMenu(editorType, responseType, buildFunc, menuParam);
1070 }
1071 
CreateJSTextCommonEvent(NG::TextCommonEvent & event)1072 JSRef<JSVal> JSRichEditor::CreateJSTextCommonEvent(NG::TextCommonEvent& event)
1073 {
1074     JSRef<JSObjTemplate> objectTemplate = JSRef<JSObjTemplate>::New();
1075     objectTemplate->SetInternalFieldCount(1);
1076     JSRef<JSObject> object = objectTemplate->NewInstance();
1077     object->SetPropertyObject("preventDefault", JSRef<JSFunc>::New<FunctionCallback>(JsPreventDefault));
1078     object->Wrap<NG::TextCommonEvent>(&event);
1079     return JSRef<JSVal>::Cast(object);
1080 }
1081 
SetOnPaste(const JSCallbackInfo & info)1082 void JSRichEditor::SetOnPaste(const JSCallbackInfo& info)
1083 {
1084     CHECK_NULL_VOID(info[0]->IsFunction());
1085     auto jsTextFunc = AceType::MakeRefPtr<JsCitedEventFunction<NG::TextCommonEvent, 1>>(
1086         JSRef<JSFunc>::Cast(info[0]), CreateJSTextCommonEvent);
1087     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1088     auto onPaste = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](
1089                        NG::TextCommonEvent& info) {
1090         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1091         ACE_SCORING_EVENT("onPaste");
1092         PipelineContext::SetCallBackNode(node);
1093         func->Execute(info);
1094         UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", "onPaste");
1095     };
1096     RichEditorModel::GetInstance()->SetOnPaste(std::move(onPaste));
1097 }
1098 
JsEnableDataDetector(const JSCallbackInfo & info)1099 void JSRichEditor::JsEnableDataDetector(const JSCallbackInfo& info)
1100 {
1101     if (info.Length() < 1) {
1102         return;
1103     }
1104     auto tmpInfo = info[0];
1105     if (!tmpInfo->IsBoolean()) {
1106         RichEditorModel::GetInstance()->SetTextDetectEnable(false);
1107         return;
1108     }
1109     auto enable = tmpInfo->ToBoolean();
1110     RichEditorModel::GetInstance()->SetTextDetectEnable(enable);
1111 }
1112 
JsEnablePreviewText(const JSCallbackInfo & info)1113 void JSRichEditor::JsEnablePreviewText(const JSCallbackInfo& info)
1114 {
1115     if (info.Length() < 1) {
1116         return;
1117     }
1118     auto tmpInfo = info[0];
1119     if (!tmpInfo->IsBoolean()) {
1120         RichEditorModel::GetInstance()->SetSupportPreviewText(true);
1121         return;
1122     }
1123     auto enable = tmpInfo->ToBoolean();
1124     RichEditorModel::GetInstance()->SetSupportPreviewText(enable);
1125 }
1126 
SetPlaceholder(const JSCallbackInfo & info)1127 void JSRichEditor::SetPlaceholder(const JSCallbackInfo& info)
1128 {
1129     if (info.Length() < 1) {
1130         return;
1131     }
1132     auto pipelineContext = PipelineBase::GetCurrentContext();
1133     if (!pipelineContext) {
1134         TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
1135         return;
1136     }
1137     std::u16string placeholderValue;
1138     PlaceholderOptions options;
1139     JSContainerBase::ParseJsString(info[0], placeholderValue);
1140     options.value = placeholderValue;
1141     Font font;
1142     if (info.Length() > 1 && info[1]->IsObject()) {
1143         JSRef<JSObject> object = JSRef<JSObject>::Cast(info[1]);
1144         auto fontObject = object->GetProperty("font");
1145         if (fontObject->IsObject()) {
1146             ParseJsFont(fontObject, font);
1147         }
1148         JSRef<JSVal> colorVal = object->GetProperty("fontColor");
1149         Color fontColor;
1150         if (!colorVal->IsNull() && JSContainerBase::ParseJsColor(colorVal, fontColor)) {
1151             options.fontColor = fontColor;
1152         }
1153     }
1154     auto textTheme = pipelineContext->GetTheme<TextTheme>();
1155     TextStyle textStyle = textTheme ? textTheme->GetTextStyle() : TextStyle();
1156     options.fontSize = font.fontSize.value_or(textStyle.GetFontSize());
1157     options.fontFamilies = !font.fontFamilies.empty() ? font.fontFamilies : textStyle.GetFontFamilies();
1158     options.fontWeight = font.fontWeight.value_or(textStyle.GetFontWeight());
1159     options.fontStyle = font.fontStyle.value_or(textStyle.GetFontStyle());
1160     if (!options.fontColor.has_value()) {
1161         Color fontColor;
1162         auto richEditorTheme = pipelineContext->GetTheme<NG::RichEditorTheme>();
1163         options.fontColor = richEditorTheme ? richEditorTheme->GetPlaceholderColor() : fontColor;
1164     }
1165     RichEditorModel::GetInstance()->SetPlaceholder(options);
1166 }
1167 
ParseJsFont(const JSRef<JSObject> & fontObject,Font & font)1168 void JSRichEditor::ParseJsFont(const JSRef<JSObject>& fontObject, Font& font)
1169 {
1170     if (fontObject->IsUndefined()) {
1171         return;
1172     }
1173     JSRef<JSVal> fontSize = fontObject->GetProperty("size");
1174     CalcDimension size;
1175     if (!fontSize->IsNull() && JSContainerBase::ParseJsDimensionFpNG(fontSize, size) && !size.IsNegative() &&
1176         size.Unit() != DimensionUnit::PERCENT) {
1177         font.fontSize = size;
1178     } else if (size.IsNegative() || size.Unit() == DimensionUnit::PERCENT) {
1179         auto theme = JSContainerBase::GetTheme<TextTheme>();
1180         CHECK_NULL_VOID(theme);
1181         size = theme->GetTextStyle().GetFontSize();
1182         font.fontSize = size;
1183     }
1184 
1185     JSRef<JSVal> fontStyle = fontObject->GetProperty("style");
1186     if (!fontStyle->IsNull() && fontStyle->IsNumber()) {
1187         font.fontStyle = static_cast<FontStyle>(fontStyle->ToNumber<int32_t>());
1188     }
1189 
1190     JSRef<JSVal> fontWeight = fontObject->GetProperty("weight");
1191     if (!fontWeight->IsNull()) {
1192         std::string weight;
1193         if (fontWeight->IsNumber()) {
1194             weight = std::to_string(fontWeight->ToNumber<int32_t>());
1195         } else {
1196             JSContainerBase::ParseJsString(fontWeight, weight);
1197         }
1198         font.fontWeight = ConvertStrToFontWeight(weight);
1199     }
1200 
1201     JSRef<JSVal> fontFamily = fontObject->GetProperty("family");
1202     if (!fontFamily->IsNull()) {
1203         std::vector<std::string> fontFamilies;
1204         if (JSContainerBase::ParseJsFontFamilies(fontFamily, fontFamilies)) {
1205             font.fontFamilies = fontFamilies;
1206         }
1207     }
1208 }
1209 
JsDataDetectorConfig(const JSCallbackInfo & info)1210 void JSRichEditor::JsDataDetectorConfig(const JSCallbackInfo& info)
1211 {
1212     if (info.Length() < 1) {
1213         return;
1214     }
1215     if (!info[0]->IsObject()) {
1216         return;
1217     }
1218 
1219     TextDetectConfig textDetectConfig;
1220     if (!ParseDataDetectorConfig(info, textDetectConfig)) {
1221         return;
1222     }
1223     RichEditorModel::GetInstance()->SetTextDetectConfig(textDetectConfig);
1224 }
1225 
SetCaretColor(const JSCallbackInfo & info)1226 void JSRichEditor::SetCaretColor(const JSCallbackInfo& info)
1227 {
1228     if (info.Length() < 1) {
1229         TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "Info length error");
1230         return;
1231     }
1232     Color color;
1233     JSRef<JSVal> colorVal = info[0];
1234     if (!ParseJsColor(colorVal, color)) {
1235         auto pipeline = PipelineBase::GetCurrentContext();
1236         CHECK_NULL_VOID(pipeline);
1237         auto theme = pipeline->GetThemeManager()->GetTheme<NG::RichEditorTheme>();
1238         CHECK_NULL_VOID(theme);
1239         color = theme->GetCaretColor();
1240     }
1241     RichEditorModel::GetInstance()->SetCaretColor(color);
1242 }
1243 
SetSelectedBackgroundColor(const JSCallbackInfo & info)1244 void JSRichEditor::SetSelectedBackgroundColor(const JSCallbackInfo& info)
1245 {
1246     if (info.Length() < 1) {
1247         TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "Info length error");
1248         return;
1249     }
1250     Color selectedColor;
1251     JSRef<JSVal> colorVal = info[0];
1252     if (!ParseJsColor(colorVal, selectedColor)) {
1253         auto pipeline = PipelineBase::GetCurrentContext();
1254         CHECK_NULL_VOID(pipeline);
1255         auto theme = pipeline->GetThemeManager()->GetTheme<NG::RichEditorTheme>();
1256         CHECK_NULL_VOID(theme);
1257         selectedColor = theme->GetSelectedBackgroundColor();
1258     }
1259     RichEditorModel::GetInstance()->SetSelectedBackgroundColor(selectedColor);
1260 }
1261 
SetEnterKeyType(const JSCallbackInfo & info)1262 void JSRichEditor::SetEnterKeyType(const JSCallbackInfo& info)
1263 {
1264     if (info.Length() < 1) {
1265         return;
1266     }
1267     auto action = info[0];
1268     if (action->IsUndefined()) {
1269         RichEditorModel::GetInstance()->SetEnterKeyType(TextInputAction::UNSPECIFIED);
1270         return;
1271     }
1272     if (!action->IsNumber()) {
1273         return;
1274     }
1275     TextInputAction textInputAction = CastToTextInputAction(action->ToNumber<int32_t>());
1276     RichEditorModel::GetInstance()->SetEnterKeyType(textInputAction);
1277 }
1278 
JsKeepEditableState(panda::JsiRuntimeCallInfo * info)1279 Local<JSValueRef> JSRichEditor::JsKeepEditableState(panda::JsiRuntimeCallInfo* info)
1280 {
1281     Local<JSValueRef> thisObj = info->GetThisRef();
1282     auto eventInfo =
1283         static_cast<NG::TextFieldCommonEvent*>(panda::Local<panda::ObjectRef>(thisObj)->GetNativePointerField(
1284             info->GetVM(), 0));
1285     if (eventInfo) {
1286         eventInfo->SetKeepEditable(true);
1287     }
1288     return JSValueRef::Undefined(info->GetVM());
1289 }
1290 
CreateJsRichEditorCommonEvent(const JSCallbackInfo & info)1291 void JSRichEditor::CreateJsRichEditorCommonEvent(const JSCallbackInfo& info)
1292 {
1293     if (!info[0]->IsFunction()) {
1294         return;
1295     }
1296     auto jsTextFunc =
1297         AceType::MakeRefPtr<JsCommonEventFunction<NG::TextFieldCommonEvent, 2>>(JSRef<JSFunc>::Cast(info[0]));
1298     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
1299     auto callback = [execCtx = info.GetExecutionContext(), func = std::move(jsTextFunc), node = targetNode](
1300                         int32_t key, NG::TextFieldCommonEvent& event) {
1301         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1302         ACE_SCORING_EVENT("onSubmit");
1303         PipelineContext::SetCallBackNode(node);
1304         JSRef<JSObjTemplate> objectTemplate = JSRef<JSObjTemplate>::New();
1305         objectTemplate->SetInternalFieldCount(2);
1306         JSRef<JSObject> object = objectTemplate->NewInstance();
1307         object->SetProperty<std::u16string>("text", event.GetText());
1308         object->SetPropertyObject("keepEditableState", JSRef<JSFunc>::New<FunctionCallback>(JsKeepEditableState));
1309         object->Wrap<NG::TextFieldCommonEvent>(&event);
1310         JSRef<JSVal> keyEvent = JSRef<JSVal>::Make(ToJSValue(key));
1311         JSRef<JSVal> dataObject = JSRef<JSVal>::Cast(object);
1312         JSRef<JSVal> param[2] = { keyEvent, dataObject };
1313         func->Execute(param);
1314     };
1315     RichEditorModel::GetInstance()->SetOnSubmit(std::move(callback));
1316 }
1317 
SetOnSubmit(const JSCallbackInfo & info)1318 void JSRichEditor::SetOnSubmit(const JSCallbackInfo& info)
1319 {
1320     CHECK_NULL_VOID(info[0]->IsFunction());
1321     CreateJsRichEditorCommonEvent(info);
1322 }
1323 
SetEnableKeyboardOnFocus(const JSCallbackInfo & info)1324 void JSRichEditor::SetEnableKeyboardOnFocus(const JSCallbackInfo& info)
1325 {
1326     CHECK_NULL_VOID(info.Length() > 0);
1327     auto jsValue = info[0];
1328     if (jsValue->IsUndefined() || !jsValue->IsBoolean()) {
1329         RichEditorModel::GetInstance()->SetRequestKeyboardOnFocus(true);
1330         return;
1331     }
1332     RichEditorModel::GetInstance()->SetRequestKeyboardOnFocus(jsValue->ToBoolean());
1333 }
1334 
SetEnableHapticFeedback(const JSCallbackInfo & info)1335 void JSRichEditor::SetEnableHapticFeedback(const JSCallbackInfo& info)
1336 {
1337     CHECK_NULL_VOID(info.Length() > 0);
1338     auto jsValue = info[0];
1339     if (jsValue->IsUndefined() || !jsValue->IsBoolean()) {
1340         RichEditorModel::GetInstance()->SetEnableHapticFeedback(true);
1341         return;
1342     }
1343     RichEditorModel::GetInstance()->SetEnableHapticFeedback(jsValue->ToBoolean());
1344 }
1345 
SetBarState(const JSCallbackInfo & info)1346 void JSRichEditor::SetBarState(const JSCallbackInfo& info)
1347 {
1348     CHECK_NULL_VOID(info.Length() > 0);
1349     auto jsValue = info[0];
1350     CHECK_NULL_VOID(!jsValue->IsUndefined() && jsValue->IsNumber());
1351     int32_t barState = jsValue->ToNumber<int32_t>();
1352     CHECK_NULL_VOID(barState >= static_cast<int32_t>(DisplayMode::OFF));
1353     CHECK_NULL_VOID(barState <= static_cast<int32_t>(DisplayMode::ON));
1354     RichEditorModel::GetInstance()->SetBarState(static_cast<DisplayMode>(barState));
1355 }
1356 
SetMaxLength(const JSCallbackInfo & info)1357 void JSRichEditor::SetMaxLength(const JSCallbackInfo& info)
1358 {
1359     if (info.Length() < 1) {
1360         return;
1361     }
1362     auto jsValue = info[0];
1363     if (jsValue->IsUndefined()) {
1364         RichEditorModel::GetInstance()->ResetMaxLength();
1365         return;
1366     } else if (!jsValue->IsNumber()) {
1367         RichEditorModel::GetInstance()->ResetMaxLength();
1368         return;
1369     }
1370     int32_t maxLength = jsValue->ToNumber<int32_t>();
1371     if (std::isinf(jsValue->ToNumber<float>())) {
1372         maxLength = INT32_MAX;
1373     }
1374     if (GreatOrEqual(maxLength, 0)) {
1375         RichEditorModel::GetInstance()->SetMaxLength(maxLength);
1376     } else {
1377         RichEditorModel::GetInstance()->ResetMaxLength();
1378     }
1379 }
1380 
SetMaxLines(const JSCallbackInfo & info)1381 void JSRichEditor::SetMaxLines(const JSCallbackInfo& info)
1382 {
1383     auto normalMaxLines = Infinity<uint32_t>();
1384     auto isValid = info.Length() >= 1 && info[0]->IsNumber() && info[0]->ToNumber<int32_t>() > 0;
1385     if (isValid) {
1386         normalMaxLines = info[0]->ToNumber<uint32_t>();
1387     }
1388     RichEditorModel::GetInstance()->SetMaxLines(normalMaxLines);
1389 }
1390 
SetStopBackPress(const JSCallbackInfo & info)1391 void JSRichEditor::SetStopBackPress(const JSCallbackInfo& info)
1392 {
1393     bool isStopBackPress = true;
1394     if (info.Length() > 0 && info[0]->IsBoolean()) {
1395         isStopBackPress = info[0]->ToBoolean();
1396     }
1397     RichEditorModel::GetInstance()->SetStopBackPress(isStopBackPress);
1398 }
1399 
SetKeyboardAppearance(const JSCallbackInfo & info)1400 void JSRichEditor::SetKeyboardAppearance(const JSCallbackInfo& info)
1401 {
1402     if (info.Length() != 1 || !info[0]->IsNumber()) {
1403         return;
1404     }
1405     auto keyboardAppearance = info[0]->ToNumber<int32_t>();
1406     if (keyboardAppearance < static_cast<int32_t>(KeyboardAppearance::NONE_IMMERSIVE) ||
1407         keyboardAppearance > static_cast<int32_t>(KeyboardAppearance::DARK_IMMERSIVE)) {
1408         RichEditorModel::GetInstance()->SetKeyboardAppearance(KeyboardAppearance::NONE_IMMERSIVE);
1409         return;
1410     }
1411     RichEditorModel::GetInstance()->
1412         SetKeyboardAppearance(static_cast<KeyboardAppearance>(keyboardAppearance));
1413 }
1414 
JSBind(BindingTarget globalObj)1415 void JSRichEditor::JSBind(BindingTarget globalObj)
1416 {
1417     JSClass<JSRichEditor>::Declare("RichEditor");
1418     JSClass<JSRichEditor>::StaticMethod("create", &JSRichEditor::Create);
1419     JSClass<JSRichEditor>::StaticMethod("onReady", &JSRichEditor::SetOnReady);
1420     JSClass<JSRichEditor>::StaticMethod("onSelect", &JSRichEditor::SetOnSelect);
1421     JSClass<JSRichEditor>::StaticMethod("onSelectionChange", &JSRichEditor::SetOnSelectionChange);
1422     JSClass<JSRichEditor>::StaticMethod("aboutToIMEInput", &JSRichEditor::SetAboutToIMEInput);
1423     JSClass<JSRichEditor>::StaticMethod("onIMEInputComplete", &JSRichEditor::SetOnIMEInputComplete);
1424     JSClass<JSRichEditor>::StaticMethod("onDidIMEInput", &JSRichEditor::SetOnDidIMEInput);
1425     JSClass<JSRichEditor>::StaticMethod("aboutToDelete", &JSRichEditor::SetAboutToDelete);
1426     JSClass<JSRichEditor>::StaticMethod("onDeleteComplete", &JSRichEditor::SetOnDeleteComplete);
1427     JSClass<JSRichEditor>::StaticMethod("customKeyboard", &JSRichEditor::SetCustomKeyboard);
1428     JSClass<JSRichEditor>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
1429     JSClass<JSRichEditor>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
1430     JSClass<JSRichEditor>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
1431     JSClass<JSRichEditor>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
1432     JSClass<JSRichEditor>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
1433     JSClass<JSRichEditor>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
1434     JSClass<JSRichEditor>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
1435     JSClass<JSRichEditor>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
1436     JSClass<JSRichEditor>::StaticMethod("clip", &JSRichEditor::JsClip);
1437     JSClass<JSRichEditor>::StaticMethod("focusable", &JSRichEditor::JsFocusable);
1438     JSClass<JSRichEditor>::StaticMethod("copyOptions", &JSRichEditor::SetCopyOptions);
1439     JSClass<JSRichEditor>::StaticMethod("bindSelectionMenu", &JSRichEditor::BindSelectionMenu);
1440     JSClass<JSRichEditor>::StaticMethod("onPaste", &JSRichEditor::SetOnPaste);
1441     JSClass<JSRichEditor>::StaticMethod("enableDataDetector", &JSRichEditor::JsEnableDataDetector);
1442     JSClass<JSRichEditor>::StaticMethod("enablePreviewText", &JSRichEditor::JsEnablePreviewText);
1443     JSClass<JSRichEditor>::StaticMethod("dataDetectorConfig", &JSRichEditor::JsDataDetectorConfig);
1444     JSClass<JSRichEditor>::StaticMethod("placeholder", &JSRichEditor::SetPlaceholder);
1445     JSClass<JSRichEditor>::StaticMethod("caretColor", &JSRichEditor::SetCaretColor);
1446     JSClass<JSRichEditor>::StaticMethod("selectedBackgroundColor", &JSRichEditor::SetSelectedBackgroundColor);
1447     JSClass<JSRichEditor>::StaticMethod("onEditingChange", &JSRichEditor::SetOnEditingChange);
1448     JSClass<JSRichEditor>::StaticMethod("enterKeyType", &JSRichEditor::SetEnterKeyType);
1449     JSClass<JSRichEditor>::StaticMethod("onSubmit", &JSRichEditor::SetOnSubmit);
1450     JSClass<JSRichEditor>::StaticMethod("onWillChange", &JSRichEditor::SetOnWillChange);
1451     JSClass<JSRichEditor>::StaticMethod("onDidChange", &JSRichEditor::SetOnDidChange);
1452     JSClass<JSRichEditor>::StaticMethod("onCut", &JSRichEditor::SetOnCut);
1453     JSClass<JSRichEditor>::StaticMethod("onCopy", &JSRichEditor::SetOnCopy);
1454     JSClass<JSRichEditor>::StaticMethod("onShare", &JSRichEditor::SetOnShare);
1455     JSClass<JSRichEditor>::StaticMethod("editMenuOptions", &JSRichEditor::EditMenuOptions);
1456     JSClass<JSRichEditor>::StaticMethod("enableKeyboardOnFocus", &JSRichEditor::SetEnableKeyboardOnFocus);
1457     JSClass<JSRichEditor>::StaticMethod("enableHapticFeedback", &JSRichEditor::SetEnableHapticFeedback);
1458     JSClass<JSRichEditor>::StaticMethod("barState", &JSRichEditor::SetBarState);
1459     JSClass<JSRichEditor>::StaticMethod("maxLength", &JSRichEditor::SetMaxLength);
1460     JSClass<JSRichEditor>::StaticMethod("maxLines", &JSRichEditor::SetMaxLines);
1461     JSClass<JSRichEditor>::StaticMethod("stopBackPress", &JSRichEditor::SetStopBackPress);
1462     JSClass<JSRichEditor>::StaticMethod("keyboardAppearance", &JSRichEditor::SetKeyboardAppearance);
1463     JSClass<JSRichEditor>::InheritAndBind<JSViewAbstract>(globalObj);
1464 }
1465 
ParseJsImageSpanAttribute(JSRef<JSObject> imageAttribute)1466 ImageSpanAttribute JSRichEditorController::ParseJsImageSpanAttribute(JSRef<JSObject> imageAttribute)
1467 {
1468     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1469     ImageSpanAttribute imageStyle;
1470     auto sizeObj = imageAttribute->GetProperty("size");
1471     if (sizeObj->IsArray()) {
1472         ImageSpanSize imageSize;
1473         JSRef<JSArray> size = JSRef<JSArray>::Cast(sizeObj);
1474         JSRef<JSVal> width = size->GetValueAt(0);
1475         CalcDimension imageSpanWidth;
1476         if (!width->IsNull() && JSContainerBase::ParseJsDimensionVp(width, imageSpanWidth)) {
1477             imageSize.width = imageSpanWidth;
1478             updateSpanStyle_.updateImageWidth = imageSpanWidth;
1479         }
1480         JSRef<JSVal> height = size->GetValueAt(1);
1481         CalcDimension imageSpanHeight;
1482         if (!height->IsNull() && JSContainerBase::ParseJsDimensionVp(height, imageSpanHeight)) {
1483             imageSize.height = imageSpanHeight;
1484             updateSpanStyle_.updateImageHeight = imageSpanHeight;
1485         }
1486         imageStyle.size = imageSize;
1487     }
1488     JSRef<JSVal> verticalAlign = imageAttribute->GetProperty("verticalAlign");
1489     if (!verticalAlign->IsNull()) {
1490         auto align = static_cast<VerticalAlign>(verticalAlign->ToNumber<int32_t>());
1491         if (align < VerticalAlign::TOP || align > VerticalAlign::NONE) {
1492             align = VerticalAlign::BOTTOM;
1493         }
1494         imageStyle.verticalAlign = align;
1495         updateSpanStyle_.updateImageVerticalAlign = align;
1496     }
1497     JSRef<JSVal> objectFit = imageAttribute->GetProperty("objectFit");
1498     if (!objectFit->IsNull() && objectFit->IsNumber()) {
1499         auto fit = static_cast<ImageFit>(objectFit->ToNumber<int32_t>());
1500         if (fit < ImageFit::FILL || fit > ImageFit::SCALE_DOWN) {
1501             fit = ImageFit::COVER;
1502         }
1503         imageStyle.objectFit = fit;
1504         updateSpanStyle_.updateImageFit = fit;
1505     } else {
1506         imageStyle.objectFit = ImageFit::COVER;
1507     }
1508     auto layoutStyleObject = JSObjectCast(imageAttribute->GetProperty("layoutStyle"));
1509     if (!layoutStyleObject->IsUndefined()) {
1510         auto marginAttr = layoutStyleObject->GetProperty("margin");
1511         imageStyle.marginProp = JSRichEditor::ParseMarginAttr(marginAttr);
1512         updateSpanStyle_.marginProp = imageStyle.marginProp;
1513         auto borderRadiusAttr = layoutStyleObject->GetProperty("borderRadius");
1514         imageStyle.borderRadius = JSRichEditor::ParseBorderRadiusAttr(borderRadiusAttr);
1515         updateSpanStyle_.borderRadius = imageStyle.borderRadius;
1516     }
1517     return imageStyle;
1518 }
1519 
ParseJsCustomSymbolStyle(const JSRef<JSVal> & jsValue,TextStyle & style,uint32_t & symbolId)1520 void JSRichEditorController::ParseJsCustomSymbolStyle(const JSRef<JSVal>& jsValue, TextStyle& style, uint32_t& symbolId)
1521 {
1522     std::vector<std::string> fontFamilies;
1523     if (symbolId > SYSTEM_SYMBOL_BOUNDARY) {
1524         JSContainerBase::ParseJsSymbolCustomFamilyNames(fontFamilies, jsValue);
1525         style.SetSymbolType(SymbolType::CUSTOM);
1526         style.SetFontFamilies(fontFamilies);
1527     } else {
1528         style.SetSymbolType(SymbolType::SYSTEM);
1529         fontFamilies.push_back(DEFAULT_SYMBOL_FONTFAMILY);
1530         style.SetFontFamilies(fontFamilies);
1531     }
1532 }
1533 
ParseJsSymbolSpanStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)1534 void JSRichEditorController::ParseJsSymbolSpanStyle(
1535     const JSRef<JSObject>& styleObject, TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
1536 {
1537     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1538     JSRef<JSVal> fontColor = styleObject->GetProperty("fontColor");
1539     COLOR_MODE_LOCK(GetColorMode());
1540     std::vector<Color> symbolColor;
1541     if (!fontColor->IsNull() && JSContainerBase::ParseJsSymbolColor(fontColor, symbolColor)) {
1542         updateSpanStyle.updateSymbolColor = symbolColor;
1543         style.SetSymbolColorList(symbolColor);
1544     }
1545     JSRef<JSVal> fontSize = styleObject->GetProperty("fontSize");
1546     CalcDimension size;
1547     if (!fontSize->IsNull() && JSContainerBase::ParseJsDimensionFpNG(fontSize, size, false) &&
1548         !FontSizeRangeIsNegative(size) && size.Unit() != DimensionUnit::PERCENT) {
1549         updateSpanStyle.updateSymbolFontSize = size;
1550         style.SetFontSize(size);
1551     } else if (FontSizeRangeIsNegative(size) || size.Unit() == DimensionUnit::PERCENT) {
1552         auto theme = JSContainerBase::GetTheme<TextTheme>();
1553         CHECK_NULL_VOID(theme);
1554         size = theme->GetTextStyle().GetFontSize();
1555         style.SetFontSize(size);
1556     }
1557     JSRef<JSVal> fontWeight = styleObject->GetProperty("fontWeight");
1558     std::string weight;
1559     if (!fontWeight->IsNull() && (fontWeight->IsNumber() || JSContainerBase::ParseJsString(fontWeight, weight))) {
1560         if (fontWeight->IsNumber()) {
1561             weight = std::to_string(fontWeight->ToNumber<int32_t>());
1562         }
1563         updateSpanStyle.updateSymbolFontWeight = ConvertStrToFontWeight(weight);
1564         style.SetFontWeight(ConvertStrToFontWeight(weight));
1565     }
1566     JSRef<JSVal> renderingStrategy = styleObject->GetProperty("renderingStrategy");
1567     uint32_t symbolRenderStrategy;
1568     if (!renderingStrategy->IsNull() && JSContainerBase::ParseJsInteger(renderingStrategy, symbolRenderStrategy)) {
1569         if (symbolRenderStrategy < 0 ||
1570             symbolRenderStrategy > static_cast<uint32_t>(RenderingStrategy::MULTIPLE_OPACITY)) {
1571             symbolRenderStrategy = static_cast<uint32_t>(RenderingStrategy::SINGLE);
1572         }
1573         updateSpanStyle.updateSymbolRenderingStrategy = symbolRenderStrategy;
1574         style.SetRenderStrategy(symbolRenderStrategy);
1575     }
1576     JSRef<JSVal> effectStrategy = styleObject->GetProperty("effectStrategy");
1577     uint32_t symbolEffectStrategy;
1578     if (!effectStrategy->IsNull() && JSContainerBase::ParseJsInteger(effectStrategy, symbolEffectStrategy)) {
1579         updateSpanStyle.updateSymbolEffectStrategy = 0;
1580         style.SetEffectStrategy(0);
1581     }
1582 }
1583 
ParseTextUrlStyle(const JSRef<JSObject> & jsObject,std::optional<std::u16string> & urlAddressOpt)1584 void JSRichEditorBaseController::ParseTextUrlStyle(const JSRef<JSObject>& jsObject,
1585     std::optional<std::u16string>& urlAddressOpt)
1586 {
1587     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1588     JSRef<JSObject> urlStyleObj = JSObjectCast(jsObject->GetProperty("urlStyle"));
1589     CHECK_NULL_VOID(!urlStyleObj->IsUndefined());
1590 
1591     JSRef<JSVal> urlObj = urlStyleObj->GetProperty("url");
1592     std::u16string urlAddress;
1593     CHECK_NULL_VOID(JSContainerBase::ParseJsString(urlObj, urlAddress));
1594     urlAddressOpt = urlAddress;
1595 }
1596 
ParseUserGesture(const JSCallbackInfo & args,UserGestureOptions & gestureOption,const std::string & spanType)1597 void JSRichEditorController::ParseUserGesture(
1598     const JSCallbackInfo& args, UserGestureOptions& gestureOption, const std::string& spanType)
1599 {
1600     if (args.Length() < 2) {
1601         return;
1602     }
1603     if (!args[1]->IsObject()) {
1604         return;
1605     }
1606     JSRef<JSObject> object = JSRef<JSObject>::Cast(args[1]);
1607     auto gesture = object->GetProperty("gesture");
1608     if (!gesture->IsUndefined() && gesture->IsObject()) {
1609         auto gestureObj = JSRef<JSObject>::Cast(gesture);
1610         ParseUserClickEvent(args, gestureObj, gestureOption, spanType);
1611         auto onLongPressFunc = gestureObj->GetProperty("onLongPress");
1612         if ((onLongPressFunc->IsUndefined() && IsDisableEventVersion()) || !onLongPressFunc->IsFunction()) {
1613             gestureOption.onLongPress = nullptr;
1614             return;
1615         }
1616         auto jsLongPressFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(onLongPressFunc));
1617         auto* targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
1618         auto onLongPress = [execCtx = args.GetExecutionContext(), func = jsLongPressFunc, spanTypeInner = spanType,
1619                                 node =  AceType::WeakClaim(targetNode)](GestureEvent& info) {
1620             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1621             ACE_SCORING_EVENT(spanTypeInner + ".onLongPress");
1622             func->Execute(info);
1623         };
1624         gestureOption.onLongPress = std::move(onLongPress);
1625     }
1626 }
1627 
ParseUserMouseOption(const JSCallbackInfo & args,UserMouseOptions & mouseOption,const std::string & spanType)1628 void JSRichEditorController::ParseUserMouseOption(
1629     const JSCallbackInfo& args, UserMouseOptions& mouseOption, const std::string& spanType)
1630 {
1631     if (args.Length() < 2) {
1632         return;
1633     }
1634     if (!args[1]->IsObject()) {
1635         return;
1636     }
1637     JSRef<JSObject> object = JSRef<JSObject>::Cast(args[1]);
1638     auto onHoverFunc = object->GetProperty("onHover");
1639     if (onHoverFunc->IsUndefined() || !onHoverFunc->IsFunction()) {
1640         mouseOption.onHover = nullptr;
1641         return;
1642     }
1643     RefPtr<JsHoverFunction> jsOnHoverFunc = AceType::MakeRefPtr<JsHoverFunction>(JSRef<JSFunc>::Cast(onHoverFunc));
1644     auto targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
1645     auto onHover = [execCtx = args.GetExecutionContext(), func = jsOnHoverFunc, spanTypeInner = spanType,
1646                        node = AceType::WeakClaim(targetNode)](bool isHover, HoverInfo& info) {
1647         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1648         PipelineContext::SetCallBackNode(node);
1649         ACE_SCORING_EVENT(spanTypeInner + ".onHover");
1650         func->HoverExecute(isHover, info);
1651     };
1652     mouseOption.onHover = std::move(onHover);
1653 }
1654 
ParseUserClickEvent(const JSCallbackInfo & args,const JSRef<JSObject> & gestureObj,UserGestureOptions & gestureOption,const std::string & spanType)1655 void JSRichEditorController::ParseUserClickEvent(const JSCallbackInfo& args, const JSRef<JSObject>& gestureObj,
1656     UserGestureOptions& gestureOption, const std::string& spanType)
1657 {
1658     CHECK_NULL_VOID(!gestureObj->IsUndefined());
1659     auto clickFunc = gestureObj->GetProperty("onClick");
1660     if ((clickFunc->IsUndefined() && IsDisableEventVersion()) || !clickFunc->IsFunction()) {
1661         gestureOption.onClick = nullptr;
1662     } else {
1663         auto jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(clickFunc));
1664         auto* targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
1665         auto onClick = [execCtx = args.GetExecutionContext(), func = jsOnClickFunc, spanTypeInner = spanType,
1666                             node = AceType::WeakClaim(targetNode)](GestureEvent& info) {
1667             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1668             ACE_SCORING_EVENT(spanTypeInner + ".onClick");
1669             PipelineContext::SetCallBackNode(node);
1670             func->Execute(info);
1671         };
1672         gestureOption.onClick = std::move(onClick);
1673     }
1674     auto onDoubleClickFunc = gestureObj->GetProperty("onDoubleClick");
1675     if ((onDoubleClickFunc->IsUndefined() && IsDisableEventVersion()) || !onDoubleClickFunc->IsFunction()) {
1676         gestureOption.onDoubleClick = nullptr;
1677     } else {
1678         auto jsDoubleClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(onDoubleClickFunc));
1679         auto* targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
1680         auto onDoubleClick = [execCtx = args.GetExecutionContext(), func = jsDoubleClickFunc, spanTypeInner = spanType,
1681                                 node =  AceType::WeakClaim(targetNode)](GestureEvent& info) {
1682             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1683             ACE_SCORING_EVENT(spanTypeInner + ".onDoubleClick");
1684             func->Execute(info);
1685         };
1686         gestureOption.onDoubleClick = std::move(onDoubleClick);
1687     }
1688 }
1689 
AddImageSpan(const JSCallbackInfo & args)1690 void JSRichEditorController::AddImageSpan(const JSCallbackInfo& args)
1691 {
1692     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1693     if (args.Length() < 1) {
1694         return;
1695     }
1696     ImageSpanOptions options;
1697     if (!args[0]->IsEmpty() && args[0]->ToString() != "") {
1698         options = CreateJsImageOptions(args);
1699     } else {
1700         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
1701         return;
1702     }
1703     if (options.image.has_value()) {
1704         std::string assetSrc = options.image.value();
1705         if (!CheckImageSource(assetSrc)) {
1706             TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "CheckImageSource failed");
1707             args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
1708             return;
1709         }
1710     }
1711     if (args.Length() > 1 && args[1]->IsObject()) {
1712         JSRef<JSObject> imageObject = JSRef<JSObject>::Cast(args[1]);
1713 
1714         JSRef<JSVal> offset = imageObject->GetProperty("offset");
1715         int32_t imageOffset = 0;
1716         if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, imageOffset)) {
1717             options.offset = imageOffset > 0 ? imageOffset : 0;
1718         }
1719         auto imageAttribute = JSObjectCast(imageObject->GetProperty("imageStyle"));
1720         if (!imageAttribute->IsUndefined()) {
1721             ImageSpanAttribute imageStyle = ParseJsImageSpanAttribute(imageAttribute);
1722             options.imageAttribute = imageStyle;
1723         }
1724         UserGestureOptions gestureOption;
1725         ParseUserGesture(args, gestureOption, "ImageSpan");
1726         UserMouseOptions mouseOption;
1727         ParseUserMouseOption(args, mouseOption, "ImageSpan");
1728         options.userGestureOption = std::move(gestureOption);
1729         options.userMouseOption = std::move(mouseOption);
1730     }
1731     auto controller = controllerWeak_.Upgrade();
1732     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1733     int32_t spanIndex = 0;
1734     if (richEditorController) {
1735         spanIndex = richEditorController->AddImageSpan(options);
1736     }
1737     args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
1738 }
1739 
CheckImageSource(std::string assetSrc)1740 bool JSRichEditorController::CheckImageSource(std::string assetSrc)
1741 {
1742     SrcType srcType = ImageSourceInfo::ResolveURIType(assetSrc);
1743     if (assetSrc[0] == '/') {
1744         assetSrc = assetSrc.substr(1); // get the asset src without '/'.
1745     } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
1746         assetSrc = assetSrc.substr(2); // get the asset src without './'.
1747     }
1748     if (srcType == SrcType::ASSET) {
1749         auto pipelineContext = PipelineBase::GetCurrentContext();
1750         if (!pipelineContext) {
1751             TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
1752             return false;
1753         }
1754         auto assetManager = pipelineContext->GetAssetManager();
1755         if (!assetManager) {
1756             TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "assetManager is null");
1757             return false;
1758         }
1759         auto assetData = assetManager->GetAsset(assetSrc);
1760         if (!assetData) {
1761             TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "assetData is null");
1762             return false;
1763         }
1764     }
1765     return true;
1766 }
1767 
CreateJsImageOptions(const JSCallbackInfo & args)1768 ImageSpanOptions JSRichEditorController::CreateJsImageOptions(const JSCallbackInfo& args)
1769 {
1770     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1771     ImageSpanOptions options;
1772     auto context = PipelineBase::GetCurrentContext();
1773     CHECK_NULL_RETURN(context, options);
1774     bool isCard = context->IsFormRender();
1775     std::string image;
1776     std::string bundleName;
1777     std::string moduleName;
1778     bool srcValid = JSContainerBase::ParseJsMedia(args[0], image);
1779     if (isCard && args[0]->IsString()) {
1780         SrcType srcType = ImageSourceInfo::ResolveURIType(image);
1781         bool notSupport = (srcType == SrcType::NETWORK || srcType == SrcType::FILE || srcType == SrcType::DATA_ABILITY);
1782         if (notSupport) {
1783             image.clear();
1784         }
1785     }
1786     JSImage::GetJsMediaBundleInfo(args[0], bundleName, moduleName);
1787     options.image = image;
1788     options.bundleName = bundleName;
1789     options.moduleName = moduleName;
1790     if (!srcValid) {
1791 #if defined(PIXEL_MAP_SUPPORTED)
1792         if (!isCard) {
1793             if (IsDrawable(args[0])) {
1794                 options.imagePixelMap = GetDrawablePixmap(args[0]);
1795             } else {
1796                 options.imagePixelMap = CreatePixelMapFromNapiValue(args[0]);
1797             }
1798         }
1799 #endif
1800     }
1801     return options;
1802 }
1803 
IsDrawable(const JSRef<JSVal> & jsValue)1804 bool JSRichEditorController::IsDrawable(const JSRef<JSVal>& jsValue)
1805 {
1806     if (!jsValue->IsObject()) {
1807         return false;
1808     }
1809     JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
1810     if (jsObj->IsUndefined()) {
1811         return false;
1812     }
1813     JSRef<JSVal> func = jsObj->GetProperty("getPixelMap");
1814     return (!func->IsNull() && func->IsFunction());
1815 }
1816 
IsPixelMap(const JSRef<JSVal> & jsValue)1817 bool JSRichEditorController::IsPixelMap(const JSRef<JSVal>& jsValue)
1818 {
1819     if (!jsValue->IsObject()) {
1820         return false;
1821     }
1822     JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
1823     if (jsObj->IsUndefined()) {
1824         return false;
1825     }
1826     JSRef<JSVal> func = jsObj->GetProperty("readPixelsToBuffer");
1827     return (!func->IsNull() && func->IsFunction());
1828 }
1829 
AddTextSpan(const JSCallbackInfo & args)1830 void JSRichEditorController::AddTextSpan(const JSCallbackInfo& args)
1831 {
1832     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1833     if (args.Length() < 1) {
1834         TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "args length invalid");
1835         return;
1836     }
1837     TextSpanOptions options;
1838     std::u16string spanValue;
1839     if (auto tempArg = args[0]; tempArg->IsEmpty() || !tempArg->IsString() || tempArg->ToString() == "" ||
1840         !JSContainerBase::ParseJsString(tempArg, spanValue)) {
1841         TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "args error");
1842         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
1843         return;
1844     }
1845     options.value = spanValue;
1846 
1847     auto controller = controllerWeak_.Upgrade();
1848     if (args.Length() > 1 && args[1]->IsObject()) {
1849         JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[1]);
1850         JSRef<JSVal> offset = spanObject->GetProperty("offset");
1851         int32_t spanOffset = 0;
1852         if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, spanOffset)) {
1853             options.offset = spanOffset > 0 ? spanOffset : 0;
1854         }
1855         auto styleObject = JSObjectCast(spanObject->GetProperty("style"));
1856         updateSpanStyle_.ResetStyle();
1857         if (!styleObject->IsUndefined()) {
1858             auto pipelineContext = PipelineBase::GetCurrentContext();
1859             if (!pipelineContext) {
1860                 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
1861                 return;
1862             }
1863             if (!controller) {
1864                 TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "add text span, rich editor controller error");
1865                 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(0)));
1866                 return;
1867             }
1868             auto theme = controller->GetTheme();
1869             TextStyle style = theme ? theme->GetTextStyle() : TextStyle();
1870             ParseJsTextStyle(styleObject, style, updateSpanStyle_);
1871             options.style = style;
1872             options.useThemeFontColor = updateSpanStyle_.useThemeFontColor;
1873             options.useThemeDecorationColor = updateSpanStyle_.useThemeDecorationColor;
1874         }
1875         auto paraStyleObj = JSObjectCast(spanObject->GetProperty("paragraphStyle"));
1876         struct UpdateParagraphStyle style;
1877         if (ParseParagraphStyle(paraStyleObj, style)) {
1878             options.paraStyle = style;
1879         }
1880         ParseTextUrlStyle(spanObject, options.urlAddress);
1881         UserGestureOptions gestureOption;
1882         ParseUserGesture(args, gestureOption, "TextSpan");
1883         options.userGestureOption = std::move(gestureOption);
1884     }
1885     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1886     int32_t spanIndex = 0;
1887     if (richEditorController) {
1888         spanIndex = richEditorController->AddTextSpan(options);
1889     } else {
1890         TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "rich editor controller error");
1891     }
1892     args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
1893 }
1894 
AddSymbolSpan(const JSCallbackInfo & args)1895 void JSRichEditorController::AddSymbolSpan(const JSCallbackInfo& args)
1896 {
1897     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1898     if (args.Length() < 1) {
1899         return;
1900     }
1901     SymbolSpanOptions options;
1902     uint32_t symbolId;
1903     RefPtr<ResourceObject> resourceObject;
1904     if (!args[0]->IsEmpty() && JSContainerBase::ParseJsSymbolId(args[0], symbolId, resourceObject)) {
1905         options.symbolId = symbolId;
1906         options.resourceObject = resourceObject;
1907     } else {
1908         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
1909         return;
1910     }
1911     auto controller = controllerWeak_.Upgrade();
1912     if (args.Length() > 1 && args[1]->IsObject()) {
1913         JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[1]);
1914         JSRef<JSVal> offset = spanObject->GetProperty("offset");
1915         int32_t spanOffset = 0;
1916         if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, spanOffset)) {
1917             options.offset = spanOffset > 0 ? spanOffset : 0;
1918         }
1919         auto styleObject = JSObjectCast(spanObject->GetProperty("style"));
1920         if (!styleObject->IsUndefined()) {
1921             auto pipelineContext = PipelineBase::GetCurrentContext();
1922             if (!pipelineContext) {
1923                 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
1924                 return;
1925             }
1926             if (!controller) {
1927                 TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "add symbol span, rich editor controller error");
1928                 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(0)));
1929                 return;
1930             }
1931             auto theme = controller->GetTheme();
1932             TextStyle style = theme ? theme->GetTextStyle() : TextStyle();
1933             ParseJsSymbolSpanStyle(styleObject, style, updateSpanStyle_);
1934             ParseJsCustomSymbolStyle(args[0], style, symbolId);
1935             options.style = style;
1936         }
1937     }
1938 
1939     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1940     int32_t spanIndex = 0;
1941     if (richEditorController) {
1942         spanIndex = richEditorController->AddSymbolSpan(options);
1943     }
1944     args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
1945 }
1946 
CreateJSSpansInfo(const SelectionInfo & info)1947 JSRef<JSVal> JSRichEditorController::CreateJSSpansInfo(const SelectionInfo& info)
1948 {
1949     uint32_t idx = 0;
1950 
1951     JSRef<JSArray> spanObjectArray = JSRef<JSArray>::New();
1952     JSRef<JSObject> selectionObject = JSRef<JSObject>::New();
1953 
1954     const std::list<ResultObject>& spanObjectList = info.GetSelection().resultObjects;
1955     for (const ResultObject& spanObject : spanObjectList) {
1956         spanObjectArray->SetValueAt(idx++, JSRichEditor::CreateJSSpanResultObject(spanObject));
1957     }
1958 
1959     return JSRef<JSVal>::Cast(spanObjectArray);
1960 }
1961 
GetSpansInfo(const JSCallbackInfo & args)1962 void JSRichEditorController::GetSpansInfo(const JSCallbackInfo& args)
1963 {
1964     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1965     int32_t end = -1;
1966     int32_t start = -1;
1967     if (args[0]->IsObject()) {
1968         JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
1969         JSRef<JSVal> startVal = obj->GetProperty("start");
1970         JSRef<JSVal> endVal = obj->GetProperty("end");
1971 
1972         if (!startVal->IsNull() && startVal->IsNumber()) {
1973             start = startVal->ToNumber<int32_t>();
1974         }
1975 
1976         if (!endVal->IsNull() && endVal->IsNumber()) {
1977             end = endVal->ToNumber<int32_t>();
1978         }
1979     }
1980     auto controller = controllerWeak_.Upgrade();
1981     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
1982     CHECK_NULL_VOID(richEditorController);
1983     SelectionInfo value = richEditorController->GetSpansInfo(start, end);
1984     args.SetReturnValue(CreateJSSpansInfo(value));
1985 }
1986 
GetPreviewTextInfo(const JSCallbackInfo & args)1987 void JSRichEditorBaseController::GetPreviewTextInfo(const JSCallbackInfo& args)
1988 {
1989     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
1990     auto controller = controllerWeak_.Upgrade();
1991     CHECK_NULL_VOID(controller);
1992     auto info = controller->GetPreviewTextInfo();
1993     args.SetReturnValue(CreateJSPreviewTextInfo(info));
1994 }
1995 
CreateJSPreviewTextInfo(const PreviewTextInfo & info)1996 JSRef<JSObject> JSRichEditorBaseController::CreateJSPreviewTextInfo(const PreviewTextInfo& info)
1997 {
1998     auto resultObj = JSRef<JSObject>::New();
1999     resultObj->SetProperty<std::u16string>("value", info.value.value_or(u""));
2000     resultObj->SetProperty<int32_t>("offset", info.offset.value_or(0));
2001     return resultObj;
2002 }
2003 
DeleteSpans(const JSCallbackInfo & args)2004 void JSRichEditorController::DeleteSpans(const JSCallbackInfo& args)
2005 {
2006     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2007     RangeOptions options;
2008     auto controller = controllerWeak_.Upgrade();
2009     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2010     CHECK_NULL_VOID(richEditorController);
2011 
2012     if (args.Length() < 1) {
2013         richEditorController->DeleteSpans(options);
2014         return;
2015     }
2016 
2017     if (!args[0]->IsObject() || !richEditorController) {
2018         return;
2019     }
2020     JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[0]);
2021     JSRef<JSVal> startVal = spanObject->GetProperty("start");
2022     int32_t start = 0;
2023     if (!startVal->IsNull() && JSContainerBase::ParseJsInt32(startVal, start)) {
2024         options.start = start;
2025     }
2026     JSRef<JSVal> endVal = spanObject->GetProperty("end");
2027     int32_t end = 0;
2028     if (!startVal->IsNull() && JSContainerBase::ParseJsInt32(endVal, end)) {
2029         options.end = end;
2030     }
2031     richEditorController->DeleteSpans(options);
2032 }
2033 
AddPlaceholderSpan(const JSCallbackInfo & args)2034 void JSRichEditorController::AddPlaceholderSpan(const JSCallbackInfo& args)
2035 {
2036     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2037     if (args.Length() < 1) {
2038         return;
2039     }
2040     auto customVal = args[0];
2041     if (!customVal->IsFunction() && !customVal->IsObject()) {
2042         return;
2043     }
2044     JSRef<JSVal> funcValue;
2045     auto customObject = JSRef<JSObject>::Cast(customVal);
2046     auto builder = customObject->GetProperty("builder");
2047     // if failed to get builder, parse function directly
2048     if (builder->IsEmpty() || builder->IsNull() || !builder->IsFunction()) {
2049         funcValue = customVal;
2050     } else {
2051         funcValue = builder;
2052     }
2053     SpanOptionBase options;
2054     {
2055         if (!funcValue->IsFunction()) {
2056             return;
2057         }
2058         auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(funcValue));
2059         CHECK_NULL_VOID(builderFunc);
2060         ViewStackModel::GetInstance()->NewScope();
2061         builderFunc->Execute();
2062         auto customNode = AceType::DynamicCast<NG::UINode>(ViewStackModel::GetInstance()->Finish());
2063         CHECK_NULL_VOID(customNode);
2064         auto controller = controllerWeak_.Upgrade();
2065         auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2066         int32_t spanIndex = 0;
2067         if (richEditorController) {
2068             ParseOptions(args, options);
2069             spanIndex = richEditorController->AddPlaceholderSpan(customNode, options);
2070         }
2071         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
2072     }
2073 }
2074 
ParseOptions(const JSCallbackInfo & args,SpanOptionBase & placeholderSpan)2075 void JSRichEditorController::ParseOptions(const JSCallbackInfo& args, SpanOptionBase& placeholderSpan)
2076 {
2077     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2078     if (args.Length() < 2) {
2079         return;
2080     }
2081     if (!args[1]->IsObject()) {
2082         return;
2083     }
2084     JSRef<JSObject> placeholderOptionObject = JSRef<JSObject>::Cast(args[1]);
2085     JSRef<JSVal> offset = placeholderOptionObject->GetProperty("offset");
2086     int32_t placeholderOffset = 0;
2087     if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, placeholderOffset)) {
2088         if (placeholderOffset >= 0) {
2089             placeholderSpan.offset = placeholderOffset;
2090         }
2091     }
2092     COLOR_MODE_LOCK(GetColorMode());
2093     JSRef<JSVal> colorMetrics = placeholderOptionObject->GetProperty("dragBackgroundColor");
2094     if (Color dragBackgroundColor; !colorMetrics->IsNull() &&
2095         JSContainerBase::ParseColorMetricsToColor(colorMetrics, dragBackgroundColor)) {
2096         placeholderSpan.dragBackgroundColor = dragBackgroundColor;
2097     }
2098     JSRef<JSVal> isDragShadowNeeded = placeholderOptionObject->GetProperty("isDragShadowNeeded");
2099     if (!isDragShadowNeeded->IsNull() && isDragShadowNeeded->IsBoolean()) {
2100         placeholderSpan.isDragShadowNeeded = isDragShadowNeeded->ToBoolean();
2101     }
2102 }
2103 
GetSelection(const JSCallbackInfo & args)2104 void JSRichEditorController::GetSelection(const JSCallbackInfo& args)
2105 {
2106     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2107     auto controller = controllerWeak_.Upgrade();
2108     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2109     CHECK_NULL_VOID(richEditorController);
2110     SelectionInfo value = richEditorController->GetSelectionSpansInfo();
2111     args.SetReturnValue(JSRichEditor::CreateJSSelection(value));
2112 }
2113 
JSBind(BindingTarget globalObj)2114 void JSRichEditorController::JSBind(BindingTarget globalObj)
2115 {
2116     JSClass<JSRichEditorController>::Declare("RichEditorController");
2117     JSClass<JSRichEditorController>::CustomMethod("addImageSpan", &JSRichEditorController::AddImageSpan);
2118     JSClass<JSRichEditorController>::CustomMethod("addTextSpan", &JSRichEditorController::AddTextSpan);
2119     JSClass<JSRichEditorController>::CustomMethod("addSymbolSpan", &JSRichEditorController::AddSymbolSpan);
2120     JSClass<JSRichEditorController>::CustomMethod("addBuilderSpan", &JSRichEditorController::AddPlaceholderSpan);
2121     JSClass<JSRichEditorController>::CustomMethod("setCaretOffset", &JSRichEditorController::SetCaretOffset);
2122     JSClass<JSRichEditorController>::CustomMethod("getCaretOffset", &JSRichEditorController::GetCaretOffset);
2123     JSClass<JSRichEditorController>::CustomMethod("getCaretRect", &JSRichEditorController::GetCaretRect);
2124     JSClass<JSRichEditorController>::CustomMethod("updateSpanStyle", &JSRichEditorController::UpdateSpanStyle);
2125     JSClass<JSRichEditorController>::CustomMethod(
2126         "updateParagraphStyle", &JSRichEditorController::UpdateParagraphStyle);
2127     JSClass<JSRichEditorController>::CustomMethod("getTypingStyle", &JSRichEditorController::GetTypingStyle);
2128     JSClass<JSRichEditorController>::CustomMethod("setTypingStyle", &JSRichEditorController::SetTypingStyle);
2129     JSClass<JSRichEditorController>::CustomMethod("getSpans", &JSRichEditorController::GetSpansInfo);
2130     JSClass<JSRichEditorController>::CustomMethod("getPreviewText", &JSRichEditorController::GetPreviewTextInfo);
2131     JSClass<JSRichEditorController>::CustomMethod("getParagraphs", &JSRichEditorController::GetParagraphsInfo);
2132     JSClass<JSRichEditorController>::CustomMethod("deleteSpans", &JSRichEditorController::DeleteSpans);
2133     JSClass<JSRichEditorController>::CustomMethod("setSelection", &JSRichEditorController::SetSelection);
2134     JSClass<JSRichEditorController>::CustomMethod("getSelection", &JSRichEditorController::GetSelection);
2135     JSClass<JSRichEditorController>::CustomMethod("getLayoutManager", &JSRichEditorController::GetLayoutManager);
2136     JSClass<JSRichEditorController>::CustomMethod("isEditing", &JSRichEditorController::IsEditing);
2137     JSClass<JSRichEditorController>::CustomMethod("toStyledString", &JSRichEditorController::ToStyledString);
2138     JSClass<JSRichEditorController>::CustomMethod("fromStyledString", &JSRichEditorController::FromStyledString);
2139     JSClass<JSRichEditorController>::Method("stopEditing", &JSRichEditorController::StopEditing);
2140     JSClass<JSRichEditorController>::Method("closeSelectionMenu", &JSRichEditorController::CloseSelectionMenu);
2141     JSClass<JSRichEditorController>::Bind(
2142         globalObj, JSRichEditorController::Constructor, JSRichEditorController::Destructor);
2143 }
2144 
2145 namespace {
ValidationCheck(const JSCallbackInfo & info)2146 bool ValidationCheck(const JSCallbackInfo& info)
2147 {
2148     if (!info[0]->IsNumber() && !info[0]->IsObject()) {
2149         return false;
2150     }
2151     return true;
2152 }
2153 
ParseRange(const JSRef<JSObject> & object)2154 std::pair<int32_t, int32_t> ParseRange(const JSRef<JSObject>& object)
2155 {
2156     int32_t start = -1;
2157     int32_t end = -1;
2158     if (!JSContainerBase::ParseJsInt32(object->GetProperty("start"), start)) {
2159         start = 0;
2160     }
2161     if (!JSContainerBase::ParseJsInt32(object->GetProperty("end"), end)) {
2162         end = INT_MAX;
2163     }
2164     if (start < 0) {
2165         start = 0;
2166     }
2167     if (end < 0) {
2168         end = INT_MAX;
2169     }
2170     if (start > end) {
2171         start = 0;
2172         end = INT_MAX;
2173     }
2174     return std::make_pair(start, end);
2175 }
2176 } // namespace
2177 
ParseWordBreakParagraphStyle(const JSRef<JSObject> & styleObject,struct UpdateParagraphStyle & style)2178 void JSRichEditorController::ParseWordBreakParagraphStyle(const JSRef<JSObject>& styleObject,
2179     struct UpdateParagraphStyle& style)
2180 {
2181     auto wordBreakObj = styleObject->GetProperty("wordBreak");
2182     if (wordBreakObj->IsNull() || !wordBreakObj->IsNumber()) {
2183         return;
2184     }
2185     auto index = wordBreakObj->ToNumber<int32_t>();
2186     if (index < 0 || index >= static_cast<int32_t>(WORD_BREAK_TYPES.size())) {
2187         index = static_cast<int32_t>(WordBreak::BREAK_WORD);
2188     }
2189     style.wordBreak = WORD_BREAK_TYPES[index];
2190 }
2191 
ParseLineBreakStrategyParagraphStyle(const JSRef<JSObject> & styleObject,struct UpdateParagraphStyle & style)2192 void JSRichEditorController::ParseLineBreakStrategyParagraphStyle(
2193     const JSRef<JSObject>& styleObject, struct UpdateParagraphStyle& style)
2194 {
2195     auto breakStrategyObj = styleObject->GetProperty("lineBreakStrategy");
2196     if (!breakStrategyObj->IsNull() && breakStrategyObj->IsNumber()) {
2197         auto breakStrategy = static_cast<LineBreakStrategy>(breakStrategyObj->ToNumber<int32_t>());
2198         if (breakStrategy < LineBreakStrategy::GREEDY || breakStrategy > LineBreakStrategy::BALANCED) {
2199             breakStrategy = LineBreakStrategy::GREEDY;
2200         }
2201         style.lineBreakStrategy = breakStrategy;
2202     }
2203 }
2204 
ParseTextAlignParagraphStyle(const JSRef<JSObject> & styleObject,struct UpdateParagraphStyle & style)2205 void JSRichEditorController::ParseTextAlignParagraphStyle(const JSRef<JSObject>& styleObject,
2206     struct UpdateParagraphStyle& style)
2207 {
2208     auto textAlignObj = styleObject->GetProperty("textAlign");
2209     if (!textAlignObj->IsNull() && textAlignObj->IsNumber()) {
2210         auto align = static_cast<TextAlign>(textAlignObj->ToNumber<int32_t>());
2211         if (align < TextAlign::START || align > TextAlign::JUSTIFY) {
2212             align = TextAlign::START;
2213         }
2214         style.textAlign = align;
2215     }
2216 }
2217 
ParseParagraphSpacing(const JSRef<JSObject> & styleObject,struct UpdateParagraphStyle & style)2218 void JSRichEditorController::ParseParagraphSpacing(const JSRef<JSObject>& styleObject,
2219     struct UpdateParagraphStyle& style)
2220 {
2221     auto paragraphSpacing = styleObject->GetProperty("paragraphSpacing");
2222     CalcDimension size;
2223     if (!paragraphSpacing->IsNull() && JSContainerBase::ParseJsDimensionFpNG(paragraphSpacing, size, false) &&
2224         !size.IsNonPositive() && size.Unit() != DimensionUnit::PERCENT) {
2225         style.paragraphSpacing = size;
2226     }
2227 }
2228 
ParseParagraphStyle(const JSRef<JSObject> & styleObject,struct UpdateParagraphStyle & style)2229 bool JSRichEditorController::ParseParagraphStyle(const JSRef<JSObject>& styleObject, struct UpdateParagraphStyle& style)
2230 {
2231     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2232     if (styleObject->IsUndefined()) {
2233         return false;
2234     }
2235     ParseTextAlignParagraphStyle(styleObject, style);
2236     if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
2237         ParseLineBreakStrategyParagraphStyle(styleObject, style);
2238         ParseWordBreakParagraphStyle(styleObject, style);
2239     }
2240     ParseParagraphSpacing(styleObject, style);
2241 
2242     auto lm = styleObject->GetProperty("leadingMargin");
2243     if (lm->IsObject()) {
2244         // [LeadingMarginPlaceholder]
2245         JSRef<JSObject> leadingMarginObject = JSRef<JSObject>::Cast(lm);
2246         style.leadingMargin = std::make_optional<NG::LeadingMargin>();
2247         JSRef<JSVal> placeholder = leadingMarginObject->GetProperty("pixelMap");
2248         if (IsPixelMap(placeholder)) {
2249 #if defined(PIXEL_MAP_SUPPORTED)
2250             auto pixelMap = CreatePixelMapFromNapiValue(placeholder);
2251             style.leadingMargin->pixmap = pixelMap;
2252 #endif
2253         }
2254 
2255         JSRef<JSVal> sizeVal = leadingMarginObject->GetProperty("size");
2256         if (!sizeVal->IsUndefined() && sizeVal->IsArray()) {
2257             auto rangeArray = JSRef<JSArray>::Cast(sizeVal);
2258             JSRef<JSVal> widthVal = rangeArray->GetValueAt(0);
2259             JSRef<JSVal> heightVal = rangeArray->GetValueAt(1);
2260 
2261             CalcDimension width;
2262             CalcDimension height;
2263             JSContainerBase::ParseJsDimensionVp(widthVal, width);
2264             JSContainerBase::ParseJsDimensionVp(heightVal, height);
2265             style.leadingMargin->size = NG::LeadingMarginSize(width, height);
2266         } else if (sizeVal->IsUndefined()) {
2267             std::string resWidthStr;
2268             if (JSContainerBase::ParseJsString(lm, resWidthStr)) {
2269                 CalcDimension width;
2270                 JSContainerBase::ParseJsDimensionVp(lm, width);
2271                 style.leadingMargin->size = NG::LeadingMarginSize(width, Dimension(0.0, width.Unit()));
2272             }
2273         }
2274     } else if (!lm->IsNull()) {
2275         // [Dimension]
2276         style.leadingMargin = std::make_optional<NG::LeadingMargin>();
2277         CalcDimension width;
2278         JSContainerBase::ParseJsDimensionVp(lm, width);
2279         style.leadingMargin->size = NG::LeadingMarginSize(width, Dimension(0.0, width.Unit()));
2280     }
2281     return true;
2282 }
2283 
UpdateSpanStyle(const JSCallbackInfo & info)2284 void JSRichEditorController::UpdateSpanStyle(const JSCallbackInfo& info)
2285 {
2286     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2287     if (!ValidationCheck(info)) {
2288         return;
2289     }
2290     auto jsObject = JSRef<JSObject>::Cast(info[0]);
2291 
2292     auto [start, end] = ParseRange(jsObject);
2293     auto pipelineContext = PipelineBase::GetCurrentContext();
2294     if (!pipelineContext) {
2295         TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
2296         return;
2297     }
2298     auto controller = controllerWeak_.Upgrade();
2299     if (!controller) {
2300         TAG_LOGW(AceLogTag::ACE_RICH_TEXT, "update span style, rich editor controller error");
2301         return;
2302     }
2303     auto theme = controller->GetTheme();
2304     TextStyle textStyle = theme ? theme->GetTextStyle() : TextStyle();
2305     ImageSpanAttribute imageStyle;
2306     auto richEditorTextStyle = JSObjectCast(jsObject->GetProperty("textStyle"));
2307     auto richEditorImageStyle = JSObjectCast(jsObject->GetProperty("imageStyle"));
2308     auto richEditorSymbolSpanStyle = JSObjectCast(jsObject->GetProperty("symbolStyle"));
2309     updateSpanStyle_.ResetStyle();
2310     if (!richEditorTextStyle->IsUndefined()) {
2311         ParseJsTextStyle(richEditorTextStyle, textStyle, updateSpanStyle_);
2312     }
2313     if (!richEditorImageStyle->IsUndefined()) {
2314         imageStyle = ParseJsImageSpanAttribute(richEditorImageStyle);
2315     }
2316     if (!richEditorSymbolSpanStyle->IsUndefined()) {
2317         TextStyle symbolTextStyle;
2318         ParseJsSymbolSpanStyle(richEditorSymbolSpanStyle, symbolTextStyle, updateSpanStyle_);
2319     }
2320     ParseTextUrlStyle(jsObject, updateSpanStyle_.updateUrlAddress);
2321 
2322     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2323     CHECK_NULL_VOID(richEditorController);
2324     richEditorController->SetUpdateSpanStyle(updateSpanStyle_);
2325     richEditorController->UpdateSpanStyle(start, end, textStyle, imageStyle);
2326 }
2327 
GetParagraphsInfo(const JSCallbackInfo & args)2328 void JSRichEditorController::GetParagraphsInfo(const JSCallbackInfo& args)
2329 {
2330     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2331     if (!args[0]->IsObject()) {
2332         return;
2333     }
2334     auto [start, end] = ParseRange(JSRef<JSObject>::Cast(args[0]));
2335     if (start == end) {
2336         return;
2337     }
2338     auto controller = controllerWeak_.Upgrade();
2339     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2340     CHECK_NULL_VOID(richEditorController);
2341     auto info = richEditorController->GetParagraphsInfo(start, end);
2342     args.SetReturnValue(CreateJSParagraphsInfo(info));
2343 }
2344 
UpdateParagraphStyle(const JSCallbackInfo & info)2345 void JSRichEditorController::UpdateParagraphStyle(const JSCallbackInfo& info)
2346 {
2347     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2348     if (!ValidationCheck(info)) {
2349         return;
2350     }
2351     auto object = JSRef<JSObject>::Cast(info[0]);
2352     auto [start, end] = ParseRange(object);
2353     if (start == end) {
2354         return;
2355     }
2356     auto styleObj = JSObjectCast(object->GetProperty("style"));
2357 
2358     struct UpdateParagraphStyle style;
2359     if (!ParseParagraphStyle(styleObj, style)) {
2360         return;
2361     }
2362     auto controller = controllerWeak_.Upgrade();
2363     CHECK_NULL_VOID(controller);
2364     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2365     CHECK_NULL_VOID(richEditorController);
2366     richEditorController->UpdateParagraphStyle(start, end, style);
2367 }
2368 
CreateJSParagraphsInfo(const std::vector<ParagraphInfo> & info)2369 JSRef<JSVal> JSRichEditorController::CreateJSParagraphsInfo(const std::vector<ParagraphInfo>& info)
2370 {
2371     auto array = JSRef<JSArray>::New();
2372     for (size_t i = 0; i < info.size(); ++i) {
2373         auto obj = JSRef<JSObject>::New();
2374         obj->SetPropertyObject("style", JSRichEditor::CreateParagraphStyleResult(info[i]));
2375 
2376         auto range = JSRef<JSArray>::New();
2377         range->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(info[i].range.first)));
2378         range->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(info[i].range.second)));
2379         obj->SetPropertyObject("range", range);
2380         array->SetValueAt(i, obj);
2381     }
2382     return JSRef<JSVal>::Cast(array);
2383 }
2384 
GetCaretOffset(const JSCallbackInfo & args)2385 void JSRichEditorBaseController::GetCaretOffset(const JSCallbackInfo& args)
2386 {
2387     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2388     auto controller = controllerWeak_.Upgrade();
2389     int32_t caretOffset = -1;
2390     if (controller) {
2391         caretOffset = controller->GetCaretOffset();
2392         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(caretOffset)));
2393     } else {
2394         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(caretOffset)));
2395     }
2396 }
2397 
GetCaretRect(const JSCallbackInfo & args)2398 void JSRichEditorBaseController::GetCaretRect(const JSCallbackInfo& args)
2399 {
2400     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2401     auto controller = controllerWeak_.Upgrade();
2402     CHECK_NULL_VOID(controller);
2403     auto caretRect = controller->GetCaretRect();
2404     CHECK_EQUAL_VOID(caretRect.IsValid(), false);
2405     JSRef<JSObject> obj = JSRef<JSObject>::New();
2406     obj->SetProperty<float>("x", caretRect.GetOffset().GetX());
2407     obj->SetProperty<float>("y", caretRect.GetOffset().GetY());
2408     obj->SetProperty<float>("width", caretRect.Width());
2409     obj->SetProperty<float>("height", caretRect.Height());
2410     args.SetReturnValue(obj);
2411 }
2412 
SetCaretOffset(const JSCallbackInfo & args)2413 void JSRichEditorBaseController::SetCaretOffset(const JSCallbackInfo& args)
2414 {
2415     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2416     auto controller = controllerWeak_.Upgrade();
2417     int32_t caretPosition = -1;
2418     bool success = false;
2419     JSViewAbstract::ParseJsInteger<int32_t>(args[0], caretPosition);
2420     caretPosition = caretPosition < 0 ? -1 : caretPosition;
2421     if (controller) {
2422         success = controller->SetCaretOffset(caretPosition);
2423         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(success)));
2424     } else {
2425         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(success)));
2426     }
2427 }
2428 
SetTypingStyle(const JSCallbackInfo & info)2429 void JSRichEditorBaseController::SetTypingStyle(const JSCallbackInfo& info)
2430 {
2431     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2432     auto controller = controllerWeak_.Upgrade();
2433     CHECK_NULL_VOID(controller);
2434     bool isBelowApi12 = !AceApplicationInfo::GetInstance().
2435         GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE);
2436     if (isBelowApi12 && !info[0]->IsObject()) {
2437         return;
2438     }
2439     auto pipelineContext = PipelineBase::GetCurrentContext();
2440     if (!pipelineContext) {
2441         TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "pipelineContext is null");
2442         return;
2443     }
2444     auto theme = controller->GetTheme();
2445     TextStyle textStyle = theme ? theme->GetTextStyle() : TextStyle();
2446     bool isUndefined = false;
2447     if (info[0]->IsObject()) {
2448         JSRef<JSObject> richEditorTextStyle = JSRef<JSObject>::Cast(info[0]);
2449         isUndefined = richEditorTextStyle->IsUndefined();
2450         typingStyle_.ResetStyle();
2451         if (isBelowApi12) {
2452             typingStyle_.updateTextColor = theme->GetTextStyle().GetTextColor();
2453         }
2454         if (!richEditorTextStyle->IsUndefined()) {
2455             ParseJsTextStyle(richEditorTextStyle, textStyle, typingStyle_);
2456         }
2457     }
2458     bool isNeedReset = !isBelowApi12 && (!info[0]->IsObject() || isUndefined);
2459     TAG_LOGI(AceLogTag::ACE_RICH_TEXT, "SetTypingStyle %{public}d", isNeedReset);
2460     if (isNeedReset) {
2461         controller->SetTypingStyle(std::nullopt, std::nullopt);
2462         return;
2463     }
2464     controller->SetTypingStyle(typingStyle_, textStyle);
2465 }
2466 
FontSizeRangeIsNegative(const CalcDimension & size)2467 bool JSRichEditorBaseController::FontSizeRangeIsNegative(const CalcDimension& size)
2468 {
2469     if (!AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
2470         return size.IsNegative();
2471     }
2472     return size.IsNonPositive();
2473 }
2474 
ParseJsTextStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2475 void JSRichEditorBaseController::ParseJsTextStyle(
2476     const JSRef<JSObject>& styleObject, TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2477 {
2478     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2479     JSRef<JSVal> fontColor = styleObject->GetProperty("fontColor");
2480     COLOR_MODE_LOCK(GetColorMode());
2481     Color textColor;
2482     if (!fontColor->IsNull() && JSContainerBase::ParseJsColor(fontColor, textColor)) {
2483         style.SetTextColor(textColor);
2484         updateSpanStyle.updateTextColor = textColor;
2485         updateSpanStyle.useThemeFontColor = false;
2486     }
2487     JSRef<JSVal> fontSize = styleObject->GetProperty("fontSize");
2488     CalcDimension size;
2489     if (!fontSize->IsNull() && JSContainerBase::ParseJsDimensionFpNG(fontSize, size) &&
2490         !FontSizeRangeIsNegative(size) && size.Unit() != DimensionUnit::PERCENT) {
2491         updateSpanStyle.updateFontSize = size;
2492         style.SetFontSize(size);
2493     } else if (FontSizeRangeIsNegative(size) || size.Unit() == DimensionUnit::PERCENT) {
2494         auto theme = JSContainerBase::GetTheme<TextTheme>();
2495         CHECK_NULL_VOID(theme);
2496         size = theme->GetTextStyle().GetFontSize();
2497         style.SetFontSize(size);
2498     }
2499     ParseJsLineHeightLetterSpacingTextStyle(styleObject, style, updateSpanStyle);
2500     ParseJsFontFeatureTextStyle(styleObject, style, updateSpanStyle);
2501     JSRef<JSVal> fontStyle = styleObject->GetProperty("fontStyle");
2502     if (!fontStyle->IsNull() && fontStyle->IsNumber()) {
2503         updateSpanStyle.updateItalicFontStyle = static_cast<FontStyle>(fontStyle->ToNumber<int32_t>());
2504         style.SetFontStyle(static_cast<FontStyle>(fontStyle->ToNumber<int32_t>()));
2505     }
2506     JSRef<JSVal> fontWeight = styleObject->GetProperty("fontWeight");
2507     std::string weight;
2508     if (!fontWeight->IsNull() && (fontWeight->IsNumber() || JSContainerBase::ParseJsString(fontWeight, weight))) {
2509         if (fontWeight->IsNumber()) {
2510             weight = std::to_string(fontWeight->ToNumber<int32_t>());
2511         }
2512         updateSpanStyle.updateFontWeight = ConvertStrToFontWeight(weight);
2513         style.SetFontWeight(ConvertStrToFontWeight(weight));
2514     }
2515     JSRef<JSVal> fontFamily = styleObject->GetProperty("fontFamily");
2516     std::vector<std::string> family;
2517     if (!fontFamily->IsNull() && JSContainerBase::ParseJsFontFamilies(fontFamily, family)) {
2518         updateSpanStyle.updateFontFamily = family;
2519         style.SetFontFamilies(family);
2520     }
2521     ParseJsHalfLeadingTextStyle(styleObject, style, updateSpanStyle);
2522     ParseTextDecoration(styleObject, style, updateSpanStyle);
2523     ParseTextShadow(styleObject, style, updateSpanStyle);
2524     ParseTextBackgroundStyle(styleObject, style, updateSpanStyle);
2525 }
2526 
ParseJsLineHeightLetterSpacingTextStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle,bool isSupportPercent)2527 void JSRichEditorBaseController::ParseJsLineHeightLetterSpacingTextStyle(const JSRef<JSObject>& styleObject,
2528     TextStyle& style, struct UpdateSpanStyle& updateSpanStyle, bool isSupportPercent)
2529 {
2530     JSRef<JSVal> lineHeight = styleObject->GetProperty("lineHeight");
2531     CalcDimension height;
2532     if (!lineHeight->IsNull() && JSContainerBase::ParseJsDimensionFpNG(lineHeight, height, isSupportPercent) &&
2533         !height.IsNegative() && height.Unit() != DimensionUnit::PERCENT) {
2534         updateSpanStyle.updateLineHeight = height;
2535         style.SetLineHeight(height);
2536     } else if (height.IsNegative() || height.Unit() == DimensionUnit::PERCENT) {
2537         auto theme = JSContainerBase::GetTheme<TextTheme>();
2538         CHECK_NULL_VOID(theme);
2539         height = theme->GetTextStyle().GetLineHeight();
2540         updateSpanStyle.updateLineHeight = height;
2541         style.SetLineHeight(height);
2542     } else if (!lineHeight->IsUndefined() &&
2543                !std::all_of(lineHeight->ToString().begin(), lineHeight->ToString().end(), ::isdigit)) {
2544         auto theme = JSContainerBase::GetTheme<TextTheme>();
2545         CHECK_NULL_VOID(theme);
2546         height = theme->GetTextStyle().GetLineHeight();
2547         updateSpanStyle.updateLineHeight = height;
2548         style.SetLineHeight(height);
2549     }
2550     JSRef<JSVal> letterSpacing = styleObject->GetProperty("letterSpacing");
2551     CalcDimension letters;
2552     if (JSContainerBase::ParseJsDimensionFpNG(letterSpacing, letters, isSupportPercent) &&
2553         letters.Unit() != DimensionUnit::PERCENT) {
2554         updateSpanStyle.updateLetterSpacing = letters;
2555         style.SetLetterSpacing(letters);
2556     } else if (letters.Unit() == DimensionUnit::PERCENT) {
2557         auto theme = JSContainerBase::GetTheme<TextTheme>();
2558         CHECK_NULL_VOID(theme);
2559         letters = theme->GetTextStyle().GetLetterSpacing();
2560         updateSpanStyle.updateLetterSpacing = letters;
2561         style.SetLetterSpacing(letters);
2562     } else if (!letterSpacing->IsUndefined() && !letterSpacing->IsNull() &&
2563                !std::all_of(letterSpacing->ToString().begin(), letterSpacing->ToString().end(), ::isdigit)) {
2564         auto theme = JSContainerBase::GetTheme<TextTheme>();
2565         CHECK_NULL_VOID(theme);
2566         letters = theme->GetTextStyle().GetLetterSpacing();
2567         updateSpanStyle.updateLetterSpacing = letters;
2568         style.SetLetterSpacing(letters);
2569     }
2570 }
2571 
ParseJsFontFeatureTextStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2572 void JSRichEditorBaseController::ParseJsFontFeatureTextStyle(const JSRef<JSObject>& styleObject,
2573     TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2574 {
2575     JSRef<JSVal> fontFeature = styleObject->GetProperty("fontFeature");
2576     std::string feature;
2577     if (!fontFeature->IsNull() && JSContainerBase::ParseJsString(fontFeature, feature)) {
2578         NG::FONT_FEATURES_LIST fontFeatures = ParseFontFeatureSettings(feature);
2579         updateSpanStyle.updateFontFeature = fontFeatures;
2580         style.SetFontFeatures(fontFeatures);
2581     } else {
2582         auto theme = JSContainerBase::GetTheme<TextTheme>();
2583         CHECK_NULL_VOID(theme);
2584         auto fontFeatures = theme->GetTextStyle().GetFontFeatures();
2585         updateSpanStyle.updateFontFeature = fontFeatures;
2586         style.SetFontFeatures(fontFeatures);
2587     }
2588 }
2589 
ParseJsHalfLeadingTextStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2590 void JSRichEditorBaseController::ParseJsHalfLeadingTextStyle(const JSRef<JSObject>& styleObject,
2591     TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2592 {
2593     JSRef<JSVal> halfLeading = styleObject->GetProperty("halfLeading");
2594     bool isHalfLeading = false;
2595     if (!halfLeading->IsNull() && halfLeading->IsBoolean()) {
2596         isHalfLeading = halfLeading->ToBoolean();
2597         updateSpanStyle.updateHalfLeading = isHalfLeading;
2598         style.SetHalfLeading(isHalfLeading);
2599     }
2600 }
2601 
ParseTextDecoration(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2602 void JSRichEditorBaseController::ParseTextDecoration(
2603     const JSRef<JSObject>& styleObject, TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2604 {
2605     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2606     auto decorationObject = JSObjectCast(styleObject->GetProperty("decoration"));
2607     if (!decorationObject->IsUndefined()) {
2608         JSRef<JSVal> type = decorationObject->GetProperty("type");
2609         if (!type->IsNull() && !type->IsUndefined()) {
2610             updateSpanStyle.updateTextDecoration = static_cast<TextDecoration>(type->ToNumber<int32_t>());
2611             style.SetTextDecoration(static_cast<TextDecoration>(type->ToNumber<int32_t>()));
2612         }
2613         JSRef<JSVal> color = decorationObject->GetProperty("color");
2614         Color decorationColor;
2615         if (!color->IsNull() && JSContainerBase::ParseJsColor(color, decorationColor)) {
2616             updateSpanStyle.updateTextDecorationColor = decorationColor;
2617             style.SetTextDecorationColor(decorationColor);
2618             updateSpanStyle.useThemeDecorationColor = false;
2619         }
2620         JSRef<JSVal> textDecorationStyle = decorationObject->GetProperty("style");
2621         if (!textDecorationStyle->IsNull() && !textDecorationStyle->IsUndefined()) {
2622             updateSpanStyle.updateTextDecorationStyle =
2623                 static_cast<TextDecorationStyle>(textDecorationStyle->ToNumber<int32_t>());
2624             style.SetTextDecorationStyle(static_cast<TextDecorationStyle>(textDecorationStyle->ToNumber<int32_t>()));
2625         }
2626         updateSpanStyle.isInitDecoration = true;
2627     }
2628     if (!updateSpanStyle.updateTextDecorationColor.has_value() && updateSpanStyle.updateTextColor.has_value()) {
2629         updateSpanStyle.updateTextDecorationColor = style.GetTextColor();
2630         style.SetTextDecorationColor(style.GetTextColor());
2631         CHECK_NULL_VOID(Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWENTY));
2632         updateSpanStyle.useThemeDecorationColor = false;
2633     }
2634 }
2635 
ParseTextShadow(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2636 void JSRichEditorBaseController::ParseTextShadow(
2637     const JSRef<JSObject>& styleObject, TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2638 {
2639     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2640     auto shadowObject = styleObject->GetProperty("textShadow");
2641     if (shadowObject->IsNull()) {
2642         return;
2643     }
2644     std::vector<Shadow> shadows;
2645     ParseTextShadowFromShadowObject(shadowObject, shadows);
2646     if (!shadows.empty()) {
2647         updateSpanStyle.updateTextShadows = shadows;
2648         style.SetTextShadows(shadows);
2649     }
2650 }
2651 
ParseTextBackgroundStyle(const JSRef<JSObject> & styleObject,TextStyle & style,struct UpdateSpanStyle & updateSpanStyle)2652 void JSRichEditorBaseController::ParseTextBackgroundStyle(
2653     const JSRef<JSObject>& styleObject, TextStyle& style, struct UpdateSpanStyle& updateSpanStyle)
2654 {
2655     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2656     auto backgroundObject = styleObject->GetProperty("textBackgroundStyle");
2657     CHECK_NULL_VOID(!backgroundObject->IsNull() && !backgroundObject->IsUndefined());
2658     auto textBackgroundValue = JSContainerSpan::ParseTextBackgroundStyle(backgroundObject);
2659     style.SetTextBackgroundStyle(textBackgroundValue);
2660     updateSpanStyle.updateTextBackgroundStyle = textBackgroundValue;
2661 }
2662 
GetTypingStyle(const JSCallbackInfo & info)2663 void JSRichEditorBaseController::GetTypingStyle(const JSCallbackInfo& info)
2664 {
2665     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2666     auto controller = controllerWeak_.Upgrade();
2667     CHECK_NULL_VOID(controller);
2668     auto typingStyle = controller->GetTypingStyle();
2669     auto style = CreateTypingStyleResult(typingStyle.value_or(UpdateSpanStyle()));
2670     info.SetReturnValue(JSRef<JSVal>::Cast(style));
2671 }
2672 
CreateTypingStyleResult(const struct UpdateSpanStyle & typingStyle)2673 JSRef<JSObject> JSRichEditorBaseController::CreateTypingStyleResult(const struct UpdateSpanStyle& typingStyle)
2674 {
2675     auto tyingStyleObj = JSRef<JSObject>::New();
2676     if (typingStyle.updateTextColor.has_value()) {
2677         tyingStyleObj->SetProperty<std::string>("fontColor", typingStyle.updateTextColor.value().ColorToString());
2678     }
2679     if (typingStyle.updateFontSize.has_value()) {
2680         tyingStyleObj->SetProperty<double>("fontSize", typingStyle.updateFontSize.value().ConvertToVp());
2681     }
2682     if (typingStyle.updateItalicFontStyle.has_value()) {
2683         tyingStyleObj->SetProperty<int32_t>(
2684             "fontStyle", static_cast<int32_t>(typingStyle.updateItalicFontStyle.value()));
2685     }
2686     if (typingStyle.updateFontWeight.has_value()) {
2687         tyingStyleObj->SetProperty<int32_t>("fontWeight", static_cast<int32_t>(typingStyle.updateFontWeight.value()));
2688     }
2689     if (typingStyle.updateFontFamily.has_value()) {
2690         std::string family = V2::ConvertFontFamily(typingStyle.updateFontFamily.value());
2691         tyingStyleObj->SetProperty<std::string>("fontFamily", family);
2692     }
2693     if (typingStyle.isInitDecoration) {
2694         tyingStyleObj->SetPropertyObject("decoration", CreateJsDecorationObj(typingStyle));
2695     }
2696     if (typingStyle.updateTextShadows.has_value()) {
2697         tyingStyleObj->SetPropertyObject("textShadows",
2698             JSRichEditor::CreateJsTextShadowObjectArray(typingStyle.updateTextShadows.value()));
2699     }
2700     if (typingStyle.updateLineHeight.has_value()) {
2701         tyingStyleObj->SetProperty<double>("lineHeight", typingStyle.updateLineHeight.value().ConvertToVp());
2702     }
2703     if (typingStyle.updateHalfLeading.has_value()) {
2704         tyingStyleObj->SetProperty<bool>("halfLeading", typingStyle.updateHalfLeading.value());
2705     }
2706     if (typingStyle.updateLetterSpacing.has_value()) {
2707         tyingStyleObj->SetProperty<double>("letterSpacing", typingStyle.updateLetterSpacing.value().ConvertToVp());
2708     }
2709     if (typingStyle.updateFontFeature.has_value()) {
2710         tyingStyleObj->SetProperty<std::string>(
2711             "fontFeature", UnParseFontFeatureSetting(typingStyle.updateFontFeature.value()));
2712     }
2713     if (typingStyle.updateTextBackgroundStyle.has_value()) {
2714         tyingStyleObj->SetPropertyObject("textBackgroundStyle",
2715             JSRichEditor::CreateJsTextBackgroundStyle(typingStyle.updateTextBackgroundStyle.value()));
2716     }
2717 
2718     return tyingStyleObj;
2719 }
2720 
CreateJsDecorationObj(const struct UpdateSpanStyle & typingStyle)2721 JSRef<JSObject> JSRichEditorBaseController::CreateJsDecorationObj(const struct UpdateSpanStyle& typingStyle)
2722 {
2723     JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
2724     if (typingStyle.updateTextDecoration.has_value()) {
2725         decorationObj->SetProperty<int32_t>("type", static_cast<int32_t>(typingStyle.updateTextDecoration.value()));
2726     }
2727     if (typingStyle.updateTextDecorationColor.has_value()) {
2728         decorationObj->SetProperty<std::string>(
2729             "color", typingStyle.updateTextDecorationColor.value().ColorToString());
2730     }
2731     if (typingStyle.updateTextDecorationStyle.has_value()) {
2732         decorationObj->SetProperty<int32_t>("style",
2733             static_cast<int32_t>(typingStyle.updateTextDecorationStyle.value()));
2734     }
2735     return decorationObj;
2736 }
2737 
CloseSelectionMenu()2738 void JSRichEditorBaseController::CloseSelectionMenu()
2739 {
2740     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2741     auto controller = controllerWeak_.Upgrade();
2742     CHECK_NULL_VOID(controller);
2743     controller->CloseSelectionMenu();
2744 }
2745 
IsEditing(const JSCallbackInfo & args)2746 void JSRichEditorBaseController::IsEditing(const JSCallbackInfo& args)
2747 {
2748     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2749     auto controller = controllerWeak_.Upgrade();
2750     CHECK_NULL_VOID(controller);
2751     bool value = controller->IsEditing();
2752     auto runtime = std::static_pointer_cast<ArkJSRuntime>(JsiDeclarativeEngineInstance::GetCurrentRuntime());
2753     args.SetReturnValue(JsiRef<JsiValue>::Make(panda::BooleanRef::New(runtime->GetEcmaVm(), value)));
2754 }
2755 
ToStyledString(const JSCallbackInfo & args)2756 void JSRichEditorController::ToStyledString(const JSCallbackInfo& args)
2757 {
2758     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2759     int32_t end = -1;
2760     int32_t start = -1;
2761     if (args[0]->IsObject()) {
2762         JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
2763         JSRef<JSVal> startVal = obj->GetProperty("start");
2764         JSRef<JSVal> endVal = obj->GetProperty("end");
2765 
2766         if (!startVal->IsNull() && startVal->IsNumber()) {
2767             start = startVal->ToNumber<int32_t>();
2768         }
2769 
2770         if (!endVal->IsNull() && endVal->IsNumber()) {
2771             end = endVal->ToNumber<int32_t>();
2772         }
2773     }
2774     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controllerWeak_.Upgrade());
2775     CHECK_NULL_VOID(richEditorController);
2776     auto spanStringBase = richEditorController->ToStyledString(start, end);
2777     auto spanString = AceType::DynamicCast<SpanString>(spanStringBase);
2778     CHECK_NULL_VOID(spanString);
2779     JSRef<JSObject> obj = JSClass<JSSpanString>::NewInstance();
2780     auto jsSpanString = Referenced::Claim(obj->Unwrap<JSSpanString>());
2781     jsSpanString->SetController(spanString);
2782     args.SetReturnValue(obj);
2783 }
2784 
FromStyledString(const JSCallbackInfo & args)2785 void JSRichEditorController::FromStyledString(const JSCallbackInfo& args)
2786 {
2787     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2788     if ((args.Length() != 1) || !args[0]->IsObject()) {
2789         return;
2790     }
2791     auto* spanString = JSRef<JSObject>::Cast(args[0])->Unwrap<JSSpanString>();
2792     CHECK_NULL_VOID(spanString);
2793     auto spanStringController = spanString->GetController();
2794     CHECK_NULL_VOID(spanStringController);
2795     auto controller = controllerWeak_.Upgrade();
2796     auto richEditorController = AceType::DynamicCast<RichEditorControllerBase>(controller);
2797     CHECK_NULL_VOID(richEditorController);
2798     SelectionInfo value = richEditorController->FromStyledString(spanStringController);
2799     args.SetReturnValue(CreateJSSpansInfo(value));
2800 }
2801 
StopEditing()2802 void JSRichEditorBaseController::StopEditing()
2803 {
2804     auto controller = controllerWeak_.Upgrade();
2805     CHECK_NULL_VOID(controller);
2806     controller->StopEditing();
2807 }
2808 
JSObjectCast(JSRef<JSVal> jsValue)2809 JSRef<JSObject> JSRichEditorBaseController::JSObjectCast(JSRef<JSVal> jsValue)
2810 {
2811     JSRef<JSObject> jsObject;
2812     if (!jsValue->IsObject()) {
2813         return jsObject;
2814     }
2815     return JSRef<JSObject>::Cast(jsValue);
2816 }
2817 
SetSelection(const JSCallbackInfo & args)2818 void JSRichEditorBaseController::SetSelection(const JSCallbackInfo& args)
2819 {
2820     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2821     if (args.Length() < 2) { // 2:At least two parameters
2822         TAG_LOGE(AceLogTag::ACE_RICH_TEXT, "Info length error.");
2823         return;
2824     }
2825     int32_t selectionStart = 0;
2826     int32_t selectionEnd = 0;
2827     JSContainerBase::ParseJsInt32(args[0], selectionStart);
2828     JSContainerBase::ParseJsInt32(args[1], selectionEnd);
2829     auto controller = controllerWeak_.Upgrade();
2830     CHECK_NULL_VOID(controller);
2831     std::optional<SelectionOptions> options = std::nullopt;
2832     ParseJsSelectionOptions(args, options);
2833     controller->SetSelection(selectionStart, selectionEnd, options);
2834 }
2835 
GetLayoutManager(const JSCallbackInfo & args)2836 void JSRichEditorBaseController::GetLayoutManager(const JSCallbackInfo& args)
2837 {
2838     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2839     JSRef<JSObject> obj = JSClass<JSLayoutManager>::NewInstance();
2840     auto jsLayoutManager = Referenced::Claim(obj->Unwrap<JSLayoutManager>());
2841     CHECK_NULL_VOID(jsLayoutManager);
2842     auto controller = controllerWeak_.Upgrade();
2843     CHECK_NULL_VOID(controller);
2844     auto layoutInfoInterface = controller->GetLayoutInfoInterface();
2845     jsLayoutManager->SetLayoutInfoInterface(layoutInfoInterface);
2846     args.SetReturnValue(obj);
2847 }
2848 
ParseJsSelectionOptions(const JSCallbackInfo & args,std::optional<SelectionOptions> & options)2849 void JSRichEditorBaseController::ParseJsSelectionOptions(
2850     const JSCallbackInfo& args, std::optional<SelectionOptions>& options)
2851 {
2852     if (args.Length() < 3) { // 3:Protect operations
2853         return;
2854     }
2855     auto temp = args[2]; // 2:Get the third parameter
2856     if (!temp->IsObject()) {
2857         return;
2858     }
2859     SelectionOptions optionTemp;
2860     JSRef<JSObject> placeholderOptionObject = JSRef<JSObject>::Cast(temp);
2861     JSRef<JSVal> menuPolicy = placeholderOptionObject->GetProperty("menuPolicy");
2862     double tempPolicy = 0.0;
2863     if (!menuPolicy->IsNull() && JSContainerBase::ParseJsDouble(menuPolicy, tempPolicy)) {
2864         if (0 == tempPolicy || 1 == tempPolicy || 2 == tempPolicy) { // 0:DEFAULT, 1:HIDE, 2:SHOW
2865             optionTemp.menuPolicy = static_cast<MenuPolicy>(tempPolicy);
2866             options = optionTemp;
2867         }
2868     }
2869 }
2870 
SetController(const RefPtr<RichEditorBaseControllerBase> & controller)2871 void JSRichEditorStyledStringController::SetController(const RefPtr<RichEditorBaseControllerBase>& controller)
2872 {
2873     JSRichEditorBaseController::SetController(controller);
2874     auto styledStringCache = GetStyledStringCache();
2875     CHECK_NULL_VOID(styledStringCache);
2876     auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2877     CHECK_NULL_VOID(styledStringController);
2878     styledStringController->SetStyledString(styledStringCache);
2879     SetStyledStringCache(nullptr);
2880 }
2881 
GetSelection(const JSCallbackInfo & args)2882 void JSRichEditorStyledStringController::GetSelection(const JSCallbackInfo& args)
2883 {
2884     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2885     auto controller = controllerWeak_.Upgrade();
2886     auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2887     CHECK_NULL_VOID(styledStringController);
2888     SelectionRangeInfo value = styledStringController->GetSelection();
2889     args.SetReturnValue(JSRichEditor::CreateJSSelectionRange(value));
2890 }
2891 
SetStyledString(const JSCallbackInfo & args)2892 void JSRichEditorStyledStringController::SetStyledString(const JSCallbackInfo& args)
2893 {
2894     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2895     if ((args.Length() != 1) || !args[0]->IsObject()) {
2896         return;
2897     }
2898     auto* spanString = JSRef<JSObject>::Cast(args[0])->Unwrap<JSSpanString>();
2899     CHECK_NULL_VOID(spanString);
2900     auto spanStringController = spanString->GetController();
2901     CHECK_NULL_VOID(spanStringController);
2902     auto controller = controllerWeak_.Upgrade();
2903     if (!controller) {
2904         SetStyledStringCache(spanStringController->GetSubSpanString(0, spanStringController->GetLength()));
2905     }
2906     auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2907     CHECK_NULL_VOID(styledStringController);
2908     styledStringController->SetStyledString(spanStringController);
2909 }
2910 
GetStyledString(const JSCallbackInfo & args)2911 void JSRichEditorStyledStringController::GetStyledString(const JSCallbackInfo& args)
2912 {
2913     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2914     auto controller = controllerWeak_.Upgrade();
2915     auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2916     CHECK_NULL_VOID(styledStringController);
2917     auto mutableSpanString = AceType::DynamicCast<MutableSpanString>(styledStringController->GetStyledString());
2918     CHECK_NULL_VOID(mutableSpanString);
2919     JSRef<JSObject> obj = JSClass<JSMutableSpanString>::NewInstance();
2920     auto jsMutableSpanString = Referenced::Claim(obj->Unwrap<JSMutableSpanString>());
2921     CHECK_NULL_VOID(jsMutableSpanString);
2922     jsMutableSpanString->SetController(mutableSpanString);
2923     jsMutableSpanString->SetMutableController(mutableSpanString);
2924     args.SetReturnValue(obj);
2925 }
2926 
OnContentChanged(const JSCallbackInfo & args)2927 void JSRichEditorStyledStringController::OnContentChanged(const JSCallbackInfo& args)
2928 {
2929     ContainerScope scope(instanceId_ < 0 ? Container::CurrentId() : instanceId_);
2930     CHECK_NULL_VOID(args[0]->IsObject());
2931     SetOnWillChange(args);
2932     SetOnDidChange(args);
2933 }
2934 
SetOnWillChange(const JSCallbackInfo & args)2935 void JSRichEditorStyledStringController::SetOnWillChange(const JSCallbackInfo& args)
2936 {
2937     if (!args[0]->IsObject()) {
2938         return;
2939     }
2940     auto paramObject = JSRef<JSObject>::Cast(args[0]);
2941     auto onWillChangeFunc = paramObject->GetProperty("onWillChange");
2942     if (onWillChangeFunc->IsNull() || !onWillChangeFunc->IsFunction()) {
2943         return;
2944     }
2945     auto jsOnWillChangeFunc = AceType::MakeRefPtr<JsEventFunction<NG::StyledStringChangeValue, 1>>(
2946         JSRef<JSFunc>::Cast(onWillChangeFunc), CreateJsOnWillChange);
2947     auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnWillChangeFunc)](
2948                         const NG::StyledStringChangeValue& changeValue) -> bool {
2949         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
2950         auto ret = func->ExecuteWithValue(changeValue);
2951         if (ret->IsBoolean()) {
2952             return ret->ToBoolean();
2953         }
2954         return true;
2955     };
2956     auto controller = controllerWeak_.Upgrade();
2957     auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2958     CHECK_NULL_VOID(styledStringController);
2959     styledStringController->SetOnWillChange(std::move(callback));
2960 }
2961 
SetOnDidChange(const JSCallbackInfo & args)2962 void JSRichEditorStyledStringController::SetOnDidChange(const JSCallbackInfo& args)
2963 {
2964     if (!args[0]->IsObject()) {
2965         return;
2966     }
2967     auto paramObject = JSRef<JSObject>::Cast(args[0]);
2968     auto onDidChangeFunc = paramObject->GetProperty("onDidChange");
2969     if (onDidChangeFunc->IsNull() || !onDidChangeFunc->IsFunction()) {
2970         return;
2971     }
2972     auto jsOnDidChangeFunc = AceType::MakeRefPtr<JsCommonEventFunction<NG::StyledStringChangeValue, 2>>(
2973         JSRef<JSFunc>::Cast(onDidChangeFunc));
2974     auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnDidChangeFunc)](
2975                         const NG::StyledStringChangeValue& changeValue) {
2976         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
2977         const auto& rangeBefore = changeValue.GetRangeBefore();
2978         JSRef<JSObject> rangeBeforeObj = JSRef<JSObject>::New();
2979         rangeBeforeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeBefore.start)));
2980         rangeBeforeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeBefore.end)));
2981 
2982         const auto& rangeAfter = changeValue.GetRangeAfter();
2983         JSRef<JSObject> rangeAfterObj = JSRef<JSObject>::New();
2984         rangeAfterObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeAfter.start)));
2985         rangeAfterObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeAfter.end)));
2986 
2987         JSRef<JSVal> param[2] = { JSRef<JSVal>::Cast(rangeBeforeObj), JSRef<JSVal>::Cast(rangeAfterObj) };
2988         func->Execute(param);
2989     };
2990     auto controller = controllerWeak_.Upgrade();
2991     auto styledStringController = AceType::DynamicCast<RichEditorStyledStringControllerBase>(controller);
2992     CHECK_NULL_VOID(styledStringController);
2993     styledStringController->SetOnDidChange(std::move(callback));
2994 }
2995 
CreateJsOnWillChange(const NG::StyledStringChangeValue & changeValue)2996 JSRef<JSVal> JSRichEditorStyledStringController::CreateJsOnWillChange(const NG::StyledStringChangeValue& changeValue)
2997 {
2998     JSRef<JSObject> onWillChangeObj = JSRef<JSObject>::New();
2999     JSRef<JSObject> rangeObj = JSRef<JSObject>::New();
3000     auto rangeBefore = changeValue.GetRangeBefore();
3001     rangeObj->SetPropertyObject("start", JSRef<JSVal>::Make(ToJSValue(rangeBefore.start)));
3002     rangeObj->SetPropertyObject("end", JSRef<JSVal>::Make(ToJSValue(rangeBefore.end)));
3003     auto spanString = AceType::DynamicCast<SpanString>(changeValue.GetReplacementString());
3004     CHECK_NULL_RETURN(spanString, JSRef<JSVal>::Cast(onWillChangeObj));
3005     JSRef<JSObject> replacementStringObj = JSClass<JSSpanString>::NewInstance();
3006     auto jsSpanString = Referenced::Claim(replacementStringObj->Unwrap<JSSpanString>());
3007     jsSpanString->SetController(spanString);
3008     onWillChangeObj->SetPropertyObject("range", rangeObj);
3009     onWillChangeObj->SetPropertyObject("replacementString", replacementStringObj);
3010     if (changeValue.GetPreviewText()) {
3011         JSRef<JSObject> previewTextObj = JSClass<JSSpanString>::NewInstance();
3012         auto jsPreviewTextSpanString = Referenced::Claim(previewTextObj->Unwrap<JSSpanString>());
3013         jsPreviewTextSpanString->SetController(AceType::DynamicCast<SpanString>(changeValue.GetPreviewText()));
3014         onWillChangeObj->SetPropertyObject("previewText", previewTextObj);
3015     }
3016     return JSRef<JSVal>::Cast(onWillChangeObj);
3017 }
3018 
JSBind(BindingTarget globalObj)3019 void JSRichEditorStyledStringController::JSBind(BindingTarget globalObj)
3020 {
3021     JSClass<JSRichEditorStyledStringController>::Declare("RichEditorStyledStringController");
3022     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3023         "setCaretOffset", &JSRichEditorStyledStringController::SetCaretOffset);
3024     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3025         "getCaretOffset", &JSRichEditorStyledStringController::GetCaretOffset);
3026     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3027         "getCaretRect", &JSRichEditorStyledStringController::GetCaretRect);
3028     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3029         "getTypingStyle", &JSRichEditorStyledStringController::GetTypingStyle);
3030     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3031         "setTypingStyle", &JSRichEditorStyledStringController::SetTypingStyle);
3032     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3033         "getSelection", &JSRichEditorStyledStringController::GetSelection);
3034     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3035         "getPreviewText", &JSRichEditorStyledStringController::GetPreviewTextInfo);
3036     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3037         "setSelection", &JSRichEditorStyledStringController::SetSelection);
3038     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3039         "isEditing", &JSRichEditorStyledStringController::IsEditing);
3040     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3041         "setStyledString", &JSRichEditorStyledStringController::SetStyledString);
3042     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3043         "getStyledString", &JSRichEditorStyledStringController::GetStyledString);
3044     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3045         "onContentChanged", &JSRichEditorStyledStringController::OnContentChanged);
3046     JSClass<JSRichEditorStyledStringController>::CustomMethod(
3047         "getLayoutManager", &JSRichEditorStyledStringController::GetLayoutManager);
3048     JSClass<JSRichEditorStyledStringController>::Method(
3049         "stopEditing", &JSRichEditorStyledStringController::StopEditing);
3050     JSClass<JSRichEditorStyledStringController>::Method(
3051         "closeSelectionMenu", &JSRichEditorStyledStringController::CloseSelectionMenu);
3052     JSClass<JSRichEditorStyledStringController>::Bind(
3053         globalObj, JSRichEditorStyledStringController::Constructor, JSRichEditorStyledStringController::Destructor);
3054 }
3055 
3056 } // namespace OHOS::Ace::Framework
3057