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