[GX] Add data types for encoding numerical variations
authorBehdad Esfahbod <behdad@behdad.org>
Tue, 1 Mar 2016 10:12:08 +0000 (19:12 +0900)
committerBehdad Esfahbod <behdad@behdad.org>
Sat, 17 Dec 2016 01:06:26 +0000 (19:06 -0600)
src/hb-font-private.hh
src/hb-font.cc
src/hb-ot-layout-common-private.hh

index cda97a6..3a1e31f 100644 (file)
@@ -108,6 +108,10 @@ struct hb_font_t {
   unsigned int x_ppem;
   unsigned int y_ppem;
 
+  /* Font variation coordinates. */
+  int *coords;
+  unsigned int coord_count;
+
   hb_font_funcs_t   *klass;
   void              *user_data;
   hb_destroy_func_t  destroy;
@@ -120,6 +124,8 @@ struct hb_font_t {
   { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
   inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
   inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
+  inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
+  inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
   inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
   { return em_scale (v, dir_scale (direction)); }
 
@@ -531,6 +537,10 @@ struct hb_font_t {
     scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
     return (hb_position_t) (scaled / upem);
   }
+  inline hb_position_t em_scalef (float v, int scale)
+  {
+    return (hb_position_t) (v * scale / face->get_upem ());
+  }
 };
 
 #define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
index 08fcd64..b4b4d0a 100644 (file)
@@ -1194,6 +1194,9 @@ hb_font_get_empty (void)
     0, /* x_ppem */
     0, /* y_ppem */
 
+    NULL, /* coords */
+    0, /* coord_count */
+
     const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
     NULL, /* user_data */
     NULL, /* destroy */
index 34fa1b7..a18ce74 100644 (file)
@@ -1236,6 +1236,119 @@ struct Device
 };
 
 
+struct VariationAxis
+{
+  inline float evaluate (int *coords, unsigned int coord_len) const
+  {
+    unsigned int i = axisIndex;
+    int coord = i < coord_len ? coords[i] : 0;
+
+    int start = startCoord, peak = peakCoord, end = endCoord;
+    if (coord < start || coord > end) return 0.;
+    if (coord == peak) return 1.;
+    /* Interpolate */
+    if (coord < peak)
+      return float (coord - start) / (peak - start);
+    else
+      return float (end - coord) / (end - peak);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  public:
+  Index                axisIndex;
+  F2DOT14      startCoord;
+  F2DOT14      peakCoord;
+  F2DOT14      endCoord;
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct VariationTuple
+{
+  inline float evaluate (int *coords, unsigned int coord_len) const
+  {
+    float v = 1.;
+    unsigned int count = axes.len;
+    for (unsigned int i = 0; i < count; i++)
+      v *= (this+axes[i]).evaluate (coords, coord_len);
+    return v;
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (axes.sanitize (c, this));
+  }
+
+  OffsetArrayOf<VariationAxis>
+               axes;
+  public:
+  DEFINE_SIZE_ARRAY (2, axes);
+};
+
+struct VariationMap
+{
+  inline const VariationTuple& operator [] (unsigned int i) const
+  { return this+tuples[i]; }
+
+  inline unsigned int get_len (void) const
+  { return tuples.len; }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (tuples.sanitize (c, this));
+  }
+
+  OffsetArrayOf<VariationTuple>
+               tuples;
+  public:
+  DEFINE_SIZE_ARRAY (2, tuples);
+};
+
+struct VariationDevice
+{
+
+  inline hb_position_t get_x_delta (hb_font_t *font) const
+  { return font->em_scalef_x (get_delta (font->coords, font->coord_count)); }
+
+  inline hb_position_t get_y_delta (hb_font_t *font) const
+  { return font->em_scalef_y (get_delta (font->coords, font->coord_count)); }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && c->check_range (&deltaValue, numDeltas * SHORT::static_size));
+  }
+
+  private:
+
+  inline float get_delta (int *coords, unsigned int coord_count) const
+  {
+    float v = 0;
+    const VariationMap &map = this+variationMap;
+    unsigned int count = MIN ((unsigned int) numDeltas, map.get_len ());
+    for (unsigned int i = 0; i < count; i++)
+      v += deltaValue[i] * map[i].evaluate (coords, coord_count);
+    return v;
+  }
+
+  protected:
+  OffsetTo<VariationMap>
+               variationMap;           /* Offset to variation mapping for this table. */
+  USHORT       numDeltas;              /* Number of deltas for in this table. */
+  USHORT       deltaFormat;            /* Format identifier for this table: 0x10 */
+  SHORT                deltaValue[VAR];        /* Deltas as signed values in design space. */
+  public:
+  DEFINE_SIZE_ARRAY (6, deltaValue);
+};
+
+
 } /* namespace OT */