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 ToolUtils_DEFINED 9#define ToolUtils_DEFINED 10 11#include "include/core/SkColor.h" 12#include "include/core/SkData.h" 13#include "include/core/SkEncodedImageFormat.h" 14#include "include/core/SkFont.h" 15#include "include/core/SkFontStyle.h" 16#include "include/core/SkFontTypes.h" 17#include "include/core/SkImageEncoder.h" 18#include "include/core/SkImageInfo.h" 19#include "include/core/SkPixmap.h" 20#include "include/core/SkRect.h" 21#include "include/core/SkRefCnt.h" 22#include "include/core/SkScalar.h" 23#include "include/core/SkStream.h" 24#include "include/core/SkSurface.h" 25#include "include/core/SkTypeface.h" 26#include "include/core/SkTypes.h" 27#include "include/private/SkTArray.h" 28#include "include/private/SkTDArray.h" 29#include "include/utils/SkRandom.h" 30#include "src/core/SkTInternalLList.h" 31 32class SkBitmap; 33class SkCanvas; 34class SkFontStyle; 35class SkImage; 36class SkPath; 37class SkPixmap; 38class SkRRect; 39class SkShader; 40class SkSurface; 41class SkSurfaceProps; 42class SkTextBlobBuilder; 43class SkTypeface; 44 45namespace ToolUtils { 46 47const char* alphatype_name (SkAlphaType); 48const char* colortype_name (SkColorType); 49const char* colortype_depth(SkColorType); // like colortype_name, but channel order agnostic 50const char* tilemode_name(SkTileMode); 51 52/** 53 * Map opaque colors from 8888 to 565. 54 */ 55SkColor color_to_565(SkColor color); 56 57/* Return a color emoji typeface with planets to scale if available. */ 58sk_sp<SkTypeface> planet_typeface(); 59 60/** Return a color emoji typeface if available. */ 61sk_sp<SkTypeface> emoji_typeface(); 62 63/** Sample text for the emoji_typeface font. */ 64const char* emoji_sample_text(); 65 66/** A simple SkUserTypeface for testing. */ 67sk_sp<SkTypeface> sample_user_typeface(); 68 69/** 70 * Returns a platform-independent text renderer. 71 */ 72sk_sp<SkTypeface> create_portable_typeface(const char* name, SkFontStyle style); 73 74static inline sk_sp<SkTypeface> create_portable_typeface() { 75 return create_portable_typeface(nullptr, SkFontStyle()); 76} 77 78void get_text_path(const SkFont&, 79 const void* text, 80 size_t length, 81 SkTextEncoding, 82 SkPath*, 83 const SkPoint* positions = nullptr); 84 85/** 86 * Returns true iff all of the pixels between the two images are identical. 87 * 88 * If the configs differ, return false. 89 */ 90bool equal_pixels(const SkPixmap&, const SkPixmap&); 91bool equal_pixels(const SkBitmap&, const SkBitmap&); 92bool equal_pixels(const SkImage* a, const SkImage* b); 93 94/** Returns a newly created CheckerboardShader. */ 95sk_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. */ 99void draw_checkerboard(SkCanvas* canvas, SkColor color1, SkColor color2, int checkSize); 100 101/** Make it easier to create a bitmap-based checkerboard */ 102SkBitmap create_checkerboard_bitmap(int w, int h, SkColor c1, SkColor c2, int checkSize); 103 104sk_sp<SkImage> create_checkerboard_image(int w, int h, SkColor c1, SkColor c2, int checkSize); 105 106/** A default checkerboard. */ 107inline void draw_checkerboard(SkCanvas* canvas) { 108 ToolUtils::draw_checkerboard(canvas, 0xFF999999, 0xFF666666, 8); 109} 110 111SkBitmap create_string_bitmap(int w, int h, SkColor c, int x, int y, int textSize, const char* str); 112sk_sp<SkImage> create_string_image(int w, int h, SkColor c, int x, int y, int textSize, const char* str); 113 114// If the canvas does't make a surface (e.g. recording), make a raster surface 115sk_sp<SkSurface> makeSurface(SkCanvas*, const SkImageInfo&, const SkSurfaceProps* = nullptr); 116 117// A helper for inserting a drawtext call into a SkTextBlobBuilder 118void add_to_text_blob_w_len(SkTextBlobBuilder*, 119 const char* text, 120 size_t len, 121 SkTextEncoding, 122 const SkFont&, 123 SkScalar x, 124 SkScalar y); 125 126void add_to_text_blob(SkTextBlobBuilder*, const char* text, const SkFont&, SkScalar x, SkScalar y); 127 128// Constructs a star by walking a 'numPts'-sided regular polygon with even/odd fill: 129// 130// moveTo(pts[0]); 131// lineTo(pts[step % numPts]); 132// ... 133// lineTo(pts[(step * (N - 1)) % numPts]); 134// 135// numPts=5, step=2 will produce a classic five-point star. 136// 137// numPts and step must be co-prime. 138SkPath make_star(const SkRect& bounds, int numPts = 5, int step = 2); 139 140void create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst); 141 142void create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst); 143 144void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst); 145 146// A helper object to test the topological sorting code (TopoSortBench.cpp & TopoSortTest.cpp) 147class TopoTestNode : public SkRefCnt { 148public: 149 TopoTestNode(int id) : fID(id) {} 150 151 void dependsOn(TopoTestNode* src) { *fDependencies.append() = src; } 152 void targets(uint32_t target) { *fTargets.append() = target; } 153 154 int id() const { return fID; } 155 void reset() { 156 fOutputPos = 0; 157 fTempMark = false; 158 fWasOutput = false; 159 } 160 161 uint32_t outputPos() const { 162 SkASSERT(fWasOutput); 163 return fOutputPos; 164 } 165 166 // check that the topological sort is valid for this node 167 bool check() { 168 if (!fWasOutput) { 169 return false; 170 } 171 172 for (int i = 0; i < fDependencies.count(); ++i) { 173 if (!fDependencies[i]->fWasOutput) { 174 return false; 175 } 176 // This node should've been output after all the nodes on which it depends 177 if (fOutputPos < fDependencies[i]->outputPos()) { 178 return false; 179 } 180 } 181 182 return true; 183 } 184 185 // The following 7 methods are needed by the topological sort 186 static void SetTempMark(TopoTestNode* node) { node->fTempMark = true; } 187 static void ResetTempMark(TopoTestNode* node) { node->fTempMark = false; } 188 static bool IsTempMarked(TopoTestNode* node) { return node->fTempMark; } 189 static void Output(TopoTestNode* node, uint32_t outputPos) { 190 SkASSERT(!node->fWasOutput); 191 node->fOutputPos = outputPos; 192 node->fWasOutput = true; 193 } 194 static bool WasOutput(TopoTestNode* node) { return node->fWasOutput; } 195 static uint32_t GetIndex(TopoTestNode* node) { return node->outputPos(); } 196 static int NumDependencies(TopoTestNode* node) { return node->fDependencies.count(); } 197 static TopoTestNode* Dependency(TopoTestNode* node, int index) { 198 return node->fDependencies[index]; 199 } 200 static int NumTargets(TopoTestNode* node) { return node->fTargets.count(); } 201 static uint32_t GetTarget(TopoTestNode* node, int i) { return node->fTargets[i]; } 202 static uint32_t GetID(TopoTestNode* node) { return node->id(); } 203 204 // Helper functions for TopoSortBench & TopoSortTest 205 static void AllocNodes(SkTArray<sk_sp<ToolUtils::TopoTestNode>>* graph, int num) { 206 graph->reserve_back(num); 207 208 for (int i = 0; i < num; ++i) { 209 graph->push_back(sk_sp<TopoTestNode>(new TopoTestNode(i))); 210 } 211 } 212 213#ifdef SK_DEBUG 214 static void Print(const SkTArray<TopoTestNode*>& graph) { 215 for (int i = 0; i < graph.count(); ++i) { 216 SkDebugf("%d, ", graph[i]->id()); 217 } 218 SkDebugf("\n"); 219 } 220#endif 221 222 // randomize the array 223 static void Shuffle(SkTArray<sk_sp<TopoTestNode>>* graph, SkRandom* rand) { 224 for (int i = graph->count() - 1; i > 0; --i) { 225 int swap = rand->nextU() % (i + 1); 226 227 (*graph)[i].swap((*graph)[swap]); 228 } 229 } 230 231 SK_DECLARE_INTERNAL_LLIST_INTERFACE(TopoTestNode); 232 233private: 234 int fID; 235 uint32_t fOutputPos = 0; 236 bool fTempMark = false; 237 bool fWasOutput = false; 238 239 SkTDArray<TopoTestNode*> fDependencies; 240 SkTDArray<uint32_t> fTargets; 241}; 242 243template <typename T> 244inline bool EncodeImageToFile(const char* path, const T& src, SkEncodedImageFormat f, int q) { 245 SkFILEWStream file(path); 246 return file.isValid() && SkEncodeImage(&file, src, f, q); 247} 248 249bool copy_to(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src); 250void copy_to_g8(SkBitmap* dst, const SkBitmap& src); 251 252class PixelIter { 253public: 254 PixelIter(); 255 PixelIter(SkSurface* surf) { 256 SkPixmap pm; 257 if (!surf->peekPixels(&pm)) { 258 pm.reset(); 259 } 260 this->reset(pm); 261 } 262 263 void reset(const SkPixmap& pm) { 264 fPM = pm; 265 fLoc = {-1, 0}; 266 } 267 268 void* next(SkIPoint* loc = nullptr) { 269 if (!fPM.addr()) { 270 return nullptr; 271 } 272 fLoc.fX += 1; 273 if (fLoc.fX >= fPM.width()) { 274 fLoc.fX = 0; 275 if (++fLoc.fY >= fPM.height()) { 276 this->setDone(); 277 return nullptr; 278 } 279 } 280 if (loc) { 281 *loc = fLoc; 282 } 283 return fPM.writable_addr(fLoc.fX, fLoc.fY); 284 } 285 286 void setDone() { fPM.reset(); } 287 288private: 289 SkPixmap fPM; 290 SkIPoint fLoc; 291}; 292 293using PathSniffCallback = void(const SkMatrix&, const SkPath&, const SkPaint&); 294 295// Calls the provided PathSniffCallback for each path in the given file. 296// Supported file formats are .svg and .skp. 297void sniff_paths(const char filepath[], std::function<PathSniffCallback>); 298 299} // namespace ToolUtils 300 301#endif // ToolUtils_DEFINED 302