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

Side by Side 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 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 unified diff | Download patch
« no previous file with comments | « src/gpu/gl/GrGLPath.h ('k') | src/gpu/gl/GrGLPathRange.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2012 Google Inc. 3 * Copyright 2012 Google Inc.
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 #include "GrGLPath.h" 9 #include "GrGLPath.h"
10 #include "GrGLPathRendering.h" 10 #include "GrGLPathRendering.h"
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkCapsToGrGLCaps) == SkPaint::kCapCount); 79 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkCapsToGrGLCaps) == SkPaint::kCapCount);
80 } 80 }
81 81
82 inline void points_to_coords(const SkPoint points[], size_t first_point, size_t amount, 82 inline void points_to_coords(const SkPoint points[], size_t first_point, size_t amount,
83 GrGLfloat coords[]) { 83 GrGLfloat coords[]) {
84 for (size_t i = 0; i < amount; ++i) { 84 for (size_t i = 0; i < amount; ++i) {
85 coords[i * 2] = SkScalarToFloat(points[first_point + i].fX); 85 coords[i * 2] = SkScalarToFloat(points[first_point + i].fX);
86 coords[i * 2 + 1] = SkScalarToFloat(points[first_point + i].fY); 86 coords[i * 2 + 1] = SkScalarToFloat(points[first_point + i].fY);
87 } 87 }
88 } 88 }
89 } 89
90 90 template<bool checkForDegenerates>
91 void GrGLPath::InitPathObject(GrGLGpu* gpu, 91 inline bool init_path_object_for_general_path(GrGLGpu* gpu, GrGLuint pathID,
92 GrGLuint pathID, 92 const SkPath& skPath) {
93 const SkPath& skPath, 93 SkDEBUGCODE(int numCoords = 0);
94 const GrStrokeInfo& stroke) { 94 int verbCnt = skPath.countVerbs();
95 SkASSERT(!stroke.isDashed()); 95 int pointCnt = skPath.countPoints();
96 if (!skPath.isEmpty()) { 96 int minCoordCnt = pointCnt * 2;
97
98 SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
99 SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt);
100 bool lastVerbWasMove = true; // A path with just "close;" means "moveto(0,0) ; close;"
101 SkPoint points[4];
102 SkPath::RawIter iter(skPath);
103 SkPath::Verb verb;
104 while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
105 pathCommands.push_back(verb_to_gl_path_cmd(verb));
106 GrGLfloat coords[6];
107 int coordsForVerb;
108 switch (verb) {
109 case SkPath::kMove_Verb:
110 if (checkForDegenerates) {
111 lastVerbWasMove = true;
112 }
113 points_to_coords(points, 0, 1, coords);
114 coordsForVerb = 2;
115 break;
116 case SkPath::kLine_Verb:
117 if (checkForDegenerates) {
118 if (SkPath::IsLineDegenerate(points[0], points[1], true)) {
119 return false;
120 }
121 lastVerbWasMove = false;
122 }
123
124 points_to_coords(points, 1, 1, coords);
125 coordsForVerb = 2;
126 break;
127 case SkPath::kConic_Verb:
128 if (checkForDegenerates) {
129 if (SkPath::IsQuadDegenerate(points[0], points[1], points[2] , true)) {
130 return false;
131 }
132 lastVerbWasMove = false;
133 }
134 points_to_coords(points, 1, 2, coords);
135 coords[4] = SkScalarToFloat(iter.conicWeight());
136 coordsForVerb = 5;
137 break;
138 case SkPath::kQuad_Verb:
139 if (checkForDegenerates) {
140 if (SkPath::IsQuadDegenerate(points[0], points[1], points[2] , true)) {
141 return false;
142 }
143 lastVerbWasMove = false;
144 }
145 points_to_coords(points, 1, 2, coords);
146 coordsForVerb = 4;
147 break;
148 case SkPath::kCubic_Verb:
149 if (checkForDegenerates) {
150 if (SkPath::IsCubicDegenerate(points[0], points[1], points[2 ], points[3],
151 true)) {
152 return false;
153 }
154 lastVerbWasMove = false;
155 }
156 points_to_coords(points, 1, 3, coords);
157 coordsForVerb = 6;
158 break;
159 case SkPath::kClose_Verb:
160 if (checkForDegenerates) {
161 if (lastVerbWasMove) {
162 // Interpret "move(x,y);close;" as "move(x,y);lineto(x,y );close;".
163 // which produces a degenerate segment.
164 return false;
165 }
166 }
167 continue;
168 default:
169 SkASSERT(false); // Not reached.
170 continue;
171 }
172 SkDEBUGCODE(numCoords += num_coords(verb));
173 pathCoords.push_back_n(coordsForVerb, coords);
174 }
175 SkASSERT(verbCnt == pathCommands.count());
176 SkASSERT(numCoords == pathCoords.count());
177
178 GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &p athCommands[0],
179 pathCoords.count(), GR_GL_FLOAT, &pathCoords[0]));
180 return true;
181 }
182 } // namespace
183
184 bool GrGLPath::InitPathObjectPathDataCheckingDegenerates(GrGLGpu* gpu, GrGLuint pathID,
185 const SkPath& skPath) {
186 return init_path_object_for_general_path<true>(gpu, pathID, skPath);
187 }
188
189 void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu,
190 GrGLuint pathID,
191 const SkPath& skPath) {
192 SkASSERT(!skPath.isEmpty());
193
194 #ifdef SK_SCALAR_IS_FLOAT
195 // This branch does type punning, converting SkPoint* to GrGLfloat*.
196 if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) {
97 int verbCnt = skPath.countVerbs(); 197 int verbCnt = skPath.countVerbs();
98 int pointCnt = skPath.countPoints(); 198 int pointCnt = skPath.countPoints();
99 int minCoordCnt = pointCnt * 2; 199 int coordCnt = pointCnt * 2;
100
101 SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt); 200 SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
102 SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt); 201 SkSTArray<16, GrGLfloat, true> pathCoords(coordCnt);
103 202
104 SkDEBUGCODE(int numCoords = 0); 203 static_assert(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, "sk_point_not_tw o_floats");
105 204
106 if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) { 205 pathCommands.resize_back(verbCnt);
107 // This branch does type punning, converting SkPoint* to GrGLfloat*. 206 pathCoords.resize_back(coordCnt);
108 static_assert(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, "sk_point_no t_two_floats"); 207 skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt);
109 // This branch does not convert with SkScalarToFloat. 208 skPath.getVerbs(&pathCommands[0], verbCnt);
110 #ifndef SK_SCALAR_IS_FLOAT 209
111 #error Need SK_SCALAR_IS_FLOAT. 210 SkDEBUGCODE(int verbCoordCnt = 0);
211 for (int i = 0; i < verbCnt; ++i) {
212 SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
213 pathCommands[i] = verb_to_gl_path_cmd(v);
214 SkDEBUGCODE(verbCoordCnt += num_coords(v));
215 }
216 SkASSERT(verbCnt == pathCommands.count());
217 SkASSERT(verbCoordCnt == pathCoords.count());
218 GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count() , &pathCommands[0],
219 pathCoords.count(), GR_GL_FL OAT,
220 &pathCoords[0]));
221 return;
222 }
112 #endif 223 #endif
113 pathCommands.resize_back(verbCnt); 224 SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath) );
114 pathCoords.resize_back(minCoordCnt); 225 }
115 skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCn t); 226
116 skPath.getVerbs(&pathCommands[0], verbCnt); 227 void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const GrStrok eInfo& stroke) {
117 for (int i = 0; i < verbCnt; ++i) { 228 SkASSERT(stroke.needToApply());
118 SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]); 229 SkASSERT(!stroke.isDashed());
119 pathCommands[i] = verb_to_gl_path_cmd(v); 230 SkASSERT(!stroke.isHairlineStyle());
120 SkDEBUGCODE(numCoords += num_coords(v)); 231 GR_GL_CALL(gpu->glInterface(),
121 } 232 PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(s troke.getWidth())));
122 } else { 233 GR_GL_CALL(gpu->glInterface(),
123 SkPoint points[4]; 234 PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(st roke.getMiter())));
124 SkPath::RawIter iter(skPath); 235 GrGLenum join = join_to_gl_join(stroke.getJoin());
125 SkPath::Verb verb; 236 GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
126 while ((verb = iter.next(points)) != SkPath::kDone_Verb) { 237 GrGLenum cap = cap_to_gl_cap(stroke.getCap());
127 pathCommands.push_back(verb_to_gl_path_cmd(verb)); 238 GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, c ap));
128 GrGLfloat coords[6]; 239 GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUN D, 0.02f));
129 int coordsForVerb; 240 }
130 switch (verb) { 241
131 case SkPath::kMove_Verb: 242 void GrGLPath::InitPathObjectEmptyPath(GrGLGpu* gpu, GrGLuint pathID) {
132 points_to_coords(points, 0, 1, coords); 243 GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLO AT, nullptr));
133 coordsForVerb = 2;
134 break;
135 case SkPath::kLine_Verb:
136 points_to_coords(points, 1, 1, coords);
137 coordsForVerb = 2;
138 break;
139 case SkPath::kConic_Verb:
140 points_to_coords(points, 1, 2, coords);
141 coords[4] = SkScalarToFloat(iter.conicWeight());
142 coordsForVerb = 5;
143 break;
144 case SkPath::kQuad_Verb:
145 points_to_coords(points, 1, 2, coords);
146 coordsForVerb = 4;
147 break;
148 case SkPath::kCubic_Verb:
149 points_to_coords(points, 1, 3, coords);
150 coordsForVerb = 6;
151 break;
152 case SkPath::kClose_Verb:
153 continue;
154 default:
155 SkASSERT(false); // Not reached.
156 continue;
157 }
158 SkDEBUGCODE(numCoords += num_coords(verb));
159 pathCoords.push_back_n(coordsForVerb, coords);
160 }
161 }
162
163 SkASSERT(verbCnt == pathCommands.count());
164 SkASSERT(numCoords == pathCoords.count());
165
166 GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count() , &pathCommands[0],
167 pathCoords.count(), GR_GL_FLOAT, &pathCoords[0]));
168 } else {
169 GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL _FLOAT, nullptr));
170 }
171
172 if (stroke.needToApply()) {
173 SkASSERT(!stroke.isHairlineStyle());
174 GR_GL_CALL(gpu->glInterface(),
175 PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stro ke.getWidth())));
176 GR_GL_CALL(gpu->glInterface(),
177 PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(strok e.getMiter())));
178 GrGLenum join = join_to_gl_join(stroke.getJoin());
179 GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_ST YLE, join));
180 GrGLenum cap = cap_to_gl_cap(stroke.getCap());
181 GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAP S, cap));
182 GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_ BOUND, 0.02f));
183 }
184 } 244 }
185 245
186 GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& o rigStroke) 246 GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStrokeInfo& o rigStroke)
187 : INHERITED(gpu, origSkPath, origStroke), 247 : INHERITED(gpu, origSkPath, origStroke),
188 fPathID(gpu->glPathRendering()->genPaths(1)) { 248 fPathID(gpu->glPathRendering()->genPaths(1)) {
189 // Convert a dashing to either a stroke or a fill. 249
190 const SkPath* skPath = &origSkPath; 250 if (origSkPath.isEmpty()) {
191 SkTLazy<SkPath> tmpPath; 251 InitPathObjectEmptyPath(gpu, fPathID);
192 const GrStrokeInfo* stroke = &origStroke; 252 fShouldStroke = false;
193 GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle); 253 fShouldFill = false;
194 254 } else {
195 if (stroke->isDashed()) { 255 const SkPath* skPath = &origSkPath;
196 if (stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) { 256 SkTLazy<SkPath> tmpPath;
197 skPath = tmpPath.get(); 257 const GrStrokeInfo* stroke = &origStroke;
198 stroke = &tmpStroke; 258 GrStrokeInfo tmpStroke(SkStrokeRec::kFill_InitStyle);
199 } 259
200 } 260 if (stroke->isDashed()) {
201 261 // Skia stroking and NVPR stroking differ with respect to dashing
202 InitPathObject(gpu, fPathID, *skPath, *stroke); 262 // pattern.
203 263 // Convert a dashing to either a stroke or a fill.
204 fShouldStroke = stroke->needToApply(); 264 if (stroke->applyDashToPath(tmpPath.init(), &tmpStroke, *skPath)) {
205 fShouldFill = stroke->isFillStyle() || 265 skPath = tmpPath.get();
206 stroke->getStyle() == SkStrokeRec::kStrokeAndFill_Style; 266 stroke = &tmpStroke;
207 267 }
208 if (fShouldStroke) { 268 }
209 // FIXME: try to account for stroking, without rasterizing the stroke. 269
210 fBounds.outset(stroke->getWidth(), stroke->getWidth()); 270 bool didInit = false;
271 if (stroke->needToApply() && stroke->getCap() != SkPaint::kButt_Cap) {
272 // Skia stroking and NVPR stroking differ with respect to stroking
273 // end caps of empty subpaths.
274 // Convert stroke to fill if path contains empty subpaths.
275 didInit = InitPathObjectPathDataCheckingDegenerates(gpu, fPathID, *s kPath);
276 if (!didInit) {
277 if (!tmpPath.isValid()) {
278 tmpPath.init();
279 }
280 SkAssertResult(stroke->applyToPath(tmpPath.get(), *skPath));
281 skPath = tmpPath.get();
282 tmpStroke.setFillStyle();
283 stroke = &tmpStroke;
284 }
285 }
286
287 if (!didInit) {
288 InitPathObjectPathData(gpu, fPathID, *skPath);
289 }
290
291 fShouldStroke = stroke->needToApply();
292 fShouldFill = stroke->isFillStyle() ||
293 stroke->getStyle() == SkStrokeRec::kStrokeAndFill_Style;
294
295 if (fShouldStroke) {
296 InitPathObjectStroke(gpu, fPathID, *stroke);
297
298 // FIXME: try to account for stroking, without rasterizing the strok e.
299 fBounds.outset(stroke->getWidth(), stroke->getWidth());
300 }
211 } 301 }
212 302
213 this->registerWithCache(); 303 this->registerWithCache();
214 } 304 }
215 305
216 void GrGLPath::onRelease() { 306 void GrGLPath::onRelease() {
217 if (0 != fPathID && this->shouldFreeResources()) { 307 if (0 != fPathID && this->shouldFreeResources()) {
218 static_cast<GrGLGpu*>(this->getGpu())->glPathRendering()->deletePaths(fP athID, 1); 308 static_cast<GrGLGpu*>(this->getGpu())->glPathRendering()->deletePaths(fP athID, 1);
219 fPathID = 0; 309 fPathID = 0;
220 } 310 }
221 311
222 INHERITED::onRelease(); 312 INHERITED::onRelease();
223 } 313 }
224 314
225 void GrGLPath::onAbandon() { 315 void GrGLPath::onAbandon() {
226 fPathID = 0; 316 fPathID = 0;
227 317
228 INHERITED::onAbandon(); 318 INHERITED::onAbandon();
229 } 319 }
OLDNEW
« 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