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