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