1 /*
   2  * Copyright © 2017  Google, Inc.
   3  *
   4  *  This is part of HarfBuzz, a text shaping library.
   5  *
   6  * Permission is hereby granted, without written agreement and without
   7  * license or royalty fees, to use, copy, modify, and distribute this
   8  * software and its documentation for any purpose, provided that the
   9  * above copyright notice and the following two paragraphs appear in
  10  * all copies of this software.
  11  *
  12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  16  * DAMAGE.
  17  *
  18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  23  *
  24  * Google Author(s): Behdad Esfahbod
  25  */
  26 
  27 #ifndef HB_OT_VAR_AVAR_TABLE_HH
  28 #define HB_OT_VAR_AVAR_TABLE_HH
  29 
  30 #include "hb-open-type-private.hh"
  31 
  32 namespace OT {
  33 
  34 
  35 struct AxisValueMap
  36 {
  37   inline bool sanitize (hb_sanitize_context_t *c) const
  38   {
  39     TRACE_SANITIZE (this);
  40     return_trace (c->check_struct (this));
  41   }
  42 
  43   public:
  44   F2DOT14       fromCoord;      /* A normalized coordinate value obtained using
  45                                  * default normalization. */
  46   F2DOT14       toCoord;        /* The modified, normalized coordinate value. */
  47 
  48   public:
  49   DEFINE_SIZE_STATIC (4);
  50 };
  51 
  52 struct SegmentMaps : ArrayOf<AxisValueMap>
  53 {
  54   inline int map (int value) const
  55   {
  56     /* The following special-cases are not part of OpenType, which requires
  57      * that at least -1, 0, and +1 must be mapped. But we include these as
  58      * part of a better error recovery scheme. */
  59 
  60     if (len < 2)
  61     {
  62       if (!len)
  63         return value;
  64       else /* len == 1*/
  65         return value - array[0].fromCoord + array[0].toCoord;
  66     }
  67 
  68     if (value <= array[0].fromCoord)
  69       return value - array[0].fromCoord + array[0].toCoord;
  70 
  71     unsigned int i;
  72     unsigned int count = len;
  73     for (i = 1; i < count && value > array[i].fromCoord; i++)
  74       ;
  75 
  76     if (value >= array[i].fromCoord)
  77       return value - array[i].fromCoord + array[i].toCoord;
  78 
  79     if (unlikely (array[i-1].fromCoord == array[i].fromCoord))
  80       return array[i-1].toCoord;
  81 
  82     int denom = array[i].fromCoord - array[i-1].fromCoord;
  83     return array[i-1].toCoord +
  84            ((array[i].toCoord - array[i-1].toCoord) *
  85             (value - array[i-1].fromCoord) + denom/2) / denom;
  86   }
  87 
  88   DEFINE_SIZE_ARRAY (2, array);
  89 };
  90 
  91 /*
  92  * avar — Axis Variations Table
  93  */
  94 
  95 #define HB_OT_TAG_avar HB_TAG('a','v','a','r')
  96 
  97 struct avar
  98 {
  99   static const hb_tag_t tableTag        = HB_OT_TAG_avar;
 100 
 101   inline bool sanitize (hb_sanitize_context_t *c) const
 102   {
 103     TRACE_SANITIZE (this);
 104     if (unlikely (!(version.sanitize (c) &&
 105                     version.major == 1 &&
 106                     c->check_struct (this))))
 107       return_trace (false);
 108 
 109     const SegmentMaps *map = &axisSegmentMapsZ;
 110     unsigned int count = axisCount;
 111     for (unsigned int i = 0; i < count; i++)
 112     {
 113       if (unlikely (!map->sanitize (c)))
 114         return_trace (false);
 115       map = &StructAfter<SegmentMaps> (*map);
 116     }
 117 
 118     return_trace (true);
 119   }
 120 
 121   inline void map_coords (int *coords, unsigned int coords_length) const
 122   {
 123     unsigned int count = MIN<unsigned int> (coords_length, axisCount);
 124 
 125     const SegmentMaps *map = &axisSegmentMapsZ;
 126     for (unsigned int i = 0; i < count; i++)
 127     {
 128       coords[i] = map->map (coords[i]);
 129       map = &StructAfter<SegmentMaps> (*map);
 130     }
 131   }
 132 
 133   protected:
 134   FixedVersion<>version;        /* Version of the avar table
 135                                  * initially set to 0x00010000u */
 136   USHORT        reserved;       /* This field is permanently reserved. Set to 0. */
 137   USHORT        axisCount;      /* The number of variation axes in the font. This
 138                                  * must be the same number as axisCount in the
 139                                  * 'fvar' table. */
 140   SegmentMaps   axisSegmentMapsZ;
 141 
 142   public:
 143   DEFINE_SIZE_MIN (8);
 144 };
 145 
 146 } /* namespace OT */
 147 
 148 
 149 #endif /* HB_OT_VAR_AVAR_TABLE_HH */