122 {
123 private:
124 using Type = T;
125
126 public:
127 constexpr TRect() : left_(0), top_(0), right_(0), bottom_(0) {}
128
129 constexpr static TRect MakeLTRB(Type left,
130 Type top,
131 Type right,
132 Type bottom) {
133 return TRect(left, top, right, bottom);
134 }
135
136 constexpr static TRect MakeXYWH(Type
x, Type
y, Type
width, Type
height) {
137 return TRect(
x,
y, saturated::Add(
x,
width), saturated::Add(
y,
height));
138 }
139
140 constexpr static TRect MakeWH(Type
width, Type
height) {
142 }
143
144 constexpr static TRect MakeOriginSize(const TPoint<Type>& origin,
145 const TSize<Type>& size) {
146 return MakeXYWH(origin.x, origin.y,
size.width,
size.height);
147 }
148
149 template <class U>
150 constexpr static TRect MakeSize(const TSize<U>& size) {
151 return TRect(0.0, 0.0,
size.width,
size.height);
152 }
153
154
155
156 constexpr static TRect MakeCircleBounds(const TPoint<Type>& center,
157 Type radius) {
160 }
161
162
163
164 constexpr static TRect MakeEllipseBounds(const TPoint<Type>& center,
165 const TSize<Type>& radii) {
166 return MakeLTRB(
center.x - radii.width,
center.y - radii.height,
168 }
169
170
171
172 constexpr static TRect MakeEllipseBounds(const TPoint<Type>& center,
173 const TPoint<Type>& radii) {
176 }
177
178
179
180 template <class U, class FT = T>
181 constexpr static std::enable_if_t<std::is_floating_point_v<FT>, TRect> Make(
182 const TRect<U>& rect) {
183 return MakeLTRB(
184 static_cast<FT>(rect.GetLeft()), static_cast<FT>(rect.GetTop()),
185 static_cast<FT>(rect.GetRight()), static_cast<FT>(rect.GetBottom()));
186 }
187
188 template <typename U>
189 constexpr static std::optional<TRect> MakePointBounds(const U& value) {
190 return MakePointBounds(
value.begin(),
value.end());
191 }
192
193 template <typename PointIter>
194 constexpr static std::optional<TRect> MakePointBounds(const PointIter first,
195 const PointIter last) {
196 if (first == last) {
197 return std::nullopt;
198 }
199 auto left = first->x;
200 auto top = first->y;
201 auto right = first->x;
202 auto bottom = first->y;
203 for (auto it = first + 1; it < last; ++it) {
204 left = std::min(left, it->x);
205 top = std::min(top, it->y);
206 right = std::max(right, it->x);
207 bottom = std::max(bottom, it->y);
208 }
209 return TRect::MakeLTRB(left, top, right, bottom);
210 }
211
212 [[nodiscard]] constexpr static TRect MakeMaximum() {
213 return TRect::MakeLTRB(std::numeric_limits<Type>::lowest(),
214 std::numeric_limits<Type>::lowest(),
215 std::numeric_limits<Type>::max(),
216 std::numeric_limits<Type>::max());
217 }
218
219 [[nodiscard]]
constexpr bool operator==(
const TRect& r)
const {
220 return left_ == r.left_ &&
221 top_ == r.top_ &&
222 right_ == r.right_ &&
223 bottom_ == r.bottom_;
224 }
225
226 [[nodiscard]] constexpr TRect Scale(Type scale) const {
227 return TRect(left_ * scale,
228 top_ * scale,
229 right_ * scale,
230 bottom_ * scale);
231 }
232
233 [[nodiscard]] constexpr TRect Scale(Type scale_x, Type scale_y) const {
234 return TRect(left_ * scale_x,
235 top_ * scale_y,
236 right_ * scale_x,
237 bottom_ * scale_y);
238 }
239
240 [[nodiscard]] constexpr TRect Scale(TPoint<T> scale) const {
241 return Scale(scale.x, scale.y);
242 }
243
244 [[nodiscard]] constexpr TRect Scale(TSize<T> scale) const {
245 return Scale(scale.width, scale.height);
246 }
247
248
249
250
251
252
253
254
255 [[nodiscard]]
constexpr bool Contains(
const TPoint<Type>& p)
const {
256 return !this->IsEmpty() &&
257 p.x >= left_ &&
258 p.y >= top_ &&
259 p.x < right_ &&
260 p.y < bottom_;
261 }
262
263
264
265
266
267
268
269
270
271
272
273
274 [[nodiscard]] constexpr bool ContainsInclusive(const TPoint<Type>& p) const {
275 return !this->IsEmpty() &&
276 p.x >= left_ &&
277 p.y >= top_ &&
278 p.x <= right_ &&
279 p.y <= bottom_;
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297 [[nodiscard]]
constexpr bool Contains(
const TRect& o)
const {
298 return !this->IsEmpty() &&
299 (o.IsEmpty() || (o.left_ >= left_ &&
300 o.top_ >= top_ &&
301 o.right_ <= right_ &&
302 o.bottom_ <= bottom_));
303 }
304
305 template <class U, class FT = T>
306 [[nodiscard]] constexpr std::enable_if_t<std::is_floating_point_v<FT>, bool>
308 return !this->IsEmpty() &&
309 (o.IsEmpty() || (o.GetLeft() >= left_ &&
310 o.GetTop() >= top_ &&
311 o.GetRight() <= right_ &&
312 o.GetBottom() <= bottom_));
313 }
314
315
316
317
318
319
320
322 IsFinite() const {
323 return std::isfinite(left_) &&
324 std::isfinite(top_) &&
325 std::isfinite(right_) &&
326 std::isfinite(bottom_);
327 }
328
329
330
331 [[nodiscard]] constexpr bool IsEmpty() const {
332
333
334 return !(left_ < right_ && top_ < bottom_);
335 }
336
337
338 [[nodiscard]] constexpr bool IsSquare() const {
339
340
341
342
343
344
345 return !IsEmpty() && (right_ - left_) == (bottom_ - top_);
346 }
347
348 [[nodiscard]] constexpr bool IsMaximum() const {
349 return *this == MakeMaximum();
350 }
351
352
353
354 [[nodiscard]] constexpr TPoint<Type> GetOrigin() const {
355 return {left_, top_};
356 }
357
358
359
360
361 [[nodiscard]] constexpr TSize<Type> GetSize() const {
362 return {GetWidth(), GetHeight()};
363 }
364
365
366
367 [[nodiscard]] constexpr Type GetX() const { return left_; }
368
369
370
371 [[nodiscard]] constexpr Type GetY() const { return top_; }
372
373
374
375 [[nodiscard]] constexpr Type GetWidth() const {
376 return saturated::Sub(right_, left_);
377 }
378
379
380
381 [[nodiscard]] constexpr Type GetHeight() const {
382 return saturated::Sub(bottom_, top_);
383 }
384
385 [[nodiscard]] constexpr auto GetLeft() const { return left_; }
386
387 [[nodiscard]] constexpr auto GetTop() const { return top_; }
388
389 [[nodiscard]] constexpr auto GetRight() const { return right_; }
390
391 [[nodiscard]] constexpr auto GetBottom() const { return bottom_; }
392
393 [[nodiscard]] constexpr TPoint<T> GetLeftTop() const {
394 return {left_, top_};
395 }
396
397 [[nodiscard]] constexpr TPoint<T> GetRightTop() const {
398 return {right_, top_};
399 }
400
401 [[nodiscard]] constexpr TPoint<T> GetLeftBottom() const {
402 return {left_, bottom_};
403 }
404
405 [[nodiscard]] constexpr TPoint<T> GetRightBottom() const {
406 return {right_, bottom_};
407 }
408
409
410 [[nodiscard]] constexpr T Area() const {
411
412 return IsEmpty() ? 0 : (right_ - left_) * (bottom_ - top_);
413 }
414
415
416 [[nodiscard]]
constexpr Point GetCenter()
const {
417 return {saturated::AverageScalar(left_, right_),
418 saturated::AverageScalar(top_, bottom_)};
419 }
420
421 [[nodiscard]] constexpr std::array<T, 4> GetLTRB() const {
422 return {left_, top_, right_, bottom_};
423 }
424
425
426
427 [[nodiscard]] constexpr std::array<T, 4> GetXYWH() const {
428 return {left_, top_, GetWidth(), GetHeight()};
429 }
430
431
432 [[nodiscard]] constexpr TRect GetPositive() const {
433 if (!IsEmpty()) {
434 return *this;
435 }
436 return {
437 std::min(left_, right_),
438 std::min(top_, bottom_),
439 std::max(left_, right_),
440 std::max(top_, bottom_),
441 };
442 }
443
444
445
446
447
448 [[nodiscard]] constexpr std::array<TPoint<T>, 4> GetPoints() const {
449 if (IsEmpty()) {
450 return {};
451 }
452 return {
453 TPoint{left_, top_},
454 TPoint{right_, top_},
455 TPoint{left_, bottom_},
456 TPoint{right_, bottom_},
457 };
458 }
459
460 [[nodiscard]] constexpr std::array<TPoint<T>, 4> GetTransformedPoints(
462 auto points = GetPoints();
463 for (
size_t i = 0;
i <
points.size();
i++) {
465 }
467 }
468
469
470
471
472 [[nodiscard]] constexpr TRect TransformAndClipBounds(
476 }
477
478 if (IsEmpty()) {
479 return {};
480 }
481
482 auto ul =
transform.TransformHomogenous({left_, top_});
483 auto ur =
transform.TransformHomogenous({right_, top_});
484 auto ll =
transform.TransformHomogenous({left_, bottom_});
485 auto lr =
transform.TransformHomogenous({right_, bottom_});
486
487
488
489
491 int index = 0;
492
493
494
495 index = ClipAndInsert(
points, index, ll, ul, ur);
496 index = ClipAndInsert(
points, index, ul, ur, lr);
497 index = ClipAndInsert(
points, index, ur, lr, ll);
498 index = ClipAndInsert(
points, index, lr, ll, ul);
499
500 auto bounds = TRect::MakePointBounds(
points,
points + index);
501 return bounds.value_or(TRect{});
502 }
503
504
505
506 [[nodiscard]]
constexpr TRect TransformBounds(
const Matrix&
transform)
const {
507 if (IsEmpty()) {
508 return {};
509 }
511 auto bounds = TRect::MakePointBounds(
points.begin(),
points.end());
512 if (bounds.has_value()) {
513 return bounds.value();
514 }
516 }
517
518
519
520
521
522
523
524
525 [[nodiscard]] constexpr Matrix GetNormalizingTransform() const {
526 if (!IsEmpty()) {
527 Scalar sx = 1.0 / GetWidth();
528 Scalar sy = 1.0 / GetHeight();
531
532
533 if (sx != 0.0 && sy != 0.0 && 0.0 * sx * sy * tx * ty == 0.0) {
534
535 return Matrix( sx, 0.0f, 0.0f, 0.0f,
536 0.0f, sy, 0.0f, 0.0f,
537 0.0f, 0.0f, 1.0f, 0.0f,
538 tx, ty, 0.0f, 1.0f);
539
540 }
541 }
542
543
544 return Matrix::MakeScale({0.0f, 0.0f, 1.0f});
545 }
546
547 [[nodiscard]] constexpr TRect Union(const TRect& o) const {
548 if (IsEmpty()) {
549 return o;
550 }
551 if (o.IsEmpty()) {
552 return *this;
553 }
554 return {
555 std::min(left_, o.left_),
556 std::min(top_, o.top_),
557 std::max(right_, o.right_),
558 std::max(bottom_, o.bottom_),
559 };
560 }
561
562 [[nodiscard]] constexpr std::optional<TRect> Intersection(
563 const TRect& o) const {
564 if (IntersectsWithRect(o)) {
565 return TRect{
566 std::max(left_, o.left_),
567 std::max(top_, o.top_),
568 std::min(right_, o.right_),
569 std::min(bottom_, o.bottom_),
570 };
571 } else {
572 return std::nullopt;
573 }
574 }
575
576 [[nodiscard]] constexpr TRect IntersectionOrEmpty(const TRect& o) const {
577 return Intersection(o).value_or(TRect());
578 }
579
580 [[nodiscard]] constexpr bool IntersectsWithRect(const TRect& o) const {
581 return !IsEmpty() &&
582 !o.IsEmpty() &&
583 left_ < o.right_ &&
584 top_ < o.bottom_ &&
585 right_ > o.left_ &&
586 bottom_ > o.top_;
587 }
588
589
590
591 [[nodiscard]] constexpr std::optional<TRect<T>> Cutout(const TRect& o) const {
592 if (IsEmpty()) {
593
594
595
596
597
598 return std::nullopt;
599 }
600
601 const auto& [a_left, a_top, a_right, a_bottom] = GetLTRB();
602 const auto& [b_left, b_top, b_right, b_bottom] = o.GetLTRB();
603 if (b_left <= a_left && b_right >= a_right) {
604 if (b_top <= a_top && b_bottom >= a_bottom) {
605
606 return std::nullopt;
607 }
608 if (b_top <= a_top && b_bottom > a_top) {
609
610 return TRect::MakeLTRB(a_left, b_bottom, a_right, a_bottom);
611 }
612 if (b_bottom >= a_bottom && b_top < a_bottom) {
613
614 return TRect::MakeLTRB(a_left, a_top, a_right, b_top);
615 }
616 }
617 if (b_top <= a_top && b_bottom >= a_bottom) {
618 if (b_left <= a_left && b_right > a_left) {
619
620 return TRect::MakeLTRB(b_right, a_top, a_right, a_bottom);
621 }
622 if (b_right >= a_right && b_left < a_right) {
623
624 return TRect::MakeLTRB(a_left, a_top, b_left, a_bottom);
625 }
626 }
627
628 return *this;
629 }
630
631 [[nodiscard]] constexpr TRect CutoutOrEmpty(const TRect& o) const {
632 return Cutout(o).value_or(TRect());
633 }
634
635
636 [[nodiscard]] constexpr TRect<T> Shift(T dx, T dy) const {
637 return {
638 saturated::Add(left_, dx),
639 saturated::Add(top_, dy),
640 saturated::Add(right_, dx),
641 saturated::Add(bottom_, dy),
642 };
643 }
644
645
646 [[nodiscard]] constexpr TRect<T> Shift(TPoint<T> offset) const {
647 return Shift(offset.x, offset.y);
648 }
649
650
651
652 [[nodiscard]] constexpr TRect<T> Expand(T left,
653 T top,
654 T right,
655 T bottom) const {
656 return {
657 saturated::Sub(left_, left),
658 saturated::Sub(top_, top),
659 saturated::Add(right_, right),
660 saturated::Add(bottom_, bottom),
661 };
662 }
663
664
665
666 [[nodiscard]] constexpr TRect<T> Expand(T amount) const {
667 return {
668 saturated::Sub(left_, amount),
669 saturated::Sub(top_, amount),
670 saturated::Add(right_, amount),
671 saturated::Add(bottom_, amount),
672 };
673 }
674
675
676
677 [[nodiscard]] constexpr TRect<T> Expand(T horizontal_amount,
678 T vertical_amount) const {
679 return {
680 saturated::Sub(left_, horizontal_amount),
681 saturated::Sub(top_, vertical_amount),
682 saturated::Add(right_, horizontal_amount),
683 saturated::Add(bottom_, vertical_amount),
684 };
685 }
686
687
688
689 [[nodiscard]] constexpr TRect<T> Expand(TPoint<T> amount) const {
690 return Expand(amount.x, amount.y);
691 }
692
693
694
695 [[nodiscard]] constexpr TRect<T> Expand(TSize<T> amount) const {
696 return Expand(amount.width, amount.height);
697 }
698
699
700
701
702
703 [[nodiscard]] constexpr TRect<T> Project(TRect<T> source) const {
704 if (IsEmpty()) {
705 return {};
706 }
707 return source.Shift(-left_, -top_)
708 .Scale(1.0 /
static_cast<Scalar>(GetWidth()),
709 1.0 /
static_cast<Scalar>(GetHeight()));
710 }
711
713 RoundOut(const TRect<U>& r) {
714 return TRect::MakeLTRB(saturated::Cast<U, Type>(floor(r.GetLeft())),
715 saturated::Cast<U, Type>(floor(r.GetTop())),
716 saturated::Cast<U, Type>(ceil(r.GetRight())),
717 saturated::Cast<U, Type>(ceil(r.GetBottom())));
718 }
719
721 RoundIn(const TRect<U>& r) {
722 return TRect::MakeLTRB(saturated::Cast<U, Type>(ceil(r.GetLeft())),
723 saturated::Cast<U, Type>(ceil(r.GetTop())),
724 saturated::Cast<U, Type>(floor(r.GetRight())),
725 saturated::Cast<U, Type>(floor(r.GetBottom())));
726 }
727
729 Round(const TRect<U>& r) {
730 return TRect::MakeLTRB(saturated::Cast<U, Type>(round(r.GetLeft())),
731 saturated::Cast<U, Type>(round(r.GetTop())),
732 saturated::Cast<U, Type>(round(r.GetRight())),
733 saturated::Cast<U, Type>(round(r.GetBottom())));
734 }
735
736 [[nodiscard]] constexpr static TRect Union(const TRect& a,
737 const std::optional<TRect> b) {
738 return b.has_value() ? a.Union(
b.value()) : a;
739 }
740
741 [[nodiscard]] constexpr static TRect Union(const std::optional<TRect> a,
742 const TRect& b) {
743 return a.has_value() ? a->Union(b) :
b;
744 }
745
746 [[nodiscard]] constexpr static std::optional<TRect> Union(
747 const std::optional<TRect> a,
748 const std::optional<TRect> b) {
749 return a.has_value() ? Union(a.value(), b) :
b;
750 }
751
752 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
753 const TRect& a,
754 const std::optional<TRect> b) {
755 return b.has_value() ? a.Intersection(
b.value()) : a;
756 }
757
758 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
759 const std::optional<TRect> a,
760 const TRect& b) {
761 return a.has_value() ? a->Intersection(b) :
b;
762 }
763
764 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
765 const std::optional<TRect> a,
766 const std::optional<TRect> b) {
767 return a.has_value() ? Intersection(a.value(), b) :
b;
768 }
769
770 private:
771 constexpr TRect(Type left, Type top, Type right, Type bottom)
772 : left_(
left), top_(top), right_(
right), bottom_(bottom) {}
773
774 Type left_;
775 Type top_;
776 Type right_;
777 Type bottom_;
778
779 static constexpr Scalar kMinimumHomogenous = 1.0f / (1 << 14);
780
781
782
783
784
785
786
787
788
789
790 static constexpr int ClipAndInsert(Point clipped[],
791 int index,
792 const Vector3& left,
793 const Vector3& p,
794 const Vector3& right) {
795 if (p.z >= kMinimumHomogenous) {
796 clipped[index++] = {p.x / p.z, p.y / p.z};
797 } else {
798 index = InterpolateAndInsert(clipped, index, p, left);
799 index = InterpolateAndInsert(clipped, index, p, right);
800 }
801 return index;
802 }
803
804
805
806
807 static constexpr int InterpolateAndInsert(Point clipped[],
808 int index,
809 const Vector3& p,
810 const Vector3& neighbor) {
811 if (neighbor.z >= kMinimumHomogenous) {
812 auto t = (kMinimumHomogenous - p.z) / (neighbor.z - p.z);
813 clipped[index++] = {
814 ((1.0f - t) * p.x + t * neighbor.x) / kMinimumHomogenous,
815 ((1.0f - t) * p.y + t * neighbor.y) / kMinimumHomogenous,
816 };
817 }
818 return index;
819 }
820};
821
822using Rect = TRect<Scalar>;
826
827#undef ONLY_ON_FLOAT
828#undef ONLY_ON_FLOAT_M
829
830}
831
833
834template <class T>
835inline std::ostream&
operator<<(std::ostream& out,
838 return out;
839}
840
841}
842
843#endif
bool operator==(const FlutterPoint &a, const FlutterPoint &b)
#define FML_UNREACHABLE()
#define ONLY_ON_FLOAT_M(Modifiers, Return)
bool Contains(const Container &container, const Value &value)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
std::ostream & operator<<(std::ostream &out, const impeller::Arc &a)
constexpr TPoint< T > GetLeftTop() const
constexpr TPoint< T > GetRightBottom() const
std::vector< Point > points