/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "gm/gm.h" #include "include/core/SkCanvas.h" #include "include/core/SkMatrix.h" #include "include/core/SkPaint.h" #include "include/core/SkPath.h" #include "include/core/SkRect.h" #include "include/core/SkScalar.h" #include "include/core/SkSize.h" #include "include/core/SkString.h" #include "include/gpu/GrContextOptions.h" #include "include/private/GrTypesPriv.h" #include "include/private/SkTArray.h" /** This tests the GPU backend's caching of path coverage masks */ class PathMaskCache : public skiagm::GM { public: PathMaskCache() {} protected: SkString onShortName() override { return SkString("path_mask_cache"); } SkISize onISize() override { return SkISize::Make(650, 950); } void onDraw(SkCanvas* canvas) override { static constexpr SkScalar kPad = 5.f; SkPaint paint; paint.setAntiAlias(true); auto drawPathSet = [canvas] (const SkPath& path, const SkMatrix& m) { SkPaint paint; paint.setAntiAlias(true); SkRect bounds = path.getBounds(); m.mapRect(&bounds); bounds.roundOut(); canvas->save(); canvas->translate(-bounds.fLeft, -bounds.fTop); canvas->save(); canvas->concat(m); canvas->drawPath(path, paint); canvas->restore(); // translate by integer canvas->translate(bounds.width() + kPad, 0.f); canvas->save(); canvas->concat(m); canvas->drawPath(path, paint); canvas->restore(); // translate by non-integer canvas->translate(bounds.width() + kPad + 0.15f, 0.f); canvas->save(); canvas->concat(m); canvas->drawPath(path, paint); canvas->restore(); // translate again so total translate fraction is almost identical to previous. canvas->translate(bounds.width() + kPad + 0.002f, 0.f); canvas->save(); canvas->concat(m); canvas->drawPath(path, paint); canvas->restore(); canvas->restore(); return bounds.fBottom + kPad; }; SkTArray paths; paths.push_back(); paths.back().moveTo(0.f, 0.f); paths.back().lineTo(98.f, 100.f); paths.back().lineTo(100.f, 100.f); paths.back().conicTo(150.f, 50.f, 100.f, 0.f, 0.6f); paths.back().conicTo(148.f, 50.f, 100.f, 100.f, 0.6f); paths.back().conicTo(50.f, 30.f, 0.f, 100.f, 0.9f); paths.push_back(); paths.back().addCircle(30.f, 30.f, 30.f); paths.back().addRect(SkRect::MakeXYWH(45.f, 45.f, 50.f, 60.f)); paths.back().setFillType(SkPathFillType::kEvenOdd); canvas->translate(kPad, kPad); for (const SkPath& path : paths) { SkScalar ty = drawPathSet(path, SkMatrix::I()); canvas->translate(0, ty); // Non-uniform scale. SkMatrix s; s.setScale(0.5f, 2.f); ty = drawPathSet(path, s); canvas->translate(0.f, ty); // Rotation SkMatrix r; r.setRotate(60.f, path.getBounds().centerX(), path.getBounds().centerY()); ty = drawPathSet(path, r); canvas->translate(0.f, ty); } } void modifyGrContextOptions(GrContextOptions* options) override { options->fGpuPathRenderers = GpuPathRenderers::kNone; options->fAllowPathMaskCaching = true; } private: using INHERITED = GM; }; DEF_GM( return new PathMaskCache(); )