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 template <class U, class FT = T>
157 constexpr static std::enable_if_t<std::is_floating_point_v<FT>, TRect> Make(
158 const TRect<U>& rect) {
159 return MakeLTRB(
160 static_cast<FT>(rect.GetLeft()), static_cast<FT>(rect.GetTop()),
161 static_cast<FT>(rect.GetRight()), static_cast<FT>(rect.GetBottom()));
162 }
163
164 template <typename U>
165 constexpr static std::optional<TRect> MakePointBounds(const U& value) {
166 return MakePointBounds(
value.begin(),
value.end());
167 }
168
169 template <typename PointIter>
170 constexpr static std::optional<TRect> MakePointBounds(const PointIter first,
171 const PointIter last) {
172 if (first == last) {
173 return std::nullopt;
174 }
175 auto left = first->x;
176 auto top = first->y;
177 auto right = first->x;
178 auto bottom = first->y;
179 for (auto it = first + 1; it < last; ++it) {
180 left = std::min(left, it->x);
181 top = std::min(top, it->y);
182 right = std::max(right, it->x);
183 bottom = std::max(bottom, it->y);
184 }
185 return TRect::MakeLTRB(left, top, right, bottom);
186 }
187
188 [[nodiscard]] constexpr static TRect MakeMaximum() {
189 return TRect::MakeLTRB(std::numeric_limits<Type>::lowest(),
190 std::numeric_limits<Type>::lowest(),
191 std::numeric_limits<Type>::max(),
192 std::numeric_limits<Type>::max());
193 }
194
195 [[nodiscard]]
constexpr bool operator==(
const TRect& r)
const {
196 return left_ == r.left_ &&
197 top_ == r.top_ &&
198 right_ == r.right_ &&
199 bottom_ == r.bottom_;
200 }
201
202 [[nodiscard]] constexpr TRect Scale(Type scale) const {
203 return TRect(left_ * scale,
204 top_ * scale,
205 right_ * scale,
206 bottom_ * scale);
207 }
208
209 [[nodiscard]] constexpr TRect Scale(Type scale_x, Type scale_y) const {
210 return TRect(left_ * scale_x,
211 top_ * scale_y,
212 right_ * scale_x,
213 bottom_ * scale_y);
214 }
215
216 [[nodiscard]] constexpr TRect Scale(TPoint<T> scale) const {
217 return Scale(scale.x, scale.y);
218 }
219
220 [[nodiscard]] constexpr TRect Scale(TSize<T> scale) const {
221 return Scale(scale.width, scale.height);
222 }
223
224
225
226
227
228
229
230
231 [[nodiscard]]
constexpr bool Contains(
const TPoint<Type>& p)
const {
232 return !this->IsEmpty() &&
233 p.x >= left_ &&
234 p.y >= top_ &&
235 p.x < right_ &&
236 p.y < bottom_;
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250 [[nodiscard]] constexpr bool ContainsInclusive(const TPoint<Type>& p) const {
251 return !this->IsEmpty() &&
252 p.x >= left_ &&
253 p.y >= top_ &&
254 p.x <= right_ &&
255 p.y <= bottom_;
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273 [[nodiscard]]
constexpr bool Contains(
const TRect& o)
const {
274 return !this->IsEmpty() &&
275 (o.IsEmpty() || (o.left_ >= left_ &&
276 o.top_ >= top_ &&
277 o.right_ <= right_ &&
278 o.bottom_ <= bottom_));
279 }
280
281
282
283
284
285
286
288 IsFinite() const {
289 return std::isfinite(left_) &&
290 std::isfinite(top_) &&
291 std::isfinite(right_) &&
292 std::isfinite(bottom_);
293 }
294
295
296
297 [[nodiscard]] constexpr bool IsEmpty() const {
298
299
300 return !(left_ < right_ && top_ < bottom_);
301 }
302
303
304 [[nodiscard]] constexpr bool IsSquare() const {
305
306
307
308
309
310
311 return !IsEmpty() && (right_ - left_) == (bottom_ - top_);
312 }
313
314 [[nodiscard]] constexpr bool IsMaximum() const {
315 return *this == MakeMaximum();
316 }
317
318
319
320 [[nodiscard]] constexpr TPoint<Type> GetOrigin() const {
321 return {left_, top_};
322 }
323
324
325
326
327 [[nodiscard]] constexpr TSize<Type> GetSize() const {
328 return {GetWidth(), GetHeight()};
329 }
330
331
332
333 [[nodiscard]] constexpr Type GetX() const { return left_; }
334
335
336
337 [[nodiscard]] constexpr Type GetY() const { return top_; }
338
339
340
341 [[nodiscard]] constexpr Type GetWidth() const {
342 return saturated::Sub(right_, left_);
343 }
344
345
346
347 [[nodiscard]] constexpr Type GetHeight() const {
348 return saturated::Sub(bottom_, top_);
349 }
350
351 [[nodiscard]] constexpr auto GetLeft() const { return left_; }
352
353 [[nodiscard]] constexpr auto GetTop() const { return top_; }
354
355 [[nodiscard]] constexpr auto GetRight() const { return right_; }
356
357 [[nodiscard]] constexpr auto GetBottom() const { return bottom_; }
358
359 [[nodiscard]] constexpr TPoint<T> GetLeftTop() const {
360 return {left_, top_};
361 }
362
363 [[nodiscard]] constexpr TPoint<T> GetRightTop() const {
364 return {right_, top_};
365 }
366
367 [[nodiscard]] constexpr TPoint<T> GetLeftBottom() const {
368 return {left_, bottom_};
369 }
370
371 [[nodiscard]] constexpr TPoint<T> GetRightBottom() const {
372 return {right_, bottom_};
373 }
374
375
376 [[nodiscard]] constexpr T Area() const {
377
378 return IsEmpty() ? 0 : (right_ - left_) * (bottom_ - top_);
379 }
380
381
382 [[nodiscard]]
constexpr Point GetCenter()
const {
383 return {saturated::AverageScalar(left_, right_),
384 saturated::AverageScalar(top_, bottom_)};
385 }
386
387 [[nodiscard]] constexpr std::array<T, 4> GetLTRB() const {
388 return {left_, top_, right_, bottom_};
389 }
390
391
392
393 [[nodiscard]] constexpr std::array<T, 4> GetXYWH() const {
394 return {left_, top_, GetWidth(), GetHeight()};
395 }
396
397
398 [[nodiscard]] constexpr TRect GetPositive() const {
399 if (!IsEmpty()) {
400 return *this;
401 }
402 return {
403 std::min(left_, right_),
404 std::min(top_, bottom_),
405 std::max(left_, right_),
406 std::max(top_, bottom_),
407 };
408 }
409
410
411
412
413
414 [[nodiscard]] constexpr std::array<TPoint<T>, 4> GetPoints() const {
415 if (IsEmpty()) {
416 return {};
417 }
418 return {
419 TPoint{left_, top_},
420 TPoint{right_, top_},
421 TPoint{left_, bottom_},
422 TPoint{right_, bottom_},
423 };
424 }
425
426 [[nodiscard]] constexpr std::array<TPoint<T>, 4> GetTransformedPoints(
428 auto points = GetPoints();
429 for (
size_t i = 0;
i <
points.size();
i++) {
431 }
433 }
434
435
436
437
438 [[nodiscard]] constexpr TRect TransformAndClipBounds(
442 }
443
444 if (IsEmpty()) {
445 return {};
446 }
447
448 auto ul =
transform.TransformHomogenous({left_, top_});
449 auto ur =
transform.TransformHomogenous({right_, top_});
450 auto ll =
transform.TransformHomogenous({left_, bottom_});
451 auto lr =
transform.TransformHomogenous({right_, bottom_});
452
453
454
455
457 int index = 0;
458
459
460
461 index = ClipAndInsert(
points, index, ll, ul, ur);
462 index = ClipAndInsert(
points, index, ul, ur, lr);
463 index = ClipAndInsert(
points, index, ur, lr, ll);
464 index = ClipAndInsert(
points, index, lr, ll, ul);
465
466 auto bounds = TRect::MakePointBounds(
points,
points + index);
467 return bounds.value_or(TRect{});
468 }
469
470
471
472 [[nodiscard]]
constexpr TRect TransformBounds(
const Matrix&
transform)
const {
473 if (IsEmpty()) {
474 return {};
475 }
477 auto bounds = TRect::MakePointBounds(
points.begin(),
points.end());
478 if (bounds.has_value()) {
479 return bounds.value();
480 }
482 }
483
484
485
486
487
488
489
490
491 [[nodiscard]] constexpr Matrix GetNormalizingTransform() const {
492 if (!IsEmpty()) {
493 Scalar sx = 1.0 / GetWidth();
494 Scalar sy = 1.0 / GetHeight();
497
498
499 if (sx != 0.0 && sy != 0.0 && 0.0 * sx * sy * tx * ty == 0.0) {
500
501 return Matrix( sx, 0.0f, 0.0f, 0.0f,
502 0.0f, sy, 0.0f, 0.0f,
503 0.0f, 0.0f, 1.0f, 0.0f,
504 tx, ty, 0.0f, 1.0f);
505
506 }
507 }
508
509
510 return Matrix::MakeScale({0.0f, 0.0f, 1.0f});
511 }
512
513 [[nodiscard]] constexpr TRect Union(const TRect& o) const {
514 if (IsEmpty()) {
515 return o;
516 }
517 if (o.IsEmpty()) {
518 return *this;
519 }
520 return {
521 std::min(left_, o.left_),
522 std::min(top_, o.top_),
523 std::max(right_, o.right_),
524 std::max(bottom_, o.bottom_),
525 };
526 }
527
528 [[nodiscard]] constexpr std::optional<TRect> Intersection(
529 const TRect& o) const {
530 if (IntersectsWithRect(o)) {
531 return TRect{
532 std::max(left_, o.left_),
533 std::max(top_, o.top_),
534 std::min(right_, o.right_),
535 std::min(bottom_, o.bottom_),
536 };
537 } else {
538 return std::nullopt;
539 }
540 }
541
542 [[nodiscard]] constexpr TRect IntersectionOrEmpty(const TRect& o) const {
543 return Intersection(o).value_or(TRect());
544 }
545
546 [[nodiscard]] constexpr bool IntersectsWithRect(const TRect& o) const {
547 return !IsEmpty() &&
548 !o.IsEmpty() &&
549 left_ < o.right_ &&
550 top_ < o.bottom_ &&
551 right_ > o.left_ &&
552 bottom_ > o.top_;
553 }
554
555
556
557 [[nodiscard]] constexpr std::optional<TRect<T>> Cutout(const TRect& o) const {
558 if (IsEmpty()) {
559
560
561
562
563
564 return std::nullopt;
565 }
566
567 const auto& [a_left, a_top, a_right, a_bottom] = GetLTRB();
568 const auto& [b_left, b_top, b_right, b_bottom] = o.GetLTRB();
569 if (b_left <= a_left && b_right >= a_right) {
570 if (b_top <= a_top && b_bottom >= a_bottom) {
571
572 return std::nullopt;
573 }
574 if (b_top <= a_top && b_bottom > a_top) {
575
576 return TRect::MakeLTRB(a_left, b_bottom, a_right, a_bottom);
577 }
578 if (b_bottom >= a_bottom && b_top < a_bottom) {
579
580 return TRect::MakeLTRB(a_left, a_top, a_right, b_top);
581 }
582 }
583 if (b_top <= a_top && b_bottom >= a_bottom) {
584 if (b_left <= a_left && b_right > a_left) {
585
586 return TRect::MakeLTRB(b_right, a_top, a_right, a_bottom);
587 }
588 if (b_right >= a_right && b_left < a_right) {
589
590 return TRect::MakeLTRB(a_left, a_top, b_left, a_bottom);
591 }
592 }
593
594 return *this;
595 }
596
597 [[nodiscard]] constexpr TRect CutoutOrEmpty(const TRect& o) const {
598 return Cutout(o).value_or(TRect());
599 }
600
601
602 [[nodiscard]] constexpr TRect<T> Shift(T dx, T dy) const {
603 return {
604 saturated::Add(left_, dx),
605 saturated::Add(top_, dy),
606 saturated::Add(right_, dx),
607 saturated::Add(bottom_, dy),
608 };
609 }
610
611
612 [[nodiscard]] constexpr TRect<T> Shift(TPoint<T> offset) const {
613 return Shift(offset.x, offset.y);
614 }
615
616
617
618 [[nodiscard]] constexpr TRect<T> Expand(T left,
619 T top,
620 T right,
621 T bottom) const {
622 return {
623 saturated::Sub(left_, left),
624 saturated::Sub(top_, top),
625 saturated::Add(right_, right),
626 saturated::Add(bottom_, bottom),
627 };
628 }
629
630
631
632 [[nodiscard]] constexpr TRect<T> Expand(T amount) const {
633 return {
634 saturated::Sub(left_, amount),
635 saturated::Sub(top_, amount),
636 saturated::Add(right_, amount),
637 saturated::Add(bottom_, amount),
638 };
639 }
640
641
642
643 [[nodiscard]] constexpr TRect<T> Expand(T horizontal_amount,
644 T vertical_amount) const {
645 return {
646 saturated::Sub(left_, horizontal_amount),
647 saturated::Sub(top_, vertical_amount),
648 saturated::Add(right_, horizontal_amount),
649 saturated::Add(bottom_, vertical_amount),
650 };
651 }
652
653
654
655 [[nodiscard]] constexpr TRect<T> Expand(TPoint<T> amount) const {
656 return Expand(amount.x, amount.y);
657 }
658
659
660
661 [[nodiscard]] constexpr TRect<T> Expand(TSize<T> amount) const {
662 return Expand(amount.width, amount.height);
663 }
664
665
666
667
668
669 [[nodiscard]] constexpr TRect<T> Project(TRect<T> source) const {
670 if (IsEmpty()) {
671 return {};
672 }
673 return source.Shift(-left_, -top_)
674 .Scale(1.0 /
static_cast<Scalar>(GetWidth()),
675 1.0 /
static_cast<Scalar>(GetHeight()));
676 }
677
679 RoundOut(const TRect<U>& r) {
680 return TRect::MakeLTRB(saturated::Cast<U, Type>(floor(r.GetLeft())),
681 saturated::Cast<U, Type>(floor(r.GetTop())),
682 saturated::Cast<U, Type>(ceil(r.GetRight())),
683 saturated::Cast<U, Type>(ceil(r.GetBottom())));
684 }
685
687 RoundIn(const TRect<U>& r) {
688 return TRect::MakeLTRB(saturated::Cast<U, Type>(ceil(r.GetLeft())),
689 saturated::Cast<U, Type>(ceil(r.GetTop())),
690 saturated::Cast<U, Type>(floor(r.GetRight())),
691 saturated::Cast<U, Type>(floor(r.GetBottom())));
692 }
693
695 Round(const TRect<U>& r) {
696 return TRect::MakeLTRB(saturated::Cast<U, Type>(round(r.GetLeft())),
697 saturated::Cast<U, Type>(round(r.GetTop())),
698 saturated::Cast<U, Type>(round(r.GetRight())),
699 saturated::Cast<U, Type>(round(r.GetBottom())));
700 }
701
702 [[nodiscard]] constexpr static TRect Union(const TRect& a,
703 const std::optional<TRect> b) {
704 return b.has_value() ? a.Union(
b.value()) : a;
705 }
706
707 [[nodiscard]] constexpr static TRect Union(const std::optional<TRect> a,
708 const TRect& b) {
709 return a.has_value() ? a->Union(b) :
b;
710 }
711
712 [[nodiscard]] constexpr static std::optional<TRect> Union(
713 const std::optional<TRect> a,
714 const std::optional<TRect> b) {
715 return a.has_value() ? Union(a.value(), b) :
b;
716 }
717
718 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
719 const TRect& a,
720 const std::optional<TRect> b) {
721 return b.has_value() ? a.Intersection(
b.value()) : a;
722 }
723
724 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
725 const std::optional<TRect> a,
726 const TRect& b) {
727 return a.has_value() ? a->Intersection(b) :
b;
728 }
729
730 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
731 const std::optional<TRect> a,
732 const std::optional<TRect> b) {
733 return a.has_value() ? Intersection(a.value(), b) :
b;
734 }
735
736 private:
737 constexpr TRect(Type left, Type top, Type right, Type bottom)
738 : left_(
left), top_(top), right_(
right), bottom_(bottom) {}
739
740 Type left_;
741 Type top_;
742 Type right_;
743 Type bottom_;
744
745 static constexpr Scalar kMinimumHomogenous = 1.0f / (1 << 14);
746
747
748
749
750
751
752
753
754
755
756 static constexpr int ClipAndInsert(Point clipped[],
757 int index,
758 const Vector3& left,
759 const Vector3& p,
760 const Vector3& right) {
761 if (p.z >= kMinimumHomogenous) {
762 clipped[index++] = {p.x / p.z, p.y / p.z};
763 } else {
764 index = InterpolateAndInsert(clipped, index, p, left);
765 index = InterpolateAndInsert(clipped, index, p, right);
766 }
767 return index;
768 }
769
770
771
772
773 static constexpr int InterpolateAndInsert(Point clipped[],
774 int index,
775 const Vector3& p,
776 const Vector3& neighbor) {
777 if (neighbor.z >= kMinimumHomogenous) {
778 auto t = (kMinimumHomogenous - p.z) / (neighbor.z - p.z);
779 clipped[index++] = {
780 (t * p.x + (1.0f - t) * neighbor.x) / kMinimumHomogenous,
781 (t * p.y + (1.0f - t) * neighbor.y) / kMinimumHomogenous,
782 };
783 }
784 return index;
785 }
786};
787
788using Rect = TRect<Scalar>;
792
793#undef ONLY_ON_FLOAT
794#undef ONLY_ON_FLOAT_M
795
796}
797
799
800template <class T>
801inline std::ostream&
operator<<(std::ostream& out,
804 return out;
805}
806
807}
808
809#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