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_BASE_GEOMETRY_NG_PROPERTIES_SIZE_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_NG_PROPERTIES_SIZE_H
18 
19 #include <cstdint>
20 #include <iomanip>
21 #include <optional>
22 #include <sstream>
23 #include <string>
24 
25 #include "base/geometry/axis.h"
26 #include "base/utils/utils.h"
27 
28 namespace OHOS::Ace::NG {
29 
30 template<typename T>
31 class SizeT {
32 public:
33     SizeT() = default;
34     ~SizeT() = default;
SizeT(T width,T height)35     SizeT(T width, T height) : width_(width), height_(height) {}
36 
SizeT(T crossSize,T mainSize,Axis axis)37     SizeT(T crossSize, T mainSize, Axis axis)
38     {
39         if (axis == Axis::HORIZONTAL) {
40             width_ = mainSize;
41             height_ = crossSize;
42         } else { // Axis::VERTICAL and others
43             width_ = crossSize;
44             height_ = mainSize;
45         }
46     }
47 
Reset()48     void Reset()
49     {
50         width_ = 0;
51         height_ = 0;
52     }
53 
Width()54     T Width() const
55     {
56         return width_;
57     }
58 
Height()59     T Height() const
60     {
61         return height_;
62     }
63 
MainSize(Axis axis)64     T MainSize(Axis axis) const
65     {
66         return axis == Axis::HORIZONTAL ? width_ : height_;
67     }
68 
CrossSize(Axis axis)69     T CrossSize(Axis axis) const
70     {
71         return axis == Axis::HORIZONTAL ? height_ : width_;
72     }
73 
SetWidth(T width)74     void SetWidth(T width)
75     {
76         width_ = width;
77     }
78 
SetHeight(T height)79     void SetHeight(T height)
80     {
81         height_ = height;
82     }
83 
SetMainSize(T mainSize,Axis axis)84     void SetMainSize(T mainSize, Axis axis)
85     {
86         axis == Axis::HORIZONTAL ? width_ = mainSize : height_ = mainSize;
87     }
88 
SetCrossSize(T crossSize,Axis axis)89     void SetCrossSize(T crossSize, Axis axis)
90     {
91         axis == Axis::HORIZONTAL ? height_ = crossSize : width_ = crossSize;
92     }
93 
SetSizeT(const SizeT & SizeT)94     void SetSizeT(const SizeT& SizeT)
95     {
96         width_ = SizeT.Width();
97         height_ = SizeT.Height();
98     }
99 
AddHeight(T height)100     SizeT& AddHeight(T height)
101     {
102         height_ += height;
103         return *this;
104     }
105 
AddWidth(T value)106     SizeT& AddWidth(T value)
107     {
108         width_ += value;
109         return *this;
110     }
111 
MinusHeight(T height)112     SizeT& MinusHeight(T height)
113     {
114         height_ -= height;
115         return *this;
116     }
117 
MinusWidth(T width)118     SizeT& MinusWidth(T width)
119     {
120         width_ -= width;
121         return *this;
122     }
123 
MinusPadding(const std::optional<T> & left,const std::optional<T> & right,const std::optional<T> & top,const std::optional<T> & bottom)124     void MinusPadding(const std::optional<T>& left, const std::optional<T>& right, const std::optional<T>& top,
125         const std::optional<T>& bottom)
126     {
127         T tempWidth = width_ - left.value_or(0) - right.value_or(0);
128         if (NonNegative(tempWidth)) {
129             width_ = tempWidth;
130         }
131         T tempHeight = height_ - top.value_or(0) - bottom.value_or(0);
132         if (NonNegative(tempHeight)) {
133             height_ = tempHeight;
134         }
135     }
136 
MinusPaddingToNonNegative(const std::optional<T> & left,const std::optional<T> & right,const std::optional<T> & top,const std::optional<T> & bottom)137     void MinusPaddingToNonNegative(const std::optional<T>& left, const std::optional<T>& right,
138         const std::optional<T>& top, const std::optional<T>& bottom)
139     {
140         if (width_) {
141             T tempWidth = width_ - left.value_or(0) - right.value_or(0);
142             width_ = NonNegative(tempWidth) ? tempWidth : 0;
143         }
144         if (height_) {
145             T tempHeight = height_ - top.value_or(0) - bottom.value_or(0);
146             height_ = NonNegative(tempHeight) ? tempHeight : 0;
147         }
148     }
149 
AddPadding(const std::optional<T> & left,const std::optional<T> & right,const std::optional<T> & top,const std::optional<T> & bottom)150     void AddPadding(const std::optional<T>& left, const std::optional<T>& right, const std::optional<T>& top,
151         const std::optional<T>& bottom)
152     {
153         width_ = width_ + left.value_or(0) + right.value_or(0);
154         height_ = height_ + top.value_or(0) + bottom.value_or(0);
155     }
156 
IsNonNegative()157     bool IsNonNegative() const
158     {
159         return NonNegative(width_) && NonNegative(height_);
160     }
161 
162     // width and height all less than zero.
IsNegative()163     bool IsNegative() const
164     {
165         return Negative(width_) && Negative(height_);
166     }
167 
IsPositive()168     bool IsPositive() const
169     {
170         return Positive(width_) && Positive(height_);
171     }
172 
IsNonPositive()173     bool IsNonPositive() const
174     {
175         return NonPositive(width_) && NonPositive(height_);
176     }
177 
UpdateSizeWithCheck(const SizeT & size)178     bool UpdateSizeWithCheck(const SizeT& size)
179     {
180         bool isModified = false;
181         if (NonNegative(size.width_) && (width_ != size.width_)) {
182             width_ = size.width_;
183             isModified = true;
184         }
185         if (NonNegative(size.height_) && (height_ != size.height_)) {
186             height_ = size.height_;
187             isModified = true;
188         }
189         return isModified;
190     }
191 
UpdateIllegalSizeWithCheck(const SizeT & size)192     void UpdateIllegalSizeWithCheck(const SizeT& size)
193     {
194         if (Negative(width_) && NonNegative(size.width_)) {
195             width_ = size.width_;
196         }
197         if (Negative(height_) && NonNegative(size.height_)) {
198             height_ = size.height_;
199         }
200     }
201 
UpdateSizeWhenLarger(const SizeT & size)202     bool UpdateSizeWhenLarger(const SizeT& size)
203     {
204         bool widthUpdated = UpdateWidthWhenLarger(size);
205         bool heightUpdated = UpdateHeightWhenLarger(size);
206         return widthUpdated || heightUpdated;
207     }
208 
UpdateWidthWhenLarger(const SizeT & size)209     bool UpdateWidthWhenLarger(const SizeT& size)
210     {
211         bool isModified = false;
212         if (NonNegative(size.width_)) {
213             auto temp = width_ > size.width_ ? width_ : size.width_;
214             if (width_ != temp) {
215                 isModified = true;
216             }
217             width_ = temp;
218         }
219         return isModified;
220     }
221 
UpdateHeightWhenLarger(const SizeT & size)222     bool UpdateHeightWhenLarger(const SizeT& size)
223     {
224         bool isModified = false;
225         if (NonNegative(size.height_)) {
226             auto temp = height_ > size.height_ ? height_ : size.height_;
227             if (height_ != temp) {
228                 isModified = true;
229             }
230             height_ = temp;
231         }
232         return isModified;
233     }
234 
UpdateSizeWhenSmaller(const SizeT & size)235     bool UpdateSizeWhenSmaller(const SizeT& size)
236     {
237         bool widthUpdated = UpdateWidthWhenSmaller(size);
238         bool heightUpdated = UpdateHeightWhenSmaller(size);
239         return widthUpdated || heightUpdated;
240     }
241 
UpdateWidthWhenSmaller(const SizeT & size)242     bool UpdateWidthWhenSmaller(const SizeT& size)
243     {
244         bool isModified = false;
245         if (NonNegative(size.width_)) {
246             auto temp = width_ < size.width_ ? width_ : size.width_;
247             if (width_ != temp) {
248                 isModified = true;
249             }
250             width_ = temp;
251         }
252         return isModified;
253     }
254 
UpdateHeightWhenSmaller(const SizeT & size)255     bool UpdateHeightWhenSmaller(const SizeT& size)
256     {
257         bool isModified = false;
258         if (NonNegative(size.height_)) {
259             auto temp = height_ < size.height_ ? height_ : size.height_;
260             if (height_ != temp) {
261                 isModified = true;
262             }
263             height_ = temp;
264         }
265         return isModified;
266     }
267 
UpdateMin(const SizeT & minSize)268     void UpdateMin(const SizeT& minSize)
269     {
270         if (NonNegative(minSize.width_)) {
271             width_ = width_ > minSize.Width() ? width_ : minSize.Width();
272         }
273         if (NonNegative(minSize.height_)) {
274             height_ = height_ > minSize.Height() ? height_ : minSize.Height();
275         }
276     }
277 
UpdateMax(const SizeT & maxSize)278     void UpdateMax(const SizeT& maxSize)
279     {
280         if (NonNegative(maxSize.width_)) {
281             width_ = width_ < maxSize.Width() ? width_ : maxSize.Width();
282         }
283         if (NonNegative(maxSize.height_)) {
284             height_ = height_ < maxSize.Height() ? height_ : maxSize.Height();
285         }
286     }
287 
288     void Constrain(const SizeT& minSize, const SizeT& maxSize, bool version10OrLarger = false)
289     {
290         if (version10OrLarger) {
291             UpdateMax(maxSize);
292             UpdateMin(minSize);
293             return;
294         }
295         UpdateMin(minSize);
296         UpdateMax(maxSize);
297     }
298 
299     SizeT operator*(double value) const
300     {
301         return SizeT(width_ * value, height_ * value);
302     }
303 
304     bool operator==(const SizeT& size) const
305     {
306         return NearEqual(width_, size.width_) && NearEqual(height_, size.height_);
307     }
308 
309     bool operator!=(const SizeT& size) const
310     {
311         return !operator==(size);
312     }
313 
314     SizeT operator+(const SizeT& size) const
315     {
316         return SizeT(width_ + size.Width(), height_ + size.Height());
317     }
318 
319     SizeT& operator+=(const SizeT& size)
320     {
321         width_ += size.Width();
322         height_ += size.Height();
323         return *this;
324     }
325 
326     SizeT operator-(const SizeT& size) const
327     {
328         return SizeT(width_ - size.Width(), height_ - size.Height());
329     }
330 
331     SizeT& operator-=(const SizeT& size)
332     {
333         width_ -= size.Width();
334         height_ -= size.Height();
335         return *this;
336     }
337 
DivideScale(float scale)338     void DivideScale(float scale)
339     {
340         if (NearZero(scale)) {
341             return;
342         }
343         width_ /= scale;
344         height_ /= scale;
345     }
346 
ApplyScale(double scale)347     void ApplyScale(double scale)
348     {
349         width_ *= scale;
350         height_ *= scale;
351     }
352 
353     /*
354      * Please make sure that two SizeTs are both valid.
355      * You can use IsValid() to see if a SizeT is valid.
356      */
357     bool operator>(const SizeT& SizeT) const
358     {
359         if (IsNonNegative() && SizeT.IsNonNegative()) {
360             return GreatOrEqual(width_, SizeT.width_) && GreatOrEqual(height_, SizeT.height_);
361         }
362         return false;
363     }
364 
365     /*
366      * Please make sure that two SizeTs are both valid.
367      * You can use IsValid() to see if a SizeT is valid.
368      */
369     bool operator<(const SizeT& SizeT) const
370     {
371         if (IsNonNegative() && SizeT.IsNonNegative()) {
372             return LessOrEqual(width_, SizeT.width_) && LessOrEqual(height_, SizeT.height_);
373         }
374         return false;
375     }
376 
CalcRatio()377     double CalcRatio() const
378     {
379         return static_cast<double>(width_) / static_cast<double>(height_);
380     }
381 
ToString()382     std::string ToString() const
383     {
384         static const int32_t precision = 2;
385         std::stringstream ss;
386         ss << "[" << std::fixed << std::setprecision(precision);
387         ss << width_;
388         ss << " x ";
389         ss << height_;
390         ss << "]";
391         std::string output = ss.str();
392         return output;
393     }
394 
395 private:
396     T width_ { 0 };
397     T height_ { 0 };
398 };
399 
400 using SizeF = SizeT<float>;
401 
402 template<typename T>
403 class OptionalSize {
404 public:
405     OptionalSize() = default;
406     ~OptionalSize() = default;
OptionalSize(const std::optional<T> & width,const std::optional<T> & height)407     OptionalSize(const std::optional<T>& width, const std::optional<T>& height) : width_(width), height_(height) {}
OptionalSize(const T & width,const T & height)408     OptionalSize(const T& width, const T& height) : width_(width), height_(height) {}
OptionalSize(const SizeT<T> & size)409     explicit OptionalSize(const SizeT<T>& size) : width_(size.Width()), height_(size.Height()) {}
410 
Reset()411     void Reset()
412     {
413         width_.reset();
414         height_.reset();
415     }
416 
Width()417     const std::optional<T>& Width() const
418     {
419         return width_;
420     }
421 
Height()422     const std::optional<T>& Height() const
423     {
424         return height_;
425     }
426 
MainSize(Axis axis)427     const std::optional<T>& MainSize(Axis axis) const
428     {
429         return axis == Axis::HORIZONTAL ? width_ : height_;
430     }
431 
CrossSize(Axis axis)432     const std::optional<T>& CrossSize(Axis axis) const
433     {
434         return axis == Axis::HORIZONTAL ? height_ : width_;
435     }
436 
SetWidth(T width)437     void SetWidth(T width)
438     {
439         width_ = width;
440     }
441 
SetHeight(T height)442     void SetHeight(T height)
443     {
444         height_ = height;
445     }
446 
SetMainSize(T mainSize,Axis axis)447     void SetMainSize(T mainSize, Axis axis)
448     {
449         axis == Axis::HORIZONTAL ? width_ = mainSize : height_ = mainSize;
450     }
451 
SetCrossSize(T crossSize,Axis axis)452     void SetCrossSize(T crossSize, Axis axis)
453     {
454         axis == Axis::HORIZONTAL ? height_ = crossSize : width_ = crossSize;
455     }
456 
SetMainSize(const std::optional<T> & mainSize,Axis axis)457     void SetMainSize(const std::optional<T>& mainSize, Axis axis)
458     {
459         axis == Axis::HORIZONTAL ? width_ = mainSize : height_ = mainSize;
460     }
461 
SetCrossSize(const std::optional<T> & crossSize,Axis axis)462     void SetCrossSize(const std::optional<T>& crossSize, Axis axis)
463     {
464         axis == Axis::HORIZONTAL ? height_ = crossSize : width_ = crossSize;
465     }
466 
SetWidth(const std::optional<T> & width)467     void SetWidth(const std::optional<T>& width)
468     {
469         width_ = width;
470     }
471 
SetHeight(const std::optional<T> & height)472     void SetHeight(const std::optional<T>& height)
473     {
474         height_ = height;
475     }
476 
SetSize(const SizeT<T> & sizeF)477     void SetSize(const SizeT<T>& sizeF)
478     {
479         width_ = sizeF.Width();
480         height_ = sizeF.Height();
481     }
482 
SetOptionalSize(const OptionalSize & size)483     void SetOptionalSize(const OptionalSize& size)
484     {
485         width_ = size.Width();
486         height_ = size.Height();
487     }
488 
AddHeight(float height)489     OptionalSize& AddHeight(float height)
490     {
491         height_ = height_.value_or(0) + height;
492         return *this;
493     }
494 
AddWidth(float width)495     OptionalSize& AddWidth(float width)
496     {
497         width_ = width_.value_or(0) + width;
498         return *this;
499     }
500 
MinusHeight(float height)501     OptionalSize& MinusHeight(float height)
502     {
503         height_ = height_.value_or(0) - height;
504         return *this;
505     }
506 
MinusWidth(float width)507     OptionalSize& MinusWidth(float width)
508     {
509         width_ = width_.value_or(0) - width;
510         return *this;
511     }
512 
MinusPadding(const std::optional<T> & left,const std::optional<T> & right,const std::optional<T> & top,const std::optional<T> & bottom)513     void MinusPadding(const std::optional<T>& left, const std::optional<T>& right, const std::optional<T>& top,
514         const std::optional<T>& bottom)
515     {
516         if (width_) {
517             T tempWidth = width_.value() - left.value_or(0) - right.value_or(0);
518             width_ = NonNegative(tempWidth) ? tempWidth : 0;
519         }
520         if (height_) {
521             T tempHeight = height_.value() - top.value_or(0) - bottom.value_or(0);
522             height_ = NonNegative(tempHeight) ? tempHeight : 0;
523         }
524     }
525 
AddPadding(const std::optional<T> & left,const std::optional<T> & right,const std::optional<T> & top,const std::optional<T> & bottom)526     void AddPadding(const std::optional<T>& left, const std::optional<T>& right, const std::optional<T>& top,
527         const std::optional<T>& bottom)
528     {
529         if (width_) {
530             width_ = width_.value() + left.value_or(0) + right.value_or(0);
531         }
532         if (height_) {
533             height_ = height_.value() + top.value_or(0) + bottom.value_or(0);
534         }
535     }
536 
IsValid()537     bool IsValid() const
538     {
539         return width_ && height_;
540     }
541 
AtLeastOneValid()542     bool AtLeastOneValid() const
543     {
544         return width_ || height_;
545     }
546 
IsNull()547     bool IsNull() const
548     {
549         return !width_ && !height_;
550     }
551 
IsNonNegative()552     bool IsNonNegative() const
553     {
554         return NonNegative(width_.value_or(-1)) && NonNegative(height_.value_or(-1));
555     }
556 
557     // width and height all less than zero.
IsNegative()558     bool IsNegative() const
559     {
560         return Negative(width_.value_or(-1)) && Negative(height_.value_or(-1));
561     }
562 
IsPositive()563     bool IsPositive() const
564     {
565         return Positive(width_.value_or(-1)) && Positive(height_.value_or(-1));
566     }
567 
IsNonPositive()568     bool IsNonPositive() const
569     {
570         return NonPositive(width_.value_or(-1)) && NonPositive(height_.value_or(-1));
571     }
572 
UpdateSizeWithCheck(const OptionalSize & size)573     bool UpdateSizeWithCheck(const OptionalSize& size)
574     {
575         bool isModified = false;
576         if (size.width_ && (width_ != size.width_)) {
577             width_ = size.width_;
578             isModified = true;
579         }
580         if (size.height_ && (height_ != size.height_)) {
581             height_ = size.height_;
582             isModified = true;
583         }
584         return isModified;
585     }
586 
UpdateSizeWithCheck(const SizeT<T> & size)587     bool UpdateSizeWithCheck(const SizeT<T>& size)
588     {
589         bool isModified = false;
590         if (NonNegative(size.Width()) && (width_ != size.Width())) {
591             width_ = size.Width();
592             isModified = true;
593         }
594         if (NonNegative(size.Height()) && (height_ != size.Height())) {
595             height_ = size.Height();
596             isModified = true;
597         }
598         return isModified;
599     }
600 
UpdateIllegalSizeWithCheck(const OptionalSize & size)601     bool UpdateIllegalSizeWithCheck(const OptionalSize& size)
602     {
603         bool isModified = false;
604         if (!width_ && size.Width()) {
605             width_ = size.Width();
606             isModified = true;
607         }
608         if (!height_ && size.Height()) {
609             height_ = size.Height();
610             isModified = true;
611         }
612         return isModified;
613     }
614 
UpdateIllegalSizeWithCheck(const SizeT<T> & size)615     bool UpdateIllegalSizeWithCheck(const SizeT<T>& size)
616     {
617         bool isModified = false;
618         if (!width_.has_value() && NonNegative(size.Width())) {
619             width_ = size.Width();
620             isModified = true;
621         }
622         if (!height_.has_value() && NonNegative(size.Height())) {
623             height_ = size.Height();
624             isModified = true;
625         }
626         return isModified;
627     }
628 
UpdateSizeWhenLarger(const SizeT<T> & size)629     bool UpdateSizeWhenLarger(const SizeT<T>& size)
630     {
631         bool widthUpdated = UpdateWidthWhenLarger(size);
632         bool heightUpdated = UpdateHeightWhenLarger(size);
633         return widthUpdated || heightUpdated;
634     }
635 
UpdateWidthWhenLarger(const SizeT<T> & size)636     bool UpdateWidthWhenLarger(const SizeT<T>& size)
637     {
638         bool isModified = false;
639         if (NonNegative(size.Width()) && width_) {
640             auto temp = width_.value_or(0) > size.Width() ? width_ : size.Width();
641             if (width_ != temp) {
642                 isModified = true;
643             }
644             width_ = temp;
645         }
646         return isModified;
647     }
648 
UpdateHeightWhenLarger(const SizeT<T> & size)649     bool UpdateHeightWhenLarger(const SizeT<T>& size)
650     {
651         bool isModified = false;
652         if (NonNegative(size.Height()) && height_) {
653             auto temp = height_.value_or(0) > size.Height() ? height_ : size.Height();
654             if (height_ != temp) {
655                 isModified = true;
656             }
657             height_ = temp;
658         }
659         return isModified;
660     }
661 
UpdateSizeWhenSmaller(const SizeT<T> & size)662     bool UpdateSizeWhenSmaller(const SizeT<T>& size)
663     {
664         bool widthUpdated = UpdateWidthWhenSmaller(size);
665         bool heightUpdated = UpdateHeightWhenSmaller(size);
666         return widthUpdated || heightUpdated;
667     }
668 
UpdateWidthWhenSmaller(const SizeT<T> & size)669     bool UpdateWidthWhenSmaller(const SizeT<T>& size)
670     {
671         bool isModified = false;
672         if (NonNegative(size.Width())) {
673             auto temp = width_.value_or(0) < size.Width() ? width_ : size.Width();
674             if (width_ != temp) {
675                 isModified = true;
676             }
677             width_ = temp;
678         }
679         return isModified;
680     }
681 
UpdateHeightWhenSmaller(const SizeT<T> & size)682     bool UpdateHeightWhenSmaller(const SizeT<T>& size)
683     {
684         bool isModified = false;
685         if (NonNegative(size.Height())) {
686             auto temp = height_.value_or(0) < size.Height() ? height_ : size.Height();
687             if (height_ != temp) {
688                 isModified = true;
689             }
690             height_ = temp;
691         }
692         return isModified;
693     }
694 
695     void UpdateMin(const SizeT<T>& minSize, bool forceOverwriteInvalidValue = false)
696     {
697         if (NonNegative(minSize.Width()) && (width_ || forceOverwriteInvalidValue)) {
698             width_ = width_.value_or(0) > minSize.Width() ? width_ : minSize.Width();
699         }
700         if (NonNegative(minSize.Height()) && (height_ || forceOverwriteInvalidValue)) {
701             height_ = height_.value_or(0) > minSize.Height() ? height_ : minSize.Height();
702         }
703     }
704 
705     void UpdateMax(const SizeT<T>& maxSize, bool forceOverwriteInvalidValue = false)
706     {
707         if (NonNegative(maxSize.Width()) && (width_ || forceOverwriteInvalidValue)) {
708             width_ = width_.value_or(0) < maxSize.Width() ? width_ : maxSize.Width();
709         }
710         if (NonNegative(maxSize.Height()) && (height_ || forceOverwriteInvalidValue)) {
711             height_ = height_.value_or(0) < maxSize.Height() ? Height() : maxSize.Height();
712         }
713     }
714 
715     void Constrain(const SizeT<T>& minSize, const SizeT<T>& maxSize, bool version10OrLarger = false,
716         bool forceOverwriteInvalidValue = false)
717     {
718         if (version10OrLarger) {
719             UpdateMax(maxSize, forceOverwriteInvalidValue);
720             UpdateMin(minSize, forceOverwriteInvalidValue);
721             return;
722         }
723         UpdateMin(minSize);
724         UpdateMax(maxSize);
725     }
726 
727     void ConstrainFloat(const SizeT<T>& minSize, const SizeT<T>& maxSize, bool isWidth, bool version10OrLarger = false)
728     {
729         if (isWidth) {
730             if (version10OrLarger) {
731                 if (NonNegative(maxSize.Width()) && width_) {
732                     width_ = width_.value_or(0) < maxSize.Width() ? width_ : maxSize.Width();
733                 }
734                 if (NonNegative(minSize.Width()) && width_) {
735                     width_ = width_.value_or(0) > minSize.Width() ? width_ : minSize.Width();
736                 }
737                 return;
738             }
739             if (NonNegative(minSize.Width()) && width_) {
740                 width_ = width_.value_or(0) > minSize.Width() ? width_ : minSize.Width();
741             }
742 
743             if (NonNegative(maxSize.Width()) && width_) {
744                 width_ = width_.value_or(0) < maxSize.Width() ? width_ : maxSize.Width();
745             }
746             return;
747         }
748         if (version10OrLarger) {
749             if (NonNegative(maxSize.Height()) && height_) {
750                 height_ = height_.value_or(0) < maxSize.Height() ? Height() : maxSize.Height();
751             }
752             if (NonNegative(minSize.Height()) && height_) {
753                 height_ = height_.value_or(0) > minSize.Height() ? height_ : minSize.Height();
754             }
755             return;
756         }
757         if (NonNegative(minSize.Height()) && height_) {
758             height_ = height_.value_or(0) > minSize.Height() ? height_ : minSize.Height();
759         }
760         if (NonNegative(maxSize.Height()) && height_) {
761             height_ = height_.value_or(0) < maxSize.Height() ? Height() : maxSize.Height();
762         }
763     }
764 
765     OptionalSize operator*(double value) const
766     {
767         return OptionalSize(width_ ? *width_.value() * value : width_, height_ ? height_.value() * value : height_);
768     }
769 
770     bool operator==(const OptionalSize& size) const
771     {
772         if (width_.has_value() ^ size.width_.has_value()) {
773             return false;
774         }
775         if (!NearEqual(width_.value_or(0), size.width_.value_or(0))) {
776             return false;
777         }
778         if (height_.has_value() ^ size.height_.has_value()) {
779             return false;
780         }
781         if (!NearEqual(height_.value_or(0), size.height_.value_or(0))) {
782             return false;
783         }
784         return true;
785     }
786 
787     bool operator!=(const OptionalSize& size) const
788     {
789         return !operator==(size);
790     }
791 
792     OptionalSize operator+(const OptionalSize& size) const
793     {
794         std::optional<T> width;
795         if (width_) {
796             width = width_.value() + size.width_.value_or(0);
797         }
798         std::optional<T> height;
799         if (height_) {
800             height = height_.value() + size.height_.value_or(0);
801         }
802         return OptionalSize(width, height);
803     }
804 
805     OptionalSize& operator+=(const OptionalSize& size)
806     {
807         if (width_) {
808             width_ = width_.value() + size.width_.value_or(0);
809         }
810         if (height_) {
811             height_ = height_.value() + size.height_.value_or(0);
812         }
813         return *this;
814     }
815 
816     OptionalSize operator-(const OptionalSize& size) const
817     {
818         std::optional<T> width;
819         if (width_) {
820             width = width_.value() - size.width_.value_or(0);
821         }
822         std::optional<T> height;
823         if (height_) {
824             height = height_.value() - size.height_.value_or(0);
825         }
826         return OptionalSize(width, height);
827     }
828 
829     OptionalSize& operator-=(const OptionalSize& size)
830     {
831         if (width_) {
832             width_ = width_.value() - size.width_.value_or(0);
833         }
834         if (height_) {
835             height_ = height_.value() - size.height_.value_or(0);
836         }
837         return *this;
838     }
839 
ApplyScale(double scale)840     void ApplyScale(double scale)
841     {
842         width_ = width_ ? width_.value() * scale : width_;
843         height_ = height_ ? height_.value() * scale : height_;
844     }
845 
846     bool operator>(const SizeT<T>& size) const
847     {
848         if (IsNonNegative() && size.IsNonNegative()) {
849             return GreatOrEqual(width_.value_or(0), size.Width()) && GreatOrEqual(height_.value_or(0), size.Height());
850         }
851         return false;
852     }
853 
854     bool operator<(const SizeT<T>& size) const
855     {
856         if (IsNonNegative() && size.IsNonNegative()) {
857             return LessOrEqual(width_.value_or(0), size.Width()) && LessOrEqual(height_.value_or(0), size.Height());
858         }
859         return false;
860     }
861 
CalcRatio()862     double CalcRatio() const
863     {
864         if (NearZero(height_.value_or(0))) {
865             return 0.0;
866         }
867         return static_cast<double>(width_.value_or(0)) / static_cast<double>(height_.value());
868     }
869 
ConvertToSizeT()870     SizeT<T> ConvertToSizeT() const
871     {
872         return { width_.value_or(-1), height_.value_or(-1) };
873     }
874 
ToString()875     std::string ToString() const
876     {
877         static const int32_t precision = 2;
878         std::stringstream ss;
879         ss << "[" << std::fixed << std::setprecision(precision);
880         if (width_) {
881             ss << width_.value();
882         } else {
883             ss << "NA";
884         }
885         ss << " x ";
886         if (height_) {
887             ss << height_.value();
888         } else {
889             ss << "NA";
890         }
891         ss << "]";
892         std::string output = ss.str();
893         return output;
894     }
895 
896 private:
897     std::optional<T> width_;
898     std::optional<T> height_;
899 };
900 
901 using OptionalSizeF = OptionalSize<float>;
902 
903 } // namespace OHOS::Ace::NG
904 
905 #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_GEOMETRY_NG_PROPERTIES_SIZE_H
906