Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright 2012 Google Inc. |
michael@0 | 3 | * |
michael@0 | 4 | * Use of this source code is governed by a BSD-style license that can be |
michael@0 | 5 | * found in the LICENSE file. |
michael@0 | 6 | */ |
michael@0 | 7 | |
michael@0 | 8 | #ifndef SkRRect_DEFINED |
michael@0 | 9 | #define SkRRect_DEFINED |
michael@0 | 10 | |
michael@0 | 11 | #include "SkRect.h" |
michael@0 | 12 | #include "SkPoint.h" |
michael@0 | 13 | |
michael@0 | 14 | class SkPath; |
michael@0 | 15 | class SkMatrix; |
michael@0 | 16 | |
michael@0 | 17 | // Path forward: |
michael@0 | 18 | // core work |
michael@0 | 19 | // add validate method (all radii positive, all radii sums < rect size, etc.) |
michael@0 | 20 | // add contains(SkRect&) - for clip stack |
michael@0 | 21 | // add contains(SkRRect&) - for clip stack |
michael@0 | 22 | // add heart rect computation (max rect inside RR) |
michael@0 | 23 | // add 9patch rect computation |
michael@0 | 24 | // add growToInclude(SkPath&) |
michael@0 | 25 | // analysis |
michael@0 | 26 | // use growToInclude to fit skp round rects & generate stats (RRs vs. real paths) |
michael@0 | 27 | // check on # of rectorus's the RRs could handle |
michael@0 | 28 | // rendering work |
michael@0 | 29 | // update SkPath.addRRect() to only use quads |
michael@0 | 30 | // add GM and bench |
michael@0 | 31 | // further out |
michael@0 | 32 | // detect and triangulate RRectorii rather than falling back to SW in Ganesh |
michael@0 | 33 | // |
michael@0 | 34 | |
michael@0 | 35 | /** \class SkRRect |
michael@0 | 36 | |
michael@0 | 37 | The SkRRect class represents a rounded rect with a potentially different |
michael@0 | 38 | radii for each corner. It does not have a constructor so must be |
michael@0 | 39 | initialized with one of the initialization functions (e.g., setEmpty, |
michael@0 | 40 | setRectRadii, etc.) |
michael@0 | 41 | |
michael@0 | 42 | This class is intended to roughly match CSS' border-*-*-radius capabilities. |
michael@0 | 43 | This means: |
michael@0 | 44 | If either of a corner's radii are 0 the corner will be square. |
michael@0 | 45 | Negative radii are not allowed (they are clamped to zero). |
michael@0 | 46 | If the corner curves overlap they will be proportionally reduced to fit. |
michael@0 | 47 | */ |
michael@0 | 48 | class SK_API SkRRect { |
michael@0 | 49 | public: |
michael@0 | 50 | /** |
michael@0 | 51 | * Enum to capture the various possible subtypes of RR. Accessed |
michael@0 | 52 | * by type(). The subtypes become progressively less restrictive. |
michael@0 | 53 | */ |
michael@0 | 54 | enum Type { |
michael@0 | 55 | // !< Internal indicator that the sub type must be computed. |
michael@0 | 56 | kUnknown_Type = -1, |
michael@0 | 57 | |
michael@0 | 58 | // !< The RR is empty |
michael@0 | 59 | kEmpty_Type, |
michael@0 | 60 | |
michael@0 | 61 | //!< The RR is actually a (non-empty) rect (i.e., at least one radius |
michael@0 | 62 | //!< at each corner is zero) |
michael@0 | 63 | kRect_Type, |
michael@0 | 64 | |
michael@0 | 65 | //!< The RR is actually a (non-empty) oval (i.e., all x radii are equal |
michael@0 | 66 | //!< and >= width/2 and all the y radii are equal and >= height/2 |
michael@0 | 67 | kOval_Type, |
michael@0 | 68 | |
michael@0 | 69 | //!< The RR is non-empty and all the x radii are equal & all y radii |
michael@0 | 70 | //!< are equal but it is not an oval (i.e., there are lines between |
michael@0 | 71 | //!< the curves) nor a rect (i.e., both radii are non-zero) |
michael@0 | 72 | kSimple_Type, |
michael@0 | 73 | |
michael@0 | 74 | //!< A fully general (non-empty) RR. Some of the x and/or y radii are |
michael@0 | 75 | //!< different from the others and there must be one corner where |
michael@0 | 76 | //!< both radii are non-zero. |
michael@0 | 77 | kComplex_Type, |
michael@0 | 78 | }; |
michael@0 | 79 | |
michael@0 | 80 | /** |
michael@0 | 81 | * Returns the RR's sub type. |
michael@0 | 82 | */ |
michael@0 | 83 | Type getType() const { |
michael@0 | 84 | SkDEBUGCODE(this->validate();) |
michael@0 | 85 | |
michael@0 | 86 | if (kUnknown_Type == fType) { |
michael@0 | 87 | this->computeType(); |
michael@0 | 88 | } |
michael@0 | 89 | SkASSERT(kUnknown_Type != fType); |
michael@0 | 90 | return fType; |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | Type type() const { return this->getType(); } |
michael@0 | 94 | |
michael@0 | 95 | inline bool isEmpty() const { return kEmpty_Type == this->getType(); } |
michael@0 | 96 | inline bool isRect() const { return kRect_Type == this->getType(); } |
michael@0 | 97 | inline bool isOval() const { return kOval_Type == this->getType(); } |
michael@0 | 98 | inline bool isSimple() const { return kSimple_Type == this->getType(); } |
michael@0 | 99 | inline bool isSimpleCircular() const { |
michael@0 | 100 | return this->isSimple() && fRadii[0].fX == fRadii[0].fY; |
michael@0 | 101 | } |
michael@0 | 102 | inline bool isComplex() const { return kComplex_Type == this->getType(); } |
michael@0 | 103 | |
michael@0 | 104 | bool allCornersCircular() const; |
michael@0 | 105 | |
michael@0 | 106 | /** |
michael@0 | 107 | * Are both x-radii the same on the two left corners, and similar for the top, right, and |
michael@0 | 108 | * bottom. When this is the case the four ellipse centers form a rectangle. |
michael@0 | 109 | */ |
michael@0 | 110 | bool isNinePatch() const { |
michael@0 | 111 | return fRadii[kUpperLeft_Corner].fX == fRadii[kLowerLeft_Corner].fX && |
michael@0 | 112 | fRadii[kUpperRight_Corner].fX == fRadii[kLowerRight_Corner].fX && |
michael@0 | 113 | fRadii[kUpperLeft_Corner].fY == fRadii[kUpperRight_Corner].fY && |
michael@0 | 114 | fRadii[kLowerLeft_Corner].fY == fRadii[kLowerRight_Corner].fY; |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | SkScalar width() const { return fRect.width(); } |
michael@0 | 118 | SkScalar height() const { return fRect.height(); } |
michael@0 | 119 | |
michael@0 | 120 | /** |
michael@0 | 121 | * Set this RR to the empty rectangle (0,0,0,0) with 0 x & y radii. |
michael@0 | 122 | */ |
michael@0 | 123 | void setEmpty() { |
michael@0 | 124 | fRect.setEmpty(); |
michael@0 | 125 | memset(fRadii, 0, sizeof(fRadii)); |
michael@0 | 126 | fType = kEmpty_Type; |
michael@0 | 127 | |
michael@0 | 128 | SkDEBUGCODE(this->validate();) |
michael@0 | 129 | } |
michael@0 | 130 | |
michael@0 | 131 | /** |
michael@0 | 132 | * Set this RR to match the supplied rect. All radii will be 0. |
michael@0 | 133 | */ |
michael@0 | 134 | void setRect(const SkRect& rect) { |
michael@0 | 135 | if (rect.isEmpty()) { |
michael@0 | 136 | this->setEmpty(); |
michael@0 | 137 | return; |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | fRect = rect; |
michael@0 | 141 | memset(fRadii, 0, sizeof(fRadii)); |
michael@0 | 142 | fType = kRect_Type; |
michael@0 | 143 | |
michael@0 | 144 | SkDEBUGCODE(this->validate();) |
michael@0 | 145 | } |
michael@0 | 146 | |
michael@0 | 147 | /** |
michael@0 | 148 | * Set this RR to match the supplied oval. All x radii will equal half the |
michael@0 | 149 | * width and all y radii will equal half the height. |
michael@0 | 150 | */ |
michael@0 | 151 | void setOval(const SkRect& oval) { |
michael@0 | 152 | if (oval.isEmpty()) { |
michael@0 | 153 | this->setEmpty(); |
michael@0 | 154 | return; |
michael@0 | 155 | } |
michael@0 | 156 | |
michael@0 | 157 | SkScalar xRad = SkScalarHalf(oval.width()); |
michael@0 | 158 | SkScalar yRad = SkScalarHalf(oval.height()); |
michael@0 | 159 | |
michael@0 | 160 | fRect = oval; |
michael@0 | 161 | for (int i = 0; i < 4; ++i) { |
michael@0 | 162 | fRadii[i].set(xRad, yRad); |
michael@0 | 163 | } |
michael@0 | 164 | fType = kOval_Type; |
michael@0 | 165 | |
michael@0 | 166 | SkDEBUGCODE(this->validate();) |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | /** |
michael@0 | 170 | * Initialize the RR with the same radii for all four corners. |
michael@0 | 171 | */ |
michael@0 | 172 | void setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad); |
michael@0 | 173 | |
michael@0 | 174 | /** |
michael@0 | 175 | * Initialize the RR with potentially different radii for all four corners. |
michael@0 | 176 | */ |
michael@0 | 177 | void setRectRadii(const SkRect& rect, const SkVector radii[4]); |
michael@0 | 178 | |
michael@0 | 179 | // The radii are stored in UL, UR, LR, LL order. |
michael@0 | 180 | enum Corner { |
michael@0 | 181 | kUpperLeft_Corner, |
michael@0 | 182 | kUpperRight_Corner, |
michael@0 | 183 | kLowerRight_Corner, |
michael@0 | 184 | kLowerLeft_Corner |
michael@0 | 185 | }; |
michael@0 | 186 | |
michael@0 | 187 | const SkRect& rect() const { return fRect; } |
michael@0 | 188 | const SkVector& radii(Corner corner) const { return fRadii[corner]; } |
michael@0 | 189 | const SkRect& getBounds() const { return fRect; } |
michael@0 | 190 | |
michael@0 | 191 | /** |
michael@0 | 192 | * When a rrect is simple, all of its radii are equal. This returns one |
michael@0 | 193 | * of those radii. This call requires the rrect to be non-complex. |
michael@0 | 194 | */ |
michael@0 | 195 | const SkVector& getSimpleRadii() const { |
michael@0 | 196 | SkASSERT(!this->isComplex()); |
michael@0 | 197 | return fRadii[0]; |
michael@0 | 198 | } |
michael@0 | 199 | |
michael@0 | 200 | friend bool operator==(const SkRRect& a, const SkRRect& b) { |
michael@0 | 201 | return a.fRect == b.fRect && |
michael@0 | 202 | SkScalarsEqual(a.fRadii[0].asScalars(), |
michael@0 | 203 | b.fRadii[0].asScalars(), 8); |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | friend bool operator!=(const SkRRect& a, const SkRRect& b) { |
michael@0 | 207 | return a.fRect != b.fRect || |
michael@0 | 208 | !SkScalarsEqual(a.fRadii[0].asScalars(), |
michael@0 | 209 | b.fRadii[0].asScalars(), 8); |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | /** |
michael@0 | 213 | * Call inset on the bounds, and adjust the radii to reflect what happens |
michael@0 | 214 | * in stroking: If the corner is sharp (no curvature), leave it alone, |
michael@0 | 215 | * otherwise we grow/shrink the radii by the amount of the inset. If a |
michael@0 | 216 | * given radius becomes negative, it is pinned to 0. |
michael@0 | 217 | * |
michael@0 | 218 | * It is valid for dst == this. |
michael@0 | 219 | */ |
michael@0 | 220 | void inset(SkScalar dx, SkScalar dy, SkRRect* dst) const; |
michael@0 | 221 | |
michael@0 | 222 | void inset(SkScalar dx, SkScalar dy) { |
michael@0 | 223 | this->inset(dx, dy, this); |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | /** |
michael@0 | 227 | * Call outset on the bounds, and adjust the radii to reflect what happens |
michael@0 | 228 | * in stroking: If the corner is sharp (no curvature), leave it alone, |
michael@0 | 229 | * otherwise we grow/shrink the radii by the amount of the inset. If a |
michael@0 | 230 | * given radius becomes negative, it is pinned to 0. |
michael@0 | 231 | * |
michael@0 | 232 | * It is valid for dst == this. |
michael@0 | 233 | */ |
michael@0 | 234 | void outset(SkScalar dx, SkScalar dy, SkRRect* dst) const { |
michael@0 | 235 | this->inset(-dx, -dy, dst); |
michael@0 | 236 | } |
michael@0 | 237 | void outset(SkScalar dx, SkScalar dy) { |
michael@0 | 238 | this->inset(-dx, -dy, this); |
michael@0 | 239 | } |
michael@0 | 240 | |
michael@0 | 241 | /** |
michael@0 | 242 | * Translate the rrect by (dx, dy). |
michael@0 | 243 | */ |
michael@0 | 244 | void offset(SkScalar dx, SkScalar dy) { |
michael@0 | 245 | fRect.offset(dx, dy); |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | /** |
michael@0 | 249 | * Returns true if 'rect' is wholy inside the RR, and both |
michael@0 | 250 | * are not empty. |
michael@0 | 251 | */ |
michael@0 | 252 | bool contains(const SkRect& rect) const; |
michael@0 | 253 | |
michael@0 | 254 | SkDEBUGCODE(void validate() const;) |
michael@0 | 255 | |
michael@0 | 256 | enum { |
michael@0 | 257 | kSizeInMemory = 12 * sizeof(SkScalar) |
michael@0 | 258 | }; |
michael@0 | 259 | |
michael@0 | 260 | /** |
michael@0 | 261 | * Write the rrect into the specified buffer. This is guaranteed to always |
michael@0 | 262 | * write kSizeInMemory bytes, and that value is guaranteed to always be |
michael@0 | 263 | * a multiple of 4. Return kSizeInMemory. |
michael@0 | 264 | */ |
michael@0 | 265 | size_t writeToMemory(void* buffer) const; |
michael@0 | 266 | |
michael@0 | 267 | /** |
michael@0 | 268 | * Reads the rrect from the specified buffer |
michael@0 | 269 | * |
michael@0 | 270 | * If the specified buffer is large enough, this will read kSizeInMemory bytes, |
michael@0 | 271 | * and that value is guaranteed to always be a multiple of 4. |
michael@0 | 272 | * |
michael@0 | 273 | * @param buffer Memory to read from |
michael@0 | 274 | * @param length Amount of memory available in the buffer |
michael@0 | 275 | * @return number of bytes read (must be a multiple of 4) or |
michael@0 | 276 | * 0 if there was not enough memory available |
michael@0 | 277 | */ |
michael@0 | 278 | size_t readFromMemory(const void* buffer, size_t length); |
michael@0 | 279 | |
michael@0 | 280 | /** |
michael@0 | 281 | * Transform by the specified matrix, and put the result in dst. |
michael@0 | 282 | * |
michael@0 | 283 | * @param matrix SkMatrix specifying the transform. Must only contain |
michael@0 | 284 | * scale and/or translate, or this call will fail. |
michael@0 | 285 | * @param dst SkRRect to store the result. It is an error to use this, |
michael@0 | 286 | * which would make this function no longer const. |
michael@0 | 287 | * @return true on success, false on failure. If false, dst is unmodified. |
michael@0 | 288 | */ |
michael@0 | 289 | bool transform(const SkMatrix& matrix, SkRRect* dst) const; |
michael@0 | 290 | |
michael@0 | 291 | private: |
michael@0 | 292 | SkRect fRect; |
michael@0 | 293 | // Radii order is UL, UR, LR, LL. Use Corner enum to index into fRadii[] |
michael@0 | 294 | SkVector fRadii[4]; |
michael@0 | 295 | mutable Type fType; |
michael@0 | 296 | // TODO: add padding so we can use memcpy for flattening and not copy |
michael@0 | 297 | // uninitialized data |
michael@0 | 298 | |
michael@0 | 299 | void computeType() const; |
michael@0 | 300 | bool checkCornerContainment(SkScalar x, SkScalar y) const; |
michael@0 | 301 | |
michael@0 | 302 | // to access fRadii directly |
michael@0 | 303 | friend class SkPath; |
michael@0 | 304 | }; |
michael@0 | 305 | |
michael@0 | 306 | #endif |