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