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 = SkFixedFloor(fstart - SK_FixedHalf);
    470                 bottom = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
    471             } else {           // B2T
    472                 bottom = SkFixedCeil(fstart + SK_FixedHalf);
    473                 top = SkFixedFloor(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 = SkFixedFloor(fstart - SK_FixedHalf);
    546                 right = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
    547             } else {           // R2L
    548                 right = SkFixedCeil(fstart + SK_FixedHalf);
    549                 left = SkFixedFloor(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 #ifdef SK_SCALAR_IS_FLOAT
    606     // We have to pre-clip the line to fit in a SkFixed, so we just chop
    607     // the line. TODO find a way to actually draw beyond that range.
    608     {
    609         SkRect fixedBounds;
    610         const SkScalar max = SkIntToScalar(32767);
    611         fixedBounds.set(-max, -max, max, max);
    612         if (!SkLineClipper::IntersectLine(pts, fixedBounds, pts)) {
    613             return;
    614         }
    615     }
    616 #endif
    617 
    618     if (clip) {
    619         SkRect clipBounds;
    620         clipBounds.set(clip->getBounds());
    621         /*  We perform integral clipping later on, but we do a scalar clip first
    622             to ensure that our coordinates are expressible in fixed/integers.
    623 
    624             antialiased hairlines can draw up to 1/2 of a pixel outside of
    625             their bounds, so we need to outset the clip before calling the
    626             clipper. To make the numerics safer, we outset by a whole pixel,
    627             since the 1/2 pixel boundary is important to the antihair blitter,
    628             we don't want to risk numerical fate by chopping on that edge.
    629          */
    630         clipBounds.inset(-SK_Scalar1, -SK_Scalar1);
    631 
    632         if (!SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
    633             return;
    634         }
    635     }
    636 
    637     SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
    638     SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
    639     SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
    640     SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
    641 
    642     if (clip) {
    643         SkFDot6 left = SkMin32(x0, x1);
    644         SkFDot6 top = SkMin32(y0, y1);
    645         SkFDot6 right = SkMax32(x0, x1);
    646         SkFDot6 bottom = SkMax32(y0, y1);
    647         SkIRect ir;
    648 
    649         ir.set( SkFDot6Floor(left) - 1,
    650                 SkFDot6Floor(top) - 1,
    651                 SkFDot6Ceil(right) + 1,
    652                 SkFDot6Ceil(bottom) + 1);
    653 
    654         if (clip->quickReject(ir)) {
    655             return;
    656         }
    657         if (!clip->quickContains(ir)) {
    658             SkRegion::Cliperator iter(*clip, ir);
    659             const SkIRect*       r = &iter.rect();
    660 
    661             while (!iter.done()) {
    662                 do_anti_hairline(x0, y0, x1, y1, r, blitter);
    663                 iter.next();
    664             }
    665             return;
    666         }
    667         // fall through to no-clip case
    668     }
    669     do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
    670 }
    671 
    672 void SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
    673                           SkBlitter* blitter) {
    674     SkPoint p0, p1;
    675 
    676     p0.set(rect.fLeft, rect.fTop);
    677     p1.set(rect.fRight, rect.fTop);
    678     SkScan::AntiHairLine(p0, p1, clip, blitter);
    679     p0.set(rect.fRight, rect.fBottom);
    680     SkScan::AntiHairLine(p0, p1, clip, blitter);
    681     p1.set(rect.fLeft, rect.fBottom);
    682     SkScan::AntiHairLine(p0, p1, clip, blitter);
    683     p0.set(rect.fLeft, rect.fTop);
    684     SkScan::AntiHairLine(p0, p1, clip, blitter);
    685 }
    686 
    687 ///////////////////////////////////////////////////////////////////////////////
    688 
    689 typedef int FDot8;  // 24.8 integer fixed point
    690 
    691 static inline FDot8 SkFixedToFDot8(SkFixed x) {
    692     return (x + 0x80) >> 8;
    693 }
    694 
    695 static void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
    696                         SkBlitter* blitter) {
    697     SkASSERT(L < R);
    698 
    699     if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
    700         blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L));
    701         return;
    702     }
    703 
    704     int left = L >> 8;
    705 
    706     if (L & 0xFF) {
    707         blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF)));
    708         left += 1;
    709     }
    710 
    711     int rite = R >> 8;
    712     int width = rite - left;
    713     if (width > 0) {
    714         call_hline_blitter(blitter, left, top, width, alpha);
    715     }
    716     if (R & 0xFF) {
    717         blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF));
    718     }
    719 }
    720 
    721 static void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter,
    722                          bool fillInner) {
    723     // check for empty now that we're in our reduced precision space
    724     if (L >= R || T >= B) {
    725         return;
    726     }
    727     int top = T >> 8;
    728     if (top == ((B - 1) >> 8)) {   // just one scanline high
    729         do_scanline(L, top, R, B - T - 1, blitter);
    730         return;
    731     }
    732 
    733     if (T & 0xFF) {
    734         do_scanline(L, top, R, 256 - (T & 0xFF), blitter);
    735         top += 1;
    736     }
    737 
    738     int bot = B >> 8;
    739     int height = bot - top;
    740     if (height > 0) {
    741         int left = L >> 8;
    742         if (left == ((R - 1) >> 8)) {   // just 1-pixel wide
    743             blitter->blitV(left, top, height, R - L - 1);
    744         } else {
    745             if (L & 0xFF) {
    746                 blitter->blitV(left, top, height, 256 - (L & 0xFF));
    747                 left += 1;
    748             }
    749             int rite = R >> 8;
    750             int width = rite - left;
    751             if (width > 0 && fillInner) {
    752                 blitter->blitRect(left, top, width, height);
    753             }
    754             if (R & 0xFF) {
    755                 blitter->blitV(rite, top, height, R & 0xFF);
    756             }
    757         }
    758     }
    759 
    760     if (B & 0xFF) {
    761         do_scanline(L, bot, R, B & 0xFF, blitter);
    762     }
    763 }
    764 
    765 static void antifillrect(const SkXRect& xr, SkBlitter* blitter) {
    766     antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop),
    767                  SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom),
    768                  blitter, true);
    769 }
    770 
    771 ///////////////////////////////////////////////////////////////////////////////
    772 
    773 void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
    774                           SkBlitter* blitter) {
    775     if (NULL == clip) {
    776         antifillrect(xr, blitter);
    777     } else {
    778         SkIRect outerBounds;
    779         XRect_roundOut(xr, &outerBounds);
    780 
    781         if (clip->isRect()) {
    782             const SkIRect& clipBounds = clip->getBounds();
    783 
    784             if (clipBounds.contains(outerBounds)) {
    785                 antifillrect(xr, blitter);
    786             } else {
    787                 SkXRect tmpR;
    788                 // this keeps our original edges fractional
    789                 XRect_set(&tmpR, clipBounds);
    790                 if (tmpR.intersect(xr)) {
    791                     antifillrect(tmpR, blitter);
    792                 }
    793             }
    794         } else {
    795             SkRegion::Cliperator clipper(*clip, outerBounds);
    796             const SkIRect&       rr = clipper.rect();
    797 
    798             while (!clipper.done()) {
    799                 SkXRect  tmpR;
    800 
    801                 // this keeps our original edges fractional
    802                 XRect_set(&tmpR, rr);
    803                 if (tmpR.intersect(xr)) {
    804                     antifillrect(tmpR, blitter);
    805                 }
    806                 clipper.next();
    807             }
    808         }
    809     }
    810 }
    811 
    812 void SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip,
    813                            SkBlitter* blitter) {
    814     if (clip.isBW()) {
    815         AntiFillXRect(xr, &clip.bwRgn(), blitter);
    816     } else {
    817         SkIRect outerBounds;
    818         XRect_roundOut(xr, &outerBounds);
    819 
    820         if (clip.quickContains(outerBounds)) {
    821             AntiFillXRect(xr, NULL, blitter);
    822         } else {
    823             SkAAClipBlitterWrapper wrapper(clip, blitter);
    824             blitter = wrapper.getBlitter();
    825 
    826             AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
    827         }
    828     }
    829 }
    830 
    831 #ifdef SK_SCALAR_IS_FLOAT
    832 
    833 /*  This guy takes a float-rect, but with the key improvement that it has
    834     already been clipped, so we know that it is safe to convert it into a
    835     XRect (fixedpoint), as it won't overflow.
    836 */
    837 static void antifillrect(const SkRect& r, SkBlitter* blitter) {
    838     SkXRect xr;
    839 
    840     XRect_set(&xr, r);
    841     antifillrect(xr, blitter);
    842 }
    843 
    844 /*  We repeat the clipping logic of AntiFillXRect because the float rect might
    845     overflow if we blindly converted it to an XRect. This sucks that we have to
    846     repeat the clipping logic, but I don't see how to share the code/logic.
    847 
    848     We clip r (as needed) into one or more (smaller) float rects, and then pass
    849     those to our version of antifillrect, which converts it into an XRect and
    850     then calls the blit.
    851 */
    852 void SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
    853                           SkBlitter* blitter) {
    854     if (clip) {
    855         SkRect newR;
    856         newR.set(clip->getBounds());
    857         if (!newR.intersect(origR)) {
    858             return;
    859         }
    860 
    861         SkIRect outerBounds;
    862         newR.roundOut(&outerBounds);
    863 
    864         if (clip->isRect()) {
    865             antifillrect(newR, blitter);
    866         } else {
    867             SkRegion::Cliperator clipper(*clip, outerBounds);
    868             while (!clipper.done()) {
    869                 newR.set(clipper.rect());
    870                 if (newR.intersect(origR)) {
    871                     antifillrect(newR, blitter);
    872                 }
    873                 clipper.next();
    874             }
    875         }
    876     } else {
    877         antifillrect(origR, blitter);
    878     }
    879 }
    880 
    881 void SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip,
    882                           SkBlitter* blitter) {
    883     if (clip.isBW()) {
    884         AntiFillRect(r, &clip.bwRgn(), blitter);
    885     } else {
    886         SkAAClipBlitterWrapper wrap(clip, blitter);
    887         AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter());
    888     }
    889 }
    890 
    891 #endif // SK_SCALAR_IS_FLOAT
    892 
    893 ///////////////////////////////////////////////////////////////////////////////
    894 
    895 #define SkAlphaMulRound(a, b)   SkMulDiv255Round(a, b)
    896 
    897 // calls blitRect() if the rectangle is non-empty
    898 static void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) {
    899     if (L < R && T < B) {
    900         blitter->blitRect(L, T, R - L, B - T);
    901     }
    902 }
    903 
    904 static inline FDot8 SkScalarToFDot8(SkScalar x) {
    905 #ifdef SK_SCALAR_IS_FLOAT
    906     return (int)(x * 256);
    907 #else
    908     return x >> 8;
    909 #endif
    910 }
    911 
    912 static inline int FDot8Floor(FDot8 x) {
    913     return x >> 8;
    914 }
    915 
    916 static inline int FDot8Ceil(FDot8 x) {
    917     return (x + 0xFF) >> 8;
    918 }
    919 
    920 // 1 - (1 - a)*(1 - b)
    921 static inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) {
    922     // need precise rounding (not just SkAlphaMul) so that values like
    923     // a=228, b=252 don't overflow the result
    924     return SkToU8(a + b - SkAlphaMulRound(a, b));
    925 }
    926 
    927 static void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
    928                            SkBlitter* blitter) {
    929     SkASSERT(L < R);
    930 
    931     if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
    932         blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L));
    933         return;
    934     }
    935 
    936     int left = L >> 8;
    937     if (L & 0xFF) {
    938         blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
    939         left += 1;
    940     }
    941 
    942     int rite = R >> 8;
    943     int width = rite - left;
    944     if (width > 0) {
    945         call_hline_blitter(blitter, left, top, width, alpha);
    946     }
    947 
    948     if (R & 0xFF) {
    949         blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
    950     }
    951 }
    952 
    953 static void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B,
    954                             SkBlitter* blitter) {
    955     SkASSERT(L < R && T < B);
    956 
    957     int top = T >> 8;
    958     if (top == ((B - 1) >> 8)) {   // just one scanline high
    959         // We want the inverse of B-T, since we're the inner-stroke
    960         int alpha = 256 - (B - T);
    961         if (alpha) {
    962             inner_scanline(L, top, R, alpha, blitter);
    963         }
    964         return;
    965     }
    966 
    967     if (T & 0xFF) {
    968         inner_scanline(L, top, R, T & 0xFF, blitter);
    969         top += 1;
    970     }
    971 
    972     int bot = B >> 8;
    973     int height = bot - top;
    974     if (height > 0) {
    975         if (L & 0xFF) {
    976             blitter->blitV(L >> 8, top, height, L & 0xFF);
    977         }
    978         if (R & 0xFF) {
    979             blitter->blitV(R >> 8, top, height, ~R & 0xFF);
    980         }
    981     }
    982 
    983     if (B & 0xFF) {
    984         inner_scanline(L, bot, R, ~B & 0xFF, blitter);
    985     }
    986 }
    987 
    988 void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
    989                            const SkRegion* clip, SkBlitter* blitter) {
    990     SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
    991 
    992     SkScalar rx = SkScalarHalf(strokeSize.fX);
    993     SkScalar ry = SkScalarHalf(strokeSize.fY);
    994 
    995     // outset by the radius
    996     FDot8 L = SkScalarToFDot8(r.fLeft - rx);
    997     FDot8 T = SkScalarToFDot8(r.fTop - ry);
    998     FDot8 R = SkScalarToFDot8(r.fRight + rx);
    999     FDot8 B = SkScalarToFDot8(r.fBottom + ry);
   1000 
   1001     SkIRect outer;
   1002     // set outer to the outer rect of the outer section
   1003     outer.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
   1004 
   1005     SkBlitterClipper clipper;
   1006     if (clip) {
   1007         if (clip->quickReject(outer)) {
   1008             return;
   1009         }
   1010         if (!clip->contains(outer)) {
   1011             blitter = clipper.apply(blitter, clip, &outer);
   1012         }
   1013         // now we can ignore clip for the rest of the function
   1014     }
   1015 
   1016     // stroke the outer hull
   1017     antifilldot8(L, T, R, B, blitter, false);
   1018 
   1019     // set outer to the outer rect of the middle section
   1020     outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B));
   1021 
   1022     // in case we lost a bit with diameter/2
   1023     rx = strokeSize.fX - rx;
   1024     ry = strokeSize.fY - ry;
   1025     // inset by the radius
   1026     L = SkScalarToFDot8(r.fLeft + rx);
   1027     T = SkScalarToFDot8(r.fTop + ry);
   1028     R = SkScalarToFDot8(r.fRight - rx);
   1029     B = SkScalarToFDot8(r.fBottom - ry);
   1030 
   1031     if (L >= R || T >= B) {
   1032         fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom,
   1033                       blitter);
   1034     } else {
   1035         SkIRect inner;
   1036         // set inner to the inner rect of the middle section
   1037         inner.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
   1038 
   1039         // draw the frame in 4 pieces
   1040         fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop,
   1041                       blitter);
   1042         fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom,
   1043                       blitter);
   1044         fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom,
   1045                       blitter);
   1046         fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom,
   1047                       blitter);
   1048 
   1049         // now stroke the inner rect, which is similar to antifilldot8() except that
   1050         // it treats the fractional coordinates with the inverse bias (since its
   1051         // inner).
   1052         innerstrokedot8(L, T, R, B, blitter);
   1053     }
   1054 }
   1055 
   1056 void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
   1057                            const SkRasterClip& clip, SkBlitter* blitter) {
   1058     if (clip.isBW()) {
   1059         AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter);
   1060     } else {
   1061         SkAAClipBlitterWrapper wrap(clip, blitter);
   1062         AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter());
   1063     }
   1064 }
   1065