1 /*
2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/pattern/shape/shape_container_pattern.h"
17
18 #include "core/components_ng/base/view_stack_processor.h"
19 #include "core/components_ng/pattern/shape/shape_container_paint_method.h"
20
21 namespace OHOS::Ace::NG {
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool skipMeasure,bool skipLayout)22 bool ShapeContainerPattern::OnDirtyLayoutWrapperSwap(
23 const RefPtr<LayoutWrapper>& dirty, bool skipMeasure, bool skipLayout)
24 {
25 if (skipMeasure || dirty->SkipMeasureContent() || isShapeContainerInit_) {
26 return false;
27 }
28 ViewPortTransform();
29 return true;
30 }
31
ViewPortTransform()32 void ShapeContainerPattern::ViewPortTransform()
33 {
34 auto curFrameNode = GetHost();
35 auto renderContext = curFrameNode->GetRenderContext();
36 auto geoNode = curFrameNode->GetGeometryNode();
37 CHECK_NULL_VOID(geoNode);
38 auto contentSize = geoNode->GetContentSize();
39 auto paintProperty = curFrameNode->GetPaintProperty<ShapeContainerPaintProperty>();
40 if (paintProperty->HasShapeViewBox() && paintProperty->GetShapeViewBoxValue().IsValid()) {
41 double portWidth = paintProperty->GetShapeViewBoxValue().Width().ConvertToPx();
42 double portHeight = paintProperty->GetShapeViewBoxValue().Height().ConvertToPx();
43 double portLeft = paintProperty->GetShapeViewBoxValue().Left().ConvertToPx();
44 double portTop = paintProperty->GetShapeViewBoxValue().Top().ConvertToPx();
45 if (contentSize.IsPositive() && GreatNotEqual(portWidth, 0.0) && GreatNotEqual(portHeight, 0.0)) {
46 double scale = std::min(contentSize.Width() / portWidth, contentSize.Height() / portHeight);
47 double tx = contentSize.Width() * 0.5 - (portWidth * 0.5 + portLeft) * scale;
48 double ty = contentSize.Height() * 0.5 - (portHeight * 0.5 + portTop) * scale;
49 for (const auto& child : curFrameNode->GetChildren()) {
50 auto node = AceType::DynamicCast<FrameNode>(child);
51 CHECK_NULL_VOID(node);
52 auto context = node->GetRenderContext();
53 CHECK_NULL_VOID(context);
54 context->UpdateTransformCenter(DimensionOffset(Offset(0.0, 0.0)));
55 context->OnTransformTranslateUpdate({ tx, ty, 0 });
56 context->OnTransformScaleUpdate({ scale, scale });
57
58 if (context->HasOffset()) {
59 auto currentOffset = context->GetOffset();
60 auto newOffset = OffsetT(Dimension(currentOffset->GetX() * scale),
61 Dimension(currentOffset->GetY() * scale));
62 context->UpdateOffset(newOffset);
63 context->OnOffsetUpdate(newOffset);
64 node->MarkModifyDone();
65 }
66 }
67 }
68 }
69 isShapeContainerInit_ = true;
70 }
71
OnModifyDone()72 void ShapeContainerPattern::OnModifyDone()
73 {
74 auto host = GetHost();
75 CHECK_NULL_VOID(host);
76 auto paintProperty = host->GetPaintProperty<ShapeContainerPaintProperty>();
77 CHECK_NULL_VOID(paintProperty);
78 if (paintProperty->HasStrokeMiterLimit()) {
79 auto miterLimit = paintProperty->GetStrokeMiterLimitValue();
80 if (Negative(miterLimit)) {
81 paintProperty->UpdateStrokeMiterLimit(ShapePaintProperty::STROKE_MITERLIMIT_DEFAULT);
82 } else if (NonNegative(miterLimit) &&
83 LessNotEqual(miterLimit, ShapePaintProperty::STROKE_MITERLIMIT_MIN)) {
84 paintProperty->UpdateStrokeMiterLimit(ShapePaintProperty::STROKE_MITERLIMIT_MIN);
85 }
86 }
87
88 Pattern::OnModifyDone();
89 for (auto childNode : ChildNodes_) {
90 auto child = childNode.Upgrade();
91 if (!child) {
92 continue;
93 }
94 child->MarkNeedRenderOnly();
95 }
96 ChildNodes_.clear();
97 }
98
OnAttachToFrameNode()99 void ShapeContainerPattern::OnAttachToFrameNode()
100 {
101 auto host = GetHost();
102 CHECK_NULL_VOID(host);
103 host->GetLayoutProperty()->UpdateAlignment(Alignment::TOP_LEFT);
104 host->GetRenderContext()->SetClipToFrame(true);
105 }
106
CreateNodePaintMethod()107 RefPtr<NodePaintMethod> ShapeContainerPattern::CreateNodePaintMethod()
108 {
109 if (!shapeContainerModifier_) {
110 shapeContainerModifier_ = MakeRefPtr<ShapeContainerModifier>();
111 }
112 return MakeRefPtr<ShapeContainerPaintMethod>(shapeContainerModifier_);
113 }
114
UpdatePropertyImpl(const std::string & key,RefPtr<PropertyValueBase> value)115 void ShapeContainerPattern::UpdatePropertyImpl(const std::string& key, RefPtr<PropertyValueBase> value)
116 {
117 auto frameNode = GetHost();
118 CHECK_NULL_VOID(frameNode);
119 using Handler = std::function<void(RefPtr<PropertyValueBase>, RefPtr<FrameNode>)>;
120 static const std::unordered_map<std::string, Handler> handlers = {
121 { "ShapeStroke",
122 [](RefPtr<PropertyValueBase> value, RefPtr<FrameNode> frameNode) {
123 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
124 ACE_UPDATE_NODE_PAINT_PROPERTY(ShapePaintProperty, Stroke, *realValue, frameNode);
125 }
126 } },
127 { "ShapeDashOffset",
128 [](RefPtr<PropertyValueBase> value, RefPtr<FrameNode> frameNode) {
129 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
130 ACE_UPDATE_NODE_PAINT_PROPERTY(ShapePaintProperty, StrokeDashOffset, *realValue, frameNode);
131 }
132 } },
133 { "ShapeMiterLimit",
134 [](RefPtr<PropertyValueBase> value, RefPtr<FrameNode> frameNode) {
135 if (auto realValue = std::get_if<double>(&(value->GetValue()))) {
136 ACE_UPDATE_NODE_PAINT_PROPERTY(ShapePaintProperty, StrokeMiterLimit, *realValue, frameNode);
137 }
138 } },
139 { "ShapeFill",
140 [](RefPtr<PropertyValueBase> value, RefPtr<FrameNode> frameNode) {
141 if (auto realValue = std::get_if<Color>(&(value->GetValue()))) {
142 ACE_UPDATE_NODE_PAINT_PROPERTY(ShapePaintProperty, Fill, *realValue, frameNode);
143 ACE_UPDATE_NODE_RENDER_CONTEXT(ForegroundColor, *realValue, frameNode);
144 ACE_UPDATE_NODE_RENDER_CONTEXT(ForegroundColorFlag, true, frameNode);
145 }
146 } },
147 { "ShapeStrokeOpacity",
148 [](RefPtr<PropertyValueBase> value, RefPtr<FrameNode> frameNode) {
149 if (auto realValue = std::get_if<double>(&(value->GetValue()))) {
150 ACE_UPDATE_NODE_PAINT_PROPERTY(
151 ShapePaintProperty, StrokeOpacity, std::clamp(*realValue, 0.0, 1.0), frameNode);
152 }
153 } },
154 { "ShapeFillOpacity",
155 [](RefPtr<PropertyValueBase> value, RefPtr<FrameNode> frameNode) {
156 if (auto realValue = std::get_if<double>(&(value->GetValue()))) {
157 ACE_UPDATE_NODE_PAINT_PROPERTY(
158 ShapePaintProperty, FillOpacity, std::clamp(*realValue, 0.0, 1.0), frameNode);
159 }
160 } },
161 { "ShapeStrokeWidth",
162 [](RefPtr<PropertyValueBase> value, RefPtr<FrameNode> frameNode) {
163 if (auto realValue = std::get_if<CalcDimension>(&(value->GetValue()))) {
164 auto strokeWidth = realValue->IsNegative() ? 1.0_vp : *realValue;
165 ACE_UPDATE_NODE_PAINT_PROPERTY(ShapePaintProperty, StrokeWidth, strokeWidth, frameNode);
166 }
167 } },
168 };
169 auto it = handlers.find(key);
170 if (it != handlers.end()) {
171 it->second(value, frameNode);
172 }
173 if (frameNode->GetRerenderable()) {
174 for (auto childNode : ChildNodes_) {
175 auto child = childNode.Upgrade();
176 if (!child) {
177 continue;
178 }
179 child->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
180 }
181 }
182 }
183 } // namespace OHOS::Ace::NG
184