• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 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/progress/progress_layout_algorithm.h"
17 
18 #include <algorithm>
19 
20 #include "base/geometry/dimension.h"
21 #include "base/log/log_wrapper.h"
22 #include "base/utils/utils.h"
23 #include "core/components/common/properties/color.h"
24 #include "core/components/progress/progress_component.h"
25 #include "core/components/progress/progress_theme.h"
26 #include "core/components_ng/pattern/progress/progress_date.h"
27 #include "core/components_ng/pattern/progress/progress_layout_property.h"
28 #include "core/components_ng/pattern/progress/progress_paint_property.h"
29 #include "core/components_ng/pattern/progress/progress_pattern.h"
30 #include "core/components_ng/pattern/text/text_layout_property.h"
31 
32 namespace OHOS::Ace::NG {
33 namespace {
34 const Dimension DEFALT_RING_DIAMETER = 72.0_vp;
35 const Dimension DEFALT_CAPSULE_WIDTH = 28.0_vp;
36 } // namespace
37 ProgressLayoutAlgorithm::ProgressLayoutAlgorithm() = default;
38 
MeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)39 std::optional<SizeF> ProgressLayoutAlgorithm::MeasureContent(
40     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
41 {
42     auto host = layoutWrapper->GetHostNode();
43     CHECK_NULL_RETURN(host, std::nullopt);
44     auto pattern = host->GetPattern<ProgressPattern>();
45     CHECK_NULL_RETURN(pattern, std::nullopt);
46     if (pattern->UseContentModifier()) {
47         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
48             host->GetGeometryNode()->ResetContent();
49         } else {
50             host->GetGeometryNode()->Reset();
51         }
52         return std::nullopt;
53     }
54     auto pipeline = PipelineBase::GetCurrentContext();
55     CHECK_NULL_RETURN(pipeline, std::nullopt);
56     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
57         return MeasureContentForApiNine(contentConstraint, layoutWrapper);
58     }
59     auto progressTheme = pipeline->GetTheme<ProgressTheme>(host->GetThemeScopeId());
60     auto progressLayoutProperty = DynamicCast<ProgressLayoutProperty>(layoutWrapper->GetLayoutProperty());
61     CHECK_NULL_RETURN(progressLayoutProperty, std::nullopt);
62     type_ = progressLayoutProperty->GetType().value_or(ProgressType::LINEAR);
63     Dimension defaultThickness;
64     if (progressTheme) {
65         defaultThickness = (type_ == ProgressType::RING) ? Dimension(progressTheme->GetRingThickness())
66                                                          : Dimension(progressTheme->GetTrackThickness());
67     } else {
68         defaultThickness = Dimension(strokeWidth_);
69     }
70     strokeWidth_ = progressLayoutProperty->GetStrokeWidth().value_or(defaultThickness).ConvertToPx();
71 
72     float diameter =
73         progressTheme ? progressTheme->GetRingDiameter().ConvertToPx() : DEFALT_RING_DIAMETER.ConvertToPx();
74     auto selfIdealWidth = contentConstraint.selfIdealSize.Width();
75     auto selfIdealHeight = contentConstraint.selfIdealSize.Height();
76     float width_ = selfIdealWidth.value_or(contentConstraint.percentReference.Width());
77     float height_ = selfIdealHeight.value_or(strokeWidth_);
78     if (type_ == ProgressType::RING || type_ == ProgressType::SCALE || type_ == ProgressType::MOON) {
79         if (!selfIdealHeight) {
80             if (!selfIdealWidth) {
81                 width_ = diameter;
82             }
83             height_ = width_;
84         } else {
85             if (selfIdealWidth) {
86                 height_ = std::min(width_, height_);
87             }
88             width_ = height_;
89         }
90     } else if (type_ == ProgressType::CAPSULE) {
91         if (!selfIdealWidth) {
92             width_ = contentConstraint.percentReference.Width();
93         }
94         if (!selfIdealHeight) {
95             height_ = contentConstraint.parentIdealSize.Height().value_or(GetChildHeight(layoutWrapper, width_));
96         }
97         auto renderContext = host->GetRenderContext();
98         CHECK_NULL_RETURN(renderContext, std::nullopt);
99         float minSize = std::min(width_, height_);
100         renderContext->UpdateBorderRadius(BorderRadiusProperty(Dimension(minSize / 2.0f)));
101     } else if (type_ == ProgressType::LINEAR) {
102         if (width_ >= height_) {
103             height_ = std::min(height_, strokeWidth_);
104         } else {
105             width_ = std::min(width_, strokeWidth_);
106         }
107     }
108     return SizeF(width_, height_);
109 }
110 
MeasureContentForApiNine(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)111 std::optional<SizeF> ProgressLayoutAlgorithm::MeasureContentForApiNine(
112     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
113 {
114     auto pipeline = PipelineBase::GetCurrentContext();
115     CHECK_NULL_RETURN(pipeline, std::nullopt);
116     auto progressLayoutProperty = DynamicCast<ProgressLayoutProperty>(layoutWrapper->GetLayoutProperty());
117     auto progressTheme = pipeline->GetTheme<ProgressTheme>(progressLayoutProperty->GetThemeScopeId());
118     CHECK_NULL_RETURN(progressLayoutProperty, std::nullopt);
119     type_ = progressLayoutProperty->GetType().value_or(ProgressType::LINEAR);
120     strokeWidth_ = progressLayoutProperty->GetStrokeWidth().
121                         value_or(progressTheme ? (type_ == ProgressType::SCALE ? progressTheme->GetScaleLength() :
122                             progressTheme->GetTrackThickness()): Dimension(strokeWidth_)).ConvertToPx();
123     float diameter =
124         progressTheme ? progressTheme->GetRingDiameter().ConvertToPx() : DEFALT_RING_DIAMETER.ConvertToPx();
125     float width_ = progressTheme ? progressTheme->GetTrackWidth().ConvertToPx() : contentConstraint.maxSize.Width();
126     auto selfIdealWidth = contentConstraint.selfIdealSize.Width();
127     auto selfIdealHeight = contentConstraint.selfIdealSize.Height();
128     if (selfIdealWidth) {
129         width_ = selfIdealWidth.value();
130     }
131     float height_ = strokeWidth_ * 2.0f;
132     if (selfIdealHeight) {
133         height_ = selfIdealHeight.value();
134     }
135     if (type_ == ProgressType::RING || type_ == ProgressType::SCALE || type_ == ProgressType::MOON) {
136         if (!selfIdealWidth && !selfIdealHeight) {
137             width_ = diameter;
138             height_ = width_;
139         } else if (selfIdealWidth && !selfIdealHeight) {
140             height_ = width_;
141         } else if (selfIdealHeight && !selfIdealWidth) {
142             width_ = height_;
143         }
144     } else if (type_ == ProgressType::CAPSULE) {
145         if (!selfIdealHeight) {
146             height_ = diameter;
147         }
148         if (!selfIdealWidth) {
149             width_ = diameter;
150         }
151     }
152     height_ = std::min(height_, static_cast<float>(contentConstraint.maxSize.Height()));
153     width_ = std::min(width_, static_cast<float>(contentConstraint.maxSize.Width()));
154     if (type_ == ProgressType::LINEAR) {
155         strokeWidth_ = std::min(strokeWidth_, height_ / 2.0f);
156         strokeWidth_ = std::min(strokeWidth_, width_ / 2.0f);
157     }
158     return SizeF(width_, height_);
159 }
160 
GetType() const161 ProgressType ProgressLayoutAlgorithm::GetType() const
162 {
163     return type_;
164 }
165 
GetStrokeWidth() const166 float ProgressLayoutAlgorithm::GetStrokeWidth() const
167 {
168     return strokeWidth_;
169 }
170 
GetChildHeight(LayoutWrapper * layoutWrapper,float width) const171 float ProgressLayoutAlgorithm::GetChildHeight(LayoutWrapper* layoutWrapper, float width) const
172 {
173     auto host = layoutWrapper->GetHostNode();
174     CHECK_NULL_RETURN(host, DEFALT_CAPSULE_WIDTH.ConvertToPx());
175     auto paintProperty = host->GetPaintProperty<ProgressPaintProperty>();
176     CHECK_NULL_RETURN(paintProperty, DEFALT_CAPSULE_WIDTH.ConvertToPx());
177     auto pipeline = PipelineBase::GetCurrentContext();
178     CHECK_NULL_RETURN(pipeline, DEFALT_CAPSULE_WIDTH.ConvertToPx());
179     auto progressTheme = pipeline->GetTheme<ProgressTheme>(host->GetThemeScopeId());
180     Dimension margin = progressTheme->GetTextMargin();
181     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
182     CHECK_NULL_RETURN(childWrapper, DEFALT_CAPSULE_WIDTH.ConvertToPx());
183     auto layoutProperty = AceType::DynamicCast<ProgressLayoutProperty>(layoutWrapper->GetLayoutProperty());
184     CHECK_NULL_RETURN(layoutProperty, DEFALT_CAPSULE_WIDTH.ConvertToPx());
185 
186     auto childLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(childWrapper->GetLayoutProperty());
187     CHECK_NULL_RETURN(childLayoutProperty, DEFALT_CAPSULE_WIDTH.ConvertToPx());
188     auto childConstraint = layoutProperty->CreateChildConstraint();
189     childConstraint.maxSize.SetWidth(width);
190     childWrapper->Measure(childConstraint);
191     auto childSize = childWrapper->GetGeometryNode()->GetContentSize();
192     if (childSize.Width() > (width - 2 * margin.ConvertToPx())) {
193         CalcSize defaultCalcSize((CalcLength(width - 2 * margin.ConvertToPx())), std::nullopt);
194         childLayoutProperty->UpdateUserDefinedIdealSize(defaultCalcSize);
195     }
196     float childHeight =
197         paintProperty->GetTextSize().value_or(progressTheme->GetTextSize()).ConvertToPx() + 2 * margin.ConvertToPx();
198 
199     auto fontScale = pipeline->GetFontScale();
200     if (GreatOrEqualCustomPrecision(fontScale, progressTheme->GetFontScale()) && (GetType() == ProgressType::CAPSULE)) {
201         const auto& paddingProperty = layoutProperty->GetPaddingProperty();
202         if (!(paddingProperty &&
203                 ((paddingProperty->top != std::nullopt) || (paddingProperty->bottom != std::nullopt)))) {
204             childHeight = childHeight + (progressTheme->GetfontScalePadding()).ConvertToPx();
205         }
206     }
207 
208     return childHeight;
209 }
210 } // namespace OHOS::Ace::NG
211