odin-blend2d

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

glyphbuffer.cpp (11052B)


      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 #include "api-build_p.h"
      7 #include "array_p.h"
      8 #include "font_p.h"
      9 #include "glyphbuffer_p.h"
     10 #include "runtime_p.h"
     11 #include "string_p.h"
     12 #include "support/intops_p.h"
     13 #include "support/ptrops_p.h"
     14 #include "support/stringops_p.h"
     15 #include "unicode/unicode_p.h"
     16 
     17 // bl::GlyphBuffer - Internals
     18 // ===========================
     19 
     20 static const constexpr BLGlyphBufferPrivateImpl bl_glyph_buffer_internal_impl_none {};
     21 
     22 static BL_INLINE BLResult bl_glyph_buffer_ensure_data(BLGlyphBufferCore* self, BLGlyphBufferPrivateImpl** impl) noexcept {
     23   *impl = bl_glyph_buffer_get_impl(self);
     24   if (*impl != &bl_glyph_buffer_internal_impl_none)
     25     return BL_SUCCESS;
     26 
     27   *impl = BLGlyphBufferPrivateImpl::create();
     28   if (BL_UNLIKELY(!*impl))
     29     return bl_make_error(BL_ERROR_OUT_OF_MEMORY);
     30 
     31   self->impl = *impl;
     32   return BL_SUCCESS;
     33 }
     34 
     35 // bl::GlyphBuffer - Private API
     36 // =============================
     37 
     38 BLResult BLGlyphBufferPrivateImpl::ensure_buffer(size_t buffer_id, size_t copy_size, size_t min_capacity) noexcept {
     39   size_t old_capacity = capacity[buffer_id];
     40   BL_ASSERT(copy_size <= old_capacity);
     41 
     42   if (min_capacity <= old_capacity)
     43     return BL_SUCCESS;
     44 
     45   size_t new_capacity = min_capacity;
     46   if (new_capacity < BL_GLYPH_BUFFER_INITIAL_CAPACITY)
     47     new_capacity = BL_GLYPH_BUFFER_INITIAL_CAPACITY;
     48   else if (new_capacity < SIZE_MAX - 256)
     49     new_capacity = bl::IntOps::align_up(min_capacity, 64);
     50 
     51   bl::OverflowFlag of = 0;
     52   size_t data_size = bl::IntOps::mul_overflow<size_t>(new_capacity, BL_GLYPH_BUFFER_ANY_ITEM_SIZE, &of);
     53 
     54   if (BL_UNLIKELY(of))
     55     return BL_ERROR_OUT_OF_MEMORY;
     56 
     57   uint8_t* new_data = static_cast<uint8_t*>(malloc(data_size));
     58   if (BL_UNLIKELY(!new_data))
     59     return BL_ERROR_OUT_OF_MEMORY;
     60 
     61   uint8_t* old_data = static_cast<uint8_t*>(buffer[buffer_id]);
     62   if (copy_size) {
     63     memcpy(new_data,
     64            old_data,
     65            copy_size * sizeof(BLGlyphId));
     66 
     67     memcpy(new_data + new_capacity * sizeof(BLGlyphId),
     68            old_data + old_capacity * sizeof(BLGlyphId),
     69            copy_size * sizeof(BLGlyphInfo));
     70   }
     71 
     72   free(old_data);
     73   buffer[buffer_id] = new_data;
     74   capacity[buffer_id] = new_capacity;
     75 
     76   if (buffer_id == 0)
     77     get_glyph_data_ptrs(0, &content, &info_data);
     78 
     79   return BL_SUCCESS;
     80 }
     81 
     82 template<typename T>
     83 static BL_INLINE BLGlyphInfo bl_glyph_info_from_cluster(const T& cluster) noexcept {
     84   return BLGlyphInfo { uint32_t(cluster), 0 };
     85 }
     86 
     87 template<typename T>
     88 static BL_INLINE BLResult bl_internal_glyph_buffer_data_set_glyph_ids(BLGlyphBufferPrivateImpl* d, const T* src, size_t size, intptr_t advance) noexcept {
     89   uint32_t* glyph_data = d->content;
     90   BLGlyphInfo* info_data = d->info_data;
     91 
     92   for (size_t i = 0; i < size; i++) {
     93     glyph_data[i] = uint32_t(src[0]);
     94     info_data[i] = bl_glyph_info_from_cluster(i);
     95     src = bl::PtrOps::offset(src, advance);
     96   }
     97 
     98   d->size = size;
     99   d->flags = 0;
    100   return BL_SUCCESS;
    101 }
    102 
    103 static BL_INLINE BLResult bl_internal_glyph_buffer_data_set_latin1_text(BLGlyphBufferPrivateImpl* d, const char* src, size_t size) noexcept {
    104   uint32_t* text_data = d->content;
    105   BLGlyphInfo* info_data = d->info_data;
    106 
    107   for (size_t i = 0; i < size; i++) {
    108     text_data[i] = uint8_t(src[i]);
    109     info_data[i] = bl_glyph_info_from_cluster(i);
    110   }
    111 
    112   d->size = size;
    113   d->flags = 0;
    114 
    115   if (d->size)
    116     d->flags |= BL_GLYPH_RUN_FLAG_UCS4_CONTENT;
    117 
    118   return BL_SUCCESS;
    119 }
    120 
    121 template<typename Reader, typename CharType>
    122 static BL_INLINE BLResult bl_internal_glyph_buffer_data_set_unicode_text(BLGlyphBufferPrivateImpl* d, const CharType* src, size_t size) noexcept {
    123   Reader reader(src, size);
    124 
    125   uint32_t* text_data = d->content;
    126   BLGlyphInfo* info_data = d->info_data;
    127 
    128   while (reader.has_next()) {
    129     uint32_t uc;
    130     uint32_t cluster = uint32_t(reader.native_index(src));
    131     BLResult result = reader.next(uc);
    132 
    133     *text_data++ = uc;
    134     *info_data++ = bl_glyph_info_from_cluster(cluster);
    135 
    136     if (BL_LIKELY(result == BL_SUCCESS))
    137       continue;
    138 
    139     text_data[-1] = bl::Unicode::kCharReplacement;
    140     d->flags |= BL_GLYPH_RUN_FLAG_INVALID_TEXT;
    141     reader.skip_one_unit();
    142   }
    143 
    144   d->size = (size_t)(text_data - d->content);
    145   d->flags = 0;
    146 
    147   if (d->size)
    148     d->flags |= BL_GLYPH_RUN_FLAG_UCS4_CONTENT;
    149 
    150   return BL_SUCCESS;
    151 }
    152 
    153 // bl::GlyphBuffer - Init & Destroy
    154 // ================================
    155 
    156 BL_API_IMPL BLResult bl_glyph_buffer_init(BLGlyphBufferCore* self) noexcept {
    157   self->impl = const_cast<BLGlyphBufferPrivateImpl*>(&bl_glyph_buffer_internal_impl_none);
    158   return BL_SUCCESS;
    159 }
    160 
    161 BL_API_IMPL BLResult bl_glyph_buffer_init_move(BLGlyphBufferCore* self, BLGlyphBufferCore* other) noexcept {
    162   BLGlyphBufferPrivateImpl* impl = bl_glyph_buffer_get_impl(other);
    163   other->impl = const_cast<BLGlyphBufferPrivateImpl*>(&bl_glyph_buffer_internal_impl_none);
    164   self->impl = impl;
    165   return BL_SUCCESS;
    166 }
    167 
    168 BL_API_IMPL BLResult bl_glyph_buffer_destroy(BLGlyphBufferCore* self) noexcept {
    169   BLGlyphBufferPrivateImpl* impl = bl_glyph_buffer_get_impl(self);
    170   self->impl = nullptr;
    171 
    172   if (impl != &bl_glyph_buffer_internal_impl_none)
    173     impl->destroy();
    174   return BL_SUCCESS;
    175 }
    176 
    177 // bl::GlyphBuffer - Reset
    178 // =======================
    179 
    180 BL_API_IMPL BLResult bl_glyph_buffer_reset(BLGlyphBufferCore* self) noexcept {
    181   BLGlyphBufferPrivateImpl* impl = bl_glyph_buffer_get_impl(self);
    182   self->impl = const_cast<BLGlyphBufferPrivateImpl*>(&bl_glyph_buffer_internal_impl_none);
    183 
    184   if (impl != &bl_glyph_buffer_internal_impl_none)
    185     impl->destroy();
    186   return BL_SUCCESS;
    187 }
    188 
    189 // bl::GlyphBuffer - Content
    190 // =========================
    191 
    192 BL_API_IMPL BLResult bl_glyph_buffer_clear(BLGlyphBufferCore* self) noexcept {
    193   BLGlyphBufferPrivateImpl* self_impl = bl_glyph_buffer_get_impl(self);
    194 
    195   // Would be true if the glyph-buffer is built-in 'none' instance or the data
    196   // is allocated, but empty.
    197   if (self_impl->size == 0)
    198     return BL_SUCCESS;
    199 
    200   self_impl->clear();
    201   return BL_SUCCESS;
    202 }
    203 
    204 BL_API_IMPL size_t bl_glyph_buffer_get_size(const BLGlyphBufferCore* self) noexcept {
    205   BLGlyphBufferPrivateImpl* self_impl = bl_glyph_buffer_get_impl(self);
    206   return self_impl->size;
    207 }
    208 
    209 BL_API_IMPL uint32_t bl_glyph_buffer_get_flags(const BLGlyphBufferCore* self) noexcept {
    210   BLGlyphBufferPrivateImpl* self_impl = bl_glyph_buffer_get_impl(self);
    211   return self_impl->flags;
    212 }
    213 
    214 BL_API_IMPL const BLGlyphRun* bl_glyph_buffer_get_glyph_run(const BLGlyphBufferCore* self) noexcept {
    215   BLGlyphBufferPrivateImpl* self_impl = bl_glyph_buffer_get_impl(self);
    216   return &self_impl->glyph_run;
    217 }
    218 
    219 BL_API_IMPL const uint32_t* bl_glyph_buffer_get_content(const BLGlyphBufferCore* self) noexcept {
    220   BLGlyphBufferPrivateImpl* self_impl = bl_glyph_buffer_get_impl(self);
    221   return self_impl->content;
    222 }
    223 
    224 BL_API_IMPL const BLGlyphInfo* bl_glyph_buffer_get_info_data(const BLGlyphBufferCore* self) noexcept {
    225   BLGlyphBufferPrivateImpl* self_impl = bl_glyph_buffer_get_impl(self);
    226   return self_impl->info_data;
    227 }
    228 
    229 BL_API_IMPL const BLGlyphPlacement* bl_glyph_buffer_get_placement_data(const BLGlyphBufferCore* self) noexcept {
    230   BLGlyphBufferPrivateImpl* self_impl = bl_glyph_buffer_get_impl(self);
    231   return self_impl->placement_data;
    232 }
    233 
    234 BL_API_IMPL BLResult bl_glyph_buffer_set_text(BLGlyphBufferCore* self, const void* text_data, size_t size, BLTextEncoding encoding) noexcept {
    235   if (BL_UNLIKELY(uint32_t(encoding) > BL_TEXT_ENCODING_MAX_VALUE))
    236     return bl_make_error(BL_ERROR_INVALID_VALUE);
    237 
    238   BLGlyphBufferPrivateImpl* d;
    239   BL_PROPAGATE(bl_glyph_buffer_ensure_data(self, &d));
    240 
    241   switch (encoding) {
    242     case BL_TEXT_ENCODING_LATIN1:
    243       if (size == SIZE_MAX)
    244         size = strlen(static_cast<const char*>(text_data));
    245 
    246       BL_PROPAGATE(d->ensure_buffer(0, 0, size));
    247       return bl_internal_glyph_buffer_data_set_latin1_text(d, static_cast<const char*>(text_data), size);
    248 
    249     case BL_TEXT_ENCODING_UTF8:
    250       if (size == SIZE_MAX)
    251         size = strlen(static_cast<const char*>(text_data));
    252 
    253       BL_PROPAGATE(d->ensure_buffer(0, 0, size));
    254       return bl_internal_glyph_buffer_data_set_unicode_text<bl::Unicode::Utf8Reader>(d, static_cast<const uint8_t*>(text_data), size);
    255 
    256     case BL_TEXT_ENCODING_UTF16:
    257       if (size == SIZE_MAX)
    258         size = bl::StringOps::length(static_cast<const uint16_t*>(text_data));
    259 
    260       BL_PROPAGATE(d->ensure_buffer(0, 0, size));
    261       return bl_internal_glyph_buffer_data_set_unicode_text<bl::Unicode::Utf16Reader>(d, static_cast<const uint16_t*>(text_data), size * 2u);
    262 
    263     case BL_TEXT_ENCODING_UTF32:
    264       if (size == SIZE_MAX)
    265         size = bl::StringOps::length(static_cast<const uint32_t*>(text_data));
    266 
    267       BL_PROPAGATE(d->ensure_buffer(0, 0, size));
    268       return bl_internal_glyph_buffer_data_set_unicode_text<bl::Unicode::Utf32Reader>(d, static_cast<const uint32_t*>(text_data), size * 4u);
    269 
    270     default:
    271       // Avoids a compile-time warning, should never be reached.
    272       return bl_make_error(BL_ERROR_INVALID_VALUE);
    273   }
    274 }
    275 
    276 BL_API_IMPL BLResult bl_glyph_buffer_set_glyphs(BLGlyphBufferCore* self, const uint32_t* glyph_data, size_t size) noexcept {
    277   if (BL_UNLIKELY(sizeof(size_t) > 4 && size > 0xFFFFFFFFu))
    278     return bl_make_error(BL_ERROR_DATA_TOO_LARGE);
    279 
    280   BLGlyphBufferPrivateImpl* d;
    281 
    282   BL_PROPAGATE(bl_glyph_buffer_ensure_data(self, &d));
    283   BL_PROPAGATE(d->ensure_buffer(0, 0, size));
    284 
    285   return bl_internal_glyph_buffer_data_set_glyph_ids(d, glyph_data, size, intptr_t(sizeof(uint16_t)));
    286 }
    287 
    288 BL_API_IMPL BLResult bl_glyph_buffer_set_glyphs_from_struct(BLGlyphBufferCore* self, const void* glyph_data, size_t size, size_t glyph_id_size, intptr_t glyph_id_advance) noexcept {
    289   if (BL_UNLIKELY(glyph_id_size != 2 && glyph_id_size != 4))
    290     return bl_make_error(BL_ERROR_INVALID_VALUE);
    291 
    292   if (BL_UNLIKELY(sizeof(size_t) > 4 && size > 0xFFFFFFFFu))
    293     return bl_make_error(BL_ERROR_DATA_TOO_LARGE);
    294 
    295   BLGlyphBufferPrivateImpl* d;
    296 
    297   BL_PROPAGATE(bl_glyph_buffer_ensure_data(self, &d));
    298   BL_PROPAGATE(d->ensure_buffer(0, 0, size));
    299 
    300   if (glyph_id_size == 2)
    301     return bl_internal_glyph_buffer_data_set_glyph_ids(d, static_cast<const uint16_t*>(glyph_data), size, glyph_id_advance);
    302   else
    303     return bl_internal_glyph_buffer_data_set_glyph_ids(d, static_cast<const uint32_t*>(glyph_data), size, glyph_id_advance);
    304 }
    305 
    306 BL_API_IMPL BLResult bl_glyph_buffer_set_debug_sink(BLGlyphBufferCore* self, BLDebugMessageSinkFunc sink, void* user_data) noexcept {
    307   if (!sink)
    308     return bl_glyph_buffer_reset_debug_sink(self);
    309 
    310   BLGlyphBufferPrivateImpl* d;
    311   BL_PROPAGATE(bl_glyph_buffer_ensure_data(self, &d));
    312 
    313   d->debug_sink = sink;
    314   d->debug_sink_user_data = user_data;
    315 
    316   return BL_SUCCESS;
    317 }
    318 
    319 BL_API_IMPL BLResult bl_glyph_buffer_reset_debug_sink(BLGlyphBufferCore* self) noexcept {
    320   if (!bl_glyph_buffer_get_impl(self)->debug_sink)
    321     return BL_SUCCESS;
    322 
    323   BLGlyphBufferPrivateImpl* d;
    324   BL_PROPAGATE(bl_glyph_buffer_ensure_data(self, &d));
    325 
    326   d->debug_sink = nullptr;
    327   d->debug_sink_user_data = nullptr;
    328 
    329   return BL_SUCCESS;
    330 }