Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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];
106 SkColor colors[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
144 const SkRect fontb = SkFontPriv::GetFontBounds(font);
145 const SkScalar max = std::max(std::max(SkScalarAbs(fontb.fLeft), SkScalarAbs(fontb.fRight)),
146 std::max(SkScalarAbs(fontb.fTop), SkScalarAbs(fontb.fBottom)));
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}};
183 SkColor colors[2] = {SK_ColorRED, SK_ColorBLUE};
184 return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kMirror);
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
244 SkRSXform xforms[len];
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
253 auto blob = SkTextBlob::MakeFromRSXform(text, len, xforms, font);
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
285 SkRSXform xforms[len];
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
294 auto blob = SkTextBlob::MakeFromRSXform(text, len, xforms, font);
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]
int count
SkPoint pos
SkColor4f color
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[]
#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)
void drawOval(const SkRect &oval, const SkPaint &paint)
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
void clear(SkColor color)
Definition SkCanvas.h:1199
int save()
Definition SkCanvas.cpp:451
void drawPath(const SkPath &path, const SkPaint &paint)
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)
void scale(SkScalar sx, SkScalar sy)
void drawVertices(const SkVertices *vertices, SkBlendMode mode, const SkPaint &paint)
void drawTextBlob(const SkTextBlob *blob, SkScalar x, SkScalar y, const SkPaint &paint)
static sk_sp< SkColorFilter > Blend(const SkColor4f &c, sk_sp< SkColorSpace >, SkBlendMode mode)
static SkRect GetFontBounds(const SkFont &)
Definition SkFont.cpp:354
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)
static sk_sp< SkTextBlob > MakeFromRSXform(const void *text, size_t byteLength, const SkRSXform xform[], const SkFont &font, SkTextEncoding encoding=SkTextEncoding::kUTF8)
static sk_sp< SkVertices > MakeCopy(VertexMode mode, int vertexCount, const SkPoint positions[], const SkPoint texs[], const SkColor colors[], int indexCount, const uint16_t indices[])
@ kTriangleFan_VertexMode
Definition SkVertices.h:33
T * get() const
Definition SkRefCnt.h:303
GM(SkColor backgroundColor=SK_ColorWHITE)
Definition gm.cpp:81
const Paint & paint
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)
static void drawTextPath(SkCanvas *canvas, bool doStroke)
static sk_sp< SkShader > make_shader()
static sk_sp< SkVertices > make_vertices(sk_sp< SkImage > image, const SkRect &r, SkColor color)
const EmbeddedViewParams * params
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19
VkSurfaceKHR surface
Definition main.cc:49
sk_sp< SkImage > image
Definition examples.cpp:29
float SkScalar
Definition extension.cpp:12
uint32_t * target
#define DEF_GM(CODE)
Definition gm.h:40
#define DEF_SIMPLE_GM(NAME, CANVAS, W, H)
Definition gm.h:50
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< SkTypeface > DefaultPortableTypeface()
SkFont DefaultPortableFont()
sk_sp< SkSurface > makeSurface(SkCanvas *canvas, const SkImageInfo &info, const SkSurfaceProps *props)
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition DecodeUtils.h:25
sk_sp< SkFontMgr > TestFontMgr()
const Scalar scale
Point offset
SkFontArguments & setVariationDesignPosition(VariationPosition position)
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
static constexpr SkPoint Make(float x, float y)
void set(float x, float y)
float fY
y-axis value
constexpr float y() const
constexpr float x() const
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