1c3dcb67f07173af1c17771965ab7254910d52ef3caryclark/* 22010891425f10257363ae6eb0da70453746dc087tfarina * Copyright 2014 Google Inc. 32010891425f10257363ae6eb0da70453746dc087tfarina * 42010891425f10257363ae6eb0da70453746dc087tfarina * Use of this source code is governed by a BSD-style license that can be 52010891425f10257363ae6eb0da70453746dc087tfarina * found in the LICENSE file. 62010891425f10257363ae6eb0da70453746dc087tfarina */ 72010891425f10257363ae6eb0da70453746dc087tfarina 84cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org#include "sk_tool_utils.h" 9992c7b03ef7914a18bfd78e965b0b4c99a5f5672Cary Clark#include "sk_tool_utils_flags.h" 104cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org 11c3dcb67f07173af1c17771965ab7254910d52ef3caryclark#include "Resources.h" 122010891425f10257363ae6eb0da70453746dc087tfarina#include "SkBitmap.h" 132010891425f10257363ae6eb0da70453746dc087tfarina#include "SkCanvas.h" 146531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark#include "SkCommonFlags.h" 152880df2609eba09b555ca37be04b6ad89290c765Tom Hudson#include "SkPoint3.h" 16b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary#include "SkShader.h" 17992c7b03ef7914a18bfd78e965b0b4c99a5f5672Cary Clark#include "SkTestScalerContext.h" 189e36c1a9306f052331550dab4728b9875127bfb5joshualitt#include "SkTextBlob.h" 192010891425f10257363ae6eb0da70453746dc087tfarina 20992c7b03ef7914a18bfd78e965b0b4c99a5f5672Cary ClarkDEFINE_bool(portableFonts, false, "Use portable fonts"); 214cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org 22992c7b03ef7914a18bfd78e965b0b4c99a5f5672Cary Clarknamespace sk_tool_utils { 235fb6bd4b7e8d00b7f2543ca10ec9022b32632f29caryclark 242880df2609eba09b555ca37be04b6ad89290c765Tom Hudson/* these are the default fonts chosen by Chrome for serif, sans-serif, and monospace */ 252880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonstatic const char* gStandardFontNames[][3] = { 262880df2609eba09b555ca37be04b6ad89290c765Tom Hudson { "Times", "Helvetica", "Courier" }, // Mac 272880df2609eba09b555ca37be04b6ad89290c765Tom Hudson { "Times New Roman", "Helvetica", "Courier" }, // iOS 282880df2609eba09b555ca37be04b6ad89290c765Tom Hudson { "Times New Roman", "Arial", "Courier New" }, // Win 292880df2609eba09b555ca37be04b6ad89290c765Tom Hudson { "Times New Roman", "Arial", "Monospace" }, // Ubuntu 302880df2609eba09b555ca37be04b6ad89290c765Tom Hudson { "serif", "sans-serif", "monospace" }, // Android 312880df2609eba09b555ca37be04b6ad89290c765Tom Hudson { "Tinos", "Arimo", "Cousine" } // ChromeOS 322880df2609eba09b555ca37be04b6ad89290c765Tom Hudson}; 332880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 342880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonconst char* platform_font_name(const char* name) { 352880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkString platform = major_platform_os_name(); 362880df2609eba09b555ca37be04b6ad89290c765Tom Hudson int index; 372880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (!strcmp(name, "serif")) { 382880df2609eba09b555ca37be04b6ad89290c765Tom Hudson index = 0; 392880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else if (!strcmp(name, "san-serif")) { 402880df2609eba09b555ca37be04b6ad89290c765Tom Hudson index = 1; 412880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else if (!strcmp(name, "monospace")) { 422880df2609eba09b555ca37be04b6ad89290c765Tom Hudson index = 2; 432880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else { 442880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return name; 452880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 462880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (platform.equals("Mac")) { 472880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return gStandardFontNames[0][index]; 482880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 492880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (platform.equals("iOS")) { 502880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return gStandardFontNames[1][index]; 512880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 522880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (platform.equals("Win")) { 532880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return gStandardFontNames[2][index]; 542880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 552880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (platform.equals("Ubuntu")) { 562880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return gStandardFontNames[3][index]; 572880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 582880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (platform.equals("Android")) { 592880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return gStandardFontNames[4][index]; 602880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 612880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (platform.equals("ChromeOS")) { 622880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return gStandardFontNames[5][index]; 632880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 642880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return name; 652880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 662880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 67c3dcb67f07173af1c17771965ab7254910d52ef3caryclarkconst char* platform_os_emoji() { 68c3dcb67f07173af1c17771965ab7254910d52ef3caryclark const char* osName = platform_os_name(); 69e6633416056d10bc781dcfc32494f5766109ec79caryclark if (!strcmp(osName, "Android") || !strcmp(osName, "Ubuntu")) { 70c3dcb67f07173af1c17771965ab7254910d52ef3caryclark return "CBDT"; 71c3dcb67f07173af1c17771965ab7254910d52ef3caryclark } 72c3dcb67f07173af1c17771965ab7254910d52ef3caryclark if (!strncmp(osName, "Mac", 3)) { 73c3dcb67f07173af1c17771965ab7254910d52ef3caryclark return "SBIX"; 74c3dcb67f07173af1c17771965ab7254910d52ef3caryclark } 75c3dcb67f07173af1c17771965ab7254910d52ef3caryclark return ""; 76c3dcb67f07173af1c17771965ab7254910d52ef3caryclark} 77c3dcb67f07173af1c17771965ab7254910d52ef3caryclark 783b0f98ee17e02aae4e1e1e9fa65d3c56104dd9c7caryclarkvoid emoji_typeface(SkAutoTUnref<SkTypeface>* tf) { 79c3dcb67f07173af1c17771965ab7254910d52ef3caryclark if (!strcmp(sk_tool_utils::platform_os_emoji(), "CBDT")) { 803b0f98ee17e02aae4e1e1e9fa65d3c56104dd9c7caryclark tf->reset(GetResourceAsTypeface("/fonts/Funkster.ttf")); 813b0f98ee17e02aae4e1e1e9fa65d3c56104dd9c7caryclark return; 82c3dcb67f07173af1c17771965ab7254910d52ef3caryclark } 83c3dcb67f07173af1c17771965ab7254910d52ef3caryclark if (!strcmp(sk_tool_utils::platform_os_emoji(), "SBIX")) { 843b0f98ee17e02aae4e1e1e9fa65d3c56104dd9c7caryclark tf->reset(SkTypeface::CreateFromName("Apple Color Emoji", SkTypeface::kNormal)); 853b0f98ee17e02aae4e1e1e9fa65d3c56104dd9c7caryclark return; 86c3dcb67f07173af1c17771965ab7254910d52ef3caryclark } 872880df2609eba09b555ca37be04b6ad89290c765Tom Hudson tf->reset(nullptr); 883b0f98ee17e02aae4e1e1e9fa65d3c56104dd9c7caryclark return; 89c3dcb67f07173af1c17771965ab7254910d52ef3caryclark} 90c3dcb67f07173af1c17771965ab7254910d52ef3caryclark 91c3dcb67f07173af1c17771965ab7254910d52ef3caryclarkconst char* emoji_sample_text() { 92c3dcb67f07173af1c17771965ab7254910d52ef3caryclark if (!strcmp(sk_tool_utils::platform_os_emoji(), "CBDT")) { 93c3dcb67f07173af1c17771965ab7254910d52ef3caryclark return "Hamburgefons"; 94c3dcb67f07173af1c17771965ab7254910d52ef3caryclark } 95c3dcb67f07173af1c17771965ab7254910d52ef3caryclark if (!strcmp(sk_tool_utils::platform_os_emoji(), "SBIX")) { 96c3dcb67f07173af1c17771965ab7254910d52ef3caryclark return "\xF0\x9F\x92\xB0" "\xF0\x9F\x8F\xA1" "\xF0\x9F\x8E\x85" // 97c3dcb67f07173af1c17771965ab7254910d52ef3caryclark "\xF0\x9F\x8D\xAA" "\xF0\x9F\x8D\x95" "\xF0\x9F\x9A\x80" // 98c3dcb67f07173af1c17771965ab7254910d52ef3caryclark "\xF0\x9F\x9A\xBB" "\xF0\x9F\x92\xA9" "\xF0\x9F\x93\xB7" // 99c3dcb67f07173af1c17771965ab7254910d52ef3caryclark "\xF0\x9F\x93\xA6" // 100c3dcb67f07173af1c17771965ab7254910d52ef3caryclark "\xF0\x9F\x87\xBA" "\xF0\x9F\x87\xB8" "\xF0\x9F\x87\xA6"; // 101c3dcb67f07173af1c17771965ab7254910d52ef3caryclark } 102c3dcb67f07173af1c17771965ab7254910d52ef3caryclark return ""; 103c3dcb67f07173af1c17771965ab7254910d52ef3caryclark} 104c3dcb67f07173af1c17771965ab7254910d52ef3caryclark 1056531c3619f08cc83aad34883c5f00f6a358c9fadcaryclarkconst char* platform_os_name() { 1066531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark for (int index = 0; index < FLAGS_key.count(); index += 2) { 1076531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark if (!strcmp("os", FLAGS_key[index])) { 1086531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark return FLAGS_key[index + 1]; 1096531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark } 1106531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark } 1116531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark // when running SampleApp or dm without a --key pair, omit the platform name 1126531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark return ""; 1136531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark} 1146531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark 1152880df2609eba09b555ca37be04b6ad89290c765Tom Hudson// omit version number in returned value 1162880df2609eba09b555ca37be04b6ad89290c765Tom HudsonSkString major_platform_os_name() { 1172880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkString name; 1182880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int index = 0; index < FLAGS_key.count(); index += 2) { 1192880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (!strcmp("os", FLAGS_key[index])) { 1202880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const char* platform = FLAGS_key[index + 1]; 1212880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const char* end = platform; 1222880df2609eba09b555ca37be04b6ad89290c765Tom Hudson while (*end && (*end < '0' || *end > '9')) { 1232880df2609eba09b555ca37be04b6ad89290c765Tom Hudson ++end; 1242880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 1252880df2609eba09b555ca37be04b6ad89290c765Tom Hudson name.append(platform, end - platform); 1262880df2609eba09b555ca37be04b6ad89290c765Tom Hudson break; 1272880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 1282880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 1292880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return name; 1302880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 1312880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 1326531c3619f08cc83aad34883c5f00f6a358c9fadcaryclarkconst char* platform_extra_config(const char* config) { 1336531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark for (int index = 0; index < FLAGS_key.count(); index += 2) { 1346531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark if (!strcmp("extra_config", FLAGS_key[index]) && !strcmp(config, FLAGS_key[index + 1])) { 1356531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark return config; 1366531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark } 1376531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark } 1386531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark return ""; 1396531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark} 1406531c3619f08cc83aad34883c5f00f6a358c9fadcaryclark 141a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.orgconst char* colortype_name(SkColorType ct) { 142a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org switch (ct) { 143a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org case kUnknown_SkColorType: return "Unknown"; 144a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org case kAlpha_8_SkColorType: return "Alpha_8"; 145a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org case kIndex_8_SkColorType: return "Index_8"; 146a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org case kARGB_4444_SkColorType: return "ARGB_4444"; 147a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org case kRGB_565_SkColorType: return "RGB_565"; 148a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org case kRGBA_8888_SkColorType: return "RGBA_8888"; 149a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org case kBGRA_8888_SkColorType: return "BGRA_8888"; 150a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org default: 151a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org SkASSERT(false); 152a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org return "unexpected colortype"; 153a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org } 154a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org} 155a713f9c6f6a06d216d53e268b9c691941053dabfcommit-bot@chromium.org 15665cdba6ba78aaec0c0a4596bb5941020c789482bcaryclarkSkColor color_to_565(SkColor color) { 15765cdba6ba78aaec0c0a4596bb5941020c789482bcaryclark SkPMColor pmColor = SkPreMultiplyColor(color); 158d85093c28fe360650c46971b00a39c6dbf991a6bcaryclark U16CPU color16 = SkPixel32ToPixel16(pmColor); 15965cdba6ba78aaec0c0a4596bb5941020c789482bcaryclark return SkPixel16ToColor(color16); 160d85093c28fe360650c46971b00a39c6dbf991a6bcaryclark} 161d85093c28fe360650c46971b00a39c6dbf991a6bcaryclark 162992c7b03ef7914a18bfd78e965b0b4c99a5f5672Cary ClarkSkTypeface* create_portable_typeface(const char* name, SkTypeface::Style style) { 16383ca628cb6c959524edc3a696d7c3b5f7f1826bacaryclark return create_font(name, style); 16483ca628cb6c959524edc3a696d7c3b5f7f1826bacaryclark} 16583ca628cb6c959524edc3a696d7c3b5f7f1826bacaryclark 166992c7b03ef7914a18bfd78e965b0b4c99a5f5672Cary Clarkvoid set_portable_typeface(SkPaint* paint, const char* name, SkTypeface::Style style) { 16783ca628cb6c959524edc3a696d7c3b5f7f1826bacaryclark SkTypeface* face = create_font(name, style); 16883ca628cb6c959524edc3a696d7c3b5f7f1826bacaryclark SkSafeUnref(paint->setTypeface(face)); 16983ca628cb6c959524edc3a696d7c3b5f7f1826bacaryclark} 17083ca628cb6c959524edc3a696d7c3b5f7f1826bacaryclark 1714cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.orgvoid write_pixels(SkCanvas* canvas, const SkBitmap& bitmap, int x, int y, 1724cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org SkColorType colorType, SkAlphaType alphaType) { 1734cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org SkBitmap tmp(bitmap); 1744cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org tmp.lockPixels(); 175e62513fb9274b65bcd9fecf61acc418dd3949df5skia.committer@gmail.com 176e5ea500d4714a7d84de2bf913e81be3b65d2de68reed const SkImageInfo info = SkImageInfo::Make(tmp.width(), tmp.height(), colorType, alphaType); 177e62513fb9274b65bcd9fecf61acc418dd3949df5skia.committer@gmail.com 1784cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org canvas->writePixels(info, tmp.getPixels(), tmp.rowBytes(), x, y); 1794cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org} 1804cd9e2169e35cd67ee7358acea6541245e1d1744commit-bot@chromium.org 181b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanarySkShader* create_checkerboard_shader(SkColor c1, SkColor c2, int size) { 182b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary SkBitmap bm; 183b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary bm.allocN32Pixels(2 * size, 2 * size); 184b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary bm.eraseColor(c1); 185b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary bm.eraseArea(SkIRect::MakeLTRB(0, 0, size, size), c2); 186b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary bm.eraseArea(SkIRect::MakeLTRB(size, size, 2 * size, 2 * size), c2); 187b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary return SkShader::CreateBitmapShader( 188b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary bm, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); 189b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary} 190b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary 1912880df2609eba09b555ca37be04b6ad89290c765Tom HudsonSkBitmap create_checkerboard_bitmap(int w, int h, SkColor c1, SkColor c2, int checkSize) { 1922880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkBitmap bitmap; 1932880df2609eba09b555ca37be04b6ad89290c765Tom Hudson bitmap.allocN32Pixels(w, h); 1942880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkCanvas canvas(bitmap); 1952880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 1962880df2609eba09b555ca37be04b6ad89290c765Tom Hudson sk_tool_utils::draw_checkerboard(&canvas, c1, c2, checkSize); 1972880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return bitmap; 1982880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 1992880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 200b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanaryvoid draw_checkerboard(SkCanvas* canvas, SkColor c1, SkColor c2, int size) { 201b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary SkPaint paint; 202b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary paint.setShader(create_checkerboard_shader(c1, c2, size))->unref(); 203f77365f43e74dee617db669369a0eb86c6acc550halcanary paint.setXfermodeMode(SkXfermode::kSrc_Mode); 204b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary canvas->drawPaint(paint); 205b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary} 206b0cce2c1d37d4bf5b89da6c70062209ac4e0e643halcanary 2072880df2609eba09b555ca37be04b6ad89290c765Tom HudsonSkBitmap create_string_bitmap(int w, int h, SkColor c, int x, int y, 2082880df2609eba09b555ca37be04b6ad89290c765Tom Hudson int textSize, const char* str) { 2092880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkBitmap bitmap; 2102880df2609eba09b555ca37be04b6ad89290c765Tom Hudson bitmap.allocN32Pixels(w, h); 2112880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkCanvas canvas(bitmap); 2122880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2132880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkPaint paint; 2142880df2609eba09b555ca37be04b6ad89290c765Tom Hudson paint.setAntiAlias(true); 2152880df2609eba09b555ca37be04b6ad89290c765Tom Hudson sk_tool_utils::set_portable_typeface(&paint); 2162880df2609eba09b555ca37be04b6ad89290c765Tom Hudson paint.setColor(c); 2172880df2609eba09b555ca37be04b6ad89290c765Tom Hudson paint.setTextSize(SkIntToScalar(textSize)); 2182880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2192880df2609eba09b555ca37be04b6ad89290c765Tom Hudson canvas.clear(0x00000000); 2202880df2609eba09b555ca37be04b6ad89290c765Tom Hudson canvas.drawText(str, strlen(str), SkIntToScalar(x), SkIntToScalar(y), paint); 2212880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2222880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return bitmap; 2232880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 2242880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2259e36c1a9306f052331550dab4728b9875127bfb5joshualittvoid add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkPaint& origPaint, 2269e36c1a9306f052331550dab4728b9875127bfb5joshualitt SkScalar x, SkScalar y) { 2279e36c1a9306f052331550dab4728b9875127bfb5joshualitt SkPaint paint(origPaint); 2289e36c1a9306f052331550dab4728b9875127bfb5joshualitt SkTDArray<uint16_t> glyphs; 2299e36c1a9306f052331550dab4728b9875127bfb5joshualitt 2309e36c1a9306f052331550dab4728b9875127bfb5joshualitt size_t len = strlen(text); 2312880df2609eba09b555ca37be04b6ad89290c765Tom Hudson glyphs.append(paint.textToGlyphs(text, len, nullptr)); 2329e36c1a9306f052331550dab4728b9875127bfb5joshualitt paint.textToGlyphs(text, len, glyphs.begin()); 2339e36c1a9306f052331550dab4728b9875127bfb5joshualitt 2349e36c1a9306f052331550dab4728b9875127bfb5joshualitt paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 2359e36c1a9306f052331550dab4728b9875127bfb5joshualitt const SkTextBlobBuilder::RunBuffer& run = builder->allocRun(paint, glyphs.count(), x, y, 2362880df2609eba09b555ca37be04b6ad89290c765Tom Hudson nullptr); 2379e36c1a9306f052331550dab4728b9875127bfb5joshualitt memcpy(run.glyphs, glyphs.begin(), glyphs.count() * sizeof(uint16_t)); 2389e36c1a9306f052331550dab4728b9875127bfb5joshualitt} 2399e36c1a9306f052331550dab4728b9875127bfb5joshualitt 2402880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonstatic inline void norm_to_rgb(SkBitmap* bm, int x, int y, const SkVector3& norm) { 2412880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkASSERT(SkScalarNearlyEqual(norm.length(), 1.0f)); 2422880df2609eba09b555ca37be04b6ad89290c765Tom Hudson unsigned char r = static_cast<unsigned char>((0.5f * norm.fX + 0.5f) * 255); 2432880df2609eba09b555ca37be04b6ad89290c765Tom Hudson unsigned char g = static_cast<unsigned char>((-0.5f * norm.fY + 0.5f) * 255); 2442880df2609eba09b555ca37be04b6ad89290c765Tom Hudson unsigned char b = static_cast<unsigned char>((0.5f * norm.fZ + 0.5f) * 255); 2452880df2609eba09b555ca37be04b6ad89290c765Tom Hudson *bm->getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b); 2462880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 2472880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2482880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonvoid create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst) { 2492880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint center = SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), 2502880df2609eba09b555ca37be04b6ad89290c765Tom Hudson dst.fTop + (dst.height() / 2.0f)); 2512880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint halfSize = SkPoint::Make(dst.width() / 2.0f, dst.height() / 2.0f); 2522880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2532880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkVector3 norm; 2542880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2552880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int y = dst.fTop; y < dst.fBottom; ++y) { 2562880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int x = dst.fLeft; x < dst.fRight; ++x) { 2572880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm.fX = (x + 0.5f - center.fX) / halfSize.fX; 2582880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm.fY = (y + 0.5f - center.fY) / halfSize.fY; 2592880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2602880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkScalar tmp = norm.fX * norm.fX + norm.fY * norm.fY; 2612880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (tmp >= 1.0f) { 2622880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm.set(0.0f, 0.0f, 1.0f); 2632880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else { 2642880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm.fZ = sqrtf(1.0f - tmp); 2652880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 2662880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2672880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm_to_rgb(bm, x, y, norm); 2682880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 2692880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 2702880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 2712880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2722880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonvoid create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst) { 2732880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint center = SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), 2742880df2609eba09b555ca37be04b6ad89290c765Tom Hudson dst.fTop + (dst.height() / 2.0f)); 2752880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2762880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkIRect inner = dst; 2772880df2609eba09b555ca37be04b6ad89290c765Tom Hudson inner.inset(dst.width()/4, dst.height()/4); 2782880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2792880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkPoint3 norm; 2802880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint3 left = SkPoint3::Make(-SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2); 2812880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint3 up = SkPoint3::Make(0.0f, -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2); 2822880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint3 right = SkPoint3::Make(SK_ScalarRoot2Over2, 0.0f, SK_ScalarRoot2Over2); 2832880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint3 down = SkPoint3::Make(0.0f, SK_ScalarRoot2Over2, SK_ScalarRoot2Over2); 2842880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2852880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int y = dst.fTop; y < dst.fBottom; ++y) { 2862880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int x = dst.fLeft; x < dst.fRight; ++x) { 2872880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (inner.contains(x, y)) { 2882880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm.set(0.0f, 0.0f, 1.0f); 2892880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else { 2902880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkScalar locX = x + 0.5f - center.fX; 2912880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkScalar locY = y + 0.5f - center.fY; 2922880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 2932880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (locX >= 0.0f) { 2942880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (locY > 0.0f) { 2952880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm = locX >= locY ? right : down; // LR corner 2962880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else { 2972880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm = locX > -locY ? right : up; // UR corner 2982880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 2992880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else { 3002880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (locY > 0.0f) { 3012880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm = -locX > locY ? left : down; // LL corner 3022880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else { 3032880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm = locX > locY ? up : left; // UL corner 3042880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3052880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3062880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3072880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3082880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm_to_rgb(bm, x, y, norm); 3092880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3102880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3112880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 3122880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3132880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonvoid create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst) { 3142880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint center = SkPoint::Make(dst.fLeft + (dst.width() / 2.0f), 3152880df2609eba09b555ca37be04b6ad89290c765Tom Hudson dst.fTop + (dst.height() / 2.0f)); 3162880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3172880df2609eba09b555ca37be04b6ad89290c765Tom Hudson static const SkScalar k1OverRoot3 = 0.5773502692f; 3182880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3192880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkPoint3 norm; 3202880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint3 leftUp = SkPoint3::Make(-k1OverRoot3, -k1OverRoot3, k1OverRoot3); 3212880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint3 rightUp = SkPoint3::Make(k1OverRoot3, -k1OverRoot3, k1OverRoot3); 3222880df2609eba09b555ca37be04b6ad89290c765Tom Hudson const SkPoint3 down = SkPoint3::Make(0.0f, SK_ScalarRoot2Over2, SK_ScalarRoot2Over2); 3232880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3242880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int y = dst.fTop; y < dst.fBottom; ++y) { 3252880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int x = dst.fLeft; x < dst.fRight; ++x) { 3262880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkScalar locX = x + 0.5f - center.fX; 3272880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkScalar locY = y + 0.5f - center.fY; 3282880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3292880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (locX >= 0.0f) { 3302880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (locY > 0.0f) { 3312880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm = locX >= locY ? rightUp : down; // LR corner 3322880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else { 3332880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm = rightUp; 3342880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3352880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else { 3362880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (locY > 0.0f) { 3372880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm = -locX > locY ? leftUp : down; // LL corner 3382880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else { 3392880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm = leftUp; 3402880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3412880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3422880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3432880df2609eba09b555ca37be04b6ad89290c765Tom Hudson norm_to_rgb(bm, x, y, norm); 3442880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3452880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3462880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 3472880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3482880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonvoid make_big_path(SkPath& path) { 3492880df2609eba09b555ca37be04b6ad89290c765Tom Hudson #include "BigPathBench.inc" 3502880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 3512880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3522880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonstatic float gaussian2d_value(int x, int y, float sigma) { 3532880df2609eba09b555ca37be04b6ad89290c765Tom Hudson // don't bother with the scale term since we're just going to normalize the 3542880df2609eba09b555ca37be04b6ad89290c765Tom Hudson // kernel anyways 3552880df2609eba09b555ca37be04b6ad89290c765Tom Hudson float temp = expf(-(x*x + y*y)/(2*sigma*sigma)); 3562880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return temp; 3572880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 3582880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3592880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonstatic float* create_2d_kernel(float sigma, int* filterSize) { 3602880df2609eba09b555ca37be04b6ad89290c765Tom Hudson // We will actually take 2*halfFilterSize+1 samples (i.e., our filter kernel 3612880df2609eba09b555ca37be04b6ad89290c765Tom Hudson // sizes are always odd) 3622880df2609eba09b555ca37be04b6ad89290c765Tom Hudson int halfFilterSize = SkScalarCeilToInt(6*sigma)/2; 3632880df2609eba09b555ca37be04b6ad89290c765Tom Hudson int wh = *filterSize = 2*halfFilterSize + 1; 3642880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3652880df2609eba09b555ca37be04b6ad89290c765Tom Hudson float* temp = new float[wh*wh]; 3662880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3672880df2609eba09b555ca37be04b6ad89290c765Tom Hudson float filterTot = 0.0f; 3682880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int yOff = 0; yOff < wh; ++yOff) { 3692880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int xOff = 0; xOff < wh; ++xOff) { 3702880df2609eba09b555ca37be04b6ad89290c765Tom Hudson temp[yOff*wh+xOff] = gaussian2d_value(xOff-halfFilterSize, yOff-halfFilterSize, sigma); 3712880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3722880df2609eba09b555ca37be04b6ad89290c765Tom Hudson filterTot += temp[yOff*wh+xOff]; 3732880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3742880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3752880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3762880df2609eba09b555ca37be04b6ad89290c765Tom Hudson // normalize the kernel 3772880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int yOff = 0; yOff < wh; ++yOff) { 3782880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int xOff = 0; xOff < wh; ++xOff) { 3792880df2609eba09b555ca37be04b6ad89290c765Tom Hudson temp[yOff*wh+xOff] /= filterTot; 3802880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3812880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 3822880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3832880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return temp; 3842880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 3852880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3862880df2609eba09b555ca37be04b6ad89290c765Tom Hudsonstatic SkPMColor blur_pixel(const SkBitmap& bm, int x, int y, float* kernel, int wh) { 3872880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkASSERT(wh & 0x1); 3882880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3892880df2609eba09b555ca37be04b6ad89290c765Tom Hudson int halfFilterSize = (wh-1)/2; 3902880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3912880df2609eba09b555ca37be04b6ad89290c765Tom Hudson float r = 0.0f, g = 0.0f, b = 0.0f; 3922880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int yOff = 0; yOff < wh; ++yOff) { 3932880df2609eba09b555ca37be04b6ad89290c765Tom Hudson int ySamp = y + yOff - halfFilterSize; 3942880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 3952880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (ySamp < 0) { 3962880df2609eba09b555ca37be04b6ad89290c765Tom Hudson ySamp = 0; 3972880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else if (ySamp > bm.height()-1) { 3982880df2609eba09b555ca37be04b6ad89290c765Tom Hudson ySamp = bm.height()-1; 3992880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 4002880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4012880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int xOff = 0; xOff < wh; ++xOff) { 4022880df2609eba09b555ca37be04b6ad89290c765Tom Hudson int xSamp = x + xOff - halfFilterSize; 4032880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4042880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if (xSamp < 0) { 4052880df2609eba09b555ca37be04b6ad89290c765Tom Hudson xSamp = 0; 4062880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } else if (xSamp > bm.width()-1) { 4072880df2609eba09b555ca37be04b6ad89290c765Tom Hudson xSamp = bm.width()-1; 4082880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 4092880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4102880df2609eba09b555ca37be04b6ad89290c765Tom Hudson float filter = kernel[yOff*wh + xOff]; 4112880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4122880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkPMColor c = *bm.getAddr32(xSamp, ySamp); 4132880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4142880df2609eba09b555ca37be04b6ad89290c765Tom Hudson r += SkGetPackedR32(c) * filter; 4152880df2609eba09b555ca37be04b6ad89290c765Tom Hudson g += SkGetPackedG32(c) * filter; 4162880df2609eba09b555ca37be04b6ad89290c765Tom Hudson b += SkGetPackedB32(c) * filter; 4172880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 4182880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 4192880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4202880df2609eba09b555ca37be04b6ad89290c765Tom Hudson U8CPU r8, g8, b8; 4212880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4222880df2609eba09b555ca37be04b6ad89290c765Tom Hudson r8 = (U8CPU) (r+0.5f); 4232880df2609eba09b555ca37be04b6ad89290c765Tom Hudson g8 = (U8CPU) (g+0.5f); 4242880df2609eba09b555ca37be04b6ad89290c765Tom Hudson b8 = (U8CPU) (b+0.5f); 4252880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4262880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return SkPackARGB32(255, r8, g8, b8); 4272880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 4282880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4292880df2609eba09b555ca37be04b6ad89290c765Tom HudsonSkBitmap slow_blur(const SkBitmap& src, float sigma) { 4302880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkBitmap dst; 4312880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4322880df2609eba09b555ca37be04b6ad89290c765Tom Hudson dst.allocN32Pixels(src.width(), src.height(), true); 4332880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4342880df2609eba09b555ca37be04b6ad89290c765Tom Hudson int wh; 4352880df2609eba09b555ca37be04b6ad89290c765Tom Hudson SkAutoTDeleteArray<float> kernel(create_2d_kernel(sigma, &wh)); 4362880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4372880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int y = 0; y < src.height(); ++y) { 4382880df2609eba09b555ca37be04b6ad89290c765Tom Hudson for (int x = 0; x < src.width(); ++x) { 4392880df2609eba09b555ca37be04b6ad89290c765Tom Hudson *dst.getAddr32(x, y) = blur_pixel(src, x, y, kernel.get(), wh); 4402880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 4412880df2609eba09b555ca37be04b6ad89290c765Tom Hudson } 4422880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 4432880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return dst; 4442880df2609eba09b555ca37be04b6ad89290c765Tom Hudson} 4459c4909b50ff9d0fdf9bce2a67cd459aeb28cdc3crobertphillips 4462010891425f10257363ae6eb0da70453746dc087tfarina} // namespace sk_tool_utils 447