/src/skia/tools/ToolUtils.h
Line | Count | Source (jump to first uncovered line) |
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/SkFontArguments.h" |
13 | | #include "include/core/SkFontParameters.h" |
14 | | #include "include/core/SkFontStyle.h" |
15 | | #include "include/core/SkPixmap.h" |
16 | | #include "include/core/SkPoint.h" |
17 | | #include "include/core/SkRect.h" |
18 | | #include "include/core/SkRefCnt.h" |
19 | | #include "include/core/SkScalar.h" |
20 | | #include "include/core/SkSpan.h" |
21 | | #include "include/core/SkString.h" |
22 | | #include "include/core/SkSurface.h" |
23 | | #include "include/core/SkTypeface.h" // IWYU pragma: keep |
24 | | #include "include/core/SkTypes.h" |
25 | | #include "include/private/base/SkDebug.h" |
26 | | #include "include/private/base/SkTArray.h" |
27 | | #include "include/private/base/SkTDArray.h" |
28 | | #include "src/base/SkRandom.h" |
29 | | #include "src/base/SkTInternalLList.h" |
30 | | |
31 | | #include <cstddef> |
32 | | #include <cstdint> |
33 | | #include <memory> |
34 | | #include <vector> |
35 | | #include <functional> |
36 | | |
37 | | class SkBitmap; |
38 | | class SkCanvas; |
39 | | class SkFont; |
40 | | class SkImage; |
41 | | class SkMatrix; |
42 | | class SkMetaData; |
43 | | class SkPaint; |
44 | | class SkPath; |
45 | | class SkShader; |
46 | | class SkSurfaceProps; |
47 | | class SkTextBlobBuilder; |
48 | | enum SkAlphaType : int; |
49 | | enum SkColorType : int; |
50 | | enum class SkTextEncoding; |
51 | | enum class SkTileMode; |
52 | | struct SkImageInfo; |
53 | | |
54 | | namespace ToolUtils { |
55 | | |
56 | | const char* alphatype_name (SkAlphaType); |
57 | | const char* colortype_name (SkColorType); |
58 | | const char* colortype_depth(SkColorType); // like colortype_name, but channel order agnostic |
59 | | const char* tilemode_name(SkTileMode); |
60 | | |
61 | | /** |
62 | | * Map opaque colors from 8888 to 565. |
63 | | */ |
64 | | SkColor color_to_565(SkColor color); |
65 | | |
66 | | void get_text_path(const SkFont&, |
67 | | const void* text, |
68 | | size_t length, |
69 | | SkTextEncoding, |
70 | | SkPath*, |
71 | | const SkPoint* positions = nullptr); |
72 | | |
73 | | /** |
74 | | * Returns true iff all of the pixels between the two images are identical. |
75 | | * |
76 | | * If the configs differ, return false. |
77 | | */ |
78 | | bool equal_pixels(const SkPixmap&, const SkPixmap&); |
79 | | bool equal_pixels(const SkBitmap&, const SkBitmap&); |
80 | | bool equal_pixels(const SkImage* a, const SkImage* b); |
81 | | |
82 | | /** Returns a newly created CheckerboardShader. */ |
83 | | sk_sp<SkShader> create_checkerboard_shader(SkColor c1, SkColor c2, int size); |
84 | | |
85 | | /** Draw a checkerboard pattern in the current canvas, restricted to |
86 | | the current clip, using SkBlendMode::kSrc. */ |
87 | | void draw_checkerboard(SkCanvas* canvas, SkColor color1, SkColor color2, int checkSize); |
88 | | |
89 | | /** Make it easier to create a bitmap-based checkerboard */ |
90 | | SkBitmap create_checkerboard_bitmap(int w, int h, SkColor c1, SkColor c2, int checkSize); |
91 | | |
92 | | sk_sp<SkImage> create_checkerboard_image(int w, int h, SkColor c1, SkColor c2, int checkSize); |
93 | | |
94 | | /** A default checkerboard. */ |
95 | 0 | inline void draw_checkerboard(SkCanvas* canvas) { |
96 | 0 | ToolUtils::draw_checkerboard(canvas, 0xFF999999, 0xFF666666, 8); |
97 | 0 | } |
98 | | |
99 | | class HilbertGenerator { |
100 | | public: |
101 | | HilbertGenerator(float desiredSize, float desiredLineWidth, int desiredDepth); |
102 | | |
103 | | // Draw a Hilbert curve into the canvas w/ a gradient along its length |
104 | | void draw(SkCanvas* canvas); |
105 | | |
106 | | private: |
107 | | void turn90(bool turnLeft); |
108 | | void line(SkCanvas* canvas); |
109 | | void recursiveDraw(SkCanvas* canvas, int curDepth, bool turnLeft); |
110 | | SkColor4f getColor(float curLen); |
111 | | |
112 | | const float fDesiredSize; |
113 | | const int fDesiredDepth; |
114 | | const float fSegmentLength; // length of a line segment |
115 | | const float fDesiredLineWidth; |
116 | | |
117 | | SkRect fActualBounds; |
118 | | |
119 | | // The "turtle" state |
120 | | SkPoint fCurPos; |
121 | | int fCurDir; |
122 | | |
123 | | const float fExpectedLen; |
124 | | float fCurLen; |
125 | | }; |
126 | | |
127 | | /** Create pixmaps to initialize a 32x32 image w/ or w/o mipmaps. |
128 | | * Returns the number of levels (either 1 or 6). The mipmap levels will be colored as |
129 | | * specified in 'colors' |
130 | | */ |
131 | | int make_pixmaps(SkColorType, |
132 | | SkAlphaType, |
133 | | bool withMips, |
134 | | const SkColor4f colors[6], |
135 | | SkPixmap pixmaps[6], |
136 | | std::unique_ptr<char[]>* mem); |
137 | | |
138 | | // If the canvas doesn't make a surface (e.g. recording), make a raster surface |
139 | | sk_sp<SkSurface> makeSurface(SkCanvas*, const SkImageInfo&, const SkSurfaceProps* = nullptr); |
140 | | |
141 | | // A helper for inserting a drawtext call into a SkTextBlobBuilder |
142 | | void add_to_text_blob_w_len(SkTextBlobBuilder*, |
143 | | const char* text, |
144 | | size_t len, |
145 | | SkTextEncoding, |
146 | | const SkFont&, |
147 | | SkScalar x, |
148 | | SkScalar y); |
149 | | |
150 | | void add_to_text_blob(SkTextBlobBuilder*, const char* text, const SkFont&, SkScalar x, SkScalar y); |
151 | | |
152 | | // Constructs a star by walking a 'numPts'-sided regular polygon with even/odd fill: |
153 | | // |
154 | | // moveTo(pts[0]); |
155 | | // lineTo(pts[step % numPts]); |
156 | | // ... |
157 | | // lineTo(pts[(step * (N - 1)) % numPts]); |
158 | | // |
159 | | // numPts=5, step=2 will produce a classic five-point star. |
160 | | // |
161 | | // numPts and step must be co-prime. |
162 | | SkPath make_star(const SkRect& bounds, int numPts = 5, int step = 2); |
163 | | |
164 | | void create_hemi_normal_map(SkBitmap* bm, const SkIRect& dst); |
165 | | |
166 | | void create_frustum_normal_map(SkBitmap* bm, const SkIRect& dst); |
167 | | |
168 | | void create_tetra_normal_map(SkBitmap* bm, const SkIRect& dst); |
169 | | |
170 | | // A helper object to test the topological sorting code (TopoSortBench.cpp & TopoSortTest.cpp) |
171 | | class TopoTestNode : public SkRefCnt { |
172 | | public: |
173 | 0 | TopoTestNode(int id) : fID(id) {} |
174 | | |
175 | 0 | void dependsOn(TopoTestNode* src) { *fDependencies.append() = src; } |
176 | 0 | void targets(uint32_t target) { *fTargets.append() = target; } |
177 | | |
178 | 0 | int id() const { return fID; } |
179 | 0 | void reset() { |
180 | 0 | fOutputPos = 0; |
181 | 0 | fTempMark = false; |
182 | 0 | fWasOutput = false; |
183 | 0 | } |
184 | | |
185 | 0 | uint32_t outputPos() const { |
186 | 0 | SkASSERT(fWasOutput); |
187 | 0 | return fOutputPos; |
188 | 0 | } |
189 | | |
190 | | // check that the topological sort is valid for this node |
191 | 0 | bool check() { |
192 | 0 | if (!fWasOutput) { |
193 | 0 | return false; |
194 | 0 | } |
195 | 0 |
|
196 | 0 | for (int i = 0; i < fDependencies.size(); ++i) { |
197 | 0 | if (!fDependencies[i]->fWasOutput) { |
198 | 0 | return false; |
199 | 0 | } |
200 | 0 | // This node should've been output after all the nodes on which it depends |
201 | 0 | if (fOutputPos < fDependencies[i]->outputPos()) { |
202 | 0 | return false; |
203 | 0 | } |
204 | 0 | } |
205 | 0 |
|
206 | 0 | return true; |
207 | 0 | } |
208 | | |
209 | | // The following 7 methods are needed by the topological sort |
210 | 0 | static void SetTempMark(TopoTestNode* node) { node->fTempMark = true; } |
211 | 0 | static void ResetTempMark(TopoTestNode* node) { node->fTempMark = false; } |
212 | 0 | static bool IsTempMarked(TopoTestNode* node) { return node->fTempMark; } |
213 | 0 | static void Output(TopoTestNode* node, uint32_t outputPos) { |
214 | 0 | SkASSERT(!node->fWasOutput); |
215 | 0 | node->fOutputPos = outputPos; |
216 | 0 | node->fWasOutput = true; |
217 | 0 | } |
218 | 0 | static bool WasOutput(TopoTestNode* node) { return node->fWasOutput; } |
219 | 0 | static uint32_t GetIndex(TopoTestNode* node) { return node->outputPos(); } |
220 | 0 | static int NumDependencies(TopoTestNode* node) { return node->fDependencies.size(); } |
221 | 0 | static TopoTestNode* Dependency(TopoTestNode* node, int index) { |
222 | 0 | return node->fDependencies[index]; |
223 | 0 | } |
224 | 0 | static int NumTargets(TopoTestNode* node) { return node->fTargets.size(); } |
225 | 0 | static uint32_t GetTarget(TopoTestNode* node, int i) { return node->fTargets[i]; } |
226 | 0 | static uint32_t GetID(TopoTestNode* node) { return node->id(); } |
227 | | |
228 | | // Helper functions for TopoSortBench & TopoSortTest |
229 | 0 | static void AllocNodes(skia_private::TArray<sk_sp<ToolUtils::TopoTestNode>>* graph, int num) { |
230 | 0 | graph->reserve_exact(graph->size() + num); |
231 | 0 |
|
232 | 0 | for (int i = 0; i < num; ++i) { |
233 | 0 | graph->push_back(sk_sp<TopoTestNode>(new TopoTestNode(i))); |
234 | 0 | } |
235 | 0 | } |
236 | | |
237 | | #ifdef SK_DEBUG |
238 | 0 | static void Print(const skia_private::TArray<TopoTestNode*>& graph) { |
239 | 0 | for (int i = 0; i < graph.size(); ++i) { |
240 | 0 | SkDebugf("%d, ", graph[i]->id()); |
241 | 0 | } |
242 | 0 | SkDebugf("\n"); |
243 | 0 | } |
244 | | #endif |
245 | | |
246 | | // randomize the array |
247 | 0 | static void Shuffle(SkSpan<sk_sp<TopoTestNode>> graph, SkRandom* rand) { |
248 | 0 | for (size_t i = graph.size() - 1; i > 0; --i) { |
249 | 0 | int swap = rand->nextU() % (i + 1); |
250 | 0 |
|
251 | 0 | graph[i].swap(graph[swap]); |
252 | 0 | } |
253 | 0 | } |
254 | | |
255 | | SK_DECLARE_INTERNAL_LLIST_INTERFACE(TopoTestNode); |
256 | | |
257 | | private: |
258 | | int fID; |
259 | | uint32_t fOutputPos = 0; |
260 | | bool fTempMark = false; |
261 | | bool fWasOutput = false; |
262 | | |
263 | | SkTDArray<TopoTestNode*> fDependencies; |
264 | | SkTDArray<uint32_t> fTargets; |
265 | | }; |
266 | | |
267 | | bool copy_to(SkBitmap* dst, SkColorType dstCT, const SkBitmap& src); |
268 | | void copy_to_g8(SkBitmap* dst, const SkBitmap& src); |
269 | | |
270 | | class PixelIter { |
271 | | public: |
272 | | PixelIter(); |
273 | 0 | PixelIter(SkSurface* surf) { |
274 | 0 | SkPixmap pm; |
275 | 0 | if (!surf->peekPixels(&pm)) { |
276 | 0 | pm.reset(); |
277 | 0 | } |
278 | 0 | this->reset(pm); |
279 | 0 | } |
280 | | |
281 | 0 | void reset(const SkPixmap& pm) { |
282 | 0 | fPM = pm; |
283 | 0 | fLoc = {-1, 0}; |
284 | 0 | } |
285 | | |
286 | 0 | void* next(SkIPoint* loc = nullptr) { |
287 | 0 | if (!fPM.addr()) { |
288 | 0 | return nullptr; |
289 | 0 | } |
290 | 0 | fLoc.fX += 1; |
291 | 0 | if (fLoc.fX >= fPM.width()) { |
292 | 0 | fLoc.fX = 0; |
293 | 0 | if (++fLoc.fY >= fPM.height()) { |
294 | 0 | this->setDone(); |
295 | 0 | return nullptr; |
296 | 0 | } |
297 | 0 | } |
298 | 0 | if (loc) { |
299 | 0 | *loc = fLoc; |
300 | 0 | } |
301 | 0 | return fPM.writable_addr(fLoc.fX, fLoc.fY); |
302 | 0 | } |
303 | | |
304 | 0 | void setDone() { fPM.reset(); } |
305 | | |
306 | | private: |
307 | | SkPixmap fPM; |
308 | | SkIPoint fLoc; |
309 | | }; |
310 | | |
311 | | using PathSniffCallback = void(const SkMatrix&, const SkPath&, const SkPaint&); |
312 | | |
313 | | // Calls the provided PathSniffCallback for each path in the given file. |
314 | | // Supported file formats .skp. (See SvgPathExtractor for .svg) |
315 | | void ExtractPathsFromSKP(const char filepath[], std::function<PathSniffCallback>); |
316 | | |
317 | | // Initialised with a font, this class can be called to setup GM UI with sliders for font |
318 | | // variations, and returns a set of variation coordinates that matches what the sliders in the UI |
319 | | // are set to. Useful for testing variable font properties, see colrv1.cpp. |
320 | | class VariationSliders { |
321 | | public: |
322 | 0 | VariationSliders() {} |
323 | | |
324 | | VariationSliders(SkTypeface*, |
325 | | SkFontArguments::VariationPosition variationPosition = {nullptr, 0}); |
326 | | |
327 | | bool writeControls(SkMetaData* controls); |
328 | | |
329 | | /* Scans controls for information about the variation axes that the user may have configured. |
330 | | * Optionally pass in a boolean to receive information on whether the axes were updated. */ |
331 | | void readControls(const SkMetaData& controls, bool* changed = nullptr); |
332 | | |
333 | | SkSpan<const SkFontArguments::VariationPosition::Coordinate> getCoordinates(); |
334 | | |
335 | | static SkString tagToString(SkFourByteTag tag); |
336 | | |
337 | | private: |
338 | | struct AxisSlider { |
339 | | SkScalar current; |
340 | | SkFontParameters::Variation::Axis axis; |
341 | | SkString name; |
342 | | }; |
343 | | |
344 | | std::vector<AxisSlider> fAxisSliders; |
345 | | std::unique_ptr<SkFontArguments::VariationPosition::Coordinate[]> fCoords; |
346 | | static constexpr size_t kAxisVarsSize = 3; |
347 | | }; |
348 | | |
349 | | } // namespace ToolUtils |
350 | | |
351 | | #endif // ToolUtils_DEFINED |