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