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