• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "bridge/declarative_frontend/jsview/js_richeditor.h"
17 
18 #include <string>
19 
20 #include "base/log/ace_scoring_log.h"
21 #include "bridge/declarative_frontend/jsview/js_textfield.h"
22 #include "core/components_ng/base/view_abstract.h"
23 #include "core/components_ng/pattern/rich_editor/rich_editor_selection.h"
24 #ifdef PIXEL_MAP_SUPPORTED
25 #include "pixel_map.h"
26 #include "pixel_map_napi.h"
27 #endif
28 #include "bridge/common/utils/utils.h"
29 #include "bridge/declarative_frontend/engine/functions/js_function.h"
30 #include "bridge/declarative_frontend/engine/js_converter.h"
31 #include "bridge/declarative_frontend/engine/js_types.h"
32 #include "bridge/declarative_frontend/jsview/js_container_base.h"
33 #include "bridge/declarative_frontend/jsview/js_image.h"
34 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
35 #include "bridge/declarative_frontend/jsview/js_utils.h"
36 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
37 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
38 #include "bridge/declarative_frontend/jsview/models/richeditor_model_impl.h"
39 #include "core/components_ng/pattern/rich_editor/rich_editor_model_ng.h"
40 #include "frameworks/bridge/common/utils/engine_helper.h"
41 
42 namespace OHOS::Ace {
43 std::unique_ptr<RichEditorModel> RichEditorModel::instance_ = nullptr;
44 std::mutex RichEditorModel::mutex_;
GetInstance()45 RichEditorModel* RichEditorModel::GetInstance()
46 {
47     if (!instance_) {
48         std::lock_guard<std::mutex> lock(mutex_);
49         if (!instance_) {
50 #ifdef NG_BUILD
51             instance_.reset(new NG::RichEditorModelNG());
52 #else
53             if (Container::IsCurrentUseNewPipeline()) {
54                 instance_.reset(new NG::RichEditorModelNG());
55             } else {
56                 // empty implementation
57                 instance_.reset(new Framework::RichEditorModelImpl());
58             }
59 #endif
60         }
61     }
62     return instance_.get();
63 }
64 } // namespace OHOS::Ace
65 
66 namespace OHOS::Ace::Framework {
Create(const JSCallbackInfo & info)67 void JSRichEditor::Create(const JSCallbackInfo& info)
68 {
69     JSRichEditorController* jsController = nullptr;
70     if (info[0]->IsObject()) {
71         auto paramObject = JSRef<JSObject>::Cast(info[0]);
72         auto controllerObj = paramObject->GetProperty("controller");
73         if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
74             jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSRichEditorController>();
75         }
76     }
77     RichEditorModel::GetInstance()->Create();
78     RefPtr<RichEditorControllerBase> controller = RichEditorModel::GetInstance()->GetRichEditorController();
79     if (jsController) {
80         jsController->SetController(controller);
81     }
82 }
83 
SetOnReady(const JSCallbackInfo & args)84 void JSRichEditor::SetOnReady(const JSCallbackInfo& args)
85 {
86     if (args.Length() < 1 || !args[0]->IsFunction()) {
87         LOGE("args not function");
88         return;
89     }
90     JsEventCallback<void()> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
91     RichEditorModel::GetInstance()->SetOnReady(callback);
92 }
93 
CreateJSTextStyleResult(const TextStyleResult & textStyleResult)94 JSRef<JSObject> JSRichEditor::CreateJSTextStyleResult(const TextStyleResult& textStyleResult)
95 {
96     JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
97     textStyleObj->SetProperty<std::string>("fontColor", textStyleResult.fontColor);
98     textStyleObj->SetProperty<double>("fontSize", textStyleResult.fontSize);
99     textStyleObj->SetProperty<int32_t>("fontStyle", textStyleResult.fontStyle);
100     textStyleObj->SetProperty<int32_t>("fontWeight", textStyleResult.fontWeight);
101     textStyleObj->SetProperty<std::string>("fontFamily", textStyleResult.fontFamily);
102     JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
103     decorationObj->SetProperty<int32_t>("type", textStyleResult.decorationType);
104     decorationObj->SetProperty<std::string>("color", textStyleResult.decorationColor);
105     textStyleObj->SetPropertyObject("decoration", decorationObj);
106 
107     return textStyleObj;
108 }
109 
CreateJSImageStyleResult(const ImageStyleResult & imageStyleResult)110 JSRef<JSObject> JSRichEditor::CreateJSImageStyleResult(const ImageStyleResult& imageStyleResult)
111 {
112     JSRef<JSObject> imageSpanStyleObj = JSRef<JSObject>::New();
113 
114     JSRef<JSArray> sizeArray = JSRef<JSArray>::New();
115     sizeArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(imageStyleResult.size[0])));
116     sizeArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(imageStyleResult.size[1])));
117     imageSpanStyleObj->SetPropertyObject("size", sizeArray);
118     imageSpanStyleObj->SetProperty<int32_t>("verticalAlign", imageStyleResult.verticalAlign);
119     imageSpanStyleObj->SetProperty<int32_t>("objectFit", imageStyleResult.objectFit);
120 
121     return imageSpanStyleObj;
122 }
123 
CreateJSSpanResultObject(const ResultObject & resultObject)124 JSRef<JSObject> JSRichEditor::CreateJSSpanResultObject(const ResultObject& resultObject)
125 {
126     JSRef<JSArray> offsetArray = JSRef<JSArray>::New();
127     JSRef<JSArray> spanRangeArray = JSRef<JSArray>::New();
128     JSRef<JSObject> spaneRsultObj = JSRef<JSObject>::New();
129     JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
130     offsetArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(resultObject.offsetInSpan[0])));
131     offsetArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(resultObject.offsetInSpan[1])));
132     spanRangeArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(resultObject.spanPosition.spanRange[0])));
133     spanRangeArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(resultObject.spanPosition.spanRange[1])));
134     spanPositionObj->SetProperty<int32_t>("spanIndex", resultObject.spanPosition.spanIndex);
135     spanPositionObj->SetPropertyObject("spanRange", spanRangeArray);
136     spaneRsultObj->SetPropertyObject("offsetInSpan", offsetArray);
137     spaneRsultObj->SetPropertyObject("spanPosition", spanPositionObj);
138     if (resultObject.type == RichEditorSpanType::TYPESPAN) {
139         spaneRsultObj->SetProperty<std::string>("value", resultObject.valueString);
140         spaneRsultObj->SetPropertyObject("textStyle", CreateJSTextStyleResult(resultObject.textStyle));
141     } else if (resultObject.type == RichEditorSpanType::TYPEIMAGE) {
142         if (resultObject.valuePixelMap) {
143 #ifdef PIXEL_MAP_SUPPORTED
144             std::shared_ptr<Media::PixelMap> pixelMap = resultObject.valuePixelMap->GetPixelMapSharedPtr();
145             auto engine = EngineHelper::GetCurrentEngine();
146             if (engine) {
147                 NativeEngine* nativeEngine = engine->GetNativeEngine();
148                 napi_env env = reinterpret_cast<napi_env>(nativeEngine);
149                 napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap);
150                 NativeValue* nativeValue = reinterpret_cast<NativeValue*>(napiValue);
151                 auto jsPixelMap = JsConverter::ConvertNativeValueToJsVal(nativeValue);
152                 spaneRsultObj->SetPropertyObject("valuePixelMap", jsPixelMap);
153             }
154 #endif
155         } else {
156             spaneRsultObj->SetProperty<std::string>("valueResourceStr", resultObject.valueString);
157         }
158         spaneRsultObj->SetPropertyObject("imageStyle", CreateJSImageStyleResult(resultObject.imageStyle));
159     }
160 
161     return spaneRsultObj;
162 }
163 
CreateJSSelection(const RichEditorSelection & selectInfo)164 JSRef<JSVal> JSRichEditor::CreateJSSelection(const RichEditorSelection& selectInfo)
165 {
166     uint32_t idx = 0;
167 
168     JSRef<JSArray> selectionArray = JSRef<JSArray>::New();
169     JSRef<JSArray> spanObjectArray = JSRef<JSArray>::New();
170     JSRef<JSObject> selectionObject = JSRef<JSObject>::New();
171 
172     const std::list<ResultObject>& spanObjectList = selectInfo.GetSelection().resultObjects;
173     for (const ResultObject& spanObject : spanObjectList) {
174         spanObjectArray->SetValueAt(idx++, CreateJSSpanResultObject(spanObject));
175     }
176 
177     selectionArray->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[0])));
178     selectionArray->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(selectInfo.GetSelection().selection[1])));
179 
180     selectionObject->SetPropertyObject("selection", selectionArray);
181     selectionObject->SetPropertyObject("spans", spanObjectArray);
182     return JSRef<JSVal>::Cast(selectionObject);
183 }
184 
SetOnSelect(const JSCallbackInfo & args)185 void JSRichEditor::SetOnSelect(const JSCallbackInfo& args)
186 {
187     if (args.Length() < 1 || !args[0]->IsFunction()) {
188         LOGI("args not function");
189         return;
190     }
191     auto jsSelectFunc =
192         AceType::MakeRefPtr<JsEventFunction<RichEditorSelection, 1>>(JSRef<JSFunc>::Cast(args[0]), CreateJSSelection);
193     auto onSelect = [execCtx = args.GetExecutionContext(), func = std::move(jsSelectFunc)](const BaseEventInfo* info) {
194         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
195         const auto* eventInfo = TypeInfoHelper::DynamicCast<RichEditorSelection>(info);
196         func->Execute(*eventInfo);
197     };
198     NG::RichEditorModelNG::GetInstance()->SetOnSelect(std::move(onSelect));
199 }
SetAboutToIMEInput(const JSCallbackInfo & args)200 void JSRichEditor::SetAboutToIMEInput(const JSCallbackInfo& args)
201 {
202     if (args.Length() < 1 || !args[0]->IsFunction()) {
203         LOGE("args not function");
204         return;
205     }
206     auto jsAboutToIMEInputFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorInsertValue, 1>>(
207         JSRef<JSFunc>::Cast(args[0]), CreateJsAboutToIMEInputObj);
208     auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsAboutToIMEInputFunc)](
209                         const NG::RichEditorInsertValue& insertValue) -> bool {
210         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
211         auto ret = func->ExecuteWithValue(insertValue);
212         if (ret->IsBoolean()) {
213             return ret->ToBoolean();
214         }
215         return true;
216     };
217     RichEditorModel::GetInstance()->SetAboutToIMEInput(std::move(callback));
218 }
219 
SetOnIMEInputComplete(const JSCallbackInfo & args)220 void JSRichEditor::SetOnIMEInputComplete(const JSCallbackInfo& args)
221 {
222     if (args.Length() < 1 || !args[0]->IsFunction()) {
223         LOGE("args not function");
224         return;
225     }
226     auto jsOnIMEInputCompleteFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorAbstractSpanResult, 1>>(
227         JSRef<JSFunc>::Cast(args[0]), CreateJsOnIMEInputComplete);
228     auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsOnIMEInputCompleteFunc)](
229                         const NG::RichEditorAbstractSpanResult& textSpanResult) {
230         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
231         func->Execute(textSpanResult);
232     };
233     RichEditorModel::GetInstance()->SetOnIMEInputComplete(std::move(callback));
234 }
SetAboutToDelete(const JSCallbackInfo & args)235 void JSRichEditor::SetAboutToDelete(const JSCallbackInfo& args)
236 {
237     if (args.Length() < 1 || !args[0]->IsFunction()) {
238         LOGE("args not function");
239         return;
240     }
241     auto jsAboutToDeleteFunc = AceType::MakeRefPtr<JsEventFunction<NG::RichEditorDeleteValue, 1>>(
242         JSRef<JSFunc>::Cast(args[0]), CreateJsAboutToDelet);
243     auto callback = [execCtx = args.GetExecutionContext(), func = std::move(jsAboutToDeleteFunc)](
244                         const NG::RichEditorDeleteValue& deleteValue) -> bool {
245         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, true);
246         auto ret = func->ExecuteWithValue(deleteValue);
247         if (ret->IsBoolean()) {
248             return ret->ToBoolean();
249         }
250         return true;
251     };
252     RichEditorModel::GetInstance()->SetAboutToDelete(std::move(callback));
253 }
254 
SetOnDeleteComplete(const JSCallbackInfo & args)255 void JSRichEditor::SetOnDeleteComplete(const JSCallbackInfo& args)
256 {
257     if (args.Length() < 1 || !args[0]->IsFunction()) {
258         LOGE("args not function");
259         return;
260     }
261     JsEventCallback<void()> callback(args.GetExecutionContext(), JSRef<JSFunc>::Cast(args[0]));
262     RichEditorModel::GetInstance()->SetOnDeleteComplete(callback);
263 }
264 
SetCustomKeyboard(const JSCallbackInfo & args)265 void JSRichEditor::SetCustomKeyboard(const JSCallbackInfo& args)
266 {
267     if (args.Length() > 0 && (args[0]->IsUndefined() || args[0]->IsNull())) {
268         RichEditorModel::GetInstance()->SetCustomKeyboard(nullptr);
269         return;
270     }
271     if (args.Length() < 1 || !args[0]->IsObject()) {
272         return;
273     }
274     std::function<void()> buildFunc;
275     if (JSTextField::ParseJsCustomKeyboardBuilder(args, 0, buildFunc)) {
276         RichEditorModel::GetInstance()->SetCustomKeyboard(std::move(buildFunc));
277     }
278 }
279 
CreateJsAboutToIMEInputObj(const NG::RichEditorInsertValue & insertValue)280 JSRef<JSVal> JSRichEditor::CreateJsAboutToIMEInputObj(const NG::RichEditorInsertValue& insertValue)
281 {
282     JSRef<JSObject> aboutToIMEInputObj = JSRef<JSObject>::New();
283     aboutToIMEInputObj->SetProperty<int32_t>("insertOffset", insertValue.GetInsertOffset());
284     aboutToIMEInputObj->SetProperty<std::string>("insertValue", insertValue.GetInsertValue());
285     return JSRef<JSVal>::Cast(aboutToIMEInputObj);
286 }
287 
CreateJsOnIMEInputComplete(const NG::RichEditorAbstractSpanResult & textSpanResult)288 JSRef<JSVal> JSRichEditor::CreateJsOnIMEInputComplete(const NG::RichEditorAbstractSpanResult& textSpanResult)
289 {
290     JSRef<JSObject> onIMEInputCompleteObj = JSRef<JSObject>::New();
291     JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
292     JSRef<JSArray> spanRange = JSRef<JSArray>::New();
293     JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
294     JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
295     JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
296     spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textSpanResult.GetSpanRangeStart())));
297     spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(textSpanResult.GetSpanRangeEnd())));
298     offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(textSpanResult.OffsetInSpan())));
299     offsetInSpan->SetValueAt(
300         1, JSRef<JSVal>::Make(ToJSValue(textSpanResult.OffsetInSpan() + textSpanResult.GetEraseLength())));
301     spanPositionObj->SetPropertyObject("spanRange", spanRange);
302     spanPositionObj->SetProperty<int32_t>("spanIndex", textSpanResult.GetSpanIndex());
303     decorationObj->SetProperty<TextDecoration>("type", textSpanResult.GetTextDecoration());
304     decorationObj->SetProperty<std::string>("color", textSpanResult.GetColor());
305     textStyleObj->SetProperty<std::string>("fontColor", textSpanResult.GetFontColor());
306     textStyleObj->SetProperty<double>("fontSize", textSpanResult.GetFontSize());
307     textStyleObj->SetProperty<int32_t>("fontStyle", static_cast<int32_t>(textSpanResult.GetFontStyle()));
308     textStyleObj->SetProperty<int32_t>("fontWeight", textSpanResult.GetFontWeight());
309     textStyleObj->SetProperty<std::string>("fontFamily", textSpanResult.GetFontFamily());
310     textStyleObj->SetPropertyObject("decoration", decorationObj);
311     onIMEInputCompleteObj->SetPropertyObject("spanPosition", spanPositionObj);
312     onIMEInputCompleteObj->SetProperty<std::string>("value", textSpanResult.GetValue());
313     onIMEInputCompleteObj->SetPropertyObject("textStyle", textStyleObj);
314     onIMEInputCompleteObj->SetPropertyObject("offsetInSpan", offsetInSpan);
315     return JSRef<JSVal>::Cast(onIMEInputCompleteObj);
316 }
317 
CreateJsAboutToDelet(const NG::RichEditorDeleteValue & deleteValue)318 JSRef<JSVal> JSRichEditor::CreateJsAboutToDelet(const NG::RichEditorDeleteValue& deleteValue)
319 {
320     JSRef<JSObject> AboutToDeletObj = JSRef<JSObject>::New();
321     AboutToDeletObj->SetProperty<int32_t>("offset", deleteValue.GetOffset());
322     AboutToDeletObj->SetProperty<int32_t>(
323         "direction", static_cast<int32_t>(deleteValue.GetRichEditorDeleteDirection()));
324     AboutToDeletObj->SetProperty<int32_t>("length", deleteValue.GetLength());
325     JSRef<JSArray> richEditorDeleteSpans = JSRef<JSArray>::New();
326     auto list = deleteValue.GetRichEditorDeleteSpans();
327     int32_t index = 0;
328     for (const auto& it : list) {
329         JSRef<JSObject> spanResultObj = JSRef<JSObject>::New();
330         JSRef<JSObject> spanPositionObj = JSRef<JSObject>::New();
331         JSRef<JSArray> spanRange = JSRef<JSArray>::New();
332         JSRef<JSArray> offsetInSpan = JSRef<JSArray>::New();
333         spanRange->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeStart())));
334         spanRange->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.GetSpanRangeEnd())));
335         offsetInSpan->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan())));
336         offsetInSpan->SetValueAt(1, JSRef<JSVal>::Make(ToJSValue(it.OffsetInSpan() + it.GetEraseLength())));
337         spanPositionObj->SetPropertyObject("spanRange", spanRange);
338         spanPositionObj->SetProperty<int32_t>("spanIndex", it.GetSpanIndex());
339         spanResultObj->SetPropertyObject("spanPosition", spanPositionObj);
340         spanResultObj->SetPropertyObject("offsetInSpan", offsetInSpan);
341         switch (it.GetType()) {
342             case NG::SpanResultType::TEXT: {
343                 JSRef<JSObject> textStyleObj = JSRef<JSObject>::New();
344                 CreateTextStyleObj(textStyleObj, it);
345                 spanResultObj->SetProperty<std::string>("value", it.GetValue());
346                 spanResultObj->SetPropertyObject("textStyle", textStyleObj);
347                 break;
348             }
349             case NG::SpanResultType::IMAGE: {
350                 JSRef<JSObject> imageStyleObj = JSRef<JSObject>::New();
351                 CreateImageStyleObj(imageStyleObj, spanResultObj, it);
352                 spanResultObj->SetPropertyObject("imageStyle", imageStyleObj);
353                 break;
354             }
355             default:
356                 break;
357         }
358         richEditorDeleteSpans->SetValueAt(index++, spanResultObj);
359     }
360     AboutToDeletObj->SetPropertyObject("richEditorDeleteSpans", richEditorDeleteSpans);
361     return JSRef<JSVal>::Cast(AboutToDeletObj);
362 }
363 
CreateTextStyleObj(JSRef<JSObject> & textStyleObj,const NG::RichEditorAbstractSpanResult & spanResult)364 void JSRichEditor::CreateTextStyleObj(JSRef<JSObject>& textStyleObj, const NG::RichEditorAbstractSpanResult& spanResult)
365 {
366     JSRef<JSObject> decorationObj = JSRef<JSObject>::New();
367     decorationObj->SetProperty<TextDecoration>("type", spanResult.GetTextDecoration());
368     decorationObj->SetProperty<std::string>("color", spanResult.GetColor());
369     textStyleObj->SetProperty<std::string>("fontColor", spanResult.GetFontColor());
370     textStyleObj->SetProperty<double>("fontSize", spanResult.GetFontSize());
371     textStyleObj->SetProperty<int32_t>("fontStyle", static_cast<int32_t>(spanResult.GetFontStyle()));
372     textStyleObj->SetProperty<int32_t>("fontWeight", spanResult.GetFontWeight());
373     textStyleObj->SetProperty<std::string>("fontFamily", spanResult.GetFontFamily());
374     textStyleObj->SetPropertyObject("decoration", decorationObj);
375 }
376 
CreateImageStyleObj(JSRef<JSObject> & imageStyleObj,JSRef<JSObject> & spanResultObj,const NG::RichEditorAbstractSpanResult & spanResult)377 void JSRichEditor::CreateImageStyleObj(
378     JSRef<JSObject>& imageStyleObj, JSRef<JSObject>& spanResultObj, const NG::RichEditorAbstractSpanResult& spanResult)
379 {
380     JSRef<JSArray> imageSize = JSRef<JSArray>::New();
381     imageSize->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(spanResult.GetSizeWidth())));
382     imageSize->SetValueAt(0, JSRef<JSVal>::Make(ToJSValue(spanResult.GetSizeHeight())));
383     imageStyleObj->SetPropertyObject("size", imageSize);
384     imageStyleObj->SetProperty<int32_t>("verticalAlign", static_cast<int32_t>(spanResult.GetVerticalAlign()));
385     imageStyleObj->SetProperty<int32_t>("objectFit", static_cast<int32_t>(spanResult.GetObjectFit()));
386     if (spanResult.GetValuePixelMap()) {
387 #ifdef PIXEL_MAP_SUPPORTED
388         std::shared_ptr<Media::PixelMap> pixelMap = spanResult.GetValuePixelMap()->GetPixelMapSharedPtr();
389         auto engine = EngineHelper::GetCurrentEngine();
390         if (engine) {
391             NativeEngine* nativeEngine = engine->GetNativeEngine();
392             napi_env env = reinterpret_cast<napi_env>(nativeEngine);
393             napi_value napiValue = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap);
394             NativeValue* nativeValue = reinterpret_cast<NativeValue*>(napiValue);
395             auto jsPixelMap = JsConverter::ConvertNativeValueToJsVal(nativeValue);
396             spanResultObj->SetPropertyObject("value", jsPixelMap);
397         }
398 #endif
399     } else {
400         spanResultObj->SetProperty<std::string>("valueResourceStr", spanResult.GetValueResourceStr());
401     }
402 }
403 
JsFocusable(const JSCallbackInfo & info)404 void JSRichEditor::JsFocusable(const JSCallbackInfo& info)
405 {
406     if (info.Length() != 1 || !info[0]->IsBoolean()) {
407         LOGW("The info is wrong, it is supposed to be an boolean");
408         return;
409     }
410     JSInteractableView::SetFocusable(info[0]->ToBoolean());
411     JSInteractableView::SetFocusNode(false);
412 }
413 
SetCopyOptions(const JSCallbackInfo & info)414 void JSRichEditor::SetCopyOptions(const JSCallbackInfo& info)
415 {
416     if (info.Length() == 0) {
417         return;
418     }
419     auto copyOptions = CopyOptions::Distributed;
420     auto tmpInfo = info[0];
421     if (tmpInfo->IsNumber()) {
422         auto emunNumber = tmpInfo->ToNumber<int>();
423         copyOptions = static_cast<CopyOptions>(emunNumber);
424     }
425     RichEditorModel::GetInstance()->SetCopyOption(copyOptions);
426 }
427 
BindSelectionMenu(const JSCallbackInfo & info)428 void JSRichEditor::BindSelectionMenu(const JSCallbackInfo& info)
429 {
430     RichEditorType editorType = RichEditorType::TEXT;
431     if (info.Length() >= 1 && info[0]->IsNumber()) {
432         auto spanType = info[0]->ToNumber<int32_t>();
433         LOGI("Set the spanType is %{public}d.", spanType);
434         editorType = static_cast<RichEditorType>(spanType);
435     }
436 
437     // Builder
438     if (info.Length() < 2 || !info[1]->IsObject()) {
439         return;
440     }
441 
442     JSRef<JSObject> menuObj = JSRef<JSObject>::Cast(info[1]);
443     auto builder = menuObj->GetProperty("builder");
444     if (!builder->IsFunction()) {
445         LOGE("builder param is not a function.");
446         return;
447     }
448     auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(builder));
449     CHECK_NULL_VOID(builderFunc);
450 
451     // responseType
452     ResponseType responseType = ResponseType::LONG_PRESS;
453     if (info.Length() >= 3 && info[2]->IsNumber()) {
454         auto response = info[2]->ToNumber<int32_t>();
455         LOGI("Set the responseType is %{public}d.", response);
456         responseType = static_cast<ResponseType>(response);
457     }
458     std::function<void()> buildFunc = [execCtx = info.GetExecutionContext(), func = std::move(builderFunc)]() {
459         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
460         ACE_SCORING_EVENT("BindSelectionMenu");
461         func->Execute();
462     };
463     SelectMenuParam menuParam;
464     if (info.Length() > 3 && info[3]->IsObject()) {
465         ParseMenuParam(info, info[3], menuParam);
466     }
467     RichEditorModel::GetInstance()->BindSelectionMenu(editorType, responseType, buildFunc, menuParam);
468 }
469 
ParseMenuParam(const JSCallbackInfo & info,const JSRef<JSObject> & menuOptions,SelectMenuParam & menuParam)470 void JSRichEditor::ParseMenuParam(
471     const JSCallbackInfo& info, const JSRef<JSObject>& menuOptions, SelectMenuParam& menuParam)
472 {
473     auto onAppearValue = menuOptions->GetProperty("onAppear");
474     if (onAppearValue->IsFunction()) {
475         RefPtr<JsFunction> jsOnAppearFunc =
476             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAppearValue));
477         auto onAppear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnAppearFunc)](
478                             int32_t start, int32_t end) {
479             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
480             ACE_SCORING_EVENT("onAppear");
481 
482             JSRef<JSVal> params[2];
483             params[0] = JSRef<JSVal>::Make(ToJSValue(start));
484             params[1] = JSRef<JSVal>::Make(ToJSValue(end));
485             func->ExecuteJS(2, params);
486         };
487         menuParam.onAppear = std::move(onAppear);
488     }
489 
490     auto onDisappearValue = menuOptions->GetProperty("onDisappear");
491     if (onDisappearValue->IsFunction()) {
492         RefPtr<JsFunction> jsOnDisAppearFunc =
493             AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDisappearValue));
494         auto onDisappear = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDisAppearFunc)]() {
495             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
496             LOGI("About to call onAppear method on js");
497             ACE_SCORING_EVENT("onDisappear");
498             func->Execute();
499         };
500         menuParam.onDisappear = std::move(onDisappear);
501     }
502 }
503 
JSBind(BindingTarget globalObj)504 void JSRichEditor::JSBind(BindingTarget globalObj)
505 {
506     JSClass<JSRichEditor>::Declare("RichEditor");
507     JSClass<JSRichEditor>::StaticMethod("create", &JSRichEditor::Create);
508     JSClass<JSRichEditor>::StaticMethod("onReady", &JSRichEditor::SetOnReady);
509     JSClass<JSRichEditor>::StaticMethod("onSelect", &JSRichEditor::SetOnSelect);
510     JSClass<JSRichEditor>::StaticMethod("aboutToIMEInput", &JSRichEditor::SetAboutToIMEInput);
511     JSClass<JSRichEditor>::StaticMethod("onIMEInputComplete", &JSRichEditor::SetOnIMEInputComplete);
512     JSClass<JSRichEditor>::StaticMethod("aboutToDelete", &JSRichEditor::SetAboutToDelete);
513     JSClass<JSRichEditor>::StaticMethod("onDeleteComplete", &JSRichEditor::SetOnDeleteComplete);
514     JSClass<JSRichEditor>::StaticMethod("customKeyboard", &JSRichEditor::SetCustomKeyboard);
515     JSClass<JSRichEditor>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
516     JSClass<JSRichEditor>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
517     JSClass<JSRichEditor>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
518     JSClass<JSRichEditor>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
519     JSClass<JSRichEditor>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
520     JSClass<JSRichEditor>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
521     JSClass<JSRichEditor>::StaticMethod("focusable", &JSRichEditor::JsFocusable);
522     JSClass<JSRichEditor>::StaticMethod("copyOptions", &JSRichEditor::SetCopyOptions);
523     JSClass<JSRichEditor>::StaticMethod("bindSelectionMenu", &JSRichEditor::BindSelectionMenu);
524     JSClass<JSRichEditor>::InheritAndBind<JSViewAbstract>(globalObj);
525 }
526 
ParseJsImageSpanAttribute(JSRef<JSObject> imageAttribute)527 ImageSpanAttribute JSRichEditorController::ParseJsImageSpanAttribute(JSRef<JSObject> imageAttribute)
528 {
529     ImageSpanAttribute imageStyle;
530     auto sizeObj = imageAttribute->GetProperty("size");
531     if (sizeObj->IsArray()) {
532         ImageSpanSize imageSize;
533         JSRef<JSArray> size = JSRef<JSArray>::Cast(sizeObj);
534         JSRef<JSVal> width = size->GetValueAt(0);
535         CalcDimension imageSpanWidth;
536         if (!width->IsNull() && JSContainerBase::ParseJsDimensionVp(width, imageSpanWidth)) {
537             imageSize.width = imageSpanWidth;
538             updateSpanStyle_.updateImageWidth = imageSpanWidth;
539         }
540         JSRef<JSVal> height = size->GetValueAt(1);
541         CalcDimension imageSpanHeight;
542         if (!height->IsNull() && JSContainerBase::ParseJsDimensionVp(height, imageSpanHeight)) {
543             imageSize.height = imageSpanHeight;
544             updateSpanStyle_.updateImageHeight = imageSpanHeight;
545         }
546         imageStyle.size = imageSize;
547     }
548     JSRef<JSVal> verticalAlign = imageAttribute->GetProperty("verticalAlign");
549     if (!verticalAlign->IsNull()) {
550         auto align = static_cast<VerticalAlign>(verticalAlign->ToNumber<int32_t>());
551         if (align < VerticalAlign::TOP || align > VerticalAlign::NONE) {
552             align = VerticalAlign::BOTTOM;
553         }
554         imageStyle.verticalAlign = align;
555         updateSpanStyle_.updateImageVerticalAlign = align;
556     }
557     JSRef<JSVal> objectFit = imageAttribute->GetProperty("objectFit");
558     if (!objectFit->IsNull() && objectFit->IsNumber()) {
559         auto fit = static_cast<ImageFit>(objectFit->ToNumber<int32_t>());
560         if (fit < ImageFit::FILL || fit > ImageFit::SCALE_DOWN) {
561             fit = ImageFit::COVER;
562         }
563         imageStyle.objectFit = fit;
564         updateSpanStyle_.updateImageFit = fit;
565     } else {
566         imageStyle.objectFit = ImageFit::COVER;
567     }
568     return imageStyle;
569 }
570 
ParseJsTextStyle(JSRef<JSObject> styleObject,struct UpdateSpanStyle & updateSpanStyle)571 TextStyle JSRichEditorController::ParseJsTextStyle(JSRef<JSObject> styleObject, struct UpdateSpanStyle& updateSpanStyle)
572 {
573     TextStyle style;
574     JSRef<JSVal> fontColor = styleObject->GetProperty("fontColor");
575     Color textColor;
576     if (!fontColor->IsNull() && JSContainerBase::ParseJsColor(fontColor, textColor)) {
577         updateSpanStyle.updateTextColor = textColor;
578         style.SetTextColor(textColor);
579     }
580     JSRef<JSVal> fontSize = styleObject->GetProperty("fontSize");
581     CalcDimension size;
582     if (!fontSize->IsNull() && JSContainerBase::ParseJsDimensionFp(fontSize, size)) {
583         updateSpanStyle.updateFontSize = size;
584         style.SetFontSize(size);
585     }
586     JSRef<JSVal> fontStyle = styleObject->GetProperty("fontStyle");
587     if (!fontStyle->IsNull() && fontStyle->IsNumber()) {
588         updateSpanStyle.updateItalicFontStyle = static_cast<FontStyle>(fontStyle->ToNumber<int32_t>());
589         style.SetFontStyle(static_cast<FontStyle>(fontStyle->ToNumber<int32_t>()));
590     }
591     JSRef<JSVal> fontWeight = styleObject->GetProperty("fontWeight");
592     std::string weight;
593     if (!fontWeight->IsNull() && (fontWeight->IsNumber() || JSContainerBase::ParseJsString(fontWeight, weight))) {
594         if (fontWeight->IsNumber()) {
595             weight = std::to_string(fontWeight->ToNumber<int32_t>());
596         }
597         updateSpanStyle.updateFontWeight = ConvertStrToFontWeight(weight);
598         style.SetFontWeight(ConvertStrToFontWeight(weight));
599     }
600     JSRef<JSVal> fontFamily = styleObject->GetProperty("fontFamily");
601     std::vector<std::string> family;
602     if (!fontFamily->IsNull() && JSContainerBase::ParseJsFontFamilies(fontFamily, family)) {
603         updateSpanStyle.updateFontFamily = family;
604         style.SetFontFamilies(family);
605     }
606     auto decorationObj = styleObject->GetProperty("decoration");
607     JSRef<JSObject> decorationObject = JSRef<JSObject>::Cast(decorationObj);
608     if (!decorationObject->IsUndefined()) {
609         JSRef<JSVal> type = decorationObject->GetProperty("type");
610         if (!type->IsNull() && !type->IsUndefined()) {
611             updateSpanStyle.updateTextDecoration = static_cast<TextDecoration>(type->ToNumber<int32_t>());
612             style.SetTextDecoration(static_cast<TextDecoration>(type->ToNumber<int32_t>()));
613         }
614         JSRef<JSVal> color = decorationObject->GetProperty("color");
615         Color decorationColor;
616         if (!color->IsNull() && JSContainerBase::ParseJsColor(color, decorationColor)) {
617             updateSpanStyle.updateTextDecorationColor = decorationColor;
618             style.SetTextDecorationColor(decorationColor);
619         }
620     }
621     return style;
622 }
623 
AddImageSpan(const JSCallbackInfo & args)624 void JSRichEditorController::AddImageSpan(const JSCallbackInfo& args)
625 {
626     if (args.Length() < 1) {
627         return;
628     }
629     ImageSpanOptions options;
630     if (!args[0]->IsEmpty() && args[0]->ToString() != "") {
631         options = CreateJsImageOptions(args);
632     } else {
633         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
634         return;
635     }
636     if (options.image.has_value()) {
637         std::string assetSrc = options.image.value();
638         SrcType srcType = ImageSourceInfo::ResolveURIType(assetSrc);
639         if (assetSrc[0] == '/') {
640             assetSrc = assetSrc.substr(1); // get the asset src without '/'.
641         } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
642             assetSrc = assetSrc.substr(2); // get the asset src without './'.
643         }
644         if (srcType == SrcType::ASSET) {
645             auto pipelineContext = PipelineBase::GetCurrentContext();
646             CHECK_NULL_VOID(pipelineContext);
647             auto assetManager = pipelineContext->GetAssetManager();
648             CHECK_NULL_VOID(assetManager);
649             auto assetData = assetManager->GetAsset(assetSrc);
650             if (!assetData) {
651                 args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
652                 return;
653             }
654         }
655     }
656     if (args.Length() > 1 && args[1]->IsObject()) {
657         JSRef<JSObject> imageObject = JSRef<JSObject>::Cast(args[1]);
658 
659         JSRef<JSVal> offset = imageObject->GetProperty("offset");
660         int32_t imageOffset = 0;
661         if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, imageOffset)) {
662             options.offset = imageOffset;
663         }
664         auto imageStyleObj = imageObject->GetProperty("imageStyle");
665         JSRef<JSObject> imageAttribute = JSRef<JSObject>::Cast(imageStyleObj);
666         if (!imageAttribute->IsUndefined()) {
667             ImageSpanAttribute imageStyle = ParseJsImageSpanAttribute(imageAttribute);
668             options.imageAttribute = imageStyle;
669         }
670     }
671     auto controller = controllerWeak_.Upgrade();
672     int32_t spanIndex = 0;
673     if (controller) {
674         spanIndex = controller->AddImageSpan(options);
675     }
676     args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
677 }
678 
CreateJsImageOptions(const JSCallbackInfo & args)679 ImageSpanOptions JSRichEditorController::CreateJsImageOptions(const JSCallbackInfo& args)
680 {
681     ImageSpanOptions options;
682     auto context = PipelineBase::GetCurrentContext();
683     CHECK_NULL_RETURN(context, options);
684     bool isCard = context->IsFormRender();
685     std::string image;
686     std::string bundleName;
687     std::string moduleName;
688     bool srcValid = JSContainerBase::ParseJsMedia(args[0], image);
689     if (isCard && args[0]->IsString()) {
690         SrcType srcType = ImageSourceInfo::ResolveURIType(image);
691         bool notSupport = (srcType == SrcType::NETWORK || srcType == SrcType::FILE || srcType == SrcType::DATA_ABILITY);
692         if (notSupport) {
693             image.clear();
694         }
695     }
696     JSImage::GetJsMediaBundleInfo(args[0], bundleName, moduleName);
697     options.image = image;
698     options.bundleName = bundleName;
699     options.moduleName = moduleName;
700     if (!srcValid) {
701 #if defined(PIXEL_MAP_SUPPORTED)
702         if (!isCard) {
703             if (IsDrawable(args[0])) {
704                 options.imagePixelMap = GetDrawablePixmap(args[0]);
705             } else {
706                 options.imagePixelMap = CreatePixelMapFromNapiValue(args[0]);
707             }
708         }
709 #endif
710     }
711     return options;
712 }
713 
IsDrawable(const JSRef<JSVal> & jsValue)714 bool JSRichEditorController::IsDrawable(const JSRef<JSVal>& jsValue)
715 {
716     if (!jsValue->IsObject()) {
717         return false;
718     }
719     JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(jsValue);
720     if (jsObj->IsUndefined()) {
721         return false;
722     }
723     JSRef<JSVal> func = jsObj->GetProperty("getPixelMap");
724     return (!func->IsNull() && func->IsFunction());
725 }
726 
AddTextSpan(const JSCallbackInfo & args)727 void JSRichEditorController::AddTextSpan(const JSCallbackInfo& args)
728 {
729     if (args.Length() < 1) {
730         return;
731     }
732     TextSpanOptions options;
733     std::string spanValue;
734     if (!args[0]->IsEmpty() && args[0]->ToString() != "" && JSContainerBase::ParseJsString(args[0], spanValue)) {
735         options.value = spanValue;
736     } else {
737         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(-1)));
738         return;
739     }
740     if (args.Length() > 1 && args[1]->IsObject()) {
741         JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[1]);
742         JSRef<JSVal> offset = spanObject->GetProperty("offset");
743         int32_t spanOffset = 0;
744         if (!offset->IsNull() && JSContainerBase::ParseJsInt32(offset, spanOffset)) {
745             options.offset = spanOffset;
746         }
747         auto styleObj = spanObject->GetProperty("style");
748         JSRef<JSObject> styleObject = JSRef<JSObject>::Cast(styleObj);
749         if (!styleObject->IsUndefined()) {
750             TextStyle style = ParseJsTextStyle(styleObject, updateSpanStyle_);
751             options.style = style;
752         }
753     }
754     auto controller = controllerWeak_.Upgrade();
755     int32_t spanIndex = 0;
756     if (controller) {
757         spanIndex = controller->AddTextSpan(options);
758     }
759     args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(spanIndex)));
760 }
761 
CreateCreateJSSpansInfo(const RichEditorSelection & info)762 JSRef<JSVal> JSRichEditorController::CreateCreateJSSpansInfo(const RichEditorSelection& info)
763 {
764     uint32_t idx = 0;
765 
766     JSRef<JSArray> spanObjectArray = JSRef<JSArray>::New();
767     JSRef<JSObject> selectionObject = JSRef<JSObject>::New();
768 
769     const std::list<ResultObject>& spanObjectList = info.GetSelection().resultObjects;
770     for (const ResultObject& spanObject : spanObjectList) {
771         spanObjectArray->SetValueAt(idx++, JSRichEditor::CreateJSSpanResultObject(spanObject));
772     }
773 
774     return JSRef<JSVal>::Cast(spanObjectArray);
775 }
776 
GetSpansInfo(const JSCallbackInfo & args)777 void JSRichEditorController::GetSpansInfo(const JSCallbackInfo& args)
778 {
779     int32_t end = -1;
780     int32_t start = -1;
781     if (args[0]->IsObject()) {
782         JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
783         JSRef<JSVal> startVal = obj->GetProperty("start");
784         JSRef<JSVal> endVal = obj->GetProperty("end");
785 
786         if (!startVal->IsNull() && startVal->IsNumber()) {
787             start = startVal->ToNumber<int32_t>();
788         }
789 
790         if (!endVal->IsNull() && endVal->IsNumber()) {
791             end = endVal->ToNumber<int32_t>();
792         }
793     }
794     if (controllerWeak_.Upgrade()) {
795         RichEditorSelection value = controllerWeak_.Upgrade()->GetSpansInfo(start, end);
796         args.SetReturnValue(CreateCreateJSSpansInfo(value));
797     }
798 }
799 
DeleteSpans(const JSCallbackInfo & args)800 void JSRichEditorController::DeleteSpans(const JSCallbackInfo& args)
801 {
802     auto controller = controllerWeak_.Upgrade();
803     CHECK_NULL_VOID(controller);
804     if (!args[0]->IsObject() || !controller) {
805         return;
806     }
807     JSRef<JSObject> spanObject = JSRef<JSObject>::Cast(args[0]);
808     RangeOptions options;
809     JSRef<JSVal> startVal = spanObject->GetProperty("start");
810     int32_t start = 0;
811     if (!startVal->IsNull() && JSContainerBase::ParseJsInt32(startVal, start)) {
812         options.start = start;
813     }
814     JSRef<JSVal> endVal = spanObject->GetProperty("end");
815     int32_t end = 0;
816     if (!startVal->IsNull() && JSContainerBase::ParseJsInt32(endVal, end)) {
817         options.end = end;
818     }
819     controller->DeleteSpans(options);
820 }
821 
CloseSelectionMenu()822 void JSRichEditorController::CloseSelectionMenu()
823 {
824     auto controller = controllerWeak_.Upgrade();
825     CHECK_NULL_VOID(controller);
826     controller->CloseSelectionMenu();
827 }
828 
JSBind(BindingTarget globalObj)829 void JSRichEditorController::JSBind(BindingTarget globalObj)
830 {
831     JSClass<JSRichEditorController>::Declare("RichEditorController");
832     JSClass<JSRichEditorController>::CustomMethod("addImageSpan", &JSRichEditorController::AddImageSpan);
833     JSClass<JSRichEditorController>::CustomMethod("addTextSpan", &JSRichEditorController::AddTextSpan);
834     JSClass<JSRichEditorController>::CustomMethod("setCaretOffset", &JSRichEditorController::SetCaretOffset);
835     JSClass<JSRichEditorController>::CustomMethod("getCaretOffset", &JSRichEditorController::GetCaretOffset);
836     JSClass<JSRichEditorController>::CustomMethod("updateSpanStyle", &JSRichEditorController::UpdateSpanStyle);
837     JSClass<JSRichEditorController>::CustomMethod("setTypingStyle", &JSRichEditorController::SetTypingStyle);
838     JSClass<JSRichEditorController>::CustomMethod("getSpans", &JSRichEditorController::GetSpansInfo);
839     JSClass<JSRichEditorController>::CustomMethod("deleteSpans", &JSRichEditorController::DeleteSpans);
840     JSClass<JSRichEditorController>::Method("closeSelectionMenu", &JSRichEditorController::CloseSelectionMenu);
841     JSClass<JSRichEditorController>::Bind(
842         globalObj, JSRichEditorController::Constructor, JSRichEditorController::Destructor);
843 }
844 
GetCaretOffset(const JSCallbackInfo & args)845 void JSRichEditorController::GetCaretOffset(const JSCallbackInfo& args)
846 {
847     auto controller = controllerWeak_.Upgrade();
848     int32_t caretOffset = -1;
849     if (controller) {
850         caretOffset = controller->GetCaretOffset();
851         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(caretOffset)));
852     } else {
853         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(caretOffset)));
854     }
855 }
856 
SetCaretOffset(const JSCallbackInfo & args)857 void JSRichEditorController::SetCaretOffset(const JSCallbackInfo& args)
858 {
859     auto controller = controllerWeak_.Upgrade();
860     int32_t caretPosition = -1;
861     bool success = false;
862     JSViewAbstract::ParseJsInteger<int32_t>(args[0], caretPosition);
863     caretPosition = caretPosition < 0 ? -1 : caretPosition;
864     if (controller) {
865         success = controller->SetCaretOffset(caretPosition);
866         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(success)));
867     } else {
868         args.SetReturnValue(JSRef<JSVal>::Make(ToJSValue(success)));
869     }
870 }
871 
UpdateSpanStyle(const JSCallbackInfo & info)872 void JSRichEditorController::UpdateSpanStyle(const JSCallbackInfo& info)
873 {
874     if (info.Length() < 1) {
875         LOGW("The argv is wrong, it is supposed to have at least 1 argument");
876         return;
877     }
878     if (!info[0]->IsNumber() && !info[0]->IsObject()) {
879         LOGW("info[0] not is Object or Number");
880         return;
881     }
882     auto jsObject = JSRef<JSObject>::Cast(info[0]);
883 
884     int32_t start = -1;
885     int32_t end = -1;
886     TextStyle textStyle;
887     ImageSpanAttribute imageStyle;
888     JSContainerBase::ParseJsInt32(jsObject->GetProperty("start"), start);
889     JSContainerBase::ParseJsInt32(jsObject->GetProperty("end"), end);
890     auto richEditorTextStyle = JSRef<JSObject>::Cast(jsObject->GetProperty("textStyle"));
891     auto richEditorImageStyle = JSRef<JSObject>::Cast(jsObject->GetProperty("imageStyle"));
892     updateSpanStyle_.ResetStyle();
893     if (!richEditorTextStyle->IsUndefined()) {
894         textStyle = ParseJsTextStyle(richEditorTextStyle, updateSpanStyle_);
895     }
896     if (!richEditorImageStyle->IsUndefined()) {
897         imageStyle = ParseJsImageSpanAttribute(richEditorImageStyle);
898     }
899 
900     auto controller = controllerWeak_.Upgrade();
901     if (controller) {
902         controller->SetUpdateSpanStyle(updateSpanStyle_);
903         controller->UpdateSpanStyle(start, end, textStyle, imageStyle);
904     }
905 }
906 
SetTypingStyle(const JSCallbackInfo & info)907 void JSRichEditorController::SetTypingStyle(const JSCallbackInfo& info)
908 {
909     auto controller = controllerWeak_.Upgrade();
910     CHECK_NULL_VOID(controller);
911     if (info.Length() < 1) {
912         LOGW("The argv is wrong, it is supposed to have at least 1 argument");
913         return;
914     }
915     if (!info[0]->IsObject()) {
916         LOGW("info[0] not is Object");
917         return;
918     }
919     TextStyle textStyle;
920     JSRef<JSObject> richEditorTextStyle = JSRef<JSObject>::Cast(info[0]);
921     typingStyle_.ResetStyle();
922     if (!richEditorTextStyle->IsUndefined()) {
923         textStyle = ParseJsTextStyle(richEditorTextStyle, typingStyle_);
924     }
925     controller->SetTypingStyle(typingStyle_, textStyle);
926 }
927 } // namespace OHOS::Ace::Framework
928