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 #ifndef sk_tool_utils_DEFINED 9 #define sk_tool_utils_DEFINED 10 11 #include "SkColor.h" 12 #include "SkImageEncoder.h" 13 #include "SkImageInfo.h" 14 #include "SkRandom.h" 15 #include "SkStream.h" 16 #include "SkTDArray.h" 17 #include "SkTypeface.h" 18 19 class SkBitmap; 20 class SkCanvas; 21 class SkColorFilter; 22 class SkImage; 23 class SkPaint; 24 class SkPath; 25 class SkRRect; 26 class SkShader; 27 class SkSurface; 28 class SkSurfaceProps; 29 class SkTestFont; 30 class SkTextBlobBuilder; 31 32 namespace sk_tool_utils { 33 34 const char* colortype_name(SkColorType); 35 36 /** 37 * Map opaque colors from 8888 to 565. 38 */ 39 SkColor color_to_565(SkColor color); 40 41 /** 42 * Return a color emoji typeface if available. 43 */ 44 sk_sp<SkTypeface> emoji_typeface(); 45 46 /** 47 * If the platform supports color emoji, return sample text the emoji can render. 48 */ 49 const char* emoji_sample_text(); 50 51 /** 52 * Returns a string describing the platform font manager, if we're using one, otherwise "". 53 */ 54 const char* platform_font_manager(); 55 56 /** 57 * Sets the paint to use a platform-independent text renderer 58 */ 59 void set_portable_typeface(SkPaint* paint, const char* name = nullptr, 60 SkFontStyle style = SkFontStyle()); 61 62 /** 63 * Returns a platform-independent text renderer. 64 */ 65 sk_sp<SkTypeface> create_portable_typeface(const char* name, SkFontStyle style); 66 67 /** Call to clean up portable font references. */ 68 void release_portable_typefaces(); 69 70 /** 71 * Call canvas->writePixels() by using the pixels from bitmap, but with an info that claims 72 * the pixels are colorType + alphaType 73 */ 74 void write_pixels(SkCanvas*, const SkBitmap&, int x, int y, SkColorType, SkAlphaType); 75 76 /** 77 * Returns true iff all of the pixels between the two images differ by <= the maxDiff value 78 * per component. 79 * 80 * If the configs differ, return false. 81 * 82 * If the colorType is half-float, then maxDiff is interpreted as 0..255 --> 0..1 83 */ 84 bool equal_pixels(const SkPixmap&, const SkPixmap&, unsigned maxDiff = 0, 85 bool respectColorSpaces = false); 86 bool equal_pixels(const SkBitmap&, const SkBitmap&, unsigned maxDiff = 0, 87 bool respectColorSpaces = false); 88 bool equal_pixels(const SkImage* a, const SkImage* b, unsigned maxDiff = 0, 89 bool respectColorSpaces = false); 90 91 // private to sk_tool_utils 92 sk_sp<SkTypeface> create_font(const char* name, SkFontStyle); 93 94 /** Returns a newly created CheckerboardShader. */ 95 sk_sp<SkShader> create_checkerboard_shader(SkColor c1, SkColor c2, int size); 96 97 /** Draw a checkerboard pattern in the current canvas, restricted to 98 the current clip, using SkXfermode::kSrc_Mode. */ 99 void draw_checkerboard(SkCanvas* canvas, 100 SkColor color1, 101 SkColor color2, 102 int checkSize); 103 104 /** Make it easier to create a bitmap-based checkerboard */ 105 SkBitmap create_checkerboard_bitmap(int w, int h, 106 SkColor c1, SkColor c2, 107 int checkSize); 108 109 /** A default checkerboard. */ 110 inline void draw_checkerboard(SkCanvas* canvas) { 111 sk_tool_utils::draw_checkerboard(canvas, 0xFF999999, 0xFF666666, 8); 112 } 113 114 SkBitmap create_string_bitmap(int w, int h, SkColor c, int x, int y, 115 int textSize, const char* str); 116 117 // If the canvas does't make a surface (e.g. recording), make a raster surface 118 sk_sp<SkSurface> makeSurface(SkCanvas*, const SkImageInfo&, const SkSurfaceProps* = nullptr); 119 120 // A helper for inserting a drawtext call into a SkTextBlobBuilder 121 void add_to_text_blob_w_len(SkTextBlobBuilder* builder, const char* text, size_t len, 122 const SkPaint& origPaint, SkScalar x, SkScalar y); 123 124 void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, 125 const SkPaint& origPaint, SkScalar x, SkScalar y); 126 127 // Constructs a star by walking a 'numPts'-sided regular polygon with even/odd fill: 128 // 129 // moveTo(pts[0]); 130 // lineTo(pts[step % numPts]); 131 // ... 132 // lineTo(pts[(step * (N - 1)) % numPts]); 133 // 134 // numPts=5, step=2 will produce a classic five-point star. 135 // 136 // numPts and step must be co-prime. 137 SkPath make_star(const SkRect& bounds, int numPts = 5, int step = 2); 138 139 void make_big_path(SkPath& path); 140 141 // Return a blurred version of 'src'. This doesn't use a separable filter 142 // so it is slow! 143 SkBitmap slow_blur(const SkBitmap& src, float sigma); 144 145 SkRect compute_central_occluder(const SkRRect& rr); 146 SkRect compute_widest_occluder(const SkRRect& rr); 147 SkRect compute_tallest_occluder(const SkRRect& rr); 148 149 // A helper object to test the topological sorting code (TopoSortBench.cpp & TopoSortTest.cpp) 150 class TopoTestNode { 151 public: 152 TopoTestNode(int id) : fID(id), fOutputPos(-1), fTempMark(false) { } 153 154 void dependsOn(TopoTestNode* src) { 155 *fDependencies.append() = src; 156 } 157 158 int id() const { return fID; } 159 void reset() { fOutputPos = -1; } 160 161 int outputPos() const { return fOutputPos; } 162 163 // check that the topological sort is valid for this node 164 bool check() { 165 if (-1 == fOutputPos) { 166 return false; 167 } 168 169 for (int i = 0; i < fDependencies.count(); ++i) { 170 if (-1 == fDependencies[i]->outputPos()) { 171 return false; 172 } 173 // This node should've been output after all the nodes on which it depends 174 if (fOutputPos < fDependencies[i]->outputPos()) { 175 return false; 176 } 177 } 178 179 return true; 180 } 181 182 // The following 7 methods are needed by the topological sort 183 static void SetTempMark(TopoTestNode* node) { node->fTempMark = true; } 184 static void ResetTempMark(TopoTestNode* node) { node->fTempMark = false; } 185 static bool IsTempMarked(TopoTestNode* node) { return node->fTempMark; } 186 static void Output(TopoTestNode* node, int outputPos) { 187 SkASSERT(-1 != outputPos); 188 node->fOutputPos = outputPos; 189 } 190 static bool WasOutput(TopoTestNode* node) { return (-1 != node->fOutputPos); } 191 static int NumDependencies(TopoTestNode* node) { return node->fDependencies.count(); } 192 static TopoTestNode* Dependency(TopoTestNode* node, int index) { 193 return node->fDependencies[index]; 194 } 195 196 // Helper functions for TopoSortBench & TopoSortTest 197 static void AllocNodes(SkTDArray<TopoTestNode*>* graph, int num) { 198 graph->setReserve(num); 199 200 for (int i = 0; i < num; ++i) { 201 *graph->append() = new TopoTestNode(i); 202 } 203 } 204 205 static void DeallocNodes(SkTDArray<TopoTestNode*>* graph) { 206 for (int i = 0; i < graph->count(); ++i) { 207 delete (*graph)[i]; 208 } 209 } 210 211 #ifdef SK_DEBUG 212 static void Print(const SkTDArray<TopoTestNode*>& graph) { 213 for (int i = 0; i < graph.count(); ++i) { 214 SkDebugf("%d, ", graph[i]->id()); 215 } 216 SkDebugf("\n"); 217 } 218 #endif 219 220 // randomize the array 221 static void Shuffle(SkTDArray<TopoTestNode*>* graph, SkRandom* rand) { 222 for (int i = graph->count()-1; i > 0; --i) { 223 int swap = rand->nextU() % (i+1); 224 225 TopoTestNode* tmp = (*graph)[i]; 226 (*graph)[i] = (*graph)[swap]; 227 (*graph)[swap] = tmp; 228 } 229 } 230 231 private: 232 int fID; 233 int fOutputPos; 234 bool fTempMark; 235 236 SkTDArray<TopoTestNode*> fDependencies; 237 }; 238 239 template <typename T> 240 inline bool EncodeImageToFile(const char* path, const T& src, SkEncodedImageFormat f, int q) { 241 SkFILEWStream file(path); 242 return file.isValid() && SkEncodeImage(&file, src, f, q); 243 } 244 245 template <typename T> 246 inline sk_sp<SkData> EncodeImageToData(const T& src, SkEncodedImageFormat f, int q) { 247 SkDynamicMemoryWStream buf; 248 return SkEncodeImage(&buf, src , f, q) ? buf.detachAsData() : nullptr; 249 } 250 251 bool copy_to(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src); 252 void copy_to_g8(SkBitmap* dst, const SkBitmap& src); 253 } // namespace sk_tool_utils 254 255 #endif // sk_tool_utils_DEFINED 256