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