| /* | |
| * Copyright 2020 Google LLC | |
| * | |
| * 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/SkRSXform.h" | |
| #include "include/core/SkShader.h" | |
| #include "include/core/SkSurface.h" | |
| #include "include/core/SkTextBlob.h" | |
| #include "include/core/SkTileMode.h" | |
| #include "tools/ToolUtils.h" | |
| #include "tools/fonts/FontToolUtils.h" | |
| // Exercises RSX text blobs + shader with various local matrix combinations. | |
| // Yellow grid should stay aligned for text vs. background. | |
| class RSXShaderGM : public skiagm::GM { | |
| public: | |
| private: | |
| SkString getName() const override { return SkString("rsx_blob_shader"); } | |
| SkISize getISize() override { return SkISize::Make(kSZ * kScale * 2.1f, kSZ * kScale * 2.1f); } | |
| void onOnceBeforeDraw() override { | |
| const SkFontStyle style(SkFontStyle::kExtraBlack_Weight, | |
| SkFontStyle::kNormal_Width, | |
| SkFontStyle::kUpright_Slant); | |
| SkFont font(ToolUtils::CreatePortableTypeface("Sans", style), kFontSZ); | |
| font.setEdging(SkFont::Edging::kAntiAlias); | |
| static constexpr char txt[] = "TEST"; | |
| SkGlyphID glyphs[16]; | |
| float widths[16]; | |
| const auto glyph_count = font.textToGlyphs(txt, strlen(txt), SkTextEncoding::kUTF8, glyphs); | |
| font.getWidths({glyphs, glyph_count}, {widths, glyph_count}); | |
| SkTextBlobBuilder builder; | |
| const auto& buf = builder.allocRunRSXform(font, glyph_count); | |
| std::copy(glyphs, glyphs + glyph_count, buf.glyphs); | |
| float x = 0; | |
| for (size_t i = 0; i < glyph_count; ++i) { | |
| buf.xforms()[i] = { | |
| 1, 0, | |
| x, 0, | |
| }; | |
| x += widths[i]; | |
| } | |
| fBlob = builder.make(); | |
| } | |
| void onDraw(SkCanvas* canvas) override { | |
| canvas->scale(kScale, kScale); | |
| this->draw_one(canvas, | |
| {0, 0}, SkMatrix::I(), SkMatrix::I()); | |
| this->draw_one(canvas, | |
| {kSZ*1.1f, 0}, SkMatrix::Scale(2, 2), SkMatrix::I()); | |
| this->draw_one(canvas, | |
| {0, kSZ*1.1f}, SkMatrix::I(), SkMatrix::RotateDeg(45)); | |
| this->draw_one(canvas, | |
| {kSZ*1.1f, kSZ*1.1f}, SkMatrix::Scale(2, 2), SkMatrix::RotateDeg(45)); | |
| } | |
| void draw_one(SkCanvas* canvas, SkPoint pos, const SkMatrix& lm, | |
| const SkMatrix& outer_lm) const { | |
| SkAutoCanvasRestore acr(canvas, true); | |
| canvas->translate(pos.fX, pos.fY); | |
| SkPaint p; | |
| p.setShader(make_shader(lm, outer_lm)); | |
| p.setAlphaf(0.75f); | |
| canvas->drawRect(SkRect::MakeWH(kSZ, kSZ), p); | |
| p.setAlphaf(1); | |
| canvas->drawTextBlob(fBlob, 0, kFontSZ*1, p); | |
| canvas->drawTextBlob(fBlob, 0, kFontSZ*2, p); | |
| } | |
| static sk_sp<SkShader> make_shader(const SkMatrix& lm, const SkMatrix& outer_lm) { | |
| static constexpr SkISize kTileSize = { 30, 30 }; | |
| auto surface = SkSurfaces::Raster( | |
| SkImageInfo::MakeN32Premul(kTileSize.width(), kTileSize.height())); | |
| SkPaint p; | |
| p.setColor(0xffffff00); | |
| surface->getCanvas()->drawPaint(p); | |
| p.setColor(0xff008000); | |
| surface->getCanvas() | |
| ->drawRect({0, 0, kTileSize.width()*0.9f, kTileSize.height()*0.9f}, p); | |
| return surface->makeImageSnapshot() | |
| ->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, | |
| SkSamplingOptions(SkFilterMode::kLinear), &lm) | |
| ->makeWithLocalMatrix(outer_lm); | |
| } | |
| inline static constexpr float kSZ = 300, | |
| kFontSZ = kSZ * 0.38, | |
| kScale = 1.4f; | |
| sk_sp<SkTextBlob> fBlob; | |
| }; | |
| DEF_GM(return new RSXShaderGM;) |