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