Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 
      9 #include "SkAnalyticEdge.h"
     10 #include "SkFDot6.h"
     11 #include "SkMathPriv.h"
     12 
     13 // This will become a bottleneck for small ovals rendering if we call SkFixedDiv twice here.
     14 // Therefore, we'll let the outter function compute the slope once and send in the value.
     15 // Moreover, we'll compute fDY by quickly lookup the inverse table (if possible).
     16 bool SkAnalyticEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1, SkFixed slope) {
     17     // Since we send in the slope, we can no longer snap y inside this function.
     18     // If we don't send in the slope, or we do some more sophisticated snapping, this function
     19     // could be a performance bottleneck.
     20     SkASSERT(fWinding == 1 || fWinding == -1);
     21     SkASSERT(fCurveCount != 0);
     22 
     23     SkASSERT(y0 <= y1);
     24 
     25     SkFDot6 dx = SkFixedToFDot6(x1 - x0);
     26     SkFDot6 dy = SkFixedToFDot6(y1 - y0);
     27 
     28     // are we a zero-height line?
     29     if (dy == 0) {
     30         return false;
     31     }
     32 
     33     SkASSERT(slope < SK_MaxS32);
     34 
     35     SkFDot6     absSlope = SkAbs32(SkFixedToFDot6(slope));
     36     fX          = x0;
     37     fDX         = slope;
     38     fUpperX     = x0;
     39     fY          = y0;
     40     fUpperY     = y0;
     41     fLowerY     = y1;
     42     fDY         = (dx == 0 || slope == 0)
     43                   ? SK_MaxS32
     44                   : absSlope < kInverseTableSize
     45                     ? QuickFDot6Inverse::Lookup(absSlope)
     46                     : SkAbs32(QuickSkFDot6Div(dy, dx));
     47 
     48     return true;
     49 }
     50 
     51 bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) {
     52     fRiteE = nullptr;
     53 
     54     if (!fQEdge.setQuadraticWithoutUpdate(pts, kDefaultAccuracy)) {
     55         return false;
     56     }
     57     fQEdge.fQx >>= kDefaultAccuracy;
     58     fQEdge.fQy >>= kDefaultAccuracy;
     59     fQEdge.fQDx >>= kDefaultAccuracy;
     60     fQEdge.fQDy >>= kDefaultAccuracy;
     61     fQEdge.fQDDx >>= kDefaultAccuracy;
     62     fQEdge.fQDDy >>= kDefaultAccuracy;
     63     fQEdge.fQLastX >>= kDefaultAccuracy;
     64     fQEdge.fQLastY >>= kDefaultAccuracy;
     65     fQEdge.fQy = SnapY(fQEdge.fQy);
     66     fQEdge.fQLastY = SnapY(fQEdge.fQLastY);
     67 
     68     fWinding = fQEdge.fWinding;
     69     fCurveCount = fQEdge.fCurveCount;
     70     fCurveShift = fQEdge.fCurveShift;
     71 
     72     fSnappedX = fQEdge.fQx;
     73     fSnappedY = fQEdge.fQy;
     74 
     75     return this->updateQuadratic();
     76 }
     77 
     78 bool SkAnalyticQuadraticEdge::updateQuadratic() {
     79     int     success = 0; // initialize to fail!
     80     int     count = fCurveCount;
     81     SkFixed oldx = fQEdge.fQx;
     82     SkFixed oldy = fQEdge.fQy;
     83     SkFixed dx = fQEdge.fQDx;
     84     SkFixed dy = fQEdge.fQDy;
     85     SkFixed newx, newy, newSnappedX, newSnappedY;
     86     int     shift = fCurveShift;
     87 
     88     SkASSERT(count > 0);
     89 
     90     do {
     91         SkFixed slope;
     92         if (--count > 0)
     93         {
     94             newx    = oldx + (dx >> shift);
     95             newy    = oldy + (dy >> shift);
     96             if (SkAbs32(dy >> shift) >= SK_Fixed1 * 2) { // only snap when dy is large enough
     97                 SkFDot6 diffY = SkFixedToFDot6(newy - fSnappedY);
     98                 slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
     99                               : SK_MaxS32;
    100                 newSnappedY = SkTMin<SkFixed>(fQEdge.fQLastY, SkFixedRoundToFixed(newy));
    101                 newSnappedX = newx - SkFixedMul(slope, newy - newSnappedY);
    102             } else {
    103                 newSnappedY = SkTMin(fQEdge.fQLastY, SnapY(newy));
    104                 newSnappedX = newx;
    105                 SkFDot6 diffY = SkFixedToFDot6(newSnappedY - fSnappedY);
    106                 slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
    107                               : SK_MaxS32;
    108             }
    109             dx += fQEdge.fQDDx;
    110             dy += fQEdge.fQDDy;
    111         }
    112         else    // last segment
    113         {
    114             newx    = fQEdge.fQLastX;
    115             newy    = fQEdge.fQLastY;
    116             newSnappedY = newy;
    117             newSnappedX = newx;
    118             SkFDot6 diffY = (newy - fSnappedY) >> 10;
    119             slope = diffY ? QuickSkFDot6Div((newx - fSnappedX) >> 10, diffY) : SK_MaxS32;
    120         }
    121         if (slope < SK_MaxS32) {
    122             success = this->updateLine(fSnappedX, fSnappedY, newSnappedX, newSnappedY, slope);
    123         }
    124         oldx = newx;
    125         oldy = newy;
    126     } while (count > 0 && !success);
    127 
    128     SkASSERT(newSnappedY <= fQEdge.fQLastY);
    129 
    130     fQEdge.fQx  = newx;
    131     fQEdge.fQy  = newy;
    132     fQEdge.fQDx = dx;
    133     fQEdge.fQDy = dy;
    134     fSnappedX   = newSnappedX;
    135     fSnappedY   = newSnappedY;
    136     fCurveCount = SkToS8(count);
    137     return success;
    138 }
    139 
    140 bool SkAnalyticCubicEdge::setCubic(const SkPoint pts[4]) {
    141     fRiteE = nullptr;
    142 
    143     if (!fCEdge.setCubicWithoutUpdate(pts, kDefaultAccuracy)) {
    144         return false;
    145     }
    146 
    147     fCEdge.fCx >>= kDefaultAccuracy;
    148     fCEdge.fCy >>= kDefaultAccuracy;
    149     fCEdge.fCDx >>= kDefaultAccuracy;
    150     fCEdge.fCDy >>= kDefaultAccuracy;
    151     fCEdge.fCDDx >>= kDefaultAccuracy;
    152     fCEdge.fCDDy >>= kDefaultAccuracy;
    153     fCEdge.fCDDDx >>= kDefaultAccuracy;
    154     fCEdge.fCDDDy >>= kDefaultAccuracy;
    155     fCEdge.fCLastX >>= kDefaultAccuracy;
    156     fCEdge.fCLastY >>= kDefaultAccuracy;
    157     fCEdge.fCy = SnapY(fCEdge.fCy);
    158     fCEdge.fCLastY = SnapY(fCEdge.fCLastY);
    159 
    160     fWinding = fCEdge.fWinding;
    161     fCurveCount = fCEdge.fCurveCount;
    162     fCurveShift = fCEdge.fCurveShift;
    163     fCubicDShift = fCEdge.fCubicDShift;
    164 
    165     fSnappedY = fCEdge.fCy;
    166 
    167     return this->updateCubic();
    168 }
    169 
    170 bool SkAnalyticCubicEdge::updateCubic() {
    171     int     success;
    172     int     count = fCurveCount;
    173     SkFixed oldx = fCEdge.fCx;
    174     SkFixed oldy = fCEdge.fCy;
    175     SkFixed newx, newy;
    176     const int ddshift = fCurveShift;
    177     const int dshift = fCubicDShift;
    178 
    179     SkASSERT(count < 0);
    180 
    181     do {
    182         if (++count < 0) {
    183             newx    = oldx + (fCEdge.fCDx >> dshift);
    184             fCEdge.fCDx    += fCEdge.fCDDx >> ddshift;
    185             fCEdge.fCDDx   += fCEdge.fCDDDx;
    186 
    187             newy    = oldy + (fCEdge.fCDy >> dshift);
    188             fCEdge.fCDy    += fCEdge.fCDDy >> ddshift;
    189             fCEdge.fCDDy   += fCEdge.fCDDDy;
    190         }
    191         else {    // last segment
    192             newx    = fCEdge.fCLastX;
    193             newy    = fCEdge.fCLastY;
    194         }
    195 
    196         // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint
    197         // doesn't always achieve that, so we have to explicitly pin it here.
    198         if (newy < oldy) {
    199             newy = oldy;
    200         }
    201 
    202         SkFixed newSnappedY = SnapY(newy);
    203         // we want to SkASSERT(snappedNewY <= fCEdge.fCLastY), but our finite fixedpoint
    204         // doesn't always achieve that, so we have to explicitly pin it here.
    205         if (fCEdge.fCLastY < newSnappedY) {
    206             newSnappedY = fCEdge.fCLastY;
    207             count = 0;
    208         }
    209 
    210         SkFixed slope = SkFixedToFDot6(newSnappedY - fSnappedY) == 0
    211                         ? SK_MaxS32
    212                         : SkFDot6Div(SkFixedToFDot6(newx - oldx),
    213                                      SkFixedToFDot6(newSnappedY - fSnappedY));
    214 
    215         success = this->updateLine(oldx, fSnappedY, newx, newSnappedY, slope);
    216 
    217         oldx = newx;
    218         oldy = newy;
    219         fSnappedY = newSnappedY;
    220     } while (count < 0 && !success);
    221 
    222     fCEdge.fCx  = newx;
    223     fCEdge.fCy  = newy;
    224     fCurveCount = SkToS8(count);
    225     return success;
    226 }
    227