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 27 TextBlobMixedSizes(bool useDFT) : fUseDFT(useDFT) {} 28 29 protected: 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 return SkStringPrintf("textblobmixedsizes%s%s", 89 sk_tool_utils::platform_font_manager(), 90 fUseDFT ? "_df" : ""); 91 } 92 93 SkISize onISize() override { 94 return SkISize::Make(kWidth, kHeight); 95 } 96 97 void onDraw(SkCanvas* inputCanvas) override { 98 SkCanvas* canvas = inputCanvas; 99 sk_sp<SkSurface> surface; 100 if (fUseDFT) { 101 #if SK_SUPPORT_GPU 102 // Create a new Canvas to enable DFT 103 GrContext* ctx = inputCanvas->getGrContext(); 104 SkISize size = onISize(); 105 sk_sp<SkColorSpace> colorSpace = inputCanvas->imageInfo().refColorSpace(); 106 SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), 107 kPremul_SkAlphaType, colorSpace); 108 SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag, 109 SkSurfaceProps::kLegacyFontHost_InitType); 110 surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props); 111 canvas = surface.get() ? surface->getCanvas() : inputCanvas; 112 // init our new canvas with the old canvas's matrix 113 canvas->setMatrix(inputCanvas->getTotalMatrix()); 114 #endif 115 } 116 canvas->drawColor(sk_tool_utils::color_to_565(SK_ColorWHITE)); 117 118 SkRect bounds = fBlob->bounds(); 119 120 const int kPadX = SkScalarFloorToInt(bounds.width() / 3); 121 const int kPadY = SkScalarFloorToInt(bounds.height() / 3); 122 123 int rowCount = 0; 124 canvas->translate(SkIntToScalar(kPadX), SkIntToScalar(kPadY)); 125 canvas->save(); 126 SkRandom random; 127 128 SkPaint paint; 129 if (!fUseDFT) { 130 paint.setColor(sk_tool_utils::color_to_565(SK_ColorWHITE)); 131 } 132 paint.setAntiAlias(false); 133 134 const SkScalar kSigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(8)); 135 136 // setup blur paint 137 SkPaint blurPaint(paint); 138 blurPaint.setColor(sk_tool_utils::color_to_565(SK_ColorBLACK)); 139 blurPaint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, kSigma)); 140 141 for (int i = 0; i < 4; i++) { 142 canvas->save(); 143 switch (i % 2) { 144 case 0: 145 canvas->rotate(random.nextF() * 45.f); 146 break; 147 case 1: 148 canvas->rotate(-random.nextF() * 45.f); 149 break; 150 } 151 if (!fUseDFT) { 152 canvas->drawTextBlob(fBlob, 0, 0, blurPaint); 153 } 154 canvas->drawTextBlob(fBlob, 0, 0, paint); 155 canvas->restore(); 156 canvas->translate(bounds.width() + SK_Scalar1 * kPadX, 0); 157 ++rowCount; 158 if ((bounds.width() + 2 * kPadX) * rowCount > kWidth) { 159 canvas->restore(); 160 canvas->translate(0, bounds.height() + SK_Scalar1 * kPadY); 161 canvas->save(); 162 rowCount = 0; 163 } 164 } 165 canvas->restore(); 166 167 #if SK_SUPPORT_GPU 168 // render offscreen buffer 169 if (surface) { 170 SkAutoCanvasRestore acr(inputCanvas, true); 171 // since we prepended this matrix already, we blit using identity 172 inputCanvas->resetMatrix(); 173 inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0, nullptr); 174 } 175 #endif 176 } 177 178 private: 179 sk_sp<SkTextBlob> fBlob; 180 181 static constexpr int kWidth = 2100; 182 static constexpr int kHeight = 1900; 183 184 bool fUseDFT; 185 186 typedef GM INHERITED; 187 }; 188 189 ////////////////////////////////////////////////////////////////////////////// 190 191 DEF_GM( return new TextBlobMixedSizes(false); ) 192 #if SK_SUPPORT_GPU 193 DEF_GM( return new TextBlobMixedSizes(true); ) 194 #endif 195 } 196