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

       1                 : 
       2                 : /*
       3                 :  * Copyright 2009 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 "SkEdgeClipper.h"
      11                 : #include "SkGeometry.h"
      12                 : 
      13               0 : static bool quick_reject(const SkRect& bounds, const SkRect& clip) {
      14               0 :     return bounds.fTop >= clip.fBottom || bounds.fBottom <= clip.fTop;
      15                 : }
      16                 : 
      17               0 : static inline void clamp_le(SkScalar& value, SkScalar max) {
      18               0 :     if (value > max) {
      19               0 :         value = max;
      20                 :     }
      21               0 : }
      22                 : 
      23               0 : static inline void clamp_ge(SkScalar& value, SkScalar min) {
      24               0 :     if (value < min) {
      25               0 :         value = min;
      26                 :     }
      27               0 : }
      28                 : 
      29                 : /*  src[] must be monotonic in Y. This routine copies src into dst, and sorts
      30                 :  it to be increasing in Y. If it had to reverse the order of the points,
      31                 :  it returns true, otherwise it returns false
      32                 :  */
      33               0 : static bool sort_increasing_Y(SkPoint dst[], const SkPoint src[], int count) {
      34                 :     // we need the data to be monotonically increasing in Y
      35               0 :     if (src[0].fY > src[count - 1].fY) {
      36               0 :         for (int i = 0; i < count; i++) {
      37               0 :             dst[i] = src[count - i - 1];
      38                 :         }
      39               0 :         return true;
      40                 :     } else {
      41               0 :         memcpy(dst, src, count * sizeof(SkPoint));
      42               0 :         return false;
      43                 :     }
      44                 : }
      45                 : 
      46                 : ///////////////////////////////////////////////////////////////////////////////
      47                 : 
      48               0 : static bool chopMonoQuadAt(SkScalar c0, SkScalar c1, SkScalar c2,
      49                 :                            SkScalar target, SkScalar* t) {
      50                 :     /* Solve F(t) = y where F(t) := [0](1-t)^2 + 2[1]t(1-t) + [2]t^2
      51                 :      *  We solve for t, using quadratic equation, hence we have to rearrange
      52                 :      * our cooefficents to look like At^2 + Bt + C
      53                 :      */
      54               0 :     SkScalar A = c0 - c1 - c1 + c2;
      55               0 :     SkScalar B = 2*(c1 - c0);
      56               0 :     SkScalar C = c0 - target;
      57                 :     
      58                 :     SkScalar roots[2];  // we only expect one, but make room for 2 for safety
      59               0 :     int count = SkFindUnitQuadRoots(A, B, C, roots);
      60               0 :     if (count) {
      61               0 :         *t = roots[0];
      62               0 :         return true;
      63                 :     }
      64               0 :     return false;
      65                 : }
      66                 : 
      67               0 : static bool chopMonoQuadAtY(SkPoint pts[3], SkScalar y, SkScalar* t) {
      68               0 :     return chopMonoQuadAt(pts[0].fY, pts[1].fY, pts[2].fY, y, t);
      69                 : }
      70                 : 
      71               0 : static bool chopMonoQuadAtX(SkPoint pts[3], SkScalar x, SkScalar* t) {
      72               0 :     return chopMonoQuadAt(pts[0].fX, pts[1].fX, pts[2].fX, x, t);
      73                 : }
      74                 : 
      75                 : // Modify pts[] in place so that it is clipped in Y to the clip rect
      76               0 : static void chop_quad_in_Y(SkPoint pts[3], const SkRect& clip) {
      77                 :     SkScalar t;
      78                 :     SkPoint tmp[5]; // for SkChopQuadAt
      79                 : 
      80                 :     // are we partially above
      81               0 :     if (pts[0].fY < clip.fTop) {
      82               0 :         if (chopMonoQuadAtY(pts, clip.fTop, &t)) {
      83                 :             // take the 2nd chopped quad
      84               0 :             SkChopQuadAt(pts, tmp, t);
      85               0 :             clamp_ge(tmp[2].fY, clip.fTop);
      86               0 :             clamp_ge(tmp[3].fY, clip.fTop);
      87               0 :             pts[0] = tmp[2];
      88               0 :             pts[1] = tmp[3];
      89                 :         } else {
      90                 :             // if chopMonoQuadAtY failed, then we may have hit inexact numerics
      91                 :             // so we just clamp against the top
      92               0 :             for (int i = 0; i < 3; i++) {
      93               0 :                 if (pts[i].fY < clip.fTop) {
      94               0 :                     pts[i].fY = clip.fTop;
      95                 :                 }
      96                 :             }
      97                 :         }
      98                 :     }
      99                 :     
     100                 :     // are we partially below
     101               0 :     if (pts[2].fY > clip.fBottom) {
     102               0 :         if (chopMonoQuadAtY(pts, clip.fBottom, &t)) {
     103               0 :             SkChopQuadAt(pts, tmp, t);
     104               0 :             clamp_le(tmp[1].fY, clip.fBottom);
     105               0 :             clamp_le(tmp[2].fY, clip.fBottom);
     106               0 :             pts[1] = tmp[1];
     107               0 :             pts[2] = tmp[2];
     108                 :         } else {
     109                 :             // if chopMonoQuadAtY failed, then we may have hit inexact numerics
     110                 :             // so we just clamp against the bottom
     111               0 :             for (int i = 0; i < 3; i++) {
     112               0 :                 if (pts[i].fY > clip.fBottom) {
     113               0 :                     pts[i].fY = clip.fBottom;
     114                 :                 }
     115                 :             }
     116                 :         }
     117                 :     }
     118               0 : }
     119                 : 
     120                 : // srcPts[] must be monotonic in X and Y
     121               0 : void SkEdgeClipper::clipMonoQuad(const SkPoint srcPts[3], const SkRect& clip) {
     122                 :     SkPoint pts[3];
     123               0 :     bool reverse = sort_increasing_Y(pts, srcPts, 3);
     124                 : 
     125                 :     // are we completely above or below
     126               0 :     if (pts[2].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
     127               0 :         return;
     128                 :     }
     129                 :     
     130                 :     // Now chop so that pts is contained within clip in Y
     131               0 :     chop_quad_in_Y(pts, clip);
     132                 : 
     133               0 :     if (pts[0].fX > pts[2].fX) {
     134               0 :         SkTSwap<SkPoint>(pts[0], pts[2]);
     135               0 :         reverse = !reverse;
     136                 :     }
     137               0 :     SkASSERT(pts[0].fX <= pts[1].fX);
     138               0 :     SkASSERT(pts[1].fX <= pts[2].fX);
     139                 : 
     140                 :     // Now chop in X has needed, and record the segments
     141                 : 
     142               0 :     if (pts[2].fX <= clip.fLeft) {  // wholly to the left
     143               0 :         this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
     144               0 :         return;
     145                 :     }
     146               0 :     if (pts[0].fX >= clip.fRight) {  // wholly to the right
     147               0 :         this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
     148               0 :         return;
     149                 :     }
     150                 : 
     151                 :     SkScalar t;
     152                 :     SkPoint tmp[5]; // for SkChopQuadAt
     153                 : 
     154                 :     // are we partially to the left
     155               0 :     if (pts[0].fX < clip.fLeft) {
     156               0 :         if (chopMonoQuadAtX(pts, clip.fLeft, &t)) {
     157               0 :             SkChopQuadAt(pts, tmp, t);
     158               0 :             this->appendVLine(clip.fLeft, tmp[0].fY, tmp[2].fY, reverse);
     159               0 :             clamp_ge(tmp[2].fX, clip.fLeft);
     160               0 :             clamp_ge(tmp[3].fX, clip.fLeft);
     161               0 :             pts[0] = tmp[2];
     162               0 :             pts[1] = tmp[3];
     163                 :         } else {
     164                 :             // if chopMonoQuadAtY failed, then we may have hit inexact numerics
     165                 :             // so we just clamp against the left
     166               0 :             this->appendVLine(clip.fLeft, pts[0].fY, pts[2].fY, reverse);
     167               0 :             return;
     168                 :         }
     169                 :     }
     170                 :     
     171                 :     // are we partially to the right
     172               0 :     if (pts[2].fX > clip.fRight) {
     173               0 :         if (chopMonoQuadAtX(pts, clip.fRight, &t)) {
     174               0 :             SkChopQuadAt(pts, tmp, t);
     175               0 :             clamp_le(tmp[1].fX, clip.fRight);
     176               0 :             clamp_le(tmp[2].fX, clip.fRight);
     177               0 :             this->appendQuad(tmp, reverse);
     178               0 :             this->appendVLine(clip.fRight, tmp[2].fY, tmp[4].fY, reverse);
     179                 :         } else {
     180                 :             // if chopMonoQuadAtY failed, then we may have hit inexact numerics
     181                 :             // so we just clamp against the right
     182               0 :             this->appendVLine(clip.fRight, pts[0].fY, pts[2].fY, reverse);
     183                 :         }
     184                 :     } else {    // wholly inside the clip
     185               0 :         this->appendQuad(pts, reverse);
     186                 :     }
     187                 : }
     188                 : 
     189               0 : bool SkEdgeClipper::clipQuad(const SkPoint srcPts[3], const SkRect& clip) {
     190               0 :     fCurrPoint = fPoints;
     191               0 :     fCurrVerb = fVerbs;
     192                 : 
     193                 :     SkRect  bounds;
     194               0 :     bounds.set(srcPts, 3);
     195                 :     
     196               0 :     if (!quick_reject(bounds, clip)) {
     197                 :         SkPoint monoY[5];
     198               0 :         int countY = SkChopQuadAtYExtrema(srcPts, monoY);
     199               0 :         for (int y = 0; y <= countY; y++) {
     200                 :             SkPoint monoX[5];
     201               0 :             int countX = SkChopQuadAtXExtrema(&monoY[y * 2], monoX);
     202               0 :             for (int x = 0; x <= countX; x++) {
     203               0 :                 this->clipMonoQuad(&monoX[x * 2], clip);
     204               0 :                 SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
     205               0 :                 SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
     206                 :             }
     207                 :         }
     208                 :     }
     209                 : 
     210               0 :     *fCurrVerb = SkPath::kDone_Verb;
     211               0 :     fCurrPoint = fPoints;
     212               0 :     fCurrVerb = fVerbs;
     213               0 :     return SkPath::kDone_Verb != fVerbs[0];
     214                 : }
     215                 : 
     216                 : ///////////////////////////////////////////////////////////////////////////////
     217                 : 
     218               0 : static SkScalar eval_cubic_coeff(SkScalar A, SkScalar B, SkScalar C,
     219                 :                                  SkScalar D, SkScalar t) {
     220               0 :     return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
     221                 : }
     222                 : 
     223                 : /*  Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the
     224                 :     t value such that cubic(t) = target
     225                 :  */
     226               0 : static bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
     227                 :                            SkScalar target, SkScalar* t) {
     228                 :  //   SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3);
     229               0 :     SkASSERT(c0 < target && target < c3);
     230                 : 
     231               0 :     SkScalar D = c0 - target;
     232               0 :     SkScalar A = c3 + 3*(c1 - c2) - c0;
     233               0 :     SkScalar B = 3*(c2 - c1 - c1 + c0);
     234               0 :     SkScalar C = 3*(c1 - c0);
     235                 : 
     236               0 :     const SkScalar TOLERANCE = SK_Scalar1 / 4096;
     237               0 :     SkScalar minT = 0;
     238               0 :     SkScalar maxT = SK_Scalar1;
     239                 :     SkScalar mid;
     240                 :     int i;
     241               0 :     for (i = 0; i < 16; i++) {
     242               0 :         mid = SkScalarAve(minT, maxT);
     243               0 :         SkScalar delta = eval_cubic_coeff(A, B, C, D, mid);
     244               0 :         if (delta < 0) {
     245               0 :             minT = mid;
     246               0 :             delta = -delta;
     247                 :         } else {
     248               0 :             maxT = mid;
     249                 :         }
     250               0 :         if (delta < TOLERANCE) {
     251               0 :             break;
     252                 :         }
     253                 :     }
     254               0 :     *t = mid;
     255                 : //    SkDebugf("-- evalCubicAt %d delta %g\n", i, eval_cubic_coeff(A, B, C, D, *t));
     256               0 :     return true;
     257                 : }
     258                 : 
     259               0 : static bool chopMonoCubicAtY(SkPoint pts[4], SkScalar y, SkScalar* t) {
     260               0 :     return chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, t);
     261                 : }
     262                 : 
     263               0 : static bool chopMonoCubicAtX(SkPoint pts[4], SkScalar x, SkScalar* t) {
     264               0 :     return chopMonoCubicAt(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, x, t);
     265                 : }
     266                 : 
     267                 : // Modify pts[] in place so that it is clipped in Y to the clip rect
     268               0 : static void chop_cubic_in_Y(SkPoint pts[4], const SkRect& clip) {
     269                 :     SkScalar t;
     270                 :     SkPoint tmp[7]; // for SkChopCubicAt
     271                 :     
     272                 :     // are we partially above
     273               0 :     if (pts[0].fY < clip.fTop) {
     274               0 :         if (chopMonoCubicAtY(pts, clip.fTop, &t)) {
     275               0 :             SkChopCubicAt(pts, tmp, t);
     276                 :             // given the imprecision of computing t, we just slam our Y coord
     277                 :             // to the top of the clip. This also saves us in the bad case where
     278                 :             // the t was soooo bad that the entire segment could have been
     279                 :             // below fBottom
     280               0 :             tmp[3].fY = clip.fTop;
     281               0 :             clamp_ge(tmp[4].fY, clip.fTop);
     282               0 :             clamp_ge(tmp[5].fY, clip.fTop);
     283               0 :             pts[0] = tmp[3];
     284               0 :             pts[1] = tmp[4];
     285               0 :             pts[2] = tmp[5];
     286                 :         } else {
     287                 :             // if chopMonoCubicAtY failed, then we may have hit inexact numerics
     288                 :             // so we just clamp against the top
     289               0 :             for (int i = 0; i < 4; i++) {
     290               0 :                 clamp_ge(pts[i].fY, clip.fTop);
     291                 :             }
     292                 :         }
     293                 :     }
     294                 :     
     295                 :     // are we partially below
     296               0 :     if (pts[3].fY > clip.fBottom) {
     297               0 :         if (chopMonoCubicAtY(pts, clip.fBottom, &t)) {
     298               0 :             SkChopCubicAt(pts, tmp, t);
     299               0 :             clamp_le(tmp[1].fY, clip.fBottom);
     300               0 :             clamp_le(tmp[2].fY, clip.fBottom);
     301               0 :             clamp_le(tmp[3].fY, clip.fBottom);
     302               0 :             pts[1] = tmp[1];
     303               0 :             pts[2] = tmp[2];
     304               0 :             pts[3] = tmp[3];
     305                 :         } else {
     306                 :             // if chopMonoCubicAtY failed, then we may have hit inexact numerics
     307                 :             // so we just clamp against the bottom
     308               0 :             for (int i = 0; i < 4; i++) {
     309               0 :                 clamp_le(pts[i].fY, clip.fBottom);
     310                 :             }
     311                 :         }
     312                 :     }
     313               0 : }
     314                 : 
     315                 : // srcPts[] must be monotonic in X and Y
     316               0 : void SkEdgeClipper::clipMonoCubic(const SkPoint src[4], const SkRect& clip) {
     317                 :     SkPoint pts[4];
     318               0 :     bool reverse = sort_increasing_Y(pts, src, 4);
     319                 :     
     320                 :     // are we completely above or below
     321               0 :     if (pts[3].fY <= clip.fTop || pts[0].fY >= clip.fBottom) {
     322               0 :         return;
     323                 :     }
     324                 : 
     325                 :     // Now chop so that pts is contained within clip in Y
     326               0 :     chop_cubic_in_Y(pts, clip);
     327                 : 
     328               0 :     if (pts[0].fX > pts[3].fX) {
     329               0 :         SkTSwap<SkPoint>(pts[0], pts[3]);
     330               0 :         SkTSwap<SkPoint>(pts[1], pts[2]);
     331               0 :         reverse = !reverse;
     332                 :     }
     333                 :     
     334                 :     // Now chop in X has needed, and record the segments
     335                 :     
     336               0 :     if (pts[3].fX <= clip.fLeft) {  // wholly to the left
     337               0 :         this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
     338               0 :         return;
     339                 :     }
     340               0 :     if (pts[0].fX >= clip.fRight) {  // wholly to the right
     341               0 :         this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
     342               0 :         return;
     343                 :     }
     344                 :     
     345                 :     SkScalar t;
     346                 :     SkPoint tmp[7];
     347                 :     
     348                 :     // are we partially to the left
     349               0 :     if (pts[0].fX < clip.fLeft) {
     350               0 :         if (chopMonoCubicAtX(pts, clip.fLeft, &t)) {
     351               0 :             SkChopCubicAt(pts, tmp, t);
     352               0 :             this->appendVLine(clip.fLeft, tmp[0].fY, tmp[3].fY, reverse);
     353               0 :             clamp_ge(tmp[3].fX, clip.fLeft);
     354               0 :             clamp_ge(tmp[4].fX, clip.fLeft);
     355               0 :             clamp_ge(tmp[5].fX, clip.fLeft);
     356               0 :             pts[0] = tmp[3];
     357               0 :             pts[1] = tmp[4];
     358               0 :             pts[2] = tmp[5];
     359                 :         } else {
     360                 :             // if chopMonocubicAtY failed, then we may have hit inexact numerics
     361                 :             // so we just clamp against the left
     362               0 :             this->appendVLine(clip.fLeft, pts[0].fY, pts[3].fY, reverse);
     363               0 :             return;
     364                 :         }
     365                 :     }
     366                 :     
     367                 :     // are we partially to the right
     368               0 :     if (pts[3].fX > clip.fRight) {
     369               0 :         if (chopMonoCubicAtX(pts, clip.fRight, &t)) {
     370               0 :             SkChopCubicAt(pts, tmp, t);
     371               0 :             clamp_le(tmp[1].fX, clip.fRight);
     372               0 :             clamp_le(tmp[2].fX, clip.fRight);
     373               0 :             clamp_le(tmp[3].fX, clip.fRight);
     374               0 :             this->appendCubic(tmp, reverse);
     375               0 :             this->appendVLine(clip.fRight, tmp[3].fY, tmp[6].fY, reverse);
     376                 :         } else {
     377                 :             // if chopMonoCubicAtX failed, then we may have hit inexact numerics
     378                 :             // so we just clamp against the right
     379               0 :             this->appendVLine(clip.fRight, pts[0].fY, pts[3].fY, reverse);
     380                 :         }
     381                 :     } else {    // wholly inside the clip
     382               0 :         this->appendCubic(pts, reverse);
     383                 :     }
     384                 : }
     385                 : 
     386               0 : bool SkEdgeClipper::clipCubic(const SkPoint srcPts[4], const SkRect& clip) {
     387               0 :     fCurrPoint = fPoints;
     388               0 :     fCurrVerb = fVerbs;
     389                 :     
     390                 :     SkRect  bounds;
     391               0 :     bounds.set(srcPts, 4);
     392                 :     
     393               0 :     if (!quick_reject(bounds, clip)) {
     394                 :         SkPoint monoY[10];
     395               0 :         int countY = SkChopCubicAtYExtrema(srcPts, monoY);
     396               0 :         for (int y = 0; y <= countY; y++) {
     397                 :         //    sk_assert_monotonic_y(&monoY[y * 3], 4);
     398                 :             SkPoint monoX[10];
     399               0 :             int countX = SkChopCubicAtXExtrema(&monoY[y * 3], monoX);
     400               0 :             for (int x = 0; x <= countX; x++) {
     401                 :             //    sk_assert_monotonic_y(&monoX[x * 3], 4);
     402                 :             //    sk_assert_monotonic_x(&monoX[x * 3], 4);
     403               0 :                 this->clipMonoCubic(&monoX[x * 3], clip);
     404               0 :                 SkASSERT(fCurrVerb - fVerbs < kMaxVerbs);
     405               0 :                 SkASSERT(fCurrPoint - fPoints <= kMaxPoints);
     406                 :             }
     407                 :         }
     408                 :     }
     409                 :     
     410               0 :     *fCurrVerb = SkPath::kDone_Verb;
     411               0 :     fCurrPoint = fPoints;
     412               0 :     fCurrVerb = fVerbs;
     413               0 :     return SkPath::kDone_Verb != fVerbs[0];
     414                 : }
     415                 : 
     416                 : ///////////////////////////////////////////////////////////////////////////////
     417                 : 
     418               0 : void SkEdgeClipper::appendVLine(SkScalar x, SkScalar y0, SkScalar y1,
     419                 :                                 bool reverse) {
     420               0 :     *fCurrVerb++ = SkPath::kLine_Verb;
     421                 :     
     422               0 :     if (reverse) {
     423               0 :         SkTSwap<SkScalar>(y0, y1);
     424                 :     }
     425               0 :     fCurrPoint[0].set(x, y0);
     426               0 :     fCurrPoint[1].set(x, y1);
     427               0 :     fCurrPoint += 2;
     428               0 : }
     429                 : 
     430               0 : void SkEdgeClipper::appendQuad(const SkPoint pts[3], bool reverse) {
     431               0 :     *fCurrVerb++ = SkPath::kQuad_Verb;
     432                 :     
     433               0 :     if (reverse) {
     434               0 :         fCurrPoint[0] = pts[2];
     435               0 :         fCurrPoint[2] = pts[0];
     436                 :     } else {
     437               0 :         fCurrPoint[0] = pts[0];
     438               0 :         fCurrPoint[2] = pts[2];
     439                 :     }
     440               0 :     fCurrPoint[1] = pts[1];
     441               0 :     fCurrPoint += 3;
     442               0 : }
     443                 : 
     444               0 : void SkEdgeClipper::appendCubic(const SkPoint pts[4], bool reverse) {
     445               0 :     *fCurrVerb++ = SkPath::kCubic_Verb;
     446                 :     
     447               0 :     if (reverse) {
     448               0 :         for (int i = 0; i < 4; i++) {
     449               0 :             fCurrPoint[i] = pts[3 - i];
     450                 :         }
     451                 :     } else {
     452               0 :         memcpy(fCurrPoint, pts, 4 * sizeof(SkPoint));
     453                 :     }
     454               0 :     fCurrPoint += 4;
     455               0 : }
     456                 : 
     457               0 : SkPath::Verb SkEdgeClipper::next(SkPoint pts[]) {
     458               0 :     SkPath::Verb verb = *fCurrVerb;
     459                 : 
     460               0 :     switch (verb) {
     461                 :         case SkPath::kLine_Verb:
     462               0 :             memcpy(pts, fCurrPoint, 2 * sizeof(SkPoint));
     463               0 :             fCurrPoint += 2;
     464               0 :             fCurrVerb += 1;
     465               0 :             break;
     466                 :         case SkPath::kQuad_Verb:
     467               0 :             memcpy(pts, fCurrPoint, 3 * sizeof(SkPoint));
     468               0 :             fCurrPoint += 3;
     469               0 :             fCurrVerb += 1;
     470               0 :             break;
     471                 :         case SkPath::kCubic_Verb:
     472               0 :             memcpy(pts, fCurrPoint, 4 * sizeof(SkPoint));
     473               0 :             fCurrPoint += 4;
     474               0 :             fCurrVerb += 1;
     475               0 :             break;
     476                 :         case SkPath::kDone_Verb:
     477               0 :             break;
     478                 :         default:
     479               0 :             SkDEBUGFAIL("unexpected verb in quadclippper2 iter");
     480               0 :             break;
     481                 :     }
     482               0 :     return verb;
     483                 : }
     484                 : 
     485                 : ///////////////////////////////////////////////////////////////////////////////
     486                 : 
     487                 : #ifdef SK_DEBUG
     488               0 : static void assert_monotonic(const SkScalar coord[], int count) {
     489               0 :     if (coord[0] > coord[(count - 1) * 2]) {
     490               0 :         for (int i = 1; i < count; i++) {
     491               0 :             SkASSERT(coord[2 * (i - 1)] >= coord[i * 2]);
     492                 :         }
     493               0 :     } else if (coord[0] < coord[(count - 1) * 2]) {
     494               0 :         for (int i = 1; i < count; i++) {
     495               0 :             SkASSERT(coord[2 * (i - 1)] <= coord[i * 2]);
     496                 :         }
     497                 :     } else {
     498               0 :         for (int i = 1; i < count; i++) {
     499               0 :             SkASSERT(coord[2 * (i - 1)] == coord[i * 2]);
     500                 :         }
     501                 :     }
     502               0 : }
     503                 : 
     504               0 : void sk_assert_monotonic_y(const SkPoint pts[], int count) {
     505               0 :     if (count > 1) {
     506               0 :         assert_monotonic(&pts[0].fY, count);
     507                 :     }
     508               0 : }
     509                 : 
     510               0 : void sk_assert_monotonic_x(const SkPoint pts[], int count) {
     511               0 :     if (count > 1) {
     512               0 :         assert_monotonic(&pts[0].fX, count);
     513                 :     }
     514               0 : }
     515                 : #endif

Generated by: LCOV version 1.7