1
2 /*
3 * Copyright 2011 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 #include "SkScan.h"
11 #include "SkBlitter.h"
12 #include "SkColorPriv.h"
13 #include "SkLineClipper.h"
14 #include "SkRasterClip.h"
15 #include "SkFDot6.h"
16
17 /* Our attempt to compute the worst case "bounds" for the horizontal and
18 vertical cases has some numerical bug in it, and we sometimes undervalue
19 our extends. The bug is that when this happens, we will set the clip to
20 NULL (for speed), and thus draw outside of the clip by a pixel, which might
21 only look bad, but it might also access memory outside of the valid range
22 allcoated for the device bitmap.
23
24 This define enables our fix to outset our "bounds" by 1, thus avoiding the
25 chance of the bug, but at the cost of sometimes taking the rectblitter
26 case (i.e. not setting the clip to NULL) when we might not actually need
27 to. If we can improve/fix the actual calculations, then we can remove this
28 step.
29 */
30 #define OUTSET_BEFORE_CLIP_TEST true
31
32 #define HLINE_STACK_BUFFER 100
33
SmallDot6Scale(int value,int dot6)34 static inline int SmallDot6Scale(int value, int dot6) {
35 SkASSERT((int16_t)value == value);
36 SkASSERT((unsigned)dot6 <= 64);
37 return SkMulS16(value, dot6) >> 6;
38 }
39
40 //#define TEST_GAMMA
41
42 #ifdef TEST_GAMMA
43 static uint8_t gGammaTable[256];
44 #define ApplyGamma(table, alpha) (table)[alpha]
45
build_gamma_table()46 static void build_gamma_table() {
47 static bool gInit = false;
48
49 if (gInit == false) {
50 for (int i = 0; i < 256; i++) {
51 SkFixed n = i * 257;
52 n += n >> 15;
53 SkASSERT(n >= 0 && n <= SK_Fixed1);
54 n = SkFixedSqrt(n);
55 n = n * 255 >> 16;
56 // SkDebugf("morph %d -> %d\n", i, n);
57 gGammaTable[i] = SkToU8(n);
58 }
59 gInit = true;
60 }
61 }
62 #else
63 #define ApplyGamma(table, alpha) SkToU8(alpha)
64 #endif
65
66 ///////////////////////////////////////////////////////////////////////////////
67
call_hline_blitter(SkBlitter * blitter,int x,int y,int count,U8CPU alpha)68 static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count,
69 U8CPU alpha) {
70 SkASSERT(count > 0);
71
72 int16_t runs[HLINE_STACK_BUFFER + 1];
73 uint8_t aa[HLINE_STACK_BUFFER];
74
75 aa[0] = ApplyGamma(gGammaTable, alpha);
76 do {
77 int n = count;
78 if (n > HLINE_STACK_BUFFER) {
79 n = HLINE_STACK_BUFFER;
80 }
81 runs[0] = SkToS16(n);
82 runs[n] = 0;
83 blitter->blitAntiH(x, y, aa, runs);
84 x += n;
85 count -= n;
86 } while (count > 0);
87 }
88
89 class SkAntiHairBlitter {
90 public:
SkAntiHairBlitter()91 SkAntiHairBlitter() : fBlitter(NULL) {}
~SkAntiHairBlitter()92 virtual ~SkAntiHairBlitter() {}
93
getBlitter() const94 SkBlitter* getBlitter() const { return fBlitter; }
95
setup(SkBlitter * blitter)96 void setup(SkBlitter* blitter) {
97 fBlitter = blitter;
98 }
99
100 virtual SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) = 0;
101 virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed slope) = 0;
102
103 private:
104 SkBlitter* fBlitter;
105 };
106
107 class HLine_SkAntiHairBlitter : public SkAntiHairBlitter {
108 public:
drawCap(int x,SkFixed fy,SkFixed slope,int mod64)109 SkFixed drawCap(int x, SkFixed fy, SkFixed slope, int mod64) override {
110 fy += SK_Fixed1/2;
111
112 int y = fy >> 16;
113 uint8_t a = (uint8_t)(fy >> 8);
114
115 // lower line
116 unsigned ma = SmallDot6Scale(a, mod64);
117 if (ma) {
118 call_hline_blitter(this->getBlitter(), x, y, 1, ma);
119 }
120
121 // upper line
122 ma = SmallDot6Scale(255 - a, mod64);
123 if (ma) {
124 call_hline_blitter(this->getBlitter(), x, y - 1, 1, ma);
125 }
126
127 return fy - SK_Fixed1/2;
128 }
129
drawLine(int x,int stopx,SkFixed fy,SkFixed slope)130 virtual SkFixed drawLine(int x, int stopx, SkFixed fy,
131 SkFixed slope) override {
132 SkASSERT(x < stopx);
133 int count = stopx - x;
134 fy += SK_Fixed1/2;
135
136 int y = fy >> 16;
137 uint8_t a = (uint8_t)(fy >> 8);
138
139 // lower line
140 if (a) {
141 call_hline_blitter(this->getBlitter(), x, y, count, a);
142 }
143
144 // upper line
145 a = 255 - a;
146 if (a) {
147 call_hline_blitter(this->getBlitter(), x, y - 1, count, a);
148 }
149
150 return fy - SK_Fixed1/2;
151 }
152 };
153
154 class Horish_SkAntiHairBlitter : public SkAntiHairBlitter {
155 public:
drawCap(int x,SkFixed fy,SkFixed dy,int mod64)156 SkFixed drawCap(int x, SkFixed fy, SkFixed dy, int mod64) override {
157 fy += SK_Fixed1/2;
158
159 int lower_y = fy >> 16;
160 uint8_t a = (uint8_t)(fy >> 8);
161 unsigned a0 = SmallDot6Scale(255 - a, mod64);
162 unsigned a1 = SmallDot6Scale(a, mod64);
163 this->getBlitter()->blitAntiV2(x, lower_y - 1, a0, a1);
164
165 return fy + dy - SK_Fixed1/2;
166 }
167
drawLine(int x,int stopx,SkFixed fy,SkFixed dy)168 SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed dy) override {
169 SkASSERT(x < stopx);
170
171 fy += SK_Fixed1/2;
172 SkBlitter* blitter = this->getBlitter();
173 do {
174 int lower_y = fy >> 16;
175 uint8_t a = (uint8_t)(fy >> 8);
176 blitter->blitAntiV2(x, lower_y - 1, 255 - a, a);
177 fy += dy;
178 } while (++x < stopx);
179
180 return fy - SK_Fixed1/2;
181 }
182 };
183
184 class VLine_SkAntiHairBlitter : public SkAntiHairBlitter {
185 public:
drawCap(int y,SkFixed fx,SkFixed dx,int mod64)186 SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) override {
187 SkASSERT(0 == dx);
188 fx += SK_Fixed1/2;
189
190 int x = fx >> 16;
191 int a = (uint8_t)(fx >> 8);
192
193 unsigned ma = SmallDot6Scale(a, mod64);
194 if (ma) {
195 this->getBlitter()->blitV(x, y, 1, ma);
196 }
197 ma = SmallDot6Scale(255 - a, mod64);
198 if (ma) {
199 this->getBlitter()->blitV(x - 1, y, 1, ma);
200 }
201
202 return fx - SK_Fixed1/2;
203 }
204
drawLine(int y,int stopy,SkFixed fx,SkFixed dx)205 SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) override {
206 SkASSERT(y < stopy);
207 SkASSERT(0 == dx);
208 fx += SK_Fixed1/2;
209
210 int x = fx >> 16;
211 int a = (uint8_t)(fx >> 8);
212
213 if (a) {
214 this->getBlitter()->blitV(x, y, stopy - y, a);
215 }
216 a = 255 - a;
217 if (a) {
218 this->getBlitter()->blitV(x - 1, y, stopy - y, a);
219 }
220
221 return fx - SK_Fixed1/2;
222 }
223 };
224
225 class Vertish_SkAntiHairBlitter : public SkAntiHairBlitter {
226 public:
drawCap(int y,SkFixed fx,SkFixed dx,int mod64)227 SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) override {
228 fx += SK_Fixed1/2;
229
230 int x = fx >> 16;
231 uint8_t a = (uint8_t)(fx >> 8);
232 this->getBlitter()->blitAntiH2(x - 1, y,
233 SmallDot6Scale(255 - a, mod64), SmallDot6Scale(a, mod64));
234
235 return fx + dx - SK_Fixed1/2;
236 }
237
drawLine(int y,int stopy,SkFixed fx,SkFixed dx)238 SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) override {
239 SkASSERT(y < stopy);
240 fx += SK_Fixed1/2;
241 do {
242 int x = fx >> 16;
243 uint8_t a = (uint8_t)(fx >> 8);
244 this->getBlitter()->blitAntiH2(x - 1, y, 255 - a, a);
245 fx += dx;
246 } while (++y < stopy);
247
248 return fx - SK_Fixed1/2;
249 }
250 };
251
fastfixdiv(SkFDot6 a,SkFDot6 b)252 static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) {
253 SkASSERT((a << 16 >> 16) == a);
254 SkASSERT(b != 0);
255 return (a << 16) / b;
256 }
257
258 #define SkBITCOUNT(x) (sizeof(x) << 3)
259
260 #if 1
261 // returns high-bit set iff x==0x8000...
bad_int(int x)262 static inline int bad_int(int x) {
263 return x & -x;
264 }
265
any_bad_ints(int a,int b,int c,int d)266 static int any_bad_ints(int a, int b, int c, int d) {
267 return (bad_int(a) | bad_int(b) | bad_int(c) | bad_int(d)) >> (SkBITCOUNT(int) - 1);
268 }
269 #else
good_int(int x)270 static inline int good_int(int x) {
271 return x ^ (1 << (SkBITCOUNT(x) - 1));
272 }
273
any_bad_ints(int a,int b,int c,int d)274 static int any_bad_ints(int a, int b, int c, int d) {
275 return !(good_int(a) & good_int(b) & good_int(c) & good_int(d));
276 }
277 #endif
278
279 #ifdef SK_DEBUG
canConvertFDot6ToFixed(SkFDot6 x)280 static bool canConvertFDot6ToFixed(SkFDot6 x) {
281 const int maxDot6 = SK_MaxS32 >> (16 - 6);
282 return SkAbs32(x) <= maxDot6;
283 }
284 #endif
285
286 /*
287 * We want the fractional part of ordinate, but we want multiples of 64 to
288 * return 64, not 0, so we can't just say (ordinate & 63).
289 * We basically want to compute those bits, and if they're 0, return 64.
290 * We can do that w/o a branch with an extra sub and add.
291 */
contribution_64(SkFDot6 ordinate)292 static int contribution_64(SkFDot6 ordinate) {
293 #if 0
294 int result = ordinate & 63;
295 if (0 == result) {
296 result = 64;
297 }
298 #else
299 int result = ((ordinate - 1) & 63) + 1;
300 #endif
301 SkASSERT(result > 0 && result <= 64);
302 return result;
303 }
304
do_anti_hairline(SkFDot6 x0,SkFDot6 y0,SkFDot6 x1,SkFDot6 y1,const SkIRect * clip,SkBlitter * blitter)305 static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
306 const SkIRect* clip, SkBlitter* blitter) {
307 // check for integer NaN (0x80000000) which we can't handle (can't negate it)
308 // It appears typically from a huge float (inf or nan) being converted to int.
309 // If we see it, just don't draw.
310 if (any_bad_ints(x0, y0, x1, y1)) {
311 return;
312 }
313
314 // The caller must clip the line to [-32767.0 ... 32767.0] ahead of time
315 // (in dot6 format)
316 SkASSERT(canConvertFDot6ToFixed(x0));
317 SkASSERT(canConvertFDot6ToFixed(y0));
318 SkASSERT(canConvertFDot6ToFixed(x1));
319 SkASSERT(canConvertFDot6ToFixed(y1));
320
321 if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511)) {
322 /* instead of (x0 + x1) >> 1, we shift each separately. This is less
323 precise, but avoids overflowing the intermediate result if the
324 values are huge. A better fix might be to clip the original pts
325 directly (i.e. do the divide), so we don't spend time subdividing
326 huge lines at all.
327 */
328 int hx = (x0 >> 1) + (x1 >> 1);
329 int hy = (y0 >> 1) + (y1 >> 1);
330 do_anti_hairline(x0, y0, hx, hy, clip, blitter);
331 do_anti_hairline(hx, hy, x1, y1, clip, blitter);
332 return;
333 }
334
335 int scaleStart, scaleStop;
336 int istart, istop;
337 SkFixed fstart, slope;
338
339 HLine_SkAntiHairBlitter hline_blitter;
340 Horish_SkAntiHairBlitter horish_blitter;
341 VLine_SkAntiHairBlitter vline_blitter;
342 Vertish_SkAntiHairBlitter vertish_blitter;
343 SkAntiHairBlitter* hairBlitter = NULL;
344
345 if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) { // mostly horizontal
346 if (x0 > x1) { // we want to go left-to-right
347 SkTSwap<SkFDot6>(x0, x1);
348 SkTSwap<SkFDot6>(y0, y1);
349 }
350
351 istart = SkFDot6Floor(x0);
352 istop = SkFDot6Ceil(x1);
353 fstart = SkFDot6ToFixed(y0);
354 if (y0 == y1) { // completely horizontal, take fast case
355 slope = 0;
356 hairBlitter = &hline_blitter;
357 } else {
358 slope = fastfixdiv(y1 - y0, x1 - x0);
359 SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1);
360 fstart += (slope * (32 - (x0 & 63)) + 32) >> 6;
361 hairBlitter = &horish_blitter;
362 }
363
364 SkASSERT(istop > istart);
365 if (istop - istart == 1) {
366 // we are within a single pixel
367 scaleStart = x1 - x0;
368 SkASSERT(scaleStart >= 0 && scaleStart <= 64);
369 scaleStop = 0;
370 } else {
371 scaleStart = 64 - (x0 & 63);
372 scaleStop = x1 & 63;
373 }
374
375 if (clip){
376 if (istart >= clip->fRight || istop <= clip->fLeft) {
377 return;
378 }
379 if (istart < clip->fLeft) {
380 fstart += slope * (clip->fLeft - istart);
381 istart = clip->fLeft;
382 scaleStart = 64;
383 if (istop - istart == 1) {
384 // we are within a single pixel
385 scaleStart = contribution_64(x1);
386 scaleStop = 0;
387 }
388 }
389 if (istop > clip->fRight) {
390 istop = clip->fRight;
391 scaleStop = 0; // so we don't draw this last column
392 }
393
394 SkASSERT(istart <= istop);
395 if (istart == istop) {
396 return;
397 }
398 // now test if our Y values are completely inside the clip
399 int top, bottom;
400 if (slope >= 0) { // T2B
401 top = SkFixedFloorToInt(fstart - SK_FixedHalf);
402 bottom = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
403 } else { // B2T
404 bottom = SkFixedCeilToInt(fstart + SK_FixedHalf);
405 top = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
406 }
407 #ifdef OUTSET_BEFORE_CLIP_TEST
408 top -= 1;
409 bottom += 1;
410 #endif
411 if (top >= clip->fBottom || bottom <= clip->fTop) {
412 return;
413 }
414 if (clip->fTop <= top && clip->fBottom >= bottom) {
415 clip = NULL;
416 }
417 }
418 } else { // mostly vertical
419 if (y0 > y1) { // we want to go top-to-bottom
420 SkTSwap<SkFDot6>(x0, x1);
421 SkTSwap<SkFDot6>(y0, y1);
422 }
423
424 istart = SkFDot6Floor(y0);
425 istop = SkFDot6Ceil(y1);
426 fstart = SkFDot6ToFixed(x0);
427 if (x0 == x1) {
428 if (y0 == y1) { // are we zero length?
429 return; // nothing to do
430 }
431 slope = 0;
432 hairBlitter = &vline_blitter;
433 } else {
434 slope = fastfixdiv(x1 - x0, y1 - y0);
435 SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1);
436 fstart += (slope * (32 - (y0 & 63)) + 32) >> 6;
437 hairBlitter = &vertish_blitter;
438 }
439
440 SkASSERT(istop > istart);
441 if (istop - istart == 1) {
442 // we are within a single pixel
443 scaleStart = y1 - y0;
444 SkASSERT(scaleStart >= 0 && scaleStart <= 64);
445 scaleStop = 0;
446 } else {
447 scaleStart = 64 - (y0 & 63);
448 scaleStop = y1 & 63;
449 }
450
451 if (clip) {
452 if (istart >= clip->fBottom || istop <= clip->fTop) {
453 return;
454 }
455 if (istart < clip->fTop) {
456 fstart += slope * (clip->fTop - istart);
457 istart = clip->fTop;
458 scaleStart = 64;
459 if (istop - istart == 1) {
460 // we are within a single pixel
461 scaleStart = contribution_64(y1);
462 scaleStop = 0;
463 }
464 }
465 if (istop > clip->fBottom) {
466 istop = clip->fBottom;
467 scaleStop = 0; // so we don't draw this last row
468 }
469
470 SkASSERT(istart <= istop);
471 if (istart == istop)
472 return;
473
474 // now test if our X values are completely inside the clip
475 int left, right;
476 if (slope >= 0) { // L2R
477 left = SkFixedFloorToInt(fstart - SK_FixedHalf);
478 right = SkFixedCeilToInt(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
479 } else { // R2L
480 right = SkFixedCeilToInt(fstart + SK_FixedHalf);
481 left = SkFixedFloorToInt(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
482 }
483 #ifdef OUTSET_BEFORE_CLIP_TEST
484 left -= 1;
485 right += 1;
486 #endif
487 if (left >= clip->fRight || right <= clip->fLeft) {
488 return;
489 }
490 if (clip->fLeft <= left && clip->fRight >= right) {
491 clip = NULL;
492 }
493 }
494 }
495
496 SkRectClipBlitter rectClipper;
497 if (clip) {
498 rectClipper.init(blitter, *clip);
499 blitter = &rectClipper;
500 }
501
502 SkASSERT(hairBlitter);
503 hairBlitter->setup(blitter);
504
505 #ifdef SK_DEBUG
506 if (scaleStart > 0 && scaleStop > 0) {
507 // be sure we don't draw twice in the same pixel
508 SkASSERT(istart < istop - 1);
509 }
510 #endif
511
512 fstart = hairBlitter->drawCap(istart, fstart, slope, scaleStart);
513 istart += 1;
514 int fullSpans = istop - istart - (scaleStop > 0);
515 if (fullSpans > 0) {
516 fstart = hairBlitter->drawLine(istart, istart + fullSpans, fstart, slope);
517 }
518 if (scaleStop > 0) {
519 hairBlitter->drawCap(istop - 1, fstart, slope, scaleStop);
520 }
521 }
522
AntiHairLineRgn(const SkPoint array[],int arrayCount,const SkRegion * clip,SkBlitter * blitter)523 void SkScan::AntiHairLineRgn(const SkPoint array[], int arrayCount, const SkRegion* clip,
524 SkBlitter* blitter) {
525 if (clip && clip->isEmpty()) {
526 return;
527 }
528
529 SkASSERT(clip == NULL || !clip->getBounds().isEmpty());
530
531 #ifdef TEST_GAMMA
532 build_gamma_table();
533 #endif
534
535 const SkScalar max = SkIntToScalar(32767);
536 const SkRect fixedBounds = SkRect::MakeLTRB(-max, -max, max, max);
537
538 SkRect clipBounds;
539 if (clip) {
540 clipBounds.set(clip->getBounds());
541 /* We perform integral clipping later on, but we do a scalar clip first
542 to ensure that our coordinates are expressible in fixed/integers.
543
544 antialiased hairlines can draw up to 1/2 of a pixel outside of
545 their bounds, so we need to outset the clip before calling the
546 clipper. To make the numerics safer, we outset by a whole pixel,
547 since the 1/2 pixel boundary is important to the antihair blitter,
548 we don't want to risk numerical fate by chopping on that edge.
549 */
550 clipBounds.outset(SK_Scalar1, SK_Scalar1);
551 }
552
553 for (int i = 0; i < arrayCount - 1; ++i) {
554 SkPoint pts[2];
555
556 // We have to pre-clip the line to fit in a SkFixed, so we just chop
557 // the line. TODO find a way to actually draw beyond that range.
558 if (!SkLineClipper::IntersectLine(&array[i], fixedBounds, pts)) {
559 continue;
560 }
561
562 if (clip && !SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
563 continue;
564 }
565
566 SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
567 SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
568 SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
569 SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
570
571 if (clip) {
572 SkFDot6 left = SkMin32(x0, x1);
573 SkFDot6 top = SkMin32(y0, y1);
574 SkFDot6 right = SkMax32(x0, x1);
575 SkFDot6 bottom = SkMax32(y0, y1);
576 SkIRect ir;
577
578 ir.set( SkFDot6Floor(left) - 1,
579 SkFDot6Floor(top) - 1,
580 SkFDot6Ceil(right) + 1,
581 SkFDot6Ceil(bottom) + 1);
582
583 if (clip->quickReject(ir)) {
584 continue;
585 }
586 if (!clip->quickContains(ir)) {
587 SkRegion::Cliperator iter(*clip, ir);
588 const SkIRect* r = &iter.rect();
589
590 while (!iter.done()) {
591 do_anti_hairline(x0, y0, x1, y1, r, blitter);
592 iter.next();
593 }
594 continue;
595 }
596 // fall through to no-clip case
597 }
598 do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
599 }
600 }
601
AntiHairRect(const SkRect & rect,const SkRasterClip & clip,SkBlitter * blitter)602 void SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
603 SkBlitter* blitter) {
604 SkPoint pts[5];
605
606 pts[0].set(rect.fLeft, rect.fTop);
607 pts[1].set(rect.fRight, rect.fTop);
608 pts[2].set(rect.fRight, rect.fBottom);
609 pts[3].set(rect.fLeft, rect.fBottom);
610 pts[4] = pts[0];
611 SkScan::AntiHairLine(pts, 5, clip, blitter);
612 }
613
614 ///////////////////////////////////////////////////////////////////////////////
615
616 typedef int FDot8; // 24.8 integer fixed point
617
SkFixedToFDot8(SkFixed x)618 static inline FDot8 SkFixedToFDot8(SkFixed x) {
619 return (x + 0x80) >> 8;
620 }
621
do_scanline(FDot8 L,int top,FDot8 R,U8CPU alpha,SkBlitter * blitter)622 static void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
623 SkBlitter* blitter) {
624 SkASSERT(L < R);
625
626 if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel
627 blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L));
628 return;
629 }
630
631 int left = L >> 8;
632
633 if (L & 0xFF) {
634 blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF)));
635 left += 1;
636 }
637
638 int rite = R >> 8;
639 int width = rite - left;
640 if (width > 0) {
641 call_hline_blitter(blitter, left, top, width, alpha);
642 }
643 if (R & 0xFF) {
644 blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF));
645 }
646 }
647
antifilldot8(FDot8 L,FDot8 T,FDot8 R,FDot8 B,SkBlitter * blitter,bool fillInner)648 static void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter,
649 bool fillInner) {
650 // check for empty now that we're in our reduced precision space
651 if (L >= R || T >= B) {
652 return;
653 }
654 int top = T >> 8;
655 if (top == ((B - 1) >> 8)) { // just one scanline high
656 do_scanline(L, top, R, B - T - 1, blitter);
657 return;
658 }
659
660 if (T & 0xFF) {
661 do_scanline(L, top, R, 256 - (T & 0xFF), blitter);
662 top += 1;
663 }
664
665 int bot = B >> 8;
666 int height = bot - top;
667 if (height > 0) {
668 int left = L >> 8;
669 if (left == ((R - 1) >> 8)) { // just 1-pixel wide
670 blitter->blitV(left, top, height, R - L - 1);
671 } else {
672 if (L & 0xFF) {
673 blitter->blitV(left, top, height, 256 - (L & 0xFF));
674 left += 1;
675 }
676 int rite = R >> 8;
677 int width = rite - left;
678 if (width > 0 && fillInner) {
679 blitter->blitRect(left, top, width, height);
680 }
681 if (R & 0xFF) {
682 blitter->blitV(rite, top, height, R & 0xFF);
683 }
684 }
685 }
686
687 if (B & 0xFF) {
688 do_scanline(L, bot, R, B & 0xFF, blitter);
689 }
690 }
691
antifillrect(const SkXRect & xr,SkBlitter * blitter)692 static void antifillrect(const SkXRect& xr, SkBlitter* blitter) {
693 antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop),
694 SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom),
695 blitter, true);
696 }
697
698 ///////////////////////////////////////////////////////////////////////////////
699
AntiFillXRect(const SkXRect & xr,const SkRegion * clip,SkBlitter * blitter)700 void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
701 SkBlitter* blitter) {
702 if (NULL == clip) {
703 antifillrect(xr, blitter);
704 } else {
705 SkIRect outerBounds;
706 XRect_roundOut(xr, &outerBounds);
707
708 if (clip->isRect()) {
709 const SkIRect& clipBounds = clip->getBounds();
710
711 if (clipBounds.contains(outerBounds)) {
712 antifillrect(xr, blitter);
713 } else {
714 SkXRect tmpR;
715 // this keeps our original edges fractional
716 XRect_set(&tmpR, clipBounds);
717 if (tmpR.intersect(xr)) {
718 antifillrect(tmpR, blitter);
719 }
720 }
721 } else {
722 SkRegion::Cliperator clipper(*clip, outerBounds);
723 const SkIRect& rr = clipper.rect();
724
725 while (!clipper.done()) {
726 SkXRect tmpR;
727
728 // this keeps our original edges fractional
729 XRect_set(&tmpR, rr);
730 if (tmpR.intersect(xr)) {
731 antifillrect(tmpR, blitter);
732 }
733 clipper.next();
734 }
735 }
736 }
737 }
738
AntiFillXRect(const SkXRect & xr,const SkRasterClip & clip,SkBlitter * blitter)739 void SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip,
740 SkBlitter* blitter) {
741 if (clip.isBW()) {
742 AntiFillXRect(xr, &clip.bwRgn(), blitter);
743 } else {
744 SkIRect outerBounds;
745 XRect_roundOut(xr, &outerBounds);
746
747 if (clip.quickContains(outerBounds)) {
748 AntiFillXRect(xr, NULL, blitter);
749 } else {
750 SkAAClipBlitterWrapper wrapper(clip, blitter);
751 blitter = wrapper.getBlitter();
752
753 AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
754 }
755 }
756 }
757
758 /* This guy takes a float-rect, but with the key improvement that it has
759 already been clipped, so we know that it is safe to convert it into a
760 XRect (fixedpoint), as it won't overflow.
761 */
antifillrect(const SkRect & r,SkBlitter * blitter)762 static void antifillrect(const SkRect& r, SkBlitter* blitter) {
763 SkXRect xr;
764
765 XRect_set(&xr, r);
766 antifillrect(xr, blitter);
767 }
768
769 /* We repeat the clipping logic of AntiFillXRect because the float rect might
770 overflow if we blindly converted it to an XRect. This sucks that we have to
771 repeat the clipping logic, but I don't see how to share the code/logic.
772
773 We clip r (as needed) into one or more (smaller) float rects, and then pass
774 those to our version of antifillrect, which converts it into an XRect and
775 then calls the blit.
776 */
AntiFillRect(const SkRect & origR,const SkRegion * clip,SkBlitter * blitter)777 void SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
778 SkBlitter* blitter) {
779 if (clip) {
780 SkRect newR;
781 newR.set(clip->getBounds());
782 if (!newR.intersect(origR)) {
783 return;
784 }
785
786 const SkIRect outerBounds = newR.roundOut();
787
788 if (clip->isRect()) {
789 antifillrect(newR, blitter);
790 } else {
791 SkRegion::Cliperator clipper(*clip, outerBounds);
792 while (!clipper.done()) {
793 newR.set(clipper.rect());
794 if (newR.intersect(origR)) {
795 antifillrect(newR, blitter);
796 }
797 clipper.next();
798 }
799 }
800 } else {
801 antifillrect(origR, blitter);
802 }
803 }
804
AntiFillRect(const SkRect & r,const SkRasterClip & clip,SkBlitter * blitter)805 void SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip,
806 SkBlitter* blitter) {
807 if (clip.isBW()) {
808 AntiFillRect(r, &clip.bwRgn(), blitter);
809 } else {
810 SkAAClipBlitterWrapper wrap(clip, blitter);
811 AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter());
812 }
813 }
814
815 ///////////////////////////////////////////////////////////////////////////////
816
817 #define SkAlphaMulRound(a, b) SkMulDiv255Round(a, b)
818
819 // calls blitRect() if the rectangle is non-empty
fillcheckrect(int L,int T,int R,int B,SkBlitter * blitter)820 static void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) {
821 if (L < R && T < B) {
822 blitter->blitRect(L, T, R - L, B - T);
823 }
824 }
825
SkScalarToFDot8(SkScalar x)826 static inline FDot8 SkScalarToFDot8(SkScalar x) {
827 return (int)(x * 256);
828 }
829
FDot8Floor(FDot8 x)830 static inline int FDot8Floor(FDot8 x) {
831 return x >> 8;
832 }
833
FDot8Ceil(FDot8 x)834 static inline int FDot8Ceil(FDot8 x) {
835 return (x + 0xFF) >> 8;
836 }
837
838 // 1 - (1 - a)*(1 - b)
InvAlphaMul(U8CPU a,U8CPU b)839 static inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) {
840 // need precise rounding (not just SkAlphaMul) so that values like
841 // a=228, b=252 don't overflow the result
842 return SkToU8(a + b - SkAlphaMulRound(a, b));
843 }
844
inner_scanline(FDot8 L,int top,FDot8 R,U8CPU alpha,SkBlitter * blitter)845 static void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
846 SkBlitter* blitter) {
847 SkASSERT(L < R);
848
849 if ((L >> 8) == ((R - 1) >> 8)) { // 1x1 pixel
850 blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L));
851 return;
852 }
853
854 int left = L >> 8;
855 if (L & 0xFF) {
856 blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
857 left += 1;
858 }
859
860 int rite = R >> 8;
861 int width = rite - left;
862 if (width > 0) {
863 call_hline_blitter(blitter, left, top, width, alpha);
864 }
865
866 if (R & 0xFF) {
867 blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
868 }
869 }
870
innerstrokedot8(FDot8 L,FDot8 T,FDot8 R,FDot8 B,SkBlitter * blitter)871 static void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B,
872 SkBlitter* blitter) {
873 SkASSERT(L < R && T < B);
874
875 int top = T >> 8;
876 if (top == ((B - 1) >> 8)) { // just one scanline high
877 // We want the inverse of B-T, since we're the inner-stroke
878 int alpha = 256 - (B - T);
879 if (alpha) {
880 inner_scanline(L, top, R, alpha, blitter);
881 }
882 return;
883 }
884
885 if (T & 0xFF) {
886 inner_scanline(L, top, R, T & 0xFF, blitter);
887 top += 1;
888 }
889
890 int bot = B >> 8;
891 int height = bot - top;
892 if (height > 0) {
893 if (L & 0xFF) {
894 blitter->blitV(L >> 8, top, height, L & 0xFF);
895 }
896 if (R & 0xFF) {
897 blitter->blitV(R >> 8, top, height, ~R & 0xFF);
898 }
899 }
900
901 if (B & 0xFF) {
902 inner_scanline(L, bot, R, ~B & 0xFF, blitter);
903 }
904 }
905
align_thin_stroke(FDot8 & edge1,FDot8 & edge2)906 static inline void align_thin_stroke(FDot8& edge1, FDot8& edge2) {
907 SkASSERT(edge1 <= edge2);
908
909 if (FDot8Floor(edge1) == FDot8Floor(edge2)) {
910 edge2 -= (edge1 & 0xFF);
911 edge1 &= ~0xFF;
912 }
913 }
914
AntiFrameRect(const SkRect & r,const SkPoint & strokeSize,const SkRegion * clip,SkBlitter * blitter)915 void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
916 const SkRegion* clip, SkBlitter* blitter) {
917 SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
918
919 SkScalar rx = SkScalarHalf(strokeSize.fX);
920 SkScalar ry = SkScalarHalf(strokeSize.fY);
921
922 // outset by the radius
923 FDot8 outerL = SkScalarToFDot8(r.fLeft - rx);
924 FDot8 outerT = SkScalarToFDot8(r.fTop - ry);
925 FDot8 outerR = SkScalarToFDot8(r.fRight + rx);
926 FDot8 outerB = SkScalarToFDot8(r.fBottom + ry);
927
928 SkIRect outer;
929 // set outer to the outer rect of the outer section
930 outer.set(FDot8Floor(outerL), FDot8Floor(outerT), FDot8Ceil(outerR), FDot8Ceil(outerB));
931
932 SkBlitterClipper clipper;
933 if (clip) {
934 if (clip->quickReject(outer)) {
935 return;
936 }
937 if (!clip->contains(outer)) {
938 blitter = clipper.apply(blitter, clip, &outer);
939 }
940 // now we can ignore clip for the rest of the function
941 }
942
943 // in case we lost a bit with diameter/2
944 rx = strokeSize.fX - rx;
945 ry = strokeSize.fY - ry;
946
947 // inset by the radius
948 FDot8 innerL = SkScalarToFDot8(r.fLeft + rx);
949 FDot8 innerT = SkScalarToFDot8(r.fTop + ry);
950 FDot8 innerR = SkScalarToFDot8(r.fRight - rx);
951 FDot8 innerB = SkScalarToFDot8(r.fBottom - ry);
952
953 // For sub-unit strokes, tweak the hulls such that one of the edges coincides with the pixel
954 // edge. This ensures that the general rect stroking logic below
955 // a) doesn't blit the same scanline twice
956 // b) computes the correct coverage when both edges fall within the same pixel
957 if (strokeSize.fX < 1 || strokeSize.fY < 1) {
958 align_thin_stroke(outerL, innerL);
959 align_thin_stroke(outerT, innerT);
960 align_thin_stroke(innerR, outerR);
961 align_thin_stroke(innerB, outerB);
962 }
963
964 // stroke the outer hull
965 antifilldot8(outerL, outerT, outerR, outerB, blitter, false);
966
967 // set outer to the outer rect of the middle section
968 outer.set(FDot8Ceil(outerL), FDot8Ceil(outerT), FDot8Floor(outerR), FDot8Floor(outerB));
969
970 if (innerL >= innerR || innerT >= innerB) {
971 fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom,
972 blitter);
973 } else {
974 SkIRect inner;
975 // set inner to the inner rect of the middle section
976 inner.set(FDot8Floor(innerL), FDot8Floor(innerT), FDot8Ceil(innerR), FDot8Ceil(innerB));
977
978 // draw the frame in 4 pieces
979 fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop,
980 blitter);
981 fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom,
982 blitter);
983 fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom,
984 blitter);
985 fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom,
986 blitter);
987
988 // now stroke the inner rect, which is similar to antifilldot8() except that
989 // it treats the fractional coordinates with the inverse bias (since its
990 // inner).
991 innerstrokedot8(innerL, innerT, innerR, innerB, blitter);
992 }
993 }
994
AntiFrameRect(const SkRect & r,const SkPoint & strokeSize,const SkRasterClip & clip,SkBlitter * blitter)995 void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
996 const SkRasterClip& clip, SkBlitter* blitter) {
997 if (clip.isBW()) {
998 AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter);
999 } else {
1000 SkAAClipBlitterWrapper wrap(clip, blitter);
1001 AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter());
1002 }
1003 }
1004