Home | History | Annotate | Download | only in core
      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     nullptr (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 nullptr) 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 
     34 static inline int SmallDot6Scale(int value, int dot6) {
     35     SkASSERT((int16_t)value == value);
     36     SkASSERT((unsigned)dot6 <= 64);
     37     return (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 
     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 
     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:
     91     SkAntiHairBlitter() : fBlitter(nullptr) {}
     92     virtual ~SkAntiHairBlitter() {}
     93 
     94     SkBlitter* getBlitter() const { return fBlitter; }
     95 
     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:
    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 
    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:
    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 
    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:
    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 
    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:
    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 
    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 
    252 static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) {
    253     SkASSERT((SkLeftShift(a, 16) >> 16) == a);
    254     SkASSERT(b != 0);
    255     return SkLeftShift(a, 16) / b;
    256 }
    257 
    258 #define SkBITCOUNT(x)   (sizeof(x) << 3)
    259 
    260 #if 1
    261 // returns high-bit set iff x==0x8000...
    262 static inline int bad_int(int x) {
    263     return x & -x;
    264 }
    265 
    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
    270 static inline int good_int(int x) {
    271     return x ^ (1 << (SkBITCOUNT(x) - 1));
    272 }
    273 
    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
    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  */
    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 
    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 = nullptr;
    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 = nullptr;
    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 = nullptr;
    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 
    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 == nullptr || !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, nullptr, blitter);
    599     }
    600 }
    601 
    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 
    618 static inline FDot8 SkFixedToFDot8(SkFixed x) {
    619     return (x + 0x80) >> 8;
    620 }
    621 
    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 
    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 
    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 
    700 void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
    701                           SkBlitter* blitter) {
    702     if (nullptr == 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 
    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, nullptr, 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 */
    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 */
    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 
    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
    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 
    826 static inline FDot8 SkScalarToFDot8(SkScalar x) {
    827     return (int)(x * 256);
    828 }
    829 
    830 static inline int FDot8Floor(FDot8 x) {
    831     return x >> 8;
    832 }
    833 
    834 static inline int FDot8Ceil(FDot8 x) {
    835     return (x + 0xFF) >> 8;
    836 }
    837 
    838 // 1 - (1 - a)*(1 - 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 
    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         FDot8 widClamp = R - L;
    851         // border case clamp 256 to 255 instead of going through call_hline_blitter
    852         // see skbug/4406
    853         widClamp = widClamp - (widClamp >> 8);
    854         blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, widClamp));
    855         return;
    856     }
    857 
    858     int left = L >> 8;
    859     if (L & 0xFF) {
    860         blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
    861         left += 1;
    862     }
    863 
    864     int rite = R >> 8;
    865     int width = rite - left;
    866     if (width > 0) {
    867         call_hline_blitter(blitter, left, top, width, alpha);
    868     }
    869 
    870     if (R & 0xFF) {
    871         blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
    872     }
    873 }
    874 
    875 static void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B,
    876                             SkBlitter* blitter) {
    877     SkASSERT(L < R && T < B);
    878 
    879     int top = T >> 8;
    880     if (top == ((B - 1) >> 8)) {   // just one scanline high
    881         // We want the inverse of B-T, since we're the inner-stroke
    882         int alpha = 256 - (B - T);
    883         if (alpha) {
    884             inner_scanline(L, top, R, alpha, blitter);
    885         }
    886         return;
    887     }
    888 
    889     if (T & 0xFF) {
    890         inner_scanline(L, top, R, T & 0xFF, blitter);
    891         top += 1;
    892     }
    893 
    894     int bot = B >> 8;
    895     int height = bot - top;
    896     if (height > 0) {
    897         if (L & 0xFF) {
    898             blitter->blitV(L >> 8, top, height, L & 0xFF);
    899         }
    900         if (R & 0xFF) {
    901             blitter->blitV(R >> 8, top, height, ~R & 0xFF);
    902         }
    903     }
    904 
    905     if (B & 0xFF) {
    906         inner_scanline(L, bot, R, ~B & 0xFF, blitter);
    907     }
    908 }
    909 
    910 static inline void align_thin_stroke(FDot8& edge1, FDot8& edge2) {
    911     SkASSERT(edge1 <= edge2);
    912 
    913     if (FDot8Floor(edge1) == FDot8Floor(edge2)) {
    914         edge2 -= (edge1 & 0xFF);
    915         edge1 &= ~0xFF;
    916     }
    917 }
    918 
    919 void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
    920                            const SkRegion* clip, SkBlitter* blitter) {
    921     SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
    922 
    923     SkScalar rx = SkScalarHalf(strokeSize.fX);
    924     SkScalar ry = SkScalarHalf(strokeSize.fY);
    925 
    926     // outset by the radius
    927     FDot8 outerL = SkScalarToFDot8(r.fLeft - rx);
    928     FDot8 outerT = SkScalarToFDot8(r.fTop - ry);
    929     FDot8 outerR = SkScalarToFDot8(r.fRight + rx);
    930     FDot8 outerB = SkScalarToFDot8(r.fBottom + ry);
    931 
    932     SkIRect outer;
    933     // set outer to the outer rect of the outer section
    934     outer.set(FDot8Floor(outerL), FDot8Floor(outerT), FDot8Ceil(outerR), FDot8Ceil(outerB));
    935 
    936     SkBlitterClipper clipper;
    937     if (clip) {
    938         if (clip->quickReject(outer)) {
    939             return;
    940         }
    941         if (!clip->contains(outer)) {
    942             blitter = clipper.apply(blitter, clip, &outer);
    943         }
    944         // now we can ignore clip for the rest of the function
    945     }
    946 
    947     // in case we lost a bit with diameter/2
    948     rx = strokeSize.fX - rx;
    949     ry = strokeSize.fY - ry;
    950 
    951     // inset by the radius
    952     FDot8 innerL = SkScalarToFDot8(r.fLeft + rx);
    953     FDot8 innerT = SkScalarToFDot8(r.fTop + ry);
    954     FDot8 innerR = SkScalarToFDot8(r.fRight - rx);
    955     FDot8 innerB = SkScalarToFDot8(r.fBottom - ry);
    956 
    957     // For sub-unit strokes, tweak the hulls such that one of the edges coincides with the pixel
    958     // edge. This ensures that the general rect stroking logic below
    959     //   a) doesn't blit the same scanline twice
    960     //   b) computes the correct coverage when both edges fall within the same pixel
    961     if (strokeSize.fX < 1 || strokeSize.fY < 1) {
    962         align_thin_stroke(outerL, innerL);
    963         align_thin_stroke(outerT, innerT);
    964         align_thin_stroke(innerR, outerR);
    965         align_thin_stroke(innerB, outerB);
    966     }
    967 
    968     // stroke the outer hull
    969     antifilldot8(outerL, outerT, outerR, outerB, blitter, false);
    970 
    971     // set outer to the outer rect of the middle section
    972     outer.set(FDot8Ceil(outerL), FDot8Ceil(outerT), FDot8Floor(outerR), FDot8Floor(outerB));
    973 
    974     if (innerL >= innerR || innerT >= innerB) {
    975         fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom,
    976                       blitter);
    977     } else {
    978         SkIRect inner;
    979         // set inner to the inner rect of the middle section
    980         inner.set(FDot8Floor(innerL), FDot8Floor(innerT), FDot8Ceil(innerR), FDot8Ceil(innerB));
    981 
    982         // draw the frame in 4 pieces
    983         fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop,
    984                       blitter);
    985         fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom,
    986                       blitter);
    987         fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom,
    988                       blitter);
    989         fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom,
    990                       blitter);
    991 
    992         // now stroke the inner rect, which is similar to antifilldot8() except that
    993         // it treats the fractional coordinates with the inverse bias (since its
    994         // inner).
    995         innerstrokedot8(innerL, innerT, innerR, innerB, blitter);
    996     }
    997 }
    998 
    999 void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
   1000                            const SkRasterClip& clip, SkBlitter* blitter) {
   1001     if (clip.isBW()) {
   1002         AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter);
   1003     } else {
   1004         SkAAClipBlitterWrapper wrap(clip, blitter);
   1005         AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter());
   1006     }
   1007 }
   1008