/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "gm.h" #include "SkAutoMalloc.h" #include "SkCanvas.h" #include "SkRSXform.h" #include "SkSurface.h" class DrawAtlasGM : public skiagm::GM { static sk_sp MakeAtlas(SkCanvas* caller, const SkRect& target) { SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); auto surface(caller->makeSurface(info)); if (nullptr == surface) { surface = SkSurface::MakeRaster(info); } SkCanvas* canvas = surface->getCanvas(); // draw red everywhere, but we don't expect to see it in the draw, testing the notion // that drawAtlas draws a subset-region of the atlas. canvas->clear(SK_ColorRED); SkPaint paint; paint.setBlendMode(SkBlendMode::kClear); SkRect r(target); r.inset(-1, -1); // zero out a place (with a 1-pixel border) to land our drawing. canvas->drawRect(r, paint); paint.setBlendMode(SkBlendMode::kSrcOver); paint.setColor(SK_ColorBLUE); paint.setAntiAlias(true); canvas->drawOval(target, paint); return surface->makeImageSnapshot(); } public: DrawAtlasGM() {} protected: SkString onShortName() override { return SkString("draw-atlas"); } SkISize onISize() override { return SkISize::Make(640, 480); } void onDraw(SkCanvas* canvas) override { const SkRect target = { 50, 50, 80, 90 }; auto atlas = MakeAtlas(canvas, target); const struct { SkScalar fScale; SkScalar fDegrees; SkScalar fTx; SkScalar fTy; void apply(SkRSXform* xform) const { const SkScalar rad = SkDegreesToRadians(fDegrees); xform->fSCos = fScale * SkScalarCos(rad); xform->fSSin = fScale * SkScalarSin(rad); xform->fTx = fTx; xform->fTy = fTy; } } rec[] = { { 1, 0, 10, 10 }, // just translate { 2, 0, 110, 10 }, // scale + translate { 1, 30, 210, 10 }, // rotate + translate { 2, -30, 310, 30 }, // scale + rotate + translate }; const int N = SK_ARRAY_COUNT(rec); SkRSXform xform[N]; SkRect tex[N]; SkColor colors[N]; for (int i = 0; i < N; ++i) { rec[i].apply(&xform[i]); tex[i] = target; colors[i] = 0x80FF0000 + (i * 40 * 256); } SkPaint paint; paint.setFilterQuality(kLow_SkFilterQuality); paint.setAntiAlias(true); canvas->drawAtlas(atlas.get(), xform, tex, N, nullptr, &paint); canvas->translate(0, 100); canvas->drawAtlas(atlas.get(), xform, tex, colors, N, SkBlendMode::kSrcIn, nullptr, &paint); } private: typedef GM INHERITED; }; DEF_GM( return new DrawAtlasGM; ) /////////////////////////////////////////////////////////////////////////////////////////////////// #include "SkPath.h" #include "SkPathMeasure.h" static void draw_text_on_path_rigid(SkCanvas* canvas, const void* text, size_t length, const SkPoint xy[], const SkPath& path, const SkPaint& paint) { SkPathMeasure meas(path, false); int count = paint.countText(text, length); size_t size = count * (sizeof(SkRSXform) + sizeof(SkScalar)); SkAutoSMalloc<512> storage(size); SkRSXform* xform = (SkRSXform*)storage.get(); SkScalar* widths = (SkScalar*)(xform + count); paint.getTextWidths(text, length, widths); for (int i = 0; i < count; ++i) { // we want to position each character on the center of its advance const SkScalar offset = SkScalarHalf(widths[i]); SkPoint pos; SkVector tan; if (!meas.getPosTan(xy[i].x() + offset, &pos, &tan)) { pos = xy[i]; tan.set(1, 0); } xform[i].fSCos = tan.x(); xform[i].fSSin = tan.y(); xform[i].fTx = pos.x() - tan.y() * xy[i].y() - tan.x() * offset; xform[i].fTy = pos.y() + tan.x() * xy[i].y() - tan.y() * offset; } // Compute a conservative bounds so we can cull the draw const SkRect font = paint.getFontBounds(); const SkScalar max = SkTMax(SkTMax(SkScalarAbs(font.fLeft), SkScalarAbs(font.fRight)), SkTMax(SkScalarAbs(font.fTop), SkScalarAbs(font.fBottom))); const SkRect bounds = path.getBounds().makeOutset(max, max); canvas->drawTextRSXform(text, length, &xform[0], &bounds, paint); if (true) { SkPaint p; p.setStyle(SkPaint::kStroke_Style); canvas->drawRect(bounds, p); } } DEF_SIMPLE_GM(drawTextRSXform, canvas, 860, 860) { const char text0[] = "ABCDFGHJKLMNOPQRSTUVWXYZ"; const int N = sizeof(text0) - 1; SkPoint pos[N]; SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(100); SkScalar x = 0; for (int i = 0; i < N; ++i) { pos[i].set(x, 0); x += paint.measureText(&text0[i], 1); } SkPath path; path.addOval(SkRect::MakeXYWH(160, 160, 540, 540)); draw_text_on_path_rigid(canvas, text0, N, pos, path, paint); paint.setStyle(SkPaint::kStroke_Style); canvas->drawPath(path, paint); }