xref: /aosp_15_r20/external/skia/tools/ToolUtils.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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. */
draw_checkerboard(SkCanvas * canvas)95 inline void draw_checkerboard(SkCanvas* canvas) {
96     ToolUtils::draw_checkerboard(canvas, 0xFF999999, 0xFF666666, 8);
97 }
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:
TopoTestNode(int id)173     TopoTestNode(int id) : fID(id) {}
174 
dependsOn(TopoTestNode * src)175     void dependsOn(TopoTestNode* src) { *fDependencies.append() = src; }
targets(uint32_t target)176     void targets(uint32_t target) { *fTargets.append() = target; }
177 
id()178     int  id() const { return fID; }
reset()179     void reset() {
180         fOutputPos = 0;
181         fTempMark = false;
182         fWasOutput = false;
183     }
184 
outputPos()185     uint32_t outputPos() const {
186         SkASSERT(fWasOutput);
187         return fOutputPos;
188     }
189 
190     // check that the topological sort is valid for this node
check()191     bool check() {
192         if (!fWasOutput) {
193             return false;
194         }
195 
196         for (int i = 0; i < fDependencies.size(); ++i) {
197             if (!fDependencies[i]->fWasOutput) {
198                 return false;
199             }
200             // This node should've been output after all the nodes on which it depends
201             if (fOutputPos < fDependencies[i]->outputPos()) {
202                 return false;
203             }
204         }
205 
206         return true;
207     }
208 
209     // The following 7 methods are needed by the topological sort
SetTempMark(TopoTestNode * node)210     static void SetTempMark(TopoTestNode* node) { node->fTempMark = true; }
ResetTempMark(TopoTestNode * node)211     static void ResetTempMark(TopoTestNode* node) { node->fTempMark = false; }
IsTempMarked(TopoTestNode * node)212     static bool IsTempMarked(TopoTestNode* node) { return node->fTempMark; }
Output(TopoTestNode * node,uint32_t outputPos)213     static void Output(TopoTestNode* node, uint32_t outputPos) {
214         SkASSERT(!node->fWasOutput);
215         node->fOutputPos = outputPos;
216         node->fWasOutput = true;
217     }
WasOutput(TopoTestNode * node)218     static bool          WasOutput(TopoTestNode* node) { return node->fWasOutput; }
GetIndex(TopoTestNode * node)219     static uint32_t      GetIndex(TopoTestNode* node) { return node->outputPos(); }
NumDependencies(TopoTestNode * node)220     static int           NumDependencies(TopoTestNode* node) { return node->fDependencies.size(); }
Dependency(TopoTestNode * node,int index)221     static TopoTestNode* Dependency(TopoTestNode* node, int index) {
222         return node->fDependencies[index];
223     }
NumTargets(TopoTestNode * node)224     static int           NumTargets(TopoTestNode* node) { return node->fTargets.size(); }
GetTarget(TopoTestNode * node,int i)225     static uint32_t      GetTarget(TopoTestNode* node, int i) { return node->fTargets[i]; }
GetID(TopoTestNode * node)226     static uint32_t      GetID(TopoTestNode* node) { return node->id(); }
227 
228     // Helper functions for TopoSortBench & TopoSortTest
AllocNodes(skia_private::TArray<sk_sp<ToolUtils::TopoTestNode>> * graph,int num)229     static void AllocNodes(skia_private::TArray<sk_sp<ToolUtils::TopoTestNode>>* graph, int num) {
230         graph->reserve_exact(graph->size() + num);
231 
232         for (int i = 0; i < num; ++i) {
233             graph->push_back(sk_sp<TopoTestNode>(new TopoTestNode(i)));
234         }
235     }
236 
237 #ifdef SK_DEBUG
Print(const skia_private::TArray<TopoTestNode * > & graph)238     static void Print(const skia_private::TArray<TopoTestNode*>& graph) {
239         for (int i = 0; i < graph.size(); ++i) {
240             SkDebugf("%d, ", graph[i]->id());
241         }
242         SkDebugf("\n");
243     }
244 #endif
245 
246     // randomize the array
Shuffle(SkSpan<sk_sp<TopoTestNode>> graph,SkRandom * rand)247     static void Shuffle(SkSpan<sk_sp<TopoTestNode>> graph, SkRandom* rand) {
248         for (size_t i = graph.size() - 1; i > 0; --i) {
249             int swap = rand->nextU() % (i + 1);
250 
251             graph[i].swap(graph[swap]);
252         }
253     }
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();
PixelIter(SkSurface * surf)273     PixelIter(SkSurface* surf) {
274         SkPixmap pm;
275         if (!surf->peekPixels(&pm)) {
276             pm.reset();
277         }
278         this->reset(pm);
279     }
280 
reset(const SkPixmap & pm)281     void reset(const SkPixmap& pm) {
282         fPM  = pm;
283         fLoc = {-1, 0};
284     }
285 
286     void* next(SkIPoint* loc = nullptr) {
287         if (!fPM.addr()) {
288             return nullptr;
289         }
290         fLoc.fX += 1;
291         if (fLoc.fX >= fPM.width()) {
292             fLoc.fX = 0;
293             if (++fLoc.fY >= fPM.height()) {
294                 this->setDone();
295                 return nullptr;
296             }
297         }
298         if (loc) {
299             *loc = fLoc;
300         }
301         return fPM.writable_addr(fLoc.fX, fLoc.fY);
302     }
303 
setDone()304     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:
VariationSliders()322     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
352