1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "gm.h" 9#include "sk_tool_utils.h" 10 11#include "Resources.h" 12#include "SkBlurMask.h" 13#include "SkBlurMaskFilter.h" 14#include "SkCanvas.h" 15#include "SkGradientShader.h" 16#include "SkImage.h" 17#include "SkRandom.h" 18#include "SkStream.h" 19#include "SkSurface.h" 20#include "SkTextBlob.h" 21#include "SkTypeface.h" 22 23namespace skiagm { 24class TextBlobMixedSizes : public GM { 25public: 26 // This gm tests that textblobs of mixed sizes with a large glyph will render properly 27 TextBlobMixedSizes(bool useDFT) : fUseDFT(useDFT) {} 28 29protected: 30 void onOnceBeforeDraw() override { 31 SkTextBlobBuilder builder; 32 33 // make textblob. To stress distance fields, we choose sizes appropriately 34 SkPaint paint; 35 paint.setAntiAlias(true); 36 paint.setSubpixelText(true); 37 paint.setLCDRenderText(true); 38 paint.setTypeface(MakeResourceAsTypeface("/fonts/HangingS.ttf")); 39 40 const char* text = "Skia"; 41 42 // extra large 43 paint.setTextSize(262); 44 45 sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, 0); 46 47 // large 48 SkRect bounds; 49 paint.measureText(text, strlen(text), &bounds); 50 SkScalar yOffset = bounds.height(); 51 paint.setTextSize(162); 52 53 sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset); 54 55 // Medium 56 paint.measureText(text, strlen(text), &bounds); 57 yOffset += bounds.height(); 58 paint.setTextSize(72); 59 60 sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset); 61 62 // Small 63 paint.measureText(text, strlen(text), &bounds); 64 yOffset += bounds.height(); 65 paint.setTextSize(32); 66 67 sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset); 68 69 // micro (will fall out of distance field text even if distance field text is enabled) 70 paint.measureText(text, strlen(text), &bounds); 71 yOffset += bounds.height(); 72 paint.setTextSize(14); 73 74 sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset); 75 76 // Zero size. 77 paint.measureText(text, strlen(text), &bounds); 78 yOffset += bounds.height(); 79 paint.setTextSize(0); 80 81 sk_tool_utils::add_to_text_blob(&builder, text, paint, 0, yOffset); 82 83 // build 84 fBlob = builder.make(); 85 } 86 87 SkString onShortName() override { 88 SkString name("textblobmixedsizes"); 89 if (fUseDFT) { 90 name.appendf("_df"); 91 } 92 return name; 93 } 94 95 SkISize onISize() override { 96 return SkISize::Make(kWidth, kHeight); 97 } 98 99 void onDraw(SkCanvas* inputCanvas) override { 100 SkCanvas* canvas = inputCanvas; 101 sk_sp<SkSurface> surface; 102 if (fUseDFT) { 103#if SK_SUPPORT_GPU 104 // Create a new Canvas to enable DFT 105 GrContext* ctx = inputCanvas->getGrContext(); 106 SkISize size = onISize(); 107 sk_sp<SkColorSpace> colorSpace = inputCanvas->imageInfo().refColorSpace(); 108 SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), 109 kPremul_SkAlphaType, colorSpace); 110 SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag, 111 SkSurfaceProps::kLegacyFontHost_InitType); 112 surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props); 113 canvas = surface.get() ? surface->getCanvas() : inputCanvas; 114 // init our new canvas with the old canvas's matrix 115 canvas->setMatrix(inputCanvas->getTotalMatrix()); 116#endif 117 } 118 canvas->drawColor(sk_tool_utils::color_to_565(SK_ColorWHITE)); 119 120 SkRect bounds = fBlob->bounds(); 121 122 const int kPadX = SkScalarFloorToInt(bounds.width() / 3); 123 const int kPadY = SkScalarFloorToInt(bounds.height() / 3); 124 125 int rowCount = 0; 126 canvas->translate(SkIntToScalar(kPadX), SkIntToScalar(kPadY)); 127 canvas->save(); 128 SkRandom random; 129 130 SkPaint paint; 131 if (!fUseDFT) { 132 paint.setColor(sk_tool_utils::color_to_565(SK_ColorWHITE)); 133 } 134 paint.setAntiAlias(false); 135 136 const SkScalar kSigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(8)); 137 138 // setup blur paint 139 SkPaint blurPaint(paint); 140 blurPaint.setColor(sk_tool_utils::color_to_565(SK_ColorBLACK)); 141 blurPaint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, kSigma)); 142 143 for (int i = 0; i < 4; i++) { 144 canvas->save(); 145 switch (i % 2) { 146 case 0: 147 canvas->rotate(random.nextF() * 45.f); 148 break; 149 case 1: 150 canvas->rotate(-random.nextF() * 45.f); 151 break; 152 } 153 if (!fUseDFT) { 154 canvas->drawTextBlob(fBlob, 0, 0, blurPaint); 155 } 156 canvas->drawTextBlob(fBlob, 0, 0, paint); 157 canvas->restore(); 158 canvas->translate(bounds.width() + SK_Scalar1 * kPadX, 0); 159 ++rowCount; 160 if ((bounds.width() + 2 * kPadX) * rowCount > kWidth) { 161 canvas->restore(); 162 canvas->translate(0, bounds.height() + SK_Scalar1 * kPadY); 163 canvas->save(); 164 rowCount = 0; 165 } 166 } 167 canvas->restore(); 168 169#if SK_SUPPORT_GPU 170 // render offscreen buffer 171 if (surface) { 172 SkAutoCanvasRestore acr(inputCanvas, true); 173 // since we prepended this matrix already, we blit using identity 174 inputCanvas->resetMatrix(); 175 inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0, nullptr); 176 } 177#endif 178 } 179 180private: 181 sk_sp<SkTextBlob> fBlob; 182 183 static constexpr int kWidth = 2100; 184 static constexpr int kHeight = 1900; 185 186 bool fUseDFT; 187 188 typedef GM INHERITED; 189}; 190 191////////////////////////////////////////////////////////////////////////////// 192 193DEF_GM( return new TextBlobMixedSizes(false); ) 194#if SK_SUPPORT_GPU 195DEF_GM( return new TextBlobMixedSizes(true); ) 196#endif 197} 198