LCOV - app.info - gfx/skia/src/core/SkEdgeClipper.cpp

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-07-07 | 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