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