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-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 (func);
     53     /* Skip "static" */
     54     if (0 == strncmp (func, "static ", 7))
     55       func += 7;
     56     /* Skip "typename" */
     57     if (0 == strncmp (func, "typename ", 9))
     58       func += 9;
     59     /* Skip return type */
     60     const char *space = strchr (func, ' ');
     61     if (space)
     62       func = space + 1;
     63     /* Skip parameter list */
     64     const char *paren = strchr (func, '(');
     65     if (paren)
     66       func_len = paren - func;
     67     fprintf (stderr, "%.*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, "%-10s", what ? what : "");
     94 
     95   if (obj)
     96     fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj);
     97   else
     98     fprintf (stderr, " %*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, "%2u %s" VRBAR "%s",
    113 	     level,
    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);
    116   } else
    117     fprintf (stderr, "   " VRBAR LBAR);
    118 
    119   _hb_print_func (func);
    120 
    121   if (message)
    122   {
    123     fprintf (stderr, ": ");
    124     vfprintf (stderr, message, ap);
    125   }
    126 
    127   fprintf (stderr, "\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, "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, "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