Imported Upstream version 2.6.7
[platform/upstream/harfbuzz.git] / src / hb-ot-post-table.hh
index 82ab388..8586331 100644 (file)
 #ifndef HB_OT_POST_TABLE_HH
 #define HB_OT_POST_TABLE_HH
 
-#include "hb-open-type-private.hh"
-
-
-namespace OT {
+#include "hb-open-type.hh"
 
+#define HB_STRING_ARRAY_NAME format1_names
+#define HB_STRING_ARRAY_LIST "hb-ot-post-macroman.hh"
+#include "hb-string-array.hh"
+#undef HB_STRING_ARRAY_LIST
+#undef HB_STRING_ARRAY_NAME
 
 /*
  * post -- PostScript
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/post
  */
-
 #define HB_OT_TAG_post HB_TAG('p','o','s','t')
 
 
+namespace OT {
+
+
 struct postV2Tail
 {
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  friend struct post;
+
+  bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (numberOfGlyphs.sanitize (c) &&
-                 c->check_array (glyphNameIndex, sizeof (USHORT), numberOfGlyphs));
+    return_trace (glyphNameIndex.sanitize (c));
   }
 
-  USHORT       numberOfGlyphs;         /* Number of glyphs (this should be the
-                                        * same as numGlyphs in 'maxp' table). */
-  USHORT       glyphNameIndex[VAR];    /* This is not an offset, but is the
+  protected:
+  ArrayOf<HBUINT16>    glyphNameIndex; /* This is not an offset, but is the
                                         * ordinal number of the glyph in 'post'
                                         * string tables. */
-  BYTE         namesX[VAR];            /* Glyph names with length bytes [variable]
+/*UnsizedArrayOf<HBUINT8>
+                       namesX;*/       /* Glyph names with length bytes [variable]
                                         * (a Pascal string). */
 
-  DEFINE_SIZE_ARRAY2 (2, glyphNameIndex, namesX);
+  public:
+  DEFINE_SIZE_ARRAY (2, glyphNameIndex);
 };
 
 struct post
 {
-  static const hb_tag_t tableTag = HB_OT_TAG_post;
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_post;
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
+  void serialize (hb_serialize_context_t *c) const
   {
-    TRACE_SANITIZE (this);
-    if (unlikely (!c->check_struct (this)))
-      return_trace (false);
-    if (version.to_int () == 0x00020000)
+    post *post_prime = c->allocate_min<post> ();
+    if (unlikely (!post_prime))  return;
+
+    memcpy (post_prime, this, post::min_size);
+    post_prime->version.major = 3; // Version 3 does not have any glyph names.
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    post *post_prime = c->serializer->start_embed<post> ();
+    if (unlikely (!post_prime)) return_trace (false);
+
+    serialize (c->serializer);
+    if (c->serializer->in_error () || c->serializer->ran_out_of_room) return_trace (false);
+
+    return_trace (true);
+  }
+
+  struct accelerator_t
+  {
+    void init (hb_face_t *face)
     {
-      const postV2Tail &v2 = StructAfter<postV2Tail>(*this);
-      return_trace (v2.sanitize (c));
+      index_to_offset.init ();
+
+      table = hb_sanitize_context_t ().reference_table<post> (face);
+      unsigned int table_length = table.get_length ();
+
+      version = table->version.to_int ();
+      if (version != 0x00020000) return;
+
+      const postV2Tail &v2 = table->v2X;
+
+      glyphNameIndex = &v2.glyphNameIndex;
+      pool = &StructAfter<uint8_t> (v2.glyphNameIndex);
+
+      const uint8_t *end = (const uint8_t *) (const void *) table + table_length;
+      for (const uint8_t *data = pool;
+          index_to_offset.length < 65535 && data < end && data + *data < end;
+          data += 1 + *data)
+       index_to_offset.push (data - pool);
     }
-    return_trace (true);
+    void fini ()
+    {
+      index_to_offset.fini ();
+      free (gids_sorted_by_name.get ());
+      table.destroy ();
+    }
+
+    bool get_glyph_name (hb_codepoint_t glyph,
+                        char *buf, unsigned int buf_len) const
+    {
+      hb_bytes_t s = find_glyph_name (glyph);
+      if (!s.length) return false;
+      if (!buf_len) return true;
+      unsigned int len = hb_min (buf_len - 1, s.length);
+      strncpy (buf, s.arrayZ, len);
+      buf[len] = '\0';
+      return true;
+    }
+
+    bool get_glyph_from_name (const char *name, int len,
+                             hb_codepoint_t *glyph) const
+    {
+      unsigned int count = get_glyph_count ();
+      if (unlikely (!count)) return false;
+
+      if (len < 0) len = strlen (name);
+
+      if (unlikely (!len)) return false;
+
+    retry:
+      uint16_t *gids = gids_sorted_by_name.get ();
+
+      if (unlikely (!gids))
+      {
+       gids = (uint16_t *) malloc (count * sizeof (gids[0]));
+       if (unlikely (!gids))
+         return false; /* Anything better?! */
+
+       for (unsigned int i = 0; i < count; i++)
+         gids[i] = i;
+       hb_qsort (gids, count, sizeof (gids[0]), cmp_gids, (void *) this);
+
+       if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
+       {
+         free (gids);
+         goto retry;
+       }
+      }
+
+      hb_bytes_t st (name, len);
+      auto* gid = hb_bsearch (st, gids, count, sizeof (gids[0]), cmp_key, (void *) this);
+      if (gid)
+      {
+       *glyph = *gid;
+       return true;
+      }
+
+      return false;
+    }
+
+    hb_blob_ptr_t<post> table;
+
+    protected:
+
+    unsigned int get_glyph_count () const
+    {
+      if (version == 0x00010000)
+       return format1_names_length;
+
+      if (version == 0x00020000)
+       return glyphNameIndex->len;
+
+      return 0;
+    }
+
+    static int cmp_gids (const void *pa, const void *pb, void *arg)
+    {
+      const accelerator_t *thiz = (const accelerator_t *) arg;
+      uint16_t a = * (const uint16_t *) pa;
+      uint16_t b = * (const uint16_t *) pb;
+      return thiz->find_glyph_name (b).cmp (thiz->find_glyph_name (a));
+    }
+
+    static int cmp_key (const void *pk, const void *po, void *arg)
+    {
+      const accelerator_t *thiz = (const accelerator_t *) arg;
+      const hb_bytes_t *key = (const hb_bytes_t *) pk;
+      uint16_t o = * (const uint16_t *) po;
+      return thiz->find_glyph_name (o).cmp (*key);
+    }
+
+    hb_bytes_t find_glyph_name (hb_codepoint_t glyph) const
+    {
+      if (version == 0x00010000)
+      {
+       if (glyph >= format1_names_length)
+         return hb_bytes_t ();
+
+       return format1_names (glyph);
+      }
+
+      if (version != 0x00020000 || glyph >= glyphNameIndex->len)
+       return hb_bytes_t ();
+
+      unsigned int index = glyphNameIndex->arrayZ[glyph];
+      if (index < format1_names_length)
+       return format1_names (index);
+      index -= format1_names_length;
+
+      if (index >= index_to_offset.length)
+       return hb_bytes_t ();
+      unsigned int offset = index_to_offset[index];
+
+      const uint8_t *data = pool + offset;
+      unsigned int name_length = *data;
+      data++;
+
+      return hb_bytes_t ((const char *) data, name_length);
+    }
+
+    private:
+    uint32_t version;
+    const ArrayOf<HBUINT16> *glyphNameIndex;
+    hb_vector_t<uint32_t> index_to_offset;
+    const uint8_t *pool;
+    hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;
+  };
+
+  bool has_data () const { return version.to_int (); }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) &&
+                         (version.to_int () == 0x00010000 ||
+                          (version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
+                          version.to_int () == 0x00030000)));
   }
 
   public:
@@ -82,7 +259,7 @@ struct post
                                         * 0x00020000 for version 2.0
                                         * 0x00025000 for version 2.5 (deprecated)
                                         * 0x00030000 for version 3.0 */
-  Fixed                italicAngle;            /* Italic angle in counter-clockwise degrees
+  HBFixed      italicAngle;            /* Italic angle in counter-clockwise degrees
                                         * from the vertical. Zero for upright text,
                                         * negative for text that leans to the right
                                         * (forward). */
@@ -98,21 +275,23 @@ struct post
                                         * from the value of this field. */
   FWORD                underlineThickness;     /* Suggested values for the underline
                                           thickness. */
-  ULONG                isFixedPitch;           /* Set to 0 if the font is proportionally
+  HBUINT32     isFixedPitch;           /* Set to 0 if the font is proportionally
                                         * spaced, non-zero if the font is not
                                         * proportionally spaced (i.e. monospaced). */
-  ULONG                minMemType42;           /* Minimum memory usage when an OpenType font
+  HBUINT32     minMemType42;           /* Minimum memory usage when an OpenType font
                                         * is downloaded. */
-  ULONG                maxMemType42;           /* Maximum memory usage when an OpenType font
+  HBUINT32     maxMemType42;           /* Maximum memory usage when an OpenType font
                                         * is downloaded. */
-  ULONG                minMemType1;            /* Minimum memory usage when an OpenType font
+  HBUINT32     minMemType1;            /* Minimum memory usage when an OpenType font
                                         * is downloaded as a Type 1 font. */
-  ULONG                maxMemType1;            /* Maximum memory usage when an OpenType font
+  HBUINT32     maxMemType1;            /* Maximum memory usage when an OpenType font
                                         * is downloaded as a Type 1 font. */
-/*postV2Tail   v2[VAR];*/
-  DEFINE_SIZE_STATIC (32);
+  postV2Tail   v2X;
+  DEFINE_SIZE_MIN (32);
 };
 
+struct post_accelerator_t : post::accelerator_t {};
+
 } /* namespace OT */