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/gm.h" 9 #include "include/core/SkBlurTypes.h" 10 #include "include/core/SkCanvas.h" 11 #include "include/core/SkColor.h" 12 #include "include/core/SkColorSpace.h" 13 #include "include/core/SkFont.h" 14 #include "include/core/SkFontTypes.h" 15 #include "include/core/SkImageInfo.h" 16 #include "include/core/SkMaskFilter.h" 17 #include "include/core/SkPaint.h" 18 #include "include/core/SkRect.h" 19 #include "include/core/SkRefCnt.h" 20 #include "include/core/SkScalar.h" 21 #include "include/core/SkSize.h" 22 #include "include/core/SkString.h" 23 #include "include/core/SkSurface.h" 24 #include "include/core/SkSurfaceProps.h" 25 #include "include/core/SkTextBlob.h" 26 #include "include/core/SkTypeface.h" 27 #include "include/core/SkTypes.h" 28 #include "include/gpu/GpuTypes.h" 29 #include "include/gpu/ganesh/SkSurfaceGanesh.h" 30 #if defined(SK_GRAPHITE) 31 #include "include/gpu/graphite/Surface.h" 32 #endif 33 #include "src/base/SkRandom.h" 34 #include "src/core/SkBlurMask.h" 35 #include "tools/Resources.h" 36 #include "tools/ToolUtils.h" 37 #include "tools/fonts/FontToolUtils.h" 38 39 #include <string.h> 40 41 namespace skiagm { 42 class TextBlobMixedSizes : public GM { 43 public: 44 // This gm tests that textblobs of mixed sizes with a large glyph will render properly TextBlobMixedSizes(bool useDFT)45 TextBlobMixedSizes(bool useDFT) : fUseDFT(useDFT) {} 46 47 protected: onOnceBeforeDraw()48 void onOnceBeforeDraw() override { 49 SkTextBlobBuilder builder; 50 51 // make textblob. To stress distance fields, we choose sizes appropriately 52 sk_sp<SkTypeface> tf = ToolUtils::CreateTypefaceFromResource("fonts/HangingS.ttf"); 53 if (!tf) { 54 tf = ToolUtils::DefaultPortableTypeface(); 55 } 56 SkFont font(tf, 262); 57 font.setSubpixel(true); 58 font.setEdging(SkFont::Edging::kSubpixelAntiAlias); 59 60 const char* text = "Skia"; 61 62 ToolUtils::add_to_text_blob(&builder, text, font, 0, 0); 63 64 // large 65 SkRect bounds; 66 font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); 67 SkScalar yOffset = bounds.height(); 68 font.setSize(162); 69 70 ToolUtils::add_to_text_blob(&builder, text, font, 0, yOffset); 71 72 // Medium 73 font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); 74 yOffset += bounds.height(); 75 font.setSize(72); 76 77 ToolUtils::add_to_text_blob(&builder, text, font, 0, yOffset); 78 79 // Small 80 font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); 81 yOffset += bounds.height(); 82 font.setSize(32); 83 84 ToolUtils::add_to_text_blob(&builder, text, font, 0, yOffset); 85 86 // micro (will fall out of distance field text even if distance field text is enabled) 87 font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); 88 yOffset += bounds.height(); 89 font.setSize(14); 90 91 ToolUtils::add_to_text_blob(&builder, text, font, 0, yOffset); 92 93 // Zero size. 94 font.measureText(text, strlen(text), SkTextEncoding::kUTF8, &bounds); 95 yOffset += bounds.height(); 96 font.setSize(0); 97 98 ToolUtils::add_to_text_blob(&builder, text, font, 0, yOffset); 99 100 // build 101 fBlob = builder.make(); 102 } 103 getName() const104 SkString getName() const override { 105 return SkStringPrintf("textblobmixedsizes%s", 106 fUseDFT ? "_df" : ""); 107 } 108 getISize()109 SkISize getISize() override { return SkISize::Make(kWidth, kHeight); } 110 onDraw(SkCanvas * inputCanvas)111 void onDraw(SkCanvas* inputCanvas) override { 112 SkCanvas* canvas = inputCanvas; 113 sk_sp<SkSurface> surface; 114 if (fUseDFT) { 115 // Create a new Canvas to enable DFT 116 auto ctx = inputCanvas->recordingContext(); 117 #if defined(SK_GRAPHITE) 118 auto recorder = inputCanvas->recorder(); 119 #endif 120 SkISize size = this->getISize(); 121 if (!inputCanvas->getBaseLayerSize().isEmpty()) { 122 size = inputCanvas->getBaseLayerSize(); 123 } 124 sk_sp<SkColorSpace> colorSpace = inputCanvas->imageInfo().refColorSpace(); 125 SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), 126 kPremul_SkAlphaType, colorSpace); 127 SkSurfaceProps inputProps; 128 inputCanvas->getProps(&inputProps); 129 SkSurfaceProps props( 130 SkSurfaceProps::kUseDeviceIndependentFonts_Flag | inputProps.flags(), 131 inputProps.pixelGeometry()); 132 #if defined(SK_GRAPHITE) 133 if (recorder) { 134 surface = SkSurfaces::RenderTarget(recorder, info, skgpu::Mipmapped::kNo, &props); 135 } else 136 #endif 137 { 138 surface = SkSurfaces::RenderTarget(ctx, skgpu::Budgeted::kNo, info, 0, &props); 139 } 140 canvas = surface ? surface->getCanvas() : inputCanvas; 141 // init our new canvas with the old canvas's matrix 142 canvas->setMatrix(inputCanvas->getTotalMatrix()); 143 } 144 canvas->drawColor(SK_ColorWHITE); 145 146 SkRect bounds = fBlob->bounds(); 147 148 const int kPadX = SkScalarFloorToInt(bounds.width() / 3); 149 const int kPadY = SkScalarFloorToInt(bounds.height() / 3); 150 151 int rowCount = 0; 152 canvas->translate(SkIntToScalar(kPadX), SkIntToScalar(kPadY)); 153 canvas->save(); 154 SkRandom random; 155 156 SkPaint paint; 157 if (!fUseDFT) { 158 paint.setColor(SK_ColorWHITE); 159 } 160 paint.setAntiAlias(false); 161 162 const SkScalar kSigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(8)); 163 164 // setup blur paint 165 SkPaint blurPaint(paint); 166 blurPaint.setColor(SK_ColorBLACK); 167 blurPaint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, kSigma)); 168 169 for (int i = 0; i < 4; i++) { 170 canvas->save(); 171 switch (i % 2) { 172 case 0: 173 canvas->rotate(random.nextF() * 45.f); 174 break; 175 case 1: 176 canvas->rotate(-random.nextF() * 45.f); 177 break; 178 } 179 if (!fUseDFT) { 180 canvas->drawTextBlob(fBlob, 0, 0, blurPaint); 181 } 182 canvas->drawTextBlob(fBlob, 0, 0, paint); 183 canvas->restore(); 184 canvas->translate(bounds.width() + SK_Scalar1 * kPadX, 0); 185 ++rowCount; 186 if ((bounds.width() + 2 * kPadX) * rowCount > kWidth) { 187 canvas->restore(); 188 canvas->translate(0, bounds.height() + SK_Scalar1 * kPadY); 189 canvas->save(); 190 rowCount = 0; 191 } 192 } 193 canvas->restore(); 194 195 // render offscreen buffer 196 if (surface) { 197 SkAutoCanvasRestore acr(inputCanvas, true); 198 // since we prepended this matrix already, we blit using identity 199 inputCanvas->resetMatrix(); 200 inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0); 201 } 202 } 203 204 private: 205 sk_sp<SkTextBlob> fBlob; 206 207 static constexpr int kWidth = 2100; 208 static constexpr int kHeight = 1900; 209 210 bool fUseDFT; 211 212 using INHERITED = GM; 213 }; 214 215 ////////////////////////////////////////////////////////////////////////////// 216 217 DEF_GM( return new TextBlobMixedSizes(false); ) 218 DEF_GM( return new TextBlobMixedSizes(true); ) 219 } // namespace skiagm 220