Home | History | Annotate | Download | only in src
      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
     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
     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
     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
    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)
    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)
    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)
    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 {
    240   const char *print (const T&) { return "something"; }
    241 };
    242 
    243 template <>
    244 struct hb_printer_t<bool> {
    245   const char *print (bool v) { return v ? "true" : "false"; }
    246 };
    247 
    248 template <>
    249 struct hb_printer_t<hb_void_t> {
    250   const char *print (hb_void_t) { return ""; }
    251 };
    252 
    253 
    254 /*
    255  * Trace
    256  */
    257 
    258 template <typename T>
    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 <>
    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 {
    272   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   }
    287   ~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 
    296   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 {
    323   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 
    330   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 {
    339   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