Flutter Engine
The Flutter Engine
drawatlas.cpp
Go to the documentation of this file.
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"
13#include "include/core/SkFont.h"
19#include "include/core/SkPath.h"
23#include "include/core/SkRect.h"
27#include "include/core/SkSize.h"
39#include "src/core/SkFontPriv.h"
40#include "tools/DecodeUtils.h"
41#include "tools/Resources.h"
42#include "tools/ToolUtils.h"
44
45#include <initializer_list>
46
47using namespace skia_private;
48
49class DrawAtlasGM : public skiagm::GM {
50 static sk_sp<SkImage> MakeAtlas(SkCanvas* caller, const SkRect& target) {
52 auto surface(ToolUtils::makeSurface(caller, info));
53 SkCanvas* canvas = surface->getCanvas();
54 // draw red everywhere, but we don't expect to see it in the draw, testing the notion
55 // that drawAtlas draws a subset-region of the atlas.
56 canvas->clear(SK_ColorRED);
57
59 paint.setBlendMode(SkBlendMode::kClear);
60 SkRect r(target);
61 r.inset(-1, -1);
62 // zero out a place (with a 1-pixel border) to land our drawing.
63 canvas->drawRect(r, paint);
64 paint.setBlendMode(SkBlendMode::kSrcOver);
65 paint.setColor(SK_ColorBLUE);
66 paint.setAntiAlias(true);
67 canvas->drawOval(target, paint);
68 return surface->makeImageSnapshot();
69 }
70
71public:
73
74protected:
75 SkString getName() const override { return SkString("draw-atlas"); }
76
77 SkISize getISize() override { return SkISize::Make(640, 480); }
78
79 void onDraw(SkCanvas* canvas) override {
80 const SkRect target = { 50, 50, 80, 90 };
81 auto atlas = MakeAtlas(canvas, target);
82
83 const struct {
84 SkScalar fScale;
85 SkScalar fDegrees;
86 SkScalar fTx;
87 SkScalar fTy;
88
89 void apply(SkRSXform* xform) const {
90 const SkScalar rad = SkDegreesToRadians(fDegrees);
91 xform->fSCos = fScale * SkScalarCos(rad);
92 xform->fSSin = fScale * SkScalarSin(rad);
93 xform->fTx = fTx;
94 xform->fTy = fTy;
95 }
96 } rec[] = {
97 { 1, 0, 10, 10 }, // just translate
98 { 2, 0, 110, 10 }, // scale + translate
99 { 1, 30, 210, 10 }, // rotate + translate
100 { 2, -30, 310, 30 }, // scale + rotate + translate
101 };
102
103 const int N = std::size(rec);
104 SkRSXform xform[N];
105 SkRect tex[N];
107
108 for (int i = 0; i < N; ++i) {
109 rec[i].apply(&xform[i]);
110 tex[i] = target;
111 colors[i] = 0x80FF0000 + (i * 40 * 256);
112 }
113
115 paint.setAntiAlias(true);
117
118 canvas->drawAtlas(atlas.get(), xform, tex, nullptr, N, SkBlendMode::kDst,
119 sampling, nullptr, &paint);
120 canvas->translate(0, 100);
121 canvas->drawAtlas(atlas.get(), xform, tex, colors, N, SkBlendMode::kSrcIn,
122 sampling, nullptr, &paint);
123 }
124
125private:
126 using INHERITED = GM;
127};
128DEF_GM( return new DrawAtlasGM; )
129
130///////////////////////////////////////////////////////////////////////////////////////////////////
131
132static void draw_text_on_path(SkCanvas* canvas, const void* text, size_t length,
133 const SkPoint xy[], const SkPath& path, const SkFont& font, const SkPaint& paint,
134 float baseline_offset) {
135 SkPathMeasure meas(path, false);
136
137 int count = font.countText(text, length, SkTextEncoding::kUTF8);
138 size_t size = count * (sizeof(SkRSXform) + sizeof(SkScalar));
139 SkAutoSMalloc<512> storage(size);
140 SkRSXform* xform = (SkRSXform*)storage.get();
141 SkScalar* widths = (SkScalar*)(xform + count);
142
143 // Compute a conservative bounds so we can cull the draw
147 const SkRect bounds = path.getBounds().makeOutset(max, max);
148
150 font.textToGlyphs(text, length, SkTextEncoding::kUTF8, glyphs.get(), count);
151 font.getWidths(glyphs.get(), count, widths);
152
153 for (int i = 0; i < count; ++i) {
154 // we want to position each character on the center of its advance
156 SkPoint pos;
157 SkVector tan;
158 if (!meas.getPosTan(xy[i].x() + offset, &pos, &tan)) {
159 pos = xy[i];
160 tan.set(1, 0);
161 }
162 pos += SkVector::Make(-tan.fY, tan.fX) * baseline_offset;
163
164 xform[i].fSCos = tan.x();
165 xform[i].fSSin = tan.y();
166 xform[i].fTx = pos.x() - tan.y() * xy[i].y() - tan.x() * offset;
167 xform[i].fTy = pos.y() + tan.x() * xy[i].y() - tan.y() * offset;
168 }
169
171 &xform[0], font, SkTextEncoding::kGlyphID),
172 0, 0, paint);
173
174 if (true) {
175 SkPaint p;
176 p.setStyle(SkPaint::kStroke_Style);
177 canvas->drawRect(bounds, p);
178 }
179}
180
182 SkPoint pts[2] = {{0, 0}, {220, 0}};
185}
186
187static void drawTextPath(SkCanvas* canvas, bool doStroke) {
188 const char text0[] = "ABCDFGHJKLMNOPQRSTUVWXYZ";
189 const int N = sizeof(text0) - 1;
190 SkPoint pos[N];
191
193 font.setSize(100);
194
196 paint.setShader(make_shader());
197 paint.setAntiAlias(true);
198 if (doStroke) {
200 paint.setStrokeWidth(2.25f);
201 paint.setStrokeJoin(SkPaint::kRound_Join);
202 }
203
204 SkScalar x = 0;
205 for (int i = 0; i < N; ++i) {
206 pos[i].set(x, 0);
207 x += font.measureText(&text0[i], 1, SkTextEncoding::kUTF8, nullptr, &paint);
208 }
209
210 SkPath path;
211 const float baseline_offset = -5;
212
213 const SkPathDirection dirs[] = {
215 };
216 for (auto d : dirs) {
217 path.reset();
218 path.addOval(SkRect::MakeXYWH(160, 160, 540, 540), d);
219 draw_text_on_path(canvas, text0, N, pos, path, font, paint, baseline_offset);
220 }
221
222 paint.reset();
224 canvas->drawPath(path, paint);
225}
226
227DEF_SIMPLE_GM(drawTextRSXform, canvas, 430, 860) {
228 canvas->scale(0.5f, 0.5f);
229 const bool doStroke[] = { false, true };
230 for (auto st : doStroke) {
231 drawTextPath(canvas, st);
232 canvas->translate(0, 860);
233 }
234}
235
236// Exercise xform blob and its bounds
237DEF_SIMPLE_GM(blob_rsxform, canvas, 500, 100) {
239 font.setSize(50);
240
241 const char text[] = "CrazyXform";
242 constexpr size_t len = sizeof(text) - 1;
243
245 SkScalar scale = 1;
246 SkScalar x = 0, y = 0;
247 for (size_t i = 0; i < len; ++i) {
248 scale = SkScalarSin(i * SK_ScalarPI / (len-1)) * 0.75f + 0.5f;
249 xforms[i] = SkRSXform::Make(scale, 0, x, y);
250 x += 50 * scale;
251 }
252
254
255 SkPoint offset = { 20, 70 };
257 paint.setColor(0xFFCCCCCC);
258 canvas->drawRect(blob->bounds().makeOffset(offset.fX, offset.fY), paint);
259 paint.setColor(SK_ColorBLACK);
260 canvas->drawTextBlob(blob, offset.fX, offset.fY, paint);
261}
262
263// Exercise xform blob and its tight bounds
264DEF_SIMPLE_GM(blob_rsxform_distortable, canvas, 500, 100) {
265 sk_sp<SkTypeface> typeface;
266 std::unique_ptr<SkStreamAsset> distortable(GetResourceAsStream("fonts/Distortable.ttf"));
267 if (distortable) {
270 { SkSetFourByteTag('w','g','h','t'), 1.618033988749895f }
271 };
273 params.setVariationDesignPosition({position, std::size(position)});
274 typeface = fm->makeFromStream(std::move(distortable), params);
275 }
276 if (!typeface) {
278 }
279
280 SkFont font(typeface, 50);
281
282 const char text[] = "abcabcabc";
283 constexpr size_t len = sizeof(text) - 1;
284
286 SkScalar scale = 1;
287 SkScalar x = 0, y = 0;
288 for (size_t i = 0; i < len; ++i) {
289 scale = SkScalarSin(i * SK_ScalarPI / (len-1)) * 0.75f + 0.5f;
290 xforms[i] = SkRSXform::Make(scale, 0, x, y);
291 x += 50 * scale;
292 }
293
295
296 SkPoint offset = { 20, 70 };
298 paint.setColor(0xFFCCCCCC);
299 canvas->drawRect(blob->bounds().makeOffset(offset.fX, offset.fY), paint);
300 paint.setColor(SK_ColorBLACK);
301 canvas->drawTextBlob(blob, offset.fX, offset.fY, paint);
302}
303
305 SkColor color) {
306 SkPoint pos[4];
307 r.toQuad(pos);
308 SkColor colors[4] = { color, color, color, color };
310 pos, pos, colors);
311}
312
313/*
314 * drawAtlas and drawVertices have several things in common:
315 * - can create compound "shaders", combining texture and colors
316 * - these are combined via an explicit blendmode
317 * - like drawImage, they only respect parts of the paint
318 * - colorfilter, imagefilter, blendmode, alpha
319 *
320 * This GM produces a series of pairs of images (atlas | vertices).
321 * Each pair should look the same, and each set shows a different combination
322 * of alpha | colorFilter | mode
323 */
324DEF_SIMPLE_GM(compare_atlas_vertices, canvas, 560, 585) {
325 const SkRect tex = SkRect::MakeWH(128, 128);
326 const SkRSXform xform = SkRSXform::Make(1, 0, 0, 0);
327 const SkColor color = 0x884488CC;
328
329 auto image = ToolUtils::GetResourceAsImage("images/mandrill_128.png");
330 auto verts = make_vertices(image, tex, color);
331 const sk_sp<SkColorFilter> filters[] = {
332 nullptr,
334 };
335 const SkBlendMode modes[] = {
338 };
339
340 canvas->translate(10, 10);
342 for (SkBlendMode mode : modes) {
343 for (float alpha : { 1.0f, 0.5f }) {
344 paint.setAlphaf(alpha);
345 canvas->save();
346 for (const sk_sp<SkColorFilter>& cf : filters) {
347 paint.setColorFilter(cf);
348 canvas->drawAtlas(image.get(), &xform, &tex, &color, 1, mode,
349 SkSamplingOptions(), &tex, &paint);
350 canvas->translate(128, 0);
352 canvas->drawVertices(verts, mode, paint);
353 paint.setShader(nullptr);
354 canvas->translate(145, 0);
355 }
356 canvas->restore();
357 canvas->translate(0, 145);
358 }
359 }
360}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
uint16_t glyphs[5]
Definition: FontMgrTest.cpp:46
int count
Definition: FontMgrTest.cpp:50
SkPoint pos
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition: Resources.cpp:31
SkBlendMode
Definition: SkBlendMode.h:38
@ kPlus
r = min(s + d, 1)
@ kModulate
r = s*d
@ kSrcOver
r = s + (1-sa)*d
@ kSrcIn
r = s * da
@ kClear
r = 0
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
@ kUTF8
uses bytes to represent UTF-8 or ASCII
@ kGlyphID
uses two byte words to represent glyph indices
SkPathDirection
Definition: SkPathTypes.h:34
static bool apply(Pass *pass, SkRecord *record)
#define SkDegreesToRadians(degrees)
Definition: SkScalar.h:77
#define SkScalarSin(radians)
Definition: SkScalar.h:45
#define SkScalarHalf(a)
Definition: SkScalar.h:75
#define SkScalarCos(radians)
Definition: SkScalar.h:46
#define SkScalarAbs(x)
Definition: SkScalar.h:39
#define SK_ScalarPI
Definition: SkScalar.h:21
uint16_t SkGlyphID
Definition: SkTypes.h:179
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition: SkTypes.h:167
const SkScalar widths[]
Definition: StrokerTest.cpp:39
#define N
Definition: beziers.cpp:19
SkISize getISize() override
Definition: drawatlas.cpp:77
void onDraw(SkCanvas *canvas) override
Definition: drawatlas.cpp:79
SkString getName() const override
Definition: drawatlas.cpp:75
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void drawOval(const SkRect &oval, const SkPaint &paint)
Definition: SkCanvas.cpp:1698
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
void clear(SkColor color)
Definition: SkCanvas.h:1199
int save()
Definition: SkCanvas.cpp:447
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void drawAtlas(const SkImage *atlas, const SkRSXform xform[], const SkRect tex[], const SkColor colors[], int count, SkBlendMode mode, const SkSamplingOptions &sampling, const SkRect *cullRect, const SkPaint *paint)
Definition: SkCanvas.cpp:1810
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
void drawVertices(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
Definition: SkCanvas.cpp:1720
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
Definition: SkCanvas.cpp:2484
static sk_sp< SkColorFilter > Blend(const SkColor4f &c, sk_sp< SkColorSpace >, SkBlendMode mode)
sk_sp< SkTypeface > makeFromStream(std::unique_ptr< SkStreamAsset >, int ttcIndex=0) const
Definition: SkFontMgr.cpp:127
static SkRect GetFontBounds(const SkFont &)
Definition: SkFont.cpp:354
Definition: SkFont.h:35
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkImage.cpp:179
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
@ kRound_Join
adds circle
Definition: SkPaint.h:360
bool getPosTan(SkScalar distance, SkPoint *position, SkVector *tangent)
Definition: SkPath.h:59
static sk_sp< SkTextBlob > MakeFromRSXform(const void *text, size_t byteLength, const SkRSXform xform[], const SkFont &font, SkTextEncoding encoding=SkTextEncoding::kUTF8)
Definition: SkTextBlob.cpp:831
static sk_sp< SkVertices > MakeCopy(VertexMode mode, int vertexCount, const SkPoint positions[], const SkPoint texs[], const SkColor colors[], int indexCount, const uint16_t indices[])
Definition: SkVertices.cpp:200
@ kTriangleFan_VertexMode
Definition: SkVertices.h:33
T * get() const
Definition: SkRefCnt.h:303
Definition: gm.h:110
GM(SkColor backgroundColor=SK_ColorWHITE)
Definition: gm.cpp:81
const Paint & paint
Definition: color_source.cc:38
DlColor color
static void draw_text_on_path(SkCanvas *canvas, const void *text, size_t length, const SkPoint xy[], const SkPath &path, const SkFont &font, const SkPaint &paint, float baseline_offset)
Definition: drawatlas.cpp:132
DEF_SIMPLE_GM(drawTextRSXform, canvas, 430, 860)
Definition: drawatlas.cpp:227
static void drawTextPath(SkCanvas *canvas, bool doStroke)
Definition: drawatlas.cpp:187
static sk_sp< SkShader > make_shader()
Definition: drawatlas.cpp:181
static sk_sp< SkVertices > make_vertices(sk_sp< SkImage > image, const SkRect &r, SkColor color)
Definition: drawatlas.cpp:304
const EmbeddedViewParams * params
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
VkSurfaceKHR surface
Definition: main.cc:49
float SkScalar
Definition: extension.cpp:12
uint32_t * target
#define DEF_GM(CODE)
Definition: gm.h:40
static float max(float r, float g, float b)
Definition: hsl.cpp:49
size_t length
std::u16string text
double y
double x
sk_sp< const SkImage > atlas
Definition: SkRecords.h:331
Optional< SkRect > bounds
Definition: SkRecords.h:189
sk_sp< const SkImage > image
Definition: SkRecords.h:269
PODArray< SkRSXform > xforms
Definition: SkRecords.h:332
PODArray< SkColor > colors
Definition: SkRecords.h:276
SkSamplingOptions sampling
Definition: SkRecords.h:337
sk_sp< SkTypeface > DefaultPortableTypeface()
SkFont DefaultPortableFont()
sk_sp< SkSurface > makeSurface(SkCanvas *canvas, const SkImageInfo &info, const SkSurfaceProps *props)
Definition: ToolUtils.cpp:512
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition: DecodeUtils.h:25
sk_sp< SkFontMgr > TestFontMgr()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
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 mode
Definition: switches.h:228
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.
const Scalar scale
SeparatedVector2 offset
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
static SkImageInfo MakeN32Premul(int width, int height)
float fX
x-axis value
Definition: SkPoint_impl.h:164
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
void set(float x, float y)
Definition: SkPoint_impl.h:200
float fY
y-axis value
Definition: SkPoint_impl.h:165
constexpr float y() const
Definition: SkPoint_impl.h:187
constexpr float x() const
Definition: SkPoint_impl.h:181
SkScalar fTy
Definition: SkRSXform.h:45
SkScalar fSCos
Definition: SkRSXform.h:42
static SkRSXform Make(SkScalar scos, SkScalar ssin, SkScalar tx, SkScalar ty)
Definition: SkRSXform.h:24
SkScalar fTx
Definition: SkRSXform.h:44
SkScalar fSSin
Definition: SkRSXform.h:43
SkScalar fBottom
larger y-axis bounds
Definition: extension.cpp:17
void toQuad(SkPoint quad[4]) const
Definition: SkRect.cpp:50
void inset(float dx, float dy)
Definition: SkRect.h:1060
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
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
SkScalar fTop
smaller y-axis bounds
Definition: extension.cpp:15