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,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 #include "hb-ot-map-private.hh"
  59 
  60 #include "hb-ot-layout-private.hh"
  61 
  62 
  63 void
  64 hb_ot_map_t::add_lookups (hb_face_t    *face,
  65                           unsigned int  table_index,
  66                           unsigned int  feature_index,
  67                           hb_mask_t     mask,
  68                           bool          auto_zwj)
  69 {
  70   unsigned int lookup_indices[32];
  71   unsigned int offset, len;
  72   unsigned int table_lookup_count;
  73 
  74   table_lookup_count = hb_ot_layout_table_get_lookup_count (face, table_tags[table_index]);
  75 
  76   offset = 0;
  77   do {
  78     len = ARRAY_LENGTH (lookup_indices);
  79     hb_ot_layout_feature_get_lookups (face,
  80                                       table_tags[table_index],
  81                                       feature_index,
  82                                       offset, &len,
  83                                       lookup_indices);
  84 
  85     for (unsigned int i = 0; i < len; i++)
  86     {
  87       if (lookup_indices[i] >= table_lookup_count)
  88         continue;
  89       hb_ot_map_t::lookup_map_t *lookup = lookups[table_index].push ();
  90       if (unlikely (!lookup))
  91         return;
  92       lookup->mask = mask;
  93       lookup->index = lookup_indices[i];
  94       lookup->auto_zwj = auto_zwj;
  95     }
  96 
  97     offset += len;
  98   } while (len == ARRAY_LENGTH (lookup_indices));
  99 }
 100 
 101 hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
 102                                           const hb_segment_properties_t *props_)
 103 {
 104   memset (this, 0, sizeof (*this));
 105 
 106   face = face_;
 107   props = *props_;
 108 
 109 
 110   /* Fetch script/language indices for GSUB/GPOS.  We need these later to skip
 111    * features not available in either table and not waste precious bits for them. */
 112 
 113   hb_tag_t script_tags[3] = {HB_TAG_NONE, HB_TAG_NONE, HB_TAG_NONE};
 114   hb_tag_t language_tag;
 115 
 116   hb_ot_tags_from_script (props.script, &script_tags[0], &script_tags[1]);
 117   language_tag = hb_ot_tag_from_language (props.language);
 118 
 119   for (unsigned int table_index = 0; table_index < 2; table_index++) {
 120     hb_tag_t table_tag = table_tags[table_index];
 121     found_script[table_index] = hb_ot_layout_table_choose_script (face, table_tag, script_tags, &script_index[table_index], &chosen_script[table_index]);
 122     hb_ot_layout_script_find_language (face, table_tag, script_index[table_index], language_tag, &language_index[table_index]);
 123   }
 124 }
 125 
 126 void hb_ot_map_builder_t::add_feature (hb_tag_t tag, unsigned int value,
 127                                        hb_ot_map_feature_flags_t flags)
 128 {
 129   feature_info_t *info = feature_infos.push();
 130   if (unlikely (!info)) return;
 131   if (unlikely (!tag)) return;
 132   info->tag = tag;
 133   info->seq = feature_infos.len;
 134   info->max_value = value;
 135   info->flags = flags;
 136   info->default_value = (flags & F_GLOBAL) ? value : 0;
 137   info->stage[0] = current_stage[0];
 138   info->stage[1] = current_stage[1];
 139 }
 140 
 141 
 142 void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const
 143 {
 144   for (unsigned int i = 0; i < lookups[table_index].len; i++)
 145     hb_set_add (lookups_out, lookups[table_index][i].index);
 146 }
 147 
 148 void hb_ot_map_builder_t::add_pause (unsigned int table_index, hb_ot_map_t::pause_func_t pause_func)
 149 {
 150   stage_info_t *s = stages[table_index].push ();
 151   if (likely (s)) {
 152     s->index = current_stage[table_index];
 153     s->pause_func = pause_func;
 154   }
 155 
 156   current_stage[table_index]++;
 157 }
 158 
 159 void
 160 hb_ot_map_builder_t::compile (hb_ot_map_t &m)
 161 {
 162   m.global_mask = 1;
 163 
 164   unsigned int required_feature_index[2];
 165   hb_tag_t required_feature_tag[2];
 166   /* We default to applying required feature in stage 0.  If the required
 167    * feature has a tag that is known to the shaper, we apply required feature
 168    * in the stage for that tag.
 169    */
 170   unsigned int required_feature_stage[2] = {0, 0};
 171 
 172   for (unsigned int table_index = 0; table_index < 2; table_index++)
 173   {
 174     m.chosen_script[table_index] = chosen_script[table_index];
 175     m.found_script[table_index] = found_script[table_index];
 176 
 177     hb_ot_layout_language_get_required_feature (face,
 178                                                 table_tags[table_index],
 179                                                 script_index[table_index],
 180                                                 language_index[table_index],
 181                                                 &required_feature_index[table_index],
 182                                                 &required_feature_tag[table_index]);
 183   }
 184 
 185   if (!feature_infos.len)
 186     return;
 187 
 188   /* Sort features and merge duplicates */
 189   {
 190     feature_infos.qsort ();
 191     unsigned int j = 0;
 192     for (unsigned int i = 1; i < feature_infos.len; i++)
 193       if (feature_infos[i].tag != feature_infos[j].tag)
 194         feature_infos[++j] = feature_infos[i];
 195       else {
 196         if (feature_infos[i].flags & F_GLOBAL) {
 197           feature_infos[j].flags |= F_GLOBAL;
 198           feature_infos[j].max_value = feature_infos[i].max_value;
 199           feature_infos[j].default_value = feature_infos[i].default_value;
 200         } else {
 201           feature_infos[j].flags &= ~F_GLOBAL;
 202           feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value);
 203           /* Inherit default_value from j */
 204         }
 205         feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK);
 206         feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]);
 207         feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]);
 208       }
 209     feature_infos.shrink (j + 1);
 210   }
 211 
 212 
 213   /* Allocate bits now */
 214   unsigned int next_bit = 1;
 215   for (unsigned int i = 0; i < feature_infos.len; i++)
 216   {
 217     const feature_info_t *info = &feature_infos[i];
 218 
 219     unsigned int bits_needed;
 220 
 221     if ((info->flags & F_GLOBAL) && info->max_value == 1)
 222       /* Uses the global bit */
 223       bits_needed = 0;
 224     else
 225       bits_needed = _hb_bit_storage (info->max_value);
 226 
 227     if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
 228       continue; /* Feature disabled, or not enough bits. */
 229 
 230 
 231     hb_bool_t found = false;
 232     unsigned int feature_index[2];
 233     for (unsigned int table_index = 0; table_index < 2; table_index++)
 234     {
 235       if (required_feature_tag[table_index] == info->tag)
 236       {
 237         required_feature_stage[table_index] = info->stage[table_index];
 238         found = true;
 239         continue;
 240       }
 241       found |= hb_ot_layout_language_find_feature (face,
 242                                                    table_tags[table_index],
 243                                                    script_index[table_index],
 244                                                    language_index[table_index],
 245                                                    info->tag,
 246                                                    &feature_index[table_index]);
 247     }
 248     if (!found && (info->flags & F_GLOBAL_SEARCH))
 249     {
 250       for (unsigned int table_index = 0; table_index < 2; table_index++)
 251       {
 252         found |= hb_ot_layout_table_find_feature (face,
 253                                                   table_tags[table_index],
 254                                                   info->tag,
 255                                                   &feature_index[table_index]);
 256       }
 257     }
 258     if (!found && !(info->flags & F_HAS_FALLBACK))
 259       continue;
 260 
 261 
 262     hb_ot_map_t::feature_map_t *map = m.features.push ();
 263     if (unlikely (!map))
 264       break;
 265 
 266     map->tag = info->tag;
 267     map->index[0] = feature_index[0];
 268     map->index[1] = feature_index[1];
 269     map->stage[0] = info->stage[0];
 270     map->stage[1] = info->stage[1];
 271     map->auto_zwj = !(info->flags & F_MANUAL_ZWJ);
 272     if ((info->flags & F_GLOBAL) && info->max_value == 1) {
 273       /* Uses the global bit */
 274       map->shift = 0;
 275       map->mask = 1;
 276     } else {
 277       map->shift = next_bit;
 278       map->mask = (1 << (next_bit + bits_needed)) - (1 << next_bit);
 279       next_bit += bits_needed;
 280       m.global_mask |= (info->default_value << map->shift) & map->mask;
 281     }
 282     map->_1_mask = (1 << map->shift) & map->mask;
 283     map->needs_fallback = !found;
 284 
 285   }
 286   feature_infos.shrink (0); /* Done with these */
 287 
 288 
 289   add_gsub_pause (NULL);
 290   add_gpos_pause (NULL);
 291 
 292   for (unsigned int table_index = 0; table_index < 2; table_index++)
 293   {
 294     /* Collect lookup indices for features */
 295 
 296     unsigned int stage_index = 0;
 297     unsigned int last_num_lookups = 0;
 298     for (unsigned stage = 0; stage < current_stage[table_index]; stage++)
 299     {
 300       if (required_feature_index[table_index] != HB_OT_LAYOUT_NO_FEATURE_INDEX &&
 301           required_feature_stage[table_index] == stage)
 302         m.add_lookups (face, table_index,
 303                        required_feature_index[table_index],
 304                        1 /* mask */,
 305                        true /* auto_zwj */);
 306 
 307       for (unsigned i = 0; i < m.features.len; i++)
 308         if (m.features[i].stage[table_index] == stage)
 309           m.add_lookups (face, table_index,
 310                          m.features[i].index[table_index],
 311                          m.features[i].mask,
 312                          m.features[i].auto_zwj);
 313 
 314       /* Sort lookups and merge duplicates */
 315       if (last_num_lookups < m.lookups[table_index].len)
 316       {
 317         m.lookups[table_index].qsort (last_num_lookups, m.lookups[table_index].len);
 318 
 319         unsigned int j = last_num_lookups;
 320         for (unsigned int i = j + 1; i < m.lookups[table_index].len; i++)
 321           if (m.lookups[table_index][i].index != m.lookups[table_index][j].index)
 322             m.lookups[table_index][++j] = m.lookups[table_index][i];
 323           else
 324           {
 325             m.lookups[table_index][j].mask |= m.lookups[table_index][i].mask;
 326             m.lookups[table_index][j].auto_zwj &= m.lookups[table_index][i].auto_zwj;
 327           }
 328         m.lookups[table_index].shrink (j + 1);
 329       }
 330 
 331       last_num_lookups = m.lookups[table_index].len;
 332 
 333       if (stage_index < stages[table_index].len && stages[table_index][stage_index].index == stage) {
 334         hb_ot_map_t::stage_map_t *stage_map = m.stages[table_index].push ();
 335         if (likely (stage_map)) {
 336           stage_map->last_lookup = last_num_lookups;
 337           stage_map->pause_func = stages[table_index][stage_index].pause_func;
 338         }
 339 
 340         stage_index++;
 341       }
 342     }
 343   }
 344 }