/* * Copyright (c) 2021-2022 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/common/dom/dom_node.h" #include "core/components/text_field/text_field_component.h" #include "core/components/video/texture_component.h" #include "core/components/web/web_component.h" #include "core/components/xcomponent/xcomponent_component.h" #include "frameworks/bridge/common/dom/dom_document.h" #include "frameworks/bridge/common/dom/dom_div.h" #include "frameworks/bridge/common/utils/utils.h" namespace OHOS::Ace::Framework { namespace { constexpr uint32_t TRANSFORM_SINGLE = 1; constexpr uint32_t TRANSFORM_DUAL = 2; constexpr uint32_t TRANSFORM_SIX = 6; constexpr uint32_t TRANSFORM_SIXTEEN = 16; constexpr uint32_t COMMON_METHOD_FOCUS_ARGS_SIZE = 1; constexpr uint32_t THREE_VALUES = 3; constexpr uint32_t FOUR_VALUES = 4; constexpr int32_t MS_TO_S = 1000; const char COMMON_METHOD_FOCUS[] = "focus"; // focusable support list, this list should be updated after the other nodes(checkbox/radio/switch/ // grid/dialog/button/input) implemented in frontend. std::unordered_set g_focusableNode; // unsupported focusable list. const std::unordered_set UNFOCUSABLED_NODE = { DOM_NODE_TAG_SPAN, }; static const std::unordered_set TRANSITION_PROPERTIES = { DOM_WIDTH, DOM_HEIGHT, DOM_PADDING_TOP, DOM_PADDING_RIGHT, DOM_PADDING_BOTTOM, DOM_PADDING_LEFT, DOM_MARGIN_TOP, DOM_MARGIN_RIGHT, DOM_MARGIN_BOTTOM, DOM_MARGIN_LEFT, DOM_BACKGROUND_COLOR, DOM_OPACITY, DOM_BORDER_LEFT_WIDTH, DOM_BORDER_TOP_WIDTH, DOM_BORDER_RIGHT_WIDTH, DOM_BORDER_BOTTOM_WIDTH, DOM_BORDER_LEFT_COLOR, DOM_BORDER_TOP_COLOR, DOM_BORDER_RIGHT_COLOR, DOM_BORDER_BOTTOM_COLOR }; // default flex value constexpr double DEFAULT_FLEX_GROW = 0.0; constexpr double DEFAULT_FLEX_SHRINK = 1.0; constexpr double DEFAULT_FLEX_BASIS = -1.0; constexpr int32_t TRANSITION_NAME_LENGTH = 4; // prefix id of TweenComponent, for differentiation from id of ComposedComponent constexpr char COMPONENT_PREFIX[] = "FrontendTween"; constexpr char TRANSITION_COMPONENT_PREFIX[] = "FrontendTransition"; } // namespace DOMNode::DOMNode(NodeId nodeId, const std::string& nodeName) : nodeId_(nodeId), tag_(nodeName) { rootComponent_ = AceType::MakeRefPtr(std::to_string(nodeId), nodeName); boxComponent_ = AceType::MakeRefPtr(); boxComponent_->SetEnableDebugBoundary(true); CreateDeclaration(nodeName); } DOMNode::~DOMNode() { if (declaration_) { auto& focusEvent = static_cast(declaration_->GetEvent(EventTag::COMMON_FOCUS_EVENT)); if (focusEvent.IsValid()) { if (!focusEvent.focus.eventMarker.IsEmpty()) { BackEndEventManager::GetInstance().RemoveBackEndEvent(focusEvent.focus.eventMarker); } if (!focusEvent.blur.eventMarker.IsEmpty()) { BackEndEventManager::GetInstance().RemoveBackEndEvent(focusEvent.blur.eventMarker); } } auto& mouseEvent = static_cast(declaration_->GetEvent(EventTag::COMMON_MOUSE_EVENT)); if (mouseEvent.IsValid()) { if (!mouseEvent.mouseHover.eventMarker.IsEmpty()) { BackEndEventManager::GetInstance().RemoveBackEndEvent(mouseEvent.mouseHover.eventMarker); } if (!mouseEvent.mouseHoverExit.eventMarker.IsEmpty()) { BackEndEventManager::GetInstance().RemoveBackEndEvent(mouseEvent.mouseHoverExit.eventMarker); } } for (uint32_t eventAction = 0; eventAction < EventAction::SIZE; eventAction++) { for (uint32_t eventStage = 0; eventStage < EventStage::SIZE; eventStage++) { for (uint32_t touchEventType = 0; touchEventType < EventType::SIZE; touchEventType++) { const auto& eventMarker = GetTouchId(eventAction, eventStage, touchEventType); if (!eventMarker.IsEmpty()) { BackEndEventManager::GetInstance().RemoveBackEndEvent(eventMarker); } } } } } } void DOMNode::Mount(int32_t slot) { auto parentNode = parentNode_.Upgrade(); if (!parentNode) { return; } // flex-item could be used in div, list-item, tabs static const std::unordered_set flexItemParents = { DOM_NODE_TAG_DIV, DOM_NODE_TAG_GRID_COLUMN, DOM_NODE_TAG_LIST_ITEM, DOM_NODE_TAG_LIST_ITEM_GROUP, DOM_NODE_TAG_TABS, DOM_NODE_TAG_REFRESH, DOM_NODE_TAG_STEPPER_ITEM, }; if (flexItemParents.count(parentTag_) > 0) { flexItemComponent_ = AceType::MakeRefPtr(DEFAULT_FLEX_GROW, DEFAULT_FLEX_SHRINK, DEFAULT_FLEX_BASIS); if (boxComponent_) { // span has no box component. boxComponent_->SetDeliverMinToChild(false); } } GenerateComponentNode(); if (parentNode->IsRootNode()) { // When parent is root node, parent contains scroll component, // box could handle percent with viewport size. if (boxComponent_) { // span has no box component. boxComponent_->SetPercentFlag(PERCENT_FLAG_USE_VIEW_PORT); } } parentNode->AddNode(AceType::Claim(this), slot); OnMounted(parentNode); } void DOMNode::AddEvent(int32_t pageId, const std::vector& events) { std::vector tempEvents; for (const auto& event : events) { if (!AddSpecializedEvent(pageId, event)) { tempEvents.emplace_back(event); } if (event == "dragstart") { auto onDragStartId = [](const RefPtr& info, const std::string &extraParams) -> DragItemInfo { DragItemInfo itemInfo; itemInfo.pixelMap = DOMDocument::pixelMap_; return itemInfo; }; boxComponent_->SetOnDragStartId(onDragStartId); } } if (declaration_) { declaration_->AddEvent(pageId, GetNodeIdForEvent(), tempEvents); } } void DOMNode::SetAttr(const std::vector>& attrs) { attributesCache_ = attrs; SetAttrInternal(attrs); } void DOMNode::SetAttrInternal(const std::vector>& attrs) { std::vector> tempAttrs; for (const auto& attr : attrs) { if (SetSpecializedAttr(attr)) { continue; } else { tempAttrs.emplace_back(attr); } } if (declaration_) { IsSubscriptEnable(); declaration_->SetAttr(tempAttrs); } } void DOMNode::CallMethod(const std::string& method, const std::string& args) { if (method == COMMON_METHOD_FOCUS) { if (!focusableEventComponent_) { return; } bool shouldFocus = true; std::unique_ptr argsValue = JsonUtil::ParseJsonString(args); if (argsValue && argsValue->IsArray() && argsValue->GetArraySize() == COMMON_METHOD_FOCUS_ARGS_SIZE) { std::unique_ptr focusValue = argsValue->GetArrayItem(0)->GetValue(COMMON_METHOD_FOCUS); if (focusValue && focusValue->IsBool()) { shouldFocus = focusValue->GetBool(); } } OnRequestFocus(shouldFocus); } else if (method == DOM_LIST_METHOD_SCROLL_BY) { std::unique_ptr argsValue = JsonUtil::ParseJsonString(args); if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != 1) { LOGW("Dom Node parse args error"); return; } std::unique_ptr scrollByPara = argsValue->GetArrayItem(0); double x = scrollByPara->GetDouble("dx", 0.0); double y = scrollByPara->GetDouble("dy", 0.0); bool isSmooth = scrollByPara->GetBool("smooth", true); OnScrollBy(x, y, isSmooth); } else { CallSpecializedMethod(method, args); } } void DOMNode::OnRequestFocus(bool shouldFocus) { auto controller = focusableEventComponent_->GetFocusableController(); if (!controller) { return; } controller->RequestFocus(shouldFocus); } void DOMNode::OnScrollBy(double dx, double dy, bool isSmooth) { auto scrollComponent = GetScrollComponent(); if (!scrollComponent) { return; } auto positionController = scrollComponent->GetScrollPositionController(); if (!positionController) { return; } positionController->ScrollBy(dx, dy, isSmooth); } void DOMNode::SetShowAttr(const std::string& showValue) { if (!declaration_) { return; } auto& renderAttr = declaration_->MaybeResetAttribute(AttributeTag::COMMON_RENDER_ATTR); if (renderAttr.IsValid()) { renderAttr.show = showValue; } if (showValue == "false") { SetDisplay(DisplayType::NONE); } else { SetDisplay(DisplayType::NO_SETTING); } } bool DOMNode::ParseTransitionPropertyStyle(const std::string& transitionProperty) { if (TRANSITION_PROPERTIES.find(transitionProperty) == TRANSITION_PROPERTIES.end()) { return false; } transitionPropertyName_ = transitionProperty; CreatePropertyAnimation(transitionPropertyName_); return true; } bool DOMNode::ParseTransitionNameStyle(const std::string& transitionName) { std::vector transitions; StringUtils::StringSplitter(transitionName, ' ', transitions); if (transitions.size() != TRANSITION_NAME_LENGTH) { return false; } transitionPropertyName_ = transitions[0]; transitionDuration_ = StringUtils::StringToDouble(transitions[1]) * MS_TO_S; transitionTimeFunction_ = transitions[2]; transitionDelay_ = StringUtils::StringToDouble(transitions[3]) * MS_TO_S; CreatePropertyAnimation(transitionPropertyName_); return true; } void DOMNode::CreatePropertyAnimation(const std::string& property) { propertyWidthAnimation_ = AceType::MakeRefPtr>(); propertyHeightAnimation_ = AceType::MakeRefPtr>(); propertyColorAnimation_ = AceType::MakeRefPtr>(); static const std::unordered_map propertyAnimationMap = { { DOM_WIDTH, [](DOMNode& node) { float widthBegin = 0.0f; float widthEnd = node.GetWidth().Value(); node.propertyWidthAnimation_ = node.SetPropertyFloatAnimationKeyframe(widthBegin, widthEnd); } }, { DOM_HEIGHT, [](DOMNode& node) { float heightBegin = 0.0f; float heightEnd = node.GetHeight().Value(); node.propertyHeightAnimation_ = node.SetPropertyFloatAnimationKeyframe(heightBegin, heightEnd); } }, { DOM_TRANSITION_BACKGROUND_COLOR, [](DOMNode& node) { Color backgroundColorBegin = Color::TRANSPARENT; Color backgroundColorEnd = node.GetBackGroundColor(); node.propertyColorAnimation_ = node.SetPropertyColorAnimationKeyframe(backgroundColorBegin, backgroundColorEnd); } }, }; auto animationIter = propertyAnimationMap.find(property); if (animationIter != propertyAnimationMap.end()) { animationIter->second(*this); } if (property == "all") { for (auto propertyAnimation : propertyAnimationMap) { propertyAnimation.second(*this); } } } RefPtr> DOMNode::SetPropertyFloatAnimationKeyframe(float begin, float end) { auto propertyDimensionAnimation = AceType::MakeRefPtr>(); auto keyframeBegin = AceType::MakeRefPtr>(0.0f, begin); auto keyframeEnd = AceType::MakeRefPtr>(1.0f, end); propertyDimensionAnimation->AddKeyframe(keyframeBegin); propertyDimensionAnimation->AddKeyframe(keyframeEnd); return propertyDimensionAnimation; } RefPtr> DOMNode::SetPropertyColorAnimationKeyframe(const Color& begin, const Color& end) { auto propertyColorAnimation = AceType::MakeRefPtr>(); auto keyframeBegin = AceType::MakeRefPtr>(0.0f, begin); auto keyframeEnd = AceType::MakeRefPtr>(1.0f, end); propertyColorAnimation->AddKeyframe(keyframeBegin); propertyColorAnimation->AddKeyframe(keyframeEnd); return propertyColorAnimation; } void DOMNode::TransitionOptionSetKeyframes(TweenOption& transitionOption) { transitionOption.SetDuration(transitionDuration_); transitionOption.SetFillMode(FillMode::FORWARDS); transitionOption.SetCurve(CreateCurve(transitionTimeFunction_)); transitionOption.SetDelay(transitionDelay_); if (propertyWidthAnimation_ && !propertyWidthAnimation_->GetKeyframes().empty()) { transitionOption.SetPropertyAnimationFloat(PropertyAnimatableType::PROPERTY_WIDTH, propertyWidthAnimation_); } if (propertyHeightAnimation_ && !propertyHeightAnimation_->GetKeyframes().empty()) { transitionOption.SetPropertyAnimationFloat(PropertyAnimatableType::PROPERTY_HEIGHT, propertyHeightAnimation_); } if (propertyColorAnimation_ && !propertyColorAnimation_->GetKeyframes().empty()) { transitionOption.SetColorAnimation(propertyColorAnimation_); } } void DOMNode::SetStyle(const std::vector>& styles) { std::vector> tempStyles; for (const auto& style : styles) { if ((style.first == DOM_TRANSITION_NAME) || (style.first == DOM_TRANSITION_PROPERTY_DURATION)) { transitionStyleUpdated_ = true; } if (style.first == DOM_BACKGROUND_COLOR) { isTransitionColor_ = true; } CachePseudoClassStyle(style); if (style.first.find(DOM_PSEUDO_CLASS_SYMBOL) == std::string::npos) { if (!SetCurrentStyle(style)) { tempStyles.emplace_back(style); } } else { tempStyles.emplace_back(style); } } if (declaration_) { declaration_->SetStyle(tempStyles); } OnSetStyleFinished(); } bool DOMNode::SetCurrentStyle(const std::pair& style) { if (SetSpecializedStyle(style)) { // If the subclass consumes this property, it will no longer look in the general property. return true; } // Operator map for styles static const std::unordered_map styleOperators = { // Set width and height { DOM_TRANSFORM, &DOMNode::SetTransform }, { DOM_TRANSITION_PROPERTY, [](const std::string& val, DOMNode& node) { node.ParseTransitionPropertyStyle(val); } }, { DOM_TRANSITION_PROPERTY_DURATION, [](const std::string& val, DOMNode& node) { node.transitionDuration_ = StringUtils::StringToInt(val) * MS_TO_S; } }, { DOM_TRANSITION_PROPERTY_TIMING_FUNCTION, [](const std::string& val, DOMNode& node) { node.transitionTimeFunction_ = val; } }, { DOM_TRANSITION_PROPERTY_DELAY, [](const std::string& val, DOMNode& node) { node.transitionDelay_ = StringUtils::StringToInt(val) * MS_TO_S; } }, }; auto operatorIter = styleOperators.find(style.first); if (operatorIter != styleOperators.end()) { operatorIter->second(style.second, *this); return true; } return false; } void DOMNode::OnActive(bool isActive) { isActive_ = isActive; UpdatePseudoStyle(true); } void DOMNode::OnFocus(bool isFocus) { isFocus_ = isFocus; UpdatePseudoStyle(true); } void DOMNode::OnChecked(bool isChecked) { if (declaration_) { declaration_->SetIsChecked(isChecked); } UpdatePseudoStyle(true); } void DOMNode::OnHover(bool isHover) { if (declaration_) { declaration_->SetIsHover(isHover); } UpdatePseudoStyle(true); } void DOMNode::MarkNeedUpdate() { auto pipelineContext = pipelineContext_.Upgrade(); if (!pipelineContext) { return; } rootComponent_->MarkNeedUpdate(); rootComponent_->SetUpdateType(UpdateType::ALL); pipelineContext->ScheduleUpdate(rootComponent_); } void DOMNode::SetOnFocusClick(const EventMarker& eventMarker) { if (!focusableEventComponent_) { return; } focusableEventComponent_->SetOnClickId(eventMarker); } bool DOMNode::IsNodeDisabled() const { return declaration_ ? declaration_->IsDisabled() : false; } void DOMNode::ResetDefaultStyles() { if (declaration_) { declaration_->ResetDefaultStyles(); } displayComponent_.Reset(); if (transformComponent_) { transformComponent_->ResetTransform(); } } void DOMNode::UpdatePseudoStyleByStatus(int32_t status, bool isBackendChange) { std::unordered_map matchedStyleMap; do { if (pseudoClassStyleMap_.empty()) { break; } // first:use status as the key, search the complete matched; // second:if first do not matched any, calculate the max value of key & status, select the max value one. auto matchedStyle = pseudoClassStyleMap_.find(status); if (matchedStyle != pseudoClassStyleMap_.end()) { matchedStyleMap = matchedStyle->second; } else { uint32_t maxAndResult = 0; uint32_t maxValueKey = pseudoClassStyleMap_.begin()->first; // status & map key, select the max result one for (const auto& pseudoClass : pseudoClassStyleMap_) { uint32_t key = pseudoClass.first; uint32_t andResult = key & static_cast(status); if (andResult > maxAndResult) { maxAndResult = andResult; maxValueKey = key; } } // if matched style except none pseudo style auto iter = pseudoClassStyleMap_.find(maxValueKey); if (maxAndResult > 0 && iter != pseudoClassStyleMap_.end()) { matchedStyleMap = iter->second; } } } while (0); ResetDefaultStyles(); ResetInitializedStyle(); // if not none pseudo style, need set none pseudo style first. auto nonePseudoStylesIter = pseudoClassStyleMap_.find(STATE_NORMAL); if (status != STATE_NORMAL && nonePseudoStylesIter != pseudoClassStyleMap_.end()) { for (const auto& noneTypeStyle : nonePseudoStylesIter->second) { if (!SetCurrentStyle(noneTypeStyle)) { declaration_->SetCurrentStyle(noneTypeStyle); } } } for (const auto& style : matchedStyleMap) { if (!SetCurrentStyle(style)) { declaration_->SetCurrentStyle(style); } } // do not move this for block into the up one for (const auto& style : matchedStyleMap) { if (style.first == DOM_TRANSITION_NAME) { if (isTransitionNameUpdateFirst_) { isTransitionNameUpdateFirst_ = false; } else { ParseTransitionNameStyle(style.second); propTransitionOption_ = TweenOption(); TransitionOptionSetKeyframes(propTransitionOption_); transitionStyleUpdated_ = true; } } if (style.first == DOM_TRANSITION_PROPERTY_DURATION) { if (isTransitionDurationUpdateFirst_) { isTransitionDurationUpdateFirst_ = false; } else { CreatePropertyAnimation(transitionPropertyName_); propTransitionOption_ = TweenOption(); TransitionOptionSetKeyframes(propTransitionOption_); transitionStyleUpdated_ = true; } } } if (isBackendChange) { auto pipelineContext = pipelineContext_.Upgrade(); if (!pipelineContext) { return; } if (GetTag() != DOM_NODE_TAG_SPAN) { UpdateUiComponents(); } UpdateSpecializedComponentWithDeclaration(); PrepareSpecializedComponent(); CompositeComponents(); rootComponent_->MarkNeedUpdate(); rootComponent_->SetUpdateType(UpdateType::STYLE); pipelineContext->ScheduleUpdate(rootComponent_); } } uint32_t DOMNode::CalculatePseudoStatus() const { uint32_t status = STATE_NORMAL; if (!declaration_) { return STATE_NORMAL; } if (isActive_) { status |= STATE_ACTIVE; } if (declaration_->IsDisabled()) { status |= STATE_DISABLED; } if (isFocus_) { status |= STATE_FOCUS; } if (declaration_->IsChecked()) { status |= STATE_CHECKED; } if (declaration_->IsWaiting()) { status |= STATE_WAITING; } if (declaration_->IsHover()) { status |= STATE_HOVERED; } return status; } void DOMNode::UpdateStyleWithChildren() { auto status = CalculatePseudoStatus(); UpdatePseudoStyleByStatus(status, true); SetAttrInternal(attributesCache_); for (const auto& child : children_) { if (child) { child->UpdateStyleWithChildren(); } } } void DOMNode::UpdatePseudoStyle(bool isBackendChange) { if (!HasPseudo()) { return; } auto status = CalculatePseudoStatus(); if (!isBackendChange) { UpdatePseudoStyleByStatus(status, false); return; } // Triggered by backend, elements may processing build or layout now. So post a new task to UI thread. auto context = GetPipelineContext().Upgrade(); if (!context || !context->GetTaskExecutor()) { return; } context->GetTaskExecutor()->PostTask( [weak = AceType::WeakClaim(this), status = status]() { auto node = weak.Upgrade(); if (!node) { return; } node->UpdatePseudoStyleByStatus(status, true); }, TaskExecutor::TaskType::UI, "ArkUIWebDomUpdatePseudoStyle"); } void DOMNode::CachePseudoClassStyle(const std::pair& pseudoClassStyle) { uint32_t pseudoClassType = STATE_NORMAL; const auto& styleKey = pseudoClassStyle.first; if (styleKey.find(DOM_ACTIVE_PSEUDO_CLASS) != std::string::npos) { pseudoClassType |= STATE_ACTIVE; } if (styleKey.find(DOM_DISABLED_PSEUDO_CLASS) != std::string::npos) { pseudoClassType |= STATE_DISABLED; } if (styleKey.find(DOM_FOCUS_PSEUDO_CLASS) != std::string::npos) { pseudoClassType |= STATE_FOCUS; } if (styleKey.find(DOM_CHECKED_PSEUDO_CLASS) != std::string::npos) { pseudoClassType |= STATE_CHECKED; } if (styleKey.find(DOM_WAITING_PSEUDO_CLASS) != std::string::npos) { pseudoClassType |= STATE_WAITING; } if (styleKey.find(DOM_HOVER_PSEUDO_CLASS) != std::string::npos) { pseudoClassType |= STATE_HOVERED; } cachedPseudoType_ |= pseudoClassType; auto pseudoSymbolLocation = styleKey.find(DOM_PSEUDO_CLASS_SYMBOL); auto dealedStyleKey = ((pseudoSymbolLocation != std::string::npos) ? styleKey.substr(0, pseudoSymbolLocation) : styleKey); auto styleMapIter = pseudoClassStyleMap_.find(pseudoClassType); if (styleMapIter != pseudoClassStyleMap_.end()) { auto result = styleMapIter->second.try_emplace(dealedStyleKey, pseudoClassStyle.second); if (!result.second) { result.first->second = pseudoClassStyle.second; } return; } std::unordered_map newPseudoMap; newPseudoMap.emplace(dealedStyleKey, pseudoClassStyle.second); pseudoClassStyleMap_.emplace(pseudoClassType, newPseudoMap); } void DOMNode::GenerateComponentNode() { UpdatePseudoStyle(false); if (GetTag() != DOM_NODE_TAG_SPAN) { UpdateUiComponents(); UpdateTouchEventComponent(); UpdateGestureEventComponent(); UpdateMouseEventComponent(); UpdateFocusableEventComponents(); // Prepare for fixed position UpdatePositionComponent(); #ifndef WEARABLE_PRODUCT UpdateMultimodalComponent(); PrepareScrollComponent(); #endif } UpdateSpecializedComponentWithDeclaration(); PrepareSpecializedComponent(); CompositeComponents(); // Relative and absolute position needs to update the top component props. UpdatePositionProps(); auto rootChild = AceType::DynamicCast(rootComponent_->GetChild()); if (isCustomComponent_) { if (rootChild) { rootChild->SetIsCustomComponent(isCustomComponent_); rootChild->SetOnLayoutReadyMarker(EventMarker(GetNodeIdForEvent(), "")); } } if (rootChild) { int32_t zIndex = 0; if (declaration_) { auto& commonStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_STYLE)); if (commonStyle.IsValid()) { zIndex = commonStyle.zIndex; } } rootChild->SetZIndex(zIndex); } rootComponent_->MarkNeedUpdate(); } void DOMNode::AddNode(const RefPtr& node, int32_t slot) { if (!node) { return; } auto isExist = std::find_if(children_.begin(), children_.end(), [node](const RefPtr& child) { return child->GetNodeId() == node->GetNodeId(); }); if (isExist != children_.end()) { LOGW("the node[%{public}d] has already in the children", node->GetNodeId()); return; } auto pos = children_.begin(); std::advance(pos, slot); children_.insert(pos, node); if (node->GetPosition() != PositionType::PTFIXED) { if (!node->IsProxy() && GetDisplay() == DisplayType::NONE) { node->GenerateComponentNode(); } OnChildNodeAdded(node, slot); } } void DOMNode::RemoveNode(const RefPtr& node) { if (!node) { return; } children_.remove_if([node](const RefPtr& child) { return node->GetNodeId() == child->GetNodeId(); }); if (node->GetPosition() != PositionType::PTFIXED) { OnChildNodeRemoved(node); } } void DOMNode::SetDisplayStyle() { switch (GetDisplay()) { case DisplayType::NONE: visible_ = VisibleType::GONE; break; case DisplayType::GRID: case DisplayType::FLEX: default: VisibilityType visibility = VisibilityType::NO_SETTING; if (declaration_) { auto& visibilityStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_VISIBILITY_STYLE)); if (visibilityStyle.IsValid()) { visibility = visibilityStyle.visibility; } } visible_ = (visibility == VisibilityType::HIDDEN) ? VisibleType::INVISIBLE : VisibleType::VISIBLE; break; } } const RefPtr& DOMNode::BuildTransitionComponent() { transitionComponent_ = AceType::MakeRefPtr(); if (!declaration_) { return transitionComponent_; } transitionComponent_->SetTextDirection(declaration_->IsRightToLeft() ? TextDirection::RTL : TextDirection::LTR); auto& pageTransitionStyle = declaration_->MaybeResetStyle(StyleTag::COMMON_PAGE_TRANSITION_STYLE); if (!pageTransitionStyle.IsValid()) { return transitionComponent_; } if (pageTransitionStyle.transitionEnterOption.IsValid() || pageTransitionStyle.transitionExitOption.IsValid()) { if (!pageTransitionStyle.transitionEnterOption.GetCurve()) { // use FRICTION as transition default curve. pageTransitionStyle.transitionEnterOption.SetCurve(Curves::FRICTION); pageTransitionStyle.transitionExitOption.SetCurve(Curves::FRICTION); } transitionComponent_->SetContentTransitionOption( pageTransitionStyle.transitionEnterOption, pageTransitionStyle.transitionExitOption); } return transitionComponent_; } std::string DOMNode::GetTransformType(const std::unique_ptr& transformJson) { if (transformJson->IsNull()) { return ""; } return transformJson->GetKey(); } std::string DOMNode::GetTransformTypeValue(const std::unique_ptr& transformJson) { if (transformJson->IsNull()) { return ""; } std::string jsonValue = transformJson->GetString(); if (jsonValue.empty()) { double jsonDouble = transformJson->GetDouble(); return std::to_string(jsonDouble); } return jsonValue; } void DOMNode::SetTransform(const std::string& value, DOMNode& node) { if (!node.transformComponent_) { node.transformComponent_ = AceType::MakeRefPtr(); } node.transformComponent_->ResetTransform(); // Avoid transform effect overlay. auto jsonValue = node.GetTransformJsonValue(value); std::unique_ptr transformJson = JsonUtil::ParseJsonString(jsonValue); for (int32_t index = 0; index < transformJson->GetArraySize(); ++index) { std::string typeKey = node.GetTransformType(transformJson->GetArrayItem(index)); std::string typeValue = node.GetTransformTypeValue(transformJson->GetArrayItem(index)); if ((!typeKey.empty()) && (!typeValue.empty())) { // Operator map for transform static const std::unordered_map transformOperators = { { DOM_ROTATE, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->RotateZ(StringUtils::StringToDegree(typeValue)); } }, { DOM_ROTATE_3D, [](const std::string& typeValue, DOMNode& node) { std::vector offsets; StringUtils::StringSplitter(typeValue, ' ', offsets); if (offsets.size() == FOUR_VALUES) { auto dx = StringToDouble(offsets[0]); auto dy = StringToDouble(offsets[1]); auto dz = StringToDouble(offsets[2]); auto degree = StringUtils::StringToDegree(offsets[3]); node.transformComponent_->Rotate(dx, dy, dz, degree); } } }, { DOM_ROTATE_X, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->RotateX(StringUtils::StringToDegree(typeValue)); } }, { DOM_ROTATE_Y, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->RotateY(StringUtils::StringToDegree(typeValue)); } }, { DOM_ROTATE_Z, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->RotateZ(StringUtils::StringToDegree(typeValue)); } }, { SCALE, [](const std::string& typeValue, DOMNode& node) { if (typeValue.find(' ', 0) != std::string::npos) { Offset offset = ConvertStrToOffset(typeValue); node.transformComponent_->Scale(offset.GetX(), offset.GetY()); } else { auto scaleValue = StringToDouble(typeValue); node.transformComponent_->Scale(scaleValue, scaleValue); } } }, { DOM_SCALE_3D, [](const std::string& typeValue, DOMNode& node) { std::vector offsets; StringUtils::StringSplitter(typeValue, ' ', offsets); if (offsets.size() == THREE_VALUES) { auto scaleX = StringToDouble(offsets[0]); auto scaleY = StringToDouble(offsets[1]); auto scaleZ = StringToDouble(offsets[2]); node.transformComponent_->Scale(scaleX, scaleY, scaleZ); } } }, { DOM_SCALE_X, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->ScaleX(StringToDouble(typeValue)); } }, { DOM_SCALE_Y, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->ScaleY(StringToDouble(typeValue)); } }, { DOM_SCALE_Z, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->ScaleZ(StringToDouble(typeValue)); } }, { DOM_TRANSLATE, [](const std::string& typeValue, DOMNode& node) { std::vector offsets; StringUtils::StringSplitter(typeValue, ' ', offsets); if (offsets.size() == TRANSFORM_DUAL) { node.transformComponent_->Translate( node.ParseDimension(offsets[0]), node.ParseDimension(offsets[1])); } else if (offsets.size() == TRANSFORM_SINGLE) { node.transformComponent_->TranslateX(node.ParseDimension(offsets[0])); } } }, { DOM_TRANSLATE_3D, [](const std::string& typeValue, DOMNode& node) { std::vector offsets; StringUtils::StringSplitter(typeValue, ' ', offsets); if (offsets.size() == THREE_VALUES) { auto dx = node.ParseDimension(offsets[0]); auto dy = node.ParseDimension(offsets[1]); auto dz = node.ParseDimension(offsets[2]); node.transformComponent_->Translate(dx, dy, dz); } } }, { DOM_TRANSLATE_X, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->TranslateX(node.ParseDimension(typeValue)); } }, { DOM_TRANSLATE_Y, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->TranslateY(node.ParseDimension(typeValue)); } }, { DOM_TRANSLATE_Z, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->TranslateZ(node.ParseDimension(typeValue)); } }, { DOM_SKEW, [](const std::string& typeValue, DOMNode& node) { std::vector offsets; StringUtils::StringSplitter(typeValue, ' ', offsets); if (offsets.size() == TRANSFORM_DUAL) { auto degreeX = StringUtils::StringToDegree(offsets[0]); auto degreeY = StringUtils::StringToDegree(offsets[1]); node.transformComponent_->Skew(degreeX, degreeY); } else if (offsets.size() == TRANSFORM_SINGLE) { auto degree = StringUtils::StringToDegree(typeValue); node.transformComponent_->Skew(degree, 0.0f); } } }, { DOM_SKEW_X, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->SkewX(StringUtils::StringToDegree(typeValue)); } }, { DOM_SKEW_Y, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->SkewY(StringUtils::StringToDegree(typeValue)); } }, { DOM_MATRIX, [](const std::string& typeValue, DOMNode& node) { std::vector offsets; StringUtils::StringSplitter(typeValue, ' ', offsets); if (offsets.size() == TRANSFORM_SIX) { double scaleX = StringToDouble(offsets[0]); double skewY = StringToDouble(offsets[1]); double skewX = StringToDouble(offsets[2]); double scaleY = StringToDouble(offsets[3]); double translateX = StringToDouble(offsets[4]); double translateY = StringToDouble(offsets[5]); node.transformComponent_->Matrix(scaleX, skewY, skewX, scaleY, translateX, translateY); } } }, { DOM_MATRIX_3D, [](const std::string& typeValue, DOMNode& node) { std::vector offsets; StringUtils::StringSplitter(typeValue, ' ', offsets); if (offsets.size() == TRANSFORM_SIXTEEN) { std::vector matrix; for (const auto& offset : offsets) { matrix.push_back(StringToDouble(offset)); } node.transformComponent_->Matrix3d(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6], matrix[7], matrix[8], matrix[9], matrix[10], matrix[11], matrix[12], matrix[13], matrix[14], matrix[15]); } } }, { DOM_PERSPECTIVE, [](const std::string& typeValue, DOMNode& node) { node.transformComponent_->Perspective(node.ParseDimension(typeValue)); } }, }; auto operatorIter = transformOperators.find(typeKey); if (operatorIter != transformOperators.end()) { operatorIter->second(typeValue, node); } } } } // Convert transform style to json format, such as rotate(50deg) to {"rotate":"50deg"} std::string DOMNode::GetTransformJsonValue(const std::string& value) { auto jsonValue = JsonUtil::Create(true); std::vector subValues; StringUtils::StringSplitter(value, ' ', subValues); for (const auto& subValue : subValues) { auto rightIndex = subValue.find('('); auto leftIndex = subValue.find(')'); if (rightIndex != std::string::npos && leftIndex != std::string::npos && (leftIndex - 1 - rightIndex > 0)) { std::string transformType = subValue.substr(0, rightIndex); std::string transformValue = subValue.substr(rightIndex + 1, leftIndex - 1 - rightIndex); jsonValue->Put(transformType.c_str(), transformValue.c_str()); } else { return value; } } return jsonValue->ToString(); } void DOMNode::AddKeyframe(double time, double typeValue, RefPtr>& transformKeyframes) { auto keyframe = AceType::MakeRefPtr>(time, typeValue); transformKeyframes->AddKeyframe(keyframe); } void DOMNode::AddKeyframe( double time, const std::string& typeValue, RefPtr>& transformKeyframes) { DOMNode::AddKeyframe(time, StringToDouble(typeValue), transformKeyframes); } void DOMNode::SetSharedTransitionStyle( const std::vector>& animationKeyframes) { if (!declaration_) { return; } auto& shareTransitionStyle = declaration_->MaybeResetStyle(StyleTag::COMMON_SHARE_TRANSITION_STYLE); if (!shareTransitionStyle.IsValid()) { return; } if (!ParseAnimationStyle(animationKeyframes)) { return; } shareTransitionStyle.sharedTransitionOption = TweenOption(); TweenOptionSetKeyframes(shareTransitionStyle.sharedTransitionOption); } bool DOMNode::ParseAnimationStyle(const std::vector>& animationKeyframes) { if (animationKeyframes.empty()) { return false; } animationUtil_.ParseAnimationStyle(animationKeyframes, declaration_, GetThemeConstants()); propAnimations_ = animationUtil_.GetPropAnimationMap(); animationName_ = animationUtil_.GetAnimationName(); if (propAnimations_.find(AnimatableType::PROPERTY_OPACITY) != propAnimations_.end()) { if (declaration_) { declaration_->SetHasDisplayStyle(true); } } return true; } void DOMNode::SetAnimationStyle(const std::vector>& animationKeyframes) { if (!declaration_ || !ParseAnimationStyle(animationKeyframes)) { return; } if (isTransition_) { auto& pageTransitionStyle = declaration_->MaybeResetStyle(StyleTag::COMMON_PAGE_TRANSITION_STYLE); if (pageTransitionStyle.IsValid()) { if (isEnter_) { TweenOptionSetKeyframes(pageTransitionStyle.transitionEnterOption); } else { TweenOptionSetKeyframes(pageTransitionStyle.transitionExitOption); } } } else { auto& animationStyle = declaration_->MaybeResetStyle(StyleTag::COMMON_ANIMATION_STYLE); if (animationStyle.IsValid()) { animationStyle.tweenOption = TweenOption(); TweenOptionSetKeyframes(animationStyle.tweenOption); animationStyleUpdated_ = true; } } } void DOMNode::UpdatePropAnimations(const PropAnimationMap& animations) { if (boxComponent_ != nullptr) { boxComponent_->ClearAnimatables(); } if (displayComponent_ != nullptr) { displayComponent_->ClearAnimatables(); } for (const auto& [type, animation] : animations) { switch (type) { case AnimatableType::PROPERTY_WIDTH: case AnimatableType::PROPERTY_HEIGHT: case AnimatableType::PROPERTY_BG_COLOR: case AnimatableType::PROPERTY_MARGIN_LEFT: case AnimatableType::PROPERTY_MARGIN_TOP: case AnimatableType::PROPERTY_MARGIN_RIGHT: case AnimatableType::PROPERTY_MARGIN_BOTTOM: case AnimatableType::PROPERTY_PADDING_LEFT: case AnimatableType::PROPERTY_PADDING_TOP: case AnimatableType::PROPERTY_PADDING_RIGHT: case AnimatableType::PROPERTY_PADDING_BOTTOM: case AnimatableType::PROPERTY_BACKGROUND_POSITION: case AnimatableType::PROPERTY_BACKGROUND_SIZE: case AnimatableType::PROPERTY_BORDER_LEFT_WIDTH: case AnimatableType::PROPERTY_BORDER_TOP_WIDTH: case AnimatableType::PROPERTY_BORDER_RIGHT_WIDTH: case AnimatableType::PROPERTY_BORDER_BOTTOM_WIDTH: case AnimatableType::PROPERTY_BORDER_LEFT_COLOR: case AnimatableType::PROPERTY_BORDER_TOP_COLOR: case AnimatableType::PROPERTY_BORDER_RIGHT_COLOR: case AnimatableType::PROPERTY_BORDER_BOTTOM_COLOR: case AnimatableType::PROPERTY_BORDER_TOP_LEFT_RADIUS: case AnimatableType::PROPERTY_BORDER_TOP_RIGHT_RADIUS: case AnimatableType::PROPERTY_BORDER_BOTTOM_LEFT_RADIUS: case AnimatableType::PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS: case AnimatableType::PROPERTY_BORDER_LEFT_STYLE: case AnimatableType::PROPERTY_BORDER_RIGHT_STYLE: case AnimatableType::PROPERTY_BORDER_TOP_STYLE: case AnimatableType::PROPERTY_BORDER_BOTTOM_STYLE: case AnimatableType::PROPERTY_FILTER_BLUR: case AnimatableType::PROPERTY_BACKDROP_FILTER_BLUR: case AnimatableType::PROPERTY_WINDOW_FILTER_BLUR: case AnimatableType::PROPERTY_BOX_SHADOW: { if (boxComponent_ != nullptr) { boxComponent_->AddAnimatable(type, animation); } break; } case AnimatableType::PROPERTY_OPACITY: { if (displayComponent_ != nullptr) { displayComponent_->AddAnimatable(type, animation); } break; } default: break; } } } void DOMNode::UpdatePositionAnimations(const RefPtr component) { if (component != nullptr) { static const AnimatableType positionAnimatableType[] = { AnimatableType::PROPERTY_POSITION_LEFT, AnimatableType::PROPERTY_POSITION_TOP, AnimatableType::PROPERTY_POSITION_RIGHT, AnimatableType::PROPERTY_POSITION_BOTTOM, }; for (const auto& type : positionAnimatableType) { const auto& animation = propAnimations_[type]; if (animation) { component->AddAnimatable(type, animation); } } } } void DOMNode::TweenOptionSetKeyframes(TweenOption& tweenOption) { auto pos = propAnimations_.find(AnimatableType::PROPERTY_OPACITY); if (pos != propAnimations_.end()) { auto opacityAnimation = AceType::MakeRefPtr>(); for (auto& item : pos->second->GetAnimatable()) { auto opacityAnimatable = AceType::DynamicCast>(item); if (opacityAnimatable) { opacityAnimation->AddKeyframe( AceType::MakeRefPtr>(item->GetTimePoint(), opacityAnimatable->GetValue())); } } tweenOption.SetOpacityAnimation(opacityAnimation); propAnimations_.erase(pos); } if (!propAnimations_.empty()) { tweenOption.SetAnimatables(propAnimations_); } animationUtil_.GetTransformConvertor().AddAnimationToTweenOption(tweenOption); } void DOMNode::SetCustomAnimationStyleUpdate(bool enable) { customAnimationStyleUpdated_ = enable; } void DOMNode::CompositeComponents() { std::vector> components; if (flexItemComponent_) { // Update flex item after PrepareSpecializedComponent to make sure sub class has finished prepare. UpdateFlexItemComponent(); components.emplace_back(flexItemComponent_); } if (tweenComponent_) { tweenComponent_->SetLeafNode(IsLeafNode()); components.emplace_back(tweenComponent_); } if (displayComponent_) { displayComponent_->DisableLayer(IsLeafNode()); components.emplace_back(displayComponent_); if (focusableEventComponent_) { focusableEventComponent_->SetShow(GetDisplay() != DisplayType::NONE); } } if (transformComponent_) { components.emplace_back(transformComponent_); } if (focusableEventComponent_) { components.emplace_back(focusableEventComponent_); } if (touchEventComponent_) { touchEventComponent_->SetIsVisible(visible_ == VisibleType::VISIBLE); components.emplace_back(touchEventComponent_); } if (gestureEventComponent_) { gestureEventComponent_->SetIsVisible(visible_ == VisibleType::VISIBLE); components.emplace_back(gestureEventComponent_); } #ifndef WEARABLE_PRODUCT if (multimodalComponent_) { components.emplace_back(multimodalComponent_); } #endif if (mouseEventComponent_) { components.emplace_back(mouseEventComponent_); } if (propTransitionComponent_) { components.emplace_back(propTransitionComponent_); } if (boxComponent_) { components.emplace_back(boxComponent_); } if (scrollComponent_) { components.emplace_back(scrollComponent_); } if (sharedTransitionComponent_) { components.emplace_back(sharedTransitionComponent_); } auto mainComponent = GetSpecializedComponent(); if (!components.empty() && (AceType::InstanceOf(mainComponent) || AceType::InstanceOf(mainComponent) || AceType::InstanceOf(mainComponent) || AceType::InstanceOf(mainComponent) || AceType::InstanceOf(mainComponent) || AceType::InstanceOf(mainComponent))) { Component::MergeRSNode(components); Component::MergeRSNode(mainComponent); } else { Component::MergeRSNode(components, mainComponent); } // Only fixed position has position component if (positionComponent_ && GetPosition() == PositionType::PTFIXED) { components.emplace(components.begin(), positionComponent_); Component::MergeRSNode(positionComponent_); } // First, composite all common components. for (int32_t idx = static_cast(components.size()) - 1; idx - 1 >= 0; --idx) { components[idx - 1]->SetChild(DynamicCast(components[idx])); } // Then composite specialized components. auto compositeComponent = CompositeSpecializedComponent(components); // At last add to composite component. rootComponent_->SetChild(compositeComponent); // final set disabled status. if (declaration_ && declaration_->IsDisabled() != rootComponent_->IsDisabledStatus()) { rootComponent_->SetDisabledStatus(declaration_->IsDisabled()); } } void DOMNode::SetDisplayType() { static std::unordered_map types = { { DOM_NODE_TAG_DIV, DisplayType::FLEX }, { DOM_NODE_TAG_BADGE, DisplayType::BLOCK }, { DOM_NODE_TAG_DIALOG, DisplayType::BLOCK }, { DOM_NODE_TAG_FORM, DisplayType::BLOCK }, { DOM_NODE_TAG_LIST, DisplayType::BLOCK }, { DOM_NODE_TAG_LIST_ITEM, DisplayType::BLOCK }, { DOM_NODE_TAG_LIST_ITEM_GROUP, DisplayType::BLOCK }, { DOM_NODE_TAG_PANEL, DisplayType::BLOCK }, { DOM_NODE_TAG_POPUP, DisplayType::BLOCK }, { DOM_NODE_TAG_REFRESH, DisplayType::BLOCK }, { DOM_NODE_TAG_STACK, DisplayType::BLOCK }, { DOM_NODE_TAG_STEPPER, DisplayType::BLOCK }, { DOM_NODE_TAG_STEPPER_ITEM, DisplayType::BLOCK }, { DOM_NODE_TAG_SWIPER, DisplayType::BLOCK }, { DOM_NODE_TAG_TABS, DisplayType::BLOCK }, { DOM_NODE_TAG_TAB_BAR, DisplayType::BLOCK }, { DOM_NODE_TAG_TAB_CONTENT, DisplayType::BLOCK }, { DOM_NODE_TAG_BUTTON, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_CHART, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_DIVIDER, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_IMAGE, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_IMAGE_ANIMATOR, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_INPUT, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_LABEL, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_MARQUEE, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_MENU, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_OPTION, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_PICKER_DIALOG, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_PICKER_VIEW, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_PIECE, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_PROGRESS, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_QRCODE, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_RATING, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_RICH_TEXT, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_SEARCH, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_SELECT, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_SLIDER, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_SPAN, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_SWITCH, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_TEXT, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_TEXTAREA, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_TOOL_BAR, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_TOOL_BAR_ITEM, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_TOGGLE, DisplayType::INLINE_BLOCK }, { DOM_NODE_TAG_WEB, DisplayType::INLINE_BLOCK }, }; DisplayType displayType = GetDisplay(); if (displayType == DisplayType::NO_SETTING) { auto item = types.find(GetTag()); if (item != types.end()) { displayType = item->second; } } if (flexItemComponent_) { flexItemComponent_->SetDisplayType(displayType); } if (boxComponent_) { boxComponent_->SetDisplayType(displayType); } } void DOMNode::UpdateFlexItemComponent() { if (!declaration_ || !flexItemComponent_) { return; } auto& flexStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_FLEX_STYLE)); if (flexStyle.IsValid()) { flexItemComponent_->SetFlexGrow(flexStyle.flexGrow); flexItemComponent_->SetFlexShrink(flexStyle.flexShrink); flexItemComponent_->SetFlexBasis(flexStyle.flexBasis); flexItemComponent_->SetFlexWeight(flexStyle.flexWeight); flexItemComponent_->SetDisplayIndex(flexStyle.displayIndex); } const LinearMapNode ALIGN_SELF_TABLE[] = { { DOM_ALIGN_ITEMS_BASELINE, FlexAlign::BASELINE }, { DOM_ALIGN_ITEMS_CENTER, FlexAlign::CENTER }, { DOM_ALIGN_ITEMS_END, FlexAlign::FLEX_END }, { DOM_ALIGN_ITEMS_START, FlexAlign::FLEX_START }, { DOM_ALIGN_ITEMS_STRETCH, FlexAlign::STRETCH }, }; auto& commonStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_STYLE)); int64_t index = -1; if (commonStyle.IsValid()) { index = BinarySearchFindIndex(ALIGN_SELF_TABLE, ArraySize(ALIGN_SELF_TABLE), commonStyle.alignSelf.c_str()); } if (index != -1) { flexItemComponent_->SetAlignSelf(ALIGN_SELF_TABLE[index].value); } else { flexItemComponent_->SetAlignSelf(FlexAlign::AUTO); } auto parentNode = parentNode_.Upgrade(); if ((parentNode) && (parentNode->GetTag() == DOM_NODE_TAG_DIV || parentNode->GetTag() == DOM_NODE_TAG_GRID_COLUMN)) { auto parent = AceType::DynamicCast(parentNode); // Stretch flag means that if the child's main size is determined, it can not be stretched. if (((parent->GetFlexDirection() == FlexDirection::ROW || parent->GetFlexDirection() == FlexDirection::ROW_REVERSE) && (GreatOrEqual(GetHeight().Value(), 0.0) || GetHeight().Unit() == DimensionUnit::CALC)) || ((parent->GetFlexDirection() == FlexDirection::COLUMN || parent->GetFlexDirection() == FlexDirection::COLUMN_REVERSE) && (GreatOrEqual(GetWidth().Value(), 0.0) || GetWidth().Unit() == DimensionUnit::CALC))) { flexItemComponent_->SetStretchFlag(false); } else { flexItemComponent_->SetStretchFlag(true); } } auto& sizeStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_SIZE_STYLE)); if (sizeStyle.IsValid()) { // Make sure input layout constraint is valid flexItemComponent_->SetMaxHeight(sizeStyle.maxHeight); flexItemComponent_->SetMaxWidth(sizeStyle.maxWidth); flexItemComponent_->SetMinHeight(sizeStyle.minHeight); flexItemComponent_->SetMinWidth(sizeStyle.minWidth); // If set aspect Ratio, it cannot be stretch if (GreatNotEqual(sizeStyle.aspectRatio, 0.0)) { flexItemComponent_->SetStretchFlag(false); } } // If set display, this flexItem is ignored. if (GetDisplay() == DisplayType::NONE) { flexItemComponent_->SetIsHidden(GetDisplay() == DisplayType::NONE); } SetDisplayType(); } void DOMNode::UpdateUiComponents() { UpdateBoxComponent(); UpdateDisplayComponent(); UpdateTweenComponent(); } void DOMNode::UpdateBoxSize(const CalcDimension& width, const CalcDimension& height) { if (height.Unit() == DimensionUnit::CALC) { boxComponent_->SetHeight(height.CalcValue(), height.Unit()); } else { boxComponent_->SetHeight(height.Value(), height.Unit()); } if (width.Unit() == DimensionUnit::CALC) { boxComponent_->SetWidth(width.CalcValue(), width.Unit()); } else { boxComponent_->SetWidth(width.Value(), width.Unit()); } } void DOMNode::UpdateBoxPadding(const Edge& padding) { boxComponent_->SetPadding(padding); } void DOMNode::UpdateBoxBorder(const Border& border) { if (declaration_ && declaration_->GetBackDecoration()) { declaration_->GetBackDecoration()->SetBorder(border); } } void DOMNode::UpdateBoxComponent() { if (!declaration_) { return; } if (declaration_->HasBoxStyle()) { if (GetWidth().Unit() != DimensionUnit::CALC && GetHeight().Unit() != DimensionUnit::CALC) { UpdateBoxSize(GetWidth(), GetHeight()); } else if (GetWidth().Unit() == DimensionUnit::CALC && GetHeight().Unit() != DimensionUnit::CALC) { UpdateBoxSize(GetCalcWidth(), GetHeight()); } else if (GetWidth().Unit() != DimensionUnit::CALC && GetHeight().Unit() == DimensionUnit::CALC) { UpdateBoxSize(GetWidth(), GetCalcHeight()); } else { UpdateBoxSize(GetCalcWidth(), GetCalcHeight()); } auto& paddingStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_PADDING_STYLE)); if (paddingStyle.IsValid()) { UpdateBoxPadding(paddingStyle.padding); } auto& marginStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_MARGIN_STYLE)); if (marginStyle.IsValid()) { boxComponent_->SetMargin(marginStyle.margin); } auto& commonStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_STYLE)); if (commonStyle.IsValid()) { boxComponent_->SetLayoutInBoxFlag(commonStyle.layoutInBox); } } SetDisplayType(); auto& sizeStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_SIZE_STYLE)); if (sizeStyle.IsValid()) { boxComponent_->SetAspectRatio(sizeStyle.aspectRatio); } if (flexItemComponent_) { boxComponent_->SetDeliverMinToChild(false); if (sizeStyle.IsValid()) { boxComponent_->SetMinWidth(sizeStyle.minWidth); boxComponent_->SetMinHeight(sizeStyle.minHeight); boxComponent_->SetMaxWidth(sizeStyle.maxWidth); boxComponent_->SetMaxHeight(sizeStyle.maxHeight); boxComponent_->SetBoxSizing(sizeStyle.boxSizing); } } if (declaration_->HasDecorationStyle()) { auto& borderStyle = declaration_->MaybeResetStyle(StyleTag::COMMON_BORDER_STYLE); if (borderStyle.IsValid()) { UpdateBoxBorder(borderStyle.border); } auto& backDecoration = declaration_->GetBackDecoration(); if (!declaration_->HasBackGroundColor() && boxComponent_->GetBackDecoration() && boxComponent_->HasBackgroundColor()) { backDecoration->SetBackgroundColor(boxComponent_->GetBackDecoration()->GetBackgroundColor()); } auto& backgroundStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_BACKGROUND_STYLE)); if (backgroundStyle.IsValid() && backgroundStyle.gradient.IsValid()) { backDecoration->SetGradient(backgroundStyle.gradient); } if (backgroundStyle.IsValid() && backgroundStyle.gradientBorderImage.IsValid()) { backDecoration->SetBorderImageGradient(backgroundStyle.gradientBorderImage); } if (declaration_->HasShadowStyle()) { auto& shadowStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_SHADOW_STYLE)); if (shadowStyle.IsValid()) { backDecoration->ClearAllShadow(); backDecoration->AddShadow(shadowStyle.shadow); } } boxComponent_->SetBackDecoration(backDecoration); } if (declaration_->HasFrontDecorationStyle()) { boxComponent_->SetFrontDecoration(declaration_->GetFrontDecoration()); } auto& overflowStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_OVERFLOW_STYLE)); if (overflowStyle.IsValid()) { boxComponent_->SetOverflow(overflowStyle.overflow); } boxComponent_->SetOnDomDragEnter(GetDragEnterId()); boxComponent_->SetOnDomDragOver(GetDragOverId()); boxComponent_->SetOnDomDragLeave(GetDragLeaveId()); boxComponent_->SetOnDomDragDrop(GetDragDropId()); auto& clipPathStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_CLIP_PATH_STYLE)); if (clipPathStyle.IsValid() && clipPathStyle.clipPath != nullptr) { boxComponent_->SetClipPath(clipPathStyle.clipPath); } auto& maskStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_MASK_STYLE)); if (maskStyle.IsValid() && !maskStyle.maskImage.empty()) { BackgroundImagePosition position; if (!maskStyle.maskPosition.empty()) { ParseBackgroundImagePosition(maskStyle.maskPosition, position); } BackgroundImageSize size; if (!maskStyle.maskSize.empty()) { ParseBackgroundImageSize(maskStyle.maskSize, size); } boxComponent_->SetMask(maskStyle.maskImage, size, position); } } void DOMNode::PrepareScrollComponent() { if (!declaration_) { return; } // div is specially handled. if (GetTag() == DOM_NODE_TAG_DIV) { return; } auto& overflowStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_OVERFLOW_STYLE)); if (!declaration_->HasOverflowStyle() || !overflowStyle.IsValid() || overflowStyle.overflow != Overflow::SCROLL) { return; } if (boxComponent_->GetWidthDimension().IsValid() && boxComponent_->GetHeightDimension().IsValid()) { if (!scrollComponent_) { scrollComponent_ = AceType::MakeRefPtr(nullptr); } scrollComponent_->InitScrollBar(GetTheme(), overflowStyle.scrollBarColor, overflowStyle.scrollBarWidth, overflowStyle.edgeEffect); declaration_->SetPositionController(scrollComponent_->GetScrollPositionController()); } } void DOMNode::UpdateDisplayComponent() { if (!declaration_ || !declaration_->HasDisplayStyle()) { return; } if (!displayComponent_) { displayComponent_ = AceType::MakeRefPtr(rootComponent_->GetChild()); } auto& opacityStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_OPACITY_STYLE)); if (opacityStyle.IsValid()) { displayComponent_->SetOpacity(opacityStyle.opacity); displayComponent_->SetAppearingDuration(opacityStyle.appearingDuration); } auto context = pipelineContext_.Upgrade(); if (!context) { return; } SetDisplayStyle(); displayComponent_->SetVisible(visible_); bool show = (GetDisplay() != DisplayType::NONE); if (!focusableEventComponent_ && !show && !context->IsJsCard()) { focusableEventComponent_ = AceType::MakeRefPtr(); focusableEventComponent_->SetFocusable(true); declaration_->SetFocusableController(focusableEventComponent_->GetFocusableController()); } if (focusableEventComponent_) { focusableEventComponent_->SetShow(show); } if (declaration_->HasShadowStyle()) { auto& shadowStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_SHADOW_STYLE)); if (shadowStyle.IsValid()) { displayComponent_->SetShadow(shadowStyle.shadow); } } } void DOMNode::UpdateTweenComponent() { if (transitionStyleUpdated_) { if (!propTransitionComponent_) { propTransitionComponent_ = AceType::MakeRefPtr(TRANSITION_COMPONENT_PREFIX + std::to_string(nodeId_), tag_); } propTransitionComponent_->SetTransitionOption(propTransitionOption_); transitionStyleUpdated_ = false; } if (!declaration_) { return; } if (declaration_->HasTransformStyle() && !transformComponent_) { transformComponent_ = AceType::MakeRefPtr(); } auto& animationStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_ANIMATION_STYLE)); auto& shadowStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_SHADOW_STYLE)); auto& clickEffectAttr = static_cast(declaration_->GetAttribute(AttributeTag::COMMON_CLICK_EFFECT_ATTR)); if (transformComponent_) { if (clickEffectAttr.IsValid()) { transformComponent_->SetClickSpringEffectType(clickEffectAttr.clickEffect); } if (animationStyle.IsValid()) { // Set transform style. if (declaration_->HasTransformOriginStyle()) { transformComponent_->SetOriginDimension( DimensionOffset(animationStyle.transformOriginX, animationStyle.transformOriginY)); } } if (declaration_->HasShadowStyle() && shadowStyle.IsValid()) { transformComponent_->SetShadow(shadowStyle.shadow); } auto& cardTransitionStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_CARD_TRANSITION_STYLE)); if (cardTransitionStyle.IsValid()) { transformComponent_->SetTransitionEffect(cardTransitionStyle.transitionEffect); } } // Only check animation style here. if (animationStyle.IsValid() && animationStyle.tweenOption.IsValid() && animationStyleUpdated_) { if (!tweenComponent_) { tweenComponent_ = AceType::MakeRefPtr(COMPONENT_PREFIX + std::to_string(nodeId_), tag_); } tweenComponent_->SetTweenOption(animationStyle.tweenOption); tweenComponent_->UpdateAnimationName(animationName_); tweenComponent_->SetAnimationOperation(animationStyle.animationOperation); if (declaration_->HasShadowStyle() && shadowStyle.IsValid()) { tweenComponent_->SetShadow(shadowStyle.shadow); } UpdatePropAnimations(propAnimations_); animationStyleUpdated_ = false; } // for custom animation if (customAnimationStyleUpdated_) { UpdatePropAnimations(propAnimations_); customAnimationStyleUpdated_ = false; } if (!shareId_.empty()) { if (!sharedTransitionComponent_) { sharedTransitionComponent_ = AceType::MakeRefPtr( "FrontendShared" + std::to_string(nodeId_), tag_, shareId_); auto& sharedTransitionStyle = static_cast( declaration_->GetStyle(StyleTag::COMMON_SHARE_TRANSITION_STYLE)); if (sharedTransitionStyle.IsValid()) { sharedTransitionComponent_->SetOption(sharedTransitionStyle.sharedTransitionOption); sharedTransitionComponent_->SetEffect(sharedTransitionStyle.sharedEffect); } } else { sharedTransitionComponent_->SetShareId(shareId_); } } } bool DOMNode::IsTabbarSubNode() const { if (isRootNode_) { return GetTag() == DOM_NODE_TAG_TAB_BAR; } RefPtr parent = parentNode_.Upgrade(); if (!parent) { return false; } if (parent->GetTag() == DOM_NODE_TAG_TAB_BAR) { return true; } while (!parent->IsRootNode()) { if (parent->GetTag() == DOM_NODE_TAG_TAB_BAR) { return true; } parent = parent->GetParentNode(); if (!parent) { return false; } } return false; } void DOMNode::PrepareTouchEvent(EventMarker& eventMarker, uint32_t type) { bool isTababrSubNode = IsTabbarSubNode(); if (isTababrSubNode) { return; } auto weak = AceType::WeakClaim(this); if (eventMarker.IsEmpty()) { eventMarker = BackEndEventManager::GetInstance().GetAvailableMarker(); BackEndEventManager::GetInstance().BindBackendEvent( eventMarker, [](const TouchEventInfo&) {}); } eventMarker.SetPreFunction([weak, type]() { auto domNode = weak.Upgrade(); if (!domNode) { return; } domNode->OnActive(type != EventType::TOUCH_UP && type != EventType::TOUCH_CANCEL); }); } void DOMNode::PrepareMouseHoverEvent() { if (!declaration_) { return; } auto& mouseEvent = declaration_->MaybeResetEvent(EventTag::COMMON_MOUSE_EVENT); if (!mouseEvent.IsValid()) { return; } auto weak = AceType::WeakClaim(this); if (mouseEvent.mouseHover.eventMarker.IsEmpty()) { mouseEvent.mouseHover.eventMarker = BackEndEventManager::GetInstance().GetAvailableMarker(); mouseEvent.mouseHover.isRefreshed = true; BackEndEventManager::GetInstance().BindBackendEvent(mouseEvent.mouseHover.eventMarker, []() {}); } mouseEvent.mouseHover.eventMarker.SetPreFunction([weak]() { auto domNode = weak.Upgrade(); if (!domNode) { return; } domNode->OnHover(true); }); if (mouseEvent.mouseHoverExit.eventMarker.IsEmpty()) { mouseEvent.mouseHoverExit.eventMarker = BackEndEventManager::GetInstance().GetAvailableMarker(); mouseEvent.mouseHoverExit.isRefreshed = true; BackEndEventManager::GetInstance().BindBackendEvent(mouseEvent.mouseHoverExit.eventMarker, []() {}); } mouseEvent.mouseHoverExit.eventMarker.SetPreFunction([weak]() { auto domNode = weak.Upgrade(); if (!domNode) { return; } domNode->OnHover(false); }); } void DOMNode::PrepareFocusableEventId() { if (!declaration_) { return; } auto& focusEvent = declaration_->MaybeResetEvent(EventTag::COMMON_FOCUS_EVENT); if (!focusEvent.IsValid()) { return; } auto weak = AceType::WeakClaim(this); if (focusEvent.focus.eventMarker.IsEmpty()) { focusEvent.focus.eventMarker = BackEndEventManager::GetInstance().GetAvailableMarker(); focusEvent.focus.isRefreshed = true; BackEndEventManager::GetInstance().BindBackendEvent(focusEvent.focus.eventMarker, []() {}); } focusEvent.focus.eventMarker.SetPreFunction([weak]() { auto domNode = weak.Upgrade(); if (!domNode) { return; } domNode->OnFocus(true); }); if (focusEvent.blur.eventMarker.IsEmpty()) { focusEvent.blur.eventMarker = BackEndEventManager::GetInstance().GetAvailableMarker(); focusEvent.blur.isRefreshed = true; BackEndEventManager::GetInstance().BindBackendEvent(focusEvent.blur.eventMarker, []() {}); } focusEvent.blur.eventMarker.SetPreFunction([weak]() { auto domNode = weak.Upgrade(); if (!domNode) { return; } domNode->OnFocus(false); }); } void DOMNode::UpdateTouchEventComponent() { if (!declaration_) { return; } auto& swipeEvent = static_cast(declaration_->GetEvent(EventTag::COMMON_SWIPE_EVENT)); if (swipeEvent.IsValid()) { for (uint32_t eventAction = 0; eventAction < EventAction::SIZE; eventAction++) { for (uint32_t eventStage = 0; eventStage < EventStage::SIZE; eventStage++) { EventMarker& eventMarker = GetSwipeId(eventAction, eventStage); if (!eventMarker.IsEmpty()) { if (!touchEventComponent_) { touchEventComponent_ = AceType::MakeRefPtr(); } touchEventComponent_->SetSwipeEvent(eventMarker, eventAction, eventStage); } } } } auto& touchableAttr = static_cast(declaration_->GetAttribute(AttributeTag::COMMON_TOUCHABLE_ATTR)); if (touchableAttr.IsValid() && !touchableAttr.touchable) { if (!touchEventComponent_) { touchEventComponent_ = AceType::MakeRefPtr(); } touchEventComponent_->SetTouchable(touchableAttr.touchable); } auto& rawEvent = static_cast(declaration_->GetEvent(EventTag::COMMON_RAW_EVENT)); if (!rawEvent.IsValid()) { return; } for (uint32_t eventAction = 0; eventAction < EventAction::SIZE; eventAction++) { for (uint32_t eventStage = 0; eventStage < EventStage::SIZE; eventStage++) { for (uint32_t touchEventType = 0; touchEventType < EventType::SIZE; touchEventType++) { EventMarker& eventMarker = GetTouchId(eventAction, eventStage, touchEventType); if (!eventMarker.IsEmpty() || HasActivePseudo()) { if (!touchEventComponent_) { touchEventComponent_ = AceType::MakeRefPtr(); } if (HasActivePseudo() && touchEventType != EventType::TOUCH_MOVE && eventAction == EventAction::ON && eventStage == EventStage::BUBBLE) { PrepareTouchEvent(eventMarker, touchEventType); } touchEventComponent_->SetEvent(eventMarker, eventAction, eventStage, touchEventType); } } } } } void DOMNode::UpdateMouseEventComponent() { if (!declaration_) { return; } auto& mouseEvent = declaration_->MaybeResetEvent(EventTag::COMMON_MOUSE_EVENT); if (!mouseEvent.IsValid()) { return; } if (!mouseEvent.mouse.eventMarker.IsEmpty()) { if (!mouseEventComponent_) { mouseEventComponent_ = AceType::MakeRefPtr(); } mouseEventComponent_->SetOnMouseId(mouseEvent.mouse.eventMarker); } PrepareMouseHoverEvent(); if (!mouseEvent.mouseHover.eventMarker.IsEmpty()) { if (!mouseEventComponent_) { mouseEventComponent_ = AceType::MakeRefPtr(); } mouseEventComponent_->SetOnMouseHoverId(mouseEvent.mouseHover.eventMarker); } if (!mouseEvent.mouseHoverExit.eventMarker.IsEmpty()) { if (!mouseEventComponent_) { mouseEventComponent_ = AceType::MakeRefPtr(); } mouseEventComponent_->SetOnMouseHoverExitId(mouseEvent.mouseHoverExit.eventMarker); } } void DOMNode::UpdateGestureEventComponent() { if (!declaration_) { return; } if (!GetClickId().IsEmpty() || !GetDoubleClickId().IsEmpty() || !GetLongPressId().IsEmpty() || !GetPinchStartId().IsEmpty() || !GetPinchUpdateId().IsEmpty() || !GetPinchEndId().IsEmpty() || !GetPinchCancelId().IsEmpty() || declaration_->HasIdAttr() || !GetDragStartId().IsEmpty() || !GetDragId().IsEmpty() || !GetDragEndId().IsEmpty()) { if (!gestureEventComponent_) { gestureEventComponent_ = AceType::MakeRefPtr(); } gestureEventComponent_->SetOnClickId(GetClickId()); gestureEventComponent_->SetOnDoubleClickId(GetDoubleClickId()); gestureEventComponent_->SetOnLongPressId(GetLongPressId()); gestureEventComponent_->SetOnPinchStartId(GetPinchStartId()); gestureEventComponent_->SetOnPinchUpdateId(GetPinchUpdateId()); gestureEventComponent_->SetOnPinchEndId(GetPinchEndId()); gestureEventComponent_->SetOnPinchCancelId(GetPinchCancelId()); gestureEventComponent_->SetOnFreeDragStartId(GetDragStartId()); gestureEventComponent_->SetOnFreeDragUpdateId(GetDragId()); gestureEventComponent_->SetOnFreeDragEndId(GetDragEndId()); auto onDragStartGestureId = []() -> GestureItemInfo { GestureItemInfo itemInfo; itemInfo.pixelMap = DOMDocument::pixelMap_; itemInfo.offsetX = DOMDocument::pixelMapOffsetX_; itemInfo.offsetY = DOMDocument::pixelMapOffsetY_; return itemInfo; }; gestureEventComponent_->SetOnDragStartId(onDragStartGestureId); } } void DOMNode::UpdateFocusableEventComponents() { if (!declaration_ || (UNFOCUSABLED_NODE.find(tag_) != UNFOCUSABLED_NODE.end())) { return; } auto& focusableAttr = static_cast(declaration_->GetAttribute(AttributeTag::COMMON_FOCUSABLE_ATTR)); auto& focusEvent = declaration_->MaybeResetEvent(EventTag::COMMON_FOCUS_EVENT); auto& keyEvent = static_cast(declaration_->GetEvent(EventTag::COMMON_KEY_EVENT)); bool focusable = focusableAttr.IsValid() && focusableAttr.focusable.second; bool supportFocus = focusEvent.IsValid() && !focusEvent.focus.eventMarker.IsEmpty(); bool supportBlur = focusEvent.IsValid() && !focusEvent.blur.eventMarker.IsEmpty(); bool supportKey = keyEvent.IsValid() && !keyEvent.key.eventMarker.IsEmpty(); if (!focusable && GetClickId().IsEmpty() && !supportFocus && !supportBlur && !supportKey && !HasFocusPseudo()) { return; } if (!focusableEventComponent_) { focusableEventComponent_ = AceType::MakeRefPtr(); declaration_->SetFocusableController(focusableEventComponent_->GetFocusableController()); } if (focusableAttr.IsValid() && focusableAttr.focusable.second) { focusableEventComponent_->SetFocusable(focusableAttr.focusable.first); } else { focusableEventComponent_->SetFocusable(true); } focusableEventComponent_->SetOnClickId(GetClickId()); PrepareFocusableEventId(); if (focusEvent.IsValid()) { focusableEventComponent_->SetOnBlurId(focusEvent.blur.eventMarker); focusableEventComponent_->SetOnFocusId(focusEvent.focus.eventMarker); } if (keyEvent.IsValid()) { focusableEventComponent_->SetOnKeyId(keyEvent.key.eventMarker); } if (g_focusableNode.empty()) { g_focusableNode = std::unordered_set({ DOM_NODE_TAG_BUTTON, DOM_NODE_TAG_DIV, DOM_NODE_TAG_FORM, DOM_NODE_TAG_LIST, DOM_NODE_TAG_LIST_ITEM, DOM_NODE_TAG_REFRESH, DOM_NODE_TAG_INPUT, DOM_NODE_TAG_OPTION, DOM_NODE_TAG_PROGRESS, DOM_NODE_TAG_POPUP, DOM_NODE_TAG_RATING, DOM_NODE_TAG_SELECT, DOM_NODE_TAG_SLIDER, DOM_NODE_TAG_STACK, DOM_NODE_TAG_STEPPER, DOM_NODE_TAG_STEPPER_ITEM, DOM_NODE_TAG_SWIPER, DOM_NODE_TAG_SWITCH, DOM_NODE_TAG_TABS, DOM_NODE_TAG_TAB_BAR, DOM_NODE_TAG_TAB_CONTENT, DOM_NODE_TAG_TEXTAREA, DOM_NODE_TAG_TOGGLE, DOM_NODE_TAG_SEARCH, DOM_NODE_TAG_VIDEO, DOM_NODE_TAG_CALENDAR, DOM_NODE_TAG_PICKER_DIALOG, DOM_NODE_TAG_PIECE, }); } if (g_focusableNode.find(tag_) != g_focusableNode.end()) { focusableEventComponent_->SetFocusNode(false); } else { focusableEventComponent_->SetFocusNode(true); } } void DOMNode::UpdatePositionProps() { if (!declaration_ || !declaration_->HasPositionStyle() || GetPosition() == PositionType::PTFIXED) { return; } declaration_->SetHasPositionStyle(false); auto tweenComponent = AceType::DynamicCast(rootComponent_->GetChild()); if (tweenComponent) { UpdateTweenPosition(tweenComponent); UpdatePositionAnimations(tweenComponent); } else { // Set position props to first RenderComponent of node auto compositeComponent = AceType::DynamicCast(rootComponent_->GetChild()); if (!compositeComponent) { return; } compositeComponent->SetHasLeft(declaration_->HasLeft()); compositeComponent->SetHasTop(declaration_->HasTop()); compositeComponent->SetHasBottom(declaration_->HasBottom()); compositeComponent->SetHasRight(declaration_->HasRight()); auto& positionStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_POSITION_STYLE)); if (positionStyle.IsValid()) { if (declaration_->HasLeft()) { compositeComponent->SetLeft(positionStyle.left); // reset value declaration_->SetHasLeft(false); } if (declaration_->HasRight()) { compositeComponent->SetRight(positionStyle.right); declaration_->SetHasRight(false); } if (declaration_->HasTop()) { compositeComponent->SetTop(positionStyle.top); declaration_->SetHasTop(false); } if (declaration_->HasBottom()) { compositeComponent->SetBottom(positionStyle.bottom); declaration_->SetHasBottom(false); } compositeComponent->SetPositionType(positionStyle.position); } UpdatePositionAnimations(compositeComponent); } } void DOMNode::UpdateTweenPosition(const RefPtr tweenComponent) { if (!declaration_ || !tweenComponent) { return; } tweenComponent->SetHasLeft(declaration_->HasLeft()); tweenComponent->SetHasTop(declaration_->HasTop()); tweenComponent->SetHasBottom(declaration_->HasBottom()); tweenComponent->SetHasRight(declaration_->HasRight()); auto& positionStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_POSITION_STYLE)); if (!positionStyle.IsValid()) { return; } if (declaration_->HasLeft()) { tweenComponent->SetLeft(positionStyle.left); // reset value declaration_->SetHasLeft(false); } if (declaration_->HasRight()) { tweenComponent->SetRight(positionStyle.right); declaration_->SetHasRight(false); } if (declaration_->HasTop()) { tweenComponent->SetTop(positionStyle.top); declaration_->SetHasTop(false); } if (declaration_->HasBottom()) { tweenComponent->SetBottom(positionStyle.bottom); declaration_->SetHasBottom(false); } tweenComponent->SetPositionType(positionStyle.position); } void DOMNode::UpdatePositionComponent() { if (!declaration_ || !declaration_->HasPositionStyle() || GetPosition() != PositionType::PTFIXED) { return; } if (!positionComponent_) { positionComponent_ = AceType::MakeRefPtr(); } auto& positionStyle = static_cast(declaration_->GetStyle(StyleTag::COMMON_POSITION_STYLE)); if (positionStyle.IsValid()) { positionComponent_->SetTop(positionStyle.top); positionComponent_->SetRight(positionStyle.right); positionComponent_->SetBottom(positionStyle.bottom); positionComponent_->SetLeft(positionStyle.left); positionComponent_->SetHasLeft(declaration_->HasLeft()); positionComponent_->SetHasRight(declaration_->HasRight()); positionComponent_->SetHasBottom(declaration_->HasBottom()); positionComponent_->SetHasTop(declaration_->HasTop()); } UpdatePositionAnimations(positionComponent_); } RefPtr DOMNode::CompositeSpecializedComponent(const std::vector>& components) { const auto& specializedComponent = GetSpecializedComponent(); if (specializedComponent) { bool touchable = true; if (declaration_) { auto& touchableAttr = static_cast(declaration_->GetAttribute(AttributeTag::COMMON_TOUCHABLE_ATTR)); if (touchableAttr.IsValid()) { touchable = touchableAttr.touchable; } } specializedComponent->SetTouchable(touchable); } if (components.empty()) { return specializedComponent; } else { const auto& parent = components.back(); if (parent) { parent->SetChild(specializedComponent); } return AceType::DynamicCast(components.front()); } } #ifndef WEARABLE_PRODUCT void DOMNode::UpdateMultimodalComponent() { if (!declaration_ || GetClickId().IsEmpty()) { return; } auto& multimodalAttr = static_cast(declaration_->GetAttribute(AttributeTag::COMMON_MULTIMODAL_ATTR)); if (!multimodalAttr.IsValid() || multimodalAttr.IsUnavailable() || multimodalAttr.scene == SceneLabel::SWITCH) { return; } if (!multimodalComponent_) { multimodalComponent_ = AceType::MakeRefPtr(pageId_); } multimodalComponent_->SetMultimodalProperties(multimodalAttr); multimodalComponent_->SetOnClickId(GetClickId()); } #endif RefPtr DOMNode::GetThemeConstants() const { auto themeManager = GetThemeManager(); if (!themeManager) { return nullptr; } return themeManager->GetThemeConstants(); } Color DOMNode::ParseColor(const std::string& value, uint32_t maskAlpha) const { auto themeConstants = GetThemeConstants(); if (!themeConstants) { return Color::TRANSPARENT; } auto&& noRefFunc = [&value, maskAlpha = maskAlpha]() { return Color::FromString(value, maskAlpha); }; auto&& idRefFunc = [constants = themeConstants](uint32_t refId) { return constants->GetColor(refId); }; return ParseThemeReference(value, noRefFunc, idRefFunc, Color::TRANSPARENT); } double DOMNode::ParseDouble(const std::string& value) const { auto themeConstants = GetThemeConstants(); if (!themeConstants) { return 0.0; } auto&& noRefFunc = [&value]() { return StringUtils::StringToDouble(value); }; auto&& idRefFunc = [constants = themeConstants](uint32_t refId) { return constants->GetDouble(refId); }; return ParseThemeReference(value, noRefFunc, idRefFunc, 0.0); } CalcDimension DOMNode::ParseDimension(const std::string& value) const { auto themeConstants = GetThemeConstants(); if (!themeConstants) { return Dimension(); } auto&& noRefFunc = [&value]() { return StringUtils::StringToDimension(value); }; auto&& idRefFunc = [constants = themeConstants](uint32_t refId) { return constants->GetDimension(refId); }; if (value.find("calc") != std::string::npos) { return CalcDimension(value, DimensionUnit::CALC); } else { return ParseThemeReference(value, noRefFunc, idRefFunc, Dimension()); } } Dimension DOMNode::ParseLineHeight(const std::string& value) const { auto themeConstants = GetThemeConstants(); if (!themeConstants) { return Dimension(); } const auto& parseResult = ThemeUtils::ParseThemeIdReference(value, GetThemeConstants()); if (!parseResult.parseSuccess) { return StringUtils::StringToDimension(value); } auto&& noRefFunc = [&value]() { return StringUtils::StringToDouble(value); }; auto&& idRefFunc = [constants = themeConstants](uint32_t refId) { return constants->GetDouble(refId); }; auto lineHeightScale = ParseThemeReference(value, noRefFunc, idRefFunc, 1.0); // If got 0.0 from ThemeConstants, use default 1.0 lineHeightScale = NearZero(lineHeightScale) ? 1.0 : lineHeightScale; return Dimension(lineHeightScale, DimensionUnit::PERCENT); } std::vector DOMNode::ParseFontFamilies(const std::string& value) const { std::vector fontFamilies; std::stringstream stream(value); std::string fontFamily; auto themeConstants = GetThemeConstants(); if (!themeConstants) { return fontFamilies; } auto&& idRefFunc = [constants = themeConstants](uint32_t refId) { return constants->GetString(refId); }; while (getline(stream, fontFamily, ',')) { auto&& noRefFunc = [&fontFamily]() { return fontFamily; }; fontFamilies.emplace_back(ParseThemeReference(fontFamily, noRefFunc, idRefFunc, fontFamily)); } return fontFamilies; } std::vector DOMNode::ParsePreferFontSizes(const std::string& value) const { std::vector prefers; std::stringstream stream(value); std::string fontSize; while (getline(stream, fontSize, ',')) { prefers.emplace_back(ParseDimension(fontSize)); } std::sort(prefers.begin(), prefers.end(), [](const Dimension& left, const Dimension& right) { return left.Value() > right.Value(); }); return prefers; } std::string DOMNode::ParseImageSrc(const std::string& imgSrc) const { return ThemeUtils::ProcessImageSource(imgSrc, GetThemeConstants()); } void DOMNode::AdjustParamInLiteMode() { if (!declaration_) { return; } declaration_->SetUseLiteStyle(true); // Change default value if (boxComponent_) { boxComponent_->SetUseLiteStyle(true); boxComponent_->SetAlignment(Alignment::TOP_CENTER); } auto& flexStyle = declaration_->MaybeResetStyle(StyleTag::COMMON_FLEX_STYLE); if (flexStyle.IsValid()) { flexStyle.flexShrink = 0.0; } AdjustSpecialParamInLiteMode(); } void DOMNode::CreateDeclaration(const std::string& tag) { declaration_ = DeclarationCreatorManager::GetInstance().CreateDeclaration(tag); if (!declaration_) { return; } declaration_->SetCachePseudoClassStyle( [weak = WeakClaim(this)](const std::pair& pseudoClassStyle) { auto node = weak.Upgrade(); if (node) { node->CachePseudoClassStyle(pseudoClassStyle); } }); declaration_->SetOnSetStyleFinished([weak = WeakClaim(this)]() { auto node = weak.Upgrade(); if (node) { node->OnSetStyleFinished(); } }); declaration_->SetOnSetAttribute([weakComponent = WeakPtr(rootComponent_)]() { auto rootComponent = weakComponent.Upgrade(); if (rootComponent) { rootComponent->SetUpdateType(UpdateType::ALL); } }); } } // namespace OHOS::Ace::Framework