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_SANITIZE
 405 #define HB_DEBUG_SANITIZE (HB_DEBUG+0)
 406 #endif
 407 #if HB_DEBUG_SANITIZE
 408 #define TRACE_SANITIZE(this) \
 409         hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
 410         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
 411          " ");
 412 #else
 413 #define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
 414 #endif
 415 
 416 #ifndef HB_DEBUG_SERIALIZE
 417 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0)
 418 #endif
 419 #if HB_DEBUG_SERIALIZE
 420 #define TRACE_SERIALIZE(this) \
 421         hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
 422         (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
 423          " ");
 424 #else
 425 #define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
 426 #endif
 427 
 428 #ifndef HB_DEBUG_SUBSET
 429 #define HB_DEBUG_SUBSET (HB_DEBUG+0)
 430 #endif
 431 #if HB_DEBUG_SUBSET
 432 #define TRACE_SUBSET(this) \
 433   hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace \
 434   (&c->debug_depth, c->get_name (), this, HB_FUNC, \
 435    " ");
 436 #else
 437 #define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
 438 #endif
 439 
 440 #ifndef HB_DEBUG_WOULD_APPLY
 441 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
 442 #endif
 443 #if HB_DEBUG_WOULD_APPLY
 444 #define TRACE_WOULD_APPLY(this) \
 445         hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
 446         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
 447          "%d glyphs", c->len);
 448 #else
 449 #define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
 450 #endif
 451 
 452 #ifndef HB_DEBUG_DISPATCH
 453 #define HB_DEBUG_DISPATCH ( \
 454         HB_DEBUG_APPLY + \
 455         HB_DEBUG_SANITIZE + \
 456         HB_DEBUG_SERIALIZE + \
 457   HB_DEBUG_SUBSET + \
 458         HB_DEBUG_WOULD_APPLY + \
 459         0)
 460 #endif
 461 #if HB_DEBUG_DISPATCH
 462 #define TRACE_DISPATCH(this, format) \
 463         hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
 464         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
 465          "format %d", (int) format);
 466 #else
 467 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
 468 #endif
 469 
 470 
 471 #endif /* HB_DEBUG_HH */