Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
rect.h File Reference
#include <array>
#include <optional>
#include <ostream>
#include <vector>
#include "fml/logging.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/saturated_math.h"
#include "impeller/geometry/scalar.h"
#include "impeller/geometry/size.h"

Go to the source code of this file.

Classes

struct  impeller::TRect< T >
 

Namespaces

namespace  impeller
 
namespace  std
 

Macros

#define ONLY_ON_FLOAT_M(Modifiers, Return)
 
#define ONLY_ON_FLOAT(Return)   DL_ONLY_ON_FLOAT_M(, Return)
 

Typedefs

using impeller::Rect = TRect< Scalar >
 
using impeller::IRect32 = TRect< int32_t >
 
using impeller::IRect64 = TRect< int64_t >
 
using impeller::IRect = IRect64
 

Macro Definition Documentation

◆ ONLY_ON_FLOAT

#define ONLY_ON_FLOAT (   Return)    DL_ONLY_ON_FLOAT_M(, Return)

Definition at line 25 of file rect.h.

◆ ONLY_ON_FLOAT_M

#define ONLY_ON_FLOAT_M (   Modifiers,
  Return 
)
Value:
template <typename U = T> \
Modifiers std::enable_if_t<std::is_floating_point_v<U>, Return>

Definition at line 22 of file rect.h.

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) {
141 return TRect(0, 0, width, 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 /// Construct the rectangular bounds of a circle with the supplied
155 /// center point and uniform radius.
156 constexpr static TRect MakeCircleBounds(const TPoint<Type>& center,
157 Type radius) {
158 return MakeLTRB(center.x - radius, center.y - radius, //
159 center.x + radius, center.y + radius);
160 }
161
162 /// Construct the rectangular bounds of a circle with the supplied
163 /// center point and non-uniform horizontal and vertical radii.
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, //
167 center.x + radii.width, center.y + radii.height);
168 }
169
170 /// Construct the rectangular bounds of a circle with the supplied
171 /// center point and non-uniform horizontal and vertical radii.
172 constexpr static TRect MakeEllipseBounds(const TPoint<Type>& center,
173 const TPoint<Type>& radii) {
174 return MakeLTRB(center.x - radii.x, center.y - radii.y, //
175 center.x + radii.x, center.y + radii.y);
176 }
177
178 /// Construct a floating point rect |Rect| from another Rect of a
179 /// potentially different storage type (eg. |IRect|).
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 /// @brief Returns true iff the provided point |p| is inside the
249 /// half-open interior of this rectangle.
250 ///
251 /// For purposes of containment, a rectangle contains points
252 /// along the top and left edges but not points along the
253 /// right and bottom edges so that a point is only ever
254 /// considered inside one of two abutting rectangles.
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 /// @brief Returns true iff the provided point |p| is inside the
264 /// closed-range interior of this rectangle.
265 ///
266 /// Unlike the regular |Contains(TPoint)| method, this method
267 /// considers all points along the boundary of the rectangle
268 /// to be contained within the rectangle - useful for testing
269 /// if vertices that define a filled shape would carry the
270 /// interior of that shape outside the bounds of the rectangle.
271 /// Since both geometries are defining half-open spaces, their
272 /// defining geometry needs to consider their boundaries to
273 /// be equivalent with respect to interior and exterior.
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 /// @brief Returns true iff this rectangle is not empty and it also
283 /// contains every point considered inside the provided
284 /// rectangle |o| (as determined by |Contains(TPoint)|).
285 ///
286 /// This is similar to a definition where the result is true iff
287 /// the union of the two rectangles is equal to this rectangle,
288 /// ignoring precision issues with performing those operations
289 /// and assuming that empty rectangles are never equal.
290 ///
291 /// An empty rectangle can contain no other rectangle.
292 ///
293 /// An empty rectangle is, however, contained within any
294 /// other non-empy rectangle as the set of points it contains
295 /// is an empty set and so there are no points to fail the
296 /// containment criteria.
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>
307 Contains(const TRect<U>& o) const {
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 /// @brief Returns true if all of the fields of this floating point
316 /// rectangle are finite.
317 ///
318 /// Note that the results of |GetWidth()| and |GetHeight()| may
319 /// still be infinite due to overflow even if the fields themselves
320 /// are finite.
321 ONLY_ON_FLOAT_M([[nodiscard]] constexpr, bool)
322 IsFinite() const {
323 return std::isfinite(left_) && //
324 std::isfinite(top_) && //
325 std::isfinite(right_) && //
326 std::isfinite(bottom_);
327 }
328
329 /// @brief Returns true if either of the width or height are 0, negative,
330 /// or NaN.
331 [[nodiscard]] constexpr bool IsEmpty() const {
332 // Computing the non-empty condition and negating the result causes any
333 // NaN value to return true - i.e. is considered empty.
334 return !(left_ < right_ && top_ < bottom_);
335 }
336
337 /// @brief Returns true if width and height are equal and neither is NaN.
338 [[nodiscard]] constexpr bool IsSquare() const {
339 // empty rectangles can technically be "square", but would be
340 // misleading to most callers. Using |IsEmpty| also prevents
341 // "non-empty and non-overflowing" computations from happening
342 // to be equal to "empty and overflowing" results.
343 // (Consider LTRB(10, 15, MAX-2, MIN+2) which is empty, but both
344 // w/h subtractions equal "5").
345 return !IsEmpty() && (right_ - left_) == (bottom_ - top_);
346 }
347
348 [[nodiscard]] constexpr bool IsMaximum() const {
349 return *this == MakeMaximum();
350 }
351
352 /// @brief Returns the upper left corner of the rectangle as specified
353 /// by the left/top or x/y values when it was constructed.
354 [[nodiscard]] constexpr TPoint<Type> GetOrigin() const {
355 return {left_, top_};
356 }
357
358 /// @brief Returns the size of the rectangle which may be negative in
359 /// either width or height and may have been clipped to the
360 /// maximum integer values for integer rects whose size overflows.
361 [[nodiscard]] constexpr TSize<Type> GetSize() const {
362 return {GetWidth(), GetHeight()};
363 }
364
365 /// @brief Returns the X coordinate of the upper left corner, equivalent
366 /// to |GetOrigin().x|
367 [[nodiscard]] constexpr Type GetX() const { return left_; }
368
369 /// @brief Returns the Y coordinate of the upper left corner, equivalent
370 /// to |GetOrigin().y|
371 [[nodiscard]] constexpr Type GetY() const { return top_; }
372
373 /// @brief Returns the width of the rectangle, equivalent to
374 /// |GetSize().width|
375 [[nodiscard]] constexpr Type GetWidth() const {
376 return saturated::Sub(right_, left_);
377 }
378
379 /// @brief Returns the height of the rectangle, equivalent to
380 /// |GetSize().height|
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 /// @brief Get the area of the rectangle, equivalent to |GetSize().Area()|
410 [[nodiscard]] constexpr T Area() const {
411 // TODO(141710): Use saturated math to avoid overflow.
412 return IsEmpty() ? 0 : (right_ - left_) * (bottom_ - top_);
413 }
414
415 /// @brief Get the center point as a |Point|.
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 /// @brief Get the x, y coordinates of the origin and the width and
426 /// height of the rectangle in an array.
427 [[nodiscard]] constexpr std::array<T, 4> GetXYWH() const {
428 return {left_, top_, GetWidth(), GetHeight()};
429 }
430
431 /// @brief Get a version of this rectangle that has a non-negative size.
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 /// @brief Get the points that represent the 4 corners of this rectangle
445 /// in a Z order that is compatible with triangle strips or a set
446 /// of all zero points if the rectangle is empty.
447 /// The order is: Top left, top right, bottom left, bottom right.
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(
461 const Matrix& transform) const {
462 auto points = GetPoints();
463 for (size_t i = 0; i < points.size(); i++) {
464 points[i] = transform * points[i];
465 }
466 return points;
467 }
468
469 /// @brief Creates a new bounding box that contains this transformed
470 /// rectangle, clipped against the near clipping plane if
471 /// necessary.
472 [[nodiscard]] constexpr TRect TransformAndClipBounds(
473 const Matrix& transform) const {
474 if (!transform.HasPerspective2D()) {
475 return TransformBounds(transform);
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 // It can probably be proven that we only ever have 5 points at most
488 // which happens when only 1 corner is clipped and we get 2 points
489 // in return for it as we interpolate against its neighbors.
490 Point points[8];
491 int index = 0;
492
493 // Process (clip and interpolate) each point against its 2 neighbors:
494 // left, pt, right
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 /// @brief Creates a new bounding box that contains this transformed
505 /// rectangle.
506 [[nodiscard]] constexpr TRect TransformBounds(const Matrix& transform) const {
507 if (IsEmpty()) {
508 return {};
509 }
510 auto points = GetTransformedPoints(transform);
511 auto bounds = TRect::MakePointBounds(points.begin(), points.end());
512 if (bounds.has_value()) {
513 return bounds.value();
514 }
516 }
517
518 /// @brief Constructs a Matrix that will map all points in the coordinate
519 /// space of the rectangle into a new normalized coordinate space
520 /// where the upper left corner of the rectangle maps to (0, 0)
521 /// and the lower right corner of the rectangle maps to (1, 1).
522 ///
523 /// Empty and non-finite rectangles will return a zero-scaling
524 /// transform that maps all points to (0, 0).
525 [[nodiscard]] constexpr Matrix GetNormalizingTransform() const {
526 if (!IsEmpty()) {
527 Scalar sx = 1.0 / GetWidth();
528 Scalar sy = 1.0 / GetHeight();
529 Scalar tx = left_ * -sx;
530 Scalar ty = top_ * -sy;
531
532 // Exclude NaN and infinities and either scale underflowing to zero
533 if (sx != 0.0 && sy != 0.0 && 0.0 * sx * sy * tx * ty == 0.0) {
534 // clang-format off
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 // clang-format on
540 }
541 }
542
543 // Map all coordinates to the origin.
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 /// @brief Returns the new boundary rectangle that would result from this
590 /// rectangle being cut out by the specified rectangle.
591 [[nodiscard]] constexpr std::optional<TRect<T>> Cutout(const TRect& o) const {
592 if (IsEmpty()) {
593 // This test isn't just a short-circuit, it also prevents the concise
594 // math below from returning the wrong answer on empty rects.
595 // Once we know that this rectangle is not empty, the math below can
596 // only succeed in computing a value if o is also non-empty and non-nan.
597 // Otherwise, the method returns *this by default.
598 return std::nullopt;
599 }
600
601 const auto& [a_left, a_top, a_right, a_bottom] = GetLTRB(); // Source rect.
602 const auto& [b_left, b_top, b_right, b_bottom] = o.GetLTRB(); // Cutout.
603 if (b_left <= a_left && b_right >= a_right) {
604 if (b_top <= a_top && b_bottom >= a_bottom) {
605 // Full cutout.
606 return std::nullopt;
607 }
608 if (b_top <= a_top && b_bottom > a_top) {
609 // Cuts off the top.
610 return TRect::MakeLTRB(a_left, b_bottom, a_right, a_bottom);
611 }
612 if (b_bottom >= a_bottom && b_top < a_bottom) {
613 // Cuts off the bottom.
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 // Cuts off the left.
620 return TRect::MakeLTRB(b_right, a_top, a_right, a_bottom);
621 }
622 if (b_right >= a_right && b_left < a_right) {
623 // Cuts off the right.
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 /// @brief Returns a new rectangle translated by the given offset.
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 /// @brief Returns a new rectangle translated by the given offset.
646 [[nodiscard]] constexpr TRect<T> Shift(TPoint<T> offset) const {
647 return Shift(offset.x, offset.y);
648 }
649
650 /// @brief Returns a rectangle with expanded edges. Negative expansion
651 /// results in shrinking.
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 /// @brief Returns a rectangle with expanded edges in all directions.
665 /// Negative expansion results in shrinking.
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 /// @brief Returns a rectangle with expanded edges in all directions.
676 /// Negative expansion results in shrinking.
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 /// @brief Returns a rectangle with expanded edges in all directions.
688 /// Negative expansion results in shrinking.
689 [[nodiscard]] constexpr TRect<T> Expand(TPoint<T> amount) const {
690 return Expand(amount.x, amount.y);
691 }
692
693 /// @brief Returns a rectangle with expanded edges in all directions.
694 /// Negative expansion results in shrinking.
695 [[nodiscard]] constexpr TRect<T> Expand(TSize<T> amount) const {
696 return Expand(amount.width, amount.height);
697 }
698
699 /// @brief Returns a rectangle with edges expanded to satisfy a minimum size
700 /// in a 2D-transformed coordinate space. This function is not valid
701 /// for a matrix with perspective elements.
702 ///
703 /// If the transform has a scaling factor of zero in either dimension,
704 /// it cannot be expanded to the minimum size. This returns nullopt.
705 [[nodiscard]] constexpr std::optional<TRect<T>> ExpandToMinTransformedSize(
706 TSize<T> min_transformed_size,
707 const Matrix& transform) const {
708 FML_DCHECK(!transform.HasPerspective2D());
709
710 Vector2 transform_scaling = transform.GetBasisScaleXY();
711 if (transform_scaling.x == 0.0f || transform_scaling.y == 0.0f) {
712 return std::nullopt;
713 }
714
715 Size min_local_size =
716 Size(min_transformed_size.width / transform_scaling.x,
717 min_transformed_size.height / transform_scaling.y);
718 if (!min_local_size.IsFinite()) {
719 return std::nullopt;
720 }
721 Size current_size = GetSize();
722
723 if (current_size.width >= min_local_size.width &&
724 current_size.height >= min_local_size.height) {
725 // No expansion needed.
726 return *this;
727 }
728
729 Size expanded_size = current_size.Max(min_local_size);
730 return MakeEllipseBounds(GetCenter(), Point(expanded_size.width * 0.5f,
731 expanded_size.height * 0.5f));
732 }
733
734 /// @brief Returns a new rectangle that represents the projection of the
735 /// source rectangle onto this rectangle. In other words, the source
736 /// rectangle is redefined in terms of the coordinate space of this
737 /// rectangle.
738 [[nodiscard]] constexpr TRect<T> Project(TRect<T> source) const {
739 if (IsEmpty()) {
740 return {};
741 }
742 return source.Shift(-left_, -top_)
743 .Scale(1.0 / static_cast<Scalar>(GetWidth()),
744 1.0 / static_cast<Scalar>(GetHeight()));
745 }
746
747 ONLY_ON_FLOAT_M([[nodiscard]] constexpr static, TRect)
748 RoundOut(const TRect<U>& r) {
749 return TRect::MakeLTRB(saturated::Cast<U, Type>(floor(r.GetLeft())),
750 saturated::Cast<U, Type>(floor(r.GetTop())),
751 saturated::Cast<U, Type>(ceil(r.GetRight())),
752 saturated::Cast<U, Type>(ceil(r.GetBottom())));
753 }
754
755 ONLY_ON_FLOAT_M([[nodiscard]] constexpr static, TRect)
756 RoundIn(const TRect<U>& r) {
757 return TRect::MakeLTRB(saturated::Cast<U, Type>(ceil(r.GetLeft())),
758 saturated::Cast<U, Type>(ceil(r.GetTop())),
759 saturated::Cast<U, Type>(floor(r.GetRight())),
760 saturated::Cast<U, Type>(floor(r.GetBottom())));
761 }
762
763 ONLY_ON_FLOAT_M([[nodiscard]] constexpr static, TRect)
764 Round(const TRect<U>& r) {
765 return TRect::MakeLTRB(saturated::Cast<U, Type>(round(r.GetLeft())),
766 saturated::Cast<U, Type>(round(r.GetTop())),
767 saturated::Cast<U, Type>(round(r.GetRight())),
768 saturated::Cast<U, Type>(round(r.GetBottom())));
769 }
770
771 [[nodiscard]] constexpr static TRect Union(const TRect& a,
772 const std::optional<TRect> b) {
773 return b.has_value() ? a.Union(b.value()) : a;
774 }
775
776 [[nodiscard]] constexpr static TRect Union(const std::optional<TRect> a,
777 const TRect& b) {
778 return a.has_value() ? a->Union(b) : b;
779 }
780
781 [[nodiscard]] constexpr static std::optional<TRect> Union(
782 const std::optional<TRect> a,
783 const std::optional<TRect> b) {
784 return a.has_value() ? Union(a.value(), b) : b;
785 }
786
787 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
788 const TRect& a,
789 const std::optional<TRect> b) {
790 return b.has_value() ? a.Intersection(b.value()) : a;
791 }
792
793 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
794 const std::optional<TRect> a,
795 const TRect& b) {
796 return a.has_value() ? a->Intersection(b) : b;
797 }
798
799 [[nodiscard]] constexpr static std::optional<TRect> Intersection(
800 const std::optional<TRect> a,
801 const std::optional<TRect> b) {
802 return a.has_value() ? Intersection(a.value(), b) : b;
803 }
804
805 private:
806 constexpr TRect(Type left, Type top, Type right, Type bottom)
807 : left_(left), top_(top), right_(right), bottom_(bottom) {}
808
809 Type left_;
810 Type top_;
811 Type right_;
812 Type bottom_;
813
814 static constexpr Scalar kMinimumHomogenous = 1.0f / (1 << 14);
815
816 // Clip p against the near clipping plane (W = kMinimumHomogenous)
817 // and interpolate a crossing point against the nearby neighbors
818 // left and right if p is clipped and either of them is not.
819 // This method can produce 0, 1, or 2 points per call depending on
820 // how many of the points are clipped.
821 // 0 - all points are clipped
822 // 1 - p is unclipped OR
823 // p is clipped and exactly one of the neighbors is not
824 // 2 - p is clipped and both neighbors are not
825 static constexpr int ClipAndInsert(Point clipped[],
826 int index,
827 const Vector3& left,
828 const Vector3& p,
829 const Vector3& right) {
830 if (p.z >= kMinimumHomogenous) {
831 clipped[index++] = {p.x / p.z, p.y / p.z};
832 } else {
833 index = InterpolateAndInsert(clipped, index, p, left);
834 index = InterpolateAndInsert(clipped, index, p, right);
835 }
836 return index;
837 }
838
839 // Interpolate (a clipped) point p against one of its neighbors
840 // and insert the point into the array where the line between them
841 // veers from clipped space to unclipped, if such a point exists.
842 static constexpr int InterpolateAndInsert(Point clipped[],
843 int index,
844 const Vector3& p,
845 const Vector3& neighbor) {
846 if (neighbor.z >= kMinimumHomogenous) {
847 auto t = (kMinimumHomogenous - p.z) / (neighbor.z - p.z);
848 clipped[index++] = {
849 ((1.0f - t) * p.x + t * neighbor.x) / kMinimumHomogenous,
850 ((1.0f - t) * p.y + t * neighbor.y) / kMinimumHomogenous,
851 };
852 }
853 return index;
854 }
855};
856
857using Rect = TRect<Scalar>;
858using IRect32 = TRect<int32_t>;
859using IRect64 = TRect<int64_t>;
860using IRect = IRect64;
861
862#undef ONLY_ON_FLOAT
863#undef ONLY_ON_FLOAT_M
864
865} // namespace impeller
866
867namespace std {
868
869template <class T>
870inline std::ostream& operator<<(std::ostream& out,
871 const impeller::TRect<T>& r) {
872 out << "(" << r.GetLeftTop() << " => " << r.GetRightBottom() << ")";
873 return out;
874}
875
876} // namespace std
877
878#endif // FLUTTER_IMPELLER_GEOMETRY_RECT_H_
int32_t value
int32_t x
bool operator==(const FlutterPoint &a, const FlutterPoint &b)
#define FML_UNREACHABLE()
Definition logging.h:128
#define FML_DCHECK(condition)
Definition logging.h:122
#define ONLY_ON_FLOAT_M(Modifiers, Return)
Definition rect.h:22
double y
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
Point Vector2
Definition point.h:430
TRect< int32_t > IRect32
Definition rect.h:858
float Scalar
Definition scalar.h:19
TRect< Scalar > Rect
Definition rect.h:857
TPoint< Scalar > Point
Definition point.h:426
IRect64 IRect
Definition rect.h:860
TSize< Scalar > Size
Definition size.h:159
TRect< int64_t > IRect64
Definition rect.h:859
Definition ref_ptr.h:261
std::ostream & operator<<(std::ostream &out, const impeller::Arc &a)
Definition arc.h:141
int32_t height
int32_t width
constexpr TPoint< T > GetLeftTop() const
Definition rect.h:393
constexpr TPoint< T > GetRightBottom() const
Definition rect.h:405
constexpr TSize Max(const TSize &o) const
Definition size.h:97
std::vector< Point > points