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