• 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.h"
9 #include "sk_tool_utils.h"
10 
11 #include "Resources.h"
12 #include "SkCanvas.h"
13 #include "SkGradientShader.h"
14 #include "SkRandomScalerContext.h"
15 #include "SkStream.h"
16 #include "SkSurface.h"
17 #include "SkTextBlob.h"
18 #include "SkTypeface.h"
19 
20 #include "GrContext.h"
21 
22 namespace skiagm {
23 class TextBlobRandomFont : public GpuGM {
24 public:
25     // This gm tests that textblobs can be translated and scaled with a font that returns random
26     // but deterministic masks
TextBlobRandomFont()27     TextBlobRandomFont() { }
28 
29 protected:
onOnceBeforeDraw()30     void onOnceBeforeDraw() override {
31         SkTextBlobBuilder builder;
32 
33         const char* text = "The quick brown fox jumps over the lazy dog.";
34 
35         SkPaint paint;
36         paint.setAntiAlias(true);
37         paint.setColor(SK_ColorMAGENTA);
38 
39         // make textbloben
40         SkFont font;
41         font.setSize(32);
42         font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
43 
44         // Setup our random scaler context
45         auto typeface = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::Bold());
46         if (!typeface) {
47             typeface = SkTypeface::MakeDefault();
48         }
49         font.setTypeface(sk_make_sp<SkRandomTypeface>(std::move(typeface), paint, false));
50 
51         SkScalar y = 0;
52         SkRect bounds;
53         font.measureText(text, strlen(text), kUTF8_SkTextEncoding, &bounds);
54         y -= bounds.fTop;
55         sk_tool_utils::add_to_text_blob(&builder, text, font, 0, y);
56         y += bounds.fBottom;
57 
58         // A8
59         const char* bigtext1 = "The quick brown fox";
60         const char* bigtext2 = "jumps over the lazy dog.";
61         font.setSize(160);
62         font.setSubpixel(false);
63         font.setEdging(SkFont::Edging::kAntiAlias);
64         font.measureText(bigtext1, strlen(bigtext1), kUTF8_SkTextEncoding, &bounds);
65         y -= bounds.fTop;
66         sk_tool_utils::add_to_text_blob(&builder, bigtext1, font, 0, y);
67         y += bounds.fBottom;
68 
69         font.measureText(bigtext2, strlen(bigtext2), kUTF8_SkTextEncoding, &bounds);
70         y -= bounds.fTop;
71         sk_tool_utils::add_to_text_blob(&builder, bigtext2, font, 0, y);
72         y += bounds.fBottom;
73 
74         // color emoji
75         if (sk_sp<SkTypeface> origEmoji = sk_tool_utils::emoji_typeface()) {
76             font.setTypeface(sk_make_sp<SkRandomTypeface>(origEmoji, paint, false));
77             const char* emojiText = sk_tool_utils::emoji_sample_text();
78             font.measureText(emojiText, strlen(emojiText), kUTF8_SkTextEncoding, &bounds);
79             y -= bounds.fTop;
80             sk_tool_utils::add_to_text_blob(&builder, emojiText, font, 0, y);
81             y += bounds.fBottom;
82         }
83 
84         // build
85         fBlob = builder.make();
86     }
87 
onShortName()88     SkString onShortName() override {
89         return SkString("textblobrandomfont");
90     }
91 
onISize()92     SkISize onISize() override {
93         return SkISize::Make(kWidth, kHeight);
94     }
95 
onDraw(GrContext * context,GrRenderTargetContext *,SkCanvas * canvas,SkString * errorMsg)96     DrawResult onDraw(GrContext* context, GrRenderTargetContext*, SkCanvas* canvas,
97                       SkString* errorMsg) override {
98         // This GM exists to test a specific feature of the GPU backend.
99         // This GM uses sk_tool_utils::makeSurface which doesn't work well with vias.
100         // This GM uses SkRandomTypeface which doesn't work well with serialization.
101         canvas->drawColor(SK_ColorWHITE);
102 
103         SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, canvas->imageInfo().colorType(),
104                                              kPremul_SkAlphaType,
105                                              canvas->imageInfo().refColorSpace());
106         SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
107         auto surface(sk_tool_utils::makeSurface(canvas, info, &props));
108         if (!surface) {
109             *errorMsg = "This test requires a surface";
110             return DrawResult::kFail;
111         }
112 
113         SkPaint paint;
114         paint.setAntiAlias(true);
115 
116         SkCanvas* surfaceCanvas = surface->getCanvas();
117 
118         SkScalar stride = SkScalarCeilToScalar(fBlob->bounds().height());
119         SkScalar yOffset = 5;
120 
121         canvas->save();
122         // Originally we would alternate between rotating and not to force blob regeneration,
123         // but that code seems to have rotted. Keeping the rotate to match the old GM as
124         // much as possible, and it seems like a reasonable stress test for transformed
125         // color emoji.
126         canvas->rotate(-0.05f);
127         canvas->drawTextBlob(fBlob, 10, yOffset, paint);
128         yOffset += stride;
129         canvas->restore();
130 
131         // Rotate in the surface canvas, not the final canvas, to avoid aliasing
132         surfaceCanvas->rotate(-0.05f);
133         surfaceCanvas->drawTextBlob(fBlob, 10, yOffset, paint);
134         surface->draw(canvas, 0, 0, nullptr);
135         yOffset += stride;
136 
137         // free gpu resources and verify
138         context->freeGpuResources();
139 
140         canvas->rotate(-0.05f);
141         canvas->drawTextBlob(fBlob, 10, yOffset, paint);
142         yOffset += stride;
143         return DrawResult::kOk;
144     }
145 
146 private:
147     sk_sp<SkTextBlob> fBlob;
148 
149     static constexpr int kWidth = 2000;
150     static constexpr int kHeight = 1600;
151 
152     typedef GM INHERITED;
153 };
154 
155 //////////////////////////////////////////////////////////////////////////////
156 
157 DEF_GM(return new TextBlobRandomFont;)
158 }
159