blob: 3b0f152a4fef4570cbb8f065720c833882952f35 [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#include "SkScan.h"
11#include "SkBlitter.h"
reed@google.com045e62d2011-10-24 12:19:46 +000012#include "SkRasterClip.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkFDot6.h"
reed@android.come28ff552009-11-19 20:46:39 +000014#include "SkLineClipper.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
mike@reedtribe.org69bc9942011-04-20 10:56:02 +000016static void horiline(int x, int stopx, SkFixed fy, SkFixed dy,
17 SkBlitter* blitter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000018 SkASSERT(x < stopx);
19
20 do {
21 blitter->blitH(x, fy >> 16, 1);
22 fy += dy;
23 } while (++x < stopx);
24}
25
mike@reedtribe.org69bc9942011-04-20 10:56:02 +000026static void vertline(int y, int stopy, SkFixed fx, SkFixed dx,
27 SkBlitter* blitter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 SkASSERT(y < stopy);
29
30 do {
31 blitter->blitH(fx >> 16, y, 1);
32 fx += dx;
33 } while (++y < stopy);
34}
35
humper@google.com0e515772013-01-07 19:54:40 +000036#ifdef SK_DEBUG
reed@google.combb39a292012-04-18 21:19:26 +000037static bool canConvertFDot6ToFixed(SkFDot6 x) {
38 const int maxDot6 = SK_MaxS32 >> (16 - 6);
39 return SkAbs32(x) <= maxDot6;
40}
humper@google.com0e515772013-01-07 19:54:40 +000041#endif
reed@google.combb39a292012-04-18 21:19:26 +000042
reed@google.com045e62d2011-10-24 12:19:46 +000043void SkScan::HairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
44 const SkRegion* clip, SkBlitter* blitter) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 SkBlitterClipper clipper;
reed@android.come28ff552009-11-19 20:46:39 +000046 SkRect r;
47 SkIRect clipR, ptsR;
48 SkPoint pts[2] = { pt0, pt1 };
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
reed@google.combb39a292012-04-18 21:19:26 +000050 // We have to pre-clip the line to fit in a SkFixed, so we just chop
51 // the line. TODO find a way to actually draw beyond that range.
52 {
53 SkRect fixedBounds;
54 const SkScalar max = SkIntToScalar(32767);
55 fixedBounds.set(-max, -max, max, max);
56 if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) {
57 return;
58 }
59 }
reed@google.combb39a292012-04-18 21:19:26 +000060
reed@android.come28ff552009-11-19 20:46:39 +000061 if (clip) {
62 // Perform a clip in scalar space, so we catch huge values which might
63 // be missed after we convert to SkFDot6 (overflow)
64 r.set(clip->getBounds());
65 if (!SkLineClipper::IntersectLine(pts, r, pts)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 return;
reed@android.come28ff552009-11-19 20:46:39 +000067 }
68 }
69
70 SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
71 SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
72 SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
73 SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000074
reed@google.combb39a292012-04-18 21:19:26 +000075 SkASSERT(canConvertFDot6ToFixed(x0));
76 SkASSERT(canConvertFDot6ToFixed(y0));
77 SkASSERT(canConvertFDot6ToFixed(x1));
78 SkASSERT(canConvertFDot6ToFixed(y1));
79
reed@android.come28ff552009-11-19 20:46:39 +000080 if (clip) {
81 // now perform clipping again, as the rounding to dot6 can wiggle us
82 // our rects are really dot6 rects, but since we've already used
83 // lineclipper, we know they will fit in 32bits (26.6)
84 const SkIRect& bounds = clip->getBounds();
85
86 clipR.set(SkIntToFDot6(bounds.fLeft), SkIntToFDot6(bounds.fTop),
87 SkIntToFDot6(bounds.fRight), SkIntToFDot6(bounds.fBottom));
88 ptsR.set(x0, y0, x1, y1);
89 ptsR.sort();
90
91 // outset the right and bottom, to account for how hairlines are
92 // actually drawn, which may hit the pixel to the right or below of
93 // the coordinate
mike@reedtribe.orgbcc1d332011-04-09 19:16:54 +000094 ptsR.fRight += SK_FDot6One;
95 ptsR.fBottom += SK_FDot6One;
reed@android.come28ff552009-11-19 20:46:39 +000096
97 if (!SkIRect::Intersects(ptsR, clipR)) {
98 return;
99 }
100 if (clip->isRect() && clipR.contains(ptsR)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101 clip = NULL;
reed@android.come28ff552009-11-19 20:46:39 +0000102 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 blitter = clipper.apply(blitter, clip);
104 }
105 }
106
107 SkFDot6 dx = x1 - x0;
108 SkFDot6 dy = y1 - y0;
109
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000110 if (SkAbs32(dx) > SkAbs32(dy)) { // mostly horizontal
111 if (x0 > x1) { // we want to go left-to-right
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 SkTSwap<SkFDot6>(x0, x1);
113 SkTSwap<SkFDot6>(y0, y1);
114 }
115 int ix0 = SkFDot6Round(x0);
116 int ix1 = SkFDot6Round(x1);
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000117 if (ix0 == ix1) {// too short to draw
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 return;
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000119 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120
121 SkFixed slope = SkFixedDiv(dy, dx);
122 SkFixed startY = SkFDot6ToFixed(y0) + (slope * ((32 - x0) & 63) >> 6);
123
124 horiline(ix0, ix1, startY, slope, blitter);
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000125 } else { // mostly vertical
126 if (y0 > y1) { // we want to go top-to-bottom
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 SkTSwap<SkFDot6>(x0, x1);
128 SkTSwap<SkFDot6>(y0, y1);
129 }
130 int iy0 = SkFDot6Round(y0);
131 int iy1 = SkFDot6Round(y1);
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000132 if (iy0 == iy1) { // too short to draw
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 return;
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000134 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135
136 SkFixed slope = SkFixedDiv(dx, dy);
137 SkFixed startX = SkFDot6ToFixed(x0) + (slope * ((32 - y0) & 63) >> 6);
138
139 vertline(iy0, iy1, startX, slope, blitter);
140 }
141}
142
143// we don't just draw 4 lines, 'cause that can leave a gap in the bottom-right
144// and double-hit the top-left.
reed@android.come28ff552009-11-19 20:46:39 +0000145// TODO: handle huge coordinates on rect (before calling SkScalarToFixed)
reed@google.com045e62d2011-10-24 12:19:46 +0000146void SkScan::HairRect(const SkRect& rect, const SkRasterClip& clip,
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000147 SkBlitter* blitter) {
reed@google.com045e62d2011-10-24 12:19:46 +0000148 SkAAClipBlitterWrapper wrapper;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 SkBlitterClipper clipper;
150 SkIRect r;
151
152 r.set(SkScalarToFixed(rect.fLeft) >> 16,
153 SkScalarToFixed(rect.fTop) >> 16,
154 (SkScalarToFixed(rect.fRight) >> 16) + 1,
155 (SkScalarToFixed(rect.fBottom) >> 16) + 1);
156
reed@google.com045e62d2011-10-24 12:19:46 +0000157 if (clip.quickReject(r)) {
158 return;
159 }
160 if (!clip.quickContains(r)) {
161 const SkRegion* clipRgn;
162 if (clip.isBW()) {
163 clipRgn = &clip.bwRgn();
164 } else {
165 wrapper.init(clip, blitter);
166 clipRgn = &wrapper.getRgn();
167 blitter = wrapper.getBlitter();
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000168 }
reed@google.com045e62d2011-10-24 12:19:46 +0000169 blitter = clipper.apply(blitter, clipRgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170 }
171
172 int width = r.width();
173 int height = r.height();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000174
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000175 if ((width | height) == 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 return;
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000177 }
178 if (width <= 2 || height <= 2) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000179 blitter->blitRect(r.fLeft, r.fTop, width, height);
180 return;
181 }
182 // if we get here, we know we have 4 segments to draw
183 blitter->blitH(r.fLeft, r.fTop, width); // top
184 blitter->blitRect(r.fLeft, r.fTop + 1, 1, height - 2); // left
185 blitter->blitRect(r.fRight - 1, r.fTop + 1, 1, height - 2); // right
186 blitter->blitH(r.fLeft, r.fBottom - 1, width); // bottom
187}
188
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000189///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190
191#include "SkPath.h"
192#include "SkGeometry.h"
193
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194static int compute_int_quad_dist(const SkPoint pts[3]) {
195 // compute the vector between the control point ([1]) and the middle of the
196 // line connecting the start and end ([0] and [2])
197 SkScalar dx = SkScalarHalf(pts[0].fX + pts[2].fX) - pts[1].fX;
198 SkScalar dy = SkScalarHalf(pts[0].fY + pts[2].fY) - pts[1].fY;
199 // we want everyone to be positive
200 dx = SkScalarAbs(dx);
201 dy = SkScalarAbs(dy);
202 // convert to whole pixel values (use ceiling to be conservative)
203 int idx = SkScalarCeil(dx);
204 int idy = SkScalarCeil(dy);
205 // use the cheap approx for distance
206 if (idx > idy) {
207 return idx + (idy >> 1);
208 } else {
209 return idy + (idx >> 1);
210 }
211}
212
reed@google.com4e05fd22013-06-10 18:58:11 +0000213typedef void (*LineProc)(const SkPoint&, const SkPoint&, const SkRegion*,
214 SkBlitter*);
215
216static void hairquad(const SkPoint pts[3], const SkRegion* clip,
217 SkBlitter* blitter, int level, LineProc lineproc) {
218 if (level > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 SkPoint tmp[5];
220
221 SkChopQuadAtHalf(pts, tmp);
222 hairquad(tmp, clip, blitter, level - 1, lineproc);
223 hairquad(&tmp[2], clip, blitter, level - 1, lineproc);
reed@google.com4e05fd22013-06-10 18:58:11 +0000224 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 lineproc(pts[0], pts[2], clip, blitter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227}
228
reed@google.com4e05fd22013-06-10 18:58:11 +0000229static void haircubic(const SkPoint pts[4], const SkRegion* clip,
230 SkBlitter* blitter, int level, LineProc lineproc) {
231 if (level > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000232 SkPoint tmp[7];
233
234 SkChopCubicAt(pts, tmp, SK_Scalar1/2);
235 haircubic(tmp, clip, blitter, level - 1, lineproc);
236 haircubic(&tmp[3], clip, blitter, level - 1, lineproc);
reed@google.com4e05fd22013-06-10 18:58:11 +0000237 } else {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 lineproc(pts[0], pts[3], clip, blitter);
reed@google.com4e05fd22013-06-10 18:58:11 +0000239 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240}
241
242#define kMaxCubicSubdivideLevel 6
243#define kMaxQuadSubdivideLevel 5
244
reed@google.com4e05fd22013-06-10 18:58:11 +0000245static int compute_quad_level(const SkPoint pts[3]) {
246 int d = compute_int_quad_dist(pts);
247 /* quadratics approach the line connecting their start and end points
248 4x closer with each subdivision, so we compute the number of
249 subdivisions to be the minimum need to get that distance to be less
250 than a pixel.
251 */
252 int level = (33 - SkCLZ(d)) >> 1;
253 // sanity check on level (from the previous version)
254 if (level > kMaxQuadSubdivideLevel) {
255 level = kMaxQuadSubdivideLevel;
256 }
257 return level;
258}
259
260static void hair_path(const SkPath& path, const SkRasterClip& rclip,
261 SkBlitter* blitter, LineProc lineproc) {
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000262 if (path.isEmpty()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 return;
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000264 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265
reed@google.com045e62d2011-10-24 12:19:46 +0000266 SkAAClipBlitterWrapper wrap;
reed@google.com045e62d2011-10-24 12:19:46 +0000267 const SkRegion* clip = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268
reed@google.com045e62d2011-10-24 12:19:46 +0000269 {
reed@android.comd252db02009-04-01 18:31:44 +0000270 SkIRect ibounds;
271 path.getBounds().roundOut(&ibounds);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 ibounds.inset(-1, -1);
273
reed@google.com045e62d2011-10-24 12:19:46 +0000274 if (rclip.quickReject(ibounds)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 return;
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000276 }
reed@google.com045e62d2011-10-24 12:19:46 +0000277 if (!rclip.quickContains(ibounds)) {
reed@google.com045e62d2011-10-24 12:19:46 +0000278 if (rclip.isBW()) {
279 clip = &rclip.bwRgn();
280 } else {
281 wrap.init(rclip, blitter);
282 blitter = wrap.getBlitter();
283 clip = &wrap.getRgn();
284 }
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000285 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286 }
287
288 SkPath::Iter iter(path, false);
289 SkPoint pts[4];
290 SkPath::Verb verb;
reed@google.com4e05fd22013-06-10 18:58:11 +0000291 SkAutoConicToQuads converter;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292
reed@google.com4a3b7142012-05-16 17:16:46 +0000293 while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 switch (verb) {
reed@google.com4e05fd22013-06-10 18:58:11 +0000295 case SkPath::kMove_Verb:
296 break;
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000297 case SkPath::kLine_Verb:
298 lineproc(pts[0], pts[1], clip, blitter);
299 break;
reed@google.com4e05fd22013-06-10 18:58:11 +0000300 case SkPath::kQuad_Verb:
301 hairquad(pts, clip, blitter, compute_quad_level(pts), lineproc);
302 break;
303 case SkPath::kConic_Verb: {
304 // how close should the quads be to the original conic?
305 const SkScalar tol = SK_Scalar1 / 4;
306 const SkPoint* quadPts = converter.computeQuads(pts,
307 iter.conicWeight(), tol);
308 for (int i = 0; i < converter.countQuads(); ++i) {
309 int level = compute_quad_level(quadPts);
310 hairquad(quadPts, clip, blitter, level, lineproc);
311 quadPts += 2;
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000312 }
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000313 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 }
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000315 case SkPath::kCubic_Verb:
316 haircubic(pts, clip, blitter, kMaxCubicSubdivideLevel, lineproc);
317 break;
reed@google.com4e05fd22013-06-10 18:58:11 +0000318 case SkPath::kClose_Verb:
319 break;
320 case SkPath::kDone_Verb:
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000321 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322 }
323 }
324}
325
reed@google.com045e62d2011-10-24 12:19:46 +0000326void SkScan::HairPath(const SkPath& path, const SkRasterClip& clip,
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000327 SkBlitter* blitter) {
reed@google.com045e62d2011-10-24 12:19:46 +0000328 hair_path(path, clip, blitter, SkScan::HairLineRgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329}
330
reed@google.com045e62d2011-10-24 12:19:46 +0000331void SkScan::AntiHairPath(const SkPath& path, const SkRasterClip& clip,
mike@reedtribe.org69bc9942011-04-20 10:56:02 +0000332 SkBlitter* blitter) {
reed@google.com045e62d2011-10-24 12:19:46 +0000333 hair_path(path, clip, blitter, SkScan::AntiHairLineRgn);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000334}
335
reed@google.com761fb622011-04-04 18:58:05 +0000336///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337
reed@google.com761fb622011-04-04 18:58:05 +0000338void SkScan::FrameRect(const SkRect& r, const SkPoint& strokeSize,
reed@google.com045e62d2011-10-24 12:19:46 +0000339 const SkRasterClip& clip, SkBlitter* blitter) {
reed@google.com761fb622011-04-04 18:58:05 +0000340 SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341
reed@google.com761fb622011-04-04 18:58:05 +0000342 if (strokeSize.fX < 0 || strokeSize.fY < 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343 return;
reed@google.com761fb622011-04-04 18:58:05 +0000344 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345
reed@google.com761fb622011-04-04 18:58:05 +0000346 const SkScalar dx = strokeSize.fX;
347 const SkScalar dy = strokeSize.fY;
348 SkScalar rx = SkScalarHalf(dx);
349 SkScalar ry = SkScalarHalf(dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 SkRect outer, tmp;
351
reed@google.com761fb622011-04-04 18:58:05 +0000352 outer.set(r.fLeft - rx, r.fTop - ry,
353 r.fRight + rx, r.fBottom + ry);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354
reed@google.com761fb622011-04-04 18:58:05 +0000355 if (r.width() <= dx || r.height() <= dx) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 SkScan::FillRect(outer, clip, blitter);
357 return;
358 }
359
reed@google.com761fb622011-04-04 18:58:05 +0000360 tmp.set(outer.fLeft, outer.fTop, outer.fRight, outer.fTop + dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 SkScan::FillRect(tmp, clip, blitter);
reed@google.com761fb622011-04-04 18:58:05 +0000362 tmp.fTop = outer.fBottom - dy;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363 tmp.fBottom = outer.fBottom;
364 SkScan::FillRect(tmp, clip, blitter);
365
reed@google.com761fb622011-04-04 18:58:05 +0000366 tmp.set(outer.fLeft, outer.fTop + dy, outer.fLeft + dx, outer.fBottom - dy);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367 SkScan::FillRect(tmp, clip, blitter);
reed@google.com761fb622011-04-04 18:58:05 +0000368 tmp.fLeft = outer.fRight - dx;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369 tmp.fRight = outer.fRight;
370 SkScan::FillRect(tmp, clip, blitter);
371}
372
reed@google.com045e62d2011-10-24 12:19:46 +0000373void SkScan::HairLine(const SkPoint& p0, const SkPoint& p1,
374 const SkRasterClip& clip, SkBlitter* blitter) {
375 if (clip.isBW()) {
376 HairLineRgn(p0, p1, &clip.bwRgn(), blitter);
377 } else {
378 const SkRegion* clipRgn = NULL;
379 SkRect r;
380 SkIRect ir;
381 r.set(p0.fX, p0.fY, p1.fX, p1.fY);
382 r.sort();
383 r.inset(-SK_ScalarHalf, -SK_ScalarHalf);
384 r.roundOut(&ir);
385
386 SkAAClipBlitterWrapper wrap;
387 if (!clip.quickContains(ir)) {
388 wrap.init(clip, blitter);
389 blitter = wrap.getBlitter();
390 clipRgn = &wrap.getRgn();
391 }
392 HairLineRgn(p0, p1, clipRgn, blitter);
393 }
394}
395
396void SkScan::AntiHairLine(const SkPoint& p0, const SkPoint& p1,
397 const SkRasterClip& clip, SkBlitter* blitter) {
398 if (clip.isBW()) {
399 AntiHairLineRgn(p0, p1, &clip.bwRgn(), blitter);
400 } else {
401 const SkRegion* clipRgn = NULL;
402 SkRect r;
403 SkIRect ir;
404 r.set(p0.fX, p0.fY, p1.fX, p1.fY);
405 r.sort();
406 r.roundOut(&ir);
407 ir.inset(-1, -1);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000408
reed@google.com045e62d2011-10-24 12:19:46 +0000409 SkAAClipBlitterWrapper wrap;
410 if (!clip.quickContains(ir)) {
411 wrap.init(clip, blitter);
412 blitter = wrap.getBlitter();
413 clipRgn = &wrap.getRgn();
414 }
415 AntiHairLineRgn(p0, p1, clipRgn, blitter);
416 }
417}