LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/gl - GrGLPath.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 160 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2012 Google Inc.
       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             : #include "GrGLPath.h"
       9             : #include "GrGLPathRendering.h"
      10             : #include "GrGLGpu.h"
      11             : #include "GrStyle.h"
      12             : 
      13             : namespace {
      14           0 : inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) {
      15             :     static const GrGLubyte gTable[] = {
      16             :         GR_GL_MOVE_TO,
      17             :         GR_GL_LINE_TO,
      18             :         GR_GL_QUADRATIC_CURVE_TO,
      19             :         GR_GL_CONIC_CURVE_TO,
      20             :         GR_GL_CUBIC_CURVE_TO,
      21             :         GR_GL_CLOSE_PATH,
      22             :     };
      23             :     GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
      24             :     GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
      25             :     GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
      26             :     GR_STATIC_ASSERT(3 == SkPath::kConic_Verb);
      27             :     GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
      28             :     GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
      29             : 
      30           0 :     SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
      31           0 :     return gTable[verb];
      32             : }
      33             : 
      34             : #ifdef SK_DEBUG
      35           0 : inline int num_coords(SkPath::Verb verb) {
      36             :     static const int gTable[] = {
      37             :         2, // move
      38             :         2, // line
      39             :         4, // quad
      40             :         5, // conic
      41             :         6, // cubic
      42             :         0, // close
      43             :     };
      44             :     GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
      45             :     GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
      46             :     GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
      47             :     GR_STATIC_ASSERT(3 == SkPath::kConic_Verb);
      48             :     GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
      49             :     GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
      50             : 
      51           0 :     SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
      52           0 :     return gTable[verb];
      53             : }
      54             : #endif
      55             : 
      56           0 : inline GrGLenum join_to_gl_join(SkPaint::Join join) {
      57             :     static GrGLenum gSkJoinsToGrGLJoins[] = {
      58             :         GR_GL_MITER_REVERT,
      59             :         GR_GL_ROUND,
      60             :         GR_GL_BEVEL
      61             :     };
      62           0 :     return gSkJoinsToGrGLJoins[join];
      63             :     GR_STATIC_ASSERT(0 == SkPaint::kMiter_Join);
      64             :     GR_STATIC_ASSERT(1 == SkPaint::kRound_Join);
      65             :     GR_STATIC_ASSERT(2 == SkPaint::kBevel_Join);
      66             :     GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkJoinsToGrGLJoins) == SkPaint::kJoinCount);
      67             : }
      68             : 
      69           0 : inline GrGLenum cap_to_gl_cap(SkPaint::Cap cap) {
      70             :     static GrGLenum gSkCapsToGrGLCaps[] = {
      71             :         GR_GL_FLAT,
      72             :         GR_GL_ROUND,
      73             :         GR_GL_SQUARE
      74             :     };
      75           0 :     return gSkCapsToGrGLCaps[cap];
      76             :     GR_STATIC_ASSERT(0 == SkPaint::kButt_Cap);
      77             :     GR_STATIC_ASSERT(1 == SkPaint::kRound_Cap);
      78             :     GR_STATIC_ASSERT(2 == SkPaint::kSquare_Cap);
      79             :     GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkCapsToGrGLCaps) == SkPaint::kCapCount);
      80             : }
      81             : 
      82             : #ifdef SK_DEBUG
      83           0 : inline void verify_floats(const float* floats, int count) {
      84           0 :     for (int i = 0; i < count; ++i) {
      85           0 :         SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
      86             :     }
      87           0 : }
      88             : #endif
      89             : 
      90           0 : inline void points_to_coords(const SkPoint points[], size_t first_point, size_t amount,
      91             :                              GrGLfloat coords[]) {
      92           0 :     for (size_t i = 0;  i < amount; ++i) {
      93           0 :         coords[i * 2] =  SkScalarToFloat(points[first_point + i].fX);
      94           0 :         coords[i * 2 + 1] = SkScalarToFloat(points[first_point + i].fY);
      95             :     }
      96           0 : }
      97             : 
      98             : template<bool checkForDegenerates>
      99           0 : inline bool init_path_object_for_general_path(GrGLGpu* gpu, GrGLuint pathID,
     100             :                                               const SkPath& skPath) {
     101           0 :     SkDEBUGCODE(int numCoords = 0);
     102           0 :     int verbCnt = skPath.countVerbs();
     103           0 :     int pointCnt = skPath.countPoints();
     104           0 :     int minCoordCnt = pointCnt * 2;
     105             : 
     106           0 :     SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
     107           0 :     SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt);
     108           0 :     bool lastVerbWasMove = true; // A path with just "close;" means "moveto(0,0); close;"
     109             :     SkPoint points[4];
     110           0 :     SkPath::RawIter iter(skPath);
     111             :     SkPath::Verb verb;
     112           0 :     while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
     113           0 :         pathCommands.push_back(verb_to_gl_path_cmd(verb));
     114             :         GrGLfloat coords[6];
     115             :         int coordsForVerb;
     116           0 :         switch (verb) {
     117             :             case SkPath::kMove_Verb:
     118             :                 if (checkForDegenerates) {
     119           0 :                     lastVerbWasMove = true;
     120             :                 }
     121           0 :                 points_to_coords(points, 0, 1, coords);
     122           0 :                 coordsForVerb = 2;
     123           0 :                 break;
     124             :             case SkPath::kLine_Verb:
     125             :                 if (checkForDegenerates) {
     126           0 :                     if (SkPath::IsLineDegenerate(points[0], points[1], true)) {
     127           0 :                         return false;
     128             :                     }
     129           0 :                     lastVerbWasMove = false;
     130             :                 }
     131             : 
     132           0 :                 points_to_coords(points, 1, 1, coords);
     133           0 :                 coordsForVerb = 2;
     134           0 :                 break;
     135             :             case SkPath::kConic_Verb:
     136             :                 if (checkForDegenerates) {
     137           0 :                     if (SkPath::IsQuadDegenerate(points[0], points[1], points[2], true)) {
     138           0 :                         return false;
     139             :                     }
     140           0 :                     lastVerbWasMove = false;
     141             :                 }
     142           0 :                 points_to_coords(points, 1, 2, coords);
     143           0 :                 coords[4] = SkScalarToFloat(iter.conicWeight());
     144           0 :                 coordsForVerb = 5;
     145           0 :                 break;
     146             :             case SkPath::kQuad_Verb:
     147             :                 if (checkForDegenerates) {
     148           0 :                     if (SkPath::IsQuadDegenerate(points[0], points[1], points[2], true)) {
     149           0 :                         return false;
     150             :                     }
     151           0 :                     lastVerbWasMove = false;
     152             :                 }
     153           0 :                 points_to_coords(points, 1, 2, coords);
     154           0 :                 coordsForVerb = 4;
     155           0 :                 break;
     156             :             case SkPath::kCubic_Verb:
     157             :                 if (checkForDegenerates) {
     158           0 :                     if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3],
     159             :                                                   true)) {
     160           0 :                         return false;
     161             :                     }
     162           0 :                     lastVerbWasMove = false;
     163             :                 }
     164           0 :                 points_to_coords(points, 1, 3, coords);
     165           0 :                 coordsForVerb = 6;
     166           0 :                 break;
     167             :             case SkPath::kClose_Verb:
     168             :                 if (checkForDegenerates) {
     169           0 :                     if (lastVerbWasMove) {
     170             :                         // Interpret "move(x,y);close;" as "move(x,y);lineto(x,y);close;".
     171             :                         // which produces a degenerate segment.
     172           0 :                         return false;
     173             :                     }
     174             :                 }
     175           0 :                 continue;
     176             :             default:
     177           0 :                 SkASSERT(false);  // Not reached.
     178           0 :                 continue;
     179             :         }
     180           0 :         SkDEBUGCODE(numCoords += num_coords(verb));
     181           0 :         SkDEBUGCODE(verify_floats(coords, coordsForVerb));
     182           0 :         pathCoords.push_back_n(coordsForVerb, coords);
     183             :     }
     184           0 :     SkASSERT(verbCnt == pathCommands.count());
     185           0 :     SkASSERT(numCoords == pathCoords.count());
     186             : 
     187           0 :     GR_GL_CALL(gpu->glInterface(),
     188             :                PathCommands(pathID, pathCommands.count(), pathCommands.begin(),
     189             :                             pathCoords.count(), GR_GL_FLOAT, pathCoords.begin()));
     190           0 :     return true;
     191             : }
     192             : 
     193             : /*
     194             :  * For now paths only natively support winding and even odd fill types
     195             :  */
     196           0 : static GrPathRendering::FillType convert_skpath_filltype(SkPath::FillType fill) {
     197           0 :     switch (fill) {
     198             :         default:
     199           0 :             SkFAIL("Incomplete Switch\n");
     200             :         case SkPath::kWinding_FillType:
     201             :         case SkPath::kInverseWinding_FillType:
     202           0 :             return GrPathRendering::kWinding_FillType;
     203             :         case SkPath::kEvenOdd_FillType:
     204             :         case SkPath::kInverseEvenOdd_FillType:
     205           0 :             return GrPathRendering::kEvenOdd_FillType;
     206             :     }
     207             : }
     208             : 
     209             : } // namespace
     210             : 
     211           0 : bool GrGLPath::InitPathObjectPathDataCheckingDegenerates(GrGLGpu* gpu, GrGLuint pathID,
     212             :                                                          const SkPath& skPath) {
     213           0 :     return init_path_object_for_general_path<true>(gpu, pathID, skPath);
     214             : }
     215             : 
     216           0 : void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu,
     217             :                                       GrGLuint pathID,
     218             :                                       const SkPath& skPath) {
     219           0 :     SkASSERT(!skPath.isEmpty());
     220             : 
     221             : #if 1  //  SK_SCALAR_IS_FLOAT
     222             :     // This branch does type punning, converting SkPoint* to GrGLfloat*.
     223           0 :     if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) {
     224           0 :         int verbCnt = skPath.countVerbs();
     225           0 :         int pointCnt = skPath.countPoints();
     226           0 :         int coordCnt = pointCnt * 2;
     227           0 :         SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
     228           0 :         SkSTArray<16, GrGLfloat, true> pathCoords(coordCnt);
     229             : 
     230             :         static_assert(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, "sk_point_not_two_floats");
     231             : 
     232           0 :         pathCommands.resize_back(verbCnt);
     233           0 :         pathCoords.resize_back(coordCnt);
     234           0 :         skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt);
     235           0 :         skPath.getVerbs(&pathCommands[0], verbCnt);
     236             : 
     237           0 :         SkDEBUGCODE(int verbCoordCnt = 0);
     238           0 :         for (int i = 0; i < verbCnt; ++i) {
     239           0 :             SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
     240           0 :             pathCommands[i] = verb_to_gl_path_cmd(v);
     241           0 :             SkDEBUGCODE(verbCoordCnt += num_coords(v));
     242             :         }
     243           0 :         SkASSERT(verbCnt == pathCommands.count());
     244           0 :         SkASSERT(verbCoordCnt == pathCoords.count());
     245           0 :         SkDEBUGCODE(verify_floats(&pathCoords[0], pathCoords.count()));
     246           0 :         GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0],
     247             :                                                     pathCoords.count(), GR_GL_FLOAT,
     248             :                                                     &pathCoords[0]));
     249           0 :         return;
     250             :     }
     251             : #endif
     252           0 :     SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath));
     253             : }
     254             : 
     255           0 : void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const SkStrokeRec& stroke) {
     256           0 :     SkASSERT(!stroke.isHairlineStyle());
     257           0 :     GR_GL_CALL(gpu->glInterface(),
     258             :                PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
     259           0 :     GR_GL_CALL(gpu->glInterface(),
     260             :                PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
     261           0 :     GrGLenum join = join_to_gl_join(stroke.getJoin());
     262           0 :     GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
     263           0 :     GrGLenum cap = cap_to_gl_cap(stroke.getCap());
     264           0 :     GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap));
     265           0 :     GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f));
     266           0 : }
     267             : 
     268           0 : void GrGLPath::InitPathObjectEmptyPath(GrGLGpu* gpu, GrGLuint pathID) {
     269           0 :     GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLOAT, nullptr));
     270           0 : }
     271             : 
     272           0 : GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStyle& style)
     273             :     : INHERITED(gpu, origSkPath, style),
     274           0 :       fPathID(gpu->glPathRendering()->genPaths(1)) {
     275             : 
     276           0 :     if (origSkPath.isEmpty()) {
     277           0 :         InitPathObjectEmptyPath(gpu, fPathID);
     278           0 :         fShouldStroke = false;
     279           0 :         fShouldFill = false;
     280             :     } else {
     281           0 :         const SkPath* skPath = &origSkPath;
     282           0 :         SkTLazy<SkPath> tmpPath;
     283           0 :         SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
     284             : 
     285           0 :         if (style.pathEffect()) {
     286             :             // Skia stroking and NVPR stroking differ with respect to dashing
     287             :             // pattern.
     288             :             // Convert a dashing (or other path effect) to either a stroke or a fill.
     289           0 :             if (style.applyPathEffectToPath(tmpPath.init(), &stroke, *skPath, SK_Scalar1)) {
     290           0 :                 skPath = tmpPath.get();
     291             :             }
     292             :         } else {
     293           0 :             stroke = style.strokeRec();
     294             :         }
     295             : 
     296           0 :         bool didInit = false;
     297           0 :         if (stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap) {
     298             :             // Skia stroking and NVPR stroking differ with respect to stroking
     299             :             // end caps of empty subpaths.
     300             :             // Convert stroke to fill if path contains empty subpaths.
     301           0 :             didInit = InitPathObjectPathDataCheckingDegenerates(gpu, fPathID, *skPath);
     302           0 :             if (!didInit) {
     303           0 :                 if (!tmpPath.isValid()) {
     304           0 :                     tmpPath.init();
     305             :                 }
     306           0 :                 SkAssertResult(stroke.applyToPath(tmpPath.get(), *skPath));
     307           0 :                 skPath = tmpPath.get();
     308           0 :                 stroke.setFillStyle();
     309             :             }
     310             :         }
     311             : 
     312           0 :         if (!didInit) {
     313           0 :             InitPathObjectPathData(gpu, fPathID, *skPath);
     314             :         }
     315             : 
     316           0 :         fShouldStroke = stroke.needToApply();
     317           0 :         fShouldFill = stroke.isFillStyle() ||
     318           0 :                 stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
     319             : 
     320           0 :         fFillType = convert_skpath_filltype(skPath->getFillType());
     321           0 :         fBounds = skPath->getBounds();
     322           0 :         SkScalar radius = stroke.getInflationRadius();
     323           0 :         fBounds.outset(radius, radius);
     324           0 :         if (fShouldStroke) {
     325           0 :             InitPathObjectStroke(gpu, fPathID, stroke);
     326             :         }
     327             :     }
     328             : 
     329           0 :     this->registerWithCache(SkBudgeted::kYes);
     330           0 : }
     331             : 
     332           0 : void GrGLPath::onRelease() {
     333           0 :     if (0 != fPathID) {
     334           0 :         static_cast<GrGLGpu*>(this->getGpu())->glPathRendering()->deletePaths(fPathID, 1);
     335           0 :         fPathID = 0;
     336             :     }
     337             : 
     338           0 :     INHERITED::onRelease();
     339           0 : }
     340             : 
     341           0 : void GrGLPath::onAbandon() {
     342           0 :     fPathID = 0;
     343             : 
     344           0 :     INHERITED::onAbandon();
     345           0 : }

Generated by: LCOV version 1.13