Flutter Engine
The Flutter Engine
TypefaceSlide.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2024 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 */
12#include "include/core/SkPath.h"
16#include "src/base/SkRandom.h"
17#include "tools/SkMetaData.h"
18#include "tools/ToolUtils.h"
21#include "tools/viewer/Slide.h"
22
23namespace {
24
25class TypefaceSlide : public Slide {
26public:
27 TypefaceSlide() { fName = "Typeface Viewer"; }
28
29 void load(SkScalar w, SkScalar h) override {
30 fWindowSize = {w, h};
31
32 fBaseTypeface = ToolUtils::CreateTypefaceFromResource("fonts/Variable.ttf");
33 fCurrentTypeface = fBaseTypeface;
34 fVariationSliders = ToolUtils::VariationSliders(fCurrentTypeface.get(), fVariationPosition);
35
36 fPathDirectionIndicator.reset();
37 fPathDirectionIndicator.moveTo(0, -3);
38 fPathDirectionIndicator.lineTo(3, 0);
39 fPathDirectionIndicator.lineTo(0, 3);
40 fPathDirectionIndicator.close();
41
42 fPathDirectionIndicatorPaint.setColor(SK_ColorRED);
43 fPathDirectionIndicatorPaint.setStroke(true);
44 fPathDirectionIndicatorPaint.setStrokeWidth(0);
45 }
46
47 void resize(SkScalar w, SkScalar h) override { fWindowSize = {w, h}; }
48
49 void unload() override {
50 fBaseTypeface = nullptr;
51 fCurrentTypeface = nullptr;
52 }
53
54 SkISize getDimensions() const override {
55 if (fDrawArea.isEmpty()) {
56 TypefaceSlide& self = *const_cast<TypefaceSlide*>(this);
57 SkNoDrawCanvas noDraw(fWindowSize.width(), fWindowSize.height());
58 self.draw(&noDraw);
59 }
60 return fDrawArea;
61 }
62
63 void updateCurrentTypeface() {
64 if (!fBaseTypeface) {
65 return;
66 }
68 fVariationSliders.getCoordinates();
70 static_cast<int>(coords.size())};
72 args.setVariationDesignPosition(varPos);
73 fCurrentTypeface = fBaseTypeface->makeClone(args);
74 fCurrentTypefaceDirty = false;
75 }
76
77 void draw(SkCanvas* canvas) override {
79 if (fOutline) {
80 paint.setStroke(true);
81 paint.setStrokeWidth(0);
82 }
83
84 if (fCurrentTypefaceDirty) {
85 this->updateCurrentTypeface();
86 }
87 SkFont font(fCurrentTypeface, fFontSize);
88 SkFontMetrics metrics;
89 font.getMetrics(&metrics);
90
91 SkPoint origin{0, 0};
92 SkPoint position{0, 0};
93 SkRect drawBounds = SkRect::MakeXYWH(0, 0, 1, 1);
94 struct Line {
96 SkGlyphID firstGlyph = 0; // inclusive
97 SkGlyphID lastGlyph = 0; // inclusive
98 int number = 0;
99 } line;
100
101 int numGlyphs = fCurrentTypeface->countGlyphs();
102 if (numGlyphs == 0) {
103 fDrawArea.setEmpty();
104 return;
105 }
106 SkGlyphID lastGlyph = numGlyphs - 1;
107 for (SkGlyphID glyph = 0; true; ++glyph) {
108 // measure a line
109 SkRect beginLineGlyphBounds;
110 {
111 SkRect newLineBounds = line.bounds;
112 if (glyph != line.firstGlyph) {
113 newLineBounds.fRight += 10;
114 }
115 SkScalar advance;
116 SkRect glyphBounds;
117 font.getWidths(&glyph, 1, &advance, &glyphBounds);
118 SkRect advanceBounds = SkRect::MakeWH(advance, 1);
119 SkRect glyphAndAdvanceBounds = glyphBounds;
120 glyphAndAdvanceBounds.join(advanceBounds);
121 beginLineGlyphBounds = glyphAndAdvanceBounds;
122 beginLineGlyphBounds.offset(-beginLineGlyphBounds.fLeft, 0);
123
124 SkRect glyphDrawBounds = beginLineGlyphBounds.makeOffset(newLineBounds.right(), 0);
125 if (line.number == -1) {
126 SkPaint p;
127 p.setColor(SK_ColorBLUE);
128 canvas->drawRect(glyphDrawBounds, p);
129 }
130 newLineBounds.join(glyphDrawBounds);
131 if (newLineBounds.width() < fWindowSize.width()) {
132 line.lastGlyph = glyph;
133 line.bounds = newLineBounds;
134 if (glyph != lastGlyph) {
135 continue;
136 }
137 }
138 }
139
140 // draw the line
141 position.fY -= line.bounds.top();
142 for (SkGlyphID gid = line.firstGlyph; gid <= line.lastGlyph; ++gid) {
143 if (gid != line.firstGlyph) {
144 position.fX += 10;
145 }
146 SkScalar advance;
147 SkRect glyphBounds;
148 font.getWidths(&gid, 1, &advance, &glyphBounds);
149 SkRect advanceBounds = SkRect::MakeWH(advance, 1);
150 SkRect glyphAndAdvanceBounds = glyphBounds;
151 glyphAndAdvanceBounds.join(advanceBounds);
152
153 position.fX -= glyphAndAdvanceBounds.left();
154
155 if (fDrawGlyphMetrics) {
156 SkPaint metricPaint;
157 metricPaint.setColor(SK_ColorRED);
158 canvas->drawRect(glyphBounds.makeOffset(position), metricPaint);
159 metricPaint.setColor(SK_ColorGREEN);
160 canvas->drawRect(advanceBounds.makeOffset(position), metricPaint);
161 }
162
163 canvas->drawGlyphs(1, &gid, &position, origin, font, paint);
164
165 // TODO: also handle drawable by using a paint override canvas?
166 SkPath glyphPath;
167 if (fOutline && font.getPath(gid, &glyphPath)) {
168 SkContourMeasureIter iter(glyphPath, false);
170 while ((contour = iter.next())) {
171 SkPoint contourStart;
172 SkVector tangent;
173 if (contour->getPosTan(0, &contourStart, &tangent)) {
174 contourStart += position;
175 SkAutoCanvasRestore acr(canvas, true);
177 matrix.setSinCos(tangent.y(), tangent.x(), 0, 0);
178 matrix.postTranslate(contourStart.x(), contourStart.y());
179 canvas->concat(matrix);
180 canvas->drawPath(fPathDirectionIndicator, fPathDirectionIndicatorPaint);
181 }
182 }
183 }
184
185 position.fX += glyphAndAdvanceBounds.right();
186 }
187 if (line.lastGlyph == lastGlyph) {
188 break;
189 }
190 drawBounds.join(line.bounds.makeOffset(-line.bounds.fLeft, position.fY));
191 position.fX = 0;
192 position.fY += line.bounds.bottom() + 10;
193 line.bounds = beginLineGlyphBounds;
194 line.firstGlyph = glyph;
195 line.lastGlyph = glyph;
196 ++line.number;
197 }
198
199 fDrawArea = drawBounds.roundOut().size();
200 }
201
202 bool onGetControls(SkMetaData* controls) override {
203 // requested font size
204 SkScalar size[3] = {fFontSize, 0, 256};
205 controls->setScalars("Size", 3, size);
206
207 // TODO: toggle glyph numbers on top?
208 // TODO: limit number of glyphs and set first glyph
209 // TODO: choose typeface factory
210 // TODO: choose between typefaces
211 // TODO: font metrics like underline, strikeout, x-height, cap-height, etc.
212
213 // show glyph metrics like advances and bounds
214 controls->setBool("Glyph Metrics", fDrawGlyphMetrics);
215
216 // hairline contours with initial direction mark
217 controls->setBool("Outline", fOutline);
218
219 return fVariationSliders.writeControls(controls);
220 }
221
222 void onSetControls(const SkMetaData& controls) override {
223 SkScalar size[3] = {0};
224 int numReturnedScalars = 0;
225 SkASSERT_RELEASE(controls.findScalars("Size", &numReturnedScalars, size));
226 SkASSERT_RELEASE(numReturnedScalars == 3);
227 if (fFontSize != size[0]) {
228 fFontSize = size[0];
229 fDrawArea.setEmpty();
230 }
231
232 controls.findBool("Glyph Metrics", &fDrawGlyphMetrics);
233 controls.findBool("Outline", &fOutline);
234
235 fVariationSliders.readControls(controls, &fCurrentTypefaceDirty);
236 }
237
238private:
239 sk_sp<SkTypeface> fBaseTypeface;
240 sk_sp<SkTypeface> fCurrentTypeface;
241
242 std::unique_ptr<SkFontArguments::VariationPosition::Coordinate[]> fCoordinates;
243 SkFontArguments::VariationPosition fVariationPosition;
244 ToolUtils::VariationSliders fVariationSliders;
245 bool fCurrentTypefaceDirty = true;
246 SkScalar fFontSize = 12;
247 bool fOutline = false;
248 bool fDrawGlyphMetrics = false;
249
250 SkSize fWindowSize;
251 SkISize fDrawArea;
252
253 SkPath fPathDirectionIndicator;
254 SkPaint fPathDirectionIndicatorPaint;
255};
256
257} //namespace
258
259//////////////////////////////////////////////////////////////////////////////
260
261DEF_SLIDE( return new TypefaceSlide(); )
const char * fName
#define SkASSERT_RELEASE(cond)
Definition: SkAssert.h:100
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
uint16_t SkGlyphID
Definition: SkTypes.h:179
#define DEF_SLIDE(code)
Definition: Slide.h:25
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
Definition: aaclip.cpp:27
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawGlyphs(int count, const SkGlyphID glyphs[], const SkPoint positions[], const uint32_t clusters[], int textByteCount, const char utf8text[], SkPoint origin, const SkFont &font, const SkPaint &paint)
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
Definition: SkFont.h:35
const SkScalar * findScalars(const char name[], int *count, SkScalar values[]=nullptr) const
Definition: SkMetaData.cpp:122
SkScalar * setScalars(const char name[], int count, const SkScalar values[]=nullptr)
Definition: SkMetaData.cpp:34
void setBool(const char name[], bool value)
Definition: SkMetaData.cpp:46
bool findBool(const char name[], bool *value=nullptr) const
Definition: SkMetaData.cpp:149
void setColor(SkColor color)
Definition: SkPaint.cpp:119
Definition: SkPath.h:59
constexpr T * data() const
Definition: SkSpan_impl.h:94
constexpr size_t size() const
Definition: SkSpan_impl.h:95
Definition: Slide.h:29
virtual void unload()
Definition: Slide.h:42
virtual void resize(SkScalar winWidth, SkScalar winHeight)
Definition: Slide.h:41
virtual SkISize getDimensions() const
Definition: Slide.h:35
virtual void load(SkScalar winWidth, SkScalar winHeight)
Definition: Slide.h:40
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
Optional< SkRect > bounds
Definition: SkRecords.h:189
sk_sp< SkTypeface > CreateTypefaceFromResource(const char *resource, int ttcIndex)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
font
Font Metadata and Metrics.
SkScalar w
SkScalar h
Definition: SkSize.h:16
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
constexpr float left() const
Definition: SkRect.h:734
constexpr SkRect makeOffset(float dx, float dy) const
Definition: SkRect.h:965
SkScalar fLeft
smaller x-axis bounds
Definition: extension.cpp:14
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
SkScalar fRight
larger x-axis bounds
Definition: extension.cpp:16
void roundOut(SkIRect *dst) const
Definition: SkRect.h:1241
void offset(float dx, float dy)
Definition: SkRect.h:1016
constexpr float right() const
Definition: SkRect.h:748
constexpr float width() const
Definition: SkRect.h:762
void join(const SkRect &r)
Definition: SkRect.cpp:126
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
Definition: SkSize.h:52