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