SkRRect.h revision 306ab9d5de38f2a547fd1d69aedbe69b5c6617cc
1/* 2 * Copyright 2012 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 SkRRect_DEFINED 9#define SkRRect_DEFINED 10 11#include "SkRect.h" 12#include "SkPoint.h" 13 14class SkPath; 15 16// Path forward: 17// core work 18// add validate method (all radii positive, all radii sums < rect size, etc.) 19// add contains(SkRect&) - for clip stack 20// add contains(SkRRect&) - for clip stack 21// add heart rect computation (max rect inside RR) 22// add 9patch rect computation 23// add growToInclude(SkPath&) 24// analysis 25// use growToInclude to fit skp round rects & generate stats (RRs vs. real paths) 26// check on # of rectorus's the RRs could handle 27// rendering work 28// add entry points (clipRRect, drawRRect) - plumb down to SkDevice 29// update SkPath.addRRect() to take an SkRRect - only use quads 30// -- alternatively add addRRectToPath here 31// add GM and bench 32// clipping opt 33// update SkClipStack to perform logic with RRs 34// further out 35// add RR rendering shader to Ganesh (akin to cicle drawing code) 36// - only for simple RRs 37// detect and triangulate RRectorii rather than falling back to SW in Ganesh 38// 39 40/** \class SkRRect 41 42 The SkRRect class represents a rounded rect with a potentially different 43 radii for each corner. It does not have a constructor so must be 44 initialized with one of the initialization functions (e.g., setEmpty, 45 setRectRadii, etc.) 46 47 This class is intended to roughly match CSS' border-*-*-radius capabilities. 48 This means: 49 If either of a corner's radii are 0 the corner will be square. 50 Negative radii are not allowed (they are clamped to zero). 51 If the corner curves overlap they will be proportionally reduced to fit. 52*/ 53class SK_API SkRRect { 54public: 55 /** 56 * Enum to capture the various possible subtypes of RR. Accessed 57 * by type(). The subtypes become progressively less restrictive. 58 */ 59 enum Type { 60 // !< Internal indicator that the sub type must be computed. 61 kUnknown_Type = -1, 62 63 // !< The RR is empty 64 kEmpty_Type, 65 66 //!< The RR is actually a (non-empty) rect (i.e., at least one radius 67 //!< at each corner is zero) 68 kRect_Type, 69 70 //!< The RR is actually a (non-empty) oval (i.e., all x radii are equal 71 //!< and >= width/2 and all the y radii are equal and >= height/2 72 kOval_Type, 73 74 //!< The RR is non-empty and all the x radii are equal & all y radii 75 //!< are equal but it is not an oval (i.e., there are lines between 76 //!< the curves) nor a rect (i.e., both radii are non-zero) 77 kSimple_Type, 78 79 //!< A fully general (non-empty) RR. Some of the x and/or y radii are 80 //!< different from the others and there must be one corner where 81 //!< both radii are non-zero. 82 kComplex_Type, 83 }; 84 85 /** 86 * Returns the RR's sub type. 87 */ 88 Type getType() const { 89 SkDEBUGCODE(this->validate();) 90 91 if (kUnknown_Type == fType) { 92 this->computeType(); 93 } 94 SkASSERT(kUnknown_Type != fType); 95 return fType; 96 } 97 98 Type type() const { return this->getType(); } 99 100 inline bool isEmpty() const { return kEmpty_Type == this->getType(); } 101 inline bool isRect() const { return kRect_Type == this->getType(); } 102 inline bool isOval() const { return kOval_Type == this->getType(); } 103 inline bool isSimple() const { return kSimple_Type == this->getType(); } 104 inline bool isComplex() const { return kComplex_Type == this->getType(); } 105 106 /** 107 * Set this RR to the empty rectangle (0,0,0,0) with 0 x & y radii. 108 */ 109 void setEmpty() { 110 fRect.setEmpty(); 111 memset(fRadii, 0, sizeof(fRadii)); 112 fType = kEmpty_Type; 113 114 SkDEBUGCODE(this->validate();) 115 } 116 117 /** 118 * Set this RR to match the supplied rect. All radii will be 0. 119 */ 120 void setRect(const SkRect& rect) { 121 if (rect.isEmpty()) { 122 this->setEmpty(); 123 return; 124 } 125 126 fRect = rect; 127 memset(fRadii, 0, sizeof(fRadii)); 128 fType = kRect_Type; 129 130 SkDEBUGCODE(this->validate();) 131 } 132 133 /** 134 * Set this RR to match the supplied oval. All x radii will equal half the 135 * width and all y radii will equal half the height. 136 */ 137 void setOval(const SkRect& oval) { 138 if (oval.isEmpty()) { 139 this->setEmpty(); 140 return; 141 } 142 143 SkScalar xRad = SkScalarHalf(oval.width()); 144 SkScalar yRad = SkScalarHalf(oval.height()); 145 146 fRect = oval; 147 for (int i = 0; i < 4; ++i) { 148 fRadii[i].set(xRad, yRad); 149 } 150 fType = kOval_Type; 151 152 SkDEBUGCODE(this->validate();) 153 } 154 155 /** 156 * Initialize the RR with the same radii for all four corners. 157 */ 158 void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad); 159 160 /** 161 * Initialize the RR with potentially different radii for all four corners. 162 */ 163 void setRectRadii(const SkRect& rect, const SkVector radii[4]); 164 165 // The radii are stored in UL, UR, LR, LL order. 166 enum Corner { 167 kUpperLeft_Corner, 168 kUpperRight_Corner, 169 kLowerRight_Corner, 170 kLowerLeft_Corner 171 }; 172 173 const SkRect& rect() const { return fRect; } 174 const SkVector& radii(Corner corner) const { return fRadii[corner]; } 175 const SkRect& getBounds() const { return fRect; } 176 177 /** 178 * When a rrect is simple, all of its radii are equal. This returns one 179 * of those radii. This call requires the rrect to be non-complex. 180 */ 181 const SkVector& getSimpleRadii() const { 182 SkASSERT(!this->isComplex()); 183 return fRadii[0]; 184 } 185 186 friend bool operator==(const SkRRect& a, const SkRRect& b) { 187 return a.fRect == b.fRect && 188 SkScalarsEqual((SkScalar*) a.fRadii, (SkScalar*) b.fRadii, 8); 189 } 190 191 friend bool operator!=(const SkRRect& a, const SkRRect& b) { 192 return a.fRect != b.fRect || 193 !SkScalarsEqual((SkScalar*) a.fRadii, (SkScalar*) b.fRadii, 8); 194 } 195 196 /** 197 * Returns true if (p.fX,p.fY) is inside the RR, and the RR 198 * is not empty. 199 * 200 * Contains treats the left and top differently from the right and bottom. 201 * The left and top coordinates of the RR are themselves considered 202 * to be inside, while the right and bottom are not. All the points on the 203 * edges of the corners are considered to be inside. 204 */ 205 bool contains(const SkPoint& p) const { 206 return contains(p.fX, p.fY); 207 } 208 209 /** 210 * Returns true if (x,y) is inside the RR, and the RR 211 * is not empty. 212 * 213 * Contains treats the left and top differently from the right and bottom. 214 * The left and top coordinates of the RR are themselves considered 215 * to be inside, while the right and bottom are not. All the points on the 216 * edges of the corners are considered to be inside. 217 */ 218 bool contains(SkScalar x, SkScalar y) const; 219 220 SkDEBUGCODE(void validate() const;) 221 222 enum { 223 kSizeInMemory = 12 * sizeof(SkScalar) 224 }; 225 226 /** 227 * Write the rrect into the specified buffer. This is guaranteed to always 228 * write kSizeInMemory bytes, and that value is guaranteed to always be 229 * a multiple of 4. Return kSizeInMemory. 230 */ 231 uint32_t writeToMemory(void* buffer) const; 232 233 /** 234 * Read the rrect from the specified buffer. This is guaranteed to always 235 * read kSizeInMemory bytes, and that value is guaranteed to always be 236 * a multiple of 4. Return kSizeInMemory. 237 */ 238 uint32_t readFromMemory(const void* buffer); 239 240private: 241 SkRect fRect; 242 // Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[] 243 SkVector fRadii[4]; 244 mutable Type fType; 245 // TODO: add padding so we can use memcpy for flattening and not copy 246 // uninitialized data 247 248 void computeType() const; 249 250 // to access fRadii directly 251 friend class SkPath; 252}; 253 254#endif 255