/* * 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 "Resources.h" #include "SkBlurMask.h" #include "SkBlurMaskFilter.h" #include "SkCanvas.h" #include "SkGradientShader.h" #include "SkImage.h" #include "SkRandom.h" #include "SkStream.h" #include "SkSurface.h" #include "SkTextBlob.h" #include "SkTypeface.h" namespace skiagm { class TextBlobMixedSizes : public GM { public: // This gm tests that textblobs of mixed sizes with a large glyph will render properly TextBlobMixedSizes(bool useDFT) : fUseDFT(useDFT) {} protected: void onOnceBeforeDraw() override { SkAutoTUnref<SkTypeface> typeface(GetResourceAsTypeface("/fonts/HangingS.ttf")); SkTextBlobBuilder builder; // make textblob. To stress distance fields, we choose sizes appropriately SkPaint paint; paint.setAntiAlias(true); paint.setSubpixelText(true); paint.setLCDRenderText(true); paint.setTypeface(typeface); const char* text = "Skia"; // extra large paint.setTextSize(262); sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, 0); // large SkRect bounds; paint.measureText(text, strlen(text), &bounds); SkScalar yOffset = bounds.height(); paint.setTextSize(162); sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset); // Medium paint.measureText(text, strlen(text), &bounds); yOffset += bounds.height(); paint.setTextSize(72); sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset); // Small paint.measureText(text, strlen(text), &bounds); yOffset += bounds.height(); paint.setTextSize(32); sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset); // micro (will fall out of distance field text even if distance field text is enabled) paint.measureText(text, strlen(text), &bounds); yOffset += bounds.height(); paint.setTextSize(14); sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset); // build fBlob.reset(builder.build()); } SkString onShortName() override { SkString name("textblobmixedsizes"); if (fUseDFT) { name.appendf("_df"); } return name; } SkISize onISize() override { return SkISize::Make(kWidth, kHeight); } void onDraw(SkCanvas* inputCanvas) override { SkCanvas* canvas = inputCanvas; SkAutoTUnref<SkSurface> surface; if (fUseDFT) { #if SK_SUPPORT_GPU // Create a new Canvas to enable DFT GrContext* ctx = inputCanvas->getGrContext(); SkImageInfo info = SkImageInfo::MakeN32Premul(onISize()); SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag, SkSurfaceProps::kLegacyFontHost_InitType); surface.reset(SkSurface::NewRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props)); canvas = surface.get() ? surface->getCanvas() : inputCanvas; // init our new canvas with the old canvas's matrix canvas->setMatrix(inputCanvas->getTotalMatrix()); #endif } canvas->drawColor(sk_tool_utils::color_to_565(SK_ColorWHITE)); SkRect bounds = fBlob->bounds(); static const int kPadX = SkScalarFloorToInt(bounds.width() / 3); static const int kPadY = SkScalarFloorToInt(bounds.height() / 3); int rowCount = 0; canvas->translate(SkIntToScalar(kPadX), SkIntToScalar(kPadY)); canvas->save(); SkRandom random; SkPaint paint; if (!fUseDFT) { paint.setColor(sk_tool_utils::color_to_565(SK_ColorWHITE)); } paint.setAntiAlias(false); static const SkScalar kSigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(8)); // setup blur paint SkPaint blurPaint(paint); blurPaint.setColor(sk_tool_utils::color_to_565(SK_ColorBLACK)); SkAutoTUnref<SkMaskFilter> mf(SkBlurMaskFilter::Create(kNormal_SkBlurStyle, kSigma)); blurPaint.setMaskFilter(mf); for (int i = 0; i < 4; i++) { canvas->save(); switch (i % 2) { case 0: canvas->rotate(random.nextF() * 45.f); break; case 1: canvas->rotate(-random.nextF() * 45.f); break; } if (!fUseDFT) { canvas->drawTextBlob(fBlob, 0, 0, blurPaint); } canvas->drawTextBlob(fBlob, 0, 0, paint); canvas->restore(); canvas->translate(bounds.width() + SK_Scalar1 * kPadX, 0); ++rowCount; if ((bounds.width() + 2 * kPadX) * rowCount > kWidth) { canvas->restore(); canvas->translate(0, bounds.height() + SK_Scalar1 * kPadY); canvas->save(); rowCount = 0; } } canvas->restore(); #if SK_SUPPORT_GPU // render offscreen buffer if (surface) { SkAutoCanvasRestore acr(inputCanvas, true); // since we prepended this matrix already, we blit using identity inputCanvas->resetMatrix(); SkImage* image = surface->newImageSnapshot(); inputCanvas->drawImage(image, 0, 0, nullptr); image->unref(); } #endif } private: SkAutoTUnref<const SkTextBlob> fBlob; static const int kWidth = 2000; static const int kHeight = 2000; bool fUseDFT; typedef GM INHERITED; }; ////////////////////////////////////////////////////////////////////////////// DEF_GM( return new TextBlobMixedSizes(false); ) #if SK_SUPPORT_GPU DEF_GM( return new TextBlobMixedSizes(true); ) #endif }