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