/* * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "frameworks/bridge/declarative_frontend/jsview/js_span.h" #include "frameworks/bridge/declarative_frontend/jsview/js_container_span.h" #include #include #include #include #if !defined(PREVIEW) && defined(OHOS_PLATFORM) #include "interfaces/inner_api/ui_session/ui_session_manager.h" #endif #include "base/geometry/dimension.h" #include "base/log/ace_scoring_log.h" #include "base/log/ace_trace.h" #include "base/utils/utils.h" #include "bridge/common/utils/utils.h" #include "bridge/declarative_frontend/engine/functions/js_click_function.h" #include "bridge/declarative_frontend/jsview/js_interactable_view.h" #include "bridge/declarative_frontend/jsview/js_utils.h" #include "bridge/declarative_frontend/jsview/js_view_abstract.h" #include "bridge/declarative_frontend/jsview/models/span_model_impl.h" #include "bridge/declarative_frontend/jsview/models/text_model_impl.h" #include "bridge/declarative_frontend/jsview/js_view_common_def.h" #ifndef NG_BUILD #include "bridge/declarative_frontend/view_stack_processor.h" #endif #include "bridge/declarative_frontend/jsview/js_text.h" #include "core/common/container.h" #include "core/components_ng/pattern/text/span_model.h" #include "core/components_ng/pattern/text/span_model_ng.h" #include "core/components_ng/pattern/text/text_model.h" namespace OHOS::Ace { std::unique_ptr SpanModel::instance_ = nullptr; std::mutex SpanModel::mutex_; SpanModel* SpanModel::GetInstance() { #ifdef NG_BUILD static NG::SpanModelNG instance; return &instance; #else if (Container::IsCurrentUseNewPipeline()) { static NG::SpanModelNG instance; return &instance; } else { static Framework::SpanModelImpl instance; return &instance; } #endif } } // namespace OHOS::Ace namespace OHOS::Ace::Framework { namespace { const std::vector FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC }; const std::vector TEXT_CASES = { TextCase::NORMAL, TextCase::LOWERCASE, TextCase::UPPERCASE }; constexpr TextDecorationStyle DEFAULT_TEXT_DECORATION_STYLE = TextDecorationStyle::SOLID; } // namespace void JSSpan::SetFont(const JSCallbackInfo& info) { Font font; JSText::GetFontInfo(info, font); SpanModel::GetInstance()->SetFont(font); } void JSSpan::SetFontSize(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } CalcDimension fontSize; if (!ParseJsDimensionFpNG(info[0], fontSize, false) || fontSize.IsNegative()) { auto pipelineContext = PipelineBase::GetCurrentContext(); CHECK_NULL_VOID(pipelineContext); auto theme = pipelineContext->GetTheme(); CHECK_NULL_VOID(theme); fontSize = theme->GetTextStyle().GetFontSize(); SpanModel::GetInstance()->SetFontSize(fontSize); return; } SpanModel::GetInstance()->SetFontSize(fontSize); } void JSSpan::SetFontWeight(const std::string& value) { SpanModel::GetInstance()->SetFontWeight(ConvertStrToFontWeight(value)); } void JSSpan::SetTextColor(const JSCallbackInfo& info) { Color textColor; if (!ParseJsColor(info[0], textColor)) { auto pipelineContext = PipelineBase::GetCurrentContext(); CHECK_NULL_VOID(pipelineContext); auto theme = pipelineContext->GetTheme(); CHECK_NULL_VOID(theme); textColor = theme->GetTextStyle().GetTextColor(); } SpanModel::GetInstance()->SetTextColor(textColor); } void JSSpan::SetFontStyle(int32_t value) { if (value >= 0 && value < static_cast(FONT_STYLES.size())) { auto style = FONT_STYLES[value]; SpanModel::GetInstance()->SetItalicFontStyle(style); } } void JSSpan::SetFontFamily(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } std::vector fontFamilies; if (!ParseJsFontFamilies(info[0], fontFamilies)) { return; } SpanModel::GetInstance()->SetFontFamily(fontFamilies); } void JSSpan::SetLetterSpacing(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } CalcDimension value; if (!ParseJsDimensionFpNG(info[0], value, false)) { value.Reset(); SpanModel::GetInstance()->SetLetterSpacing(value); return; } SpanModel::GetInstance()->SetLetterSpacing(value); } void JSSpan::SetBaselineOffset(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } NG::CalcLength value; if (ConvertFromJSValueNG(info[0], value) && value.GetDimensionContainsNegative().Unit() != DimensionUnit::PERCENT) { SpanModel::GetInstance()->SetBaselineOffset(value.GetDimensionContainsNegative()); return; } value.Reset(); SpanModel::GetInstance()->SetBaselineOffset(value.GetDimensionContainsNegative()); } void JSSpan::SetTextCase(int32_t value) { if (value >= 0 && value < static_cast(TEXT_CASES.size())) { auto textCase = TEXT_CASES[value]; SpanModel::GetInstance()->SetTextCase(textCase); } } void JSSpan::SetDecoration(const JSCallbackInfo& info) { if (info[0]->IsUndefined()) { SpanModel::GetInstance()->SetTextDecoration(TextDecoration::NONE); return; } if (!info[0]->IsObject()) { return; } JSRef obj = JSRef::Cast(info[0]); JSRef typeValue = obj->GetProperty("type"); JSRef colorValue = obj->GetProperty("color"); JSRef styleValue = obj->GetProperty("style"); std::optional textDecoration; if (typeValue->IsNumber()) { textDecoration = static_cast(typeValue->ToNumber()); } else { auto theme = GetTheme(); CHECK_NULL_VOID(theme); textDecoration = theme->GetTextStyle().GetTextDecoration(); } std::optional textDecorationStyle; if (styleValue->IsNumber()) { textDecorationStyle = static_cast(styleValue->ToNumber()); } else { textDecorationStyle = DEFAULT_TEXT_DECORATION_STYLE; } std::optional colorVal; Color result; if (ParseJsColor(colorValue, result)) { colorVal = result; } else { auto theme = GetTheme(); CHECK_NULL_VOID(theme); if (SystemProperties::GetColorMode() == ColorMode::DARK) { colorVal = theme->GetTextStyle().GetTextColor(); } else { colorVal = Color::BLACK; } } SpanModel::GetInstance()->SetTextDecoration(textDecoration.value()); SpanModel::GetInstance()->SetTextDecorationColor(colorVal.value()); if (textDecorationStyle) { SpanModel::GetInstance()->SetTextDecorationStyle(textDecorationStyle.value()); } } void JSSpan::JsOnClick(const JSCallbackInfo& info) { if (Container::IsCurrentUseNewPipeline()) { if (info[0]->IsUndefined() && IsDisableEventVersion()) { SpanModel::GetInstance()->ClearOnClick(); return; } if (!info[0]->IsFunction()) { return; } auto jsOnClickFunc = AceType::MakeRefPtr(JSRef::Cast(info[0])); auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto onClick = [execCtx = info.GetExecutionContext(), func = jsOnClickFunc, node = targetNode]( BaseEventInfo* info) { auto* clickInfo = TypeInfoHelper::DynamicCast(info); JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("onClick"); PipelineContext::SetCallBackNode(node); func->Execute(*clickInfo); #if !defined(PREVIEW) && defined(OHOS_PLATFORM) JSInteractableView::ReportClickEvent(node); #endif }; SpanModel::GetInstance()->SetOnClick(std::move(onClick)); return; } #ifndef NG_BUILD if (info[0]->IsFunction()) { auto inspector = ViewStackProcessor::GetInstance()->GetInspectorComposedComponent(); CHECK_NULL_VOID(inspector); auto impl = inspector->GetInspectorFunctionImpl(); RefPtr jsOnClickFunc = AceType::MakeRefPtr(JSRef::Cast(info[0])); auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto clickFunc = [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc), impl, node = targetNode](const BaseEventInfo* info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); const auto* clickInfo = TypeInfoHelper::DynamicCast(info); auto newInfo = *clickInfo; if (impl) { impl->UpdateEventInfo(newInfo); } ACE_SCORING_EVENT("Span.onClick"); PipelineContext::SetCallBackNode(node); func->Execute(newInfo); }; SpanModel::GetInstance()->SetOnClick(std::move(clickFunc)); } #endif } void JSSpan::JsRemoteMessage(const JSCallbackInfo& info) { #ifndef NG_BUILD RemoteCallback remoteCallback; JSInteractableView::JsRemoteMessage(info, remoteCallback); EventMarker remoteMessageEventId(std::move(remoteCallback)); auto* stack = ViewStackProcessor::GetInstance(); auto textSpanComponent = AceType::DynamicCast(stack->GetMainComponent()); textSpanComponent->SetRemoteMessageEventId(remoteMessageEventId); #endif } void JSSpan::SetLineHeight(const JSCallbackInfo& info) { CalcDimension value; if (!ParseJsDimensionFpNG(info[0], value)) { value.Reset(); SpanModel::GetInstance()->SetLineHeight(value); return; } if (value.IsNegative()) { value.Reset(); } SpanModel::GetInstance()->SetLineHeight(value); } void JSSpan::SetTextShadow(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } std::vector shadows; ParseTextShadowFromShadowObject(info[0], shadows); SpanModel::GetInstance()->SetTextShadow(shadows); } void JSSpan::SetAccessibilityText(const JSCallbackInfo& info) { std::string text; if ((info.Length() > 0) && info[0]->IsString()) { text = info[0]->ToString(); } SpanModel::GetInstance()->SetAccessibilityText(text); } void JSSpan::SetAccessibilityDescription(const JSCallbackInfo& info) { std::string description; if ((info.Length() > 0) && info[0]->IsString()) { description = info[0]->ToString(); } SpanModel::GetInstance()->SetAccessibilityDescription(description); } void JSSpan::SetAccessibilityLevel(const JSCallbackInfo& info) { std::string level; if ((info.Length() > 0) && info[0]->IsString()) { level = info[0]->ToString(); } SpanModel::GetInstance()->SetAccessibilityImportance(level); } void JSSpan::JSBind(BindingTarget globalObj) { JSClass::Declare("Span"); MethodOptions opt = MethodOptions::NONE; JSClass::StaticMethod("create", &JSSpan::Create, opt); JSClass::StaticMethod("font", &JSSpan::SetFont, opt); JSClass::StaticMethod("fontColor", &JSSpan::SetTextColor, opt); JSClass::StaticMethod("fontSize", &JSSpan::SetFontSize, opt); JSClass::StaticMethod("fontWeight", &JSSpan::SetFontWeight, opt); JSClass::StaticMethod("fontStyle", &JSSpan::SetFontStyle, opt); JSClass::StaticMethod("fontFamily", &JSSpan::SetFontFamily, opt); JSClass::StaticMethod("letterSpacing", &JSSpan::SetLetterSpacing, opt); JSClass::StaticMethod("baselineOffset", &JSSpan::SetBaselineOffset, opt); JSClass::StaticMethod("textCase", &JSSpan::SetTextCase, opt); JSClass::StaticMethod("textShadow", &JSSpan::SetTextShadow, opt); JSClass::StaticMethod("decoration", &JSSpan::SetDecoration); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("onHover", &JSInteractableView::JsOnHover); JSClass::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey); JSClass::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete); JSClass::StaticMethod("remoteMessage", &JSSpan::JsRemoteMessage); JSClass::StaticMethod("onClick", &JSSpan::JsOnClick); JSClass::StaticMethod("lineHeight", &JSSpan::SetLineHeight, opt); JSClass::StaticMethod("textBackgroundStyle", &JSContainerSpan::SetTextBackgroundStyle, opt); JSClass::StaticMethod("accessibilityText", &JSSpan::SetAccessibilityText, opt); JSClass::StaticMethod("accessibilityDescription", &JSSpan::SetAccessibilityDescription, opt); JSClass::StaticMethod("accessibilityLevel", &JSSpan::SetAccessibilityLevel, opt); JSClass::InheritAndBind(globalObj); } void JSSpan::Create(const JSCallbackInfo& info) { std::string label; if (info.Length() > 0) { ParseJsString(info[0], label); } SpanModel::GetInstance()->Create(label); } } // namespace OHOS::Ace::Framework