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