Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Firefox/gfx/harfbuzz/src/OT/Color/CBDT/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 30 kB image not shown  

Quelle  CBDT.hh   Sprache: C

 
/*
 * Copyright © 2016  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Google Author(s): Seigo Nonaka, Calder Kitagawa
 */


#ifndef OT_COLOR_CBDT_CBDT_HH
#define OT_COLOR_CBDT_CBDT_HH

#include "../../../hb-open-type.hh"
#include "../../../hb-paint.hh"

/*
 * CBLC -- Color Bitmap Location
 * https://docs.microsoft.com/en-us/typography/opentype/spec/cblc
 * https://docs.microsoft.com/en-us/typography/opentype/spec/eblc
 * CBDT -- Color Bitmap Data
 * https://docs.microsoft.com/en-us/typography/opentype/spec/cbdt
 * https://docs.microsoft.com/en-us/typography/opentype/spec/ebdt
 */

#define HB_OT_TAG_CBLC HB_TAG('C','B','L','C')
#define HB_OT_TAG_CBDT HB_TAG('C','B','D','T')


namespace OT {

struct cblc_bitmap_size_subset_context_t
{
  const char *cbdt;
  unsigned int cbdt_length;
  hb_vector_t<char> *cbdt_prime;
  unsigned int size;  /* INOUT
 *  Input: old size of IndexSubtable
 *  Output: new size of IndexSubtable
 */

  unsigned int num_tables; /* INOUT
 *  Input: old number of subtables.
 *  Output: new number of subtables.
 */

  hb_codepoint_t start_glyph; /* OUT */
  hb_codepoint_t end_glyph; /* OUT */
};

static inline bool
_copy_data_to_cbdt (hb_vector_t<char> *cbdt_prime,
      const void        *data,
      unsigned           length)
{
  unsigned int new_len = cbdt_prime->length + length;
  if (unlikely (!cbdt_prime->alloc (new_len))) return false;
  hb_memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length);
  cbdt_prime->length = new_len;
  return true;
}

struct SmallGlyphMetrics
{
  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scale) const
  {
    extents->x_bearing = bearingX;
    extents->y_bearing = bearingY;
    extents->width = width;
    extents->height = -static_cast<int> (height);

    if (scale)
      font->scale_glyph_extents (extents);
  }

  HBUINT8 height;
  HBUINT8 width;
  HBINT8 bearingX;
  HBINT8 bearingY;
  HBUINT8 advance;
  public:
  DEFINE_SIZE_STATIC (5);
};

struct BigGlyphMetrics : SmallGlyphMetrics
{
  HBINT8 vertBearingX;
  HBINT8 vertBearingY;
  HBUINT8 vertAdvance;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct SBitLineMetrics
{
  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  HBINT8 ascender;
  HBINT8 decender;
  HBUINT8 widthMax;
  HBINT8 caretSlopeNumerator;
  HBINT8 caretSlopeDenominator;
  HBINT8 caretOffset;
  HBINT8 minOriginSB;
  HBINT8 minAdvanceSB;
  HBINT8 maxBeforeBL;
  HBINT8 minAfterBL;
  HBINT8 padding1;
  HBINT8 padding2;
  public:
  DEFINE_SIZE_STATIC (12);
};


/*
 * Index Subtables.
 */


struct IndexSubtableHeader
{
  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  HBUINT16 indexFormat;
  HBUINT16 imageFormat;
  HBUINT32 imageDataOffset;
  public:
  DEFINE_SIZE_STATIC (8);
};

template <typename OffsetType>
struct IndexSubtableFormat1Or3
{
  bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
    offsetArrayZ.sanitize (c, glyph_count + 1));
  }

  bool get_image_data (unsigned int idx,
         unsigned int *offset,
         unsigned int *length) const
  {
    if (unlikely (offsetArrayZ[idx + 1] <= offsetArrayZ[idx]))
      return false;

    *offset = header.imageDataOffset + offsetArrayZ[idx];
    *length = offsetArrayZ[idx + 1] - offsetArrayZ[idx];
    return true;
  }

  bool add_offset (hb_serialize_context_t *c,
     unsigned int offset,
     unsigned int *size /* OUT (accumulated) */)
  {
    TRACE_SERIALIZE (this);
    Offset<OffsetType> embedded_offset;
    embedded_offset = offset;
    *size += sizeof (OffsetType);
    auto *o = c->embed (embedded_offset);
    return_trace ((bool) o);
  }

  IndexSubtableHeader header;
  UnsizedArrayOf<Offset<OffsetType>>
   offsetArrayZ;
  public:
  DEFINE_SIZE_ARRAY (8, offsetArrayZ);
};

struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<HBUINT32> {};
struct IndexSubtableFormat3 : IndexSubtableFormat1Or3<HBUINT16> {};

struct IndexSubtable
{
  bool sanitize (hb_sanitize_context_t *c, unsigned int glyph_count) const
  {
    TRACE_SANITIZE (this);
    if (!u.header.sanitize (c)) return_trace (false);
    hb_barrier ();
    switch (u.header.indexFormat)
    {
    case 1: return_trace (u.format1.sanitize (c, glyph_count));
    case 3: return_trace (u.format3.sanitize (c, glyph_count));
    default:return_trace (true);
    }
  }

  bool
  finish_subtable (hb_serialize_context_t *c,
     unsigned int cbdt_prime_len,
     unsigned int num_glyphs,
     unsigned int *size /* OUT (accumulated) */)
  {
    TRACE_SERIALIZE (this);

    unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset;
    switch (u.header.indexFormat)
    {
    case 1: return_trace (u.format1.add_offset (c, local_offset, size));
    case 3: {
      if (!u.format3.add_offset (c, local_offset, size))
 return_trace (false);
      if (!(num_glyphs & 0x01))  // Pad to 32-bit alignment if needed.
 return_trace (u.format3.add_offset (c, 0, size));
      return_trace (true);
    }
    // TODO: implement 2, 4, 5.
    case 2: case 4:  // No-op.
    case 5:  // Pad to 32-bit aligned.
    default: return_trace (false);
    }
  }

  bool
  fill_missing_glyphs (hb_serialize_context_t *c,
         unsigned int cbdt_prime_len,
         unsigned int num_missing,
         unsigned int *size /* OUT (accumulated) */,
         unsigned int *num_glyphs /* OUT (accumulated) */)
  {
    TRACE_SERIALIZE (this);

    unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset;
    switch (u.header.indexFormat)
    {
    case 1: {
      for (unsigned int i = 0; i < num_missing; i++)
      {
 if (unlikely (!u.format1.add_offset (c, local_offset, size)))
   return_trace (false);
 *num_glyphs += 1;
      }
      return_trace (true);
    }
    case 3: {
      for (unsigned int i = 0; i < num_missing; i++)
      {
 if (unlikely (!u.format3.add_offset (c, local_offset, size)))
   return_trace (false);
 *num_glyphs += 1;
      }
      return_trace (true);
    }
    // TODO: implement 2, 4, 5.
    case 2:  // Add empty space in cbdt_prime?.
    case 4: case 5:  // No-op as sparse is supported.
    default: return_trace (false);
    }
  }

  bool
  copy_glyph_at_idx (hb_serialize_context_t *c, unsigned int idx,
       const char *cbdt, unsigned int cbdt_length,
       hb_vector_t<char> *cbdt_prime /* INOUT */,
       IndexSubtable *subtable_prime /* INOUT */,
       unsigned int *size /* OUT (accumulated) */) const
  {
    TRACE_SERIALIZE (this);

    unsigned int offset, length, format;
    if (unlikely (!get_image_data (idx, &offset, &length, &format))) return_trace (false);
    if (unlikely (offset > cbdt_length || cbdt_length - offset < length)) return_trace (false);

    auto *header_prime = subtable_prime->get_header ();
    unsigned int new_local_offset = cbdt_prime->length - (unsigned int) header_prime->imageDataOffset;
    if (unlikely (!_copy_data_to_cbdt (cbdt_prime, cbdt + offset, length))) return_trace (false);

    return_trace (subtable_prime->add_offset (c, new_local_offset, size));
  }

  bool
  add_offset (hb_serialize_context_t *c, unsigned int local_offset,
       unsigned int *size /* OUT (accumulated) */)
  {
    TRACE_SERIALIZE (this);
    switch (u.header.indexFormat)
    {
    case 1: return_trace (u.format1.add_offset (c, local_offset, size));
    case 3: return_trace (u.format3.add_offset (c, local_offset, size));
    // TODO: Implement tables 2, 4, 5
    case 2:  // Should be a no-op.
    case 4: case 5:  // Handle sparse cases.
    default: return_trace (false);
    }
  }

  bool get_extents (hb_glyph_extents_t *extents HB_UNUSED, bool scale HB_UNUSED) const
  {
    switch (u.header.indexFormat)
    {
    case 2: case 5: /* TODO */
    case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
    default:return (false);
    }
  }

  bool
  get_image_data (unsigned int idx, unsigned int *offset,
    unsigned int *length, unsigned int *format) const
  {
    *format = u.header.imageFormat;
    switch (u.header.indexFormat)
    {
    case 1: return u.format1.get_image_data (idx, offset, length);
    case 3: return u.format3.get_image_data (idx, offset, length);
    defaultreturn false;
    }
  }

  const IndexSubtableHeader* get_header () const { return &u.header; }

  void populate_header (unsigned index_format,
   unsigned image_format,
   unsigned int image_data_offset,
   unsigned int *size)
  {
    u.header.indexFormat = index_format;
    u.header.imageFormat = image_format;
    u.header.imageDataOffset = image_data_offset;
    switch (u.header.indexFormat)
    {
    case 1: *size += IndexSubtableFormat1::min_size; break;
    case 3: *size += IndexSubtableFormat3::min_size; break;
    }
  }

  protected:
  union {
  IndexSubtableHeader header;
  IndexSubtableFormat1 format1;
  IndexSubtableFormat3 format3;
  /* TODO: Format 2, 4, 5. */
  } u;
  public:
  DEFINE_SIZE_UNION (8, header);
};

struct IndexSubtableRecord
{
  /* XXX Remove this and fix by not inserting it into vector. */
  IndexSubtableRecord& operator = (const IndexSubtableRecord &o)
  {
    firstGlyphIndex = o.firstGlyphIndex;
    lastGlyphIndex = o.lastGlyphIndex;
    offsetToSubtable = (unsigned) o.offsetToSubtable;
    assert (offsetToSubtable.is_null ());
    return *this;
  }

  bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
    hb_barrier () &&
    firstGlyphIndex <= lastGlyphIndex &&
    offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
  }

  const IndexSubtable* get_subtable (const void *base) const
  {
    return &(base+offsetToSubtable);
  }

  bool add_new_subtable (hb_subset_context_t* c,
    cblc_bitmap_size_subset_context_t *bitmap_size_context,
    IndexSubtableRecord *record,
    const hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> *lookup, /* IN */
    const void *base,
    unsigned int *start /* INOUT */) const
  {
    TRACE_SERIALIZE (this);

    auto *subtable = c->serializer->start_embed<IndexSubtable> ();
    if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false);

    auto *old_subtable = get_subtable (base);
    auto *old_header = old_subtable->get_header ();

    subtable->populate_header (old_header->indexFormat,
          old_header->imageFormat,
          bitmap_size_context->cbdt_prime->length,
          &bitmap_size_context->size);

    unsigned int num_glyphs = 0;
    bool early_exit = false;
    for (unsigned int i = *start; i < lookup->length; i++)
    {
      hb_codepoint_t new_gid = (*lookup)[i].first;
      const IndexSubtableRecord *next_record = (*lookup)[i].second;
      const IndexSubtable *next_subtable = next_record->get_subtable (base);
      auto *next_header = next_subtable->get_header ();
      if (next_header != old_header)
      {
 *start = i;
 early_exit = true;
 break;
      }
      unsigned int num_missing = record->add_glyph_for_subset (new_gid);
      if (unlikely (!subtable->fill_missing_glyphs (c->serializer,
          bitmap_size_context->cbdt_prime->length,
          num_missing,
          &bitmap_size_context->size,
          &num_glyphs)))
 return_trace (false);

      hb_codepoint_t old_gid = 0;
      c->plan->old_gid_for_new_gid (new_gid, &old_gid);
      if (old_gid < next_record->firstGlyphIndex)
 return_trace (false);

      unsigned int old_idx = (unsigned int) old_gid - next_record->firstGlyphIndex;
      if (unlikely (!next_subtable->copy_glyph_at_idx (c->serializer,
             old_idx,
             bitmap_size_context->cbdt,
             bitmap_size_context->cbdt_length,
             bitmap_size_context->cbdt_prime,
             subtable,
             &bitmap_size_context->size)))
 return_trace (false);
      num_glyphs += 1;
    }
    if (!early_exit)
      *start = lookup->length;
    if (unlikely (!subtable->finish_subtable (c->serializer,
           bitmap_size_context->cbdt_prime->length,
           num_glyphs,
           &bitmap_size_context->size)))
      return_trace (false);
    return_trace (true);
  }

  bool add_new_record (hb_subset_context_t *c,
         cblc_bitmap_size_subset_context_t *bitmap_size_context,
         const hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> *lookup, /* IN */
         const void *base,
         unsigned int *start, /* INOUT */
         hb_vector_t<IndexSubtableRecord>* records /* INOUT */) const
  {
    TRACE_SERIALIZE (this);
    auto snap = c->serializer->snapshot ();
    unsigned int old_size = bitmap_size_context->size;
    unsigned int old_cbdt_prime_length = bitmap_size_context->cbdt_prime->length;

    // Set to invalid state to indicate filling glyphs is not yet started.
    if (unlikely (!c->serializer->check_success (records->resize (records->length + 1))))
      return_trace (false);

    records->tail ().firstGlyphIndex = 1;
    records->tail ().lastGlyphIndex = 0;
    bitmap_size_context->size += IndexSubtableRecord::min_size;

    c->serializer->push ();

    if (unlikely (!add_new_subtable (c, bitmap_size_context, &(records->tail ()), lookup, base, start)))
    {
      c->serializer->pop_discard ();
      c->serializer->revert (snap);
      bitmap_size_context->cbdt_prime->shrink (old_cbdt_prime_length);
      bitmap_size_context->size = old_size;
      records->resize (records->length - 1);
      return_trace (false);
    }

    bitmap_size_context->num_tables += 1;
    return_trace (true);
  }

  unsigned int add_glyph_for_subset (hb_codepoint_t gid)
  {
    if (firstGlyphIndex > lastGlyphIndex)
    {
      firstGlyphIndex = gid;
      lastGlyphIndex = gid;
      return 0;
    }
    // TODO maybe assert? this shouldn't occur.
    if (lastGlyphIndex > gid)
      return 0;
    unsigned int num_missing = (unsigned int) (gid - lastGlyphIndex - 1);
    lastGlyphIndex = gid;
    return num_missing;
  }

  bool get_extents (hb_glyph_extents_t *extents, const void *base, bool scale) const
  { return (base+offsetToSubtable).get_extents (extents, scale); }

  bool get_image_data (unsigned int  gid,
         const void   *base,
         unsigned int *offset,
         unsigned int *length,
         unsigned int *format) const
  {
    if (gid < firstGlyphIndex || gid > lastGlyphIndex) return false;
    return (base+offsetToSubtable).get_image_data (gid - firstGlyphIndex,
         offset, length, format);
  }

  HBGlyphID16   firstGlyphIndex;
  HBGlyphID16   lastGlyphIndex;
  Offset32To<IndexSubtable> offsetToSubtable;
  public:
  DEFINE_SIZE_STATIC (8);
};

struct IndexSubtableArray
{
  friend struct CBDT;

  bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
  {
    TRACE_SANITIZE (this);
    return_trace (indexSubtablesZ.sanitize (c, count, this));
  }

  void
  build_lookup (hb_subset_context_t *c, cblc_bitmap_size_subset_context_t *bitmap_size_context,
  hb_vector_t<hb_pair_t<hb_codepoint_t,
  const IndexSubtableRecord*>> *lookup /* OUT */) const
  {
    bool start_glyph_is_set = false;
    unsigned num_glyphs = c->plan->num_output_glyphs ();
    for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
    {
      hb_codepoint_t old_gid;
      if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue;

      const IndexSubtableRecord* record = find_table (old_gid, bitmap_size_context->num_tables);
      if (unlikely (!record)) continue;

      // Don't add gaps to the lookup. The best way to determine if a glyph is a
      // gap is that it has no image data.
      unsigned int offset, length, format;
      if (unlikely (!record->get_image_data (old_gid, this, &offset, &length, &format))) continue;

      lookup->push (hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*> (new_gid, record));

      if (!start_glyph_is_set)
      {
 bitmap_size_context->start_glyph = new_gid;
 start_glyph_is_set = true;
      }

      bitmap_size_context->end_glyph = new_gid;
    }
  }

  bool
  subset (hb_subset_context_t *c,
   cblc_bitmap_size_subset_context_t *bitmap_size_context) const
  {
    TRACE_SUBSET (this);

    hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup;
    build_lookup (c, bitmap_size_context, &lookup);
    if (unlikely (!c->serializer->propagate_error (lookup)))
      return false;

    bitmap_size_context->size = 0;
    bitmap_size_context->num_tables = 0;
    hb_vector_t<IndexSubtableRecord> records;
    for (unsigned int start = 0; start < lookup.length;)
    {
      if (unlikely (!lookup[start].second->add_new_record (c, bitmap_size_context, &lookup, this, &start, &records)))
      {
 // Discard any leftover pushes to the serializer from successful records.
 for (unsigned int i = 0; i < records.length; i++)
   c->serializer->pop_discard ();
 return_trace (false);
      }
    }

    /* Workaround to ensure offset ordering is from least to greatest when
     * resolving links. */

    hb_vector_t<hb_serialize_context_t::objidx_t> objidxs;
    for (unsigned int i = 0; i < records.length; i++)
      objidxs.push (c->serializer->pop_pack ());
    for (unsigned int i = 0; i < records.length; i++)
    {
      IndexSubtableRecord* record = c->serializer->embed (records[i]);
      if (unlikely (!record)) return_trace (false);
      c->serializer->add_link (record->offsetToSubtable, objidxs[records.length - 1 - i]);
    }
    return_trace (true);
  }

  public:
  const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
  {
    for (unsigned int i = 0; i < numTables; ++i)
    {
      unsigned int firstGlyphIndex = indexSubtablesZ[i].firstGlyphIndex;
      unsigned int lastGlyphIndex = indexSubtablesZ[i].lastGlyphIndex;
      if (firstGlyphIndex <= glyph && glyph <= lastGlyphIndex)
 return &indexSubtablesZ[i];
    }
    return nullptr;
  }

  protected:
  UnsizedArrayOf<IndexSubtableRecord> indexSubtablesZ;
};

struct BitmapSizeTable
{
  friend struct CBLC;
  friend struct CBDT;

  bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
    hb_barrier () &&
    indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
    horizontal.sanitize (c) &&
    vertical.sanitize (c));
  }

  const IndexSubtableRecord *
  find_table (hb_codepoint_t glyph, const void *base, const void **out_base) const
  {
    *out_base = &(base+indexSubtableArrayOffset);
    return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
  }

  bool
  subset (hb_subset_context_t *c, const void *base,
   const char *cbdt, unsigned int cbdt_length,
   hb_vector_t<char> *cbdt_prime /* INOUT */) const
  {
    TRACE_SUBSET (this);
    auto *out_table = c->serializer->embed (this);
    if (unlikely (!out_table)) return_trace (false);

    cblc_bitmap_size_subset_context_t bitmap_size_context;
    bitmap_size_context.cbdt = cbdt;
    bitmap_size_context.cbdt_length = cbdt_length;
    bitmap_size_context.cbdt_prime = cbdt_prime;
    bitmap_size_context.size = indexTablesSize;
    bitmap_size_context.num_tables = numberOfIndexSubtables;
    bitmap_size_context.start_glyph = 1;
    bitmap_size_context.end_glyph = 0;

    if (!out_table->indexSubtableArrayOffset.serialize_subset (c,
              indexSubtableArrayOffset,
              base,
              &bitmap_size_context))
      return_trace (false);
    if (!bitmap_size_context.size ||
 !bitmap_size_context.num_tables ||
 bitmap_size_context.start_glyph > bitmap_size_context.end_glyph)
      return_trace (false);

    out_table->indexTablesSize = bitmap_size_context.size;
    out_table->numberOfIndexSubtables = bitmap_size_context.num_tables;
    out_table->startGlyphIndex = bitmap_size_context.start_glyph;
    out_table->endGlyphIndex = bitmap_size_context.end_glyph;
    return_trace (true);
  }

  protected:
  NNOffset32To<IndexSubtableArray>
   indexSubtableArrayOffset;
  HBUINT32  indexTablesSize;
  HBUINT32  numberOfIndexSubtables;
  HBUINT32  colorRef;
  SBitLineMetrics horizontal;
  SBitLineMetrics vertical;
  HBGlyphID16  startGlyphIndex;
  HBGlyphID16  endGlyphIndex;
  HBUINT8  ppemX;
  HBUINT8  ppemY;
  HBUINT8  bitDepth;
  HBINT8  flags;
  public:
  DEFINE_SIZE_STATIC (48);
};


/*
 * Glyph Bitmap Data Formats.
 */


struct GlyphBitmapDataFormat17
{
  SmallGlyphMetrics glyphMetrics;
  Array32Of<HBUINT8> data;
  public:
  DEFINE_SIZE_ARRAY (9, data);
};

struct GlyphBitmapDataFormat18
{
  BigGlyphMetrics glyphMetrics;
  Array32Of<HBUINT8> data;
  public:
  DEFINE_SIZE_ARRAY (12, data);
};

struct GlyphBitmapDataFormat19
{
  Array32Of<HBUINT8> data;
  public:
  DEFINE_SIZE_ARRAY (4, data);
};

struct CBLC
{
  friend struct CBDT;

  static constexpr hb_tag_t tableTag = HB_OT_TAG_CBLC;

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
    hb_barrier () &&
    likely (version.major == 2 || version.major == 3) &&
    hb_barrier () &&
    sizeTables.sanitize (c, this));
  }

  static bool
  sink_cbdt (hb_subset_context_t *c, hb_vector_t<char>* cbdt_prime)
  {
    hb_blob_t *cbdt_prime_blob = hb_blob_create (cbdt_prime->arrayZ,
       cbdt_prime->length,
       HB_MEMORY_MODE_WRITABLE,
       cbdt_prime->arrayZ,
       hb_free);
    cbdt_prime->init ();  // Leak arrayZ to the blob.
    bool ret = c->plan->add_table (HB_OT_TAG_CBDT, cbdt_prime_blob);
    hb_blob_destroy (cbdt_prime_blob);
    return ret;
  }

  bool
  subset_size_table (hb_subset_context_t *c, const BitmapSizeTable& table,
       const char *cbdt /* IN */, unsigned int cbdt_length,
       CBLC *cblc_prime /* INOUT */, hb_vector_t<char> *cbdt_prime /* INOUT */) const
  {
    TRACE_SUBSET (this);
    cblc_prime->sizeTables.len++;

    auto snap = c->serializer->snapshot ();
    auto cbdt_prime_len = cbdt_prime->length;

    if (!table.subset (c, this, cbdt, cbdt_length, cbdt_prime))
    {
      cblc_prime->sizeTables.len--;
      c->serializer->revert (snap);
      cbdt_prime->shrink (cbdt_prime_len);
      return_trace (false);
    }
    return_trace (true);
  }

  // Implemented in cc file as it depends on definition of CBDT.
  HB_INTERNAL bool subset (hb_subset_context_t *c) const;

  protected:
  const BitmapSizeTable &choose_strike (hb_font_t *font) const
  {
    unsigned count = sizeTables.len;
    if (unlikely (!count))
      return Null (BitmapSizeTable);

    unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
    if (!requested_ppem)
      requested_ppem = 1<<30; /* Choose largest strike. */
    unsigned int best_i = 0;
    unsigned int best_ppem = hb_max (sizeTables[0].ppemX, sizeTables[0].ppemY);

    for (unsigned int i = 1; i < count; i++)
    {
      unsigned int ppem = hb_max (sizeTables[i].ppemX, sizeTables[i].ppemY);
      if ((requested_ppem <= ppem && ppem < best_ppem) ||
   (requested_ppem > best_ppem && ppem > best_ppem))
      {
 best_i = i;
 best_ppem = ppem;
      }
    }

    return sizeTables[best_i];
  }

  protected:
  FixedVersion<>  version;
  Array32Of<BitmapSizeTable> sizeTables;
  public:
  DEFINE_SIZE_ARRAY (8, sizeTables);
};

struct CBDT
{
  static constexpr hb_tag_t tableTag = HB_OT_TAG_CBDT;

  struct accelerator_t
  {
    accelerator_t (hb_face_t *face)
    {
      this->cblc = hb_sanitize_context_t ().reference_table<CBLC> (face);
      this->cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face);

      upem = hb_face_get_upem (face);
    }
    ~accelerator_t ()
    {
      this->cblc.destroy ();
      this->cbdt.destroy ();
    }

    bool
    get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, bool scale = trueconst
    {
      const void *base;
      const BitmapSizeTable &strike = this->cblc->choose_strike (font);
      const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base);
      if (!subtable_record || !strike.ppemX || !strike.ppemY)
 return false;

      if (subtable_record->get_extents (extents, base, scale))
 return true;

      unsigned int image_offset = 0, image_length = 0, image_format = 0;
      if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
 return false;

      unsigned int cbdt_len = cbdt.get_length ();
      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
 return false;

      switch (image_format)
      {
      case 17: {
 if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
   return false;
 auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
 glyphFormat17.glyphMetrics.get_extents (font, extents, scale);
 break;
      }
      case 18: {
 if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
   return false;
 auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
 glyphFormat18.glyphMetrics.get_extents (font, extents, scale);
 break;
      }
      defaultreturn false/* TODO: Support other image formats. */
      }

      /* Convert to font units. */
      if (scale)
      {
 float x_scale = upem / (float) strike.ppemX;
 float y_scale = upem / (float) strike.ppemY;
 extents->x_bearing = roundf (extents->x_bearing * x_scale);
 extents->y_bearing = roundf (extents->y_bearing * y_scale);
 extents->width = roundf (extents->width * x_scale);
 extents->height = roundf (extents->height * y_scale);
      }

      return true;
    }

    hb_blob_t*
    reference_png (hb_font_t *font, hb_codepoint_t glyph) const
    {
      const void *base;
      const BitmapSizeTable &strike = this->cblc->choose_strike (font);
      const IndexSubtableRecord *subtable_record = strike.find_table (glyph, cblc, &base);
      if (!subtable_record || !strike.ppemX || !strike.ppemY)
 return hb_blob_get_empty ();

      unsigned int image_offset = 0, image_length = 0, image_format = 0;
      if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
 return hb_blob_get_empty ();

      unsigned int cbdt_len = cbdt.get_length ();
      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
 return hb_blob_get_empty ();

      switch (image_format)
      {
      case 17:
      {
 if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
   return hb_blob_get_empty ();
 auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
 return hb_blob_create_sub_blob (cbdt.get_blob (),
     image_offset + GlyphBitmapDataFormat17::min_size,
     glyphFormat17.data.len);
      }
      case 18:
      {
 if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
   return hb_blob_get_empty ();
 auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
 return hb_blob_create_sub_blob (cbdt.get_blob (),
     image_offset + GlyphBitmapDataFormat18::min_size,
     glyphFormat18.data.len);
      }
      case 19:
      {
 if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
   return hb_blob_get_empty ();
 auto &glyphFormat19 = StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
 return hb_blob_create_sub_blob (cbdt.get_blob (),
     image_offset + GlyphBitmapDataFormat19::min_size,
     glyphFormat19.data.len);
      }
      defaultreturn hb_blob_get_empty (); /* TODO: Support other image formats. */
      }
    }

    bool has_data () const { return cbdt.get_length (); }

    bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
    {
      hb_glyph_extents_t extents;
      hb_glyph_extents_t pixel_extents;
      hb_blob_t *blob = reference_png (font, glyph);

      if (unlikely (blob == hb_blob_get_empty ()))
        return false;

      if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents)))
        return false;

      if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
        return false;

      bool ret = funcs->image (data,
          blob,
          pixel_extents.width, -pixel_extents.height,
          HB_PAINT_IMAGE_FORMAT_PNG,
          font->slant_xy,
          &extents);

      hb_blob_destroy (blob);
      return ret;
    }

    private:
    hb_blob_ptr_t<CBLC> cblc;
    hb_blob_ptr_t<CBDT> cbdt;

    unsigned int upem;
  };

  bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
    hb_barrier () &&
    likely (version.major == 2 || version.major == 3));
  }

  protected:
  FixedVersion<>  version;
  UnsizedArrayOf<HBUINT8> dataZ;
  public:
  DEFINE_SIZE_ARRAY (4, dataZ);
};

inline bool
CBLC::subset (hb_subset_context_t *c) const
{
  TRACE_SUBSET (this);

  // Use a vector as a secondary buffer as the tables need to be built in parallel.
  hb_vector_t<char> cbdt_prime;

  auto *cblc_prime = c->serializer->start_embed<CBLC> ();
  if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false);
  cblc_prime->version = version;

  hb_blob_t* cbdt_blob = hb_sanitize_context_t ().reference_table<CBDT> (c->plan->source);
  unsigned int cbdt_length;
  CBDT* cbdt = (CBDT *) hb_blob_get_data (cbdt_blob, &cbdt_length);
  if (unlikely (cbdt_length < CBDT::min_size))
  {
    hb_blob_destroy (cbdt_blob);
    return_trace (false);
  }
  _copy_data_to_cbdt (&cbdt_prime, cbdt, CBDT::min_size);

  for (const BitmapSizeTable& table : + sizeTables.iter ())
    subset_size_table (c, table, (const char *) cbdt, cbdt_length, cblc_prime, &cbdt_prime);

  hb_blob_destroy (cbdt_blob);

  return_trace (CBLC::sink_cbdt (c, &cbdt_prime));
}

struct CBDT_accelerator_t : CBDT::accelerator_t {
  CBDT_accelerator_t (hb_face_t *face) : CBDT::accelerator_t (face) {}
};


/* namespace OT */

#endif /* OT_COLOR_CBDT_CBDT_HH */

Messung V0.5
C=97 H=96 G=96

¤ Dauer der Verarbeitung: 0.37 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.