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