1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 // This file is available under and governed by the GNU General Public
  26 // License version 2 only, as published by the Free Software Foundation.
  27 // However, the following notice accompanied the original version of this
  28 // file:
  29 //
  30 /*
  31  * Copyright © 2009,2010  Red Hat, Inc.
  32  * Copyright © 2010,2011,2012,2013  Google, Inc.
  33  *
  34  *  This is part of HarfBuzz, a text shaping library.
  35  *
  36  * Permission is hereby granted, without written agreement and without
  37  * license or royalty fees, to use, copy, modify, and distribute this
  38  * software and its documentation for any purpose, provided that the
  39  * above copyright notice and the following two paragraphs appear in
  40  * all copies of this software.
  41  *
  42  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
  43  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
  44  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
  45  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
  46  * DAMAGE.
  47  *
  48  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
  49  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  50  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  51  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
  52  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  53  *
  54  * Red Hat Author(s): Behdad Esfahbod
  55  * Google Author(s): Behdad Esfahbod
  56  */
  57 
  58 #ifndef HB_OT_MAP_PRIVATE_HH
  59 #define HB_OT_MAP_PRIVATE_HH
  60 
  61 #include "hb-buffer-private.hh"
  62 
  63 
  64 struct hb_ot_shape_plan_t;
  65 
  66 static const hb_tag_t table_tags[2] = {HB_OT_TAG_GSUB, HB_OT_TAG_GPOS};
  67 
  68 struct hb_ot_map_t
  69 {
  70   friend struct hb_ot_map_builder_t;
  71 
  72   public:
  73 
  74   struct feature_map_t {
  75     hb_tag_t tag; /* should be first for our bsearch to work */
  76     unsigned int index[2]; /* GSUB/GPOS */
  77     unsigned int stage[2]; /* GSUB/GPOS */
  78     unsigned int shift;
  79     hb_mask_t mask;
  80     hb_mask_t _1_mask; /* mask for value=1, for quick access */
  81     unsigned int needs_fallback : 1;
  82     unsigned int auto_zwj : 1;
  83 
  84     static int cmp (const feature_map_t *a, const feature_map_t *b)
  85     { return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0; }
  86   };
  87 
  88   struct lookup_map_t {
  89     unsigned short index;
  90     unsigned short auto_zwj : 1;
  91     hb_mask_t mask;
  92 
  93     static int cmp (const lookup_map_t *a, const lookup_map_t *b)
  94     { return a->index < b->index ? -1 : a->index > b->index ? 1 : 0; }
  95   };
  96 
  97   typedef void (*pause_func_t) (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer);
  98 
  99   struct stage_map_t {
 100     unsigned int last_lookup; /* Cumulative */
 101     pause_func_t pause_func;
 102   };
 103 
 104 
 105   hb_ot_map_t (void) { memset (this, 0, sizeof (*this)); }
 106 
 107   inline hb_mask_t get_global_mask (void) const { return global_mask; }
 108 
 109   inline hb_mask_t get_mask (hb_tag_t feature_tag, unsigned int *shift = NULL) const {
 110     const feature_map_t *map = features.bsearch (&feature_tag);
 111     if (shift) *shift = map ? map->shift : 0;
 112     return map ? map->mask : 0;
 113   }
 114 
 115   inline bool needs_fallback (hb_tag_t feature_tag) const {
 116     const feature_map_t *map = features.bsearch (&feature_tag);
 117     return map ? map->needs_fallback : false;
 118   }
 119 
 120   inline hb_mask_t get_1_mask (hb_tag_t feature_tag) const {
 121     const feature_map_t *map = features.bsearch (&feature_tag);
 122     return map ? map->_1_mask : 0;
 123   }
 124 
 125   inline unsigned int get_feature_index (unsigned int table_index, hb_tag_t feature_tag) const {
 126     const feature_map_t *map = features.bsearch (&feature_tag);
 127     return map ? map->index[table_index] : HB_OT_LAYOUT_NO_FEATURE_INDEX;
 128   }
 129 
 130   inline unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const {
 131     const feature_map_t *map = features.bsearch (&feature_tag);
 132     return map ? map->stage[table_index] : (unsigned int) -1;
 133   }
 134 
 135   inline void get_stage_lookups (unsigned int table_index, unsigned int stage,
 136                                  const struct lookup_map_t **plookups, unsigned int *lookup_count) const {
 137     if (unlikely (stage == (unsigned int) -1)) {
 138       *plookups = NULL;
 139       *lookup_count = 0;
 140       return;
 141     }
 142     assert (stage <= stages[table_index].len);
 143     unsigned int start = stage ? stages[table_index][stage - 1].last_lookup : 0;
 144     unsigned int end   = stage < stages[table_index].len ? stages[table_index][stage].last_lookup : lookups[table_index].len;
 145     *plookups = &lookups[table_index][start];
 146     *lookup_count = end - start;
 147   }
 148 
 149   HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const;
 150   template <typename Proxy>
 151   HB_INTERNAL inline void apply (const Proxy &proxy,
 152                                  const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
 153   HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
 154   HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const;
 155 
 156   inline void finish (void) {
 157     features.finish ();
 158     for (unsigned int table_index = 0; table_index < 2; table_index++)
 159     {
 160       lookups[table_index].finish ();
 161       stages[table_index].finish ();
 162     }
 163   }
 164 
 165   public:
 166   hb_tag_t chosen_script[2];
 167   bool found_script[2];
 168 
 169   private:
 170 
 171   HB_INTERNAL void add_lookups (hb_face_t    *face,
 172                                 unsigned int  table_index,
 173                                 unsigned int  feature_index,
 174                                 hb_mask_t     mask,
 175                                 bool          auto_zwj);
 176 
 177   hb_mask_t global_mask;
 178 
 179   hb_prealloced_array_t<feature_map_t, 8> features;
 180   hb_prealloced_array_t<lookup_map_t, 32> lookups[2]; /* GSUB/GPOS */
 181   hb_prealloced_array_t<stage_map_t, 4> stages[2]; /* GSUB/GPOS */
 182 };
 183 
 184 enum hb_ot_map_feature_flags_t {
 185   F_NONE                = 0x0000u,
 186   F_GLOBAL              = 0x0001u, /* Feature applies to all characters; results in no mask allocated for it. */
 187   F_HAS_FALLBACK        = 0x0002u, /* Has fallback implementation, so include mask bit even if feature not found. */
 188   F_MANUAL_ZWJ          = 0x0004u, /* Don't skip over ZWJ when matching. */
 189   F_GLOBAL_SEARCH       = 0x0008u  /* If feature not found in LangSys, look for it in global feature list and pick one. */
 190 };
 191 /* Macro version for where const is desired. */
 192 #define F_COMBINE(l,r) (hb_ot_map_feature_flags_t ((unsigned int) (l) | (unsigned int) (r)))
 193 static inline hb_ot_map_feature_flags_t
 194 operator | (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
 195 { return hb_ot_map_feature_flags_t ((unsigned int) l | (unsigned int) r); }
 196 static inline hb_ot_map_feature_flags_t
 197 operator & (hb_ot_map_feature_flags_t l, hb_ot_map_feature_flags_t r)
 198 { return hb_ot_map_feature_flags_t ((unsigned int) l & (unsigned int) r); }
 199 static inline hb_ot_map_feature_flags_t
 200 operator ~ (hb_ot_map_feature_flags_t r)
 201 { return hb_ot_map_feature_flags_t (~(unsigned int) r); }
 202 static inline hb_ot_map_feature_flags_t&
 203 operator |= (hb_ot_map_feature_flags_t &l, hb_ot_map_feature_flags_t r)
 204 { l = l | r; return l; }
 205 static inline hb_ot_map_feature_flags_t&
 206 operator &= (hb_ot_map_feature_flags_t& l, hb_ot_map_feature_flags_t r)
 207 { l = l & r; return l; }
 208 
 209 
 210 struct hb_ot_map_builder_t
 211 {
 212   public:
 213 
 214   HB_INTERNAL hb_ot_map_builder_t (hb_face_t *face_,
 215                                    const hb_segment_properties_t *props_);
 216 
 217   HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value,
 218                                 hb_ot_map_feature_flags_t flags);
 219 
 220   inline void add_global_bool_feature (hb_tag_t tag)
 221   { add_feature (tag, 1, F_GLOBAL); }
 222 
 223   inline void add_gsub_pause (hb_ot_map_t::pause_func_t pause_func)
 224   { add_pause (0, pause_func); }
 225   inline void add_gpos_pause (hb_ot_map_t::pause_func_t pause_func)
 226   { add_pause (1, pause_func); }
 227 
 228   HB_INTERNAL void compile (struct hb_ot_map_t &m);
 229 
 230   inline void finish (void) {
 231     feature_infos.finish ();
 232     for (unsigned int table_index = 0; table_index < 2; table_index++)
 233     {
 234       stages[table_index].finish ();
 235     }
 236   }
 237 
 238   private:
 239 
 240   struct feature_info_t {
 241     hb_tag_t tag;
 242     unsigned int seq; /* sequence#, used for stable sorting only */
 243     unsigned int max_value;
 244     hb_ot_map_feature_flags_t flags;
 245     unsigned int default_value; /* for non-global features, what should the unset glyphs take */
 246     unsigned int stage[2]; /* GSUB/GPOS */
 247 
 248     static int cmp (const feature_info_t *a, const feature_info_t *b)
 249     { return (a->tag != b->tag) ?  (a->tag < b->tag ? -1 : 1) : (a->seq < b->seq ? -1 : 1); }
 250   };
 251 
 252   struct stage_info_t {
 253     unsigned int index;
 254     hb_ot_map_t::pause_func_t pause_func;
 255   };
 256 
 257   HB_INTERNAL void add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func);
 258 
 259   public:
 260 
 261   hb_face_t *face;
 262   hb_segment_properties_t props;
 263 
 264   hb_tag_t chosen_script[2];
 265   bool found_script[2];
 266   unsigned int script_index[2], language_index[2];
 267 
 268   private:
 269 
 270   unsigned int current_stage[2]; /* GSUB/GPOS */
 271   hb_prealloced_array_t<feature_info_t, 32> feature_infos;
 272   hb_prealloced_array_t<stage_info_t, 8> stages[2]; /* GSUB/GPOS */
 273 };
 274 
 275 
 276 
 277 #endif /* HB_OT_MAP_PRIVATE_HH */