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     // We don't chop at y extrema for cubics so the y is not guaranteed to be increasing for them.
     24     // In that case, we have to swap x/y and negate the winding.
     25     if (y0 > y1) {
     26         SkTSwap(x0, x1);
     27         SkTSwap(y0, y1);
     28         fWinding = -fWinding;
     29     }
     30 
     31     SkASSERT(y0 <= y1);
     32 
     33     SkFDot6 dx = SkFixedToFDot6(x1 - x0);
     34     SkFDot6 dy = SkFixedToFDot6(y1 - y0);
     35 
     36     // are we a zero-height line?
     37     if (dy == 0) {
     38         return false;
     39     }
     40 
     41     SkASSERT(slope < SK_MaxS32);
     42 
     43     SkFDot6     absSlope = SkAbs32(SkFixedToFDot6(slope));
     44     fX          = x0;
     45     fDX         = slope;
     46     fUpperX     = x0;
     47     fY          = y0;
     48     fUpperY     = y0;
     49     fLowerY     = y1;
     50     fDY         = (dx == 0 || slope == 0)
     51                   ? SK_MaxS32
     52                   : absSlope < kInverseTableSize
     53                     ? QuickFDot6Inverse::Lookup(absSlope)
     54                     : SkAbs32(QuickSkFDot6Div(dy, dx));
     55 
     56     return true;
     57 }
     58 
     59 bool SkAnalyticEdge::update(SkFixed last_y, bool sortY) {
     60     SkASSERT(last_y >= fLowerY); // we shouldn't update edge if last_y < fLowerY
     61     if (fCurveCount < 0) {
     62         return static_cast<SkAnalyticCubicEdge*>(this)->updateCubic(sortY);
     63     } else if (fCurveCount > 0) {
     64         return static_cast<SkAnalyticQuadraticEdge*>(this)->updateQuadratic();
     65     }
     66     return false;
     67 }
     68 
     69 bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) {
     70     fRiteE = nullptr;
     71 
     72     if (!fQEdge.setQuadraticWithoutUpdate(pts, kDefaultAccuracy)) {
     73         return false;
     74     }
     75     fQEdge.fQx >>= kDefaultAccuracy;
     76     fQEdge.fQy >>= kDefaultAccuracy;
     77     fQEdge.fQDx >>= kDefaultAccuracy;
     78     fQEdge.fQDy >>= kDefaultAccuracy;
     79     fQEdge.fQDDx >>= kDefaultAccuracy;
     80     fQEdge.fQDDy >>= kDefaultAccuracy;
     81     fQEdge.fQLastX >>= kDefaultAccuracy;
     82     fQEdge.fQLastY >>= kDefaultAccuracy;
     83     fQEdge.fQy = SnapY(fQEdge.fQy);
     84     fQEdge.fQLastY = SnapY(fQEdge.fQLastY);
     85 
     86     fWinding = fQEdge.fWinding;
     87     fCurveCount = fQEdge.fCurveCount;
     88     fCurveShift = fQEdge.fCurveShift;
     89 
     90     fSnappedX = fQEdge.fQx;
     91     fSnappedY = fQEdge.fQy;
     92 
     93     return this->updateQuadratic();
     94 }
     95 
     96 bool SkAnalyticQuadraticEdge::updateQuadratic() {
     97     int     success = 0; // initialize to fail!
     98     int     count = fCurveCount;
     99     SkFixed oldx = fQEdge.fQx;
    100     SkFixed oldy = fQEdge.fQy;
    101     SkFixed dx = fQEdge.fQDx;
    102     SkFixed dy = fQEdge.fQDy;
    103     SkFixed newx, newy, newSnappedX, newSnappedY;
    104     int     shift = fCurveShift;
    105 
    106     SkASSERT(count > 0);
    107 
    108     do {
    109         SkFixed slope;
    110         if (--count > 0)
    111         {
    112             newx    = oldx + (dx >> shift);
    113             newy    = oldy + (dy >> shift);
    114             if (SkAbs32(dy >> shift) >= SK_Fixed1 * 2) { // only snap when dy is large enough
    115                 SkFDot6 diffY = SkFixedToFDot6(newy - fSnappedY);
    116                 slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
    117                               : SK_MaxS32;
    118                 newSnappedY = SkTMin<SkFixed>(fQEdge.fQLastY, SkFixedRoundToFixed(newy));
    119                 newSnappedX = newx - SkFixedMul(slope, newy - newSnappedY);
    120             } else {
    121                 newSnappedY = SkTMin(fQEdge.fQLastY, SnapY(newy));
    122                 newSnappedX = newx;
    123                 SkFDot6 diffY = SkFixedToFDot6(newSnappedY - fSnappedY);
    124                 slope = diffY ? QuickSkFDot6Div(SkFixedToFDot6(newx - fSnappedX), diffY)
    125                               : SK_MaxS32;
    126             }
    127             dx += fQEdge.fQDDx;
    128             dy += fQEdge.fQDDy;
    129         }
    130         else    // last segment
    131         {
    132             newx    = fQEdge.fQLastX;
    133             newy    = fQEdge.fQLastY;
    134             newSnappedY = newy;
    135             newSnappedX = newx;
    136             SkFDot6 diffY = (newy - fSnappedY) >> 10;
    137             slope = diffY ? QuickSkFDot6Div((newx - fSnappedX) >> 10, diffY) : SK_MaxS32;
    138         }
    139         if (slope < SK_MaxS32) {
    140             success = this->updateLine(fSnappedX, fSnappedY, newSnappedX, newSnappedY, slope);
    141         }
    142         oldx = newx;
    143         oldy = newy;
    144     } while (count > 0 && !success);
    145 
    146     SkASSERT(newSnappedY <= fQEdge.fQLastY);
    147 
    148     fQEdge.fQx  = newx;
    149     fQEdge.fQy  = newy;
    150     fQEdge.fQDx = dx;
    151     fQEdge.fQDy = dy;
    152     fSnappedX   = newSnappedX;
    153     fSnappedY   = newSnappedY;
    154     fCurveCount = SkToS8(count);
    155     return success;
    156 }
    157 
    158 bool SkAnalyticCubicEdge::setCubic(const SkPoint pts[4], bool sortY) {
    159     fRiteE = nullptr;
    160 
    161     if (!fCEdge.setCubicWithoutUpdate(pts, kDefaultAccuracy, sortY)) {
    162         return false;
    163     }
    164 
    165     fCEdge.fCx >>= kDefaultAccuracy;
    166     fCEdge.fCy >>= kDefaultAccuracy;
    167     fCEdge.fCDx >>= kDefaultAccuracy;
    168     fCEdge.fCDy >>= kDefaultAccuracy;
    169     fCEdge.fCDDx >>= kDefaultAccuracy;
    170     fCEdge.fCDDy >>= kDefaultAccuracy;
    171     fCEdge.fCDDDx >>= kDefaultAccuracy;
    172     fCEdge.fCDDDy >>= kDefaultAccuracy;
    173     fCEdge.fCLastX >>= kDefaultAccuracy;
    174     fCEdge.fCLastY >>= kDefaultAccuracy;
    175     fCEdge.fCy = SnapY(fCEdge.fCy);
    176     fCEdge.fCLastY = SnapY(fCEdge.fCLastY);
    177 
    178     fWinding = fCEdge.fWinding;
    179     fCurveCount = fCEdge.fCurveCount;
    180     fCurveShift = fCEdge.fCurveShift;
    181     fCubicDShift = fCEdge.fCubicDShift;
    182 
    183     fSnappedY = fCEdge.fCy;
    184 
    185     return this->updateCubic(sortY);
    186 }
    187 
    188 bool SkAnalyticCubicEdge::updateCubic(bool sortY) {
    189     int     success;
    190     int     count = fCurveCount;
    191     SkFixed oldx = fCEdge.fCx;
    192     SkFixed oldy = fCEdge.fCy;
    193     SkFixed newx, newy;
    194     const int ddshift = fCurveShift;
    195     const int dshift = fCubicDShift;
    196 
    197     SkASSERT(count < 0);
    198 
    199     do {
    200         if (++count < 0) {
    201             newx    = oldx + (fCEdge.fCDx >> dshift);
    202             fCEdge.fCDx    += fCEdge.fCDDx >> ddshift;
    203             fCEdge.fCDDx   += fCEdge.fCDDDx;
    204 
    205             newy    = oldy + (fCEdge.fCDy >> dshift);
    206             fCEdge.fCDy    += fCEdge.fCDDy >> ddshift;
    207             fCEdge.fCDDy   += fCEdge.fCDDDy;
    208         }
    209         else {    // last segment
    210             newx    = fCEdge.fCLastX;
    211             newy    = fCEdge.fCLastY;
    212         }
    213 
    214         // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint
    215         // doesn't always achieve that, so we have to explicitly pin it here.
    216         if (sortY && newy < oldy) {
    217             newy = oldy;
    218         }
    219 
    220         SkFixed newSnappedY = SnapY(newy);
    221         // we want to SkASSERT(snappedNewY <= fCEdge.fCLastY), but our finite fixedpoint
    222         // doesn't always achieve that, so we have to explicitly pin it here.
    223         if (sortY && fCEdge.fCLastY < newSnappedY) {
    224             newSnappedY = fCEdge.fCLastY;
    225             count = 0;
    226         }
    227 
    228         SkFixed slope = SkFixedToFDot6(newSnappedY - fSnappedY) == 0
    229                         ? SK_MaxS32
    230                         : SkFDot6Div(SkFixedToFDot6(newx - oldx),
    231                                      SkFixedToFDot6(newSnappedY - fSnappedY));
    232 
    233         success = this->updateLine(oldx, fSnappedY, newx, newSnappedY, slope);
    234 
    235         oldx = newx;
    236         oldy = newy;
    237         fSnappedY = newSnappedY;
    238     } while (count < 0 && !success);
    239 
    240     fCEdge.fCx  = newx;
    241     fCEdge.fCy  = newy;
    242     fCurveCount = SkToS8(count);
    243     return success;
    244 }
    245