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