1 | /* |
2 | * Copyright © 2017 Google, Inc. |
3 | * |
4 | * This is part of HarfBuzz, a text shaping library. |
5 | * |
6 | * Permission is hereby granted, without written agreement and without |
7 | * license or royalty fees, to use, copy, modify, and distribute this |
8 | * software and its documentation for any purpose, provided that the |
9 | * above copyright notice and the following two paragraphs appear in |
10 | * all copies of this software. |
11 | * |
12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | * DAMAGE. |
17 | * |
18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | * |
24 | * Google Author(s): Behdad Esfahbod |
25 | */ |
26 | |
27 | #ifndef HB_DEBUG_HH |
28 | #define HB_DEBUG_HH |
29 | |
30 | #include "hb-private.hh" |
31 | |
32 | |
33 | #ifndef HB_DEBUG |
34 | #define HB_DEBUG 0 |
35 | #endif |
36 | |
37 | static inline bool |
38 | _hb_debug (unsigned int level, |
39 | unsigned int max_level) |
40 | { |
41 | return level < max_level; |
42 | } |
43 | |
44 | #define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT)) |
45 | #define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0)) |
46 | |
47 | static inline void |
48 | _hb_print_func (const char *func) |
49 | { |
50 | if (func) |
51 | { |
52 | unsigned int func_len = strlen (s: func); |
53 | /* Skip "static" */ |
54 | if (0 == strncmp (s1: func, s2: "static " , n: 7)) |
55 | func += 7; |
56 | /* Skip "typename" */ |
57 | if (0 == strncmp (s1: func, s2: "typename " , n: 9)) |
58 | func += 9; |
59 | /* Skip return type */ |
60 | const char *space = strchr (s: func, c: ' '); |
61 | if (space) |
62 | func = space + 1; |
63 | /* Skip parameter list */ |
64 | const char *paren = strchr (s: func, c: '('); |
65 | if (paren) |
66 | func_len = paren - func; |
67 | fprintf (stderr, format: "%.*s" , func_len, func); |
68 | } |
69 | } |
70 | |
71 | template <int max_level> static inline void |
72 | _hb_debug_msg_va (const char *what, |
73 | const void *obj, |
74 | const char *func, |
75 | bool indented, |
76 | unsigned int level, |
77 | int level_dir, |
78 | const char *message, |
79 | va_list ap) HB_PRINTF_FUNC(7, 0); |
80 | template <int max_level> static inline void |
81 | _hb_debug_msg_va (const char *what, |
82 | const void *obj, |
83 | const char *func, |
84 | bool indented, |
85 | unsigned int level, |
86 | int level_dir, |
87 | const char *message, |
88 | va_list ap) |
89 | { |
90 | if (!_hb_debug (level, max_level)) |
91 | return; |
92 | |
93 | fprintf (stderr, format: "%-10s" , what ? what : "" ); |
94 | |
95 | if (obj) |
96 | fprintf (stderr, format: "(%*p) " , (unsigned int) (2 * sizeof (void *)), obj); |
97 | else |
98 | fprintf (stderr, format: " %*s " , (unsigned int) (2 * sizeof (void *)), "" ); |
99 | |
100 | if (indented) { |
101 | #define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */ |
102 | #define VRBAR "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ |
103 | #define DLBAR "\342\225\256" /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */ |
104 | #define ULBAR "\342\225\257" /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */ |
105 | #define LBAR "\342\225\264" /* U+2574 BOX DRAWINGS LIGHT LEFT */ |
106 | static const char bars[] = |
107 | VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR |
108 | VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR |
109 | VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR |
110 | VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR |
111 | VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR; |
112 | fprintf (stderr, format: "%2u %s" VRBAR "%s" , |
113 | level, |
114 | bars + sizeof (bars) - 1 - MIN (a: (unsigned int) sizeof (bars) - 1, b: (unsigned int) (sizeof (VBAR) - 1) * level), |
115 | level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR); |
116 | } else |
117 | fprintf (stderr, format: " " VRBAR LBAR); |
118 | |
119 | _hb_print_func (func); |
120 | |
121 | if (message) |
122 | { |
123 | fprintf (stderr, format: ": " ); |
124 | vfprintf (stderr, format: message, arg: ap); |
125 | } |
126 | |
127 | fprintf (stderr, format: "\n" ); |
128 | } |
129 | template <> inline void |
130 | _hb_debug_msg_va<0> (const char *what HB_UNUSED, |
131 | const void *obj HB_UNUSED, |
132 | const char *func HB_UNUSED, |
133 | bool indented HB_UNUSED, |
134 | unsigned int level HB_UNUSED, |
135 | int level_dir HB_UNUSED, |
136 | const char *message HB_UNUSED, |
137 | va_list ap HB_UNUSED) {} |
138 | |
139 | template <int max_level> static inline void |
140 | _hb_debug_msg (const char *what, |
141 | const void *obj, |
142 | const char *func, |
143 | bool indented, |
144 | unsigned int level, |
145 | int level_dir, |
146 | const char *message, |
147 | ...) HB_PRINTF_FUNC(7, 8); |
148 | template <int max_level> static inline void |
149 | _hb_debug_msg (const char *what, |
150 | const void *obj, |
151 | const char *func, |
152 | bool indented, |
153 | unsigned int level, |
154 | int level_dir, |
155 | const char *message, |
156 | ...) |
157 | { |
158 | va_list ap; |
159 | va_start (ap, message); |
160 | _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap); |
161 | va_end (ap); |
162 | } |
163 | template <> inline void |
164 | _hb_debug_msg<0> (const char *what HB_UNUSED, |
165 | const void *obj HB_UNUSED, |
166 | const char *func HB_UNUSED, |
167 | bool indented HB_UNUSED, |
168 | unsigned int level HB_UNUSED, |
169 | int level_dir HB_UNUSED, |
170 | const char *message HB_UNUSED, |
171 | ...) HB_PRINTF_FUNC(7, 8); |
172 | template <> inline void |
173 | _hb_debug_msg<0> (const char *what HB_UNUSED, |
174 | const void *obj HB_UNUSED, |
175 | const char *func HB_UNUSED, |
176 | bool indented HB_UNUSED, |
177 | unsigned int level HB_UNUSED, |
178 | int level_dir HB_UNUSED, |
179 | const char *message HB_UNUSED, |
180 | ...) {} |
181 | |
182 | #define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr, true, (LEVEL), (LEVEL_DIR), __VA_ARGS__) |
183 | #define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr, false, 0, 0, __VA_ARGS__) |
184 | #define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__) |
185 | |
186 | |
187 | /* |
188 | * Printer |
189 | */ |
190 | |
191 | template <typename T> |
192 | struct hb_printer_t { |
193 | const char *print (const T&) { return "something" ; } |
194 | }; |
195 | |
196 | template <> |
197 | struct hb_printer_t<bool> { |
198 | const char *print (bool v) { return v ? "true" : "false" ; } |
199 | }; |
200 | |
201 | template <> |
202 | struct hb_printer_t<hb_void_t> { |
203 | const char *print (hb_void_t) { return "" ; } |
204 | }; |
205 | |
206 | |
207 | /* |
208 | * Trace |
209 | */ |
210 | |
211 | template <typename T> |
212 | static inline void _hb_warn_no_return (bool returned) |
213 | { |
214 | if (unlikely (!returned)) { |
215 | fprintf (stderr, format: "OUCH, returned with no call to return_trace(). This is a bug, please report.\n" ); |
216 | } |
217 | } |
218 | template <> |
219 | /*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED) |
220 | {} |
221 | |
222 | template <int max_level, typename ret_t> |
223 | struct hb_auto_trace_t |
224 | { |
225 | explicit inline hb_auto_trace_t (unsigned int *plevel_, |
226 | const char *what_, |
227 | const void *obj_, |
228 | const char *func, |
229 | const char *message, |
230 | ...) HB_PRINTF_FUNC(6, 7) |
231 | : plevel (plevel_), what (what_), obj (obj_), returned (false) |
232 | { |
233 | if (plevel) ++*plevel; |
234 | |
235 | va_list ap; |
236 | va_start (ap, message); |
237 | _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap); |
238 | va_end (ap); |
239 | } |
240 | inline ~hb_auto_trace_t (void) |
241 | { |
242 | _hb_warn_no_return<ret_t> (returned); |
243 | if (!returned) { |
244 | _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, " " ); |
245 | } |
246 | if (plevel) --*plevel; |
247 | } |
248 | |
249 | inline ret_t ret (ret_t v, unsigned int line = 0) |
250 | { |
251 | if (unlikely (returned)) { |
252 | fprintf (stderr, format: "OUCH, double calls to return_trace(). This is a bug, please report.\n" ); |
253 | return v; |
254 | } |
255 | |
256 | _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, |
257 | "return %s (line %d)" , |
258 | hb_printer_t<ret_t>().print (v), line); |
259 | if (plevel) --*plevel; |
260 | plevel = nullptr; |
261 | returned = true; |
262 | return v; |
263 | } |
264 | |
265 | private: |
266 | unsigned int *plevel; |
267 | const char *what; |
268 | const void *obj; |
269 | bool returned; |
270 | }; |
271 | template <typename ret_t> /* Make sure we don't use hb_auto_trace_t when not tracing. */ |
272 | struct hb_auto_trace_t<0, ret_t> |
273 | { |
274 | explicit inline hb_auto_trace_t (unsigned int *plevel_, |
275 | const char *what_, |
276 | const void *obj_, |
277 | const char *func, |
278 | const char *message, |
279 | ...) HB_PRINTF_FUNC(6, 7) {} |
280 | |
281 | inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; } |
282 | }; |
283 | |
284 | /* For disabled tracing; optimize out everything. |
285 | * https://github.com/harfbuzz/harfbuzz/pull/605 */ |
286 | template <typename ret_t> |
287 | struct hb_no_trace_t { |
288 | inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; } |
289 | }; |
290 | |
291 | #define return_trace(RET) return trace.ret (RET, __LINE__) |
292 | |
293 | |
294 | /* |
295 | * Instances. |
296 | */ |
297 | |
298 | #ifndef HB_DEBUG_ARABIC |
299 | #define HB_DEBUG_ARABIC (HB_DEBUG+0) |
300 | #endif |
301 | |
302 | #ifndef HB_DEBUG_BLOB |
303 | #define HB_DEBUG_BLOB (HB_DEBUG+0) |
304 | #endif |
305 | |
306 | #ifndef HB_DEBUG_CORETEXT |
307 | #define HB_DEBUG_CORETEXT (HB_DEBUG+0) |
308 | #endif |
309 | |
310 | #ifndef HB_DEBUG_DIRECTWRITE |
311 | #define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0) |
312 | #endif |
313 | |
314 | #ifndef HB_DEBUG_FT |
315 | #define HB_DEBUG_FT (HB_DEBUG+0) |
316 | #endif |
317 | |
318 | #ifndef HB_DEBUG_GET_COVERAGE |
319 | #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0) |
320 | #endif |
321 | |
322 | #ifndef HB_DEBUG_OBJECT |
323 | #define HB_DEBUG_OBJECT (HB_DEBUG+0) |
324 | #endif |
325 | |
326 | #ifndef HB_DEBUG_SHAPE_PLAN |
327 | #define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0) |
328 | #endif |
329 | |
330 | #ifndef HB_DEBUG_UNISCRIBE |
331 | #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) |
332 | #endif |
333 | |
334 | /* |
335 | * With tracing. |
336 | */ |
337 | |
338 | #ifndef HB_DEBUG_APPLY |
339 | #define HB_DEBUG_APPLY (HB_DEBUG+0) |
340 | #endif |
341 | #if HB_DEBUG_APPLY |
342 | #define TRACE_APPLY(this) \ |
343 | hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ |
344 | (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
345 | "idx %d gid %u lookup %d", \ |
346 | c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index) |
347 | #else |
348 | #define TRACE_APPLY(this) hb_no_trace_t<bool> trace |
349 | #endif |
350 | |
351 | #ifndef HB_DEBUG_CLOSURE |
352 | #define HB_DEBUG_CLOSURE (HB_DEBUG+0) |
353 | #endif |
354 | #if HB_DEBUG_CLOSURE |
355 | #define TRACE_CLOSURE(this) \ |
356 | hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \ |
357 | (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
358 | " ") |
359 | #else |
360 | #define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED |
361 | #endif |
362 | |
363 | #ifndef HB_DEBUG_COLLECT_GLYPHS |
364 | #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0) |
365 | #endif |
366 | #if HB_DEBUG_COLLECT_GLYPHS |
367 | #define TRACE_COLLECT_GLYPHS(this) \ |
368 | hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \ |
369 | (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
370 | " ") |
371 | #else |
372 | #define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED |
373 | #endif |
374 | |
375 | #ifndef HB_DEBUG_SANITIZE |
376 | #define HB_DEBUG_SANITIZE (HB_DEBUG+0) |
377 | #endif |
378 | #if HB_DEBUG_SANITIZE |
379 | #define TRACE_SANITIZE(this) \ |
380 | hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \ |
381 | (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
382 | " "); |
383 | #else |
384 | #define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace |
385 | #endif |
386 | |
387 | #ifndef HB_DEBUG_SERIALIZE |
388 | #define HB_DEBUG_SERIALIZE (HB_DEBUG+0) |
389 | #endif |
390 | #if HB_DEBUG_SERIALIZE |
391 | #define TRACE_SERIALIZE(this) \ |
392 | hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \ |
393 | (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \ |
394 | " "); |
395 | #else |
396 | #define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace |
397 | #endif |
398 | |
399 | #ifndef HB_DEBUG_WOULD_APPLY |
400 | #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) |
401 | #endif |
402 | #if HB_DEBUG_WOULD_APPLY |
403 | #define TRACE_WOULD_APPLY(this) \ |
404 | hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \ |
405 | (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
406 | "%d glyphs", c->len); |
407 | #else |
408 | #define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace |
409 | #endif |
410 | |
411 | #ifndef HB_DEBUG_DISPATCH |
412 | #define HB_DEBUG_DISPATCH ( \ |
413 | HB_DEBUG_APPLY + \ |
414 | HB_DEBUG_CLOSURE + \ |
415 | HB_DEBUG_COLLECT_GLYPHS + \ |
416 | HB_DEBUG_SANITIZE + \ |
417 | HB_DEBUG_SERIALIZE + \ |
418 | HB_DEBUG_WOULD_APPLY + \ |
419 | 0) |
420 | #endif |
421 | #if HB_DEBUG_DISPATCH |
422 | #define TRACE_DISPATCH(this, format) \ |
423 | hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ |
424 | (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
425 | "format %d", (int) format); |
426 | #else |
427 | #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace |
428 | #endif |
429 | |
430 | |
431 | #endif /* HB_DEBUG_HH */ |
432 | |