Imported Upstream version 1.7.6
[platform/upstream/harfbuzz.git] / src / hb-open-file-private.hh
index f208419..e2644ea 100644 (file)
@@ -30,6 +30,7 @@
 #define HB_OPEN_FILE_PRIVATE_HH
 
 #include "hb-open-type-private.hh"
+#include "hb-ot-head-table.hh"
 
 
 namespace OT {
@@ -53,6 +54,16 @@ struct TTCHeader;
 
 typedef struct TableRecord
 {
+  int cmp (Tag t) const
+  { return -t.cmp (tag); }
+
+  static int cmp (const void *pa, const void *pb)
+  {
+    const TableRecord *a = (const TableRecord *) pa;
+    const TableRecord *b = (const TableRecord *) pb;
+    return b->cmp (a->tag);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -61,9 +72,9 @@ typedef struct TableRecord
 
   Tag          tag;            /* 4-byte identifier. */
   CheckSum     checkSum;       /* CheckSum for this table. */
-  ULONG                offset;         /* Offset from beginning of TrueType font
+  Offset32     offset;         /* Offset from beginning of TrueType font
                                 * file. */
-  ULONG                length;         /* Length of this table. */
+  HBUINT32     length;         /* Length of this table. */
   public:
   DEFINE_SIZE_STATIC (16);
 } OpenTypeTable;
@@ -73,27 +84,39 @@ typedef struct OffsetTable
   friend struct OpenTypeFontFile;
 
   inline unsigned int get_table_count (void) const
-  { return numTables; }
+  { return tables.len; }
   inline const TableRecord& get_table (unsigned int i) const
   {
-    if (unlikely (i >= numTables)) return Null(TableRecord);
     return tables[i];
   }
+  inline unsigned int get_table_tags (unsigned int  start_offset,
+                                     unsigned int *table_count, /* IN/OUT */
+                                     hb_tag_t     *table_tags /* OUT */) const
+  {
+    if (table_count)
+    {
+      if (start_offset >= tables.len)
+        *table_count = 0;
+      else
+        *table_count = MIN<unsigned int> (*table_count, tables.len - start_offset);
+
+      const TableRecord *sub_tables = tables.array + start_offset;
+      unsigned int count = *table_count;
+      for (unsigned int i = 0; i < count; i++)
+       table_tags[i] = sub_tables[i].tag;
+    }
+    return tables.len;
+  }
   inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
   {
     Tag t;
     t.set (tag);
-    unsigned int count = numTables;
-    for (unsigned int i = 0; i < count; i++)
-    {
-      if (t == tables[i].tag)
-      {
-        if (table_index) *table_index = i;
-        return true;
-      }
-    }
-    if (table_index) *table_index = Index::NOT_FOUND_INDEX;
-    return false;
+    /* Linear-search for small tables to work around fonts with unsorted
+     * table list. */
+    int i = tables.len < 64 ? tables.lsearch (t) : tables.bsearch (t);
+    if (table_index)
+      *table_index = i == -1 ? Index::NOT_FOUND_INDEX : (unsigned int) i;
+    return i != -1;
   }
   inline const TableRecord& get_table_by_tag (hb_tag_t tag) const
   {
@@ -103,19 +126,88 @@ typedef struct OffsetTable
   }
 
   public:
+
+  inline bool serialize (hb_serialize_context_t *c,
+                        hb_tag_t sfnt_tag,
+                        Supplier<hb_tag_t> &tags,
+                        Supplier<hb_blob_t *> &blobs,
+                        unsigned int table_count)
+  {
+    TRACE_SERIALIZE (this);
+    /* Alloc 12 for the OTHeader. */
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    /* Write sfntVersion (bytes 0..3). */
+    sfnt_version.set (sfnt_tag);
+    /* Take space for numTables, searchRange, entrySelector, RangeShift
+     * and the TableRecords themselves.  */
+    if (unlikely (!tables.serialize (c, table_count))) return_trace (false);
+
+    const char *dir_end = (const char *) c->head;
+    HBUINT32 *checksum_adjustment = nullptr;
+
+    /* Write OffsetTables, alloc for and write actual table blobs. */
+    for (unsigned int i = 0; i < table_count; i++)
+    {
+      TableRecord &rec = tables.array[i];
+      hb_blob_t *blob = blobs[i];
+      rec.tag.set (tags[i]);
+      rec.length.set (hb_blob_get_length (blob));
+      rec.offset.serialize (c, this);
+
+      /* Allocate room for the table and copy it. */
+      char *start = (char *) c->allocate_size<void> (rec.length);
+      if (unlikely (!start)) {return false;}
+
+      memcpy (start, hb_blob_get_data (blob, nullptr), rec.length);
+
+      /* 4-byte allignment. */
+      if (rec.length % 4)
+       c->allocate_size<void> (4 - rec.length % 4);
+      const char *end = (const char *) c->head;
+
+      if (tags[i] == HB_OT_TAG_head && end - start >= head::static_size)
+      {
+       head *h = (head *) start;
+       checksum_adjustment = &h->checkSumAdjustment;
+       checksum_adjustment->set (0);
+      }
+
+      rec.checkSum.set_for_data (start, end - start);
+    }
+    tags += table_count;
+    blobs += table_count;
+
+    tables.qsort ();
+
+    if (checksum_adjustment)
+    {
+      CheckSum checksum;
+
+      /* The following line is a slower version of the following block. */
+      //checksum.set_for_data (this, (const char *) c->head - (const char *) this);
+      checksum.set_for_data (this, dir_end - (const char *) this);
+      for (unsigned int i = 0; i < table_count; i++)
+      {
+       TableRecord &rec = tables.array[i];
+       checksum.set (checksum + rec.checkSum);
+      }
+
+      checksum_adjustment->set (0xB1B0AFBAu - checksum);
+    }
+
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
+    return_trace (c->check_struct (this) && tables.sanitize (c));
   }
 
   protected:
   Tag          sfnt_version;   /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
-  USHORT       numTables;      /* Number of tables. */
-  USHORT       searchRangeZ;   /* (Maximum power of 2 <= numTables) x 16 */
-  USHORT       entrySelectorZ; /* Log2(maximum power of 2 <= numTables). */
-  USHORT       rangeShiftZ;    /* NumTables x 16-searchRange. */
-  TableRecord  tables[VAR];    /* TableRecord entries. numTables items */
+  BinSearchArrayOf<TableRecord>
+               tables;
   public:
   DEFINE_SIZE_ARRAY (12, tables);
 } OpenTypeFontFace;
@@ -142,7 +234,7 @@ struct TTCHeaderVersion1
   Tag          ttcTag;         /* TrueType Collection ID string: 'ttcf' */
   FixedVersion<>version;       /* Version of the TTC Header (1.0),
                                 * 0x00010000u */
-  ArrayOf<LOffsetTo<OffsetTable>, ULONG>
+  ArrayOf<LOffsetTo<OffsetTable>, HBUINT32>
                table;          /* Array of offsets to the OffsetTable for each font
                                 * from the beginning of the file */
   public:
@@ -237,6 +329,18 @@ struct OpenTypeFontFile
     }
   }
 
+  inline bool serialize_single (hb_serialize_context_t *c,
+                               hb_tag_t sfnt_tag,
+                               Supplier<hb_tag_t> &tags,
+                               Supplier<hb_blob_t *> &blobs,
+                               unsigned int table_count)
+  {
+    TRACE_SERIALIZE (this);
+    assert (sfnt_tag != TTCTag);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    return_trace (u.fontFace.serialize (c, sfnt_tag, tags, blobs, table_count));
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);