2 * Copyright © 2017 Google, Inc.
4 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
24 * Google Author(s): Behdad Esfahbod
30 #include "hb-private.hh"
38 _hb_debug (unsigned int level,
39 unsigned int max_level)
41 return level < max_level;
44 #define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
45 #define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
48 _hb_print_func (const char *func)
52 unsigned int func_len = strlen (func);
54 if (0 == strncmp (func, "static ", 7))
57 if (0 == strncmp (func, "typename ", 9))
59 /* Skip return type */
60 const char *space = strchr (func, ' ');
63 /* Skip parameter list */
64 const char *paren = strchr (func, '(');
66 func_len = paren - func;
67 fprintf (stderr, "%.*s", func_len, func);
71 template <int max_level> static inline void
72 _hb_debug_msg_va (const char *what,
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,
90 if (!_hb_debug (level, max_level))
93 fprintf (stderr, "%-10s", what ? what : "");
96 fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj);
98 fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), "");
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, "%2u %s" VRBAR "%s",
114 bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
115 level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
117 fprintf (stderr, " " VRBAR LBAR);
119 _hb_print_func (func);
123 fprintf (stderr, ": ");
124 vfprintf (stderr, message, ap);
127 fprintf (stderr, "\n");
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) {}
139 template <int max_level> static inline void
140 _hb_debug_msg (const char *what,
147 ...) HB_PRINTF_FUNC(7, 8);
148 template <int max_level> static inline void
149 _hb_debug_msg (const char *what,
159 va_start (ap, message);
160 _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
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,
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__)
191 template <typename T>
192 struct hb_printer_t {
193 const char *print (const T&) { return "something"; }
197 struct hb_printer_t<bool> {
198 const char *print (bool v) { return v ? "true" : "false"; }
202 struct hb_printer_t<hb_void_t> {
203 const char *print (hb_void_t) { return ""; }
211 template <typename T>
212 static inline void _hb_warn_no_return (bool returned)
214 if (unlikely (!returned)) {
215 fprintf (stderr, "OUCH, returned with no call to return_trace(). This is a bug, please report.\n");
219 /*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
222 template <int max_level, typename ret_t>
223 struct hb_auto_trace_t
225 explicit inline hb_auto_trace_t (unsigned int *plevel_,
230 ...) HB_PRINTF_FUNC(6, 7)
231 : plevel (plevel_), what (what_), obj (obj_), returned (false)
233 if (plevel) ++*plevel;
236 va_start (ap, message);
237 _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
240 inline ~hb_auto_trace_t (void)
242 _hb_warn_no_return<ret_t> (returned);
244 _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, " ");
246 if (plevel) --*plevel;
249 inline ret_t ret (ret_t v, unsigned int line = 0)
251 if (unlikely (returned)) {
252 fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n");
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;
266 unsigned int *plevel;
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>
274 explicit inline hb_auto_trace_t (unsigned int *plevel_,
279 ...) HB_PRINTF_FUNC(6, 7) {}
281 inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
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; }
291 #define return_trace(RET) return trace.ret (RET, __LINE__)
298 #ifndef HB_DEBUG_ARABIC
299 #define HB_DEBUG_ARABIC (HB_DEBUG+0)
302 #ifndef HB_DEBUG_BLOB
303 #define HB_DEBUG_BLOB (HB_DEBUG+0)
306 #ifndef HB_DEBUG_CORETEXT
307 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
310 #ifndef HB_DEBUG_DIRECTWRITE
311 #define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
315 #define HB_DEBUG_FT (HB_DEBUG+0)
318 #ifndef HB_DEBUG_GET_COVERAGE
319 #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
322 #ifndef HB_DEBUG_OBJECT
323 #define HB_DEBUG_OBJECT (HB_DEBUG+0)
326 #ifndef HB_DEBUG_SHAPE_PLAN
327 #define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
330 #ifndef HB_DEBUG_UNISCRIBE
331 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
338 #ifndef HB_DEBUG_APPLY
339 #define HB_DEBUG_APPLY (HB_DEBUG+0)
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)
348 #define TRACE_APPLY(this) hb_no_trace_t<bool> trace
351 #ifndef HB_DEBUG_CLOSURE
352 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
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, \
360 #define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
363 #ifndef HB_DEBUG_COLLECT_GLYPHS
364 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
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, \
372 #define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
375 #ifndef HB_DEBUG_SANITIZE
376 #define HB_DEBUG_SANITIZE (HB_DEBUG+0)
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, \
384 #define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
387 #ifndef HB_DEBUG_SERIALIZE
388 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
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, \
396 #define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
399 #ifndef HB_DEBUG_SUBSET
400 #define HB_DEBUG_SUBSET (HB_DEBUG+0)
403 #define TRACE_SUBSET(this) \
404 hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace \
405 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
408 #define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
411 #ifndef HB_DEBUG_WOULD_APPLY
412 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
414 #if HB_DEBUG_WOULD_APPLY
415 #define TRACE_WOULD_APPLY(this) \
416 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
417 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
418 "%d glyphs", c->len);
420 #define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
423 #ifndef HB_DEBUG_DISPATCH
424 #define HB_DEBUG_DISPATCH ( \
427 HB_DEBUG_COLLECT_GLYPHS + \
428 HB_DEBUG_SANITIZE + \
429 HB_DEBUG_SERIALIZE + \
431 HB_DEBUG_WOULD_APPLY + \
434 #if HB_DEBUG_DISPATCH
435 #define TRACE_DISPATCH(this, format) \
436 hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
437 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
438 "format %d", (int) format);
440 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
444 #endif /* HB_DEBUG_HH */