blob: 91b3a2e75a8ee4f0547f835e351a2be8496d974c [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 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
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#ifndef SkRegionPriv_DEFINED
11#define SkRegionPriv_DEFINED
12
13#include "SkRegion.h"
14#include "SkThread.h"
15
16#define assert_sentinel(value, isSentinel) \
17 SkASSERT(((value) == SkRegion::kRunTypeSentinel) == isSentinel)
18
19//SkDEBUGCODE(extern int32_t gRgnAllocCounter;)
20
reed@google.com9c36a762012-05-02 18:07:33 +000021#ifdef SK_DEBUG
22// Given the first interval (just past the interval-count), compute the
23// interval count, by search for the x-sentinel
24//
25static int compute_intervalcount(const SkRegion::RunType runs[]) {
26 const SkRegion::RunType* curr = runs;
27 while (*curr < SkRegion::kRunTypeSentinel) {
28 SkASSERT(curr[0] < curr[1]);
29 SkASSERT(curr[1] < SkRegion::kRunTypeSentinel);
30 curr += 2;
31 }
32 return (curr - runs) >> 1;
33}
34#endif
35
reed@android.com8a1c16f2008-12-17 15:59:43 +000036struct SkRegion::RunHead {
reed@google.com9c36a762012-05-02 18:07:33 +000037private:
38
39public:
reed@android.com8a1c16f2008-12-17 15:59:43 +000040 int32_t fRefCnt;
41 int32_t fRunCount;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000042
reed@google.comaf7e6942012-05-01 14:43:22 +000043 /**
44 * Number of spans with different Y values. This does not count the initial
45 * Top value, nor does it count the final Y-Sentinel value. In the logical
46 * case of a rectangle, this would return 1, and an empty region would
47 * return 0.
48 */
49 int getYSpanCount() const {
50 return fYSpanCount;
51 }
52
53 /**
54 * Number of intervals in the entire region. This equals the number of
55 * rects that would be returned by the Iterator. In the logical case of
56 * a rect, this would return 1, and an empty region would return 0.
57 */
58 int getIntervalCount() const {
59 return fIntervalCount;
60 }
61
reed@google.coma95ea2c2012-04-30 16:35:25 +000062 static RunHead* Alloc(int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000063 //SkDEBUGCODE(sk_atomic_inc(&gRgnAllocCounter);)
64 //SkDEBUGF(("************** gRgnAllocCounter::alloc %d\n", gRgnAllocCounter));
rmistry@google.comfbfcd562012-08-23 18:09:54 +000065
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 SkASSERT(count >= SkRegion::kRectRegionRuns);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000067
reed@android.com8a1c16f2008-12-17 15:59:43 +000068 RunHead* head = (RunHead*)sk_malloc_throw(sizeof(RunHead) + count * sizeof(RunType));
69 head->fRefCnt = 1;
70 head->fRunCount = count;
reed@google.comaf7e6942012-05-01 14:43:22 +000071 // these must be filled in later, otherwise we will be invalid
72 head->fYSpanCount = 0;
73 head->fIntervalCount = 0;
74 return head;
75 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000076
reed@google.comaf7e6942012-05-01 14:43:22 +000077 static RunHead* Alloc(int count, int yspancount, int intervalCount) {
78 SkASSERT(yspancount > 0);
79 SkASSERT(intervalCount > 1);
80
81 RunHead* head = Alloc(count);
82 head->fYSpanCount = yspancount;
83 head->fIntervalCount = intervalCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 return head;
85 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000086
reed@google.coma95ea2c2012-04-30 16:35:25 +000087 bool isComplex() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000088 return this != SkRegion_gEmptyRunHeadPtr && this != SkRegion_gRectRunHeadPtr;
89 }
90
reed@google.coma95ea2c2012-04-30 16:35:25 +000091 SkRegion::RunType* writable_runs() {
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 SkASSERT(this->isComplex());
93 SkASSERT(fRefCnt == 1);
94 return (SkRegion::RunType*)(this + 1);
95 }
reed@google.coma95ea2c2012-04-30 16:35:25 +000096
97 const SkRegion::RunType* readonly_runs() const {
reed@android.com8a1c16f2008-12-17 15:59:43 +000098 SkASSERT(this->isComplex());
99 return (const SkRegion::RunType*)(this + 1);
100 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000101
reed@google.coma95ea2c2012-04-30 16:35:25 +0000102 RunHead* ensureWritable() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 SkASSERT(this->isComplex());
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000104
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 RunHead* writable = this;
reed@google.coma95ea2c2012-04-30 16:35:25 +0000106 if (fRefCnt > 1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 // We need to alloc & copy the current region before we call
108 // sk_atomic_dec because it could be freed in the meantime,
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000109 // otherwise.
reed@google.comaf7e6942012-05-01 14:43:22 +0000110 writable = Alloc(fRunCount, fYSpanCount, fIntervalCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000111 memcpy(writable->writable_runs(), this->readonly_runs(),
112 fRunCount * sizeof(RunType));
113
114 // fRefCount might have changed since we last checked.
115 // If we own the last reference at this point, we need to
116 // free the memory.
reed@google.coma95ea2c2012-04-30 16:35:25 +0000117 if (sk_atomic_dec(&fRefCnt) == 1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 sk_free(this);
119 }
120 }
121 return writable;
122 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000123
reed@google.com9c36a762012-05-02 18:07:33 +0000124 /**
125 * Given a scanline (including its Bottom value at runs[0]), return the next
126 * scanline. Asserts that there is one (i.e. runs[0] < Sentinel)
127 */
128 static SkRegion::RunType* SkipEntireScanline(const SkRegion::RunType runs[]) {
129 // we are not the Y Sentinel
130 SkASSERT(runs[0] < SkRegion::kRunTypeSentinel);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000131
reed@google.com9c36a762012-05-02 18:07:33 +0000132 const int intervals = runs[1];
133 SkASSERT(runs[2 + intervals * 2] == SkRegion::kRunTypeSentinel);
134#ifdef SK_DEBUG
135 {
136 int n = compute_intervalcount(&runs[2]);
137 SkASSERT(n == intervals);
138 }
139#endif
140
141 // skip the entire line [B N [L R] S]
142 runs += 1 + 1 + intervals * 2 + 1;
143 return const_cast<SkRegion::RunType*>(runs);
144 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000145
146
reed@google.com9c36a762012-05-02 18:07:33 +0000147 /**
148 * Return the scanline that contains the Y value. This requires that the Y
149 * value is already known to be contained within the bounds of the region,
150 * and so this routine never returns NULL.
151 *
152 * It returns the beginning of the scanline, starting with its Bottom value.
153 */
154 SkRegion::RunType* findScanline(int y) const {
155 const RunType* runs = this->readonly_runs();
156
157 // if the top-check fails, we didn't do a quick check on the bounds
158 SkASSERT(y >= runs[0]);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000159
reed@google.com9c36a762012-05-02 18:07:33 +0000160 runs += 1; // skip top-Y
161 for (;;) {
162 int bottom = runs[0];
163 // If we hit this, we've walked off the region, and our bounds check
164 // failed.
165 SkASSERT(bottom < SkRegion::kRunTypeSentinel);
166 if (y < bottom) {
167 break;
168 }
169 runs = SkipEntireScanline(runs);
170 }
171 return const_cast<SkRegion::RunType*>(runs);
172 }
173
174 // Copy src runs into us, computing interval counts and bounds along the way
175 void computeRunBounds(SkIRect* bounds) {
176 RunType* runs = this->writable_runs();
177 bounds->fTop = *runs++;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000178
reed@google.com9c36a762012-05-02 18:07:33 +0000179 int bot;
180 int ySpanCount = 0;
181 int intervalCount = 0;
182 int left = SK_MaxS32;
183 int rite = SK_MinS32;
184
185 do {
186 bot = *runs++;
187 SkASSERT(bot < SkRegion::kRunTypeSentinel);
188 ySpanCount += 1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000189
reed@google.com9c36a762012-05-02 18:07:33 +0000190 const int intervals = *runs++;
191 SkASSERT(intervals >= 0);
192 SkASSERT(intervals < SkRegion::kRunTypeSentinel);
193
194 if (intervals > 0) {
195#ifdef SK_DEBUG
196 {
197 int n = compute_intervalcount(runs);
198 SkASSERT(n == intervals);
199 }
200#endif
201 RunType L = runs[0];
202 SkASSERT(L < SkRegion::kRunTypeSentinel);
203 if (left > L) {
204 left = L;
205 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000206
reed@google.com9c36a762012-05-02 18:07:33 +0000207 runs += intervals * 2;
208 RunType R = runs[-1];
209 SkASSERT(R < SkRegion::kRunTypeSentinel);
210 if (rite < R) {
211 rite = R;
212 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000213
reed@google.com9c36a762012-05-02 18:07:33 +0000214 intervalCount += intervals;
215 }
216 SkASSERT(SkRegion::kRunTypeSentinel == *runs);
217 runs += 1; // skip x-sentinel
218
219 // test Y-sentinel
220 } while (SkRegion::kRunTypeSentinel > *runs);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000221
reed@google.com9c36a762012-05-02 18:07:33 +0000222#ifdef SK_DEBUG
223 // +1 to skip the last Y-sentinel
224 int runCount = runs - this->writable_runs() + 1;
225 SkASSERT(runCount == fRunCount);
226#endif
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000227
reed@google.com9c36a762012-05-02 18:07:33 +0000228 fYSpanCount = ySpanCount;
229 fIntervalCount = intervalCount;
230
231 bounds->fLeft = left;
232 bounds->fRight = rite;
233 bounds->fBottom = bot;
234 }
reed@google.comaf7e6942012-05-01 14:43:22 +0000235
236private:
237 int32_t fYSpanCount;
238 int32_t fIntervalCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239};
240
241#endif