• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "include/core/SkBitmap.h"
9 #include "include/core/SkBlendMode.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColorPriv.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPathBuilder.h"
16 #include "include/core/SkPicture.h"
17 #include "include/core/SkPixelRef.h"
18 #include "include/core/SkPixmap.h"
19 #include "include/core/SkPoint3.h"
20 #include "include/core/SkRRect.h"
21 #include "include/core/SkShader.h"
22 #include "include/core/SkSurface.h"
23 #include "include/core/SkTextBlob.h"
24 #include "include/ports/SkTypeface_win.h"
25 #include "include/private/SkColorData.h"
26 #include "include/private/SkFloatingPoint.h"
27 #include "src/core/SkFontPriv.h"
28 #include "tools/ToolUtils.h"
29 
30 #include <cmath>
31 #include <cstring>
32 
33 #if defined(SK_ENABLE_SVG)
34 #include "modules/svg/include/SkSVGDOM.h"
35 #include "modules/svg/include/SkSVGNode.h"
36 #include "src/xml/SkDOM.h"
37 #endif
38 
39 namespace ToolUtils {
40 
alphatype_name(SkAlphaType at)41 const char* alphatype_name(SkAlphaType at) {
42     switch (at) {
43         case kUnknown_SkAlphaType:  return "Unknown";
44         case kOpaque_SkAlphaType:   return "Opaque";
45         case kPremul_SkAlphaType:   return "Premul";
46         case kUnpremul_SkAlphaType: return "Unpremul";
47     }
48     SkASSERT(false);
49     return "unexpected alphatype";
50 }
51 
colortype_name(SkColorType ct)52 const char* colortype_name(SkColorType ct) {
53     switch (ct) {
54         case kUnknown_SkColorType:            return "Unknown";
55         case kAlpha_8_SkColorType:            return "Alpha_8";
56         case kA16_unorm_SkColorType:          return "Alpha_16";
57         case kA16_float_SkColorType:          return "A16_float";
58         case kRGB_565_SkColorType:            return "RGB_565";
59         case kARGB_4444_SkColorType:          return "ARGB_4444";
60         case kRGBA_8888_SkColorType:          return "RGBA_8888";
61         case kSRGBA_8888_SkColorType:         return "SRGBA_8888";
62         case kRGB_888x_SkColorType:           return "RGB_888x";
63         case kBGRA_8888_SkColorType:          return "BGRA_8888";
64         case kRGBA_1010102_SkColorType:       return "RGBA_1010102";
65         case kBGRA_1010102_SkColorType:       return "BGRA_1010102";
66         case kRGB_101010x_SkColorType:        return "RGB_101010x";
67         case kBGR_101010x_SkColorType:        return "BGR_101010x";
68         case kGray_8_SkColorType:             return "Gray_8";
69         case kRGBA_F16Norm_SkColorType:       return "RGBA_F16Norm";
70         case kRGBA_F16_SkColorType:           return "RGBA_F16";
71         case kRGBA_F32_SkColorType:           return "RGBA_F32";
72         case kR8G8_unorm_SkColorType:         return "R8G8_unorm";
73         case kR16G16_unorm_SkColorType:       return "R16G16_unorm";
74         case kR16G16_float_SkColorType:       return "R16G16_float";
75         case kR16G16B16A16_unorm_SkColorType: return "R16G16B16A16_unorm";
76         case kR8_unorm_SkColorType:           return "R8_unorm";
77     }
78     SkASSERT(false);
79     return "unexpected colortype";
80 }
81 
colortype_depth(SkColorType ct)82 const char* colortype_depth(SkColorType ct) {
83     switch (ct) {
84         case kUnknown_SkColorType:            return "Unknown";
85         case kAlpha_8_SkColorType:            return "A8";
86         case kA16_unorm_SkColorType:          return "A16";
87         case kA16_float_SkColorType:          return "AF16";
88         case kRGB_565_SkColorType:            return "565";
89         case kARGB_4444_SkColorType:          return "4444";
90         case kRGBA_8888_SkColorType:          return "8888";
91         case kSRGBA_8888_SkColorType:         return "8888";
92         case kRGB_888x_SkColorType:           return "888";
93         case kBGRA_8888_SkColorType:          return "8888";
94         case kRGBA_1010102_SkColorType:       return "1010102";
95         case kBGRA_1010102_SkColorType:       return "1010102";
96         case kRGB_101010x_SkColorType:        return "101010";
97         case kBGR_101010x_SkColorType:        return "101010";
98         case kGray_8_SkColorType:             return "G8";
99         case kRGBA_F16Norm_SkColorType:       return "F16Norm";  // TODO: "F16"?
100         case kRGBA_F16_SkColorType:           return "F16";
101         case kRGBA_F32_SkColorType:           return "F32";
102         case kR8G8_unorm_SkColorType:         return "88";
103         case kR16G16_unorm_SkColorType:       return "1616";
104         case kR16G16_float_SkColorType:       return "F16F16";
105         case kR16G16B16A16_unorm_SkColorType: return "16161616";
106         case kR8_unorm_SkColorType:           return "8";
107     }
108     SkASSERT(false);
109     return "unexpected colortype";
110 }
111 
tilemode_name(SkTileMode mode)112 const char* tilemode_name(SkTileMode mode) {
113     switch (mode) {
114         case SkTileMode::kClamp:  return "clamp";
115         case SkTileMode::kRepeat: return "repeat";
116         case SkTileMode::kMirror: return "mirror";
117         case SkTileMode::kDecal:  return "decal";
118     }
119     SkASSERT(false);
120     return "unexpected tilemode";
121 }
122 
color_to_565(SkColor color)123 SkColor color_to_565(SkColor color) {
124     // Not a good idea to use this function for greyscale colors...
125     // it will add an obvious purple or green tint.
126     SkASSERT(SkColorGetR(color) != SkColorGetG(color) || SkColorGetR(color) != SkColorGetB(color) ||
127              SkColorGetG(color) != SkColorGetB(color));
128 
129     SkPMColor pmColor = SkPreMultiplyColor(color);
130     U16CPU    color16 = SkPixel32ToPixel16(pmColor);
131     return SkPixel16ToColor(color16);
132 }
133 
create_checkerboard_shader(SkColor c1,SkColor c2,int size)134 sk_sp<SkShader> create_checkerboard_shader(SkColor c1, SkColor c2, int size) {
135     SkBitmap bm;
136     bm.allocPixels(SkImageInfo::MakeS32(2 * size, 2 * size, kPremul_SkAlphaType));
137     bm.eraseColor(c1);
138     bm.eraseArea(SkIRect::MakeLTRB(0, 0, size, size), c2);
139     bm.eraseArea(SkIRect::MakeLTRB(size, size, 2 * size, 2 * size), c2);
140     return bm.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions());
141 }
142 
create_checkerboard_bitmap(int w,int h,SkColor c1,SkColor c2,int checkSize)143 SkBitmap create_checkerboard_bitmap(int w, int h, SkColor c1, SkColor c2, int checkSize) {
144     SkBitmap bitmap;
145     bitmap.allocPixels(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType));
146     SkCanvas canvas(bitmap);
147 
148     ToolUtils::draw_checkerboard(&canvas, c1, c2, checkSize);
149     return bitmap;
150 }
151 
create_checkerboard_image(int w,int h,SkColor c1,SkColor c2,int checkSize)152 sk_sp<SkImage> create_checkerboard_image(int w, int h, SkColor c1, SkColor c2, int checkSize) {
153     auto surf = SkSurface::MakeRasterN32Premul(w, h);
154     ToolUtils::draw_checkerboard(surf->getCanvas(), c1, c2, checkSize);
155     return surf->makeImageSnapshot();
156 }
157 
draw_checkerboard(SkCanvas * canvas,SkColor c1,SkColor c2,int size)158 void draw_checkerboard(SkCanvas* canvas, SkColor c1, SkColor c2, int size) {
159     SkPaint paint;
160     paint.setShader(create_checkerboard_shader(c1, c2, size));
161     paint.setBlendMode(SkBlendMode::kSrc);
162     canvas->drawPaint(paint);
163 }
164 
165 SkBitmap
create_string_bitmap(int w,int h,SkColor c,int x,int y,int textSize,const char * str)166 create_string_bitmap(int w, int h, SkColor c, int x, int y, int textSize, const char* str) {
167     SkBitmap bitmap;
168     bitmap.allocN32Pixels(w, h);
169     SkCanvas canvas(bitmap);
170 
171     SkPaint paint;
172     paint.setColor(c);
173 
174     SkFont font(ToolUtils::create_portable_typeface(), textSize);
175 
176     canvas.clear(0x00000000);
177     canvas.drawSimpleText(str,
178                           strlen(str),
179                           SkTextEncoding::kUTF8,
180                           SkIntToScalar(x),
181                           SkIntToScalar(y),
182                           font,
183                           paint);
184 
185     // Tag data as sRGB (without doing any color space conversion). Color-space aware configs
186     // will process this correctly but legacy configs will render as if this returned N32.
187     SkBitmap result;
188     result.setInfo(SkImageInfo::MakeS32(w, h, kPremul_SkAlphaType));
189     result.setPixelRef(sk_ref_sp(bitmap.pixelRef()), 0, 0);
190     return result;
191 }
192 
create_string_image(int w,int h,SkColor c,int x,int y,int textSize,const char * str)193 sk_sp<SkImage> create_string_image(int w, int h, SkColor c, int x, int y, int textSize,
194                                    const char* str) {
195     return create_string_bitmap(w, h, c, x, y, textSize, str).asImage();
196 }
197 
add_to_text_blob_w_len(SkTextBlobBuilder * builder,const char * text,size_t len,SkTextEncoding encoding,const SkFont & font,SkScalar x,SkScalar y)198 void add_to_text_blob_w_len(SkTextBlobBuilder* builder,
199                             const char*        text,
200                             size_t             len,
201                             SkTextEncoding     encoding,
202                             const SkFont&      font,
203                             SkScalar           x,
204                             SkScalar           y) {
205     int  count = font.countText(text, len, encoding);
206     if (count < 1) {
207         return;
208     }
209     auto run   = builder->allocRun(font, count, x, y);
210     font.textToGlyphs(text, len, encoding, run.glyphs, count);
211 }
212 
add_to_text_blob(SkTextBlobBuilder * builder,const char * text,const SkFont & font,SkScalar x,SkScalar y)213 void add_to_text_blob(SkTextBlobBuilder* builder,
214                       const char*        text,
215                       const SkFont&      font,
216                       SkScalar           x,
217                       SkScalar           y) {
218     add_to_text_blob_w_len(builder, text, strlen(text), SkTextEncoding::kUTF8, font, x, y);
219 }
220 
get_text_path(const SkFont & font,const void * text,size_t length,SkTextEncoding encoding,SkPath * dst,const SkPoint pos[])221 void get_text_path(const SkFont&  font,
222                    const void*    text,
223                    size_t         length,
224                    SkTextEncoding encoding,
225                    SkPath*        dst,
226                    const SkPoint  pos[]) {
227     SkAutoToGlyphs        atg(font, text, length, encoding);
228     const int             count = atg.count();
229     SkAutoTArray<SkPoint> computedPos;
230     if (pos == nullptr) {
231         computedPos.reset(count);
232         font.getPos(atg.glyphs(), count, &computedPos[0]);
233         pos = computedPos.get();
234     }
235 
236     struct Rec {
237         SkPath*        fDst;
238         const SkPoint* fPos;
239     } rec = {dst, pos};
240     font.getPaths(atg.glyphs(),
241                   atg.count(),
242                   [](const SkPath* src, const SkMatrix& mx, void* ctx) {
243                       Rec* rec = (Rec*)ctx;
244                       if (src) {
245                           SkMatrix tmp(mx);
246                           tmp.postTranslate(rec->fPos->fX, rec->fPos->fY);
247                           rec->fDst->addPath(*src, tmp);
248                       }
249                       rec->fPos += 1;
250                   },
251                   &rec);
252 }
253 
make_star(const SkRect & bounds,int numPts,int step)254 SkPath make_star(const SkRect& bounds, int numPts, int step) {
255     SkASSERT(numPts != step);
256     SkPathBuilder builder;
257     builder.setFillType(SkPathFillType::kEvenOdd);
258     builder.moveTo(0, -1);
259     for (int i = 1; i < numPts; ++i) {
260         int      idx   = i * step % numPts;
261         SkScalar theta = idx * 2 * SK_ScalarPI / numPts + SK_ScalarPI / 2;
262         SkScalar x     = SkScalarCos(theta);
263         SkScalar y     = -SkScalarSin(theta);
264         builder.lineTo(x, y);
265     }
266     SkPath path = builder.detach();
267     path.transform(SkMatrix::RectToRect(path.getBounds(), bounds));
268     return path;
269 }
270 
norm_to_rgb(SkBitmap * bm,int x,int y,const SkVector3 & norm)271 static inline void norm_to_rgb(SkBitmap* bm, int x, int y, const SkVector3& norm) {
272     SkASSERT(SkScalarNearlyEqual(norm.length(), 1.0f));
273     unsigned char r      = static_cast<unsigned char>((0.5f * norm.fX + 0.5f) * 255);
274     unsigned char g      = static_cast<unsigned char>((-0.5f * norm.fY + 0.5f) * 255);
275     unsigned char b      = static_cast<unsigned char>((0.5f * norm.fZ + 0.5f) * 255);
276     *bm->getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
277 }
278 
create_hemi_normal_map(SkBitmap * bm,const SkIRect & dst)279 void create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst) {
280     const SkPoint center =
281             SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), dst.fTop + (dst.height() / 2.0f));
282     const SkPoint halfSize = SkPoint::Make(dst.width() / 2.0f, dst.height() / 2.0f);
283 
284     SkVector3 norm;
285 
286     for (int y = dst.fTop; y < dst.fBottom; ++y) {
287         for (int x = dst.fLeft; x < dst.fRight; ++x) {
288             norm.fX = (x + 0.5f - center.fX) / halfSize.fX;
289             norm.fY = (y + 0.5f - center.fY) / halfSize.fY;
290 
291             SkScalar tmp = norm.fX * norm.fX + norm.fY * norm.fY;
292             if (tmp >= 1.0f) {
293                 norm.set(0.0f, 0.0f, 1.0f);
294             } else {
295                 norm.fZ = sqrtf(1.0f - tmp);
296             }
297 
298             norm_to_rgb(bm, x, y, norm);
299         }
300     }
301 }
302 
create_frustum_normal_map(SkBitmap * bm,const SkIRect & dst)303 void create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst) {
304     const SkPoint center =
305             SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), dst.fTop + (dst.height() / 2.0f));
306 
307     SkIRect inner = dst;
308     inner.inset(dst.width() / 4, dst.height() / 4);
309 
310     SkPoint3       norm;
311     const SkPoint3 left  = SkPoint3::Make(-SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2);
312     const SkPoint3 up    = SkPoint3::Make(0.0f, -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
313     const SkPoint3 right = SkPoint3::Make(SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2);
314     const SkPoint3 down  = SkPoint3::Make(0.0f, SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
315 
316     for (int y = dst.fTop; y < dst.fBottom; ++y) {
317         for (int x = dst.fLeft; x < dst.fRight; ++x) {
318             if (inner.contains(x, y)) {
319                 norm.set(0.0f, 0.0f, 1.0f);
320             } else {
321                 SkScalar locX = x + 0.5f - center.fX;
322                 SkScalar locY = y + 0.5f - center.fY;
323 
324                 if (locX >= 0.0f) {
325                     if (locY > 0.0f) {
326                         norm = locX >= locY ? right : down;  // LR corner
327                     } else {
328                         norm = locX > -locY ? right : up;  // UR corner
329                     }
330                 } else {
331                     if (locY > 0.0f) {
332                         norm = -locX > locY ? left : down;  // LL corner
333                     } else {
334                         norm = locX > locY ? up : left;  // UL corner
335                     }
336                 }
337             }
338 
339             norm_to_rgb(bm, x, y, norm);
340         }
341     }
342 }
343 
create_tetra_normal_map(SkBitmap * bm,const SkIRect & dst)344 void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst) {
345     const SkPoint center =
346             SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), dst.fTop + (dst.height() / 2.0f));
347 
348     static const SkScalar k1OverRoot3 = 0.5773502692f;
349 
350     SkPoint3       norm;
351     const SkPoint3 leftUp  = SkPoint3::Make(-k1OverRoot3, -k1OverRoot3, k1OverRoot3);
352     const SkPoint3 rightUp = SkPoint3::Make(k1OverRoot3, -k1OverRoot3, k1OverRoot3);
353     const SkPoint3 down    = SkPoint3::Make(0.0f, SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
354 
355     for (int y = dst.fTop; y < dst.fBottom; ++y) {
356         for (int x = dst.fLeft; x < dst.fRight; ++x) {
357             SkScalar locX = x + 0.5f - center.fX;
358             SkScalar locY = y + 0.5f - center.fY;
359 
360             if (locX >= 0.0f) {
361                 if (locY > 0.0f) {
362                     norm = locX >= locY ? rightUp : down;  // LR corner
363                 } else {
364                     norm = rightUp;
365                 }
366             } else {
367                 if (locY > 0.0f) {
368                     norm = -locX > locY ? leftUp : down;  // LL corner
369                 } else {
370                     norm = leftUp;
371                 }
372             }
373 
374             norm_to_rgb(bm, x, y, norm);
375         }
376     }
377 }
378 
copy_to(SkBitmap * dst,SkColorType dstColorType,const SkBitmap & src)379 bool copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) {
380     SkPixmap srcPM;
381     if (!src.peekPixels(&srcPM)) {
382         return false;
383     }
384 
385     SkBitmap    tmpDst;
386     SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType);
387     if (!tmpDst.setInfo(dstInfo)) {
388         return false;
389     }
390 
391     if (!tmpDst.tryAllocPixels()) {
392         return false;
393     }
394 
395     SkPixmap dstPM;
396     if (!tmpDst.peekPixels(&dstPM)) {
397         return false;
398     }
399 
400     if (!srcPM.readPixels(dstPM)) {
401         return false;
402     }
403 
404     dst->swap(tmpDst);
405     return true;
406 }
407 
copy_to_g8(SkBitmap * dst,const SkBitmap & src)408 void copy_to_g8(SkBitmap* dst, const SkBitmap& src) {
409     SkASSERT(kBGRA_8888_SkColorType == src.colorType() ||
410              kRGBA_8888_SkColorType == src.colorType());
411 
412     SkImageInfo grayInfo = src.info().makeColorType(kGray_8_SkColorType);
413     dst->allocPixels(grayInfo);
414     uint8_t*        dst8  = (uint8_t*)dst->getPixels();
415     const uint32_t* src32 = (const uint32_t*)src.getPixels();
416 
417     const int  w      = src.width();
418     const int  h      = src.height();
419     const bool isBGRA = (kBGRA_8888_SkColorType == src.colorType());
420     for (int y = 0; y < h; ++y) {
421         if (isBGRA) {
422             // BGRA
423             for (int x = 0; x < w; ++x) {
424                 uint32_t s = src32[x];
425                 dst8[x]    = SkComputeLuminance((s >> 16) & 0xFF, (s >> 8) & 0xFF, s & 0xFF);
426             }
427         } else {
428             // RGBA
429             for (int x = 0; x < w; ++x) {
430                 uint32_t s = src32[x];
431                 dst8[x]    = SkComputeLuminance(s & 0xFF, (s >> 8) & 0xFF, (s >> 16) & 0xFF);
432             }
433         }
434         src32 = (const uint32_t*)((const char*)src32 + src.rowBytes());
435         dst8 += dst->rowBytes();
436     }
437 }
438 
439 //////////////////////////////////////////////////////////////////////////////////////////////
440 
equal_pixels(const SkPixmap & a,const SkPixmap & b)441 bool equal_pixels(const SkPixmap& a, const SkPixmap& b) {
442     if (a.width() != b.width() || a.height() != b.height() || a.colorType() != b.colorType()) {
443         return false;
444     }
445 
446     for (int y = 0; y < a.height(); ++y) {
447         const char* aptr = (const char*)a.addr(0, y);
448         const char* bptr = (const char*)b.addr(0, y);
449         if (0 != memcmp(aptr, bptr, a.width() * a.info().bytesPerPixel())) {
450             return false;
451         }
452     }
453     return true;
454 }
455 
equal_pixels(const SkBitmap & bm0,const SkBitmap & bm1)456 bool equal_pixels(const SkBitmap& bm0, const SkBitmap& bm1) {
457     SkPixmap pm0, pm1;
458     return bm0.peekPixels(&pm0) && bm1.peekPixels(&pm1) && equal_pixels(pm0, pm1);
459 }
460 
equal_pixels(const SkImage * a,const SkImage * b)461 bool equal_pixels(const SkImage* a, const SkImage* b) {
462     // ensure that peekPixels will succeed
463     auto imga = a->makeRasterImage();
464     auto imgb = b->makeRasterImage();
465 
466     SkPixmap pm0, pm1;
467     return imga->peekPixels(&pm0) && imgb->peekPixels(&pm1) && equal_pixels(pm0, pm1);
468 }
469 
makeSurface(SkCanvas * canvas,const SkImageInfo & info,const SkSurfaceProps * props)470 sk_sp<SkSurface> makeSurface(SkCanvas*             canvas,
471                              const SkImageInfo&    info,
472                              const SkSurfaceProps* props) {
473     auto surf = canvas->makeSurface(info, props);
474     if (!surf) {
475         surf = SkSurface::MakeRaster(info, props);
476     }
477     return surf;
478 }
479 
sniff_paths(const char filepath[],std::function<PathSniffCallback> callback)480 void sniff_paths(const char filepath[], std::function<PathSniffCallback> callback) {
481     SkFILEStream stream(filepath);
482     if (!stream.isValid()) {
483         SkDebugf("sniff_paths: invalid input file at \"%s\"\n", filepath);
484         return;
485     }
486 
487     class PathSniffer : public SkCanvas {
488     public:
489         PathSniffer(std::function<PathSniffCallback> callback)
490                 : SkCanvas(4096, 4096, nullptr)
491                 , fPathSniffCallback(callback) {}
492     private:
493         void onDrawPath(const SkPath& path, const SkPaint& paint) override {
494             fPathSniffCallback(this->getTotalMatrix(), path, paint);
495         }
496         std::function<PathSniffCallback> fPathSniffCallback;
497     };
498 
499     PathSniffer pathSniffer(callback);
500     if (const char* ext = strrchr(filepath, '.'); ext && !strcmp(ext, ".svg")) {
501 #if defined(SK_ENABLE_SVG)
502         sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromStream(stream);
503         if (!svg) {
504             SkDebugf("sniff_paths: couldn't load svg at \"%s\"\n", filepath);
505             return;
506         }
507         svg->setContainerSize(SkSize::Make(pathSniffer.getBaseLayerSize()));
508         svg->render(&pathSniffer);
509 #endif
510     } else {
511         sk_sp<SkPicture> skp = SkPicture::MakeFromStream(&stream);
512         if (!skp) {
513             SkDebugf("sniff_paths: couldn't load skp at \"%s\"\n", filepath);
514             return;
515         }
516         skp->playback(&pathSniffer);
517     }
518 }
519 
520 }  // namespace ToolUtils
521