LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkScan_Antihair.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 416 0 0.0 %
Date: 2012-06-02 Functions: 28 0 0.0 %

       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               0 : static inline int SmallDot6Scale(int value, int dot6) {
      35               0 :     SkASSERT((int16_t)value == value);
      36               0 :     SkASSERT((unsigned)dot6 <= 64);
      37               0 :     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               0 : static void call_hline_blitter(SkBlitter* blitter, int x, int y, int count,
      69                 :                                U8CPU alpha) {
      70               0 :     SkASSERT(count > 0);
      71                 : 
      72                 :     int16_t runs[HLINE_STACK_BUFFER + 1];
      73                 :     uint8_t  aa[HLINE_STACK_BUFFER];
      74                 : 
      75               0 :     aa[0] = ApplyGamma(gGammaTable, alpha);
      76               0 :     do {
      77               0 :         int n = count;
      78               0 :         if (n > HLINE_STACK_BUFFER) {
      79               0 :             n = HLINE_STACK_BUFFER;
      80                 :         }
      81               0 :         runs[0] = SkToS16(n);
      82               0 :         runs[n] = 0;
      83               0 :         blitter->blitAntiH(x, y, aa, runs);
      84               0 :         x += n;
      85               0 :         count -= n;
      86                 :     } while (count > 0);
      87               0 : }
      88                 : 
      89               0 : static SkFixed hline(int x, int stopx, SkFixed fy, SkFixed /*slope*/,
      90                 :                      SkBlitter* blitter, int mod64) {
      91               0 :     SkASSERT(x < stopx);
      92               0 :     int count = stopx - x;
      93               0 :     fy += SK_Fixed1/2;
      94                 : 
      95               0 :     int y = fy >> 16;
      96               0 :     uint8_t  a = (uint8_t)(fy >> 8);
      97                 : 
      98                 :     // lower line
      99               0 :     unsigned ma = SmallDot6Scale(a, mod64);
     100               0 :     if (ma) {
     101               0 :         call_hline_blitter(blitter, x, y, count, ma);
     102                 :     }
     103                 : 
     104                 :     // upper line
     105               0 :     ma = SmallDot6Scale(255 - a, mod64);
     106               0 :     if (ma) {
     107               0 :         call_hline_blitter(blitter, x, y - 1, count, ma);
     108                 :     }
     109                 :     
     110               0 :     return fy - SK_Fixed1/2;
     111                 : }
     112                 : 
     113               0 : static SkFixed horish(int x, int stopx, SkFixed fy, SkFixed dy,
     114                 :                       SkBlitter* blitter, int mod64) {
     115               0 :     SkASSERT(x < stopx);
     116                 : 
     117                 : #ifdef TEST_GAMMA
     118                 :     const uint8_t* gamma = gGammaTable;
     119                 : #endif
     120                 :     int16_t runs[2];
     121                 :     uint8_t  aa[1];
     122                 : 
     123               0 :     runs[0] = 1;
     124               0 :     runs[1] = 0;
     125                 : 
     126               0 :     fy += SK_Fixed1/2;
     127               0 :     do {
     128               0 :         int lower_y = fy >> 16;
     129               0 :         uint8_t  a = (uint8_t)(fy >> 8);
     130               0 :         unsigned ma = SmallDot6Scale(a, mod64);
     131               0 :         if (ma) {
     132               0 :             aa[0] = ApplyGamma(gamma, ma);
     133               0 :             blitter->blitAntiH(x, lower_y, aa, runs);
     134                 :             // the clipping blitters might edit runs, but should not affect us
     135               0 :             SkASSERT(runs[0] == 1);
     136               0 :             SkASSERT(runs[1] == 0);
     137                 :         }
     138               0 :         ma = SmallDot6Scale(255 - a, mod64);
     139               0 :         if (ma) {
     140               0 :             aa[0] = ApplyGamma(gamma, ma);
     141               0 :             blitter->blitAntiH(x, lower_y - 1, aa, runs);
     142                 :             // the clipping blitters might edit runs, but should not affect us
     143               0 :             SkASSERT(runs[0] == 1);
     144               0 :             SkASSERT(runs[1] == 0);
     145                 :         }
     146               0 :         fy += dy;
     147                 :     } while (++x < stopx);
     148                 :     
     149               0 :     return fy - SK_Fixed1/2;
     150                 : }
     151                 : 
     152               0 : static SkFixed vline(int y, int stopy, SkFixed fx, SkFixed /*slope*/,
     153                 :                      SkBlitter* blitter, int mod64) {
     154               0 :     SkASSERT(y < stopy);
     155               0 :     fx += SK_Fixed1/2;
     156                 : 
     157               0 :     int x = fx >> 16;
     158               0 :     int a = (uint8_t)(fx >> 8);
     159                 : 
     160               0 :     unsigned ma = SmallDot6Scale(a, mod64);
     161               0 :     if (ma) {
     162               0 :         blitter->blitV(x, y, stopy - y, ApplyGamma(gGammaTable, ma));
     163                 :     }
     164               0 :     ma = SmallDot6Scale(255 - a, mod64);
     165               0 :     if (ma) {
     166               0 :         blitter->blitV(x - 1, y, stopy - y, ApplyGamma(gGammaTable, ma));
     167                 :     }
     168                 :     
     169               0 :     return fx - SK_Fixed1/2;
     170                 : }
     171                 : 
     172               0 : static SkFixed vertish(int y, int stopy, SkFixed fx, SkFixed dx,
     173                 :                        SkBlitter* blitter, int mod64) {
     174               0 :     SkASSERT(y < stopy);
     175                 : #ifdef TEST_GAMMA
     176                 :     const uint8_t* gamma = gGammaTable;
     177                 : #endif
     178                 :     int16_t runs[3];
     179                 :     uint8_t  aa[2];
     180                 : 
     181               0 :     runs[0] = 1;
     182               0 :     runs[2] = 0;
     183                 : 
     184               0 :     fx += SK_Fixed1/2;
     185               0 :     do {
     186               0 :         int x = fx >> 16;
     187               0 :         uint8_t  a = (uint8_t)(fx >> 8);
     188                 : 
     189               0 :         aa[0] = ApplyGamma(gamma, SmallDot6Scale(255 - a, mod64));
     190               0 :         aa[1] = ApplyGamma(gamma, SmallDot6Scale(a, mod64));
     191                 :         // the clippng blitters might overwrite this guy, so we have to reset it each time
     192               0 :         runs[1] = 1;
     193               0 :         blitter->blitAntiH(x - 1, y, aa, runs);
     194                 :         // the clipping blitters might edit runs, but should not affect us
     195               0 :         SkASSERT(runs[0] == 1);
     196               0 :         SkASSERT(runs[2] == 0);
     197               0 :         fx += dx;
     198                 :     } while (++y < stopy);
     199                 : 
     200               0 :     return fx - SK_Fixed1/2;
     201                 : }
     202                 : 
     203                 : typedef SkFixed (*LineProc)(int istart, int istop, SkFixed fstart,
     204                 :                             SkFixed slope, SkBlitter*, int);
     205                 : 
     206               0 : static inline SkFixed fastfixdiv(SkFDot6 a, SkFDot6 b) {
     207               0 :     SkASSERT((a << 16 >> 16) == a);
     208               0 :     SkASSERT(b != 0);
     209               0 :     return (a << 16) / b;
     210                 : }
     211                 : 
     212               0 : static void do_anti_hairline(SkFDot6 x0, SkFDot6 y0, SkFDot6 x1, SkFDot6 y1,
     213                 :                              const SkIRect* clip, SkBlitter* blitter) {
     214                 :     // check that we're no larger than 511 pixels (so we can do a faster div).
     215                 :     // if we are, subdivide and call again
     216                 : 
     217               0 :     if (SkAbs32(x1 - x0) > SkIntToFDot6(511) || SkAbs32(y1 - y0) > SkIntToFDot6(511)) {
     218                 :         /*  instead of (x0 + x1) >> 1, we shift each separately. This is less
     219                 :             precise, but avoids overflowing the intermediate result if the
     220                 :             values are huge. A better fix might be to clip the original pts
     221                 :             directly (i.e. do the divide), so we don't spend time subdividing
     222                 :             huge lines at all.
     223                 :          */
     224               0 :         int hx = (x0 >> 1) + (x1 >> 1);
     225               0 :         int hy = (y0 >> 1) + (y1 >> 1);
     226               0 :         do_anti_hairline(x0, y0, hx, hy, clip, blitter);
     227               0 :         do_anti_hairline(hx, hy, x1, y1, clip, blitter);
     228               0 :         return;
     229                 :     }
     230                 : 
     231                 :     int         scaleStart, scaleStop;
     232                 :     int         istart, istop;
     233                 :     SkFixed     fstart, slope; 
     234                 :     LineProc    proc;
     235                 : 
     236               0 :     if (SkAbs32(x1 - x0) > SkAbs32(y1 - y0)) {   // mostly horizontal
     237               0 :         if (x0 > x1) {    // we want to go left-to-right
     238               0 :             SkTSwap<SkFDot6>(x0, x1);
     239               0 :             SkTSwap<SkFDot6>(y0, y1);
     240                 :         }
     241                 : 
     242               0 :         istart = SkFDot6Floor(x0);
     243               0 :         istop = SkFDot6Ceil(x1);
     244               0 :         fstart = SkFDot6ToFixed(y0);
     245               0 :         if (y0 == y1) {   // completely horizontal, take fast case
     246               0 :             slope = 0;
     247               0 :             proc = hline;
     248                 :         } else {
     249               0 :             slope = fastfixdiv(y1 - y0, x1 - x0);
     250               0 :             SkASSERT(slope >= -SK_Fixed1 && slope <= SK_Fixed1);
     251               0 :             fstart += (slope * (32 - (x0 & 63)) + 32) >> 6;
     252               0 :             proc = horish;
     253                 :         }
     254                 :         
     255               0 :         SkASSERT(istop > istart);
     256               0 :         if (istop - istart == 1) {
     257               0 :             scaleStart = x1 - x0;
     258               0 :             SkASSERT(scaleStart >= 0 && scaleStart <= 64);
     259               0 :             scaleStop = 0;
     260                 :         } else {
     261               0 :             scaleStart = 64 - (x0 & 63);
     262               0 :             scaleStop = x1 & 63;
     263                 :         }
     264                 : 
     265               0 :         if (clip){
     266               0 :             if (istart >= clip->fRight || istop <= clip->fLeft) {
     267               0 :                 return;
     268                 :             }
     269               0 :             if (istart < clip->fLeft) {
     270               0 :                 fstart += slope * (clip->fLeft - istart);
     271               0 :                 istart = clip->fLeft;
     272               0 :                 scaleStart = 64;
     273                 :             }
     274               0 :             if (istop > clip->fRight) {
     275               0 :                 istop = clip->fRight;
     276               0 :                 scaleStop = 64;
     277                 :             }
     278               0 :             SkASSERT(istart <= istop);
     279               0 :             if (istart == istop) {
     280               0 :                 return;
     281                 :             }
     282                 :             // now test if our Y values are completely inside the clip
     283                 :             int top, bottom;
     284               0 :             if (slope >= 0) { // T2B
     285               0 :                 top = SkFixedFloor(fstart - SK_FixedHalf);
     286               0 :                 bottom = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
     287                 :             } else {           // B2T
     288               0 :                 bottom = SkFixedCeil(fstart + SK_FixedHalf);
     289               0 :                 top = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
     290                 :             }
     291                 : #ifdef OUTSET_BEFORE_CLIP_TEST
     292               0 :             top -= 1;
     293               0 :             bottom += 1;
     294                 : #endif
     295               0 :             if (top >= clip->fBottom || bottom <= clip->fTop) {
     296               0 :                 return;
     297                 :             }
     298               0 :             if (clip->fTop <= top && clip->fBottom >= bottom) {
     299               0 :                 clip = NULL;
     300                 :             }
     301                 :         }
     302                 :     } else {   // mostly vertical
     303               0 :         if (y0 > y1) {  // we want to go top-to-bottom
     304               0 :             SkTSwap<SkFDot6>(x0, x1);
     305               0 :             SkTSwap<SkFDot6>(y0, y1);
     306                 :         }
     307                 : 
     308               0 :         istart = SkFDot6Floor(y0);
     309               0 :         istop = SkFDot6Ceil(y1);
     310               0 :         fstart = SkFDot6ToFixed(x0);
     311               0 :         if (x0 == x1) {
     312               0 :             if (y0 == y1) { // are we zero length?
     313               0 :                 return;     // nothing to do
     314                 :             }
     315               0 :             slope = 0;
     316               0 :             proc = vline;
     317                 :         } else {
     318               0 :             slope = fastfixdiv(x1 - x0, y1 - y0);
     319               0 :             SkASSERT(slope <= SK_Fixed1 && slope >= -SK_Fixed1);
     320               0 :             fstart += (slope * (32 - (y0 & 63)) + 32) >> 6;
     321               0 :             proc = vertish;
     322                 :         }
     323                 : 
     324               0 :         SkASSERT(istop > istart);
     325               0 :         if (istop - istart == 1) {
     326               0 :             scaleStart = y1 - y0;
     327               0 :             SkASSERT(scaleStart >= 0 && scaleStart <= 64);
     328               0 :             scaleStop = 0;
     329                 :         } else {
     330               0 :             scaleStart = 64 - (y0 & 63);
     331               0 :             scaleStop = y1 & 63;
     332                 :         }
     333                 :         
     334               0 :         if (clip) {
     335               0 :             if (istart >= clip->fBottom || istop <= clip->fTop) {
     336               0 :                 return;
     337                 :             }
     338               0 :             if (istart < clip->fTop) {
     339               0 :                 fstart += slope * (clip->fTop - istart);
     340               0 :                 istart = clip->fTop;
     341               0 :                 scaleStart = 64;
     342                 :             }
     343               0 :             if (istop > clip->fBottom) {
     344               0 :                 istop = clip->fBottom;
     345               0 :                 scaleStop = 64;
     346                 :             }
     347               0 :             SkASSERT(istart <= istop);
     348               0 :             if (istart == istop)
     349               0 :                 return;
     350                 : 
     351                 :             // now test if our X values are completely inside the clip
     352                 :             int left, right;
     353               0 :             if (slope >= 0) { // L2R
     354               0 :                 left = SkFixedFloor(fstart - SK_FixedHalf);
     355               0 :                 right = SkFixedCeil(fstart + (istop - istart - 1) * slope + SK_FixedHalf);
     356                 :             } else {           // R2L
     357               0 :                 right = SkFixedCeil(fstart + SK_FixedHalf);
     358               0 :                 left = SkFixedFloor(fstart + (istop - istart - 1) * slope - SK_FixedHalf);
     359                 :             }
     360                 : #ifdef OUTSET_BEFORE_CLIP_TEST
     361               0 :             left -= 1;
     362               0 :             right += 1;
     363                 : #endif
     364               0 :             if (left >= clip->fRight || right <= clip->fLeft) {
     365               0 :                 return;
     366                 :             }
     367               0 :             if (clip->fLeft <= left && clip->fRight >= right) {
     368               0 :                 clip = NULL;
     369                 :             }
     370                 :         }
     371                 :     }
     372                 : 
     373               0 :     SkRectClipBlitter   rectClipper;
     374               0 :     if (clip) {
     375               0 :         rectClipper.init(blitter, *clip);
     376               0 :         blitter = &rectClipper;
     377                 :     }
     378                 :     
     379               0 :     fstart = proc(istart, istart + 1, fstart, slope, blitter, scaleStart);
     380               0 :     istart += 1;
     381               0 :     int fullSpans = istop - istart - (scaleStop > 0);
     382               0 :     if (fullSpans > 0) {
     383               0 :         fstart = proc(istart, istart + fullSpans, fstart, slope, blitter, 64);
     384                 :     }
     385               0 :     if (scaleStop > 0) {
     386               0 :         proc(istop - 1, istop, fstart, slope, blitter, scaleStop);
     387                 :     }
     388                 : }
     389                 : 
     390               0 : void SkScan::AntiHairLineRgn(const SkPoint& pt0, const SkPoint& pt1,
     391                 :                              const SkRegion* clip, SkBlitter* blitter) {
     392               0 :     if (clip && clip->isEmpty()) {
     393               0 :         return;
     394                 :     }
     395                 : 
     396               0 :     SkASSERT(clip == NULL || !clip->getBounds().isEmpty());
     397                 : 
     398                 : #ifdef TEST_GAMMA
     399                 :     build_gamma_table();
     400                 : #endif
     401                 : 
     402               0 :     SkPoint pts[2] = { pt0, pt1 };
     403                 : 
     404               0 :     if (clip) {
     405                 :         SkRect clipBounds;
     406               0 :         clipBounds.set(clip->getBounds());
     407                 :         /*  We perform integral clipping later on, but we do a scalar clip first
     408                 :             to ensure that our coordinates are expressible in fixed/integers.
     409                 : 
     410                 :             antialiased hairlines can draw up to 1/2 of a pixel outside of
     411                 :             their bounds, so we need to outset the clip before calling the
     412                 :             clipper. To make the numerics safer, we outset by a whole pixel,
     413                 :             since the 1/2 pixel boundary is important to the antihair blitter,
     414                 :             we don't want to risk numerical fate by chopping on that edge.
     415                 :          */
     416               0 :         clipBounds.inset(-SK_Scalar1, -SK_Scalar1);
     417                 : 
     418               0 :         if (!SkLineClipper::IntersectLine(pts, clipBounds, pts)) {
     419               0 :             return;
     420                 :         }
     421                 :     }
     422                 :         
     423               0 :     SkFDot6 x0 = SkScalarToFDot6(pts[0].fX);
     424               0 :     SkFDot6 y0 = SkScalarToFDot6(pts[0].fY);
     425               0 :     SkFDot6 x1 = SkScalarToFDot6(pts[1].fX);
     426               0 :     SkFDot6 y1 = SkScalarToFDot6(pts[1].fY);
     427                 : 
     428               0 :     if (clip) {
     429               0 :         SkFDot6 left = SkMin32(x0, x1);
     430               0 :         SkFDot6 top = SkMin32(y0, y1);
     431               0 :         SkFDot6 right = SkMax32(x0, x1);
     432               0 :         SkFDot6 bottom = SkMax32(y0, y1);
     433                 :         SkIRect ir;
     434                 : 
     435                 :         ir.set( SkFDot6Floor(left) - 1,
     436                 :                 SkFDot6Floor(top) - 1,
     437                 :                 SkFDot6Ceil(right) + 1,
     438               0 :                 SkFDot6Ceil(bottom) + 1);
     439                 : 
     440               0 :         if (clip->quickReject(ir)) {
     441               0 :             return;
     442                 :         }
     443               0 :         if (!clip->quickContains(ir)) {
     444               0 :             SkRegion::Cliperator iter(*clip, ir);
     445               0 :             const SkIRect*       r = &iter.rect();
     446                 : 
     447               0 :             while (!iter.done()) {
     448               0 :                 do_anti_hairline(x0, y0, x1, y1, r, blitter);
     449               0 :                 iter.next();
     450                 :             }
     451               0 :             return;
     452                 :         }
     453                 :         // fall through to no-clip case
     454                 :     }
     455               0 :     do_anti_hairline(x0, y0, x1, y1, NULL, blitter);
     456                 : }
     457                 : 
     458               0 : void SkScan::AntiHairRect(const SkRect& rect, const SkRasterClip& clip,
     459                 :                           SkBlitter* blitter) {
     460                 :     SkPoint p0, p1;
     461                 : 
     462               0 :     p0.set(rect.fLeft, rect.fTop);
     463               0 :     p1.set(rect.fRight, rect.fTop);
     464               0 :     SkScan::AntiHairLine(p0, p1, clip, blitter);
     465               0 :     p0.set(rect.fRight, rect.fBottom);
     466               0 :     SkScan::AntiHairLine(p0, p1, clip, blitter);
     467               0 :     p1.set(rect.fLeft, rect.fBottom);
     468               0 :     SkScan::AntiHairLine(p0, p1, clip, blitter);
     469               0 :     p0.set(rect.fLeft, rect.fTop);
     470               0 :     SkScan::AntiHairLine(p0, p1, clip, blitter);
     471               0 : }
     472                 : 
     473                 : ///////////////////////////////////////////////////////////////////////////////
     474                 : 
     475                 : typedef int FDot8;  // 24.8 integer fixed point
     476                 : 
     477               0 : static inline FDot8 SkFixedToFDot8(SkFixed x) {
     478               0 :     return (x + 0x80) >> 8;
     479                 : }
     480                 : 
     481               0 : static void do_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
     482                 :                         SkBlitter* blitter) {
     483               0 :     SkASSERT(L < R);
     484                 :     
     485               0 :     if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
     486               0 :         blitter->blitV(L >> 8, top, 1, SkAlphaMul(alpha, R - L));
     487               0 :         return;
     488                 :     }
     489                 :     
     490               0 :     int left = L >> 8;
     491                 :     
     492               0 :     if (L & 0xFF) {
     493               0 :         blitter->blitV(left, top, 1, SkAlphaMul(alpha, 256 - (L & 0xFF)));
     494               0 :         left += 1;
     495                 :     }
     496                 : 
     497               0 :     int rite = R >> 8;
     498               0 :     int width = rite - left;
     499               0 :     if (width > 0) {
     500               0 :         call_hline_blitter(blitter, left, top, width, alpha);
     501                 :     }
     502               0 :     if (R & 0xFF) {
     503               0 :         blitter->blitV(rite, top, 1, SkAlphaMul(alpha, R & 0xFF));
     504                 :     }
     505                 : }
     506                 : 
     507               0 : static void antifilldot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, SkBlitter* blitter,
     508                 :                          bool fillInner) {
     509                 :     // check for empty now that we're in our reduced precision space
     510               0 :     if (L >= R || T >= B) {
     511               0 :         return;
     512                 :     }
     513               0 :     int top = T >> 8;
     514               0 :     if (top == ((B - 1) >> 8)) {   // just one scanline high
     515               0 :         do_scanline(L, top, R, B - T - 1, blitter);
     516               0 :         return;
     517                 :     }
     518                 :     
     519               0 :     if (T & 0xFF) {
     520               0 :         do_scanline(L, top, R, 256 - (T & 0xFF), blitter);
     521               0 :         top += 1;
     522                 :     }
     523                 :     
     524               0 :     int bot = B >> 8;
     525               0 :     int height = bot - top;
     526               0 :     if (height > 0) {
     527               0 :         int left = L >> 8;
     528               0 :         if (left == ((R - 1) >> 8)) {   // just 1-pixel wide
     529               0 :             blitter->blitV(left, top, height, R - L - 1);
     530                 :         } else {
     531               0 :             if (L & 0xFF) {
     532               0 :                 blitter->blitV(left, top, height, 256 - (L & 0xFF));
     533               0 :                 left += 1;
     534                 :             }
     535               0 :             int rite = R >> 8;
     536               0 :             int width = rite - left;
     537               0 :             if (width > 0 && fillInner) {
     538               0 :                 blitter->blitRect(left, top, width, height);
     539                 :             }
     540               0 :             if (R & 0xFF) {
     541               0 :                 blitter->blitV(rite, top, height, R & 0xFF);
     542                 :             }
     543                 :         }
     544                 :     }
     545                 :     
     546               0 :     if (B & 0xFF) {
     547               0 :         do_scanline(L, bot, R, B & 0xFF, blitter);
     548                 :     }
     549                 : }
     550                 : 
     551               0 : static void antifillrect(const SkXRect& xr, SkBlitter* blitter) {
     552                 :     antifilldot8(SkFixedToFDot8(xr.fLeft), SkFixedToFDot8(xr.fTop),
     553                 :                  SkFixedToFDot8(xr.fRight), SkFixedToFDot8(xr.fBottom),
     554               0 :                  blitter, true);
     555               0 : }
     556                 : 
     557                 : ///////////////////////////////////////////////////////////////////////////////
     558                 : 
     559               0 : void SkScan::AntiFillXRect(const SkXRect& xr, const SkRegion* clip,
     560                 :                           SkBlitter* blitter) {
     561               0 :     if (NULL == clip) {
     562               0 :         antifillrect(xr, blitter);
     563                 :     } else {
     564                 :         SkIRect outerBounds;
     565               0 :         XRect_roundOut(xr, &outerBounds);
     566                 : 
     567               0 :         if (clip->isRect()) {
     568               0 :             const SkIRect& clipBounds = clip->getBounds();
     569                 : 
     570               0 :             if (clipBounds.contains(outerBounds)) {
     571               0 :                 antifillrect(xr, blitter);
     572                 :             } else {
     573                 :                 SkXRect tmpR;
     574                 :                 // this keeps our original edges fractional
     575               0 :                 XRect_set(&tmpR, clipBounds);
     576               0 :                 if (tmpR.intersect(xr)) {
     577               0 :                     antifillrect(tmpR, blitter);
     578                 :                 }
     579                 :             }
     580                 :         } else {
     581               0 :             SkRegion::Cliperator clipper(*clip, outerBounds);
     582               0 :             const SkIRect&       rr = clipper.rect();
     583                 :             
     584               0 :             while (!clipper.done()) {
     585                 :                 SkXRect  tmpR;
     586                 :                 
     587                 :                 // this keeps our original edges fractional
     588               0 :                 XRect_set(&tmpR, rr);
     589               0 :                 if (tmpR.intersect(xr)) {
     590               0 :                     antifillrect(tmpR, blitter);
     591                 :                 }
     592               0 :                 clipper.next();
     593                 :             }
     594                 :         }
     595                 :     }
     596               0 : }
     597                 : 
     598               0 : void SkScan::AntiFillXRect(const SkXRect& xr, const SkRasterClip& clip,
     599                 :                            SkBlitter* blitter) {
     600               0 :     if (clip.isBW()) {
     601               0 :         AntiFillXRect(xr, &clip.bwRgn(), blitter);
     602                 :     } else {
     603                 :         SkIRect outerBounds;
     604               0 :         XRect_roundOut(xr, &outerBounds);
     605                 : 
     606               0 :         if (clip.quickContains(outerBounds)) {
     607               0 :             AntiFillXRect(xr, NULL, blitter);
     608                 :         } else {
     609               0 :             SkAAClipBlitterWrapper wrapper(clip, blitter);
     610               0 :             blitter = wrapper.getBlitter();
     611                 : 
     612               0 :             AntiFillXRect(xr, &wrapper.getRgn(), wrapper.getBlitter());
     613                 :         }
     614                 :     }
     615               0 : }
     616                 : 
     617                 : #ifdef SK_SCALAR_IS_FLOAT
     618                 : 
     619                 : /*  This guy takes a float-rect, but with the key improvement that it has
     620                 :     already been clipped, so we know that it is safe to convert it into a
     621                 :     XRect (fixedpoint), as it won't overflow.
     622                 : */
     623               0 : static void antifillrect(const SkRect& r, SkBlitter* blitter) {
     624                 :     SkXRect xr;
     625                 :     
     626               0 :     XRect_set(&xr, r);
     627               0 :     antifillrect(xr, blitter);
     628               0 : }
     629                 : 
     630                 : /*  We repeat the clipping logic of AntiFillXRect because the float rect might
     631                 :     overflow if we blindly converted it to an XRect. This sucks that we have to
     632                 :     repeat the clipping logic, but I don't see how to share the code/logic.
     633                 :  
     634                 :     We clip r (as needed) into one or more (smaller) float rects, and then pass
     635                 :     those to our version of antifillrect, which converts it into an XRect and
     636                 :     then calls the blit.
     637                 : */
     638               0 : void SkScan::AntiFillRect(const SkRect& origR, const SkRegion* clip,
     639                 :                           SkBlitter* blitter) {
     640               0 :     if (clip) {
     641                 :         SkRect newR;
     642               0 :         newR.set(clip->getBounds());
     643               0 :         if (!newR.intersect(origR)) {
     644               0 :             return;
     645                 :         }
     646                 : 
     647                 :         SkIRect outerBounds;
     648               0 :         newR.roundOut(&outerBounds);
     649                 :         
     650               0 :         if (clip->isRect()) {
     651               0 :             antifillrect(newR, blitter);
     652                 :         } else {
     653               0 :             SkRegion::Cliperator clipper(*clip, outerBounds);
     654               0 :             while (!clipper.done()) {
     655               0 :                 newR.set(clipper.rect());
     656               0 :                 if (newR.intersect(origR)) {
     657               0 :                     antifillrect(newR, blitter);
     658                 :                 }
     659               0 :                 clipper.next();
     660                 :             }
     661                 :         }
     662                 :     } else {
     663               0 :         antifillrect(origR, blitter);
     664                 :     }
     665                 : }
     666                 : 
     667               0 : void SkScan::AntiFillRect(const SkRect& r, const SkRasterClip& clip,
     668                 :                           SkBlitter* blitter) {
     669               0 :     if (clip.isBW()) {
     670               0 :         AntiFillRect(r, &clip.bwRgn(), blitter);
     671                 :     } else {
     672               0 :         SkAAClipBlitterWrapper wrap(clip, blitter);
     673               0 :         AntiFillRect(r, &wrap.getRgn(), wrap.getBlitter());
     674                 :     }
     675               0 : }
     676                 : 
     677                 : #endif // SK_SCALAR_IS_FLOAT
     678                 : 
     679                 : ///////////////////////////////////////////////////////////////////////////////
     680                 : 
     681                 : #define SkAlphaMulRound(a, b)   SkMulDiv255Round(a, b)
     682                 : 
     683                 : // calls blitRect() if the rectangle is non-empty
     684               0 : static void fillcheckrect(int L, int T, int R, int B, SkBlitter* blitter) {
     685               0 :     if (L < R && T < B) {
     686               0 :         blitter->blitRect(L, T, R - L, B - T);
     687                 :     }
     688               0 : }
     689                 : 
     690               0 : static inline FDot8 SkScalarToFDot8(SkScalar x) {
     691                 : #ifdef SK_SCALAR_IS_FLOAT
     692               0 :     return (int)(x * 256);
     693                 : #else
     694                 :     return x >> 8;
     695                 : #endif
     696                 : }
     697                 : 
     698               0 : static inline int FDot8Floor(FDot8 x) {
     699               0 :     return x >> 8;
     700                 : }
     701                 : 
     702               0 : static inline int FDot8Ceil(FDot8 x) {
     703               0 :     return (x + 0xFF) >> 8;
     704                 : }
     705                 : 
     706                 : // 1 - (1 - a)*(1 - b)
     707               0 : static inline U8CPU InvAlphaMul(U8CPU a, U8CPU b) {
     708                 :     // need precise rounding (not just SkAlphaMul) so that values like
     709                 :     // a=228, b=252 don't overflow the result
     710               0 :     return SkToU8(a + b - SkAlphaMulRound(a, b));
     711                 : }
     712                 : 
     713               0 : static void inner_scanline(FDot8 L, int top, FDot8 R, U8CPU alpha,
     714                 :                            SkBlitter* blitter) {
     715               0 :     SkASSERT(L < R);
     716                 :     
     717               0 :     if ((L >> 8) == ((R - 1) >> 8)) {  // 1x1 pixel
     718               0 :         blitter->blitV(L >> 8, top, 1, InvAlphaMul(alpha, R - L));
     719               0 :         return;
     720                 :     }
     721                 :     
     722               0 :     int left = L >> 8;
     723               0 :     if (L & 0xFF) {
     724               0 :         blitter->blitV(left, top, 1, InvAlphaMul(alpha, L & 0xFF));
     725               0 :         left += 1;
     726                 :     }
     727                 :     
     728               0 :     int rite = R >> 8;
     729               0 :     int width = rite - left;
     730               0 :     if (width > 0) {
     731               0 :         call_hline_blitter(blitter, left, top, width, alpha);
     732                 :     }
     733                 :     
     734               0 :     if (R & 0xFF) {
     735               0 :         blitter->blitV(rite, top, 1, InvAlphaMul(alpha, ~R & 0xFF));
     736                 :     }
     737                 : }
     738                 : 
     739               0 : static void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B,
     740                 :                             SkBlitter* blitter) {
     741               0 :     SkASSERT(L < R && T < B);
     742                 : 
     743               0 :     int top = T >> 8;
     744               0 :     if (top == ((B - 1) >> 8)) {   // just one scanline high
     745               0 :         inner_scanline(L, top, R, B - T, blitter);
     746               0 :         return;
     747                 :     }
     748                 :     
     749               0 :     if (T & 0xFF) {
     750               0 :         inner_scanline(L, top, R, T & 0xFF, blitter);
     751               0 :         top += 1;
     752                 :     }
     753                 :     
     754               0 :     int bot = B >> 8;
     755               0 :     int height = bot - top;
     756               0 :     if (height > 0) {
     757               0 :         if (L & 0xFF) {
     758               0 :             blitter->blitV(L >> 8, top, height, L & 0xFF);
     759                 :         }
     760               0 :         if (R & 0xFF) {
     761               0 :             blitter->blitV(R >> 8, top, height, ~R & 0xFF);
     762                 :         }
     763                 :     }
     764                 :     
     765               0 :     if (B & 0xFF) {
     766               0 :         inner_scanline(L, bot, R, ~B & 0xFF, blitter);
     767                 :     }
     768                 : }
     769                 : 
     770               0 : void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
     771                 :                            const SkRegion* clip, SkBlitter* blitter) {
     772               0 :     SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0);
     773                 : 
     774               0 :     SkScalar rx = SkScalarHalf(strokeSize.fX);
     775               0 :     SkScalar ry = SkScalarHalf(strokeSize.fY);
     776                 : 
     777                 :     // outset by the radius
     778               0 :     FDot8 L = SkScalarToFDot8(r.fLeft - rx);
     779               0 :     FDot8 T = SkScalarToFDot8(r.fTop - ry);
     780               0 :     FDot8 R = SkScalarToFDot8(r.fRight + rx);
     781               0 :     FDot8 B = SkScalarToFDot8(r.fBottom + ry);
     782                 : 
     783                 :     SkIRect outer;
     784                 :     // set outer to the outer rect of the outer section
     785               0 :     outer.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
     786                 : 
     787               0 :     SkBlitterClipper clipper;
     788               0 :     if (clip) {
     789               0 :         if (clip->quickReject(outer)) {
     790                 :             return;
     791                 :         }
     792               0 :         if (!clip->contains(outer)) {
     793               0 :             blitter = clipper.apply(blitter, clip, &outer);
     794                 :         }
     795                 :         // now we can ignore clip for the rest of the function
     796                 :     }
     797                 :     
     798                 :     // stroke the outer hull
     799               0 :     antifilldot8(L, T, R, B, blitter, false);
     800                 : 
     801                 :     // set outer to the outer rect of the middle section
     802               0 :     outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B));
     803                 : 
     804                 :     // in case we lost a bit with diameter/2
     805               0 :     rx = strokeSize.fX - rx;
     806               0 :     ry = strokeSize.fY - ry;
     807                 :     // inset by the radius
     808               0 :     L = SkScalarToFDot8(r.fLeft + rx);
     809               0 :     T = SkScalarToFDot8(r.fTop + ry);
     810               0 :     R = SkScalarToFDot8(r.fRight - rx);
     811               0 :     B = SkScalarToFDot8(r.fBottom - ry);
     812                 : 
     813               0 :     if (L >= R || T >= B) {
     814                 :         fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom,
     815               0 :                       blitter);
     816                 :     } else {
     817                 :         SkIRect inner;
     818                 :         // set inner to the inner rect of the middle section
     819               0 :         inner.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B));
     820                 : 
     821                 :         // draw the frame in 4 pieces
     822                 :         fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop,
     823               0 :                       blitter);
     824                 :         fillcheckrect(outer.fLeft, inner.fTop, inner.fLeft, inner.fBottom,
     825               0 :                       blitter);
     826                 :         fillcheckrect(inner.fRight, inner.fTop, outer.fRight, inner.fBottom,
     827               0 :                       blitter);
     828                 :         fillcheckrect(outer.fLeft, inner.fBottom, outer.fRight, outer.fBottom,
     829               0 :                       blitter);
     830                 : 
     831                 :         // now stroke the inner rect, which is similar to antifilldot8() except that
     832                 :         // it treats the fractional coordinates with the inverse bias (since its
     833                 :         // inner).
     834               0 :         innerstrokedot8(L, T, R, B, blitter);
     835                 :     }
     836                 : }
     837                 : 
     838               0 : void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize,
     839                 :                            const SkRasterClip& clip, SkBlitter* blitter) {
     840               0 :     if (clip.isBW()) {
     841               0 :         AntiFrameRect(r, strokeSize, &clip.bwRgn(), blitter);
     842                 :     } else {
     843               0 :         SkAAClipBlitterWrapper wrap(clip, blitter);
     844               0 :         AntiFrameRect(r, strokeSize, &wrap.getRgn(), wrap.getBlitter());
     845                 :     }
     846               0 : }
     847                 : 

Generated by: LCOV version 1.7