gfx/skia/trunk/src/core/SkScan_Antihair.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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  */
    10 #include "SkScan.h"
    11 #include "SkBlitter.h"
    12 #include "SkColorPriv.h"
    13 #include "SkLineClipper.h"
    14 #include "SkRasterClip.h"
    15 #include "SkFDot6.h"
    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.
    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
    32 #define HLINE_STACK_BUFFER      100
    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 }
    40 //#define TEST_GAMMA
    42 #ifdef TEST_GAMMA
    43     static uint8_t gGammaTable[256];
    44     #define ApplyGamma(table, alpha)    (table)[alpha]
    46     static void build_gamma_table() {
    47         static bool gInit = false;
    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
    66 ///////////////////////////////////////////////////////////////////////////////
    68 static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count,
    69                                U8CPU alpha) {
    70     SkASSERT(count > 0);
    72     int16_t runs[HLINE_STACK_BUFFER + 1];
    73     uint8_t  aa[HLINE_STACK_BUFFER];
    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 }
    89 class SkAntiHairBlitter {
    90 public:
    91     SkAntiHairBlitter() : fBlitter(NULL) {}
    92     virtual ~SkAntiHairBlitter() {}
    94     SkBlitter* getBlitter() const { return fBlitter; }
    96     void setup(SkBlitter* blitter) {
    97         fBlitter = blitter;
    98     }
   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;
   103 private:
   104     SkBlitter*  fBlitter;
   105 };
   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;
   112         int y = fy >> 16;
   113         uint8_t  a = (uint8_t)(fy >> 8);
   115         // lower line
   116         unsigned ma = SmallDot6Scale(a, mod64);
   117         if (ma) {
   118             call_hline_blitter(this->getBlitter(), x, y, 1, ma);
   119         }
   121         // upper line
   122         ma = SmallDot6Scale(255 - a, mod64);
   123         if (ma) {
   124             call_hline_blitter(this->getBlitter(), x, y - 1, 1, ma);
   125         }
   127         return fy - SK_Fixed1/2;
   128     }
   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;
   136         int y = fy >> 16;
   137         uint8_t  a = (uint8_t)(fy >> 8);
   139         // lower line
   140         if (a) {
   141             call_hline_blitter(this->getBlitter(), x, y, count, a);
   142         }
   144         // upper line
   145         a = 255 - a;
   146         if (a) {
   147             call_hline_blitter(this->getBlitter(), x, y - 1, count, a);
   148         }
   150         return fy - SK_Fixed1/2;
   151     }
   152 };
   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];
   160         runs[0] = 1;
   161         runs[1] = 0;
   163         fy += SK_Fixed1/2;
   164         SkBlitter* blitter = this->getBlitter();
   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;
   186         return fy - SK_Fixed1/2;
   187     }
   189     virtual SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed dy) SK_OVERRIDE {
   190         SkASSERT(x < stopx);
   192         int16_t runs[2];
   193         uint8_t  aa[1];
   195         runs[0] = 1;
   196         runs[1] = 0;
   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);
   221         return fy - SK_Fixed1/2;
   222     }
   223 };
   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;
   231         int x = fx >> 16;
   232         int a = (uint8_t)(fx >> 8);
   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         }
   243         return fx - SK_Fixed1/2;
   244     }
   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;
   251         int x = fx >> 16;
   252         int a = (uint8_t)(fx >> 8);
   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         }
   262         return fx - SK_Fixed1/2;
   263     }
   264 };
   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];
   272         runs[0] = 1;
   273         runs[2] = 0;
   275         fx += SK_Fixed1/2;
   276         int x = fx >> 16;
   277         uint8_t  a = (uint8_t)(fx >> 8);
   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;
   289         return fx - SK_Fixed1/2;
   290     }
   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];
   297         runs[0] = 1;
   298         runs[2] = 0;
   300         fx += SK_Fixed1/2;
   301         do {
   302             int x = fx >> 16;
   303             uint8_t  a = (uint8_t)(fx >> 8);
   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);
   316         return fx - SK_Fixed1/2;
   317     }
   318 };
   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 }
   326 #define SkBITCOUNT(x)   (sizeof(x) << 3)
   328 #if 1
   329 // returns high-bit set iff x==0x8000...
   330 static inline int bad_int(int x) {
   331     return x & -x;
   332 }
   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 }
   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
   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
   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 }
   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     }
   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));
   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     }
   403     int         scaleStart, scaleStop;
   404     int         istart, istop;
   405     SkFixed     fstart, slope;
   407     HLine_SkAntiHairBlitter     hline_blitter;
   408     Horish_SkAntiHairBlitter    horish_blitter;
   409     VLine_SkAntiHairBlitter     vline_blitter;
   410     Vertish_SkAntiHairBlitter   vertish_blitter;
   411     SkAntiHairBlitter*          hairBlitter = NULL;
   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         }
   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         }
   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         }
   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             }
   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         }
   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         }
   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         }
   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             }
   538             SkASSERT(istart <= istop);
   539             if (istart == istop)
   540                 return;
   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     }
   564     SkRectClipBlitter   rectClipper;
   565     if (clip) {
   566         rectClipper.init(blitter, *clip);
   567         blitter = &rectClipper;
   568     }
   570     SkASSERT(hairBlitter);
   571     hairBlitter->setup(blitter);
   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
   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 }
   591 void SkScan::AntiHairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
   592                              const SkRegion* clip, SkBlitter* blitter) {
   593     if (clip && clip->isEmpty()) {
   594         return;
   595     }
   597     SkASSERT(clip == NULL || !clip->getBounds().isEmpty());
   599 #ifdef TEST_GAMMA
   600     build_gamma_table();
   601 #endif
   603     SkPoint pts[2] = { pt0, pt1 };
   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     }
   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.
   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);
   630         if (!SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
   631             return;
   632         }
   633     }
   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);
   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;
   647         ir.set( SkFDot6Floor(left) - 1,
   648                 SkFDot6Floor(top) - 1,
   649                 SkFDot6Ceil(right) + 1,
   650                 SkFDot6Ceil(bottom) + 1);
   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();
   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 }
   670 void SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
   671                           SkBlitter* blitter) {
   672     SkPoint p0, p1;
   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 }
   685 ///////////////////////////////////////////////////////////////////////////////
   687 typedef int FDot8;  // 24.8 integer fixed point
   689 static inline FDot8 SkFixedToFDot8(SkFixed x) {
   690     return (x + 0x80) >> 8;
   691 }
   693 static void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
   694                         SkBlitter* blitter) {
   695     SkASSERT(L < R);
   697     if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
   698         blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L));
   699         return;
   700     }
   702     int left = L >> 8;
   704     if (L & 0xFF) {
   705         blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF)));
   706         left += 1;
   707     }
   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 }
   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     }
   731     if (T & 0xFF) {
   732         do_scanline(L, top, R, 256 - (T & 0xFF), blitter);
   733         top += 1;
   734     }
   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     }
   758     if (B & 0xFF) {
   759         do_scanline(L, bot, R, B & 0xFF, blitter);
   760     }
   761 }
   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 }
   769 ///////////////////////////////////////////////////////////////////////////////
   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);
   779         if (clip->isRect()) {
   780             const SkIRect& clipBounds = clip->getBounds();
   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();
   796             while (!clipper.done()) {
   797                 SkXRect  tmpR;
   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 }
   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);
   818         if (clip.quickContains(outerBounds)) {
   819             AntiFillXRect(xr, NULL, blitter);
   820         } else {
   821             SkAAClipBlitterWrapper wrapper(clip, blitter);
   822             blitter = wrapper.getBlitter();
   824             AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
   825         }
   826     }
   827 }
   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;
   836     XRect_set(&xr, r);
   837     antifillrect(xr, blitter);
   838 }
   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.
   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         }
   857         SkIRect outerBounds;
   858         newR.roundOut(&outerBounds);
   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 }
   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 }
   887 ///////////////////////////////////////////////////////////////////////////////
   889 #define SkAlphaMulRound(a, b)   SkMulDiv255Round(a, b)
   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 }
   898 static inline FDot8 SkScalarToFDot8(SkScalar x) {
   899     return (int)(x * 256);
   900 }
   902 static inline int FDot8Floor(FDot8 x) {
   903     return x >> 8;
   904 }
   906 static inline int FDot8Ceil(FDot8 x) {
   907     return (x + 0xFF) >> 8;
   908 }
   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 }
   917 static void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
   918                            SkBlitter* blitter) {
   919     SkASSERT(L < R);
   921     if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
   922         blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L));
   923         return;
   924     }
   926     int left = L >> 8;
   927     if (L & 0xFF) {
   928         blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
   929         left += 1;
   930     }
   932     int rite = R >> 8;
   933     int width = rite - left;
   934     if (width > 0) {
   935         call_hline_blitter(blitter, left, top, width, alpha);
   936     }
   938     if (R & 0xFF) {
   939         blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
   940     }
   941 }
   943 static void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B,
   944                             SkBlitter* blitter) {
   945     SkASSERT(L < R && T < B);
   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     }
   957     if (T & 0xFF) {
   958         inner_scanline(L, top, R, T & 0xFF, blitter);
   959         top += 1;
   960     }
   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     }
   973     if (B & 0xFF) {
   974         inner_scanline(L, bot, R, ~B & 0xFF, blitter);
   975     }
   976 }
   978 void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
   979                            const SkRegion* clip, SkBlitter* blitter) {
   980     SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
   982     SkScalar rx = SkScalarHalf(strokeSize.fX);
   983     SkScalar ry = SkScalarHalf(strokeSize.fY);
   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);
   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));
   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);
  1003         // now we can ignore clip for the rest of the function
  1006     // stroke the outer hull
  1007     antifilldot8(L, T, R, B, blitter, false);
  1009     // set outer to the outer rect of the middle section
  1010     outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B));
  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);
  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));
  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);
  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);
  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());

mercurial