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