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_SUBSET
 400 #define HB_DEBUG_SUBSET (HB_DEBUG+0)
 401 #endif
 402 #if HB_DEBUG_SUBSET
 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, \
 406    " ");
 407 #else
 408 #define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
 409 #endif
 410 
 411 #ifndef HB_DEBUG_WOULD_APPLY
 412 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
 413 #endif
 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);
 419 #else
 420 #define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
 421 #endif
 422 
 423 #ifndef HB_DEBUG_DISPATCH
 424 #define HB_DEBUG_DISPATCH ( \
 425         HB_DEBUG_APPLY + \
 426         HB_DEBUG_CLOSURE + \
 427         HB_DEBUG_COLLECT_GLYPHS + \
 428         HB_DEBUG_SANITIZE + \
 429         HB_DEBUG_SERIALIZE + \
 430   HB_DEBUG_SUBSET + \
 431         HB_DEBUG_WOULD_APPLY + \
 432         0)
 433 #endif
 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);
 439 #else
 440 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
 441 #endif
 442 
 443 
 444 #endif /* HB_DEBUG_HH */