123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- /*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "src/gpu/GrStyle.h"
- #include "src/gpu/gl/GrGLGpu.h"
- #include "src/gpu/gl/GrGLPath.h"
- #include "src/gpu/gl/GrGLPathRendering.h"
- namespace {
- inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) {
- static const GrGLubyte gTable[] = {
- GR_GL_MOVE_TO,
- GR_GL_LINE_TO,
- GR_GL_QUADRATIC_CURVE_TO,
- GR_GL_CONIC_CURVE_TO,
- GR_GL_CUBIC_CURVE_TO,
- GR_GL_CLOSE_PATH,
- };
- GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
- GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
- GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
- GR_STATIC_ASSERT(3 == SkPath::kConic_Verb);
- GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
- GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
- SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
- return gTable[verb];
- }
- #ifdef SK_DEBUG
- inline int num_coords(SkPath::Verb verb) {
- static const int gTable[] = {
- 2, // move
- 2, // line
- 4, // quad
- 5, // conic
- 6, // cubic
- 0, // close
- };
- GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
- GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
- GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
- GR_STATIC_ASSERT(3 == SkPath::kConic_Verb);
- GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
- GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
- SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
- return gTable[verb];
- }
- #endif
- inline GrGLenum join_to_gl_join(SkPaint::Join join) {
- static GrGLenum gSkJoinsToGrGLJoins[] = {
- GR_GL_MITER_REVERT,
- GR_GL_ROUND,
- GR_GL_BEVEL
- };
- return gSkJoinsToGrGLJoins[join];
- GR_STATIC_ASSERT(0 == SkPaint::kMiter_Join);
- GR_STATIC_ASSERT(1 == SkPaint::kRound_Join);
- GR_STATIC_ASSERT(2 == SkPaint::kBevel_Join);
- GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkJoinsToGrGLJoins) == SkPaint::kJoinCount);
- }
- inline GrGLenum cap_to_gl_cap(SkPaint::Cap cap) {
- static GrGLenum gSkCapsToGrGLCaps[] = {
- GR_GL_FLAT,
- GR_GL_ROUND,
- GR_GL_SQUARE
- };
- return gSkCapsToGrGLCaps[cap];
- GR_STATIC_ASSERT(0 == SkPaint::kButt_Cap);
- GR_STATIC_ASSERT(1 == SkPaint::kRound_Cap);
- GR_STATIC_ASSERT(2 == SkPaint::kSquare_Cap);
- GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkCapsToGrGLCaps) == SkPaint::kCapCount);
- }
- #ifdef SK_DEBUG
- inline void verify_floats(const float* floats, int count) {
- for (int i = 0; i < count; ++i) {
- SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
- }
- }
- #endif
- inline void points_to_coords(const SkPoint points[], size_t first_point, size_t amount,
- GrGLfloat coords[]) {
- for (size_t i = 0; i < amount; ++i) {
- coords[i * 2] = SkScalarToFloat(points[first_point + i].fX);
- 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));
- SkDEBUGCODE(verify_floats(coords, coordsForVerb));
- pathCoords.push_back_n(coordsForVerb, coords);
- }
- SkASSERT(verbCnt == pathCommands.count());
- SkASSERT(numCoords == pathCoords.count());
- GR_GL_CALL(gpu->glInterface(),
- PathCommands(pathID, pathCommands.count(), pathCommands.begin(),
- pathCoords.count(), GR_GL_FLOAT, pathCoords.begin()));
- return true;
- }
- /*
- * For now paths only natively support winding and even odd fill types
- */
- static GrPathRendering::FillType convert_skpath_filltype(SkPath::FillType fill) {
- switch (fill) {
- default:
- SK_ABORT("Incomplete Switch\n");
- case SkPath::kWinding_FillType:
- case SkPath::kInverseWinding_FillType:
- return GrPathRendering::kWinding_FillType;
- case SkPath::kEvenOdd_FillType:
- case SkPath::kInverseEvenOdd_FillType:
- return GrPathRendering::kEvenOdd_FillType;
- }
- }
- } // namespace
- 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());
- #if 1 // 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 coordCnt = pointCnt * 2;
- SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
- SkSTArray<16, GrGLfloat, true> pathCoords(coordCnt);
- static_assert(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, "sk_point_not_two_floats");
- 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(verbCoordCnt == pathCoords.count());
- SkDEBUGCODE(verify_floats(&pathCoords[0], pathCoords.count()));
- GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0],
- pathCoords.count(), GR_GL_FLOAT,
- &pathCoords[0]));
- return;
- }
- #endif
- SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath));
- }
- void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const SkStrokeRec& stroke) {
- 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 GrStyle& style)
- : INHERITED(gpu, origSkPath, style),
- fPathID(gpu->glPathRendering()->genPaths(1)) {
- if (origSkPath.isEmpty()) {
- InitPathObjectEmptyPath(gpu, fPathID);
- fShouldStroke = false;
- fShouldFill = false;
- } else {
- const SkPath* skPath = &origSkPath;
- SkTLazy<SkPath> tmpPath;
- SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
- if (style.pathEffect()) {
- // Skia stroking and NVPR stroking differ with respect to dashing
- // pattern.
- // Convert a dashing (or other path effect) to either a stroke or a fill.
- if (style.applyPathEffectToPath(tmpPath.init(), &stroke, *skPath, SK_Scalar1)) {
- skPath = tmpPath.get();
- }
- } else {
- stroke = style.strokeRec();
- }
- 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();
- stroke.setFillStyle();
- }
- }
- if (!didInit) {
- InitPathObjectPathData(gpu, fPathID, *skPath);
- }
- fShouldStroke = stroke.needToApply();
- fShouldFill = stroke.isFillStyle() ||
- stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
- fFillType = convert_skpath_filltype(skPath->getFillType());
- fBounds = skPath->getBounds();
- SkScalar radius = stroke.getInflationRadius();
- fBounds.outset(radius, radius);
- if (fShouldStroke) {
- InitPathObjectStroke(gpu, fPathID, stroke);
- }
- }
- this->registerWithCache(SkBudgeted::kYes);
- }
- void GrGLPath::onRelease() {
- TRACE_EVENT0("skia.gpu", TRACE_FUNC);
- if (0 != fPathID) {
- static_cast<GrGLGpu*>(this->getGpu())->glPathRendering()->deletePaths(fPathID, 1);
- fPathID = 0;
- }
- INHERITED::onRelease();
- }
- void GrGLPath::onAbandon() {
- fPathID = 0;
- INHERITED::onAbandon();
- }
|