• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PROPERTIES_MEASURE_PROPERTIES_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PROPERTIES_MEASURE_PROPERTIES_H
18 
19 #include <array>
20 #include <cstdint>
21 #include <iomanip>
22 #include <optional>
23 #include <sstream>
24 #include <string>
25 #include <utility>
26 
27 #include "base/geometry/ng/offset_t.h"
28 #include "base/json/json_util.h"
29 #include "base/utils/utils.h"
30 #include "core/common/ace_application_info.h"
31 #include "core/components_ng/property/calc_length.h"
32 #include "core/pipeline/pipeline_base.h"
33 
34 namespace OHOS::Ace::NG {
35 const std::string BORDERZERO = "0.0";
36 
37 enum class MeasureType {
38     MATCH_PARENT,
39     MATCH_CONTENT,
40     MATCH_PARENT_CROSS_AXIS,
41     MATCH_PARENT_MAIN_AXIS,
42 };
43 
44 class CalcSize {
45 public:
46     CalcSize() = default;
47     ~CalcSize() = default;
CalcSize(const CalcLength & width,const CalcLength & height)48     CalcSize(const CalcLength& width, const CalcLength& height) : width_(width), height_(height) {}
CalcSize(std::optional<CalcLength> width,std::optional<CalcLength> height)49     CalcSize(std::optional<CalcLength> width, std::optional<CalcLength> height)
50         : width_(std::move(width)), height_(std::move(height))
51     {}
52 
Reset()53     void Reset()
54     {
55         width_.reset();
56         height_.reset();
57     }
58 
IsValid()59     bool IsValid() const
60     {
61         return width_ && height_;
62     }
63 
Width()64     const std::optional<CalcLength>& Width() const
65     {
66         return width_;
67     }
68 
Height()69     const std::optional<CalcLength>& Height() const
70     {
71         return height_;
72     }
73 
SetWidth(const std::optional<CalcLength> & width)74     void SetWidth(const std::optional<CalcLength>& width)
75     {
76         width_ = width;
77     }
78 
SetHeight(const std::optional<CalcLength> & height)79     void SetHeight(const std::optional<CalcLength>& height)
80     {
81         height_ = height;
82     }
83 
SetSizeT(const CalcSize & Size)84     void SetSizeT(const CalcSize& Size)
85     {
86         width_ = Size.Width();
87         height_ = Size.Height();
88     }
89 
90     bool operator==(const CalcSize& Size) const
91     {
92         return (width_ == Size.width_) && (height_ == Size.height_);
93     }
94 
95     bool operator!=(const CalcSize& Size) const
96     {
97         return !operator==(Size);
98     }
99 
UpdateSizeWithCheck(const CalcSize & size)100     bool UpdateSizeWithCheck(const CalcSize& size)
101     {
102         if ((width_ == size.width_) && ((height_ == size.height_))) {
103             return false;
104         }
105         if (size.width_) {
106             width_ = size.width_;
107         }
108         if (size.height_) {
109             height_ = size.height_;
110         }
111         return true;
112     }
113 
ClearSize(bool clearWidth,bool clearHeight)114     bool ClearSize(bool clearWidth, bool clearHeight)
115     {
116         bool changed = false;
117         if (clearWidth && width_.has_value()) {
118             width_.reset();
119             changed = true;
120         }
121         if (clearHeight && height_.has_value()) {
122             height_.reset();
123             changed = true;
124         }
125         return changed;
126     }
127 
WidthFixed()128     bool WidthFixed() const
129     {
130         return width_ && width_->GetDimension().Unit() != DimensionUnit::PERCENT;
131     }
132 
HeightFixed()133     bool HeightFixed() const
134     {
135         return height_ && height_->GetDimension().Unit() != DimensionUnit::PERCENT;
136     }
137 
PercentWidth()138     bool PercentWidth() const
139     {
140         return width_ && width_->GetDimension().Unit() == DimensionUnit::PERCENT;
141     }
142 
PercentHeight()143     bool PercentHeight() const
144     {
145         return height_ && height_->GetDimension().Unit() == DimensionUnit::PERCENT;
146     }
147 
ToString()148     std::string ToString() const
149     {
150         static const int32_t precision = 2;
151         std::stringstream ss;
152         ss << "[" << std::fixed << std::setprecision(precision);
153         ss << (width_ ? width_->ToString() : "NA");
154         ss << " x ";
155         ss << (height_ ? height_->ToString() : "NA");
156         ss << "]";
157         std::string output = ss.str();
158         return output;
159     }
160 
161 private:
162     std::optional<CalcLength> width_;
163     std::optional<CalcLength> height_;
164 };
165 
166 struct MeasureProperty {
167     std::optional<CalcSize> minSize;
168     std::optional<CalcSize> maxSize;
169     std::optional<CalcSize> selfIdealSize;
170 
ResetMeasureProperty171     void Reset()
172     {
173         minSize.reset();
174         maxSize.reset();
175         selfIdealSize.reset();
176     }
177 
178     bool operator==(const MeasureProperty& measureProperty) const
179     {
180         return (minSize == measureProperty.minSize) && (maxSize == measureProperty.maxSize) &&
181                (selfIdealSize == measureProperty.selfIdealSize);
182     }
183 
UpdateSelfIdealSizeWithCheckMeasureProperty184     bool UpdateSelfIdealSizeWithCheck(const CalcSize& size)
185     {
186         if (selfIdealSize == size) {
187             return false;
188         }
189         if (selfIdealSize.has_value()) {
190             return selfIdealSize->UpdateSizeWithCheck(size);
191         }
192         selfIdealSize = size;
193         return true;
194     }
195 
ClearSelfIdealSizeMeasureProperty196     bool ClearSelfIdealSize(bool clearWidth, bool clearHeight)
197     {
198         if (selfIdealSize.has_value()) {
199             return selfIdealSize->ClearSize(clearWidth, clearHeight);
200         }
201         return false;
202     }
203 
UpdateMaxSizeWithCheckMeasureProperty204     bool UpdateMaxSizeWithCheck(const CalcSize& size)
205     {
206         if (maxSize == size) {
207             return false;
208         }
209         if (maxSize.has_value()) {
210             return maxSize->UpdateSizeWithCheck(size);
211         }
212         maxSize = size;
213         return true;
214     }
215 
UpdateMinSizeWithCheckMeasureProperty216     bool UpdateMinSizeWithCheck(const CalcSize& size)
217     {
218         if (minSize == size) {
219             return false;
220         }
221         if (minSize.has_value()) {
222             return minSize->UpdateSizeWithCheck(size);
223         }
224         minSize = size;
225         return true;
226     }
227 
PercentWidthMeasureProperty228     bool PercentWidth() const
229     {
230         if (selfIdealSize.has_value()) {
231             return selfIdealSize->PercentWidth();
232         }
233         if (maxSize.has_value()) {
234             return maxSize->PercentWidth();
235         }
236         if (minSize.has_value()) {
237             return minSize->PercentWidth();
238         }
239         return false;
240     }
241 
PercentHeightMeasureProperty242     bool PercentHeight() const
243     {
244         if (selfIdealSize.has_value()) {
245             return selfIdealSize->PercentHeight();
246         }
247         if (maxSize.has_value()) {
248             return maxSize->PercentHeight();
249         }
250         if (minSize.has_value()) {
251             return minSize->PercentHeight();
252         }
253         return false;
254     }
255 
ToStringMeasureProperty256     std::string ToString() const
257     {
258         std::string str;
259         str.append("minSize: [").append(minSize.has_value() ? minSize->ToString() : "NA").append("]");
260         str.append("maxSize: [").append(maxSize.has_value() ? maxSize->ToString() : "NA").append("]");
261         str.append("selfIdealSize: [").append(selfIdealSize.has_value() ? selfIdealSize->ToString() : "NA").append("]");
262         return str;
263     }
264 
ToJsonValueMeasureProperty265     void ToJsonValue(std::unique_ptr<JsonValue>& json) const
266     {
267         // this may affect XTS, check later.
268         auto context = PipelineBase::GetCurrentContext();
269         if (context && context->GetMinPlatformVersion() < static_cast<int32_t>(PlatformVersion::VERSION_ELEVEN)) {
270 #if !defined(PREVIEW)
271             std::string width = selfIdealSize.has_value() ?
272                 (selfIdealSize.value().Width().has_value() ? selfIdealSize.value().Width().value().ToString() : "-")
273                 : "-";
274             std::string height = selfIdealSize.has_value() ?
275                 (selfIdealSize.value().Height().has_value() ? selfIdealSize.value().Height().value().ToString() : "-")
276                 : "-";
277             json->Put("width", width.c_str());
278             json->Put("height", height.c_str());
279 
280             auto jsonSize = JsonUtil::Create(true);
281             jsonSize->Put("width", width.c_str());
282             jsonSize->Put("height", height.c_str());
283             json->Put("size", jsonSize);
284 #else
285             ToJsonValue_GetJsonSize(json);
286 #endif
287         } else {
288             ToJsonValue_GetJsonSize(json);
289         }
290 
291         auto jsonConstraintSize = JsonUtil::Create(true);
292         jsonConstraintSize->Put("minWidth",
293             minSize.value_or(CalcSize()).Width().value_or(CalcLength(0, DimensionUnit::VP)).ToString().c_str());
294         jsonConstraintSize->Put("minHeight",
295             minSize.value_or(CalcSize()).Height().value_or(CalcLength(0, DimensionUnit::VP)).ToString().c_str());
296         jsonConstraintSize->Put("maxWidth", maxSize.value_or(CalcSize())
297                                                 .Width()
298                                                 .value_or(CalcLength(Infinity<double>(), DimensionUnit::VP))
299                                                 .ToString()
300                                                 .c_str());
301         jsonConstraintSize->Put("maxHeight", maxSize.value_or(CalcSize())
302                                                  .Height()
303                                                  .value_or(CalcLength(Infinity<double>(), DimensionUnit::VP))
304                                                  .ToString()
305                                                  .c_str());
306         json->Put("constraintSize", jsonConstraintSize->ToString().c_str());
307     }
308 
ToJsonValue_GetJsonSizeMeasureProperty309     void ToJsonValue_GetJsonSize(std::unique_ptr<JsonValue>& json) const
310     {
311         auto jsonSize = JsonUtil::Create(true);
312         if (selfIdealSize.has_value()) {
313             if (selfIdealSize.value().Width().has_value()) {
314                 auto widthStr = selfIdealSize.value().Width().value().ToString();
315                 json->Put("width", widthStr.c_str());
316                 jsonSize->Put("width", widthStr.c_str());
317             }
318             if (selfIdealSize.value().Height().has_value()) {
319                 auto heightStr = selfIdealSize.value().Height().value().ToString();
320                 json->Put("height", heightStr.c_str());
321                 jsonSize->Put("height", heightStr.c_str());
322             }
323         }
324         json->Put("size", jsonSize);
325     }
326 
FromJsonMeasureProperty327     static MeasureProperty FromJson(const std::unique_ptr<JsonValue>& json)
328     {
329         MeasureProperty ans;
330         auto width = json->GetString("width");
331         auto height = json->GetString("height");
332         if (width != "-" || height != "-") {
333             ans.selfIdealSize =
334                 CalcSize(width != "-" ? std::optional<CalcLength>(Dimension::FromString(width)) : std::nullopt,
335                     height != "-" ? std::optional<CalcLength>(Dimension::FromString(height)) : std::nullopt);
336         }
337         return ans;
338     }
339 };
340 
341 template<typename T>
342 struct PaddingPropertyT {
343     std::optional<T> left;
344     std::optional<T> right;
345     std::optional<T> top;
346     std::optional<T> bottom;
347 
SetEdgesPaddingPropertyT348     void SetEdges(const T& padding)
349     {
350         left = padding;
351         right = padding;
352         top = padding;
353         bottom = padding;
354     }
355 
356     bool operator==(const PaddingPropertyT& value) const
357     {
358         return (left == value.left) && (right == value.right) && (top == value.top) && (bottom == value.bottom);
359     }
360 
361     bool operator!=(const PaddingPropertyT& value) const
362     {
363         return !(*this == value);
364     }
365 
UpdateWithCheckPaddingPropertyT366     bool UpdateWithCheck(const PaddingPropertyT& value)
367     {
368         if (*this != value) {
369             left = value.left;
370             right = value.right;
371             top = value.top;
372             bottom = value.bottom;
373             return true;
374         }
375         return false;
376     }
377 
ToStringPaddingPropertyT378     std::string ToString() const
379     {
380         std::string str;
381         str.append("left: [").append(left.has_value() ? left->ToString() : "NA").append("]");
382         str.append("right: [").append(right.has_value() ? right->ToString() : "NA").append("]");
383         str.append("top: [").append(top.has_value() ? top->ToString() : "NA").append("]");
384         str.append("bottom: [").append(bottom.has_value() ? bottom->ToString() : "NA").append("]");
385         return str;
386     }
ToJsonStringPaddingPropertyT387     std::string ToJsonString() const
388     {
389         if (top == right && right == bottom && bottom == left) {
390             if (top.has_value()) {
391                 return top->ToString();
392             }
393             return "0.0";
394         }
395         auto jsonValue = JsonUtil::Create(true);
396         jsonValue->Put("top", top->ToString().c_str());
397         jsonValue->Put("right", right->ToString().c_str());
398         jsonValue->Put("bottom", bottom->ToString().c_str());
399         jsonValue->Put("left", left->ToString().c_str());
400         return jsonValue->ToString();
401     }
402 
FromJsonStringPaddingPropertyT403     static PaddingPropertyT FromJsonString(const std::string& str)
404     {
405         PaddingPropertyT property;
406 
407         if (str.empty()) {
408             LOGE("UITree |ERROR| empty string");
409             return property;
410         }
411 
412         if (str[0] >= '0' && str[0] <= '9') {
413             property.top = property.right = property.bottom = property.left = T::FromString(str);
414         } else if (str[0] == '{') {
415             auto json = JsonUtil::ParseJsonString(str);
416             if (!json->IsValid()) {
417                 return property;
418             }
419             property.top = T::FromString(json->GetString("top"));
420             property.right = T::FromString(json->GetString("right"));
421             property.bottom = T::FromString(json->GetString("bottom"));
422             property.left = T::FromString(json->GetString("left"));
423         } else {
424             LOGE("UITree |ERROR| invalid str=%{public}s", str.c_str());
425         }
426 
427         return property;
428     }
429 };
430 
431 template<>
432 struct PaddingPropertyT<float> {
433     std::optional<float> left;
434     std::optional<float> right;
435     std::optional<float> top;
436     std::optional<float> bottom;
437 
438     bool operator==(const PaddingPropertyT<float>& value) const
439     {
440         if (left.has_value() ^ value.left.has_value()) {
441             return false;
442         }
443         if (!NearEqual(left.value_or(0), value.left.value_or(0))) {
444             return false;
445         }
446         if (right.has_value() ^ value.right.has_value()) {
447             return false;
448         }
449         if (!NearEqual(right.value_or(0), value.right.value_or(0))) {
450             return false;
451         }
452         if (top.has_value() ^ value.top.has_value()) {
453             return false;
454         }
455         if (!NearEqual(top.value_or(0), value.top.value_or(0))) {
456             return false;
457         }
458         if (bottom.has_value() ^ value.bottom.has_value()) {
459             return false;
460         }
461         if (!NearEqual(bottom.value_or(0), value.bottom.value_or(0))) {
462             return false;
463         }
464         return true;
465     }
466 
467     std::string ToString() const
468     {
469         std::string str;
470         str.append("left: [").append(left.has_value() ? std::to_string(left.value()) : "NA").append("]");
471         str.append("right: [").append(right.has_value() ? std::to_string(right.value()) : "NA").append("]");
472         str.append("top: [").append(top.has_value() ? std::to_string(top.value()) : "NA").append("]");
473         str.append("bottom: [").append(bottom.has_value() ? std::to_string(bottom.value()) : "NA").append("]");
474         return str;
475     }
476 
477     std::string ToJsonString() const
478     {
479         auto jsonValue = JsonUtil::Create(true);
480         jsonValue->Put("top", top.has_value() ? std::to_string(top.value()).c_str() : BORDERZERO.c_str());
481         jsonValue->Put("right", right.has_value() ? std::to_string(right.value()).c_str() : BORDERZERO.c_str());
482         jsonValue->Put("bottom", bottom.has_value() ? std::to_string(bottom.value()).c_str() : BORDERZERO.c_str());
483         jsonValue->Put("left", left.has_value() ? std::to_string(left.value()).c_str() : BORDERZERO.c_str());
484         return jsonValue->ToString();
485     }
486 
487     float Width() const
488     {
489         return left.value_or(0.0f) + right.value_or(0.0f);
490     }
491 
492     float Height() const
493     {
494         return top.value_or(0.0f) + bottom.value_or(0.0f);
495     }
496 
497     SizeF Size() const
498     {
499         return SizeF(Width(), Height());
500     }
501 
502     OffsetF Offset() const
503     {
504         return OffsetF(left.value_or(0.0f), top.value_or(0.0f));
505     }
506 };
507 
508 using PaddingProperty = PaddingPropertyT<CalcLength>;
509 using MarginProperty = PaddingProperty;
510 using PaddingPropertyF = PaddingPropertyT<float>;
511 using MarginPropertyF = PaddingPropertyT<float>;
512 } // namespace OHOS::Ace::NG
513 
514 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PROPERTIES_MEASURE_PROPERTIES_H