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