OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkScanPriv.h" | 8 #include "SkScanPriv.h" |
9 #include "SkBlitter.h" | 9 #include "SkBlitter.h" |
10 #include "SkEdge.h" | 10 #include "SkEdge.h" |
11 #include "SkEdgeBuilder.h" | 11 #include "SkEdgeBuilder.h" |
12 #include "SkGeometry.h" | 12 #include "SkGeometry.h" |
13 #include "SkPath.h" | 13 #include "SkPath.h" |
14 #include "SkQuadClipper.h" | 14 #include "SkQuadClipper.h" |
15 #include "SkRasterClip.h" | 15 #include "SkRasterClip.h" |
16 #include "SkRegion.h" | 16 #include "SkRegion.h" |
| 17 #include "SkStroke.h" |
17 #include "SkTemplates.h" | 18 #include "SkTemplates.h" |
18 #include "SkTSort.h" | 19 #include "SkTSort.h" |
19 | 20 |
| 21 #include <stdio.h> // FIXME |
| 22 |
| 23 static bool dumping; |
| 24 |
20 #define kEDGE_HEAD_Y SK_MinS32 | 25 #define kEDGE_HEAD_Y SK_MinS32 |
21 #define kEDGE_TAIL_Y SK_MaxS32 | 26 #define kEDGE_TAIL_Y SK_MaxS32 |
22 | 27 |
23 #ifdef SK_DEBUG | 28 #ifdef SK_DEBUG |
24 static void validate_sort(const SkEdge* edge) { | 29 static void validate_sort(const SkEdge* edge) { |
25 int y = kEDGE_HEAD_Y; | 30 int y = kEDGE_HEAD_Y; |
26 | 31 |
27 while (edge->fFirstY != SK_MaxS32) { | 32 while (edge->fFirstY != SK_MaxS32) { |
28 edge->validate(); | 33 edge->validate(); |
29 SkASSERT(y <= edge->fFirstY); | 34 SkASSERT(y <= edge->fFirstY); |
(...skipping 11 matching lines...) Expand all Loading... |
41 edge->fNext->fPrev = edge->fPrev; | 46 edge->fNext->fPrev = edge->fPrev; |
42 } | 47 } |
43 | 48 |
44 static inline void insert_edge_after(SkEdge* edge, SkEdge* afterMe) { | 49 static inline void insert_edge_after(SkEdge* edge, SkEdge* afterMe) { |
45 edge->fPrev = afterMe; | 50 edge->fPrev = afterMe; |
46 edge->fNext = afterMe->fNext; | 51 edge->fNext = afterMe->fNext; |
47 afterMe->fNext->fPrev = edge; | 52 afterMe->fNext->fPrev = edge; |
48 afterMe->fNext = edge; | 53 afterMe->fNext = edge; |
49 } | 54 } |
50 | 55 |
| 56 static void emit_wireframe_triangle(SkPoint t[3], SkTDArray<SkPoint>* points) { |
| 57 SkPoint *p = points->append(6); |
| 58 p[0] = t[0]; |
| 59 p[1] = t[1]; |
| 60 p[2] = t[1]; |
| 61 p[3] = t[2]; |
| 62 p[4] = t[2]; |
| 63 p[5] = t[0]; |
| 64 } |
| 65 |
| 66 static void emit_trapezoid(SkEdge* left, SkEdge* right, float top, float bottom,
SkTDArray<SkPoint>* points) |
| 67 { |
| 68 // If this edge was already neutered by its partner, don't emit. |
| 69 if (top > bottom) { |
| 70 return; |
| 71 } |
| 72 |
| 73 if (!left || !right) { |
| 74 return; |
| 75 } |
| 76 |
| 77 float top_left = left->fFirstXf; |
| 78 float top_right = right->fFirstXf; |
| 79 float bottom_left = left->fFirstXf + SkFixedToFloat(left->fDX * (bottom - to
p)); |
| 80 float bottom_right = right->fFirstXf + SkFixedToFloat(right->fDX * (bottom -
top)); |
| 81 if (dumping) { |
| 82 printf("top %g bot %g tl %g tr %g bl %g br %g\n", |
| 83 top, bottom, left->fFirstXf, right->fFirstXf, bottom_left, bottom
_right); |
| 84 } |
| 85 if (SkScan::gWireframe) { |
| 86 if (top_left == top_right) { |
| 87 SkPoint p[3]; |
| 88 p[0] = SkPoint::Make(top_right, top); |
| 89 p[1] = SkPoint::Make(bottom_right, bottom); |
| 90 p[2] = SkPoint::Make(bottom_left , bottom); |
| 91 emit_wireframe_triangle(p, points); |
| 92 } else if (bottom_left == bottom_right) { |
| 93 SkPoint p[3]; |
| 94 p[0] = SkPoint::Make(top_left, top); |
| 95 p[1] = SkPoint::Make(top_right, top); |
| 96 p[2] = SkPoint::Make(bottom_left, bottom); |
| 97 emit_wireframe_triangle(p, points); |
| 98 } else { |
| 99 SkPoint p[3]; |
| 100 p[0] = SkPoint::Make(top_left, top); |
| 101 p[1] = SkPoint::Make(top_right, top); |
| 102 p[2] = SkPoint::Make(bottom_left , bottom); |
| 103 emit_wireframe_triangle(p, points); |
| 104 p[0] = SkPoint::Make(top_right, top); |
| 105 p[1] = SkPoint::Make(bottom_right, bottom); |
| 106 p[2] = SkPoint::Make(bottom_left , bottom); |
| 107 emit_wireframe_triangle(p, points); |
| 108 } |
| 109 } else { |
| 110 if (top_left == top_right) { |
| 111 SkPoint *p = points->append(3); |
| 112 p[0] = SkPoint::Make(top_right, top); |
| 113 p[1] = SkPoint::Make(bottom_right, bottom); |
| 114 p[2] = SkPoint::Make(bottom_left , bottom); |
| 115 } else if (bottom_left == bottom_right) { |
| 116 SkPoint *p = points->append(3); |
| 117 p[0] = SkPoint::Make(top_left, top); |
| 118 p[1] = SkPoint::Make(top_right, top); |
| 119 p[2] = SkPoint::Make(bottom_left, bottom); |
| 120 } else { |
| 121 SkPoint *p = points->append(6); |
| 122 p[0] = SkPoint::Make(top_left, top); |
| 123 p[1] = SkPoint::Make(top_right, top); |
| 124 p[2] = SkPoint::Make(bottom_left , bottom); |
| 125 p[3] = SkPoint::Make(top_right, top); |
| 126 p[4] = SkPoint::Make(bottom_right, bottom); |
| 127 p[5] = SkPoint::Make(bottom_left , bottom); |
| 128 } |
| 129 } |
| 130 left->fFirstXf = bottom_left; |
| 131 left->fFirstYf = bottom; |
| 132 right->fFirstXf = bottom_right; |
| 133 right->fFirstYf = bottom; |
| 134 } |
| 135 |
| 136 static void emit_all_trapezoids(SkEdge* start, int windingMask, int curr_y, SkTD
Array<SkPoint>* points) |
| 137 { |
| 138 int w = 0; |
| 139 SkEdge* left = NULL; |
| 140 for (SkEdge* edge = start; edge != NULL && edge->fFirstY < curr_y && edge->f
FirstYf < curr_y; edge = edge->fNext) { |
| 141 w += edge->fWinding; |
| 142 if ((w & windingMask) == 0) { |
| 143 SkASSERT(left); |
| 144 emit_trapezoid(left, edge, left->fFirstYf, curr_y, points); |
| 145 left = NULL; |
| 146 } else if (!left) { |
| 147 left = edge; |
| 148 } else { |
| 149 edge->fFirstXf += SkFixedToFloat(edge->fDX * (curr_y - edge->fFirstY
f)); |
| 150 edge->fFirstYf = (float) curr_y; |
| 151 } |
| 152 } |
| 153 } |
| 154 |
51 static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, cur
r_y)) { | 155 static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, cur
r_y)) { |
52 SkFixed x = edge->fX; | 156 SkFixed x = edge->fX; |
53 | 157 |
54 SkEdge* prev = edge->fPrev; | 158 SkEdge* prev = edge->fPrev; |
55 while (prev->fX > x) { | 159 while (prev->fX > x) { |
56 prev = prev->fPrev; | 160 prev = prev->fPrev; |
57 } | 161 } |
58 if (prev->fNext != edge) { | 162 if (prev->fNext != edge) { |
59 remove_edge(edge); | 163 remove_edge(edge); |
60 insert_edge_after(edge, prev); | 164 insert_edge_after(edge, prev); |
(...skipping 29 matching lines...) Expand all Loading... |
90 #if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used
without having been initialized | 194 #if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used
without having been initialized |
91 #pragma warning ( push ) | 195 #pragma warning ( push ) |
92 #pragma warning ( disable : 4701 ) | 196 #pragma warning ( disable : 4701 ) |
93 #endif | 197 #endif |
94 | 198 |
95 typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline); | 199 typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline); |
96 #define PREPOST_START true | 200 #define PREPOST_START true |
97 #define PREPOST_END false | 201 #define PREPOST_END false |
98 | 202 |
99 static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, | 203 static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, |
100 SkBlitter* blitter, int start_y, int stop_y, | 204 SkBlitter* blitter, SkTDArray<SkPoint>* points, |
101 PrePostProc proc, int rightClip) { | 205 int start_y, int stop_y, PrePostProc proc, int rightClip)
{ |
102 validate_sort(prevHead->fNext); | 206 validate_sort(prevHead->fNext); |
103 | 207 |
104 int curr_y = start_y; | 208 int curr_y = start_y; |
105 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness | 209 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness |
106 int windingMask = (fillType & 1) ? 1 : -1; | 210 int windingMask = (fillType & 1) ? 1 : -1; |
107 | 211 |
108 for (;;) { | 212 for (;;) { |
109 int w = 0; | 213 int w = 0; |
110 int left SK_INIT_TO_AVOID_WARNING; | 214 int left SK_INIT_TO_AVOID_WARNING; |
111 bool in_interval = false; | 215 bool in_interval = false; |
112 SkEdge* currE = prevHead->fNext; | 216 SkEdge* currE = prevHead->fNext; |
113 SkFixed prevX = prevHead->fX; | 217 SkFixed prevX = prevHead->fX; |
114 | 218 |
115 validate_edges_for_y(currE, curr_y); | 219 validate_edges_for_y(currE, curr_y); |
116 | 220 |
117 if (proc) { | 221 if (proc && blitter) { |
118 proc(blitter, curr_y, PREPOST_START); // pre-proc | 222 proc(blitter, curr_y, PREPOST_START); // pre-proc |
119 } | 223 } |
120 | 224 |
121 while (currE->fFirstY <= curr_y) { | 225 while (currE->fFirstY <= curr_y) { |
122 SkASSERT(currE->fLastY >= curr_y); | 226 SkASSERT(currE->fLastY >= curr_y); |
123 | 227 |
124 int x = SkFixedRoundToInt(currE->fX); | 228 int x = SkFixedRoundToInt(currE->fX); |
125 w += currE->fWinding; | 229 w += currE->fWinding; |
126 if ((w & windingMask) == 0) { // we finished an interval | 230 if ((w & windingMask) == 0) { // we finished an interval |
127 SkASSERT(in_interval); | 231 SkASSERT(in_interval); |
128 int width = x - left; | 232 int width = x - left; |
129 SkASSERT(width >= 0); | 233 SkASSERT(width >= 0); |
130 if (width) | 234 if (width) { |
131 blitter->blitH(left, curr_y, width); | 235 if (blitter) { |
| 236 blitter->blitH(left, curr_y, width); |
| 237 } |
| 238 } |
132 in_interval = false; | 239 in_interval = false; |
133 } else if (!in_interval) { | 240 } else if (!in_interval) { |
134 left = x; | 241 left = x; |
135 in_interval = true; | 242 in_interval = true; |
136 } | 243 } |
137 | 244 |
138 SkEdge* next = currE->fNext; | 245 SkEdge* next = currE->fNext; |
139 SkFixed newX; | 246 SkFixed newX; |
140 | 247 |
141 if (currE->fLastY == curr_y) { // are we done with this edge? | 248 if (currE->fLastY == curr_y) { // are we done with this edge? |
| 249 if (points) emit_all_trapezoids(prevHead->fNext, windingMask, cu
rr_y + 1, points); |
142 if (currE->fCurveCount < 0) { | 250 if (currE->fCurveCount < 0) { |
143 if (((SkCubicEdge*)currE)->updateCubic()) { | 251 if (((SkCubicEdge*)currE)->updateCubic()) { |
144 SkASSERT(currE->fFirstY == curr_y + 1); | 252 SkASSERT(currE->fFirstY == curr_y + 1); |
145 | 253 |
146 newX = currE->fX; | 254 newX = currE->fX; |
147 goto NEXT_X; | 255 goto NEXT_X; |
148 } | 256 } |
149 } else if (currE->fCurveCount > 0) { | 257 } else if (currE->fCurveCount > 0) { |
150 if (((SkQuadraticEdge*)currE)->updateQuadratic()) { | 258 if (((SkQuadraticEdge*)currE)->updateQuadratic()) { |
151 newX = currE->fX; | 259 newX = currE->fX; |
152 goto NEXT_X; | 260 goto NEXT_X; |
153 } | 261 } |
154 } | 262 } |
155 remove_edge(currE); | 263 remove_edge(currE); |
156 } else { | 264 } else { |
157 SkASSERT(currE->fLastY > curr_y); | 265 SkASSERT(currE->fLastY > curr_y); |
158 newX = currE->fX + currE->fDX; | 266 newX = currE->fX + currE->fDX; |
159 currE->fX = newX; | 267 currE->fX = newX; |
160 NEXT_X: | 268 NEXT_X: |
161 if (newX < prevX) { // ripple currE backwards until it is x-sort
ed | 269 if (newX < prevX) { // ripple currE backwards until it is x-sort
ed |
| 270 if (points) emit_all_trapezoids(prevHead->fNext, windingMask
, curr_y + 1, points); |
162 backward_insert_edge_based_on_x(currE SkPARAM(curr_y)); | 271 backward_insert_edge_based_on_x(currE SkPARAM(curr_y)); |
163 } else { | 272 } else { |
164 prevX = newX; | 273 prevX = newX; |
165 } | 274 } |
166 } | 275 } |
167 currE = next; | 276 currE = next; |
168 SkASSERT(currE); | 277 SkASSERT(currE); |
169 } | 278 } |
170 | 279 |
171 // was our right-edge culled away? | 280 // was our right-edge culled away? |
172 if (in_interval) { | 281 if (in_interval && blitter) { |
173 int width = rightClip - left; | 282 int width = rightClip - left; |
174 if (width > 0) { | 283 if (width > 0) { |
175 blitter->blitH(left, curr_y, width); | 284 blitter->blitH(left, curr_y, width); |
176 } | 285 } |
177 } | 286 } |
178 | 287 |
179 if (proc) { | 288 if (proc && blitter) { |
180 proc(blitter, curr_y, PREPOST_END); // post-proc | 289 proc(blitter, curr_y, PREPOST_END); // post-proc |
181 } | 290 } |
182 | 291 |
183 curr_y += 1; | 292 curr_y += 1; |
184 if (curr_y >= stop_y) { | 293 if (curr_y >= stop_y) { |
185 break; | 294 break; |
186 } | 295 } |
| 296 if (points && currE->fFirstY == curr_y) { |
| 297 emit_all_trapezoids(prevHead->fNext, windingMask, curr_y, points); |
| 298 } |
187 // now currE points to the first edge with a Yint larger than curr_y | 299 // now currE points to the first edge with a Yint larger than curr_y |
188 insert_new_edges(currE, curr_y); | 300 insert_new_edges(currE, curr_y); |
189 } | 301 } |
190 } | 302 } |
191 | 303 |
192 // return true if we're done with this edge | 304 // return true if we're done with this edge |
193 static bool update_edge(SkEdge* edge, int last_y) { | 305 static bool update_edge(SkEdge* edge, int last_y) { |
194 SkASSERT(edge->fLastY >= last_y); | 306 SkASSERT(edge->fLastY >= last_y); |
195 if (last_y == edge->fLastY) { | 307 if (last_y == edge->fLastY) { |
196 if (edge->fCurveCount < 0) { | 308 if (edge->fCurveCount < 0) { |
197 if (((SkCubicEdge*)edge)->updateCubic()) { | 309 if (((SkCubicEdge*)edge)->updateCubic()) { |
198 SkASSERT(edge->fFirstY == last_y + 1); | 310 SkASSERT(edge->fFirstY == last_y + 1); |
199 return false; | 311 return false; |
200 } | 312 } |
201 } else if (edge->fCurveCount > 0) { | 313 } else if (edge->fCurveCount > 0) { |
202 if (((SkQuadraticEdge*)edge)->updateQuadratic()) { | 314 if (((SkQuadraticEdge*)edge)->updateQuadratic()) { |
203 SkASSERT(edge->fFirstY == last_y + 1); | 315 SkASSERT(edge->fFirstY == last_y + 1); |
204 return false; | 316 return false; |
205 } | 317 } |
206 } | 318 } |
207 return true; | 319 return true; |
208 } | 320 } |
209 return false; | 321 return false; |
210 } | 322 } |
211 | 323 |
212 static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType, | 324 static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType, |
213 SkBlitter* blitter, int start_y, int stop_y, | 325 SkBlitter* blitter, SkTDArray<SkPoint>* points, |
| 326 int start_y, int stop_y, |
214 PrePostProc proc) { | 327 PrePostProc proc) { |
215 validate_sort(prevHead->fNext); | 328 validate_sort(prevHead->fNext); |
216 | 329 |
217 SkEdge* leftE = prevHead->fNext; | 330 SkEdge* leftE = prevHead->fNext; |
218 SkEdge* riteE = leftE->fNext; | 331 SkEdge* riteE = leftE->fNext; |
219 SkEdge* currE = riteE->fNext; | 332 SkEdge* currE = riteE->fNext; |
220 | 333 |
221 #if 0 | 334 #if 0 |
222 int local_top = leftE->fFirstY; | 335 int local_top = leftE->fFirstY; |
223 SkASSERT(local_top == riteE->fFirstY); | 336 SkASSERT(local_top == riteE->fFirstY); |
(...skipping 16 matching lines...) Expand all Loading... |
240 int local_bot = SkMin32(leftE->fLastY, riteE->fLastY); | 353 int local_bot = SkMin32(leftE->fLastY, riteE->fLastY); |
241 local_bot = SkMin32(local_bot, stop_y - 1); | 354 local_bot = SkMin32(local_bot, stop_y - 1); |
242 SkASSERT(local_top <= local_bot); | 355 SkASSERT(local_top <= local_bot); |
243 | 356 |
244 SkFixed left = leftE->fX; | 357 SkFixed left = leftE->fX; |
245 SkFixed dLeft = leftE->fDX; | 358 SkFixed dLeft = leftE->fDX; |
246 SkFixed rite = riteE->fX; | 359 SkFixed rite = riteE->fX; |
247 SkFixed dRite = riteE->fDX; | 360 SkFixed dRite = riteE->fDX; |
248 int count = local_bot - local_top; | 361 int count = local_bot - local_top; |
249 SkASSERT(count >= 0); | 362 SkASSERT(count >= 0); |
250 if (0 == (dLeft | dRite)) { | 363 if (points) { |
| 364 emit_trapezoid(leftE, riteE, (float) local_top, (float) (local_bot +
1), points); |
| 365 if (left < rite) { |
| 366 count += 1; |
| 367 left += count * dLeft; |
| 368 rite += count * dRite; |
| 369 } |
| 370 local_top = local_bot + 1; |
| 371 } else if (0 == (dLeft | dRite)) { |
251 int L = SkFixedRoundToInt(left); | 372 int L = SkFixedRoundToInt(left); |
252 int R = SkFixedRoundToInt(rite); | 373 int R = SkFixedRoundToInt(rite); |
253 if (L < R) { | 374 if (L < R) { |
254 count += 1; | 375 count += 1; |
255 blitter->blitRect(L, local_top, R - L, count); | 376 blitter->blitRect(L, local_top, R - L, count); |
| 377 left += count * dLeft; |
| 378 rite += count * dRite; |
256 } | 379 } |
257 local_top = local_bot + 1; | 380 local_top = local_bot + 1; |
258 } else { | 381 } else { |
259 do { | 382 do { |
260 int L = SkFixedRoundToInt(left); | 383 int L = SkFixedRoundToInt(left); |
261 int R = SkFixedRoundToInt(rite); | 384 int R = SkFixedRoundToInt(rite); |
262 if (L < R) { | 385 if (L < R) { |
263 blitter->blitH(L, local_top, R - L); | 386 blitter->blitH(L, local_top, R - L); |
264 } | 387 } |
265 left += dLeft; | 388 left += dLeft; |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 | 510 |
388 *last = list[count - 1]; | 511 *last = list[count - 1]; |
389 return list[0]; | 512 return list[0]; |
390 } | 513 } |
391 | 514 |
392 // clipRect may be null, even though we always have a clip. This indicates that | 515 // clipRect may be null, even though we always have a clip. This indicates that |
393 // the path is contained in the clip, and so we can ignore it during the blit | 516 // the path is contained in the clip, and so we can ignore it during the blit |
394 // | 517 // |
395 // clipRect (if no null) has already been shifted up | 518 // clipRect (if no null) has already been shifted up |
396 // | 519 // |
397 void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitte
r, | 520 void sk_fill_path(const SkPath& path, const SkIRect* clipRect, |
398 int start_y, int stop_y, int shiftEdgesUp, const SkRegion& cli
pRgn) { | 521 SkBlitter* blitter, SkTDArray<SkPoint>* points, |
399 SkASSERT(blitter); | 522 int start_y, int stop_y, int shiftEdgesUp, |
| 523 const SkRegion& clipRgn) { |
| 524 SkASSERT(blitter || points); |
400 | 525 |
401 SkEdgeBuilder builder; | 526 SkEdgeBuilder builder; |
402 | 527 |
403 // If we're convex, then we need both edges, even the right edge is past the
clip | 528 // If we're convex, then we need both edges, even the right edge is past the
clip |
404 const bool canCullToTheRight = !path.isConvex(); | 529 const bool canCullToTheRight = !path.isConvex() && !points; |
405 | 530 |
406 int count = builder.build(path, clipRect, shiftEdgesUp, canCullToTheRight); | 531 int count = builder.build(path, clipRect, shiftEdgesUp, canCullToTheRight); |
407 SkASSERT(count >= 0); | 532 SkASSERT(count >= 0); |
408 | 533 |
409 SkEdge** list = builder.edgeList(); | 534 SkEdge** list = builder.edgeList(); |
410 | 535 |
411 if (0 == count) { | 536 if (0 == count) { |
412 if (path.isInverseFillType()) { | 537 if (path.isInverseFillType()) { |
413 /* | 538 /* |
414 * Since we are in inverse-fill, our caller has already drawn above | 539 * Since we are in inverse-fill, our caller has already drawn above |
415 * our top (start_y) and will draw below our bottom (stop_y). Thus | 540 * our top (start_y) and will draw below our bottom (stop_y). Thus |
416 * we need to restrict our drawing to the intersection of the clip | 541 * we need to restrict our drawing to the intersection of the clip |
417 * and those two limits. | 542 * and those two limits. |
418 */ | 543 */ |
419 SkIRect rect = clipRgn.getBounds(); | 544 SkIRect rect = clipRgn.getBounds(); |
420 if (rect.fTop < start_y) { | 545 if (rect.fTop < start_y) { |
421 rect.fTop = start_y; | 546 rect.fTop = start_y; |
422 } | 547 } |
423 if (rect.fBottom > stop_y) { | 548 if (rect.fBottom > stop_y) { |
424 rect.fBottom = stop_y; | 549 rect.fBottom = stop_y; |
425 } | 550 } |
426 if (!rect.isEmpty()) { | 551 if (!rect.isEmpty()) { |
427 blitter->blitRect(rect.fLeft << shiftEdgesUp, | 552 if (blitter) { |
428 rect.fTop << shiftEdgesUp, | 553 blitter->blitRect(rect.fLeft << shiftEdgesUp, |
429 rect.width() << shiftEdgesUp, | 554 rect.fTop << shiftEdgesUp, |
430 rect.height() << shiftEdgesUp); | 555 rect.width() << shiftEdgesUp, |
| 556 rect.height() << shiftEdgesUp); |
| 557 } else { |
| 558 SkRect r = SkRect::Make(rect); |
| 559 r.toQuad(points->append(4)); |
| 560 } |
431 } | 561 } |
432 } | 562 } |
| 563 |
433 return; | 564 return; |
434 } | 565 } |
435 | 566 |
436 SkEdge headEdge, tailEdge, *last; | 567 SkEdge headEdge, tailEdge, *last; |
437 // this returns the first and last edge after they're sorted into a dlink li
st | 568 // this returns the first and last edge after they're sorted into a dlink li
st |
438 SkEdge* edge = sort_edges(list, count, &last); | 569 SkEdge* edge = sort_edges(list, count, &last); |
| 570 if (dumping) { |
| 571 printf("sorted into %d edges:\n", count); |
| 572 SkEdge* e = edge; |
| 573 for (int i = 0; i < count; i++) { |
| 574 printf("edge %p fFirstXf %g fFirstYf %g fLastY %d fDX %g\n", e, e->f
FirstXf, e->fFirstYf, e->fLastY, e->fDX / 65536.0); |
| 575 e = e->fNext; |
| 576 } |
| 577 } |
439 | 578 |
440 headEdge.fPrev = nullptr; | 579 headEdge.fPrev = nullptr; |
441 headEdge.fNext = edge; | 580 headEdge.fNext = edge; |
442 headEdge.fFirstY = kEDGE_HEAD_Y; | 581 headEdge.fFirstY = kEDGE_HEAD_Y; |
443 headEdge.fX = SK_MinS32; | 582 headEdge.fX = SK_MinS32; |
444 edge->fPrev = &headEdge; | 583 edge->fPrev = &headEdge; |
445 | 584 |
446 tailEdge.fPrev = last; | 585 tailEdge.fPrev = last; |
447 tailEdge.fNext = nullptr; | 586 tailEdge.fNext = nullptr; |
448 tailEdge.fFirstY = kEDGE_TAIL_Y; | 587 tailEdge.fFirstY = kEDGE_TAIL_Y; |
449 last->fNext = &tailEdge; | 588 last->fNext = &tailEdge; |
450 | 589 |
451 // now edge is the head of the sorted linklist | 590 // now edge is the head of the sorted linklist |
452 | 591 |
453 start_y <<= shiftEdgesUp; | 592 start_y <<= shiftEdgesUp; |
454 stop_y <<= shiftEdgesUp; | 593 stop_y <<= shiftEdgesUp; |
455 if (clipRect && start_y < clipRect->fTop) { | 594 if (clipRect && start_y < clipRect->fTop) { |
456 start_y = clipRect->fTop; | 595 start_y = clipRect->fTop; |
457 } | 596 } |
458 if (clipRect && stop_y > clipRect->fBottom) { | 597 if (clipRect && stop_y > clipRect->fBottom) { |
459 stop_y = clipRect->fBottom; | 598 stop_y = clipRect->fBottom; |
460 } | 599 } |
461 | 600 |
462 InverseBlitter ib; | 601 InverseBlitter ib; |
463 PrePostProc proc = nullptr; | 602 PrePostProc proc = nullptr; |
464 | 603 |
465 if (path.isInverseFillType()) { | 604 if (path.isInverseFillType() && blitter) { |
466 ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp); | 605 ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp); |
467 blitter = &ib; | 606 blitter = &ib; |
468 proc = PrePostInverseBlitterProc; | 607 proc = PrePostInverseBlitterProc; |
469 } | 608 } |
470 | 609 |
471 if (path.isConvex() && (nullptr == proc)) { | 610 if (path.isConvex() && (nullptr == proc) && blitter) { |
472 SkASSERT(count >= 2); // convex walker does not handle missing right e
dges | 611 SkASSERT(count >= 2); // convex walker does not handle missing right e
dges |
473 walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_
y, nullptr); | 612 walk_convex_edges(&headEdge, path.getFillType(), blitter, points, start_
y, stop_y, NULL); |
474 } else { | 613 } else { |
475 int rightEdge; | 614 int rightEdge; |
476 if (clipRect) { | 615 if (clipRect) { |
477 rightEdge = clipRect->right(); | 616 rightEdge = clipRect->right(); |
478 } else { | 617 } else { |
479 rightEdge = SkScalarRoundToInt(path.getBounds().right()) << shiftEdg
esUp; | 618 rightEdge = SkScalarRoundToInt(path.getBounds().right()) << shiftEdg
esUp; |
480 } | 619 } |
481 | 620 |
482 walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc
, rightEdge); | 621 walk_edges(&headEdge, path.getFillType(), blitter, points, start_y, stop
_y, proc, rightEdge); |
483 } | 622 } |
484 } | 623 } |
485 | 624 |
486 void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip)
{ | 625 void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip)
{ |
487 const SkIRect& cr = clip.getBounds(); | 626 const SkIRect& cr = clip.getBounds(); |
488 SkIRect tmp; | 627 SkIRect tmp; |
489 | 628 |
490 tmp.fLeft = cr.fLeft; | 629 tmp.fLeft = cr.fLeft; |
491 tmp.fRight = cr.fRight; | 630 tmp.fRight = cr.fRight; |
492 tmp.fTop = cr.fTop; | 631 tmp.fTop = cr.fTop; |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
592 | 731 |
593 SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType()); | 732 SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType()); |
594 | 733 |
595 blitter = clipper.getBlitter(); | 734 blitter = clipper.getBlitter(); |
596 if (blitter) { | 735 if (blitter) { |
597 // we have to keep our calls to blitter in sorted order, so we | 736 // we have to keep our calls to blitter in sorted order, so we |
598 // must blit the above section first, then the middle, then the bottom. | 737 // must blit the above section first, then the middle, then the bottom. |
599 if (path.isInverseFillType()) { | 738 if (path.isInverseFillType()) { |
600 sk_blit_above(blitter, ir, *clipPtr); | 739 sk_blit_above(blitter, ir, *clipPtr); |
601 } | 740 } |
602 sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, | 741 sk_fill_path(path, clipper.getClipRect(), blitter, NULL, ir.fTop, ir.fBo
ttom, |
603 0, *clipPtr); | 742 0, *clipPtr); |
604 if (path.isInverseFillType()) { | 743 if (path.isInverseFillType()) { |
605 sk_blit_below(blitter, ir, *clipPtr); | 744 sk_blit_below(blitter, ir, *clipPtr); |
606 } | 745 } |
607 } else { | 746 } else { |
608 // what does it mean to not have a blitter if path.isInverseFillType??? | 747 // what does it mean to not have a blitter if path.isInverseFillType??? |
609 } | 748 } |
610 } | 749 } |
611 | 750 |
612 void SkScan::FillPath(const SkPath& path, const SkIRect& ir, | 751 void SkScan::FillPath(const SkPath& path, const SkIRect& ir, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
666 | 805 |
667 // now edge is the head of the sorted linklist | 806 // now edge is the head of the sorted linklist |
668 int stop_y = ir.fBottom; | 807 int stop_y = ir.fBottom; |
669 if (clipRect && stop_y > clipRect->fBottom) { | 808 if (clipRect && stop_y > clipRect->fBottom) { |
670 stop_y = clipRect->fBottom; | 809 stop_y = clipRect->fBottom; |
671 } | 810 } |
672 int start_y = ir.fTop; | 811 int start_y = ir.fTop; |
673 if (clipRect && start_y < clipRect->fTop) { | 812 if (clipRect && start_y < clipRect->fTop) { |
674 start_y = clipRect->fTop; | 813 start_y = clipRect->fTop; |
675 } | 814 } |
676 walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, st
op_y, nullptr); | 815 walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, nullptr, st
art_y, stop_y, nullptr); |
677 // walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y,
nullptr); | 816 // walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y,
NULL); |
678 } | 817 } |
679 | 818 |
680 void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip, | 819 void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip, |
681 SkBlitter* blitter) { | 820 SkBlitter* blitter) { |
682 if (clip.isEmpty()) { | 821 if (clip.isEmpty()) { |
683 return; | 822 return; |
684 } | 823 } |
685 | 824 |
686 SkRect r; | 825 SkRect r; |
687 SkIRect ir; | 826 SkIRect ir; |
(...skipping 12 matching lines...) Expand all Loading... |
700 clipRgn = &wrap.getRgn(); | 839 clipRgn = &wrap.getRgn(); |
701 blitter = wrap.getBlitter(); | 840 blitter = wrap.getBlitter(); |
702 } | 841 } |
703 | 842 |
704 SkScanClipper clipper(blitter, clipRgn, ir); | 843 SkScanClipper clipper(blitter, clipRgn, ir); |
705 blitter = clipper.getBlitter(); | 844 blitter = clipper.getBlitter(); |
706 if (blitter) { | 845 if (blitter) { |
707 sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); | 846 sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); |
708 } | 847 } |
709 } | 848 } |
| 849 |
| 850 void SkScan::PathToTriangles(const SkPath& path, const SkIRect& clipBounds, |
| 851 bool antiAlias, SkTDArray<SkPoint>* points) { |
| 852 // dumping = true; |
| 853 // printf("*** SkScan::PathToTriangles start\n"); |
| 854 points->setReserve(path.countPoints()); |
| 855 SkPath localPath = path; |
| 856 SkIRect localClipBounds = clipBounds; |
| 857 if (antiAlias) { |
| 858 // Stroke 1-pix wide around path. |
| 859 SkStroke stroker; |
| 860 stroker.setJoin(SkPaint::kMiter_Join); |
| 861 stroker.setWidth(5); |
| 862 SkPath strokedPath; |
| 863 // We want even open paths to become closed, so we can fill them. |
| 864 stroker.setAutoClose(true); |
| 865 // Don't reverse the inner path direction, since want the interior to be
filled. |
| 866 stroker.setReverseInner(false); |
| 867 stroker.strokePath(localPath, &strokedPath); |
| 868 localPath = strokedPath; |
| 869 } |
| 870 SkRect pathBounds = localPath.getBounds(); |
| 871 SkRegion clipRgn(localClipBounds); |
| 872 if (localPath.isInverseFillType()) { |
| 873 localPath.addRect(SkRect::Make(localClipBounds), SkPath::kCCW_Direction)
; |
| 874 sk_fill_path(localPath, &localClipBounds, NULL, points, |
| 875 localClipBounds.top(), localClipBounds.bottom(), 0, |
| 876 clipRgn); |
| 877 } else { |
| 878 sk_fill_path(localPath, &localClipBounds, NULL, points, |
| 879 pathBounds.top() - 1, pathBounds.bottom() + 1, 0, |
| 880 clipRgn); |
| 881 } |
| 882 // printf("*** SkScan::PathToTriangles end\n"); |
| 883 // dumping = false; |
| 884 } |
OLD | NEW |