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