[subset] Towards GSUB/GPOS subsetting
authorBehdad Esfahbod <behdad@behdad.org>
Sun, 2 Sep 2018 01:34:50 +0000 (18:34 -0700)
committerBehdad Esfahbod <behdad@behdad.org>
Sun, 2 Sep 2018 01:34:50 +0000 (18:34 -0700)
Add subset() call for GSUBGPOS struct and its dependencies.
Not hooked up anywhere.

src/hb-machinery.hh
src/hb-open-type.hh
src/hb-ot-layout-common.hh
src/hb-ot-layout-gdef-table.hh
src/hb-ot-layout-gsub-table.hh
src/hb-ot-layout-gsubgpos.hh

index 3f86754..6e3e70c 100644 (file)
@@ -111,9 +111,13 @@ static inline Type& StructAfter(TObject &X)
   static const unsigned int min_size = (size)
 
 #define DEFINE_SIZE_ARRAY(size, array) \
-  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
+  DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof (array[0])); \
   DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
-  static const unsigned int min_size = (size)
+  static const unsigned int min_size = (size); \
+
+#define DEFINE_SIZE_ARRAY_SIZED(size, array) \
+       DEFINE_SIZE_ARRAY(size, array); \
+       inline unsigned int get_size (void) const { return (size - array[0].min_size + array.get_size ()); }
 
 #define DEFINE_SIZE_ARRAY2(size, array1, array2) \
   DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
@@ -508,7 +512,7 @@ struct hb_serialize_context_t
     unsigned int size = obj.get_size ();
     Type *ret = this->allocate_size<Type> (size);
     if (unlikely (!ret)) return nullptr;
-    memcpy (ret, obj, size);
+    memcpy (ret, &obj, size);
     return ret;
   }
 
index d43dcac..24fafd9 100644 (file)
@@ -247,6 +247,19 @@ struct OffsetTo : Offset<OffsetType>
     return * (Type *) Offset<OffsetType>::serialize (c, base);
   }
 
+  template <typename T>
+  inline void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
+  {
+    if (&src == &Null(T))
+    {
+      this->set (0);
+      return;
+    }
+    serialize (c->serializer, base);
+    if (!src.subset (c))
+      this->set (0);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
   {
     TRACE_SANITIZE (this);
@@ -405,7 +418,6 @@ struct ArrayOf
     if (unlikely (!c->extend (*this))) return_trace (false);
     return_trace (true);
   }
-
   inline bool serialize (hb_serialize_context_t *c,
                         Supplier<Type> &items,
                         unsigned int items_len)
@@ -506,6 +518,17 @@ struct OffsetListOf : OffsetArrayOf<Type>
     return this+this->arrayZ[i];
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct OffsetListOf<Type> *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    unsigned int count = this->len;
+    for (unsigned int i = 0; i < count; i++)
+      out->arrayZ[i].serialize_subset (c, (*this)[i], this);
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
index 887f27e..a51a6c7 100644 (file)
@@ -97,15 +97,14 @@ struct Record
 };
 
 template <typename Type>
-struct RecordArrayOf : SortedArrayOf<Record<Type> > {
+struct RecordArrayOf : SortedArrayOf<Record<Type> >
+{
+  inline const OffsetTo<Type>& get_offset (unsigned int i) const
+  { return (*this)[i].offset; }
+  inline OffsetTo<Type>& get_offset (unsigned int i)
+  { return (*this)[i].offset; }
   inline const Tag& get_tag (unsigned int i) const
-  {
-    /* We cheat slightly and don't define separate Null objects
-     * for Record types.  Instead, we return the correct Null(Tag)
-     * here. */
-    if (unlikely (i >= this->len)) return Null(Tag);
-    return (*this)[i].tag;
-  }
+  { return (*this)[i].tag; }
   inline unsigned int get_tags (unsigned int start_offset,
                                unsigned int *record_count /* IN/OUT */,
                                hb_tag_t     *record_tags /* OUT */) const
@@ -136,7 +135,18 @@ template <typename Type>
 struct RecordListOf : RecordArrayOf<Type>
 {
   inline const Type& operator [] (unsigned int i) const
-  { return this+RecordArrayOf<Type>::operator [](i).offset; }
+  { return this+this->get_offset (i); }
+
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct RecordListOf<Type> *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    unsigned int count = this->len;
+    for (unsigned int i = 0; i < count; i++)
+      out->get_offset (i).serialize_subset (c, (*this)[i], this);
+    return_trace (true);
+  }
 
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
@@ -224,6 +234,12 @@ struct LangSys
    return reqFeatureIndex;;
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace (c->serializer->embed (*this));
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c,
                        const Record<LangSys>::sanitize_closure_t * = nullptr) const
   {
@@ -238,7 +254,7 @@ struct LangSys
                                 * = 0xFFFFu */
   IndexArray   featureIndex;   /* Array of indices into the FeatureList */
   public:
-  DEFINE_SIZE_ARRAY (6, featureIndex);
+  DEFINE_SIZE_ARRAY_SIZED (6, featureIndex);
 };
 DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
 
@@ -263,6 +279,18 @@ struct Script
   inline bool has_default_lang_sys (void) const { return defaultLangSys != 0; }
   inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct Script *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    out->defaultLangSys.serialize_subset (c, this+defaultLangSys, this);
+    unsigned int count = langSys.len;
+    for (unsigned int i = 0; i < count; i++)
+      out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, this);
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c,
                        const Record<Script>::sanitize_closure_t * = nullptr) const
   {
@@ -278,7 +306,7 @@ struct Script
                langSys;        /* Array of LangSysRecords--listed
                                 * alphabetically by LangSysTag */
   public:
-  DEFINE_SIZE_ARRAY (4, langSys);
+  DEFINE_SIZE_ARRAY_SIZED (4, langSys);
 };
 
 typedef RecordListOf<Script> ScriptList;
@@ -516,6 +544,15 @@ struct Feature
   inline const FeatureParams &get_feature_params (void) const
   { return this+featureParams; }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct Feature *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    out->featureParams.set (0); /* TODO(subset) FeatureParams. */
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c,
                        const Record<Feature>::sanitize_closure_t *closure = nullptr) const
   {
@@ -567,7 +604,7 @@ struct Feature
                                 * if not required */
   IndexArray    lookupIndex;   /* Array of LookupList indices */
   public:
-  DEFINE_SIZE_ARRAY (4, lookupIndex);
+  DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
 };
 
 typedef RecordListOf<Feature> FeatureList;
@@ -666,6 +703,17 @@ struct Lookup
     return_trace (true);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct Lookup *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    unsigned int count = subTable.len;
+    for (unsigned int i = 0; i < count; i++)
+      out->subTable[i].set (0); /* To be filled out by SubstLookup/PosLookup. */
+    return_trace (true);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1629,6 +1677,12 @@ struct FeatureVariations
     return (this+record.substitutions).find_substitute (feature_index);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    return_trace (c->serializer->embed (*this));
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -1642,7 +1696,7 @@ struct FeatureVariations
   LArrayOf<FeatureVariationRecord>
                        varRecords;
   public:
-  DEFINE_SIZE_ARRAY (8, varRecords);
+  DEFINE_SIZE_ARRAY_SIZED (8, varRecords);
 };
 
 
index 7930864..cad99a3 100644 (file)
@@ -387,19 +387,6 @@ struct GDEF
   inline const VariationStore &get_var_store (void) const
   { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
 
-  inline bool sanitize (hb_sanitize_context_t *c) const
-  {
-    TRACE_SANITIZE (this);
-    return_trace (version.sanitize (c) &&
-                 likely (version.major == 1) &&
-                 glyphClassDef.sanitize (c, this) &&
-                 attachList.sanitize (c, this) &&
-                 ligCaretList.sanitize (c, this) &&
-                 markAttachClassDef.sanitize (c, this) &&
-                 (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
-                 (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
-  }
-
   /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
    * glyph class and other bits, and high 8-bit gthe mark attachment type (if any).
    * Not to be confused with lookup_props which is very similar. */
@@ -434,6 +421,26 @@ struct GDEF
     const GDEF *table;
   };
 
+  inline unsigned int get_size (void) const
+  {
+    return min_size +
+          (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
+          (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+                 likely (version.major == 1) &&
+                 glyphClassDef.sanitize (c, this) &&
+                 attachList.sanitize (c, this) &&
+                 ligCaretList.sanitize (c, this) &&
+                 markAttachClassDef.sanitize (c, this) &&
+                 (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+                 (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
+  }
+
   protected:
   FixedVersion<>version;               /* Version of the GDEF table--currently
                                         * 0x00010003u */
index 7f8489f..c108e16 100644 (file)
@@ -1308,15 +1308,20 @@ struct GSUB : GSUBGPOS
   inline const SubstLookup& get_lookup (unsigned int i) const
   { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
 
-  inline bool subset (hb_subset_context_t *c)
+  inline bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
     struct GSUB *out = c->serializer->start_embed<GSUB> ();
-    //XXX if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
+    if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
+    /* TODO Replace following with c->iter_copy_and_subset()ish. */
+    unsigned int count = get_lookup_count ();
+    LookupList &outLookupList = out+out->lookupList;
+    for (unsigned int i = 0; i < count; i++)
+      //XXX if (unlikely (!outLookupList.arrayZ[i].subset (c, get_lookup (i), &outLookupList)))
+       return_trace (false);
     return_trace (true);
   }
 
-
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
index 3727dd9..1749f58 100644 (file)
@@ -2370,6 +2370,25 @@ struct GSUBGPOS
     return get_feature (feature_index);
   }
 
+  inline bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    struct GSUBGPOS *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    out->scriptList.serialize_subset (c, this+scriptList, this);
+    out->featureList.serialize_subset (c, this+featureList, this);
+    out->lookupList.serialize_subset (c, this+lookupList, this);
+    if (version.to_int () >= 0x00010001u)
+     out->featureVars.serialize_subset (c, this+featureVars, this);
+    return_trace (true);
+  }
+
+  inline unsigned int get_size (void) const
+  {
+    return min_size +
+          (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
+  }
+
   inline bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);