Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(341)

Unified Diff: src/gpu/gl/GrGLPath.cpp

Issue 1471763002: Fix stroking of zero length paths with end caps on NVPR (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/gl/GrGLPath.h ('k') | src/gpu/gl/GrGLPathRange.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/gl/GrGLPath.cpp
diff --git a/src/gpu/gl/GrGLPath.cpp b/src/gpu/gl/GrGLPath.cpp
index 1dfeaee7b3f8e0f7144cae87b7cb49da2cde5c9f..d1fc39dffcc554e22035ced711275323b2baa9fb 100644
--- a/src/gpu/gl/GrGLPath.cpp
+++ b/src/gpu/gl/GrGLPath.cpp
@@ -86,128 +86,218 @@ inline void points_to_coords(const SkPoint points[], size_t first_point, size_t
coords[i * 2 + 1] = SkScalarToFloat(points[first_point + i].fY);
}
}
+
+template<bool checkForDegenerates>
+inline bool init_path_object_for_general_path(GrGLGpu* gpu, GrGLuint pathID,
+ const SkPath& skPath) {
+ SkDEBUGCODE(int numCoords = 0);
+ int verbCnt = skPath.countVerbs();
+ int pointCnt = skPath.countPoints();
+ int minCoordCnt = pointCnt * 2;
+
+ SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
+ SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt);
+ bool lastVerbWasMove = true; // A path with just "close;" means "moveto(0,0); close;"
+ SkPoint points[4];
+ SkPath::RawIter iter(skPath);
+ SkPath::Verb verb;
+ while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
+ pathCommands.push_back(verb_to_gl_path_cmd(verb));
+ GrGLfloat coords[6];
+ int coordsForVerb;
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ if (checkForDegenerates) {
+ lastVerbWasMove = true;
+ }
+ points_to_coords(points, 0, 1, coords);
+ coordsForVerb = 2;
+ break;
+ case SkPath::kLine_Verb:
+ if (checkForDegenerates) {
+ if (SkPath::IsLineDegenerate(points[0], points[1], true)) {
+ return false;
+ }
+ lastVerbWasMove = false;
+ }
+
+ points_to_coords(points, 1, 1, coords);
+ coordsForVerb = 2;
+ break;
+ case SkPath::kConic_Verb:
+ if (checkForDegenerates) {
+ if (SkPath::IsQuadDegenerate(points[0], points[1], points[2], true)) {
+ return false;
+ }
+ lastVerbWasMove = false;
+ }
+ points_to_coords(points, 1, 2, coords);
+ coords[4] = SkScalarToFloat(iter.conicWeight());
+ coordsForVerb = 5;
+ break;
+ case SkPath::kQuad_Verb:
+ if (checkForDegenerates) {
+ if (SkPath::IsQuadDegenerate(points[0], points[1], points[2], true)) {
+ return false;
+ }
+ lastVerbWasMove = false;
+ }
+ points_to_coords(points, 1, 2, coords);
+ coordsForVerb = 4;
+ break;
+ case SkPath::kCubic_Verb:
+ if (checkForDegenerates) {
+ if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3],
+ true)) {
+ return false;
+ }
+ lastVerbWasMove = false;
+ }
+ points_to_coords(points, 1, 3, coords);
+ coordsForVerb = 6;
+ break;
+ case SkPath::kClose_Verb:
+ if (checkForDegenerates) {
+ if (lastVerbWasMove) {
+ // Interpret "move(x,y);close;" as "move(x,y);lineto(x,y);close;".
+ // which produces a degenerate segment.
+ return false;
+ }
+ }
+ continue;
+ default:
+ SkASSERT(false); // Not reached.
+ continue;
+ }
+ SkDEBUGCODE(numCoords += num_coords(verb));
+ pathCoords.push_back_n(coordsForVerb, coords);
+ }
+ SkASSERT(verbCnt == pathCommands.count());
+ SkASSERT(numCoords == pathCoords.count());
+
+ GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0],
+ pathCoords.count(), GR_GL_FLOAT, &pathCoords[0]));
+ return true;
}
+} // namespace
-void GrGLPath::InitPathObject(GrGLGpu* gpu,
- GrGLuint pathID,
- const SkPath& skPath,
- const GrStrokeInfo& stroke) {
- SkASSERT(!stroke.isDashed());
- if (!skPath.isEmpty()) {
+bool GrGLPath::InitPathObjectPathDataCheckingDegenerates(GrGLGpu* gpu, GrGLuint pathID,
+ const SkPath& skPath) {
+ return init_path_object_for_general_path<true>(gpu, pathID, skPath);
+}
+
+void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu,
+ GrGLuint pathID,
+ const SkPath& skPath) {
+ SkASSERT(!skPath.isEmpty());
+
+#ifdef SK_SCALAR_IS_FLOAT
+ // This branch does type punning, converting SkPoint* to GrGLfloat*.
+ if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) {
int verbCnt = skPath.countVerbs();
int pointCnt = skPath.countPoints();
- int minCoordCnt = pointCnt * 2;
-
+ int coordCnt = pointCnt * 2;
SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
- SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt);
+ SkSTArray<16, GrGLfloat, true> pathCoords(coordCnt);
- SkDEBUGCODE(int numCoords = 0);
+ static_assert(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, "sk_point_not_two_floats");
- if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) {
- // This branch does type punning, converting SkPoint* to GrGLfloat*.
- static_assert(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, "sk_point_not_two_floats");
- // This branch does not convert with SkScalarToFloat.
-#ifndef SK_SCALAR_IS_FLOAT
-#error Need SK_SCALAR_IS_FLOAT.
-#endif
- pathCommands.resize_back(verbCnt);
- pathCoords.resize_back(minCoordCnt);
- skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt);
- skPath.getVerbs(&pathCommands[0], verbCnt);
- for (int i = 0; i < verbCnt; ++i) {
- SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
- pathCommands[i] = verb_to_gl_path_cmd(v);
- SkDEBUGCODE(numCoords += num_coords(v));
- }
- } else {
- SkPoint points[4];
- SkPath::RawIter iter(skPath);
- SkPath::Verb verb;
- while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
- pathCommands.push_back(verb_to_gl_path_cmd(verb));
- GrGLfloat coords[6];
- int coordsForVerb;
- switch (verb) {
- case SkPath::kMove_Verb:
- points_to_coords(points, 0, 1, coords);
- coordsForVerb = 2;
- break;
- case SkPath::kLine_Verb:
- points_to_coords(points, 1, 1, coords);
- coordsForVerb = 2;
- break;
- case SkPath::kConic_Verb:
- points_to_coords(points, 1, 2, coords);
- coords[4] = SkScalarToFloat(iter.conicWeight());
- coordsForVerb = 5;
- break;
- case SkPath::kQuad_Verb:
- points_to_coords(points, 1, 2, coords);
- coordsForVerb = 4;
- break;
- case SkPath::kCubic_Verb:
- points_to_coords(points, 1, 3, coords);
- coordsForVerb = 6;
- break;
- case SkPath::kClose_Verb:
- continue;
- default:
- SkASSERT(false); // Not reached.
- continue;
- }
- SkDEBUGCODE(numCoords += num_coords(verb));
- pathCoords.push_back_n(coordsForVerb, coords);
- }
- }
+ pathCommands.resize_back(verbCnt);
+ pathCoords.resize_back(coordCnt);
+ skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt);
+ skPath.getVerbs(&pathCommands[0], verbCnt);
+ SkDEBUGCODE(int verbCoordCnt = 0);
+ for (int i = 0; i < verbCnt; ++i) {
+ SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
+ pathCommands[i] = verb_to_gl_path_cmd(v);
+ SkDEBUGCODE(verbCoordCnt += num_coords(v));
+ }
SkASSERT(verbCnt == pathCommands.count());
- SkASSERT(numCoords == pathCoords.count());
-
+ SkASSERT(verbCoordCnt == pathCoords.count());
GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0],
- pathCoords.count(), GR_GL_FLOAT, &pathCoords[0]));
- } else {
- GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLOAT, nullptr));
+ pathCoords.count(), GR_GL_FLOAT,
+ &pathCoords[0]));
+ return;
}
+#endif
+ SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath));
+}
- if (stroke.needToApply()) {
- SkASSERT(!stroke.isHairlineStyle());
- GR_GL_CALL(gpu->glInterface(),
- PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
- GR_GL_CALL(gpu->glInterface(),
- PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
- GrGLenum join = join_to_gl_join(stroke.getJoin());
- GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
- GrGLenum cap = cap_to_gl_cap(stroke.getCap());
- GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap));
- GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f));
- }
+void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const GrStrokeInfo& stroke) {
+ SkASSERT(stroke.needToApply());
+ SkASSERT(!stroke.isDashed());
+ SkASSERT(!stroke.isHairlineStyle());
+ GR_GL_CALL(gpu->glInterface(),
+ PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
+ GR_GL_CALL(gpu->glInterface(),
+ PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
+ GrGLenum join = join_to_gl_join(stroke.getJoin());
+ GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
+ GrGLenum cap = cap_to_gl_cap(stroke.getCap());
+ GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap));
+ GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f));
+}
+
+void GrGLPath::InitPathObjectEmptyPath(GrGLGpu* gpu, GrGLuint pathID) {
+ GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLOAT, nullptr));
}
GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& origStroke)
: INHERITED(gpu, origSkPath, origStroke),
fPathID(gpu->glPathRendering()->genPaths(1)) {
- // Convert a dashing to either a stroke or a fill.
- const SkPath* skPath = &origSkPath;
- SkTLazy<SkPath> tmpPath;
- const GrStrokeInfo* stroke = &origStroke;
- GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle);
-
- if (stroke->isDashed()) {
- if (stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) {
- skPath = tmpPath.get();
- stroke = &tmpStroke;
+
+ if (origSkPath.isEmpty()) {
+ InitPathObjectEmptyPath(gpu, fPathID);
+ fShouldStroke = false;
+ fShouldFill = false;
+ } else {
+ const SkPath* skPath = &origSkPath;
+ SkTLazy<SkPath> tmpPath;
+ const GrStrokeInfo* stroke = &origStroke;
+ GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle);
+
+ if (stroke->isDashed()) {
+ // Skia stroking and NVPR stroking differ with respect to dashing
+ // pattern.
+ // Convert a dashing to either a stroke or a fill.
+ if (stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) {
+ skPath = tmpPath.get();
+ stroke = &tmpStroke;
+ }
+ }
+
+ bool didInit = false;
+ if (stroke->needToApply() && stroke->getCap() != SkPaint::kButt_Cap) {
+ // Skia stroking and NVPR stroking differ with respect to stroking
+ // end caps of empty subpaths.
+ // Convert stroke to fill if path contains empty subpaths.
+ didInit = InitPathObjectPathDataCheckingDegenerates(gpu, fPathID, *skPath);
+ if (!didInit) {
+ if (!tmpPath.isValid()) {
+ tmpPath.init();
+ }
+ SkAssertResult(stroke->applyToPath(tmpPath.get(), *skPath));
+ skPath = tmpPath.get();
+ tmpStroke.setFillStyle();
+ stroke = &tmpStroke;
+ }
}
- }
- InitPathObject(gpu, fPathID, *skPath, *stroke);
+ if (!didInit) {
+ InitPathObjectPathData(gpu, fPathID, *skPath);
+ }
- fShouldStroke = stroke->needToApply();
- fShouldFill = stroke->isFillStyle() ||
- stroke->getStyle() == SkStrokeRec::kStrokeAndFill_Style;
+ fShouldStroke = stroke->needToApply();
+ fShouldFill = stroke->isFillStyle() ||
+ stroke->getStyle() == SkStrokeRec::kStrokeAndFill_Style;
- if (fShouldStroke) {
- // FIXME: try to account for stroking, without rasterizing the stroke.
- fBounds.outset(stroke->getWidth(), stroke->getWidth());
+ if (fShouldStroke) {
+ InitPathObjectStroke(gpu, fPathID, *stroke);
+
+ // FIXME: try to account for stroking, without rasterizing the stroke.
+ fBounds.outset(stroke->getWidth(), stroke->getWidth());
+ }
}
this->registerWithCache();
« no previous file with comments | « src/gpu/gl/GrGLPath.h ('k') | src/gpu/gl/GrGLPathRange.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698