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