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