Flutter Impeller
rect.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef FLUTTER_IMPELLER_GEOMETRY_RECT_H_
6 #define FLUTTER_IMPELLER_GEOMETRY_RECT_H_
7 
8 #include <array>
9 #include <optional>
10 #include <ostream>
11 #include <vector>
12 
13 #include "fml/logging.h"
18 #include "impeller/geometry/size.h"
19 
20 namespace impeller {
21 
22 #define ONLY_ON_FLOAT_M(Modifiers, Return) \
23  template <typename U = T> \
24  Modifiers std::enable_if_t<std::is_floating_point_v<U>, Return>
25 #define ONLY_ON_FLOAT(Return) DL_ONLY_ON_FLOAT_M(, Return)
26 
27 /// Templated struct for holding an axis-aligned rectangle.
28 ///
29 /// Rectangles are defined as 4 axis-aligned edges that might contain
30 /// space. They can be viewed as 2 X coordinates that define the
31 /// left and right edges and 2 Y coordinates that define the top and
32 /// bottom edges; or they can be viewed as an origin and horizontal
33 /// and vertical dimensions (width and height).
34 ///
35 /// When the left and right edges are equal or reversed (right <= left)
36 /// or the top and bottom edges are equal or reversed (bottom <= top),
37 /// the rectangle is considered empty. Considering the rectangle in XYWH
38 /// form, the width and/or the height would be negative or zero. Such
39 /// reversed/empty rectangles contain no space and act as such in the
40 /// methods that operate on them (Intersection, Union, IntersectsWithRect,
41 /// Contains, Cutout, etc.)
42 ///
43 /// Rectangles cannot be modified by any method and a new value can only
44 /// be stored into an existing rect using assignment. This keeps the API
45 /// clean compared to implementations that might have similar methods
46 /// that produce the answer in place, or construct a new object with
47 /// the answer, or place the result in an indicated result object.
48 ///
49 /// Methods that might fail to produce an answer will use |std::optional|
50 /// to indicate that success or failure (see |Intersection| and |CutOut|).
51 /// For convenience, |Intersection| and |Union| both have overloaded
52 /// variants that take |std::optional| arguments and treat them as if
53 /// the argument was an empty rect to allow chaining multiple such methods
54 /// and only needing to check the optional condition of the final result.
55 /// The primary methods also provide |...OrEmpty| overloaded variants that
56 /// translate an empty optional answer into a simple empty rectangle of the
57 /// same type.
58 ///
59 /// Rounding instance methods are not provided as the return value might
60 /// be wanted as another floating point rectangle or sometimes as an integer
61 /// rectangle. Instead a |RoundOut| factory, defined only for floating point
62 /// input rectangles, is provided to provide control over the result type.
63 ///
64 /// NaN and Infinity values
65 ///
66 /// Constructing an LTRB rectangle using Infinity values should work as
67 /// expected with either 0 or +Infinity returned as dimensions depending on
68 /// which side the Infinity values are on and the sign.
69 ///
70 /// Constructing an XYWH rectangle using Infinity values will usually
71 /// not work if the math requires the object to compute a right or bottom
72 /// edge from ([xy] -Infinity + [wh] +Infinity). Other combinations might
73 /// work.
74 ///
75 /// The special factory |MakeMaximum| is provided to construct a rectangle
76 /// of the indicated coordinate type that covers all finite coordinates.
77 /// It does not use infinity values, but rather the largest finite values
78 /// to avoid math that might produce a NaN value from various getters.
79 ///
80 /// Any rectangle that is constructed with, or computed to have a NaN value
81 /// will be considered the same as any empty rectangle.
82 ///
83 /// Empty Rectangle canonical results summary:
84 ///
85 /// Union will ignore any empty rects and return the other rect
86 /// Intersection will return nullopt if either rect is empty
87 /// IntersectsWithRect will return false if either rect is empty
88 /// Cutout will return the source rect if the argument is empty
89 /// Cutout will return nullopt if the source rectangle is empty
90 /// Contains(Point) will return false if the source rectangle is empty
91 /// Contains(Rect) will return false if the source rectangle is empty
92 /// Contains(Rect) will otherwise return true if the argument is empty
93 /// Specifically, EmptyRect.Contains(EmptyRect) returns false
94 ///
95 /// ---------------
96 /// Special notes on problems using the XYWH form of specifying rectangles:
97 ///
98 /// It is possible to have integer rectangles whose dimensions exceed
99 /// the maximum number that their coordinates can represent since
100 /// (MAX_INT - MIN_INT) overflows the representable positive numbers.
101 /// Floating point rectangles technically have a similar issue in that
102 /// overflow can occur, but it will be automatically converted into
103 /// either an infinity, or a finite-overflow value and still be
104 /// representable, just with little to no precision.
105 ///
106 /// Secondly, specifying a rectangle using XYWH leads to cases where the
107 /// math for (x+w) and/or (y+h) are also beyond the maximum representable
108 /// coordinates. For N-bit integer rectangles declared as XYWH, the
109 /// maximum right coordinate will require N+1 signed bits which cannot be
110 /// stored in storage that uses N-bit integers.
111 ///
112 /// Saturated math is used when constructing a rectangle from XYWH values
113 /// and when returning the dimensions of the rectangle. Constructing an
114 /// integer rectangle from values such that xy + wh is beyond the range
115 /// of the integer type will place the right or bottom edges at the maximum
116 /// value for the integer type. Similarly, constructing an integer rectangle
117 /// such that the distance from the left to the right (or top to bottom) is
118 /// greater than the range of the integer type will simply return the
119 /// maximum integer value as the dimension. Floating point rectangles are
120 /// naturally saturated by the rules of IEEE arithmetic.
121 template <class T>
122 struct TRect {
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 MakeOriginSize(const TPoint<Type>& origin,
141  const TSize<Type>& size) {
142  return MakeXYWH(origin.x, origin.y, size.width, size.height);
143  }
144 
145  template <class U>
146  constexpr static TRect MakeSize(const TSize<U>& size) {
147  return TRect(0.0, 0.0, size.width, size.height);
148  }
149 
150  template <typename U>
151  constexpr static std::optional<TRect> MakePointBounds(const U& value) {
152  return MakePointBounds(value.begin(), value.end());
153  }
154 
155  template <typename PointIter>
156  constexpr static std::optional<TRect> MakePointBounds(const PointIter first,
157  const PointIter last) {
158  if (first == last) {
159  return std::nullopt;
160  }
161  auto left = first->x;
162  auto top = first->y;
163  auto right = first->x;
164  auto bottom = first->y;
165  for (auto it = first + 1; it < last; ++it) {
166  left = std::min(left, it->x);
167  top = std::min(top, it->y);
168  right = std::max(right, it->x);
169  bottom = std::max(bottom, it->y);
170  }
171  return TRect::MakeLTRB(left, top, right, bottom);
172  }
173 
174  [[nodiscard]] constexpr static TRect MakeMaximum() {
175  return TRect::MakeLTRB(std::numeric_limits<Type>::lowest(),
176  std::numeric_limits<Type>::lowest(),
177  std::numeric_limits<Type>::max(),
178  std::numeric_limits<Type>::max());
179  }
180 
181  [[nodiscard]] constexpr bool operator==(const TRect& r) const {
182  return left_ == r.left_ && //
183  top_ == r.top_ && //
184  right_ == r.right_ && //
185  bottom_ == r.bottom_;
186  }
187 
188  [[nodiscard]] constexpr TRect Scale(Type scale) const {
189  return TRect(left_ * scale, //
190  top_ * scale, //
191  right_ * scale, //
192  bottom_ * scale);
193  }
194 
195  [[nodiscard]] constexpr TRect Scale(Type scale_x, Type scale_y) const {
196  return TRect(left_ * scale_x, //
197  top_ * scale_y, //
198  right_ * scale_x, //
199  bottom_ * scale_y);
200  }
201 
202  [[nodiscard]] constexpr TRect Scale(TPoint<T> scale) const {
203  return Scale(scale.x, scale.y);
204  }
205 
206  [[nodiscard]] constexpr TRect Scale(TSize<T> scale) const {
207  return Scale(scale.width, scale.height);
208  }
209 
210  /// @brief Returns true iff the provided point |p| is inside the
211  /// half-open interior of this rectangle.
212  ///
213  /// For purposes of containment, a rectangle contains points
214  /// along the top and left edges but not points along the
215  /// right and bottom edges so that a point is only ever
216  /// considered inside one of two abutting rectangles.
217  [[nodiscard]] constexpr bool Contains(const TPoint<Type>& p) const {
218  return !this->IsEmpty() && //
219  p.x >= left_ && //
220  p.y >= top_ && //
221  p.x < right_ && //
222  p.y < bottom_;
223  }
224 
225  /// @brief Returns true iff this rectangle is not empty and it also
226  /// contains every point considered inside the provided
227  /// rectangle |o| (as determined by |Contains(TPoint)|).
228  ///
229  /// This is similar to a definition where the result is true iff
230  /// the union of the two rectangles is equal to this rectangle,
231  /// ignoring precision issues with performing those operations
232  /// and assuming that empty rectangles are never equal.
233  ///
234  /// An empty rectangle can contain no other rectangle.
235  ///
236  /// An empty rectangle is, however, contained within any
237  /// other non-empy rectangle as the set of points it contains
238  /// is an empty set and so there are no points to fail the
239  /// containment criteria.
240  [[nodiscard]] constexpr bool Contains(const TRect& o) const {
241  return !this->IsEmpty() && //
242  (o.IsEmpty() || (o.left_ >= left_ && //
243  o.top_ >= top_ && //
244  o.right_ <= right_ && //
245  o.bottom_ <= bottom_));
246  }
247 
248  /// @brief Returns true if all of the fields of this floating point
249  /// rectangle are finite.
250  ///
251  /// Note that the results of |GetWidth()| and |GetHeight()| may
252  /// still be infinite due to overflow even if the fields themselves
253  /// are finite.
254  ONLY_ON_FLOAT_M([[nodiscard]] constexpr, bool)
255  IsFinite() const {
256  return std::isfinite(left_) && //
257  std::isfinite(top_) && //
258  std::isfinite(right_) && //
259  std::isfinite(bottom_);
260  }
261 
262  /// @brief Returns true if either of the width or height are 0, negative,
263  /// or NaN.
264  [[nodiscard]] constexpr bool IsEmpty() const {
265  // Computing the non-empty condition and negating the result causes any
266  // NaN value to return true - i.e. is considered empty.
267  return !(left_ < right_ && top_ < bottom_);
268  }
269 
270  /// @brief Returns true if width and height are equal and neither is NaN.
271  [[nodiscard]] constexpr bool IsSquare() const {
272  // empty rectangles can technically be "square", but would be
273  // misleading to most callers. Using |IsEmpty| also prevents
274  // "non-empty and non-overflowing" computations from happening
275  // to be equal to "empty and overflowing" results.
276  // (Consider LTRB(10, 15, MAX-2, MIN+2) which is empty, but both
277  // w/h subtractions equal "5").
278  return !IsEmpty() && (right_ - left_) == (bottom_ - top_);
279  }
280 
281  [[nodiscard]] constexpr bool IsMaximum() const {
282  return *this == MakeMaximum();
283  }
284 
285  /// @brief Returns the upper left corner of the rectangle as specified
286  /// by the left/top or x/y values when it was constructed.
287  [[nodiscard]] constexpr TPoint<Type> GetOrigin() const {
288  return {left_, top_};
289  }
290 
291  /// @brief Returns the size of the rectangle which may be negative in
292  /// either width or height and may have been clipped to the
293  /// maximum integer values for integer rects whose size overflows.
294  [[nodiscard]] constexpr TSize<Type> GetSize() const {
295  return {GetWidth(), GetHeight()};
296  }
297 
298  /// @brief Returns the X coordinate of the upper left corner, equivalent
299  /// to |GetOrigin().x|
300  [[nodiscard]] constexpr Type GetX() const { return left_; }
301 
302  /// @brief Returns the Y coordinate of the upper left corner, equivalent
303  /// to |GetOrigin().y|
304  [[nodiscard]] constexpr Type GetY() const { return top_; }
305 
306  /// @brief Returns the width of the rectangle, equivalent to
307  /// |GetSize().width|
308  [[nodiscard]] constexpr Type GetWidth() const {
309  return saturated::Sub(right_, left_);
310  }
311 
312  /// @brief Returns the height of the rectangle, equivalent to
313  /// |GetSize().height|
314  [[nodiscard]] constexpr Type GetHeight() const {
315  return saturated::Sub(bottom_, top_);
316  }
317 
318  [[nodiscard]] constexpr auto GetLeft() const { return left_; }
319 
320  [[nodiscard]] constexpr auto GetTop() const { return top_; }
321 
322  [[nodiscard]] constexpr auto GetRight() const { return right_; }
323 
324  [[nodiscard]] constexpr auto GetBottom() const { return bottom_; }
325 
326  [[nodiscard]] constexpr TPoint<T> GetLeftTop() const { //
327  return {left_, top_};
328  }
329 
330  [[nodiscard]] constexpr TPoint<T> GetRightTop() const {
331  return {right_, top_};
332  }
333 
334  [[nodiscard]] constexpr TPoint<T> GetLeftBottom() const {
335  return {left_, bottom_};
336  }
337 
338  [[nodiscard]] constexpr TPoint<T> GetRightBottom() const {
339  return {right_, bottom_};
340  }
341 
342  /// @brief Get the area of the rectangle, equivalent to |GetSize().Area()|
343  [[nodiscard]] constexpr T Area() const {
344  // TODO(flutter/flutter#141710) - Use saturated math to avoid overflow
345  // https://github.com/flutter/flutter/issues/141710
346  return IsEmpty() ? 0 : (right_ - left_) * (bottom_ - top_);
347  }
348 
349  /// @brief Get the center point as a |Point|.
350  [[nodiscard]] constexpr Point GetCenter() const {
351  return {saturated::AverageScalar(left_, right_),
352  saturated::AverageScalar(top_, bottom_)};
353  }
354 
355  [[nodiscard]] constexpr std::array<T, 4> GetLTRB() const {
356  return {left_, top_, right_, bottom_};
357  }
358 
359  /// @brief Get the x, y coordinates of the origin and the width and
360  /// height of the rectangle in an array.
361  [[nodiscard]] constexpr std::array<T, 4> GetXYWH() const {
362  return {left_, top_, GetWidth(), GetHeight()};
363  }
364 
365  /// @brief Get a version of this rectangle that has a non-negative size.
366  [[nodiscard]] constexpr TRect GetPositive() const {
367  if (!IsEmpty()) {
368  return *this;
369  }
370  return {
371  std::min(left_, right_),
372  std::min(top_, bottom_),
373  std::max(left_, right_),
374  std::max(top_, bottom_),
375  };
376  }
377 
378  /// @brief Get the points that represent the 4 corners of this rectangle
379  /// in a Z order that is compatible with triangle strips or a set
380  /// of all zero points if the rectangle is empty.
381  /// The order is: Top left, top right, bottom left, bottom right.
382  [[nodiscard]] constexpr std::array<TPoint<T>, 4> GetPoints() const {
383  if (IsEmpty()) {
384  return {};
385  }
386  return {
387  TPoint{left_, top_},
388  TPoint{right_, top_},
389  TPoint{left_, bottom_},
390  TPoint{right_, bottom_},
391  };
392  }
393 
394  [[nodiscard]] constexpr std::array<TPoint<T>, 4> GetTransformedPoints(
395  const Matrix& transform) const {
396  auto points = GetPoints();
397  for (size_t i = 0; i < points.size(); i++) {
398  points[i] = transform * points[i];
399  }
400  return points;
401  }
402 
403  /// @brief Creates a new bounding box that contains this transformed
404  /// rectangle.
405  [[nodiscard]] constexpr TRect TransformBounds(const Matrix& transform) const {
406  if (IsEmpty()) {
407  return {};
408  }
409  auto points = GetTransformedPoints(transform);
410  auto bounds = TRect::MakePointBounds(points.begin(), points.end());
411  if (bounds.has_value()) {
412  return bounds.value();
413  }
414  FML_UNREACHABLE();
415  }
416 
417  /// @brief Constructs a Matrix that will map all points in the coordinate
418  /// space of the rectangle into a new normalized coordinate space
419  /// where the upper left corner of the rectangle maps to (0, 0)
420  /// and the lower right corner of the rectangle maps to (1, 1).
421  ///
422  /// Empty and non-finite rectangles will return a zero-scaling
423  /// transform that maps all points to (0, 0).
424  [[nodiscard]] constexpr Matrix GetNormalizingTransform() const {
425  if (!IsEmpty()) {
426  Scalar sx = 1.0 / GetWidth();
427  Scalar sy = 1.0 / GetHeight();
428  Scalar tx = left_ * -sx;
429  Scalar ty = top_ * -sy;
430 
431  // Exclude NaN and infinities and either scale underflowing to zero
432  if (sx != 0.0 && sy != 0.0 && 0.0 * sx * sy * tx * ty == 0.0) {
433  // clang-format off
434  return Matrix( sx, 0.0f, 0.0f, 0.0f,
435  0.0f, sy, 0.0f, 0.0f,
436  0.0f, 0.0f, 1.0f, 0.0f,
437  tx, ty, 0.0f, 1.0f);
438  // clang-format on
439  }
440  }
441 
442  // Map all coordinates to the origin.
443  return Matrix::MakeScale({0.0f, 0.0f, 1.0f});
444  }
445 
446  [[nodiscard]] constexpr TRect Union(const TRect& o) const {
447  if (IsEmpty()) {
448  return o;
449  }
450  if (o.IsEmpty()) {
451  return *this;
452  }
453  return {
454  std::min(left_, o.left_),
455  std::min(top_, o.top_),
456  std::max(right_, o.right_),
457  std::max(bottom_, o.bottom_),
458  };
459  }
460 
461  [[nodiscard]] constexpr std::optional<TRect> Intersection(
462  const TRect& o) const {
463  if (IntersectsWithRect(o)) {
464  return TRect{
465  std::max(left_, o.left_),
466  std::max(top_, o.top_),
467  std::min(right_, o.right_),
468  std::min(bottom_, o.bottom_),
469  };
470  } else {
471  return std::nullopt;
472  }
473  }
474 
475  [[nodiscard]] constexpr bool IntersectsWithRect(const TRect& o) const {
476  return !IsEmpty() && //
477  !o.IsEmpty() && //
478  left_ < o.right_ && //
479  top_ < o.bottom_ && //
480  right_ > o.left_ && //
481  bottom_ > o.top_;
482  }
483 
484  /// @brief Returns the new boundary rectangle that would result from this
485  /// rectangle being cut out by the specified rectangle.
486  [[nodiscard]] constexpr std::optional<TRect<T>> Cutout(const TRect& o) const {
487  if (IsEmpty()) {
488  // This test isn't just a short-circuit, it also prevents the concise
489  // math below from returning the wrong answer on empty rects.
490  // Once we know that this rectangle is not empty, the math below can
491  // only succeed in computing a value if o is also non-empty and non-nan.
492  // Otherwise, the method returns *this by default.
493  return std::nullopt;
494  }
495 
496  const auto& [a_left, a_top, a_right, a_bottom] = GetLTRB(); // Source rect.
497  const auto& [b_left, b_top, b_right, b_bottom] = o.GetLTRB(); // Cutout.
498  if (b_left <= a_left && b_right >= a_right) {
499  if (b_top <= a_top && b_bottom >= a_bottom) {
500  // Full cutout.
501  return std::nullopt;
502  }
503  if (b_top <= a_top && b_bottom > a_top) {
504  // Cuts off the top.
505  return TRect::MakeLTRB(a_left, b_bottom, a_right, a_bottom);
506  }
507  if (b_bottom >= a_bottom && b_top < a_bottom) {
508  // Cuts off the bottom.
509  return TRect::MakeLTRB(a_left, a_top, a_right, b_top);
510  }
511  }
512  if (b_top <= a_top && b_bottom >= a_bottom) {
513  if (b_left <= a_left && b_right > a_left) {
514  // Cuts off the left.
515  return TRect::MakeLTRB(b_right, a_top, a_right, a_bottom);
516  }
517  if (b_right >= a_right && b_left < a_right) {
518  // Cuts off the right.
519  return TRect::MakeLTRB(a_left, a_top, b_left, a_bottom);
520  }
521  }
522 
523  return *this;
524  }
525 
526  [[nodiscard]] constexpr TRect CutoutOrEmpty(const TRect& o) const {
527  return Cutout(o).value_or(TRect());
528  }
529 
530  /// @brief Returns a new rectangle translated by the given offset.
531  [[nodiscard]] constexpr TRect<T> Shift(T dx, T dy) const {
532  return {
533  saturated::Add(left_, dx), //
534  saturated::Add(top_, dy), //
535  saturated::Add(right_, dx), //
536  saturated::Add(bottom_, dy), //
537  };
538  }
539 
540  /// @brief Returns a new rectangle translated by the given offset.
541  [[nodiscard]] constexpr TRect<T> Shift(TPoint<T> offset) const {
542  return Shift(offset.x, offset.y);
543  }
544 
545  /// @brief Returns a rectangle with expanded edges. Negative expansion
546  /// results in shrinking.
547  [[nodiscard]] constexpr TRect<T> Expand(T left,
548  T top,
549  T right,
550  T bottom) const {
551  return {
552  saturated::Sub(left_, left), //
553  saturated::Sub(top_, top), //
554  saturated::Add(right_, right), //
555  saturated::Add(bottom_, bottom), //
556  };
557  }
558 
559  /// @brief Returns a rectangle with expanded edges in all directions.
560  /// Negative expansion results in shrinking.
561  [[nodiscard]] constexpr TRect<T> Expand(T amount) const {
562  return {
563  saturated::Sub(left_, amount), //
564  saturated::Sub(top_, amount), //
565  saturated::Add(right_, amount), //
566  saturated::Add(bottom_, amount), //
567  };
568  }
569 
570  /// @brief Returns a rectangle with expanded edges in all directions.
571  /// Negative expansion results in shrinking.
572  [[nodiscard]] constexpr TRect<T> Expand(T horizontal_amount,
573  T vertical_amount) const {
574  return {
575  saturated::Sub(left_, horizontal_amount), //
576  saturated::Sub(top_, vertical_amount), //
577  saturated::Add(right_, horizontal_amount), //
578  saturated::Add(bottom_, vertical_amount), //
579  };
580  }
581 
582  /// @brief Returns a rectangle with expanded edges in all directions.
583  /// Negative expansion results in shrinking.
584  [[nodiscard]] constexpr TRect<T> Expand(TPoint<T> amount) const {
585  return Expand(amount.x, amount.y);
586  }
587 
588  /// @brief Returns a rectangle with expanded edges in all directions.
589  /// Negative expansion results in shrinking.
590  [[nodiscard]] constexpr TRect<T> Expand(TSize<T> amount) const {
591  return Expand(amount.width, amount.height);
592  }
593 
594  /// @brief Returns a new rectangle that represents the projection of the
595  /// source rectangle onto this rectangle. In other words, the source
596  /// rectangle is redefined in terms of the coordinate space of this
597  /// rectangle.
598  [[nodiscard]] constexpr TRect<T> Project(TRect<T> source) const {
599  if (IsEmpty()) {
600  return {};
601  }
602  return source.Shift(-left_, -top_)
603  .Scale(1.0 / static_cast<Scalar>(GetWidth()),
604  1.0 / static_cast<Scalar>(GetHeight()));
605  }
606 
607  ONLY_ON_FLOAT_M([[nodiscard]] constexpr static, TRect)
608  RoundOut(const TRect<U>& r) {
609  return TRect::MakeLTRB(saturated::Cast<U, Type>(floor(r.GetLeft())),
610  saturated::Cast<U, Type>(floor(r.GetTop())),
611  saturated::Cast<U, Type>(ceil(r.GetRight())),
612  saturated::Cast<U, Type>(ceil(r.GetBottom())));
613  }
614 
615  [[nodiscard]] constexpr static std::optional<TRect> Union(
616  const TRect& a,
617  const std::optional<TRect> b) {
618  return b.has_value() ? a.Union(b.value()) : a;
619  }
620 
621  [[nodiscard]] constexpr static std::optional<TRect> Union(
622  const std::optional<TRect> a,
623  const TRect& b) {
624  return a.has_value() ? a->Union(b) : b;
625  }
626 
627  [[nodiscard]] constexpr static std::optional<TRect> Union(
628  const std::optional<TRect> a,
629  const std::optional<TRect> b) {
630  return a.has_value() ? Union(a.value(), b) : b;
631  }
632 
633  [[nodiscard]] constexpr static std::optional<TRect> Intersection(
634  const TRect& a,
635  const std::optional<TRect> b) {
636  return b.has_value() ? a.Intersection(b.value()) : a;
637  }
638 
639  [[nodiscard]] constexpr static std::optional<TRect> Intersection(
640  const std::optional<TRect> a,
641  const TRect& b) {
642  return a.has_value() ? a->Intersection(b) : b;
643  }
644 
645  [[nodiscard]] constexpr static std::optional<TRect> Intersection(
646  const std::optional<TRect> a,
647  const std::optional<TRect> b) {
648  return a.has_value() ? Intersection(a.value(), b) : b;
649  }
650 
651  private:
652  constexpr TRect(Type left, Type top, Type right, Type bottom)
653  : left_(left), top_(top), right_(right), bottom_(bottom) {}
654 
655  Type left_;
656  Type top_;
657  Type right_;
658  Type bottom_;
659 };
660 
663 
664 #undef ONLY_ON_FLOAT
665 #undef ONLY_ON_FLOAT_M
666 
667 } // namespace impeller
668 
669 namespace std {
670 
671 template <class T>
672 inline std::ostream& operator<<(std::ostream& out,
673  const impeller::TRect<T>& r) {
674  out << "(" << r.GetOrigin() << ", " << r.GetSize() << ")";
675  return out;
676 }
677 
678 } // namespace std
679 
680 #endif // FLUTTER_IMPELLER_GEOMETRY_RECT_H_
impeller::TRect::Union
constexpr static std::optional< TRect > Union(const std::optional< TRect > a, const TRect &b)
Definition: rect.h:621
impeller::TRect::GetLTRB
constexpr std::array< T, 4 > GetLTRB() const
Definition: rect.h:355
point.h
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::TRect::Expand
constexpr TRect< T > Expand(T horizontal_amount, T vertical_amount) const
Returns a rectangle with expanded edges in all directions. Negative expansion results in shrinking.
Definition: rect.h:572
impeller::TRect::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::TRect::Expand
constexpr TRect< T > Expand(T amount) const
Returns a rectangle with expanded edges in all directions. Negative expansion results in shrinking.
Definition: rect.h:561
saturated_math.h
impeller::TRect::TransformBounds
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:405
impeller::TRect::IsMaximum
constexpr bool IsMaximum() const
Definition: rect.h:281
impeller::TRect::GetLeftTop
constexpr TPoint< T > GetLeftTop() const
Definition: rect.h:326
impeller::TRect::Intersection
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition: rect.h:461
impeller::TRect::Scale
constexpr TRect Scale(Type scale_x, Type scale_y) const
Definition: rect.h:195
impeller::TRect::GetNormalizingTransform
constexpr Matrix GetNormalizingTransform() const
Constructs a Matrix that will map all points in the coordinate space of the rectangle into a new norm...
Definition: rect.h:424
impeller::TRect::CutoutOrEmpty
constexpr TRect CutoutOrEmpty(const TRect &o) const
Definition: rect.h:526
impeller::TRect::Intersection
constexpr static std::optional< TRect > Intersection(const TRect &a, const std::optional< TRect > b)
Definition: rect.h:633
std::operator<<
std::ostream & operator<<(std::ostream &out, const impeller::Color &c)
Definition: color.h:951
impeller::TRect::TRect
constexpr TRect()
Definition: rect.h:127
impeller::TRect::GetCenter
constexpr Point GetCenter() const
Get the center point as a |Point|.
Definition: rect.h:350
impeller::TRect::GetX
constexpr Type GetX() const
Returns the X coordinate of the upper left corner, equivalent to |GetOrigin().x|.
Definition: rect.h:300
ONLY_ON_FLOAT_M
#define ONLY_ON_FLOAT_M(Modifiers, Return)
Definition: rect.h:22
impeller::TRect::GetHeight
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition: rect.h:314
impeller::TRect::GetOrigin
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
Definition: rect.h:287
impeller::TRect::GetRightTop
constexpr TPoint< T > GetRightTop() const
Definition: rect.h:330
impeller::TRect::Contains
constexpr bool Contains(const TRect &o) const
Returns true iff this rectangle is not empty and it also contains every point considered inside the p...
Definition: rect.h:240
impeller::TRect::operator==
constexpr bool operator==(const TRect &r) const
Definition: rect.h:181
impeller::TRect::IntersectsWithRect
constexpr bool IntersectsWithRect(const TRect &o) const
Definition: rect.h:475
impeller::TRect::GetPoints
constexpr std::array< TPoint< T >, 4 > GetPoints() const
Get the points that represent the 4 corners of this rectangle in a Z order that is compatible with tr...
Definition: rect.h:382
impeller::TRect::MakePointBounds
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:151
impeller::TRect::Shift
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
Definition: rect.h:531
impeller::TRect::IsEmpty
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
Definition: rect.h:264
impeller::TRect::RoundOut
RoundOut(const TRect< U > &r)
Definition: rect.h:608
matrix.h
impeller::TRect::Scale
constexpr TRect Scale(TSize< T > scale) const
Definition: rect.h:206
impeller::TSize
Definition: size.h:19
impeller::TRect::GetLeft
constexpr auto GetLeft() const
Definition: rect.h:318
impeller::TRect::GetTransformedPoints
constexpr std::array< TPoint< T >, 4 > GetTransformedPoints(const Matrix &transform) const
Definition: rect.h:394
impeller::TRect::GetWidth
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition: rect.h:308
impeller::TRect::GetLeftBottom
constexpr TPoint< T > GetLeftBottom() const
Definition: rect.h:334
impeller::TRect::IsSquare
constexpr bool IsSquare() const
Returns true if width and height are equal and neither is NaN.
Definition: rect.h:271
impeller::TRect::MakeOriginSize
constexpr static TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
Definition: rect.h:140
impeller::TRect::Scale
constexpr TRect Scale(Type scale) const
Definition: rect.h:188
impeller::TRect::MakePointBounds
constexpr static std::optional< TRect > MakePointBounds(const PointIter first, const PointIter last)
Definition: rect.h:156
impeller::TRect::Shift
constexpr TRect< T > Shift(TPoint< T > offset) const
Returns a new rectangle translated by the given offset.
Definition: rect.h:541
impeller::TRect::Scale
constexpr TRect Scale(TPoint< T > scale) const
Definition: rect.h:202
impeller::TSize::width
Type width
Definition: size.h:22
impeller::TRect::Contains
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
Definition: rect.h:217
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::TRect::IsFinite
IsFinite() const
Returns true if all of the fields of this floating point rectangle are finite.
Definition: rect.h:255
scalar.h
impeller::TRect::Expand
constexpr TRect< T > Expand(TPoint< T > amount) const
Returns a rectangle with expanded edges in all directions. Negative expansion results in shrinking.
Definition: rect.h:584
impeller::TRect::Expand
constexpr TRect< T > Expand(TSize< T > amount) const
Returns a rectangle with expanded edges in all directions. Negative expansion results in shrinking.
Definition: rect.h:590
impeller::TRect::Cutout
constexpr std::optional< TRect< T > > Cutout(const TRect &o) const
Returns the new boundary rectangle that would result from this rectangle being cut out by the specifi...
Definition: rect.h:486
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition: rect.h:294
impeller::TRect::GetRight
constexpr auto GetRight() const
Definition: rect.h:322
impeller::TRect::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
std
Definition: comparable.h:95
impeller::TRect::Project
constexpr TRect< T > Project(TRect< T > source) const
Returns a new rectangle that represents the projection of the source rectangle onto this rectangle....
Definition: rect.h:598
impeller::TPoint
Definition: point.h:27
impeller::TRect::MakeMaximum
constexpr static TRect MakeMaximum()
Definition: rect.h:174
impeller::saturated::b
SI b
Definition: saturated_math.h:87
scale
const Scalar scale
Definition: stroke_path_geometry.cc:297
impeller::TRect::Union
constexpr TRect Union(const TRect &o) const
Definition: rect.h:446
impeller::TRect::Area
constexpr T Area() const
Get the area of the rectangle, equivalent to |GetSize().Area()|.
Definition: rect.h:343
impeller::TRect::GetBottom
constexpr auto GetBottom() const
Definition: rect.h:324
impeller::TSize::height
Type height
Definition: size.h:23
impeller::TRect::Union
constexpr static std::optional< TRect > Union(const std::optional< TRect > a, const std::optional< TRect > b)
Definition: rect.h:627
impeller::TRect::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::TRect::GetPositive
constexpr TRect GetPositive() const
Get a version of this rectangle that has a non-negative size.
Definition: rect.h:366
offset
Point offset
Definition: stroke_path_geometry.cc:300
impeller::TRect::GetRightBottom
constexpr TPoint< T > GetRightBottom() const
Definition: rect.h:338
impeller::TRect::Intersection
constexpr static std::optional< TRect > Intersection(const std::optional< TRect > a, const TRect &b)
Definition: rect.h:639
impeller::TRect::GetY
constexpr Type GetY() const
Returns the Y coordinate of the upper left corner, equivalent to |GetOrigin().y|.
Definition: rect.h:304
impeller
Definition: aiks_blur_unittests.cc:20
impeller::TRect::GetXYWH
constexpr std::array< T, 4 > GetXYWH() const
Get the x, y coordinates of the origin and the width and height of the rectangle in an array.
Definition: rect.h:361
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::TRect::GetTop
constexpr auto GetTop() const
Definition: rect.h:320
impeller::TRect
Definition: rect.h:122
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
size.h
impeller::TRect::Expand
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
Definition: rect.h:547
impeller::TRect::Union
constexpr static std::optional< TRect > Union(const TRect &a, const std::optional< TRect > b)
Definition: rect.h:615
impeller::TRect::Intersection
constexpr static std::optional< TRect > Intersection(const std::optional< TRect > a, const std::optional< TRect > b)
Definition: rect.h:645