1 /* 2 * Copyright 2019 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef GrOctoBounds_DEFINED 9 #define GrOctoBounds_DEFINED 10 11 #include "include/core/SkRect.h" 12 #include <functional> 13 14 /** 15 * This class is composed of two bounding boxes: one in device space, and one in a 45-degree rotated 16 * space. 17 * 18 * The 45-degree bounding box resides in "| 1 -1 | * coords" space. 19 * | 1 1 | 20 * 21 * The intersection of these two boxes defines the bounding octagon of a shape. 22 * 23 * Furthermore, both bounding boxes are fully tightened. This means we can blindly find the 24 * intersections between each diagonal and its vertical and horizontal neighbors, and be left with 25 * 8 points that define a convex (possibly degenerate) octagon. 26 */ 27 class GrOctoBounds { 28 public: 29 GrOctoBounds() = default; GrOctoBounds(const SkRect & bounds,const SkRect & bounds45)30 GrOctoBounds(const SkRect& bounds, const SkRect& bounds45) { 31 this->set(bounds, bounds45); 32 } 33 set(const SkRect & bounds,const SkRect & bounds45)34 void set(const SkRect& bounds, const SkRect& bounds45) { 35 fBounds = bounds; 36 fBounds45 = bounds45; 37 SkDEBUGCODE(this->validateBoundsAreTight()); 38 } 39 40 bool operator==(const GrOctoBounds& that) const { 41 return fBounds == that.fBounds && fBounds45 == that.fBounds45; 42 } 43 bool operator!=(const GrOctoBounds& that) const { return !(*this == that); } 44 bounds()45 const SkRect& bounds() const { return fBounds; } left()46 float left() const { return fBounds.left(); } top()47 float top() const { return fBounds.top(); } right()48 float right() const { return fBounds.right(); } bottom()49 float bottom() const { return fBounds.bottom(); } 50 51 52 // The 45-degree bounding box resides in "| 1 -1 | * coords" space. 53 // | 1 1 | bounds45()54 const SkRect& bounds45() const { return fBounds45; } left45()55 float left45() const { return fBounds45.left(); } top45()56 float top45() const { return fBounds45.top(); } right45()57 float right45() const { return fBounds45.right(); } bottom45()58 float bottom45() const { return fBounds45.bottom(); } 59 roundOut(SkIRect * out)60 void roundOut(SkIRect* out) const { 61 // The octagon is the intersection of fBounds and fBounds45 (see the comment at the start of 62 // the class). The octagon's bounding box is therefore just fBounds. And the integer 63 // bounding box can be found by simply rounding out fBounds. 64 fBounds.roundOut(out); 65 } 66 makeOffset(float dx,float dy)67 GrOctoBounds makeOffset(float dx, float dy) const { 68 GrOctoBounds offset; 69 offset.setOffset(*this, dx, dy); 70 return offset; 71 } 72 setOffset(const GrOctoBounds & octoBounds,float dx,float dy)73 void setOffset(const GrOctoBounds& octoBounds, float dx, float dy) { 74 fBounds = octoBounds.fBounds.makeOffset(dx, dy); 75 fBounds45 = octoBounds.fBounds45.makeOffset(dx - dy, dx + dy); 76 SkDEBUGCODE(this->validateBoundsAreTight()); 77 } 78 outset(float radius)79 void outset(float radius) { 80 fBounds.outset(radius, radius); 81 fBounds45.outset(radius*SK_ScalarSqrt2, radius*SK_ScalarSqrt2); 82 SkDEBUGCODE(this->validateBoundsAreTight()); 83 } 84 85 // Clips the octo bounds by a clip rect and ensures the resulting bounds are fully tightened. 86 // Returns false if the octagon and clipRect do not intersect at all. 87 // 88 // NOTE: Does not perform a trivial containment test before the clip routine. It is probably a 89 // good idea to not call this method if 'this->bounds()' are fully contained within 'clipRect'. 90 bool SK_WARN_UNUSED_RESULT clip(const SkIRect& clipRect); 91 92 // The 45-degree bounding box resides in "| 1 -1 | * coords" space. 93 // | 1 1 | 94 // 95 // i.e., | x45 | = | x - y | 96 // | y45 | = | x + y | 97 // 98 // These methods transform points between device space and 45-degree space. Get_x45(float x,float y)99 constexpr static float Get_x45(float x, float y) { return x - y; } Get_y45(float x,float y)100 constexpr static float Get_y45(float x, float y) { return x + y; } Get_x(float x45,float y45)101 constexpr static float Get_x(float x45, float y45) { return (x45 + y45) * .5f; } Get_y(float x45,float y45)102 constexpr static float Get_y(float x45, float y45) { return (y45 - x45) * .5f; } 103 104 #if defined(SK_DEBUG) || defined(GR_TEST_UTILS) 105 void validateBoundsAreTight() const; 106 void validateBoundsAreTight(const std::function<void( 107 bool cond, const char* file, int line, const char* code)>& validateFn) const; 108 #endif 109 110 private: 111 SkRect fBounds; 112 SkRect fBounds45; 113 }; 114 115 #endif 116