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

       1                 : 
       2                 : /*
       3                 :  * Copyright 2006 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 "SkEdge.h"
      11                 : #include "SkFDot6.h"
      12                 : #include "SkMath.h"
      13                 : 
      14                 : /*
      15                 :     In setLine, setQuadratic, setCubic, the first thing we do is to convert
      16                 :     the points into FDot6. This is modulated by the shift parameter, which
      17                 :     will either be 0, or something like 2 for antialiasing.
      18                 : 
      19                 :     In the float case, we want to turn the float into .6 by saying pt * 64,
      20                 :     or pt * 256 for antialiasing. This is implemented as 1 << (shift + 6).
      21                 : 
      22                 :     In the fixed case, we want to turn the fixed into .6 by saying pt >> 10,
      23                 :     or pt >> 8 for antialiasing. This is implemented as pt >> (10 - shift).
      24                 : */
      25                 : 
      26                 : /////////////////////////////////////////////////////////////////////////
      27                 : 
      28               0 : int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip,
      29                 :                     int shift) {
      30                 :     SkFDot6 x0, y0, x1, y1;
      31                 : 
      32                 :     {
      33                 : #ifdef SK_SCALAR_IS_FLOAT
      34               0 :         float scale = float(1 << (shift + 6));
      35               0 :         x0 = int(p0.fX * scale);
      36               0 :         y0 = int(p0.fY * scale);
      37               0 :         x1 = int(p1.fX * scale);
      38               0 :         y1 = int(p1.fY * scale);
      39                 : #else
      40                 :         shift = 10 - shift;
      41                 :         x0 = p0.fX >> shift;
      42                 :         y0 = p0.fY >> shift;
      43                 :         x1 = p1.fX >> shift;
      44                 :         y1 = p1.fY >> shift;
      45                 : #endif
      46                 :     }
      47                 : 
      48               0 :     int winding = 1;
      49                 : 
      50               0 :     if (y0 > y1) {
      51               0 :         SkTSwap(x0, x1);
      52               0 :         SkTSwap(y0, y1);
      53               0 :         winding = -1;
      54                 :     }
      55                 : 
      56               0 :     int top = SkFDot6Round(y0);
      57               0 :     int bot = SkFDot6Round(y1);
      58                 : 
      59                 :     // are we a zero-height line?
      60               0 :     if (top == bot) {
      61               0 :         return 0;
      62                 :     }
      63                 :     // are we completely above or below the clip?
      64               0 :     if (NULL != clip && (top >= clip->fBottom || bot <= clip->fTop)) {
      65               0 :         return 0;
      66                 :     }
      67                 : 
      68               0 :     SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0);
      69                 : 
      70               0 :     fX          = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63));   // + SK_Fixed1/2
      71               0 :     fDX         = slope;
      72               0 :     fFirstY     = top;
      73               0 :     fLastY      = bot - 1;
      74               0 :     fCurveCount = 0;
      75               0 :     fWinding    = SkToS8(winding);
      76               0 :     fCurveShift = 0;
      77                 : 
      78               0 :     if (clip) {
      79               0 :         this->chopLineWithClip(*clip);
      80                 :     }
      81               0 :     return 1;
      82                 : }
      83                 : 
      84                 : // called from a curve subclass
      85               0 : int SkEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1)
      86                 : {
      87               0 :     SkASSERT(fWinding == 1 || fWinding == -1);
      88               0 :     SkASSERT(fCurveCount != 0);
      89                 : //    SkASSERT(fCurveShift != 0);
      90                 : 
      91               0 :     y0 >>= 10;
      92               0 :     y1 >>= 10;
      93                 : 
      94               0 :     SkASSERT(y0 <= y1);
      95                 : 
      96               0 :     int top = SkFDot6Round(y0);
      97               0 :     int bot = SkFDot6Round(y1);
      98                 : 
      99                 : //  SkASSERT(top >= fFirstY);
     100                 : 
     101                 :     // are we a zero-height line?
     102               0 :     if (top == bot)
     103               0 :         return 0;
     104                 : 
     105               0 :     x0 >>= 10;
     106               0 :     x1 >>= 10;
     107                 : 
     108               0 :     SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0);
     109                 : 
     110               0 :     fX          = SkFDot6ToFixed(x0 + SkFixedMul(slope, (32 - y0) & 63));   // + SK_Fixed1/2
     111               0 :     fDX         = slope;
     112               0 :     fFirstY     = top;
     113               0 :     fLastY      = bot - 1;
     114                 : 
     115               0 :     return 1;
     116                 : }
     117                 : 
     118               0 : void SkEdge::chopLineWithClip(const SkIRect& clip)
     119                 : {
     120               0 :     int top = fFirstY;
     121                 : 
     122               0 :     SkASSERT(top < clip.fBottom);
     123                 : 
     124                 :     // clip the line to the top
     125               0 :     if (top < clip.fTop)
     126                 :     {
     127               0 :         SkASSERT(fLastY >= clip.fTop);
     128               0 :         fX += fDX * (clip.fTop - top);
     129               0 :         fFirstY = clip.fTop;
     130                 :     }
     131               0 : }
     132                 : 
     133                 : ///////////////////////////////////////////////////////////////////////////////
     134                 : 
     135                 : /*  We store 1<<shift in a (signed) byte, so its maximum value is 1<<6 == 64.
     136                 :     Note that this limits the number of lines we use to approximate a curve.
     137                 :     If we need to increase this, we need to store fCurveCount in something
     138                 :     larger than int8_t.
     139                 : */
     140                 : #define MAX_COEFF_SHIFT     6
     141                 : 
     142               0 : static inline SkFDot6 cheap_distance(SkFDot6 dx, SkFDot6 dy)
     143                 : {
     144               0 :     dx = SkAbs32(dx);
     145               0 :     dy = SkAbs32(dy);
     146                 :     // return max + min/2
     147               0 :     if (dx > dy)
     148               0 :         dx += dy >> 1;
     149                 :     else
     150               0 :         dx = dy + (dx >> 1);
     151               0 :     return dx;
     152                 : }
     153                 : 
     154               0 : static inline int diff_to_shift(SkFDot6 dx, SkFDot6 dy)
     155                 : {
     156                 :     // cheap calc of distance from center of p0-p2 to the center of the curve
     157               0 :     SkFDot6 dist = cheap_distance(dx, dy);
     158                 : 
     159                 :     // shift down dist (it is currently in dot6)
     160                 :     // down by 5 should give us 1/2 pixel accuracy (assuming our dist is accurate...)
     161                 :     // this is chosen by heuristic: make it as big as possible (to minimize segments)
     162                 :     // ... but small enough so that our curves still look smooth
     163               0 :     dist = (dist + (1 << 4)) >> 5;
     164                 : 
     165                 :     // each subdivision (shift value) cuts this dist (error) by 1/4
     166               0 :     return (32 - SkCLZ(dist)) >> 1;
     167                 : }
     168                 : 
     169               0 : int SkQuadraticEdge::setQuadratic(const SkPoint pts[3], int shift)
     170                 : {
     171                 :     SkFDot6 x0, y0, x1, y1, x2, y2;
     172                 : 
     173                 :     {
     174                 : #ifdef SK_SCALAR_IS_FLOAT
     175               0 :         float scale = float(1 << (shift + 6));
     176               0 :         x0 = int(pts[0].fX * scale);
     177               0 :         y0 = int(pts[0].fY * scale);
     178               0 :         x1 = int(pts[1].fX * scale);
     179               0 :         y1 = int(pts[1].fY * scale);
     180               0 :         x2 = int(pts[2].fX * scale);
     181               0 :         y2 = int(pts[2].fY * scale);
     182                 : #else
     183                 :         shift = 10 - shift;
     184                 :         x0 = pts[0].fX >> shift;
     185                 :         y0 = pts[0].fY >> shift;
     186                 :         x1 = pts[1].fX >> shift;
     187                 :         y1 = pts[1].fY >> shift;
     188                 :         x2 = pts[2].fX >> shift;
     189                 :         y2 = pts[2].fY >> shift;
     190                 : #endif
     191                 :     }
     192                 : 
     193               0 :     int winding = 1;
     194               0 :     if (y0 > y2)
     195                 :     {
     196               0 :         SkTSwap(x0, x2);
     197               0 :         SkTSwap(y0, y2);
     198               0 :         winding = -1;
     199                 :     }
     200               0 :     SkASSERT(y0 <= y1 && y1 <= y2);
     201                 : 
     202               0 :     int top = SkFDot6Round(y0);
     203               0 :     int bot = SkFDot6Round(y2);
     204                 : 
     205                 :     // are we a zero-height quad (line)?
     206               0 :     if (top == bot)
     207               0 :         return 0;
     208                 : 
     209                 :     // compute number of steps needed (1 << shift)
     210                 :     {
     211               0 :         SkFDot6 dx = ((x1 << 1) - x0 - x2) >> 2;
     212               0 :         SkFDot6 dy = ((y1 << 1) - y0 - y2) >> 2;
     213               0 :         shift = diff_to_shift(dx, dy);
     214               0 :         SkASSERT(shift >= 0);
     215                 :     }
     216                 :     // need at least 1 subdivision for our bias trick
     217               0 :     if (shift == 0) {
     218               0 :         shift = 1;
     219               0 :     } else if (shift > MAX_COEFF_SHIFT) {
     220               0 :         shift = MAX_COEFF_SHIFT;
     221                 :     }
     222                 :     
     223               0 :     fWinding    = SkToS8(winding);
     224               0 :     fCurveShift = SkToU8(shift);
     225                 :     //fCubicDShift only set for cubics
     226               0 :     fCurveCount = SkToS8(1 << shift);
     227                 : 
     228               0 :     SkFixed A = SkFDot6ToFixed(x0 - x1 - x1 + x2);
     229               0 :     SkFixed B = SkFDot6ToFixed(x1 - x0 + x1 - x0);
     230                 : 
     231               0 :     fQx     = SkFDot6ToFixed(x0);
     232               0 :     fQDx    = B + (A >> shift);     // biased by shift
     233               0 :     fQDDx   = A >> (shift - 1);     // biased by shift
     234                 : 
     235               0 :     A = SkFDot6ToFixed(y0 - y1 - y1 + y2);
     236               0 :     B = SkFDot6ToFixed(y1 - y0 + y1 - y0);
     237                 : 
     238               0 :     fQy     = SkFDot6ToFixed(y0);
     239               0 :     fQDy    = B + (A >> shift);     // biased by shift
     240               0 :     fQDDy   = A >> (shift - 1);     // biased by shift
     241                 : 
     242               0 :     fQLastX = SkFDot6ToFixed(x2);
     243               0 :     fQLastY = SkFDot6ToFixed(y2);
     244                 : 
     245               0 :     return this->updateQuadratic();
     246                 : }
     247                 : 
     248               0 : int SkQuadraticEdge::updateQuadratic()
     249                 : {
     250                 :     int     success;
     251               0 :     int     count = fCurveCount;
     252               0 :     SkFixed oldx = fQx;
     253               0 :     SkFixed oldy = fQy;
     254               0 :     SkFixed dx = fQDx;
     255               0 :     SkFixed dy = fQDy;
     256                 :     SkFixed newx, newy;
     257               0 :     int     shift = fCurveShift;
     258                 : 
     259               0 :     SkASSERT(count > 0);
     260                 : 
     261               0 :     do {
     262               0 :         if (--count > 0)
     263                 :         {
     264               0 :             newx    = oldx + (dx >> shift);
     265               0 :             dx    += fQDDx;
     266               0 :             newy    = oldy + (dy >> shift);
     267               0 :             dy    += fQDDy;
     268                 :         }
     269                 :         else    // last segment
     270                 :         {
     271               0 :             newx    = fQLastX;
     272               0 :             newy    = fQLastY;
     273                 :         }
     274               0 :         success = this->updateLine(oldx, oldy, newx, newy);
     275               0 :         oldx = newx;
     276               0 :         oldy = newy;
     277                 :     } while (count > 0 && !success);
     278                 : 
     279               0 :     fQx         = newx;
     280               0 :     fQy         = newy;
     281               0 :     fQDx        = dx;
     282               0 :     fQDy        = dy;
     283               0 :     fCurveCount = SkToS8(count);
     284               0 :     return success;
     285                 : }
     286                 : 
     287                 : /////////////////////////////////////////////////////////////////////////
     288                 : 
     289               0 : static inline int SkFDot6UpShift(SkFDot6 x, int upShift) {
     290               0 :     SkASSERT((x << upShift >> upShift) == x);
     291               0 :     return x << upShift;
     292                 : }
     293                 : 
     294                 : /*  f(1/3) = (8a + 12b + 6c + d) / 27
     295                 :     f(2/3) = (a + 6b + 12c + 8d) / 27
     296                 : 
     297                 :     f(1/3)-b = (8a - 15b + 6c + d) / 27
     298                 :     f(2/3)-c = (a + 6b - 15c + 8d) / 27
     299                 : 
     300                 :     use 16/512 to approximate 1/27
     301                 : */
     302               0 : static SkFDot6 cubic_delta_from_line(SkFDot6 a, SkFDot6 b, SkFDot6 c, SkFDot6 d)
     303                 : {
     304               0 :     SkFDot6 oneThird = ((a << 3) - ((b << 4) - b) + 6*c + d) * 19 >> 9;
     305               0 :     SkFDot6 twoThird = (a + 6*b - ((c << 4) - c) + (d << 3)) * 19 >> 9;
     306                 : 
     307               0 :     return SkMax32(SkAbs32(oneThird), SkAbs32(twoThird));
     308                 : }
     309                 : 
     310               0 : int SkCubicEdge::setCubic(const SkPoint pts[4], const SkIRect* clip, int shift)
     311                 : {
     312                 :     SkFDot6 x0, y0, x1, y1, x2, y2, x3, y3;
     313                 : 
     314                 :     {
     315                 : #ifdef SK_SCALAR_IS_FLOAT
     316               0 :         float scale = float(1 << (shift + 6));
     317               0 :         x0 = int(pts[0].fX * scale);
     318               0 :         y0 = int(pts[0].fY * scale);
     319               0 :         x1 = int(pts[1].fX * scale);
     320               0 :         y1 = int(pts[1].fY * scale);
     321               0 :         x2 = int(pts[2].fX * scale);
     322               0 :         y2 = int(pts[2].fY * scale);
     323               0 :         x3 = int(pts[3].fX * scale);
     324               0 :         y3 = int(pts[3].fY * scale);
     325                 : #else
     326                 :         shift = 10 - shift;
     327                 :         x0 = pts[0].fX >> shift;
     328                 :         y0 = pts[0].fY >> shift;
     329                 :         x1 = pts[1].fX >> shift;
     330                 :         y1 = pts[1].fY >> shift;
     331                 :         x2 = pts[2].fX >> shift;
     332                 :         y2 = pts[2].fY >> shift;
     333                 :         x3 = pts[3].fX >> shift;
     334                 :         y3 = pts[3].fY >> shift;
     335                 : #endif
     336                 :     }
     337                 : 
     338               0 :     int winding = 1;
     339               0 :     if (y0 > y3)
     340                 :     {
     341               0 :         SkTSwap(x0, x3);
     342               0 :         SkTSwap(x1, x2);
     343               0 :         SkTSwap(y0, y3);
     344               0 :         SkTSwap(y1, y2);
     345               0 :         winding = -1;
     346                 :     }
     347                 : 
     348               0 :     int top = SkFDot6Round(y0);
     349               0 :     int bot = SkFDot6Round(y3);
     350                 : 
     351                 :     // are we a zero-height cubic (line)?
     352               0 :     if (top == bot)
     353               0 :         return 0;
     354                 : 
     355                 :     // are we completely above or below the clip?
     356               0 :     if (clip && (top >= clip->fBottom || bot <= clip->fTop))
     357               0 :         return 0;
     358                 : 
     359                 :     // compute number of steps needed (1 << shift)
     360                 :     {
     361                 :         // Can't use (center of curve - center of baseline), since center-of-curve
     362                 :         // need not be the max delta from the baseline (it could even be coincident)
     363                 :         // so we try just looking at the two off-curve points
     364               0 :         SkFDot6 dx = cubic_delta_from_line(x0, x1, x2, x3);
     365               0 :         SkFDot6 dy = cubic_delta_from_line(y0, y1, y2, y3);
     366                 :         // add 1 (by observation)
     367               0 :         shift = diff_to_shift(dx, dy) + 1;
     368                 :     }
     369                 :     // need at least 1 subdivision for our bias trick
     370               0 :     SkASSERT(shift > 0);
     371               0 :     if (shift > MAX_COEFF_SHIFT) {
     372               0 :         shift = MAX_COEFF_SHIFT;
     373                 :     }
     374                 : 
     375                 :     /*  Since our in coming data is initially shifted down by 10 (or 8 in
     376                 :         antialias). That means the most we can shift up is 8. However, we
     377                 :         compute coefficients with a 3*, so the safest upshift is really 6
     378                 :     */
     379               0 :     int upShift = 6;    // largest safe value
     380               0 :     int downShift = shift + upShift - 10;
     381               0 :     if (downShift < 0) {
     382               0 :         downShift = 0;
     383               0 :         upShift = 10 - shift;
     384                 :     }
     385                 : 
     386               0 :     fWinding    = SkToS8(winding);
     387               0 :     fCurveCount = SkToS8(-1 << shift);
     388               0 :     fCurveShift = SkToU8(shift);
     389               0 :     fCubicDShift = SkToU8(downShift);
     390                 : 
     391               0 :     SkFixed B = SkFDot6UpShift(3 * (x1 - x0), upShift);
     392               0 :     SkFixed C = SkFDot6UpShift(3 * (x0 - x1 - x1 + x2), upShift);
     393               0 :     SkFixed D = SkFDot6UpShift(x3 + 3 * (x1 - x2) - x0, upShift);
     394                 : 
     395               0 :     fCx     = SkFDot6ToFixed(x0);
     396               0 :     fCDx    = B + (C >> shift) + (D >> 2*shift);    // biased by shift
     397               0 :     fCDDx   = 2*C + (3*D >> (shift - 1));           // biased by 2*shift
     398               0 :     fCDDDx  = 3*D >> (shift - 1);                   // biased by 2*shift
     399                 : 
     400               0 :     B = SkFDot6UpShift(3 * (y1 - y0), upShift);
     401               0 :     C = SkFDot6UpShift(3 * (y0 - y1 - y1 + y2), upShift);
     402               0 :     D = SkFDot6UpShift(y3 + 3 * (y1 - y2) - y0, upShift);
     403                 : 
     404               0 :     fCy     = SkFDot6ToFixed(y0);
     405               0 :     fCDy    = B + (C >> shift) + (D >> 2*shift);    // biased by shift
     406               0 :     fCDDy   = 2*C + (3*D >> (shift - 1));           // biased by 2*shift
     407               0 :     fCDDDy  = 3*D >> (shift - 1);                   // biased by 2*shift
     408                 : 
     409               0 :     fCLastX = SkFDot6ToFixed(x3);
     410               0 :     fCLastY = SkFDot6ToFixed(y3);
     411                 : 
     412               0 :     if (clip)
     413                 :     {
     414               0 :         do {
     415               0 :             if (!this->updateCubic()) {
     416               0 :                 return 0;
     417                 :             }
     418               0 :         } while (!this->intersectsClip(*clip));
     419               0 :         this->chopLineWithClip(*clip);
     420               0 :         return 1;
     421                 :     }
     422               0 :     return this->updateCubic();
     423                 : }
     424                 : 
     425               0 : int SkCubicEdge::updateCubic()
     426                 : {
     427                 :     int     success;
     428               0 :     int     count = fCurveCount;
     429               0 :     SkFixed oldx = fCx;
     430               0 :     SkFixed oldy = fCy;
     431                 :     SkFixed newx, newy;
     432               0 :     const int ddshift = fCurveShift;
     433               0 :     const int dshift = fCubicDShift;
     434                 : 
     435               0 :     SkASSERT(count < 0);
     436                 : 
     437               0 :     do {
     438               0 :         if (++count < 0)
     439                 :         {
     440               0 :             newx    = oldx + (fCDx >> dshift);
     441               0 :             fCDx    += fCDDx >> ddshift;
     442               0 :             fCDDx   += fCDDDx;
     443                 : 
     444               0 :             newy    = oldy + (fCDy >> dshift);
     445               0 :             fCDy    += fCDDy >> ddshift;
     446               0 :             fCDDy   += fCDDDy;
     447                 :         }
     448                 :         else    // last segment
     449                 :         {
     450                 :         //  SkDebugf("LastX err=%d, LastY err=%d\n", (oldx + (fCDx >> shift) - fLastX), (oldy + (fCDy >> shift) - fLastY));
     451               0 :             newx    = fCLastX;
     452               0 :             newy    = fCLastY;
     453                 :         }
     454               0 :         success = this->updateLine(oldx, oldy, newx, newy);
     455               0 :         oldx = newx;
     456               0 :         oldy = newy;
     457                 :     } while (count < 0 && !success);
     458                 : 
     459               0 :     fCx         = newx;
     460               0 :     fCy         = newy;
     461               0 :     fCurveCount = SkToS8(count);
     462               0 :     return success;
     463                 : }
     464                 : 
     465                 : 
     466                 : 

Generated by: LCOV version 1.7