• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.hh"
31 #include "hb-atomic.hh"
32 #include "hb-dsalgs.hh"
33 
34 
35 #ifndef HB_DEBUG
36 #define HB_DEBUG 0
37 #endif
38 
39 
40 /*
41  * Global runtime options.
42  */
43 
44 struct hb_options_t
45 {
46   bool unused : 1; /* In-case sign bit is here. */
47   bool initialized : 1;
48   bool uniscribe_bug_compatible : 1;
49   bool aat : 1;
50 };
51 
52 union hb_options_union_t {
53   int i;
54   hb_options_t opts;
55 };
56 static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), "");
57 
58 HB_INTERNAL void
59 _hb_options_init ();
60 
61 extern HB_INTERNAL hb_atomic_int_t _hb_options;
62 
63 static inline hb_options_t
hb_options()64 hb_options ()
65 {
66   /* Make a local copy, so we can access bitfield threadsafely. */
67   hb_options_union_t u;
68   u.i = _hb_options.get_relaxed ();
69 
70   if (unlikely (!u.i))
71   {
72     _hb_options_init ();
73     u.i = _hb_options.get_relaxed ();
74   }
75 
76   return u.opts;
77 }
78 
79 
80 /*
81  * Debug output (needs enabling at compile time.)
82  */
83 
84 static inline bool
_hb_debug(unsigned int level,unsigned int max_level)85 _hb_debug (unsigned int level,
86 	   unsigned int max_level)
87 {
88   return level < max_level;
89 }
90 
91 #define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
92 #define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
93 
94 static inline void
_hb_print_func(const char * func)95 _hb_print_func (const char *func)
96 {
97   if (func)
98   {
99     unsigned int func_len = strlen (func);
100     /* Skip "static" */
101     if (0 == strncmp (func, "static ", 7))
102       func += 7;
103     /* Skip "typename" */
104     if (0 == strncmp (func, "typename ", 9))
105       func += 9;
106     /* Skip return type */
107     const char *space = strchr (func, ' ');
108     if (space)
109       func = space + 1;
110     /* Skip parameter list */
111     const char *paren = strchr (func, '(');
112     if (paren)
113       func_len = paren - func;
114     fprintf (stderr, "%.*s", func_len, func);
115   }
116 }
117 
118 template <int max_level> static inline void
119 _hb_debug_msg_va (const char *what,
120 		  const void *obj,
121 		  const char *func,
122 		  bool indented,
123 		  unsigned int level,
124 		  int level_dir,
125 		  const char *message,
126 		  va_list ap) HB_PRINTF_FUNC(7, 0);
127 template <int max_level> static inline void
_hb_debug_msg_va(const char * what,const void * obj,const char * func,bool indented,unsigned int level,int level_dir,const char * message,va_list ap)128 _hb_debug_msg_va (const char *what,
129 		  const void *obj,
130 		  const char *func,
131 		  bool indented,
132 		  unsigned int level,
133 		  int level_dir,
134 		  const char *message,
135 		  va_list ap)
136 {
137   if (!_hb_debug (level, max_level))
138     return;
139 
140   fprintf (stderr, "%-10s", what ? what : "");
141 
142   if (obj)
143     fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj);
144   else
145     fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");
146 
147   if (indented) {
148 #define VBAR	"\342\224\202"	/* U+2502 BOX DRAWINGS LIGHT VERTICAL */
149 #define VRBAR	"\342\224\234"	/* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
150 #define DLBAR	"\342\225\256"	/* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */
151 #define ULBAR	"\342\225\257"	/* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */
152 #define LBAR	"\342\225\264"	/* U+2574 BOX DRAWINGS LIGHT LEFT */
153     static const char bars[] =
154       VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
155       VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
156       VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
157       VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR
158       VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
159     fprintf (stderr, "%2u %s" VRBAR "%s",
160 	     level,
161 	     bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
162 	     level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
163   } else
164     fprintf (stderr, "   " VRBAR LBAR);
165 
166   _hb_print_func (func);
167 
168   if (message)
169   {
170     fprintf (stderr, ": ");
171     vfprintf (stderr, message, ap);
172   }
173 
174   fprintf (stderr, "\n");
175 }
176 template <> inline void HB_PRINTF_FUNC(7, 0)
_hb_debug_msg_va(const char * what HB_UNUSED,const void * obj HB_UNUSED,const char * func HB_UNUSED,bool indented HB_UNUSED,unsigned int level HB_UNUSED,int level_dir HB_UNUSED,const char * message HB_UNUSED,va_list ap HB_UNUSED)177 _hb_debug_msg_va<0> (const char *what HB_UNUSED,
178 		     const void *obj HB_UNUSED,
179 		     const char *func HB_UNUSED,
180 		     bool indented HB_UNUSED,
181 		     unsigned int level HB_UNUSED,
182 		     int level_dir HB_UNUSED,
183 		     const char *message HB_UNUSED,
184 		     va_list ap HB_UNUSED) {}
185 
186 template <int max_level> static inline void
187 _hb_debug_msg (const char *what,
188 	       const void *obj,
189 	       const char *func,
190 	       bool indented,
191 	       unsigned int level,
192 	       int level_dir,
193 	       const char *message,
194 	       ...) HB_PRINTF_FUNC(7, 8);
195 template <int max_level> static inline void HB_PRINTF_FUNC(7, 8)
_hb_debug_msg(const char * what,const void * obj,const char * func,bool indented,unsigned int level,int level_dir,const char * message,...)196 _hb_debug_msg (const char *what,
197 	       const void *obj,
198 	       const char *func,
199 	       bool indented,
200 	       unsigned int level,
201 	       int level_dir,
202 	       const char *message,
203 	       ...)
204 {
205   va_list ap;
206   va_start (ap, message);
207   _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap);
208   va_end (ap);
209 }
210 template <> inline void
211 _hb_debug_msg<0> (const char *what HB_UNUSED,
212 		  const void *obj HB_UNUSED,
213 		  const char *func HB_UNUSED,
214 		  bool indented HB_UNUSED,
215 		  unsigned int level HB_UNUSED,
216 		  int level_dir HB_UNUSED,
217 		  const char *message HB_UNUSED,
218 		  ...) HB_PRINTF_FUNC(7, 8);
219 template <> inline void HB_PRINTF_FUNC(7, 8)
_hb_debug_msg(const char * what HB_UNUSED,const void * obj HB_UNUSED,const char * func HB_UNUSED,bool indented HB_UNUSED,unsigned int level HB_UNUSED,int level_dir HB_UNUSED,const char * message HB_UNUSED,...)220 _hb_debug_msg<0> (const char *what HB_UNUSED,
221 		  const void *obj HB_UNUSED,
222 		  const char *func HB_UNUSED,
223 		  bool indented HB_UNUSED,
224 		  unsigned int level HB_UNUSED,
225 		  int level_dir HB_UNUSED,
226 		  const char *message HB_UNUSED,
227 		  ...) {}
228 
229 #define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...)	_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr,    true, (LEVEL), (LEVEL_DIR), __VA_ARGS__)
230 #define DEBUG_MSG(WHAT, OBJ, ...) 				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr,    false, 0, 0, __VA_ARGS__)
231 #define DEBUG_MSG_FUNC(WHAT, OBJ, ...)				_hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__)
232 
233 
234 /*
235  * Printer
236  */
237 
238 template <typename T>
239 struct hb_printer_t {
printhb_printer_t240   const char *print (const T&) { return "something"; }
241 };
242 
243 template <>
244 struct hb_printer_t<bool> {
printhb_printer_t245   const char *print (bool v) { return v ? "true" : "false"; }
246 };
247 
248 template <>
249 struct hb_printer_t<hb_void_t> {
printhb_printer_t250   const char *print (hb_void_t) { return ""; }
251 };
252 
253 
254 /*
255  * Trace
256  */
257 
258 template <typename T>
_hb_warn_no_return(bool returned)259 static inline void _hb_warn_no_return (bool returned)
260 {
261   if (unlikely (!returned)) {
262     fprintf (stderr, "OUCH, returned with no call to return_trace().  This is a bug, please report.\n");
263   }
264 }
265 template <>
_hb_warn_no_return(bool returned HB_UNUSED)266 /*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
267 {}
268 
269 template <int max_level, typename ret_t>
270 struct hb_auto_trace_t
271 {
hb_auto_trace_thb_auto_trace_t272   explicit inline hb_auto_trace_t (unsigned int *plevel_,
273 				   const char *what_,
274 				   const void *obj_,
275 				   const char *func,
276 				   const char *message,
277 				   ...) HB_PRINTF_FUNC(6, 7)
278 				   : plevel (plevel_), what (what_), obj (obj_), returned (false)
279   {
280     if (plevel) ++*plevel;
281 
282     va_list ap;
283     va_start (ap, message);
284     _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
285     va_end (ap);
286   }
~hb_auto_trace_thb_auto_trace_t287   ~hb_auto_trace_t ()
288   {
289     _hb_warn_no_return<ret_t> (returned);
290     if (!returned) {
291       _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, " ");
292     }
293     if (plevel) --*plevel;
294   }
295 
rethb_auto_trace_t296   ret_t ret (ret_t v,
297 	     const char *func = "",
298 	     unsigned int line = 0)
299   {
300     if (unlikely (returned)) {
301       fprintf (stderr, "OUCH, double calls to return_trace().  This is a bug, please report.\n");
302       return v;
303     }
304 
305     _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
306 			      "return %s (line %d)",
307 			      hb_printer_t<ret_t>().print (v), line);
308     if (plevel) --*plevel;
309     plevel = nullptr;
310     returned = true;
311     return v;
312   }
313 
314   private:
315   unsigned int *plevel;
316   const char *what;
317   const void *obj;
318   bool returned;
319 };
320 template <typename ret_t> /* Make sure we don't use hb_auto_trace_t when not tracing. */
321 struct hb_auto_trace_t<0, ret_t>
322 {
hb_auto_trace_thb_auto_trace_t323   explicit inline hb_auto_trace_t (unsigned int *plevel_,
324 				   const char *what_,
325 				   const void *obj_,
326 				   const char *func,
327 				   const char *message,
328 				   ...) HB_PRINTF_FUNC(6, 7) {}
329 
rethb_auto_trace_t330   ret_t ret (ret_t v,
331 	     const char *func HB_UNUSED = nullptr,
332 	     unsigned int line HB_UNUSED = 0) { return v; }
333 };
334 
335 /* For disabled tracing; optimize out everything.
336  * https://github.com/harfbuzz/harfbuzz/pull/605 */
337 template <typename ret_t>
338 struct hb_no_trace_t {
rethb_no_trace_t339   ret_t ret (ret_t v,
340 	     const char *func HB_UNUSED = "",
341 	     unsigned int line HB_UNUSED = 0) { return v; }
342 };
343 
344 #define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
345 
346 
347 /*
348  * Instances.
349  */
350 
351 #ifndef HB_DEBUG_ARABIC
352 #define HB_DEBUG_ARABIC (HB_DEBUG+0)
353 #endif
354 
355 #ifndef HB_DEBUG_BLOB
356 #define HB_DEBUG_BLOB (HB_DEBUG+0)
357 #endif
358 
359 #ifndef HB_DEBUG_CORETEXT
360 #define HB_DEBUG_CORETEXT (HB_DEBUG+0)
361 #endif
362 
363 #ifndef HB_DEBUG_DIRECTWRITE
364 #define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0)
365 #endif
366 
367 #ifndef HB_DEBUG_FT
368 #define HB_DEBUG_FT (HB_DEBUG+0)
369 #endif
370 
371 #ifndef HB_DEBUG_GET_COVERAGE
372 #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
373 #endif
374 
375 #ifndef HB_DEBUG_OBJECT
376 #define HB_DEBUG_OBJECT (HB_DEBUG+0)
377 #endif
378 
379 #ifndef HB_DEBUG_SHAPE_PLAN
380 #define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0)
381 #endif
382 
383 #ifndef HB_DEBUG_UNISCRIBE
384 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
385 #endif
386 
387 /*
388  * With tracing.
389  */
390 
391 #ifndef HB_DEBUG_APPLY
392 #define HB_DEBUG_APPLY (HB_DEBUG+0)
393 #endif
394 #if HB_DEBUG_APPLY
395 #define TRACE_APPLY(this) \
396 	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
397 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
398 	 "idx %d gid %u lookup %d", \
399 	 c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index)
400 #else
401 #define TRACE_APPLY(this) hb_no_trace_t<bool> trace
402 #endif
403 
404 #ifndef HB_DEBUG_CLOSURE
405 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
406 #endif
407 #if HB_DEBUG_CLOSURE
408 #define TRACE_CLOSURE(this) \
409 	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
410 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
411 	 " ")
412 #else
413 #define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
414 #endif
415 
416 #ifndef HB_DEBUG_COLLECT_GLYPHS
417 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
418 #endif
419 #if HB_DEBUG_COLLECT_GLYPHS
420 #define TRACE_COLLECT_GLYPHS(this) \
421 	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
422 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
423 	 " ")
424 #else
425 #define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
426 #endif
427 
428 #ifndef HB_DEBUG_SANITIZE
429 #define HB_DEBUG_SANITIZE (HB_DEBUG+0)
430 #endif
431 #if HB_DEBUG_SANITIZE
432 #define TRACE_SANITIZE(this) \
433 	hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
434 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
435 	 " ");
436 #else
437 #define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
438 #endif
439 
440 #ifndef HB_DEBUG_SERIALIZE
441 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
442 #endif
443 #if HB_DEBUG_SERIALIZE
444 #define TRACE_SERIALIZE(this) \
445 	hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
446 	(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
447 	 " ");
448 #else
449 #define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
450 #endif
451 
452 #ifndef HB_DEBUG_SUBSET
453 #define HB_DEBUG_SUBSET (HB_DEBUG+0)
454 #endif
455 #if HB_DEBUG_SUBSET
456 #define TRACE_SUBSET(this) \
457   hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace \
458   (&c->debug_depth, c->get_name (), this, HB_FUNC, \
459    " ");
460 #else
461 #define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
462 #endif
463 
464 #ifndef HB_DEBUG_WOULD_APPLY
465 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
466 #endif
467 #if HB_DEBUG_WOULD_APPLY
468 #define TRACE_WOULD_APPLY(this) \
469 	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
470 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
471 	 "%d glyphs", c->len);
472 #else
473 #define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
474 #endif
475 
476 #ifndef HB_DEBUG_DISPATCH
477 #define HB_DEBUG_DISPATCH ( \
478 	HB_DEBUG_APPLY + \
479 	HB_DEBUG_CLOSURE + \
480 	HB_DEBUG_COLLECT_GLYPHS + \
481 	HB_DEBUG_SANITIZE + \
482 	HB_DEBUG_SERIALIZE + \
483   HB_DEBUG_SUBSET + \
484 	HB_DEBUG_WOULD_APPLY + \
485 	0)
486 #endif
487 #if HB_DEBUG_DISPATCH
488 #define TRACE_DISPATCH(this, format) \
489 	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
490 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
491 	 "format %d", (int) format);
492 #else
493 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
494 #endif
495 
496 
497 #endif /* HB_DEBUG_HH */
498