Line data Source code
1 :
2 : /*
3 : * Copyright 2005 The Android Open Source Project
4 : *
5 : * Use of this source code is governed by a BSD-style license that can be
6 : * found in the LICENSE file.
7 : */
8 :
9 :
10 : #ifndef SkRegion_DEFINED
11 : #define SkRegion_DEFINED
12 :
13 : #include "SkRect.h"
14 :
15 : class SkPath;
16 : class SkRgnBuilder;
17 :
18 : namespace android {
19 : class Region;
20 : }
21 :
22 : #define SkRegion_gEmptyRunHeadPtr ((SkRegion::RunHead*)-1)
23 : #define SkRegion_gRectRunHeadPtr 0
24 :
25 : /** \class SkRegion
26 :
27 : The SkRegion class encapsulates the geometric region used to specify
28 : clipping areas for drawing.
29 : */
30 : class SK_API SkRegion {
31 : public:
32 : typedef int32_t RunType;
33 : enum {
34 : kRunTypeSentinel = 0x7FFFFFFF
35 : };
36 :
37 : SkRegion();
38 : SkRegion(const SkRegion&);
39 : explicit SkRegion(const SkIRect&);
40 : ~SkRegion();
41 :
42 : SkRegion& operator=(const SkRegion&);
43 :
44 : /**
45 : * Return true if the two regions are equal. i.e. The enclose exactly
46 : * the same area.
47 : */
48 : bool operator==(const SkRegion& other) const;
49 :
50 : /**
51 : * Return true if the two regions are not equal.
52 : */
53 : bool operator!=(const SkRegion& other) const {
54 : return !(*this == other);
55 : }
56 :
57 : /**
58 : * Replace this region with the specified region, and return true if the
59 : * resulting region is non-empty.
60 : */
61 0 : bool set(const SkRegion& src) {
62 0 : *this = src;
63 0 : return !this->isEmpty();
64 : }
65 :
66 : /**
67 : * Swap the contents of this and the specified region. This operation
68 : * is gauarenteed to never fail.
69 : */
70 : void swap(SkRegion&);
71 :
72 : /** Return true if this region is empty */
73 15526 : bool isEmpty() const { return fRunHead == SkRegion_gEmptyRunHeadPtr; }
74 :
75 : /** Return true if this region is a single, non-empty rectangle */
76 12059 : bool isRect() const { return fRunHead == SkRegion_gRectRunHeadPtr; }
77 :
78 : /** Return true if this region consists of more than 1 rectangular area */
79 3958 : bool isComplex() const { return !this->isEmpty() && !this->isRect(); }
80 :
81 : /**
82 : * Return the bounds of this region. If the region is empty, returns an
83 : * empty rectangle.
84 : */
85 2857 : const SkIRect& getBounds() const { return fBounds; }
86 :
87 : /**
88 : * Returns a value that grows approximately linearly with the number of
89 : * intervals comprised in the region. Empty region will return 0, Rect
90 : * will return 1, Complex will return a value > 1.
91 : *
92 : * Use this to compare two regions, where the larger count likely
93 : * indicates a more complex region.
94 : */
95 : int computeRegionComplexity() const;
96 :
97 : /**
98 : * Returns true if the region is non-empty, and if so, appends the
99 : * boundary(s) of the region to the specified path.
100 : * If the region is empty, returns false, and path is left unmodified.
101 : */
102 : bool getBoundaryPath(SkPath* path) const;
103 :
104 : /**
105 : * Set the region to be empty, and return false, since the resulting
106 : * region is empty
107 : */
108 : bool setEmpty();
109 :
110 : /**
111 : * If rect is non-empty, set this region to that rectangle and return true,
112 : * otherwise set this region to empty and return false.
113 : */
114 : bool setRect(const SkIRect&);
115 :
116 : /**
117 : * If left < right and top < bottom, set this region to that rectangle and
118 : * return true, otherwise set this region to empty and return false.
119 : */
120 : bool setRect(int32_t left, int32_t top, int32_t right, int32_t bottom);
121 :
122 : /**
123 : * Set this region to the union of an array of rects. This is generally
124 : * faster than calling region.op(rect, kUnion_Op) in a loop. If count is
125 : * 0, then this region is set to the empty region.
126 : * @return true if the resulting region is non-empty
127 : */
128 : bool setRects(const SkIRect rects[], int count);
129 :
130 : /**
131 : * Set this region to the specified region, and return true if it is
132 : * non-empty.
133 : */
134 : bool setRegion(const SkRegion&);
135 :
136 : /**
137 : * Set this region to the area described by the path, clipped.
138 : * Return true if the resulting region is non-empty.
139 : * This produces a region that is identical to the pixels that would be
140 : * drawn by the path (with no antialiasing) with the specified clip.
141 : */
142 : bool setPath(const SkPath&, const SkRegion& clip);
143 :
144 : /**
145 : * Returns true if the specified rectangle has a non-empty intersection
146 : * with this region.
147 : */
148 : bool intersects(const SkIRect&) const;
149 :
150 : /**
151 : * Returns true if the specified region has a non-empty intersection
152 : * with this region.
153 : */
154 : bool intersects(const SkRegion&) const;
155 :
156 : /**
157 : * Return true if the specified x,y coordinate is inside the region.
158 : */
159 : bool contains(int32_t x, int32_t y) const;
160 :
161 : /**
162 : * Return true if the specified rectangle is completely inside the region.
163 : * This works for simple (rectangular) and complex regions, and always
164 : * returns the correct result. Note: if either this region or the rectangle
165 : * is empty, contains() returns false.
166 : */
167 : bool contains(const SkIRect&) const;
168 :
169 : /**
170 : * Return true if the specified region is completely inside the region.
171 : * This works for simple (rectangular) and complex regions, and always
172 : * returns the correct result. Note: if either region is empty, contains()
173 : * returns false.
174 : */
175 : bool contains(const SkRegion&) const;
176 :
177 : /**
178 : * Return true if this region is a single rectangle (not complex) and the
179 : * specified rectangle is contained by this region. Returning false is not
180 : * a guarantee that the rectangle is not contained by this region, but
181 : * return true is a guarantee that the rectangle is contained by this region.
182 : */
183 0 : bool quickContains(const SkIRect& r) const {
184 0 : return this->quickContains(r.fLeft, r.fTop, r.fRight, r.fBottom);
185 : }
186 :
187 : /**
188 : * Return true if this region is a single rectangle (not complex) and the
189 : * specified rectangle is contained by this region. Returning false is not
190 : * a guarantee that the rectangle is not contained by this region, but
191 : * return true is a guarantee that the rectangle is contained by this
192 : * region.
193 : */
194 0 : bool quickContains(int32_t left, int32_t top, int32_t right,
195 : int32_t bottom) const {
196 0 : SkASSERT(this->isEmpty() == fBounds.isEmpty()); // valid region
197 :
198 0 : return left < right && top < bottom &&
199 0 : fRunHead == SkRegion_gRectRunHeadPtr && // this->isRect()
200 : /* fBounds.contains(left, top, right, bottom); */
201 0 : fBounds.fLeft <= left && fBounds.fTop <= top &&
202 0 : fBounds.fRight >= right && fBounds.fBottom >= bottom;
203 : }
204 :
205 : /**
206 : * Return true if this region is empty, or if the specified rectangle does
207 : * not intersect the region. Returning false is not a guarantee that they
208 : * intersect, but returning true is a guarantee that they do not.
209 : */
210 4 : bool quickReject(const SkIRect& rect) const {
211 8 : return this->isEmpty() || rect.isEmpty() ||
212 8 : !SkIRect::Intersects(fBounds, rect);
213 : }
214 :
215 : /**
216 : * Return true if this region, or rgn, is empty, or if their bounds do not
217 : * intersect. Returning false is not a guarantee that they intersect, but
218 : * returning true is a guarantee that they do not.
219 : */
220 : bool quickReject(const SkRegion& rgn) const {
221 : return this->isEmpty() || rgn.isEmpty() ||
222 : !SkIRect::Intersects(fBounds, rgn.fBounds);
223 : }
224 :
225 : /** Translate the region by the specified (dx, dy) amount. */
226 0 : void translate(int dx, int dy) { this->translate(dx, dy, this); }
227 :
228 : /**
229 : * Translate the region by the specified (dx, dy) amount, writing the
230 : * resulting region into dst. Note: it is legal to pass this region as the
231 : * dst parameter, effectively translating the region in place. If dst is
232 : * null, nothing happens.
233 : */
234 : void translate(int dx, int dy, SkRegion* dst) const;
235 :
236 : /**
237 : * The logical operations that can be performed when combining two regions.
238 : */
239 : enum Op {
240 : kDifference_Op, //!< subtract the op region from the first region
241 : kIntersect_Op, //!< intersect the two regions
242 : kUnion_Op, //!< union (inclusive-or) the two regions
243 : kXOR_Op, //!< exclusive-or the two regions
244 : /** subtract the first region from the op region */
245 : kReverseDifference_Op,
246 : kReplace_Op, //!< replace the dst region with the op region
247 :
248 : kLastOp = kReplace_Op
249 : };
250 :
251 : static const int kOpCnt = kLastOp + 1;
252 :
253 : /**
254 : * Set this region to the result of applying the Op to this region and the
255 : * specified rectangle: this = (this op rect).
256 : * Return true if the resulting region is non-empty.
257 : */
258 659 : bool op(const SkIRect& rect, Op op) {
259 659 : if (this->isRect() && kIntersect_Op == op) {
260 532 : if (!fBounds.intersect(rect)) {
261 13 : return this->setEmpty();
262 : }
263 519 : return true;
264 : }
265 127 : return this->op(*this, rect, op);
266 : }
267 :
268 : /**
269 : * Set this region to the result of applying the Op to this region and the
270 : * specified rectangle: this = (this op rect).
271 : * Return true if the resulting region is non-empty.
272 : */
273 : bool op(int left, int top, int right, int bottom, Op op) {
274 : SkIRect rect;
275 : rect.set(left, top, right, bottom);
276 : return this->op(*this, rect, op);
277 : }
278 :
279 : /**
280 : * Set this region to the result of applying the Op to this region and the
281 : * specified region: this = (this op rgn).
282 : * Return true if the resulting region is non-empty.
283 : */
284 24 : bool op(const SkRegion& rgn, Op op) { return this->op(*this, rgn, op); }
285 :
286 : /**
287 : * Set this region to the result of applying the Op to the specified
288 : * rectangle and region: this = (rect op rgn).
289 : * Return true if the resulting region is non-empty.
290 : */
291 : bool op(const SkIRect& rect, const SkRegion& rgn, Op);
292 :
293 : /**
294 : * Set this region to the result of applying the Op to the specified
295 : * region and rectangle: this = (rgn op rect).
296 : * Return true if the resulting region is non-empty.
297 : */
298 : bool op(const SkRegion& rgn, const SkIRect& rect, Op);
299 :
300 : /**
301 : * Set this region to the result of applying the Op to the specified
302 : * regions: this = (rgna op rgnb).
303 : * Return true if the resulting region is non-empty.
304 : */
305 : bool op(const SkRegion& rgna, const SkRegion& rgnb, Op op);
306 :
307 : #ifdef SK_BUILD_FOR_ANDROID
308 : /** Returns a new char* containing the list of rectangles in this region
309 : */
310 : char* toString();
311 : #endif
312 :
313 : /**
314 : * Returns the sequence of rectangles, sorted in Y and X, that make up
315 : * this region.
316 : */
317 : class SK_API Iterator {
318 : public:
319 : Iterator() : fRgn(NULL), fDone(true) {}
320 : Iterator(const SkRegion&);
321 : // if we have a region, reset to it and return true, else return false
322 : bool rewind();
323 : // reset the iterator, using the new region
324 : void reset(const SkRegion&);
325 125 : bool done() const { return fDone; }
326 : void next();
327 94 : const SkIRect& rect() const { return fRect; }
328 : // may return null
329 : const SkRegion* rgn() const { return fRgn; }
330 :
331 : private:
332 : const SkRegion* fRgn;
333 : const RunType* fRuns;
334 : SkIRect fRect;
335 : bool fDone;
336 : };
337 :
338 : /**
339 : * Returns the sequence of rectangles, sorted in Y and X, that make up
340 : * this region intersected with the specified clip rectangle.
341 : */
342 : class SK_API Cliperator {
343 : public:
344 : Cliperator(const SkRegion&, const SkIRect& clip);
345 77 : bool done() { return fDone; }
346 : void next();
347 53 : const SkIRect& rect() const { return fRect; }
348 :
349 : private:
350 : Iterator fIter;
351 : SkIRect fClip;
352 : SkIRect fRect;
353 : bool fDone;
354 : };
355 :
356 : /**
357 : * Returns the sequence of runs that make up this region for the specified
358 : * Y scanline, clipped to the specified left and right X values.
359 : */
360 : class Spanerator {
361 : public:
362 : Spanerator(const SkRegion&, int y, int left, int right);
363 : bool next(int* left, int* right);
364 :
365 : private:
366 : const SkRegion::RunType* fRuns;
367 : int fLeft, fRight;
368 : bool fDone;
369 : };
370 :
371 : /**
372 : * Write the region to the buffer, and return the number of bytes written.
373 : * If buffer is NULL, it still returns the number of bytes.
374 : */
375 : size_t writeToMemory(void* buffer) const;
376 : /**
377 : * Initializes the region from the buffer
378 : *
379 : * @param buffer Memory to read from
380 : * @param length Amount of memory available in the buffer
381 : * @return number of bytes read (must be a multiple of 4) or
382 : * 0 if there was not enough memory available
383 : */
384 : size_t readFromMemory(const void* buffer, size_t length);
385 :
386 : /**
387 : * Returns a reference to a global empty region. Just a convenience for
388 : * callers that need a const empty region.
389 : */
390 : static const SkRegion& GetEmptyRegion();
391 :
392 : SkDEBUGCODE(void dump() const;)
393 : SkDEBUGCODE(void validate() const;)
394 : SkDEBUGCODE(static void UnitTest();)
395 :
396 : // expose this to allow for regression test on complex regions
397 : SkDEBUGCODE(bool debugSetRuns(const RunType runs[], int count);)
398 :
399 : private:
400 : enum {
401 : kOpCount = kReplace_Op + 1
402 : };
403 :
404 : enum {
405 : // T
406 : // [B N L R S]
407 : // S
408 : kRectRegionRuns = 7
409 : };
410 :
411 : friend class android::Region; // needed for marshalling efficiently
412 :
413 : struct RunHead;
414 :
415 : // allocate space for count runs
416 : void allocateRuns(int count);
417 : void allocateRuns(int count, int ySpanCount, int intervalCount);
418 : void allocateRuns(const RunHead& src);
419 :
420 : SkIRect fBounds;
421 : RunHead* fRunHead;
422 :
423 : void freeRuns();
424 :
425 : /**
426 : * Return the runs from this region, consing up fake runs if the region
427 : * is empty or a rect. In those 2 cases, we use tmpStorage to hold the
428 : * run data.
429 : */
430 : const RunType* getRuns(RunType tmpStorage[], int* intervals) const;
431 :
432 : // This is called with runs[] that do not yet have their interval-count
433 : // field set on each scanline. That is computed as part of this call
434 : // (inside ComputeRunBounds).
435 : bool setRuns(RunType runs[], int count);
436 :
437 : int count_runtype_values(int* itop, int* ibot) const;
438 :
439 : bool isValid() const;
440 :
441 : static void BuildRectRuns(const SkIRect& bounds,
442 : RunType runs[kRectRegionRuns]);
443 :
444 : // If the runs define a simple rect, return true and set bounds to that
445 : // rect. If not, return false and ignore bounds.
446 : static bool RunsAreARect(const SkRegion::RunType runs[], int count,
447 : SkIRect* bounds);
448 :
449 : /**
450 : * If the last arg is null, just return if the result is non-empty,
451 : * else store the result in the last arg.
452 : */
453 : static bool Oper(const SkRegion&, const SkRegion&, SkRegion::Op, SkRegion*);
454 :
455 : friend struct RunHead;
456 : friend class Iterator;
457 : friend class Spanerator;
458 : friend class SkRgnBuilder;
459 : friend class SkFlatRegion;
460 : };
461 :
462 : #endif
|