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, "(%0*lx) ", (unsigned int) (2 * sizeof (void *)), (unsigned long) 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 explicit inline hb_auto_trace_t (unsigned int *plevel_, 225 const char *what_, 226 const void *obj_, 227 const char *func, 228 const char *message, 229 ...) : plevel (plevel_), what (what_), obj (obj_), returned (false) 230 { 231 if (plevel) ++*plevel; 232 233 va_list ap; 234 va_start (ap, message); 235 _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap); 236 va_end (ap); 237 } 238 inline ~hb_auto_trace_t (void) 239 { 240 _hb_warn_no_return<ret_t> (returned); 241 if (!returned) { 242 _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, " "); 243 } 244 if (plevel) --*plevel; 245 } 246 247 inline ret_t ret (ret_t v, unsigned int line = 0) 248 { 249 if (unlikely (returned)) { 250 fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n"); 251 return v; 252 } 253 254 _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, 255 "return %s (line %d)", 256 hb_printer_t<ret_t>().print (v), line); 257 if (plevel) --*plevel; 258 plevel = nullptr; 259 returned = true; 260 return v; 261 } 262 263 private: 264 unsigned int *plevel; 265 const char *what; 266 const void *obj; 267 bool returned; 268 }; 269 template <typename ret_t> /* Make sure we don't use hb_auto_trace_t when not tracing. */ 270 struct hb_auto_trace_t<0, ret_t>; 271 272 /* For disabled tracing; optimize out everything. 273 * https://github.com/behdad/harfbuzz/pull/605 */ 274 template <typename ret_t> 275 struct hb_no_trace_t { 276 inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; } 277 }; 278 279 #define return_trace(RET) return trace.ret (RET, __LINE__) 280 281 282 /* 283 * Instances. 284 */ 285 286 #ifndef HB_DEBUG_ARABIC 287 #define HB_DEBUG_ARABIC (HB_DEBUG+0) 288 #endif 289 290 #ifndef HB_DEBUG_BLOB 291 #define HB_DEBUG_BLOB (HB_DEBUG+0) 292 #endif 293 294 #ifndef HB_DEBUG_CORETEXT 295 #define HB_DEBUG_CORETEXT (HB_DEBUG+0) 296 #endif 297 298 #ifndef HB_DEBUG_DIRECTWRITE 299 #define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0) 300 #endif 301 302 #ifndef HB_DEBUG_FT 303 #define HB_DEBUG_FT (HB_DEBUG+0) 304 #endif 305 306 #ifndef HB_DEBUG_GET_COVERAGE 307 #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0) 308 #endif 309 310 #ifndef HB_DEBUG_OBJECT 311 #define HB_DEBUG_OBJECT (HB_DEBUG+0) 312 #endif 313 314 #ifndef HB_DEBUG_SHAPE_PLAN 315 #define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0) 316 #endif 317 318 #ifndef HB_DEBUG_UNISCRIBE 319 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) 320 #endif 321 322 /* 323 * With tracing. 324 */ 325 326 #ifndef HB_DEBUG_APPLY 327 #define HB_DEBUG_APPLY (HB_DEBUG+0) 328 #endif 329 #if HB_DEBUG_APPLY 330 #define TRACE_APPLY(this) \ 331 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ 332 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 333 "idx %d gid %u lookup %d", \ 334 c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index) 335 #else 336 #define TRACE_APPLY(this) hb_no_trace_t<bool> trace 337 #endif 338 339 #ifndef HB_DEBUG_CLOSURE 340 #define HB_DEBUG_CLOSURE (HB_DEBUG+0) 341 #endif 342 #if HB_DEBUG_CLOSURE 343 #define TRACE_CLOSURE(this) \ 344 hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \ 345 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 346 "") 347 #else 348 #define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED 349 #endif 350 351 #ifndef HB_DEBUG_COLLECT_GLYPHS 352 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0) 353 #endif 354 #if HB_DEBUG_COLLECT_GLYPHS 355 #define TRACE_COLLECT_GLYPHS(this) \ 356 hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \ 357 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 358 "") 359 #else 360 #define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED 361 #endif 362 363 #ifndef HB_DEBUG_SANITIZE 364 #define HB_DEBUG_SANITIZE (HB_DEBUG+0) 365 #endif 366 #if HB_DEBUG_SANITIZE 367 #define TRACE_SANITIZE(this) \ 368 hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \ 369 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 370 ""); 371 #else 372 #define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace 373 #endif 374 375 #ifndef HB_DEBUG_SERIALIZE 376 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0) 377 #endif 378 #if HB_DEBUG_SERIALIZE 379 #define TRACE_SERIALIZE(this) \ 380 hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \ 381 (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \ 382 ""); 383 #else 384 #define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace 385 #endif 386 387 #ifndef HB_DEBUG_WOULD_APPLY 388 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) 389 #endif 390 #if HB_DEBUG_WOULD_APPLY 391 #define TRACE_WOULD_APPLY(this) \ 392 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \ 393 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 394 "%d glyphs", c->len); 395 #else 396 #define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace 397 #endif 398 399 #ifndef HB_DEBUG_DISPATCH 400 #define HB_DEBUG_DISPATCH ( \ 401 HB_DEBUG_APPLY + \ 402 HB_DEBUG_CLOSURE + \ 403 HB_DEBUG_COLLECT_GLYPHS + \ 404 HB_DEBUG_SANITIZE + \ 405 HB_DEBUG_SERIALIZE + \ 406 HB_DEBUG_WOULD_APPLY + \ 407 0) 408 #endif 409 #if HB_DEBUG_DISPATCH 410 #define TRACE_DISPATCH(this, format) \ 411 hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ 412 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 413 "format %d", (int) format); 414 #else 415 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace 416 #endif 417 418 419 #endif /* HB_DEBUG_HH */