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 "sk_tool_utils.h"
9 #include "sk_tool_utils_flags.h"
10 
11 #include "Resources.h"
12 #include "SkBitmap.h"
13 #include "SkCanvas.h"
14 #include "SkCommonFlags.h"
15 #include "SkPoint3.h"
16 #include "SkShader.h"
17 #include "SkTestScalerContext.h"
18 #include "SkTextBlob.h"
19 
20 DEFINE_bool(portableFonts, false, "Use portable fonts");
21 
22 namespace sk_tool_utils {
23 
24 /* these are the default fonts chosen by Chrome for serif, sans-serif, and monospace */
25 static const char* gStandardFontNames[][3] = {
26     { "Times", "Helvetica", "Courier" }, // Mac
27     { "Times New Roman", "Helvetica", "Courier" }, // iOS
28     { "Times New Roman", "Arial", "Courier New" }, // Win
29     { "Times New Roman", "Arial", "Monospace" }, // Ubuntu
30     { "serif", "sans-serif", "monospace" }, // Android
31     { "Tinos", "Arimo", "Cousine" } // ChromeOS
32 };
33 
platform_font_name(const char * name)34 const char* platform_font_name(const char* name) {
35     SkString platform = major_platform_os_name();
36     int index;
37     if (!strcmp(name, "serif")) {
38         index = 0;
39     } else if (!strcmp(name, "san-serif")) {
40         index = 1;
41     } else if (!strcmp(name, "monospace")) {
42         index = 2;
43     } else {
44         return name;
45     }
46     if (platform.equals("Mac")) {
47         return gStandardFontNames[0][index];
48     }
49     if (platform.equals("iOS")) {
50         return gStandardFontNames[1][index];
51     }
52     if (platform.equals("Win")) {
53         return gStandardFontNames[2][index];
54     }
55     if (platform.equals("Ubuntu")) {
56         return gStandardFontNames[3][index];
57     }
58     if (platform.equals("Android")) {
59         return gStandardFontNames[4][index];
60     }
61     if (platform.equals("ChromeOS")) {
62         return gStandardFontNames[5][index];
63     }
64     return name;
65 }
66 
platform_os_emoji()67 const char* platform_os_emoji() {
68     const char* osName = platform_os_name();
69     if (!strcmp(osName, "Android") || !strcmp(osName, "Ubuntu")) {
70         return "CBDT";
71     }
72     if (!strncmp(osName, "Mac", 3)) {
73         return "SBIX";
74     }
75     return "";
76 }
77 
emoji_typeface(SkAutoTUnref<SkTypeface> * tf)78 void emoji_typeface(SkAutoTUnref<SkTypeface>* tf) {
79     if (!strcmp(sk_tool_utils::platform_os_emoji(), "CBDT")) {
80         tf->reset(GetResourceAsTypeface("/fonts/Funkster.ttf"));
81         return;
82     }
83     if (!strcmp(sk_tool_utils::platform_os_emoji(), "SBIX")) {
84         tf->reset(SkTypeface::CreateFromName("Apple Color Emoji", SkTypeface::kNormal));
85         return;
86     }
87     tf->reset(nullptr);
88     return;
89 }
90 
emoji_sample_text()91 const char* emoji_sample_text() {
92     if (!strcmp(sk_tool_utils::platform_os_emoji(), "CBDT")) {
93         return "Hamburgefons";
94     }
95     if (!strcmp(sk_tool_utils::platform_os_emoji(), "SBIX")) {
96         return "\xF0\x9F\x92\xB0" "\xF0\x9F\x8F\xA1" "\xF0\x9F\x8E\x85"  // ������
97                "\xF0\x9F\x8D\xAA" "\xF0\x9F\x8D\x95" "\xF0\x9F\x9A\x80"  // ������
98                "\xF0\x9F\x9A\xBB" "\xF0\x9F\x92\xA9" "\xF0\x9F\x93\xB7" // ������
99                "\xF0\x9F\x93\xA6" // ��
100                "\xF0\x9F\x87\xBA" "\xF0\x9F\x87\xB8" "\xF0\x9F\x87\xA6"; // ������
101     }
102     return "";
103 }
104 
platform_os_name()105 const char* platform_os_name() {
106     for (int index = 0; index < FLAGS_key.count(); index += 2) {
107         if (!strcmp("os", FLAGS_key[index])) {
108             return FLAGS_key[index + 1];
109         }
110     }
111     // when running SampleApp or dm without a --key pair, omit the platform name
112     return "";
113 }
114 
115 // omit version number in returned value
major_platform_os_name()116 SkString major_platform_os_name() {
117     SkString name;
118     for (int index = 0; index < FLAGS_key.count(); index += 2) {
119         if (!strcmp("os", FLAGS_key[index])) {
120             const char* platform = FLAGS_key[index + 1];
121             const char* end = platform;
122             while (*end && (*end < '0' || *end > '9')) {
123                 ++end;
124             }
125             name.append(platform, end - platform);
126             break;
127         }
128     }
129     return name;
130 }
131 
platform_extra_config(const char * config)132 const char* platform_extra_config(const char* config) {
133     for (int index = 0; index < FLAGS_key.count(); index += 2) {
134         if (!strcmp("extra_config", FLAGS_key[index]) && !strcmp(config, FLAGS_key[index + 1])) {
135             return config;
136         }
137     }
138     return "";
139 }
140 
colortype_name(SkColorType ct)141 const char* colortype_name(SkColorType ct) {
142     switch (ct) {
143         case kUnknown_SkColorType:      return "Unknown";
144         case kAlpha_8_SkColorType:      return "Alpha_8";
145         case kIndex_8_SkColorType:      return "Index_8";
146         case kARGB_4444_SkColorType:    return "ARGB_4444";
147         case kRGB_565_SkColorType:      return "RGB_565";
148         case kRGBA_8888_SkColorType:    return "RGBA_8888";
149         case kBGRA_8888_SkColorType:    return "BGRA_8888";
150         default:
151             SkASSERT(false);
152             return "unexpected colortype";
153     }
154 }
155 
color_to_565(SkColor color)156 SkColor color_to_565(SkColor color) {
157     SkPMColor pmColor = SkPreMultiplyColor(color);
158     U16CPU color16 = SkPixel32ToPixel16(pmColor);
159     return SkPixel16ToColor(color16);
160 }
161 
create_portable_typeface(const char * name,SkTypeface::Style style)162 SkTypeface* create_portable_typeface(const char* name, SkTypeface::Style style) {
163     return create_font(name, style);
164 }
165 
set_portable_typeface(SkPaint * paint,const char * name,SkTypeface::Style style)166 void set_portable_typeface(SkPaint* paint, const char* name, SkTypeface::Style style) {
167     SkTypeface* face = create_font(name, style);
168     SkSafeUnref(paint->setTypeface(face));
169 }
170 
write_pixels(SkCanvas * canvas,const SkBitmap & bitmap,int x,int y,SkColorType colorType,SkAlphaType alphaType)171 void write_pixels(SkCanvas* canvas, const SkBitmap& bitmap, int x, int y,
172                   SkColorType colorType, SkAlphaType alphaType) {
173     SkBitmap tmp(bitmap);
174     tmp.lockPixels();
175 
176     const SkImageInfo info = SkImageInfo::Make(tmp.width(), tmp.height(), colorType, alphaType);
177 
178     canvas->writePixels(info, tmp.getPixels(), tmp.rowBytes(), x, y);
179 }
180 
create_checkerboard_shader(SkColor c1,SkColor c2,int size)181 SkShader* create_checkerboard_shader(SkColor c1, SkColor c2, int size) {
182     SkBitmap bm;
183     bm.allocN32Pixels(2 * size, 2 * size);
184     bm.eraseColor(c1);
185     bm.eraseArea(SkIRect::MakeLTRB(0, 0, size, size), c2);
186     bm.eraseArea(SkIRect::MakeLTRB(size, size, 2 * size, 2 * size), c2);
187     return SkShader::CreateBitmapShader(
188             bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode);
189 }
190 
create_checkerboard_bitmap(int w,int h,SkColor c1,SkColor c2,int checkSize)191 SkBitmap create_checkerboard_bitmap(int w, int h, SkColor c1, SkColor c2, int checkSize) {
192     SkBitmap bitmap;
193     bitmap.allocN32Pixels(w, h);
194     SkCanvas canvas(bitmap);
195 
196     sk_tool_utils::draw_checkerboard(&canvas, c1, c2, checkSize);
197     return bitmap;
198 }
199 
draw_checkerboard(SkCanvas * canvas,SkColor c1,SkColor c2,int size)200 void draw_checkerboard(SkCanvas* canvas, SkColor c1, SkColor c2, int size) {
201     SkPaint paint;
202     paint.setShader(create_checkerboard_shader(c1, c2, size))->unref();
203     paint.setXfermodeMode(SkXfermode::kSrc_Mode);
204     canvas->drawPaint(paint);
205 }
206 
create_string_bitmap(int w,int h,SkColor c,int x,int y,int textSize,const char * str)207 SkBitmap create_string_bitmap(int w, int h, SkColor c, int x, int y,
208                               int textSize, const char* str) {
209     SkBitmap bitmap;
210     bitmap.allocN32Pixels(w, h);
211     SkCanvas canvas(bitmap);
212 
213     SkPaint paint;
214     paint.setAntiAlias(true);
215     sk_tool_utils::set_portable_typeface(&paint);
216     paint.setColor(c);
217     paint.setTextSize(SkIntToScalar(textSize));
218 
219     canvas.clear(0x00000000);
220     canvas.drawText(str, strlen(str), SkIntToScalar(x), SkIntToScalar(y), paint);
221 
222     return bitmap;
223 }
224 
add_to_text_blob(SkTextBlobBuilder * builder,const char * text,const SkPaint & origPaint,SkScalar x,SkScalar y)225 void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkPaint& origPaint,
226                       SkScalar x, SkScalar y) {
227     SkPaint paint(origPaint);
228     SkTDArray<uint16_t> glyphs;
229 
230     size_t len = strlen(text);
231     glyphs.append(paint.textToGlyphs(text, len, nullptr));
232     paint.textToGlyphs(text, len, glyphs.begin());
233 
234     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
235     const SkTextBlobBuilder::RunBuffer& run = builder->allocRun(paint, glyphs.count(), x, y,
236                                                                 nullptr);
237     memcpy(run.glyphs, glyphs.begin(), glyphs.count() * sizeof(uint16_t));
238 }
239 
norm_to_rgb(SkBitmap * bm,int x,int y,const SkVector3 & norm)240 static inline void norm_to_rgb(SkBitmap* bm, int x, int y, const SkVector3& norm) {
241     SkASSERT(SkScalarNearlyEqual(norm.length(), 1.0f));
242     unsigned char r = static_cast<unsigned char>((0.5f * norm.fX + 0.5f) * 255);
243     unsigned char g = static_cast<unsigned char>((-0.5f * norm.fY + 0.5f) * 255);
244     unsigned char b = static_cast<unsigned char>((0.5f * norm.fZ + 0.5f) * 255);
245     *bm->getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
246 }
247 
create_hemi_normal_map(SkBitmap * bm,const SkIRect & dst)248 void create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst) {
249     const SkPoint center = SkPoint::Make(dst.fLeft + (dst.width() / 2.0f),
250                                          dst.fTop + (dst.height() / 2.0f));
251     const SkPoint halfSize = SkPoint::Make(dst.width() / 2.0f, dst.height() / 2.0f);
252 
253     SkVector3 norm;
254 
255     for (int y = dst.fTop; y < dst.fBottom; ++y) {
256         for (int x = dst.fLeft; x < dst.fRight; ++x) {
257             norm.fX = (x + 0.5f - center.fX) / halfSize.fX;
258             norm.fY = (y + 0.5f - center.fY) / halfSize.fY;
259 
260             SkScalar tmp = norm.fX * norm.fX + norm.fY * norm.fY;
261             if (tmp >= 1.0f) {
262                 norm.set(0.0f, 0.0f, 1.0f);
263             } else {
264                 norm.fZ = sqrtf(1.0f - tmp);
265             }
266 
267             norm_to_rgb(bm, x, y, norm);
268         }
269     }
270 }
271 
create_frustum_normal_map(SkBitmap * bm,const SkIRect & dst)272 void create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst) {
273     const SkPoint center = SkPoint::Make(dst.fLeft + (dst.width() / 2.0f),
274                                          dst.fTop + (dst.height() / 2.0f));
275 
276     SkIRect inner = dst;
277     inner.inset(dst.width()/4, dst.height()/4);
278 
279     SkPoint3 norm;
280     const SkPoint3 left =  SkPoint3::Make(-SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2);
281     const SkPoint3 up =    SkPoint3::Make(0.0f, -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
282     const SkPoint3 right = SkPoint3::Make(SK_ScalarRoot2Over2,  0.0f, SK_ScalarRoot2Over2);
283     const SkPoint3 down =  SkPoint3::Make(0.0f,  SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
284 
285     for (int y = dst.fTop; y < dst.fBottom; ++y) {
286         for (int x = dst.fLeft; x < dst.fRight; ++x) {
287             if (inner.contains(x, y)) {
288                 norm.set(0.0f, 0.0f, 1.0f);
289             } else {
290                 SkScalar locX = x + 0.5f - center.fX;
291                 SkScalar locY = y + 0.5f - center.fY;
292 
293                 if (locX >= 0.0f) {
294                     if (locY > 0.0f) {
295                         norm = locX >= locY ? right : down;   // LR corner
296                     } else {
297                         norm = locX > -locY ? right : up;     // UR corner
298                     }
299                 } else {
300                     if (locY > 0.0f) {
301                         norm = -locX > locY ? left : down;    // LL corner
302                     } else {
303                         norm = locX > locY ? up : left;       // UL corner
304                     }
305                 }
306             }
307 
308             norm_to_rgb(bm, x, y, norm);
309         }
310     }
311 }
312 
create_tetra_normal_map(SkBitmap * bm,const SkIRect & dst)313 void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst) {
314     const SkPoint center = SkPoint::Make(dst.fLeft + (dst.width() / 2.0f),
315                                          dst.fTop + (dst.height() / 2.0f));
316 
317     static const SkScalar k1OverRoot3 = 0.5773502692f;
318 
319     SkPoint3 norm;
320     const SkPoint3 leftUp =  SkPoint3::Make(-k1OverRoot3, -k1OverRoot3, k1OverRoot3);
321     const SkPoint3 rightUp = SkPoint3::Make(k1OverRoot3,  -k1OverRoot3, k1OverRoot3);
322     const SkPoint3 down =  SkPoint3::Make(0.0f,  SK_ScalarRoot2Over2, SK_ScalarRoot2Over2);
323 
324     for (int y = dst.fTop; y < dst.fBottom; ++y) {
325         for (int x = dst.fLeft; x < dst.fRight; ++x) {
326             SkScalar locX = x + 0.5f - center.fX;
327             SkScalar locY = y + 0.5f - center.fY;
328 
329             if (locX >= 0.0f) {
330                 if (locY > 0.0f) {
331                     norm = locX >= locY ? rightUp : down;   // LR corner
332                 } else {
333                     norm = rightUp;
334                 }
335             } else {
336                 if (locY > 0.0f) {
337                     norm = -locX > locY ? leftUp : down;    // LL corner
338                 } else {
339                     norm = leftUp;
340                 }
341             }
342 
343             norm_to_rgb(bm, x, y, norm);
344         }
345     }
346 }
347 
make_big_path(SkPath & path)348 void make_big_path(SkPath& path) {
349     #include "BigPathBench.inc"
350 }
351 
gaussian2d_value(int x,int y,float sigma)352 static float gaussian2d_value(int x, int y, float sigma) {
353     // don't bother with the scale term since we're just going to normalize the
354     // kernel anyways
355     float temp = expf(-(x*x + y*y)/(2*sigma*sigma));
356     return temp;
357 }
358 
create_2d_kernel(float sigma,int * filterSize)359 static float* create_2d_kernel(float sigma, int* filterSize) {
360     // We will actually take 2*halfFilterSize+1 samples (i.e., our filter kernel
361     // sizes are always odd)
362     int halfFilterSize = SkScalarCeilToInt(6*sigma)/2;
363     int wh = *filterSize = 2*halfFilterSize + 1;
364 
365     float* temp = new float[wh*wh];
366 
367     float filterTot = 0.0f;
368     for (int yOff = 0; yOff < wh; ++yOff) {
369         for (int xOff = 0; xOff < wh; ++xOff) {
370             temp[yOff*wh+xOff] = gaussian2d_value(xOff-halfFilterSize, yOff-halfFilterSize, sigma);
371 
372             filterTot += temp[yOff*wh+xOff];
373         }
374     }
375 
376     // normalize the kernel
377     for (int yOff = 0; yOff < wh; ++yOff) {
378         for (int xOff = 0; xOff < wh; ++xOff) {
379             temp[yOff*wh+xOff] /= filterTot;
380         }
381     }
382 
383     return temp;
384 }
385 
blur_pixel(const SkBitmap & bm,int x,int y,float * kernel,int wh)386 static SkPMColor blur_pixel(const SkBitmap& bm, int x, int y, float* kernel, int wh) {
387     SkASSERT(wh & 0x1);
388 
389     int halfFilterSize = (wh-1)/2;
390 
391     float r = 0.0f, g = 0.0f, b = 0.0f;
392     for (int yOff = 0; yOff < wh; ++yOff) {
393         int ySamp = y + yOff - halfFilterSize;
394 
395         if (ySamp < 0) {
396             ySamp = 0;
397         } else if (ySamp > bm.height()-1) {
398             ySamp = bm.height()-1;
399         }
400 
401         for (int xOff = 0; xOff < wh; ++xOff) {
402             int xSamp = x + xOff - halfFilterSize;
403 
404             if (xSamp < 0) {
405                 xSamp = 0;
406             } else if (xSamp > bm.width()-1) {
407                 xSamp = bm.width()-1;
408             }
409 
410             float filter = kernel[yOff*wh + xOff];
411 
412             SkPMColor c = *bm.getAddr32(xSamp, ySamp);
413 
414             r += SkGetPackedR32(c) * filter;
415             g += SkGetPackedG32(c) * filter;
416             b += SkGetPackedB32(c) * filter;
417         }
418     }
419 
420     U8CPU r8, g8, b8;
421 
422     r8 = (U8CPU) (r+0.5f);
423     g8 = (U8CPU) (g+0.5f);
424     b8 = (U8CPU) (b+0.5f);
425 
426     return SkPackARGB32(255, r8, g8, b8);
427 }
428 
slow_blur(const SkBitmap & src,float sigma)429 SkBitmap slow_blur(const SkBitmap& src, float sigma) {
430     SkBitmap dst;
431 
432     dst.allocN32Pixels(src.width(), src.height(), true);
433 
434     int wh;
435     SkAutoTDeleteArray<float> kernel(create_2d_kernel(sigma, &wh));
436 
437     for (int y = 0; y < src.height(); ++y) {
438         for (int x = 0; x < src.width(); ++x) {
439             *dst.getAddr32(x, y) = blur_pixel(src, x, y, kernel.get(), wh);
440         }
441     }
442 
443     return dst;
444 }
445 
446 }  // namespace sk_tool_utils
447