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