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 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 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 onShortName()87 SkString onShortName() override { 88 SkString name("textblobmixedsizes"); 89 if (fUseDFT) { 90 name.appendf("_df"); 91 } 92 return name; 93 } 94 onISize()95 SkISize onISize() override { 96 return SkISize::Make(kWidth, kHeight); 97 } 98 onDraw(SkCanvas * inputCanvas)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 180 private: 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 193 DEF_GM( return new TextBlobMixedSizes(false); ) 194 #if SK_SUPPORT_GPU 195 DEF_GM( return new TextBlobMixedSizes(true); ) 196 #endif 197 } 198