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