xref: /aosp_15_r20/external/skia/gm/variedtext.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 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/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkFont.h"
12 #include "include/core/SkFontStyle.h"
13 #include "include/core/SkFontTypes.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPoint.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/core/SkScalar.h"
19 #include "include/core/SkSize.h"
20 #include "include/core/SkString.h"
21 #include "include/core/SkTypeface.h"
22 #include "include/core/SkTypes.h"
23 #include "src/base/SkRandom.h"
24 #include "tools/ToolUtils.h"
25 #include "tools/fonts/FontToolUtils.h"
26 
27 /**
28  * Draws text with random parameters. The text draws each get their own clip rect. It is also
29  * used as a bench to measure how well the GPU backend combines draw ops for text draws.
30  */
31 
32 class VariedTextGM : public skiagm::GM {
33 public:
VariedTextGM(bool effectiveClip,bool lcd)34     VariedTextGM(bool effectiveClip, bool lcd)
35         : fEffectiveClip(effectiveClip)
36         , fLCD(lcd) {
37     }
38 
39 protected:
getName() const40     SkString getName() const override {
41         SkString name("varied_text");
42         if (fEffectiveClip) {
43             name.append("_clipped");
44         } else {
45             name.append("_ignorable_clip");
46         }
47         if (fLCD) {
48             name.append("_lcd");
49         } else {
50             name.append("_no_lcd");
51         }
52         return name;
53     }
54 
getISize()55     SkISize getISize() override { return SkISize::Make(640, 480); }
56 
onOnceBeforeDraw()57     void onOnceBeforeDraw() override {
58         fPaint.setAntiAlias(true);
59         fFont.setEdging(fLCD ? SkFont::Edging::kSubpixelAntiAlias : SkFont::Edging::kAntiAlias);
60 
61         SkISize size = this->getISize();
62         SkScalar w = SkIntToScalar(size.fWidth);
63         SkScalar h = SkIntToScalar(size.fHeight);
64 
65         SkASSERTF(4 == std::size(fTypefaces), "typeface_cnt");
66         fTypefaces[0] = ToolUtils::CreatePortableTypeface("sans-serif", SkFontStyle());
67         fTypefaces[1] = ToolUtils::CreatePortableTypeface("sans-serif", SkFontStyle::Bold());
68         fTypefaces[2] = ToolUtils::CreatePortableTypeface("serif", SkFontStyle());
69         fTypefaces[3] = ToolUtils::CreatePortableTypeface("serif", SkFontStyle::Bold());
70 
71         SkRandom random;
72         for (int i = 0; i < kCnt; ++i) {
73             int length = random.nextRangeU(kMinLength, kMaxLength);
74             char text[kMaxLength];
75             for (int j = 0; j < length; ++j) {
76                 text[j] = (char)random.nextRangeU('!', 'z');
77             }
78             fStrings[i].set(text, length);
79 
80             fColors[i] = random.nextU();
81             fColors[i] |= 0xFF000000;
82             fColors[i] = ToolUtils::color_to_565(fColors[i]);
83 
84             constexpr SkScalar kMinPtSize = 8.f;
85             constexpr SkScalar kMaxPtSize = 32.f;
86 
87             fPtSizes[i] = random.nextRangeScalar(kMinPtSize, kMaxPtSize);
88 
89             fTypefaceIndices[i] = random.nextULessThan(std::size(fTypefaces));
90 
91             SkRect r;
92             fPaint.setColor(fColors[i]);
93             fFont.setTypeface(fTypefaces[fTypefaceIndices[i]]);
94             fFont.setSize(fPtSizes[i]);
95 
96             fFont.measureText(fStrings[i].c_str(), fStrings[i].size(), SkTextEncoding::kUTF8, &r);
97             // The set of x,y offsets which place the bounding box inside the GM's border.
98             SkRect safeRect = SkRect::MakeLTRB(-r.fLeft, -r.fTop, w - r.fRight, h - r.fBottom);
99             if (safeRect.isEmpty()) {
100                 // If the bounds don't fit then allow any offset in the GM's border.
101                 safeRect = SkRect::MakeWH(w, h);
102             }
103             fOffsets[i].fX = random.nextRangeScalar(safeRect.fLeft, safeRect.fRight);
104             fOffsets[i].fY = random.nextRangeScalar(safeRect.fTop, safeRect.fBottom);
105 
106             fClipRects[i] = r;
107             fClipRects[i].offset(fOffsets[i].fX, fOffsets[i].fY);
108             fClipRects[i].outset(2.f, 2.f);
109 
110             if (fEffectiveClip) {
111                 fClipRects[i].fRight -= 0.25f * fClipRects[i].width();
112             }
113         }
114     }
115 
onDraw(SkCanvas * canvas)116     void onDraw(SkCanvas* canvas) override {
117         for (int i = 0; i < kCnt; ++i) {
118             fPaint.setColor(fColors[i]);
119             fFont.setSize(fPtSizes[i]);
120             fFont.setTypeface(fTypefaces[fTypefaceIndices[i]]);
121 
122             canvas->save();
123                 canvas->clipRect(fClipRects[i]);
124                 canvas->translate(fOffsets[i].fX, fOffsets[i].fY);
125                 canvas->drawSimpleText(fStrings[i].c_str(), fStrings[i].size(), SkTextEncoding::kUTF8,
126                                        0, 0, fFont, fPaint);
127             canvas->restore();
128         }
129 
130         // Visualize the clips, but not in bench mode.
131         if (kBench_Mode != this->getMode()) {
132             SkPaint wirePaint;
133             wirePaint.setAntiAlias(true);
134             wirePaint.setStrokeWidth(0);
135             wirePaint.setStyle(SkPaint::kStroke_Style);
136             for (int i = 0; i < kCnt; ++i) {
137                 canvas->drawRect(fClipRects[i], wirePaint);
138             }
139         }
140     }
141 
runAsBench() const142     bool runAsBench() const override { return true; }
143 
144 private:
145     inline static constexpr int kCnt = 30;
146     inline static constexpr int kMinLength = 15;
147     inline static constexpr int kMaxLength = 40;
148 
149     bool        fEffectiveClip;
150     bool        fLCD;
151     sk_sp<SkTypeface> fTypefaces[4];
152     SkPaint     fPaint;
153     SkFont      fFont;
154 
155     // precomputed for each text draw
156     SkString        fStrings[kCnt];
157     SkColor         fColors[kCnt];
158     SkScalar        fPtSizes[kCnt];
159     int             fTypefaceIndices[kCnt];
160     SkPoint         fOffsets[kCnt];
161     SkRect          fClipRects[kCnt];
162 
163     using INHERITED = skiagm::GM;
164 };
165 
166 DEF_GM(return new VariedTextGM(false, false);)
167 DEF_GM(return new VariedTextGM(true, false);)
168 DEF_GM(return new VariedTextGM(false, true);)
169 DEF_GM(return new VariedTextGM(true, true);)
170