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 "tools/ToolUtils.h"
9
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkBitmap.h"
12 #include "include/core/SkBlendMode.h"
13 #include "include/core/SkCanvas.h"
14 #include "include/core/SkColorPriv.h"
15 #include "include/core/SkColorSpace.h"
16 #include "include/core/SkColorType.h"
17 #include "include/core/SkFont.h"
18 #include "include/core/SkFontTypes.h"
19 #include "include/core/SkImage.h"
20 #include "include/core/SkImageInfo.h"
21 #include "include/core/SkMatrix.h"
22 #include "include/core/SkPaint.h"
23 #include "include/core/SkPath.h"
24 #include "include/core/SkPathBuilder.h"
25 #include "include/core/SkPathTypes.h"
26 #include "include/core/SkPicture.h"
27 #include "include/core/SkPixelRef.h" // IWYU pragma: keep
28 #include "include/core/SkPixmap.h"
29 #include "include/core/SkPoint3.h"
30 #include "include/core/SkRefCnt.h"
31 #include "include/core/SkSamplingOptions.h"
32 #include "include/core/SkStream.h"
33 #include "include/core/SkSurface.h"
34 #include "include/core/SkTextBlob.h"
35 #include "include/core/SkTileMode.h"
36 #include "include/core/SkTypeface.h"
37 #include "include/effects/SkGradientShader.h"
38 #include "include/private/SkColorData.h"
39 #include "include/private/base/SkCPUTypes.h"
40 #include "include/private/base/SkTemplates.h"
41 #include "src/core/SkFontPriv.h"
42 #include "tools/SkMetaData.h"
43
44 #include <cmath>
45 #include <cstring>
46
47 using namespace skia_private;
48
49 namespace ToolUtils {
50
alphatype_name(SkAlphaType at)51 const char* alphatype_name(SkAlphaType at) {
52 switch (at) {
53 case kUnknown_SkAlphaType: return "Unknown";
54 case kOpaque_SkAlphaType: return "Opaque";
55 case kPremul_SkAlphaType: return "Premul";
56 case kUnpremul_SkAlphaType: return "Unpremul";
57 }
58 SkUNREACHABLE;
59 }
60
colortype_name(SkColorType ct)61 const char* colortype_name(SkColorType ct) {
62 switch (ct) {
63 case kUnknown_SkColorType: return "Unknown";
64 case kAlpha_8_SkColorType: return "Alpha_8";
65 case kA16_unorm_SkColorType: return "Alpha_16";
66 case kA16_float_SkColorType: return "A16_float";
67 case kRGB_565_SkColorType: return "RGB_565";
68 case kARGB_4444_SkColorType: return "ARGB_4444";
69 case kRGBA_8888_SkColorType: return "RGBA_8888";
70 case kSRGBA_8888_SkColorType: return "SRGBA_8888";
71 case kRGB_888x_SkColorType: return "RGB_888x";
72 case kBGRA_8888_SkColorType: return "BGRA_8888";
73 case kRGBA_1010102_SkColorType: return "RGBA_1010102";
74 case kBGRA_1010102_SkColorType: return "BGRA_1010102";
75 case kRGB_101010x_SkColorType: return "RGB_101010x";
76 case kBGR_101010x_SkColorType: return "BGR_101010x";
77 case kBGR_101010x_XR_SkColorType: return "BGR_101010x_XR";
78 case kRGBA_10x6_SkColorType: return "RGBA_10x6";
79 case kGray_8_SkColorType: return "Gray_8";
80 case kRGBA_F16Norm_SkColorType: return "RGBA_F16Norm";
81 case kRGB_F16F16F16x_SkColorType: return "RGB_F16F16F16x";
82 case kRGBA_F16_SkColorType: return "RGBA_F16";
83 case kRGBA_F32_SkColorType: return "RGBA_F32";
84 case kR8G8_unorm_SkColorType: return "R8G8_unorm";
85 case kR16G16_unorm_SkColorType: return "R16G16_unorm";
86 case kR16G16_float_SkColorType: return "R16G16_float";
87 case kR16G16B16A16_unorm_SkColorType: return "R16G16B16A16_unorm";
88 case kR8_unorm_SkColorType: return "R8_unorm";
89 case kBGRA_10101010_XR_SkColorType: return "BGRA_10101010_XR";
90 }
91 SkUNREACHABLE;
92 }
93
colortype_depth(SkColorType ct)94 const char* colortype_depth(SkColorType ct) {
95 switch (ct) {
96 case kUnknown_SkColorType: return "Unknown";
97 case kAlpha_8_SkColorType: return "A8";
98 case kA16_unorm_SkColorType: return "A16";
99 case kA16_float_SkColorType: return "AF16";
100 case kRGB_565_SkColorType: return "565";
101 case kARGB_4444_SkColorType: return "4444";
102 case kRGBA_8888_SkColorType: return "8888";
103 case kSRGBA_8888_SkColorType: return "8888";
104 case kRGB_888x_SkColorType: return "888";
105 case kBGRA_8888_SkColorType: return "8888";
106 case kRGBA_1010102_SkColorType: return "1010102";
107 case kBGRA_1010102_SkColorType: return "1010102";
108 case kRGB_101010x_SkColorType: return "101010";
109 case kBGR_101010x_SkColorType: return "101010";
110 case kBGR_101010x_XR_SkColorType: return "101010";
111 case kBGRA_10101010_XR_SkColorType: return "10101010";
112 case kRGBA_10x6_SkColorType: return "10101010";
113 case kGray_8_SkColorType: return "G8";
114 case kRGBA_F16Norm_SkColorType: return "F16Norm";
115 case kRGB_F16F16F16x_SkColorType: return "F16F16F16x";
116 case kRGBA_F16_SkColorType: return "F16";
117 case kRGBA_F32_SkColorType: return "F32";
118 case kR8G8_unorm_SkColorType: return "88";
119 case kR16G16_unorm_SkColorType: return "1616";
120 case kR16G16_float_SkColorType: return "F16F16";
121 case kR16G16B16A16_unorm_SkColorType: return "16161616";
122 case kR8_unorm_SkColorType: return "R8";
123 }
124 SkUNREACHABLE;
125 }
126
tilemode_name(SkTileMode mode)127 const char* tilemode_name(SkTileMode mode) {
128 switch (mode) {
129 case SkTileMode::kClamp: return "clamp";
130 case SkTileMode::kRepeat: return "repeat";
131 case SkTileMode::kMirror: return "mirror";
132 case SkTileMode::kDecal: return "decal";
133 }
134 SkUNREACHABLE;
135 }
136
color_to_565(SkColor color)137 SkColor color_to_565(SkColor color) {
138 // Not a good idea to use this function for greyscale colors...
139 // it will add an obvious purple or green tint.
140 SkASSERT(SkColorGetR(color) != SkColorGetG(color) || SkColorGetR(color) != SkColorGetB(color) ||
141 SkColorGetG(color) != SkColorGetB(color));
142
143 SkPMColor pmColor = SkPreMultiplyColor(color);
144 U16CPU color16 = SkPixel32ToPixel16(pmColor);
145 return SkPixel16ToColor(color16);
146 }
147
create_checkerboard_shader(SkColor c1,SkColor c2,int size)148 sk_sp<SkShader> create_checkerboard_shader(SkColor c1, SkColor c2, int size) {
149 SkBitmap bm;
150 bm.allocPixels(SkImageInfo::MakeS32(2 * size, 2 * size, kPremul_SkAlphaType));
151 bm.eraseColor(c1);
152 bm.eraseArea(SkIRect::MakeLTRB(0, 0, size, size), c2);
153 bm.eraseArea(SkIRect::MakeLTRB(size, size, 2 * size, 2 * size), c2);
154 return bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions());
155 }
156
create_checkerboard_bitmap(int w,int h,SkColor c1,SkColor c2,int checkSize)157 SkBitmap create_checkerboard_bitmap(int w, int h, SkColor c1, SkColor c2, int checkSize) {
158 SkBitmap bitmap;
159 bitmap.allocPixels(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType));
160 SkCanvas canvas(bitmap);
161
162 ToolUtils::draw_checkerboard(&canvas, c1, c2, checkSize);
163 return bitmap;
164 }
165
create_checkerboard_image(int w,int h,SkColor c1,SkColor c2,int checkSize)166 sk_sp<SkImage> create_checkerboard_image(int w, int h, SkColor c1, SkColor c2, int checkSize) {
167 auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(w, h));
168 ToolUtils::draw_checkerboard(surf->getCanvas(), c1, c2, checkSize);
169 return surf->makeImageSnapshot();
170 }
171
draw_checkerboard(SkCanvas * canvas,SkColor c1,SkColor c2,int size)172 void draw_checkerboard(SkCanvas* canvas, SkColor c1, SkColor c2, int size) {
173 SkPaint paint;
174 paint.setShader(create_checkerboard_shader(c1, c2, size));
175 paint.setBlendMode(SkBlendMode::kSrc);
176 canvas->drawPaint(paint);
177 }
178
make_pixmaps(SkColorType ct,SkAlphaType at,bool withMips,const SkColor4f colors[6],SkPixmap pixmaps[6],std::unique_ptr<char[]> * mem)179 int make_pixmaps(SkColorType ct,
180 SkAlphaType at,
181 bool withMips,
182 const SkColor4f colors[6],
183 SkPixmap pixmaps[6],
184 std::unique_ptr<char[]>* mem) {
185
186 int levelSize = 32;
187 int numMipLevels = withMips ? 6 : 1;
188 size_t size = 0;
189 SkImageInfo ii[6];
190 size_t rowBytes[6];
191 for (int level = 0; level < numMipLevels; ++level) {
192 ii[level] = SkImageInfo::Make(levelSize, levelSize, ct, at);
193 rowBytes[level] = ii[level].minRowBytes();
194 // Make sure we test row bytes that aren't tight.
195 if (!(level % 2)) {
196 rowBytes[level] += (level + 1)*SkColorTypeBytesPerPixel(ii[level].colorType());
197 }
198 size += rowBytes[level]*ii[level].height();
199 levelSize /= 2;
200 }
201 mem->reset(new char[size]);
202 char* addr = mem->get();
203 for (int level = 0; level < numMipLevels; ++level) {
204 pixmaps[level].reset(ii[level], addr, rowBytes[level]);
205 addr += rowBytes[level]*ii[level].height();
206 pixmaps[level].erase(colors[level]);
207 }
208 return numMipLevels;
209 }
210
add_to_text_blob_w_len(SkTextBlobBuilder * builder,const char * text,size_t len,SkTextEncoding encoding,const SkFont & font,SkScalar x,SkScalar y)211 void add_to_text_blob_w_len(SkTextBlobBuilder* builder,
212 const char* text,
213 size_t len,
214 SkTextEncoding encoding,
215 const SkFont& font,
216 SkScalar x,
217 SkScalar y) {
218 int count = font.countText(text, len, encoding);
219 if (count < 1) {
220 return;
221 }
222 auto run = builder->allocRun(font, count, x, y);
223 font.textToGlyphs(text, len, encoding, run.glyphs, count);
224 }
225
add_to_text_blob(SkTextBlobBuilder * builder,const char * text,const SkFont & font,SkScalar x,SkScalar y)226 void add_to_text_blob(SkTextBlobBuilder* builder,
227 const char* text,
228 const SkFont& font,
229 SkScalar x,
230 SkScalar y) {
231 add_to_text_blob_w_len(builder, text, strlen(text), SkTextEncoding::kUTF8, font, x, y);
232 }
233
get_text_path(const SkFont & font,const void * text,size_t length,SkTextEncoding encoding,SkPath * dst,const SkPoint pos[])234 void get_text_path(const SkFont& font,
235 const void* text,
236 size_t length,
237 SkTextEncoding encoding,
238 SkPath* dst,
239 const SkPoint pos[]) {
240 SkAutoToGlyphs atg(font, text, length, encoding);
241 const int count = atg.count();
242 AutoTArray<SkPoint> computedPos;
243 if (pos == nullptr) {
244 computedPos.reset(count);
245 font.getPos(atg.glyphs(), count, &computedPos[0]);
246 pos = computedPos.get();
247 }
248
249 struct Rec {
250 SkPath* fDst;
251 const SkPoint* fPos;
252 } rec = {dst, pos};
253 font.getPaths(atg.glyphs(),
254 atg.count(),
255 [](const SkPath* src, const SkMatrix& mx, void* ctx) {
256 Rec* rec = (Rec*)ctx;
257 if (src) {
258 SkMatrix tmp(mx);
259 tmp.postTranslate(rec->fPos->fX, rec->fPos->fY);
260 rec->fDst->addPath(*src, tmp);
261 }
262 rec->fPos += 1;
263 },
264 &rec);
265 }
266
make_star(const SkRect & bounds,int numPts,int step)267 SkPath make_star(const SkRect& bounds, int numPts, int step) {
268 SkASSERT(numPts != step);
269 SkPathBuilder builder;
270 builder.setFillType(SkPathFillType::kEvenOdd);
271 builder.moveTo(0, -1);
272 for (int i = 1; i < numPts; ++i) {
273 int idx = i * step % numPts;
274 SkScalar theta = idx * 2 * SK_ScalarPI / numPts + SK_ScalarPI / 2;
275 SkScalar x = SkScalarCos(theta);
276 SkScalar y = -SkScalarSin(theta);
277 builder.lineTo(x, y);
278 }
279 SkPath path = builder.detach();
280 path.transform(SkMatrix::RectToRect(path.getBounds(), bounds));
281 return path;
282 }
283
norm_to_rgb(SkBitmap * bm,int x,int y,const SkVector3 & norm)284 static inline void norm_to_rgb(SkBitmap* bm, int x, int y, const SkVector3& norm) {
285 SkASSERT(SkScalarNearlyEqual(norm.length(), 1.0f));
286 unsigned char r = static_cast<unsigned char>((0.5f * norm.fX + 0.5f) * 255);
287 unsigned char g = static_cast<unsigned char>((-0.5f * norm.fY + 0.5f) * 255);
288 unsigned char b = static_cast<unsigned char>((0.5f * norm.fZ + 0.5f) * 255);
289 *bm->getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
290 }
291
create_hemi_normal_map(SkBitmap * bm,const SkIRect & dst)292 void create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst) {
293 const SkPoint center =
294 SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), dst.fTop + (dst.height() / 2.0f));
295 const SkPoint halfSize = SkPoint::Make(dst.width() / 2.0f, dst.height() / 2.0f);
296
297 SkVector3 norm;
298
299 for (int y = dst.fTop; y < dst.fBottom; ++y) {
300 for (int x = dst.fLeft; x < dst.fRight; ++x) {
301 norm.fX = (x + 0.5f - center.fX) / halfSize.fX;
302 norm.fY = (y + 0.5f - center.fY) / halfSize.fY;
303
304 SkScalar tmp = norm.fX * norm.fX + norm.fY * norm.fY;
305 if (tmp >= 1.0f) {
306 norm.set(0.0f, 0.0f, 1.0f);
307 } else {
308 norm.fZ = sqrtf(1.0f - tmp);
309 }
310
311 norm_to_rgb(bm, x, y, norm);
312 }
313 }
314 }
315
create_frustum_normal_map(SkBitmap * bm,const SkIRect & dst)316 void create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst) {
317 const SkPoint center =
318 SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), dst.fTop + (dst.height() / 2.0f));
319
320 SkIRect inner = dst;
321 inner.inset(dst.width() / 4, dst.height() / 4);
322
323 SkPoint3 norm;
324 const SkPoint3 left = SkPoint3::Make(-SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2);
325 const SkPoint3 up = SkPoint3::Make(0.0f, -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
326 const SkPoint3 right = SkPoint3::Make(SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2);
327 const SkPoint3 down = SkPoint3::Make(0.0f, SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
328
329 for (int y = dst.fTop; y < dst.fBottom; ++y) {
330 for (int x = dst.fLeft; x < dst.fRight; ++x) {
331 if (inner.contains(x, y)) {
332 norm.set(0.0f, 0.0f, 1.0f);
333 } else {
334 SkScalar locX = x + 0.5f - center.fX;
335 SkScalar locY = y + 0.5f - center.fY;
336
337 if (locX >= 0.0f) {
338 if (locY > 0.0f) {
339 norm = locX >= locY ? right : down; // LR corner
340 } else {
341 norm = locX > -locY ? right : up; // UR corner
342 }
343 } else {
344 if (locY > 0.0f) {
345 norm = -locX > locY ? left : down; // LL corner
346 } else {
347 norm = locX > locY ? up : left; // UL corner
348 }
349 }
350 }
351
352 norm_to_rgb(bm, x, y, norm);
353 }
354 }
355 }
356
create_tetra_normal_map(SkBitmap * bm,const SkIRect & dst)357 void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst) {
358 const SkPoint center =
359 SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), dst.fTop + (dst.height() / 2.0f));
360
361 static const SkScalar k1OverRoot3 = 0.5773502692f;
362
363 SkPoint3 norm;
364 const SkPoint3 leftUp = SkPoint3::Make(-k1OverRoot3, -k1OverRoot3, k1OverRoot3);
365 const SkPoint3 rightUp = SkPoint3::Make(k1OverRoot3, -k1OverRoot3, k1OverRoot3);
366 const SkPoint3 down = SkPoint3::Make(0.0f, SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
367
368 for (int y = dst.fTop; y < dst.fBottom; ++y) {
369 for (int x = dst.fLeft; x < dst.fRight; ++x) {
370 SkScalar locX = x + 0.5f - center.fX;
371 SkScalar locY = y + 0.5f - center.fY;
372
373 if (locX >= 0.0f) {
374 if (locY > 0.0f) {
375 norm = locX >= locY ? rightUp : down; // LR corner
376 } else {
377 norm = rightUp;
378 }
379 } else {
380 if (locY > 0.0f) {
381 norm = -locX > locY ? leftUp : down; // LL corner
382 } else {
383 norm = leftUp;
384 }
385 }
386
387 norm_to_rgb(bm, x, y, norm);
388 }
389 }
390 }
391
copy_to(SkBitmap * dst,SkColorType dstColorType,const SkBitmap & src)392 bool copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) {
393 SkPixmap srcPM;
394 if (!src.peekPixels(&srcPM)) {
395 return false;
396 }
397
398 SkBitmap tmpDst;
399 SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
400 if (!tmpDst.setInfo(dstInfo)) {
401 return false;
402 }
403
404 if (!tmpDst.tryAllocPixels()) {
405 return false;
406 }
407
408 SkPixmap dstPM;
409 if (!tmpDst.peekPixels(&dstPM)) {
410 return false;
411 }
412
413 if (!srcPM.readPixels(dstPM)) {
414 return false;
415 }
416
417 dst->swap(tmpDst);
418 return true;
419 }
420
copy_to_g8(SkBitmap * dst,const SkBitmap & src)421 void copy_to_g8(SkBitmap* dst, const SkBitmap& src) {
422 SkASSERT(kBGRA_8888_SkColorType == src.colorType() ||
423 kRGBA_8888_SkColorType == src.colorType());
424
425 SkImageInfo grayInfo = src.info().makeColorType(kGray_8_SkColorType);
426 dst->allocPixels(grayInfo);
427 uint8_t* dst8 = (uint8_t*)dst->getPixels();
428 const uint32_t* src32 = (const uint32_t*)src.getPixels();
429
430 const int w = src.width();
431 const int h = src.height();
432 const bool isBGRA = (kBGRA_8888_SkColorType == src.colorType());
433 for (int y = 0; y < h; ++y) {
434 if (isBGRA) {
435 // BGRA
436 for (int x = 0; x < w; ++x) {
437 uint32_t s = src32[x];
438 dst8[x] = SkComputeLuminance((s >> 16) & 0xFF, (s >> 8) & 0xFF, s & 0xFF);
439 }
440 } else {
441 // RGBA
442 for (int x = 0; x < w; ++x) {
443 uint32_t s = src32[x];
444 dst8[x] = SkComputeLuminance(s & 0xFF, (s >> 8) & 0xFF, (s >> 16) & 0xFF);
445 }
446 }
447 src32 = (const uint32_t*)((const char*)src32 + src.rowBytes());
448 dst8 += dst->rowBytes();
449 }
450 }
451
452 //////////////////////////////////////////////////////////////////////////////////////////////
453
equal_pixels(const SkPixmap & a,const SkPixmap & b)454 bool equal_pixels(const SkPixmap& a, const SkPixmap& b) {
455 if (a.width() != b.width() || a.height() != b.height()) {
456 SkDebugf("[ToolUtils::equal_pixels] Dimensions do not match (%d x %d) != (%d x %d)\n",
457 a.width(), a.height(), b.width(), b.height());
458 return false;
459 }
460
461 if (a.colorType() != b.colorType()) {
462 SkDebugf("[ToolUtils::equal_pixels] colorType does not match %d != %d\n",
463 (int) a.colorType(), (int) b.colorType());
464 return false;
465 }
466
467 for (int y = 0; y < a.height(); ++y) {
468 const char* aptr = (const char*)a.addr(0, y);
469 const char* bptr = (const char*)b.addr(0, y);
470 if (0 != memcmp(aptr, bptr, a.width() * a.info().bytesPerPixel())) {
471 SkDebugf("[ToolUtils::equal_pixels] row %d does not match byte for byte\n", y);
472 return false;
473 }
474 }
475 return true;
476 }
477
equal_pixels(const SkBitmap & bm0,const SkBitmap & bm1)478 bool equal_pixels(const SkBitmap& bm0, const SkBitmap& bm1) {
479 SkPixmap pm0, pm1;
480 if (!bm0.peekPixels(&pm0)) {
481 SkDebugf("Could not read pixels from A\n");
482 return false;
483 }
484 if (!bm1.peekPixels(&pm1)) {
485 SkDebugf("Could not read pixels from B\n");
486 return false;
487 }
488 return equal_pixels(pm0, pm1);
489 }
490
equal_pixels(const SkImage * a,const SkImage * b)491 bool equal_pixels(const SkImage* a, const SkImage* b) {
492 SkASSERT_RELEASE(a);
493 SkASSERT_RELEASE(b);
494 // ensure that peekPixels will succeed
495 auto imga = a->makeRasterImage();
496 auto imgb = b->makeRasterImage();
497
498 SkPixmap pm0, pm1;
499 if (!imga->peekPixels(&pm0)) {
500 SkDebugf("Could not read pixels from A\n");
501 return false;
502 }
503 if (!imgb->peekPixels(&pm1)) {
504 SkDebugf("Could not read pixels from B\n");
505 return false;
506 }
507 return equal_pixels(pm0, pm1);
508 }
509
makeSurface(SkCanvas * canvas,const SkImageInfo & info,const SkSurfaceProps * props)510 sk_sp<SkSurface> makeSurface(SkCanvas* canvas,
511 const SkImageInfo& info,
512 const SkSurfaceProps* props) {
513 auto surf = canvas->makeSurface(info, props);
514 if (!surf) {
515 surf = SkSurfaces::Raster(info, props);
516 }
517 return surf;
518 }
519
VariationSliders(SkTypeface * typeface,SkFontArguments::VariationPosition variationPosition)520 VariationSliders::VariationSliders(SkTypeface* typeface,
521 SkFontArguments::VariationPosition variationPosition) {
522 if (!typeface) {
523 return;
524 }
525
526 int numAxes = typeface->getVariationDesignParameters(nullptr, 0);
527 if (numAxes < 0) {
528 return;
529 }
530
531 std::unique_ptr<SkFontParameters::Variation::Axis[]> copiedAxes =
532 std::make_unique<SkFontParameters::Variation::Axis[]>(numAxes);
533
534 numAxes = typeface->getVariationDesignParameters(copiedAxes.get(), numAxes);
535 if (numAxes < 0) {
536 return;
537 }
538
539 auto argVariationPositionOrDefault = [&variationPosition](SkFourByteTag tag,
540 SkScalar defaultValue) -> SkScalar {
541 for (int i = 0; i < variationPosition.coordinateCount; ++i) {
542 if (variationPosition.coordinates[i].axis == tag) {
543 return variationPosition.coordinates[i].value;
544 }
545 }
546 return defaultValue;
547 };
548
549 fAxisSliders.resize(numAxes);
550 fCoords = std::make_unique<SkFontArguments::VariationPosition::Coordinate[]>(numAxes);
551 for (int i = 0; i < numAxes; ++i) {
552 fAxisSliders[i].axis = copiedAxes[i];
553 fAxisSliders[i].current =
554 argVariationPositionOrDefault(copiedAxes[i].tag, copiedAxes[i].def);
555 fAxisSliders[i].name = tagToString(fAxisSliders[i].axis.tag);
556 fCoords[i] = { fAxisSliders[i].axis.tag, fAxisSliders[i].current };
557 }
558 }
559
560 /* static */
tagToString(SkFourByteTag tag)561 SkString VariationSliders::tagToString(SkFourByteTag tag) {
562 char tagAsString[5];
563 tagAsString[4] = 0;
564 tagAsString[0] = (char)(uint8_t)(tag >> 24);
565 tagAsString[1] = (char)(uint8_t)(tag >> 16);
566 tagAsString[2] = (char)(uint8_t)(tag >> 8);
567 tagAsString[3] = (char)(uint8_t)(tag >> 0);
568 return SkString(tagAsString);
569 }
570
writeControls(SkMetaData * controls)571 bool VariationSliders::writeControls(SkMetaData* controls) {
572 for (size_t i = 0; i < fAxisSliders.size(); ++i) {
573 SkScalar axisVars[kAxisVarsSize];
574
575 axisVars[0] = fAxisSliders[i].current;
576 axisVars[1] = fAxisSliders[i].axis.min;
577 axisVars[2] = fAxisSliders[i].axis.max;
578 controls->setScalars(fAxisSliders[i].name.c_str(), kAxisVarsSize, axisVars);
579 }
580 return true;
581 }
582
readControls(const SkMetaData & controls,bool * changed)583 void VariationSliders::readControls(const SkMetaData& controls, bool* changed) {
584 for (size_t i = 0; i < fAxisSliders.size(); ++i) {
585 SkScalar axisVars[kAxisVarsSize] = {0};
586 int resultAxisVarsSize = 0;
587 SkASSERT_RELEASE(controls.findScalars(
588 tagToString(fAxisSliders[i].axis.tag).c_str(), &resultAxisVarsSize, axisVars));
589 SkASSERT_RELEASE(resultAxisVarsSize == kAxisVarsSize);
590 if (changed) {
591 *changed |= fAxisSliders[i].current != axisVars[0];
592 }
593 fAxisSliders[i].current = axisVars[0];
594 fCoords[i] = { fAxisSliders[i].axis.tag, fAxisSliders[i].current };
595 }
596 }
597
getCoordinates()598 SkSpan<const SkFontArguments::VariationPosition::Coordinate> VariationSliders::getCoordinates() {
599 return SkSpan<const SkFontArguments::VariationPosition::Coordinate>{fCoords.get(),
600 fAxisSliders.size()};
601 }
602
603 ////////////////////////////////////////////////////////////////////////////////////////////////////
HilbertGenerator(float desiredSize,float desiredLineWidth,int desiredDepth)604 HilbertGenerator::HilbertGenerator(float desiredSize, float desiredLineWidth, int desiredDepth)
605 : fDesiredSize(desiredSize)
606 , fDesiredDepth(desiredDepth)
607 , fSegmentLength(fDesiredSize / ((0x1 << fDesiredDepth) - 1.0f))
608 , fDesiredLineWidth(desiredLineWidth)
609 , fActualBounds(SkRect::MakeEmpty())
610 , fCurPos(SkPoint::Make(0.0f, 0.0f))
611 , fCurDir(0)
612 , fExpectedLen(fSegmentLength * ((0x1 << (2*fDesiredDepth)) - 1.0f))
613 , fCurLen(0.0f) {
614 }
615
draw(SkCanvas * canvas)616 void HilbertGenerator::draw(SkCanvas* canvas) {
617 this->recursiveDraw(canvas, /* curDepth= */ 0, /* turnLeft= */ true);
618
619 SkScalarNearlyEqual(fExpectedLen, fCurLen, 0.01f);
620 SkScalarNearlyEqual(fDesiredSize, fActualBounds.width(), 0.01f);
621 SkScalarNearlyEqual(fDesiredSize, fActualBounds.height(), 0.01f);
622 }
623
turn90(bool turnLeft)624 void HilbertGenerator::turn90(bool turnLeft) {
625 fCurDir += turnLeft ? 90 : -90;
626 if (fCurDir >= 360) {
627 fCurDir = 0;
628 } else if (fCurDir < 0) {
629 fCurDir = 270;
630 }
631
632 SkASSERT(fCurDir == 0 || fCurDir == 90 || fCurDir == 180 || fCurDir == 270);
633 }
634
line(SkCanvas * canvas)635 void HilbertGenerator::line(SkCanvas* canvas) {
636
637 SkPoint before = fCurPos;
638
639 SkRect r;
640 switch (fCurDir) {
641 case 0:
642 r.fLeft = fCurPos.fX;
643 r.fTop = fCurPos.fY - fDesiredLineWidth / 2.0f;
644 r.fRight = fCurPos.fX + fSegmentLength;
645 r.fBottom = fCurPos.fY + fDesiredLineWidth / 2.0f;
646 fCurPos.fX += fSegmentLength;
647 break;
648 case 90:
649 r.fLeft = fCurPos.fX - fDesiredLineWidth / 2.0f;
650 r.fTop = fCurPos.fY - fSegmentLength;
651 r.fRight = fCurPos.fX + fDesiredLineWidth / 2.0f;
652 r.fBottom = fCurPos.fY;
653 fCurPos.fY -= fSegmentLength;
654 break;
655 case 180:
656 r.fLeft = fCurPos.fX - fSegmentLength;
657 r.fTop = fCurPos.fY - fDesiredLineWidth / 2.0f;
658 r.fRight = fCurPos.fX;
659 r.fBottom = fCurPos.fY + fDesiredLineWidth / 2.0f;
660 fCurPos.fX -= fSegmentLength;
661 break;
662 case 270:
663 r.fLeft = fCurPos.fX - fDesiredLineWidth / 2.0f;
664 r.fTop = fCurPos.fY;
665 r.fRight = fCurPos.fX + fDesiredLineWidth / 2.0f;
666 r.fBottom = fCurPos.fY + fSegmentLength;
667 fCurPos.fY += fSegmentLength;
668 break;
669 default:
670 return;
671 }
672
673 SkPoint pts[2] = { before, fCurPos };
674
675 SkColor4f colors[2] = {
676 this->getColor(fCurLen),
677 this->getColor(fCurLen + fSegmentLength),
678 };
679
680 fCurLen += fSegmentLength;
681 if (fActualBounds.isEmpty()) {
682 fActualBounds = r;
683 } else {
684 fActualBounds.join(r);
685 }
686
687 SkPaint paint;
688 paint.setShader(SkGradientShader::MakeLinear(pts, colors, /* colorSpace= */ nullptr,
689 /* pos= */ nullptr, 2, SkTileMode::kClamp));
690 canvas->drawRect(r, paint);
691 }
692
recursiveDraw(SkCanvas * canvas,int curDepth,bool turnLeft)693 void HilbertGenerator::recursiveDraw(SkCanvas* canvas, int curDepth, bool turnLeft) {
694 if (curDepth >= fDesiredDepth) {
695 return;
696 }
697
698 this->turn90(turnLeft);
699 this->recursiveDraw(canvas, curDepth + 1, !turnLeft);
700 this->line(canvas);
701 this->turn90(!turnLeft);
702 this->recursiveDraw(canvas, curDepth + 1, turnLeft);
703 this->line(canvas);
704 this->recursiveDraw(canvas, curDepth + 1, turnLeft);
705 this->turn90(!turnLeft);
706 this->line(canvas);
707 this->recursiveDraw(canvas, curDepth + 1, !turnLeft);
708 this->turn90(turnLeft);
709 }
710
getColor(float curLen)711 SkColor4f HilbertGenerator::getColor(float curLen) {
712 static const SkColor4f kColors[] = {
713 SkColors::kBlack,
714 SkColors::kBlue,
715 SkColors::kCyan,
716 SkColors::kGreen,
717 SkColors::kYellow,
718 SkColors::kRed,
719 SkColors::kWhite,
720 };
721
722 static const float kStops[] = {
723 0.0f,
724 1.0f/6.0f,
725 2.0f/6.0f,
726 0.5f,
727 4.0f/6.0f,
728 5.0f/6.0f,
729 1.0f,
730 };
731 static_assert(std::size(kColors) == std::size(kStops));
732
733 float t = curLen / fExpectedLen;
734 if (t <= 0.0f) {
735 return kColors[0];
736 } else if (t >= 1.0f) {
737 return kColors[std::size(kColors)-1];
738 }
739
740 for (unsigned int i = 0; i < std::size(kColors)-1; ++i) {
741 if (kStops[i] <= t && t <= kStops[i+1]) {
742 t = (t - kStops[i]) / (kStops[i+1] - kStops[i]);
743 SkASSERT(0.0f <= t && t <= 1.0f);
744 return { kColors[i].fR * (1 - t) + kColors[i+1].fR * t,
745 kColors[i].fG * (1 - t) + kColors[i+1].fG * t,
746 kColors[i].fB * (1 - t) + kColors[i+1].fB * t,
747 kColors[i].fA * (1 - t) + kColors[i+1].fA * t };
748
749 }
750 }
751
752 return SkColors::kBlack;
753 }
754
ExtractPathsFromSKP(const char filepath[],std::function<PathSniffCallback> callback)755 void ExtractPathsFromSKP(const char filepath[], std::function<PathSniffCallback> callback) {
756 SkFILEStream stream(filepath);
757 if (!stream.isValid()) {
758 SkDebugf("ExtractPaths: invalid input file at \"%s\"\n", filepath);
759 return;
760 }
761
762 class PathSniffer : public SkCanvas {
763 public:
764 PathSniffer(std::function<PathSniffCallback> callback)
765 : SkCanvas(4096, 4096, nullptr)
766 , fPathSniffCallback(callback) {}
767 private:
768 void onDrawPath(const SkPath& path, const SkPaint& paint) override {
769 fPathSniffCallback(this->getTotalMatrix(), path, paint);
770 }
771 std::function<PathSniffCallback> fPathSniffCallback;
772 };
773
774 sk_sp<SkPicture> skp = SkPicture::MakeFromStream(&stream);
775 if (!skp) {
776 SkDebugf("ExtractPaths: couldn't load skp at \"%s\"\n", filepath);
777 return;
778 }
779 PathSniffer pathSniffer(callback);
780 skp->playback(&pathSniffer);
781 }
782
783 } // namespace ToolUtils
784