• 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 constexpr float ZERO_MEASURE_CONTENT_SIZE = 0.0f;
37 } // namespace
38 ProgressLayoutAlgorithm::ProgressLayoutAlgorithm() = default;
39 
MeasureContent(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)40 std::optional<SizeF> ProgressLayoutAlgorithm::MeasureContent(
41     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
42 {
43     auto host = layoutWrapper->GetHostNode();
44     CHECK_NULL_RETURN(host, std::nullopt);
45     auto pattern = host->GetPattern<ProgressPattern>();
46     CHECK_NULL_RETURN(pattern, std::nullopt);
47     if (pattern->UseContentModifier()) {
48         if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
49             host->GetGeometryNode()->ResetContent();
50         } else {
51             host->GetGeometryNode()->Reset();
52         }
53         return std::nullopt;
54     }
55     auto pipeline = PipelineBase::GetCurrentContext();
56     CHECK_NULL_RETURN(pipeline, std::nullopt);
57     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
58         return MeasureContentForApiNine(contentConstraint, layoutWrapper);
59     }
60     auto progressTheme = pipeline->GetTheme<ProgressTheme>(host->GetThemeScopeId());
61     auto progressLayoutProperty = DynamicCast<ProgressLayoutProperty>(layoutWrapper->GetLayoutProperty());
62     CHECK_NULL_RETURN(progressLayoutProperty, std::nullopt);
63     auto layoutProperty = AceType::DynamicCast<LayoutProperty>(layoutWrapper->GetLayoutProperty());
64     CHECK_NULL_RETURN(layoutProperty, std::nullopt);
65     auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
66     if (layoutPolicy.has_value() && (layoutPolicy->IsWrap() || layoutPolicy->IsFix())) {
67         return SizeF(ZERO_MEASURE_CONTENT_SIZE, ZERO_MEASURE_CONTENT_SIZE);
68     }
69     type_ = progressLayoutProperty->GetType().value_or(ProgressType::LINEAR);
70     Dimension defaultThickness;
71     if (progressTheme) {
72         defaultThickness = (type_ == ProgressType::RING) ? Dimension(progressTheme->GetRingThickness())
73                                                          : Dimension(progressTheme->GetTrackThickness());
74     } else {
75         defaultThickness = Dimension(strokeWidth_);
76     }
77     strokeWidth_ = progressLayoutProperty->GetStrokeWidth().value_or(defaultThickness).ConvertToPx();
78 
79     float diameter =
80         progressTheme ? progressTheme->GetRingDiameter().ConvertToPx() : DEFALT_RING_DIAMETER.ConvertToPx();
81     auto selfIdealWidth = contentConstraint.selfIdealSize.Width();
82     auto selfIdealHeight = contentConstraint.selfIdealSize.Height();
83     float width_ = selfIdealWidth.value_or(contentConstraint.percentReference.Width());
84     float height_ = selfIdealHeight.value_or(strokeWidth_);
85     if (type_ == ProgressType::RING || type_ == ProgressType::SCALE || type_ == ProgressType::MOON) {
86         if (!selfIdealHeight) {
87             if (!selfIdealWidth) {
88                 width_ = diameter;
89             }
90             height_ = width_;
91         } else {
92             if (selfIdealWidth) {
93                 height_ = std::min(width_, height_);
94             }
95             width_ = height_;
96         }
97     } else if (type_ == ProgressType::CAPSULE) {
98         if (!selfIdealWidth) {
99             width_ = contentConstraint.percentReference.Width();
100         }
101         if (!selfIdealHeight) {
102             height_ = contentConstraint.parentIdealSize.Height().value_or(GetChildHeight(layoutWrapper, width_));
103         }
104         auto renderContext = host->GetRenderContext();
105         CHECK_NULL_RETURN(renderContext, std::nullopt);
106         float minSize = std::min(width_, height_);
107         renderContext->UpdateBorderRadius(BorderRadiusProperty(Dimension(minSize / 2.0f)));
108     } else if (type_ == ProgressType::LINEAR) {
109         if (width_ >= height_) {
110             height_ = std::min(height_, strokeWidth_);
111         } else {
112             width_ = std::min(width_, strokeWidth_);
113         }
114     }
115     return SizeF(width_, height_);
116 }
117 
MeasureContentForApiNine(const LayoutConstraintF & contentConstraint,LayoutWrapper * layoutWrapper)118 std::optional<SizeF> ProgressLayoutAlgorithm::MeasureContentForApiNine(
119     const LayoutConstraintF& contentConstraint, LayoutWrapper* layoutWrapper)
120 {
121     auto pipeline = PipelineBase::GetCurrentContext();
122     CHECK_NULL_RETURN(pipeline, std::nullopt);
123     auto progressLayoutProperty = DynamicCast<ProgressLayoutProperty>(layoutWrapper->GetLayoutProperty());
124     auto progressTheme = pipeline->GetTheme<ProgressTheme>(progressLayoutProperty->GetThemeScopeId());
125     CHECK_NULL_RETURN(progressLayoutProperty, std::nullopt);
126     type_ = progressLayoutProperty->GetType().value_or(ProgressType::LINEAR);
127     strokeWidth_ = progressLayoutProperty->GetStrokeWidth().
128                         value_or(progressTheme ? (type_ == ProgressType::SCALE ? progressTheme->GetScaleLength() :
129                             progressTheme->GetTrackThickness()): Dimension(strokeWidth_)).ConvertToPx();
130     float diameter =
131         progressTheme ? progressTheme->GetRingDiameter().ConvertToPx() : DEFALT_RING_DIAMETER.ConvertToPx();
132     float width_ = progressTheme ? progressTheme->GetTrackWidth().ConvertToPx() : contentConstraint.maxSize.Width();
133     auto selfIdealWidth = contentConstraint.selfIdealSize.Width();
134     auto selfIdealHeight = contentConstraint.selfIdealSize.Height();
135     if (selfIdealWidth) {
136         width_ = selfIdealWidth.value();
137     }
138     float height_ = strokeWidth_ * 2.0f;
139     if (selfIdealHeight) {
140         height_ = selfIdealHeight.value();
141     }
142     if (type_ == ProgressType::RING || type_ == ProgressType::SCALE || type_ == ProgressType::MOON) {
143         if (!selfIdealWidth && !selfIdealHeight) {
144             width_ = diameter;
145             height_ = width_;
146         } else if (selfIdealWidth && !selfIdealHeight) {
147             height_ = width_;
148         } else if (selfIdealHeight && !selfIdealWidth) {
149             width_ = height_;
150         }
151     } else if (type_ == ProgressType::CAPSULE) {
152         if (!selfIdealHeight) {
153             height_ = diameter;
154         }
155         if (!selfIdealWidth) {
156             width_ = diameter;
157         }
158     }
159     height_ = std::min(height_, static_cast<float>(contentConstraint.maxSize.Height()));
160     width_ = std::min(width_, static_cast<float>(contentConstraint.maxSize.Width()));
161     if (type_ == ProgressType::LINEAR) {
162         strokeWidth_ = std::min(strokeWidth_, height_ / 2.0f);
163         strokeWidth_ = std::min(strokeWidth_, width_ / 2.0f);
164     }
165     return SizeF(width_, height_);
166 }
167 
GetType() const168 ProgressType ProgressLayoutAlgorithm::GetType() const
169 {
170     return type_;
171 }
172 
GetStrokeWidth() const173 float ProgressLayoutAlgorithm::GetStrokeWidth() const
174 {
175     return strokeWidth_;
176 }
177 
GetChildHeight(LayoutWrapper * layoutWrapper,float width) const178 float ProgressLayoutAlgorithm::GetChildHeight(LayoutWrapper* layoutWrapper, float width) const
179 {
180     auto host = layoutWrapper->GetHostNode();
181     CHECK_NULL_RETURN(host, DEFALT_CAPSULE_WIDTH.ConvertToPx());
182     auto paintProperty = host->GetPaintProperty<ProgressPaintProperty>();
183     CHECK_NULL_RETURN(paintProperty, DEFALT_CAPSULE_WIDTH.ConvertToPx());
184     auto pipeline = PipelineBase::GetCurrentContext();
185     CHECK_NULL_RETURN(pipeline, DEFALT_CAPSULE_WIDTH.ConvertToPx());
186     auto progressTheme = pipeline->GetTheme<ProgressTheme>(host->GetThemeScopeId());
187     Dimension margin = progressTheme->GetTextMargin();
188     auto childWrapper = layoutWrapper->GetOrCreateChildByIndex(0);
189     CHECK_NULL_RETURN(childWrapper, DEFALT_CAPSULE_WIDTH.ConvertToPx());
190     auto layoutProperty = AceType::DynamicCast<ProgressLayoutProperty>(layoutWrapper->GetLayoutProperty());
191     CHECK_NULL_RETURN(layoutProperty, DEFALT_CAPSULE_WIDTH.ConvertToPx());
192 
193     auto childLayoutProperty = AceType::DynamicCast<TextLayoutProperty>(childWrapper->GetLayoutProperty());
194     CHECK_NULL_RETURN(childLayoutProperty, DEFALT_CAPSULE_WIDTH.ConvertToPx());
195     auto childConstraint = layoutProperty->CreateChildConstraint();
196     childConstraint.maxSize.SetWidth(width);
197     childWrapper->Measure(childConstraint);
198     auto childSize = childWrapper->GetGeometryNode()->GetContentSize();
199     if (childSize.Width() > (width - 2 * margin.ConvertToPx())) {
200         CalcSize defaultCalcSize((CalcLength(width - 2 * margin.ConvertToPx())), std::nullopt);
201         childLayoutProperty->UpdateUserDefinedIdealSize(defaultCalcSize);
202     }
203     float childHeight =
204         paintProperty->GetTextSize().value_or(progressTheme->GetTextSize()).ConvertToPx() + 2 * margin.ConvertToPx();
205 
206     auto fontScale = pipeline->GetFontScale();
207     if (GreatOrEqualCustomPrecision(fontScale, progressTheme->GetFontScale()) && (GetType() == ProgressType::CAPSULE)) {
208         const auto& paddingProperty = layoutProperty->GetPaddingProperty();
209         if (!(paddingProperty &&
210                 ((paddingProperty->top != std::nullopt) || (paddingProperty->bottom != std::nullopt)))) {
211             childHeight = childHeight + (progressTheme->GetfontScalePadding()).ConvertToPx();
212         }
213     }
214 
215     return childHeight;
216 }
217 } // namespace OHOS::Ace::NG
218