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