odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

blend2d-debug.h (25827B)


      1 // This file is part of Blend2D project <https://blend2d.com>
      2 //
      3 // See blend2d.h or LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 // ----------------------------------------------------------------------------
      7 // IMPORTANT: DO NOT USE THIS HEADER IN PRODUCTION, ONLY FOR BUG REPORTING!
      8 //
      9 // This file provides debug helpers that are not a part of Blend2D library.
     10 // Functions this header provides are not exported, they are only provided
     11 // for making it easier to report bugs and to give more information about the
     12 // environment where such bugs happened to Blend2D developers. The functions
     13 // defined below are not stable and are subject to change in future Blend2D
     14 // releases.
     15 //
     16 // This file can be included by both C and C++ API users.
     17 // ----------------------------------------------------------------------------
     18 
     19 #ifndef BLEND2D_DEBUG_H_INCLUDED
     20 #define BLEND2D_DEBUG_H_INCLUDED
     21 
     22 #include <stdio.h>
     23 #include "blend2d.h"
     24 
     25 //! \cond INTERNAL
     26 
     27 // Forward Declarations
     28 // ====================
     29 
     30 static void bl_debug_object_(const void* obj, const char* name, int indent);
     31 
     32 // BLDebug - Begin
     33 // ===============
     34 
     35 #define BL_DEBUG_OUT(MSG) bl_runtime_message_fmt("%*s%s", indent * 2, "", MSG);
     36 #define BL_DEBUG_FMT(FMT, ...) bl_runtime_message_fmt("%*s" FMT, indent * 2, "", __VA_ARGS__);
     37 
     38 // BLDebug - Utilities
     39 // ===================
     40 
     41 static const char* bl_debug_get_enum_as_string(uint32_t value, const char* enum_data) {
     42   uint32_t i = 0;
     43   const char* p = enum_data;
     44 
     45   while (i != value) {
     46     // 0 indicates end of data.
     47     if (!*p)
     48       return "Unknown";
     49 
     50     // Skip the entire sub-string.
     51     while (*++p)
     52       continue;
     53 
     54     i++; // Advance the current index.
     55     p++; // Skip the zero value.
     56   }
     57 
     58   return p;
     59 }
     60 
     61 // BLDebug - Runtime
     62 // =================
     63 
     64 static void bl_debug_runtime_cpu_features(char* buf, size_t buf_size, uint32_t arch, uint32_t features) {
     65   if (!arch) {
     66     #if defined(_M_X64) || defined(__x86_64__) || defined(_M_IX86) || defined(__X86__) || defined(__i386__)
     67     arch = BL_RUNTIME_CPU_ARCH_X86;
     68     #endif
     69 
     70     #if defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM) || defined(_M_ARMT) || defined(__arm__) || defined(__thumb__) || defined(__thumb2__)
     71     arch = BL_RUNTIME_CPU_ARCH_ARM;
     72     #endif
     73 
     74     #if defined(_MIPS_ARCH_MIPS64) || defined(__mips64) || defined(_MIPS_ARCH_MIPS32) || defined(_M_MRX000) || defined(__mips__)
     75     arch = BL_RUNTIME_CPU_ARCH_MIPS;
     76     #endif
     77   }
     78 
     79   switch (arch) {
     80     case BL_RUNTIME_CPU_ARCH_X86:
     81       snprintf(buf, buf_size, "%s%s%s%s%s%s%s%s",
     82         (features & BL_RUNTIME_CPU_FEATURE_X86_SSE2  ) ? "SSE2 "   : "",
     83         (features & BL_RUNTIME_CPU_FEATURE_X86_SSE3  ) ? "SSE3 "   : "",
     84         (features & BL_RUNTIME_CPU_FEATURE_X86_SSSE3 ) ? "SSSE3 "  : "",
     85         (features & BL_RUNTIME_CPU_FEATURE_X86_SSE4_1) ? "SSE4.1 " : "",
     86         (features & BL_RUNTIME_CPU_FEATURE_X86_SSE4_2) ? "SSE4.2 " : "",
     87         (features & BL_RUNTIME_CPU_FEATURE_X86_AVX   ) ? "AVX "    : "",
     88         (features & BL_RUNTIME_CPU_FEATURE_X86_AVX2  ) ? "AVX2 "   : "",
     89         (features & BL_RUNTIME_CPU_FEATURE_X86_AVX512) ? "AVX512 " : "");
     90       break;
     91 
     92     default:
     93       buf[0] = '\0';
     94       break;
     95   }
     96 }
     97 
     98 //! Dumps `BLRuntimeBuildInfo` queried through `bl_runtime_query_info()`.
     99 static void bl_debug_runtime_build_info(void) {
    100   const char* build_mode = "";
    101   char baseline_cpu_features[128];
    102   char supported_cpu_features[128];
    103 
    104   BLRuntimeBuildInfo info;
    105   bl_runtime_query_info(BL_RUNTIME_INFO_TYPE_BUILD, &info);
    106 
    107   #if defined(BL_STATIC)
    108   build_mode = "Static";
    109   #else
    110   build_mode = "Shared";
    111   #endif
    112 
    113   bl_debug_runtime_cpu_features(baseline_cpu_features, 128, 0, info.baseline_cpu_features);
    114   bl_debug_runtime_cpu_features(supported_cpu_features, 128, 0, info.supported_cpu_features);
    115 
    116   bl_runtime_message_fmt(
    117     "BuildInformation: {\n"
    118     "  Version: %u.%u.%u\n"
    119     "  BuildType: %s\n"
    120     "  BuildMode: %s\n"
    121     "  BaselineCpuFeatures: %s\n"
    122     "  SupportedCpuFeatures: %s\n"
    123     "  Compiler: %s\n"
    124     "  MaxImageSize: %u\n"
    125     "  MaxThreadCount: %u\n"
    126     "}\n",
    127     info.major_version,
    128     info.minor_version,
    129     info.patch_version,
    130     info.build_type == BL_RUNTIME_BUILD_TYPE_DEBUG ? "Debug" : "Release",
    131     build_mode,
    132     baseline_cpu_features,
    133     supported_cpu_features,
    134     info.compiler_info,
    135     info.max_image_size,
    136     info.max_thread_count);
    137 }
    138 
    139 //! Dumps `BLRuntimeSystemInfo` queried through `bl_runtime_query_info()`.
    140 static void bl_debug_runtime_system_info(void) {
    141   static const char cpu_arch_enum[] =
    142     "NONE\0"
    143     "X86\0"
    144     "ARM\0"
    145     "MIPS\0";
    146 
    147   const char* os = "Unknown";
    148   char cpu_features[128];
    149 
    150   BLRuntimeSystemInfo info;
    151   bl_runtime_query_info(BL_RUNTIME_INFO_TYPE_SYSTEM, &info);
    152   cpu_features[0] = '\0';
    153 
    154 #if defined(__linux__)
    155   os = "Linux";
    156 #elif defined(__APPLE__)
    157   os = "Apple";
    158 #elif defined(__DragonFly__)
    159   os = "DragonFlyBSD";
    160 #elif defined(__FreeBSD__)
    161   os = "FreeBSD";
    162 #elif defined(__NetBSD__)
    163   os = "NetBSD";
    164 #elif defined(__OpenBSD__)
    165   os = "OpenBSD";
    166 #elif defined(__HAIKU__)
    167   os = "Haiku";
    168 #elif defined(_WIN32)
    169   os = "Windows";
    170 #endif
    171 
    172   bl_debug_runtime_cpu_features(cpu_features, 128, info.cpu_arch, info.cpu_features);
    173 
    174   bl_runtime_message_fmt(
    175     "SystemInformation: {\n"
    176     "  OperatingSystem: %s\n"
    177     "  CpuArch: %s [%u bit]\n"
    178     "  CpuFeatures: %s\n"
    179     "  ThreadCount: %u\n"
    180     "  ThreadStackSize: %u\n"
    181     "  AllocationGranularity: %u\n"
    182     "}\n",
    183     os,
    184     bl_debug_get_enum_as_string(info.cpu_arch, cpu_arch_enum), sizeof(void*) >= 8 ? 64 : 32,
    185     cpu_features,
    186     info.thread_count,
    187     info.thread_stack_size,
    188     info.allocation_granularity);
    189 }
    190 
    191 // BLDebug - Matrix
    192 // ================
    193 
    194 static void bl_debug_matrix2d_(const BLMatrix2D* obj, const char* name, int indent) {
    195   static const char matrix_type_enum[] =
    196     "IDENTITY\0"
    197     "TRANSLATE\0"
    198     "SCALE\0"
    199     "SWAP\0"
    200     "AFFINE\0"
    201     "INVALID\0";
    202 
    203   BL_DEBUG_FMT("%s: [%s] {\n", name, bl_debug_get_enum_as_string(bl_matrix2d_get_type(obj), matrix_type_enum));
    204   BL_DEBUG_FMT("  [% 3.14f |% 3.14f]\n", obj->m00, obj->m01);
    205   BL_DEBUG_FMT("  [% 3.14f |% 3.14f]\n", obj->m10, obj->m11);
    206   BL_DEBUG_FMT("  [% 3.14f |% 3.14f]\n", obj->m20, obj->m21);
    207   BL_DEBUG_OUT("}\n");
    208 }
    209 
    210 // BLDebug - StrokeOptions
    211 // =======================
    212 
    213 static void bl_debug_stroke_options_(const BLStrokeOptionsCore* obj, const char* name, int indent) {
    214   static const char stroke_cap_position_enum[] =
    215     "StartCap\0"
    216     "EndCap\0";
    217 
    218   static const char stroke_cap_enum[] =
    219     "BUTT\0"
    220     "SQUARE\0"
    221     "ROUND\0"
    222     "ROUND_REV\0"
    223     "TRIANGLE\0"
    224     "TRIANGLE_REV\0";
    225 
    226   static const char stroke_join_enum[] =
    227     "MITER_CLIP\0"
    228     "MITER_BEVEL\0"
    229     "MITER_ROUND\0"
    230     "BEVEL\0ROUND\0";
    231 
    232   static const char stroke_transform_order_enum[] =
    233     "AFTER\0"
    234     "BEFORE\0";
    235 
    236   uint32_t i;
    237 
    238   BL_DEBUG_FMT("%s: {\n", name);
    239   indent++;
    240 
    241   for (i = 0; i <= BL_STROKE_CAP_POSITION_MAX_VALUE; i++)
    242     BL_DEBUG_FMT("%s: %s\n", bl_debug_get_enum_as_string(i, stroke_cap_position_enum), bl_debug_get_enum_as_string(obj->caps[i], stroke_cap_enum));
    243   BL_DEBUG_FMT("Join: %s\n", bl_debug_get_enum_as_string(obj->join, stroke_join_enum));
    244   BL_DEBUG_FMT("TransformOrder: %s\n", bl_debug_get_enum_as_string(obj->transform_order, stroke_transform_order_enum));
    245   BL_DEBUG_FMT("Width: %g\n", obj->width);
    246   BL_DEBUG_FMT("MiterLimit: %g\n", obj->miter_limit);
    247   BL_DEBUG_FMT("DashOffset: %g\n", obj->dash_offset);
    248   bl_debug_object_(&obj->dash_array, "DashArray", indent);
    249 
    250   indent--;
    251   BL_DEBUG_OUT("}\n");
    252 }
    253 static void bl_debug_stroke_options(const BLStrokeOptionsCore* obj) { bl_debug_stroke_options_(obj, "BLStrokeOptions", 0); }
    254 
    255 // BLDebug - Array
    256 // ===============
    257 
    258 static void bl_debug_array_(const BLArrayCore* obj, const char* name, int indent) {
    259   BLObjectType object_type = bl_var_get_type(obj);
    260   const void* void_data = bl_array_get_data(obj);
    261 
    262   size_t i;
    263   size_t size = bl_array_get_size(obj);
    264 
    265   if (size == 0) {
    266     BL_DEBUG_FMT("%s: {}\n", name);
    267     return;
    268   }
    269 
    270   BL_DEBUG_FMT("%s: {\n", name);
    271   indent++;
    272 
    273   switch (object_type) {
    274     case BL_OBJECT_TYPE_ARRAY_OBJECT: {
    275       char prefix[64];
    276       const BLObjectCore** data = (const BLObjectCore**)void_data;
    277       for (i = 0; i < size; i++) {
    278         snprintf(prefix, 64, "[%zu]", i);
    279         bl_debug_object_(data[i], prefix, indent);
    280       }
    281       break;
    282     }
    283     case BL_OBJECT_TYPE_ARRAY_INT8: {
    284       const int8_t* data = (const int8_t*)void_data;
    285       for (i = 0; i < size; i++)
    286         BL_DEBUG_FMT("[%zu] %d", i, data[i]);
    287       break;
    288     }
    289     case BL_OBJECT_TYPE_ARRAY_UINT8: {
    290       const uint8_t* data = (const uint8_t*)void_data;
    291       for (i = 0; i < size; i++)
    292         BL_DEBUG_FMT("[%zu] %u", i, data[i]);
    293       break;
    294     }
    295     case BL_OBJECT_TYPE_ARRAY_INT16: {
    296       const int16_t* data = (const int16_t*)void_data;
    297       for (i = 0; i < size; i++)
    298         BL_DEBUG_FMT("[%zu] %d", i, data[i]);
    299       break;
    300     }
    301     case BL_OBJECT_TYPE_ARRAY_UINT16: {
    302       const uint16_t* data = (const uint16_t*)void_data;
    303       for (i = 0; i < size; i++)
    304         BL_DEBUG_FMT("[%zu] %u", i, data[i]);
    305       break;
    306     }
    307     case BL_OBJECT_TYPE_ARRAY_INT32: {
    308       const int32_t* data = (const int32_t*)void_data;
    309       for (i = 0; i < size; i++)
    310         BL_DEBUG_FMT("[%zu] %d", i, data[i]);
    311       break;
    312     }
    313     case BL_OBJECT_TYPE_ARRAY_UINT32: {
    314       const uint32_t* data = (const uint32_t*)void_data;
    315       for (i = 0; i < size; i++)
    316         BL_DEBUG_FMT("[%zu] %u", i, data[i]);
    317       break;
    318     }
    319     case BL_OBJECT_TYPE_ARRAY_INT64: {
    320       const int64_t* data = (const int64_t*)void_data;
    321       for (i = 0; i < size; i++)
    322         BL_DEBUG_FMT("[%zu] %lld", i, (long long)data[i]);
    323       break;
    324     }
    325     case BL_OBJECT_TYPE_ARRAY_UINT64: {
    326       const uint64_t* data = (const uint64_t*)void_data;
    327       for (i = 0; i < size; i++)
    328         BL_DEBUG_FMT("[%zu] %llu", i, (unsigned long long)data[i]);
    329       break;
    330     }
    331     case BL_OBJECT_TYPE_ARRAY_FLOAT32: {
    332       const float* data = (const float*)void_data;
    333       for (i = 0; i < size; i++)
    334         BL_DEBUG_FMT("[%zu] %g", i, data[i]);
    335       break;
    336     }
    337     case BL_OBJECT_TYPE_ARRAY_FLOAT64: {
    338       const double* data = (const double*)void_data;
    339       for (i = 0; i < size; i++)
    340         BL_DEBUG_FMT("[%zu] %g", i, data[i]);
    341       break;
    342     }
    343     default:
    344       break;
    345   }
    346 
    347   indent--;
    348   BL_DEBUG_OUT("}\n");
    349 }
    350 
    351 // BLDebug - Image
    352 // ===============
    353 
    354 static void bl_debug_image_(const BLImageCore* obj, const char* name, int indent) {
    355   static const char format_enum[] =
    356     "NONE\0"
    357     "PRGB32\0"
    358     "XRGB32\0"
    359     "A8\0";
    360 
    361   BLImageData data;
    362   bl_image_get_data(obj, &data);
    363 
    364   BL_DEBUG_FMT("%s: {\n", name);
    365   BL_DEBUG_FMT("  Size: %ux%u\n", data.size.w, data.size.h);
    366   BL_DEBUG_FMT("  Format: %s\n", bl_debug_get_enum_as_string(data.format, format_enum));
    367   BL_DEBUG_OUT("}\n");
    368 }
    369 
    370 // BLDebug - Pattern
    371 // =================
    372 
    373 static void bl_debug_pattern_(const BLPatternCore* obj, const char* name, int indent) {
    374   static const char extend_mode_enum[] =
    375     "PAD\0"
    376     "REPEAT\0"
    377     "REFLECT\0"
    378     "PAD_X_REPEAT_Y\0"
    379     "PAD_X_REFLECT_Y\0"
    380     "REPEAT_X_PAD_Y\0"
    381     "REPEAT_X_REFLECT_Y\0"
    382     "REFLECT_X_PAD_Y\0"
    383     "REFLECT_X_REPEAT_Y\0";
    384 
    385   BLImageCore image;
    386   BLMatrix2D transform;
    387 
    388   BLExtendMode extend_mode = bl_pattern_get_extend_mode(obj);
    389 
    390   bl_image_init(&image);
    391   bl_pattern_get_image(obj, &image);
    392   bl_pattern_get_transform(obj, &transform);
    393 
    394   BL_DEBUG_FMT("%s: {\n", name);
    395   {
    396     indent++;
    397     bl_debug_image_(&image, "Image", indent);
    398     BL_DEBUG_FMT("ExtendMode: %s\n", bl_debug_get_enum_as_string(extend_mode, extend_mode_enum));
    399     bl_debug_matrix2d_(&transform, "Transform", indent);
    400     indent--;
    401   }
    402   BL_DEBUG_OUT("}\n");
    403 
    404   bl_image_destroy(&image);
    405 }
    406 
    407 // BLDebug - Gradient
    408 // ==================
    409 
    410 static void bl_debug_gradient_(const BLGradientCore* obj, const char* name, int indent) {
    411   static const char gradient_type_enum[] =
    412     "LINEAR\0"
    413     "RADIAL\0"
    414     "CONIC\0";
    415 
    416   static const char extend_mode_enum[] =
    417     "PAD\0"
    418     "REPEAT\0"
    419     "REFLECT\0";
    420 
    421   size_t i;
    422   size_t value_count = 0;
    423   BLMatrix2D transform;
    424 
    425   BLGradientType gradient_type = bl_gradient_get_type(obj);
    426   BLExtendMode extend_mode = bl_gradient_get_extend_mode(obj);
    427   size_t stop_count = bl_gradient_get_size(obj);
    428   const BLGradientStop* stop_data = bl_gradient_get_stops(obj);
    429 
    430   bl_gradient_get_transform(obj, &transform);
    431 
    432   switch (gradient_type) {
    433     case BL_GRADIENT_TYPE_LINEAR: value_count = 4; break;
    434     case BL_GRADIENT_TYPE_RADIAL: value_count = 5; break;
    435     case BL_GRADIENT_TYPE_CONIC : value_count = 3; break;
    436     default: break;
    437   }
    438 
    439   double vals[6];
    440   for (i = 0; i < value_count; i++)
    441     vals[i] = bl_gradient_get_value(obj, i);
    442 
    443   BL_DEBUG_FMT("%s: {\n", name);
    444   {
    445     indent++;
    446     BL_DEBUG_FMT("Type: %s\n", bl_debug_get_enum_as_string(gradient_type, gradient_type_enum));
    447     BL_DEBUG_FMT("ExtendMode: %s\n", bl_debug_get_enum_as_string(extend_mode, extend_mode_enum));
    448 
    449     switch (gradient_type) {
    450       case BL_GRADIENT_TYPE_LINEAR:
    451         BL_DEBUG_FMT("Values: Start=[%f, %f], End=[%f, %f]\n",
    452           vals[0], vals[1],
    453           vals[2], vals[3]);
    454         break;
    455 
    456       case BL_GRADIENT_TYPE_RADIAL:
    457         BL_DEBUG_FMT("Values: Center=[%f, %f], Focal=[%f, %f] R=%f\n",
    458           vals[0], vals[1],
    459           vals[2], vals[3],
    460           vals[4]);
    461         break;
    462 
    463       case BL_GRADIENT_TYPE_CONIC:
    464         BL_DEBUG_FMT("Values: Center=[%f, %f], Angle=%f\n",
    465           vals[0], vals[1],
    466           vals[2]);
    467         break;
    468 
    469       default:
    470         break;
    471     }
    472 
    473     BL_DEBUG_OUT("Stops: {\n");
    474     indent++;
    475     for (i = 0; i < stop_count; i++) {
    476       uint64_t rgba64 = stop_data[i].rgba.value;
    477       BL_DEBUG_FMT("[%zu] Offset=%f BLRgba64(R=%d, G=%d, B=%d, A=%d)\n",
    478         i,
    479         stop_data[i].offset,
    480         (rgba64 >> 32) & 0xFFFF,
    481         (rgba64 >> 16) & 0xFFFF,
    482         (rgba64 >>  0) & 0xFFFF,
    483         (rgba64 >> 48) & 0xFFFF);
    484     }
    485     indent--;
    486     BL_DEBUG_OUT("}\n");
    487 
    488     bl_debug_matrix2d_(&transform, "Transform", indent);
    489     indent--;
    490   }
    491   BL_DEBUG_OUT("}\n");
    492 }
    493 
    494 // BLDebug - Path
    495 // ==============
    496 
    497 static void bl_debug_path_(const BLPathCore* obj, const char* name, int indent) {
    498   size_t i = 0;
    499   size_t size = bl_path_get_size(obj);
    500 
    501   const uint8_t* cmd = bl_path_get_command_data(obj);
    502   const BLPoint* vtx = bl_path_get_vertex_data(obj);
    503 
    504   BL_DEBUG_FMT("%s: {\n", name);
    505   indent++;
    506 
    507   while (i < size) {
    508     switch (cmd[i]) {
    509       case BL_PATH_CMD_MOVE:
    510         BL_DEBUG_FMT("p.move_to(%g, %g);\n", vtx[i].x, vtx[i].y);
    511         i++;
    512         continue;
    513       case BL_PATH_CMD_ON:
    514         BL_DEBUG_FMT("p.line_to(%g, %g);\n", vtx[i].x, vtx[i].y);
    515         i++;
    516         continue;
    517       case BL_PATH_CMD_QUAD:
    518         if ((size - i) < 2)
    519           break;
    520         BL_DEBUG_FMT("p.quad_to(%g, %g, %g, %g);\n", vtx[i].x, vtx[i].y, vtx[i+1].x, vtx[i+1].y);
    521         i += 2;
    522         continue;
    523       case BL_PATH_CMD_CUBIC:
    524         if ((size - i) < 3)
    525           break;
    526         BL_DEBUG_FMT("p.cubic_to(%g, %g, %g, %g, %g, %g);\n", vtx[i].x, vtx[i].y, vtx[i+1].x, vtx[i+1].y, vtx[i+2].x, vtx[i+2].y);
    527         i += 3;
    528         continue;
    529       case BL_PATH_CMD_CLOSE:
    530         BL_DEBUG_OUT("p.close();\n");
    531         i++;
    532         continue;
    533     }
    534 
    535     BL_DEBUG_FMT("p.unknown_command(%u, %g, %g);\n", cmd[i], vtx[i].x, vtx[i].y);
    536     i++;
    537   }
    538 
    539   indent--;
    540   BL_DEBUG_OUT("}\n");
    541 }
    542 
    543 // BLDebug - FontFeatureSettings
    544 // =============================
    545 
    546 static void bl_debug_font_feature_settings_(const BLFontFeatureSettingsCore* obj, const char* name, int indent) {
    547   size_t i;
    548   BLFontFeatureSettingsView view;
    549 
    550   bl_font_feature_settings_get_view(obj, &view);
    551 
    552   if (view.size == 0) {
    553     BL_DEBUG_FMT("%s: {}\n", name);
    554   }
    555   else {
    556     BL_DEBUG_FMT("%s: {\n", name);
    557     indent++;
    558 
    559     for (i = 0; i < view.size; i++) {
    560       BLTag tag = view.data[i].tag;
    561       uint32_t value = view.data[i].value;
    562       BL_DEBUG_FMT("'%c%c%c%c': %u\n",
    563         (tag >> 24) & 0xFF,
    564         (tag >> 16) & 0xFF,
    565         (tag >>  8) & 0xFF,
    566         (tag >>  0) & 0xFF,
    567         (unsigned)value);
    568     }
    569 
    570     indent--;
    571     BL_DEBUG_OUT("}\n");
    572   }
    573 }
    574 
    575 // BLDebug - FontVariationSettings
    576 // ==============================
    577 
    578 static void bl_debug_font_variation_settings_(const BLFontVariationSettingsCore* obj, const char* name, int indent) {
    579   size_t i;
    580   BLFontVariationSettingsView view;
    581 
    582   bl_font_variation_settings_get_view(obj, &view);
    583 
    584   if (view.size == 0) {
    585     BL_DEBUG_FMT("%s: {}\n", name);
    586   }
    587   else {
    588     BL_DEBUG_FMT("%s: {\n", name);
    589     indent++;
    590 
    591     for (i = 0; i < view.size; i++) {
    592       BLTag tag = view.data[i].tag;
    593       float value = view.data[i].value;
    594       BL_DEBUG_FMT("'%c%c%c%c': %f\n",
    595         (tag >> 24) & 0xFF,
    596         (tag >> 16) & 0xFF,
    597         (tag >>  8) & 0xFF,
    598         (tag >>  0) & 0xFF,
    599         value);
    600     }
    601 
    602     indent--;
    603     BL_DEBUG_OUT("}\n");
    604   }
    605 }
    606 
    607 // BLDebug - Font
    608 // ==============
    609 
    610 static void bl_debug_font_(const BLFontCore* obj, const char* name, int indent) {
    611   float size = bl_font_get_size(obj);
    612 
    613   BLStringCore str;
    614   BLFontFaceCore face;
    615   BLFontFeatureSettingsCore features;
    616   BLFontVariationSettingsCore variations;
    617 
    618   bl_string_init(&str);
    619   bl_font_face_init(&face);
    620   bl_font_feature_settings_init(&features);
    621   bl_font_variation_settings_init(&variations);
    622 
    623   bl_font_get_face(obj, &face);
    624   bl_font_get_feature_settings(obj, &features);
    625   bl_font_get_variation_settings(obj, &variations);
    626 
    627   BL_DEBUG_FMT("%s: {\n", name);
    628   {
    629     indent++;
    630     bl_font_face_get_family_name(&face, &str);
    631     BL_DEBUG_FMT("Face: %s\n", bl_string_get_data(&str));
    632     BL_DEBUG_FMT("Size: %f\n", size);
    633     bl_debug_font_feature_settings_(&features, "FeatureSettings", indent);
    634     bl_debug_font_variation_settings_(&variations, "VariationSettings", indent);
    635     indent--;
    636   }
    637   BL_DEBUG_OUT("}\n");
    638 
    639   bl_font_variation_settings_destroy(&variations);
    640   bl_font_feature_settings_destroy(&features);
    641   bl_font_face_destroy(&face);
    642   bl_string_destroy(&str);
    643 }
    644 
    645 // BLDebug - Context
    646 // =================
    647 
    648 static void bl_debug_context_(const BLContextCore* obj, const char* name, int indent) {
    649   static const char context_type_enum[] =
    650     "NONE\0"
    651     "DUMMY\0"
    652     "PROXY\0"
    653     "RASTER\0";
    654 
    655   static const char fill_rule_enum[] =
    656     "NON_ZERO\0"
    657     "EVEN_ODD\0";
    658 
    659   const BLContextState* state = ((BLContextImpl*)obj->_d.impl)->state;
    660 
    661   BLVarCore fill_style;
    662   BLVarCore stroke_style;
    663 
    664   bl_var_init_null(&fill_style);
    665   bl_var_init_null(&stroke_style);
    666 
    667   bl_context_get_transformed_fill_style(obj, &fill_style);
    668   bl_context_get_transformed_stroke_style(obj, &stroke_style);
    669 
    670   BL_DEBUG_FMT("%s: {\n", name);
    671   {
    672     indent++;
    673     BL_DEBUG_FMT("Type: %s\n", bl_debug_get_enum_as_string(bl_context_get_type(obj), context_type_enum));
    674     BL_DEBUG_FMT("GlobalAlpha: %f\n", state->global_alpha);
    675     BL_DEBUG_FMT("SavedStateCount: %u\n", state->saved_state_count);
    676 
    677     bl_debug_matrix2d_(&state->meta_transform, "MetaTransform", indent);
    678     bl_debug_matrix2d_(&state->user_transform, "UserTransform", indent);
    679     bl_debug_matrix2d_(&state->final_transform, "FinalTransform", indent);
    680 
    681     bl_debug_object_(&fill_style, "FillStyle", indent);
    682     BL_DEBUG_FMT("FillAlpha: %f\n", state->style_alpha[BL_CONTEXT_STYLE_SLOT_FILL]);
    683     BL_DEBUG_FMT("FillRule: %s\n", bl_debug_get_enum_as_string(state->fill_rule, fill_rule_enum));
    684 
    685     bl_debug_object_(&fill_style, "StrokeStyle", indent);
    686     BL_DEBUG_FMT("StrokeAlpha: %f\n", state->style_alpha[BL_CONTEXT_STYLE_SLOT_STROKE]);
    687     bl_debug_stroke_options_(&state->stroke_options, "StrokeOptions", indent);
    688     indent--;
    689   }
    690   BL_DEBUG_OUT("}\n");
    691 
    692   bl_var_destroy(&stroke_style);
    693   bl_var_destroy(&fill_style);
    694 }
    695 
    696 // BLDebug - Object
    697 // ================
    698 
    699 static void bl_debug_object_(const void* obj, const char* name, int indent) {
    700   BLObjectType type = bl_var_get_type(obj);
    701   switch (type) {
    702     case BL_OBJECT_TYPE_RGBA: {
    703       BLRgba rgba;
    704       bl_var_to_rgba(obj, &rgba);
    705       BL_DEBUG_FMT("%s: Rgba(R=%f, G=%f, B=%f, A=%f)\n",
    706         name,
    707         rgba.r,
    708         rgba.g,
    709         rgba.b,
    710         rgba.a);
    711       break;
    712     }
    713 
    714     case BL_OBJECT_TYPE_RGBA32: {
    715       uint32_t rgba32;
    716       bl_var_to_rgba32(obj, &rgba32);
    717       BL_DEBUG_FMT("%s: BLRgba32(R=%d, G=%d, B=%d, A=%d)\n",
    718         name,
    719         (rgba32 >> 16) & 0xFF,
    720         (rgba32 >>  8) & 0xFF,
    721         (rgba32 >>  0) & 0xFF,
    722         (rgba32 >> 24) & 0xFF);
    723       break;
    724     }
    725 
    726     case BL_OBJECT_TYPE_RGBA64: {
    727       uint64_t rgba64;
    728       bl_var_to_rgba64(obj, &rgba64);
    729       BL_DEBUG_FMT("%s: BLRgba64(R=%d, G=%d, B=%d, A=%d)\n",
    730         name,
    731         (rgba64 >> 32) & 0xFFFF,
    732         (rgba64 >> 16) & 0xFFFF,
    733         (rgba64 >>  0) & 0xFFFF,
    734         (rgba64 >> 48) & 0xFFFF);
    735       break;
    736     }
    737 
    738     case BL_OBJECT_TYPE_NULL: {
    739       BL_DEBUG_FMT("%s: Null\n", name);
    740       break;
    741     }
    742 
    743     case BL_OBJECT_TYPE_PATTERN: {
    744       bl_debug_pattern_((const BLPatternCore*)obj, name, indent);
    745       break;
    746     }
    747 
    748     case BL_OBJECT_TYPE_GRADIENT: {
    749       bl_debug_gradient_((const BLGradientCore*)obj, name, indent);
    750       break;
    751     }
    752 
    753     case BL_OBJECT_TYPE_IMAGE: {
    754       bl_debug_image_((const BLImageCore*)obj, name, indent);
    755       break;
    756     }
    757 
    758     case BL_OBJECT_TYPE_PATH: {
    759       bl_debug_path_((const BLPathCore*)obj, name, indent);
    760       break;
    761     }
    762 
    763     case BL_OBJECT_TYPE_FONT: {
    764       bl_debug_font_((BLFontCore*)obj, name, indent);
    765       break;
    766     }
    767 
    768     case BL_OBJECT_TYPE_FONT_FEATURE_SETTINGS: {
    769       bl_debug_font_feature_settings_((BLFontFeatureSettingsCore*)obj, name, indent);
    770       break;
    771     }
    772 
    773     case BL_OBJECT_TYPE_FONT_VARIATION_SETTINGS: {
    774       bl_debug_font_variation_settings_((BLFontVariationSettingsCore*)obj, name, indent);
    775       break;
    776     }
    777 
    778     case BL_OBJECT_TYPE_BOOL: {
    779       bool val;
    780       bl_var_to_bool(obj, &val);
    781       BL_DEBUG_FMT("%s: Bool(%s)\n", name, val ? "true" : "false");
    782       break;
    783     }
    784 
    785     case BL_OBJECT_TYPE_INT64: {
    786       int64_t val;
    787       bl_var_to_int64(obj, &val);
    788       BL_DEBUG_FMT("%s: Int64(%lld)\n", name, (long long)val);
    789       break;
    790     }
    791 
    792     case BL_OBJECT_TYPE_UINT64: {
    793       uint64_t val;
    794       bl_var_to_uint64(obj, &val);
    795       BL_DEBUG_FMT("%s: UInt64(%llu)\n", name, (unsigned long long)val);
    796       break;
    797     }
    798 
    799     case BL_OBJECT_TYPE_DOUBLE: {
    800       double val;
    801       bl_var_to_double(obj, &val);
    802       BL_DEBUG_FMT("%s: Double(%f)\n", name, val);
    803       break;
    804     }
    805 
    806     case BL_OBJECT_TYPE_ARRAY_OBJECT:
    807     case BL_OBJECT_TYPE_ARRAY_INT8:
    808     case BL_OBJECT_TYPE_ARRAY_UINT8:
    809     case BL_OBJECT_TYPE_ARRAY_INT16:
    810     case BL_OBJECT_TYPE_ARRAY_UINT16:
    811     case BL_OBJECT_TYPE_ARRAY_INT32:
    812     case BL_OBJECT_TYPE_ARRAY_UINT32:
    813     case BL_OBJECT_TYPE_ARRAY_INT64:
    814     case BL_OBJECT_TYPE_ARRAY_UINT64:
    815     case BL_OBJECT_TYPE_ARRAY_FLOAT32:
    816     case BL_OBJECT_TYPE_ARRAY_FLOAT64:
    817     case BL_OBJECT_TYPE_ARRAY_STRUCT_1:
    818     case BL_OBJECT_TYPE_ARRAY_STRUCT_2:
    819     case BL_OBJECT_TYPE_ARRAY_STRUCT_3:
    820     case BL_OBJECT_TYPE_ARRAY_STRUCT_4:
    821     case BL_OBJECT_TYPE_ARRAY_STRUCT_6:
    822     case BL_OBJECT_TYPE_ARRAY_STRUCT_8:
    823     case BL_OBJECT_TYPE_ARRAY_STRUCT_10:
    824     case BL_OBJECT_TYPE_ARRAY_STRUCT_12:
    825     case BL_OBJECT_TYPE_ARRAY_STRUCT_16:
    826     case BL_OBJECT_TYPE_ARRAY_STRUCT_20:
    827     case BL_OBJECT_TYPE_ARRAY_STRUCT_24:
    828     case BL_OBJECT_TYPE_ARRAY_STRUCT_32:
    829       bl_debug_array_((const BLArrayCore*)obj, name, indent);
    830       break;
    831 
    832     case BL_OBJECT_TYPE_CONTEXT:
    833       bl_debug_context_((const BLContextCore*)obj, name, indent);
    834       break;
    835 
    836     default:
    837       BL_DEBUG_FMT("BLObject { Type: %u }\n", (uint32_t)type);
    838       break;
    839   }
    840 }
    841 
    842 // BLDebug - Public API
    843 // ====================
    844 
    845 //! Dumps both `BLRuntimeBuildInfo` and `BLRuntimeSystemInfo`.
    846 //!
    847 //! This function should be used to retrieve information for Blend2D bug reports.
    848 static void bl_debug_runtime(void) {
    849   bl_debug_runtime_build_info();
    850   bl_debug_runtime_system_info();
    851 }
    852 
    853 //! Dumps BLArrayCore or BLArray<T>.
    854 static void bl_debug_array(const BLArrayCore* obj) {
    855   bl_debug_array_(obj, "BLArray", 0);
    856 }
    857 
    858 //! Dumps BLContextCore or BLContext.
    859 static void bl_debug_context(const BLContextCore* obj) {
    860   bl_debug_context_(obj, "BLContext", 0);
    861 }
    862 
    863 //! Dumps BLFontCore or BLFont.
    864 static void bl_debug_font(const BLFontCore* obj) {
    865   bl_debug_font_(obj, "BLFont", 0);
    866 }
    867 
    868 //! Dumps BLFontFeatureSettingsCore or BLFontFeatureSettings.
    869 static void bl_debug_font_feature_settings(const BLFontFeatureSettingsCore* obj) {
    870   bl_debug_font_feature_settings_(obj, "BLFontFeatureSettings", 0);
    871 }
    872 
    873 //! Dumps BLFontVariationSettingsCore or BLFontVariationSettings.
    874 static void bl_debug_font_variation_settings(const BLFontVariationSettingsCore* obj) {
    875   bl_debug_font_variation_settings_(obj, "BLFontVariationSettings", 0);
    876 }
    877 
    878 //! Dumps BLGradientCore or BLGradient.
    879 static void bl_debug_gradient(const BLGradientCore* obj) {
    880   bl_debug_gradient_(obj, "BLGradient", 0);
    881 }
    882 
    883 //! Dumps BLImageCore or BLImage.
    884 static void bl_debug_image(const BLImageCore* obj) {
    885   bl_debug_image_(obj, "BLImage", 0);
    886 }
    887 
    888 static void bl_debug_matrix2d(const BLMatrix2D* obj) {
    889   bl_debug_matrix2d_(obj, "BLMatrix", 0);
    890 }
    891 
    892 //! Dumps BLObjectCore or BLObject.
    893 //!
    894 //! You can use this function with any object that implements `BLObject` interface.
    895 static void bl_debug_object(const void* obj) {
    896   bl_debug_object_(obj, "BLObject", 0);
    897 }
    898 
    899 //! Dumps BLPathCore or BLPath.
    900 static void bl_debug_path(const BLPathCore* obj) {
    901   bl_debug_path_(obj, "BLPath", 0);
    902 }
    903 
    904 //! Dumps BLPatternCore or BLPattern.
    905 static void bl_debug_pattern(const BLPatternCore* obj) {
    906   bl_debug_pattern_(obj, "BLPattern", 0);
    907 }
    908 
    909 // BLDebug - End
    910 // =============
    911 
    912 #undef BL_DEBUG_FMT
    913 #undef BL_DEBUG_OUT
    914 
    915 //! \endcond
    916 
    917 #endif // BLEND2D_DEBUG_H_INCLUDED