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