tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-aat-map.cc (5994B)


      1 /*
      2 * Copyright © 2009,2010  Red Hat, Inc.
      3 * Copyright © 2010,2011,2013  Google, Inc.
      4 *
      5 *  This is part of HarfBuzz, a text shaping library.
      6 *
      7 * Permission is hereby granted, without written agreement and without
      8 * license or royalty fees, to use, copy, modify, and distribute this
      9 * software and its documentation for any purpose, provided that the
     10 * above copyright notice and the following two paragraphs appear in
     11 * all copies of this software.
     12 *
     13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     17 * DAMAGE.
     18 *
     19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     21 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     24 *
     25 * Red Hat Author(s): Behdad Esfahbod
     26 * Google Author(s): Behdad Esfahbod
     27 */
     28 
     29 #include "hb.hh"
     30 
     31 #ifndef HB_NO_AAT_SHAPE
     32 
     33 #include "hb-aat-map.hh"
     34 
     35 #include "hb-aat-layout.hh"
     36 #include "hb-aat-layout-feat-table.hh"
     37 
     38 
     39 void hb_aat_map_builder_t::add_feature (const hb_feature_t &feature)
     40 {
     41  if (!face->table.feat->has_data ()) return;
     42 
     43  if (feature.tag == HB_TAG ('a','a','l','t'))
     44  {
     45    if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
     46      return;
     47    feature_range_t *range = features.push();
     48    range->start = feature.start;
     49    range->end = feature.end;
     50    range->info.type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
     51    range->info.setting = (hb_aat_layout_feature_selector_t) feature.value;
     52    range->info.seq = features.length;
     53    range->info.is_exclusive = true;
     54    return;
     55  }
     56 
     57  const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (feature.tag);
     58  if (!mapping) return;
     59 
     60  const AAT::FeatureName* feature_name = &face->table.feat->get_feature (mapping->aatFeatureType);
     61  if (!feature_name->has_data ())
     62  {
     63    /* Special case: Chain::compile_flags will fall back to the deprecated version of
     64     * small-caps if necessary, so we need to check for that possibility.
     65     * https://github.com/harfbuzz/harfbuzz/issues/2307 */
     66    if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
     67 mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
     68    {
     69      feature_name = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
     70      if (!feature_name->has_data ()) return;
     71    }
     72    else return;
     73  }
     74 
     75  feature_range_t *range = features.push();
     76  range->start = feature.start;
     77  range->end = feature.end;
     78  range->info.type = mapping->aatFeatureType;
     79  range->info.setting = feature.value ? mapping->selectorToEnable : mapping->selectorToDisable;
     80  range->info.seq = features.length;
     81  range->info.is_exclusive = feature_name->is_exclusive ();
     82 }
     83 
     84 void
     85 hb_aat_map_builder_t::compile (hb_aat_map_t  &m)
     86 {
     87  /* Compute active features per range, and compile each. */
     88  if (!features.length)
     89  {
     90    hb_aat_layout_compile_map (this, &m);
     91    return;
     92  }
     93 
     94  /* Sort features by start/end events. */
     95  hb_vector_t<feature_event_t> feature_events;
     96  feature_events.alloc_exact (features.length * 2 + 1);
     97  for (unsigned int i = 0; i < features.length; i++)
     98  {
     99    auto &feature = features.arrayZ[i];
    100 
    101    if (feature.start == feature.end)
    102      continue;
    103 
    104    feature_event_t *event;
    105 
    106    event = feature_events.push ();
    107    event->index = feature.start;
    108    event->start = true;
    109    event->feature = feature.info;
    110 
    111    event = feature_events.push ();
    112    event->index = feature.end;
    113    event->start = false;
    114    event->feature = feature.info;
    115  }
    116  feature_events.qsort ();
    117  /* Add a strategic final event. */
    118  {
    119    feature_info_t feature;
    120    feature.seq = features.length + 1;
    121 
    122    feature_event_t *event = feature_events.push ();
    123    event->index = -1; /* This value does magic. */
    124    event->start = false;
    125    event->feature = feature;
    126  }
    127 
    128  /* Scan events and save features for each range. */
    129  hb_sorted_vector_t<feature_info_t> active_features;
    130  unsigned int last_index = 0;
    131  for (unsigned int i = 0; i < feature_events.length; i++)
    132  {
    133    feature_event_t *event = &feature_events[i];
    134 
    135    if (event->index != last_index)
    136    {
    137      /* Save a snapshot of active features and the range. */
    138 
    139      /* Sort features and merge duplicates */
    140      current_features = active_features;
    141      range_first = last_index;
    142      range_last = event->index - 1;
    143      if (current_features.length)
    144      {
    145 current_features.qsort ();
    146 unsigned int j = 0;
    147 for (unsigned int i = 1; i < current_features.length; i++)
    148   if (current_features.arrayZ[i].type != current_features.arrayZ[j].type ||
    149       /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
    150        * respectively, so we mask out the low-order bit when checking for "duplicates"
    151        * (selectors referring to the same feature setting) here. */
    152       (!current_features.arrayZ[i].is_exclusive && ((current_features.arrayZ[i].setting & ~1) != (current_features.arrayZ[j].setting & ~1))))
    153     current_features.arrayZ[++j] = current_features.arrayZ[i];
    154 current_features.shrink (j + 1);
    155      }
    156 
    157      hb_aat_layout_compile_map (this, &m);
    158 
    159      last_index = event->index;
    160    }
    161 
    162    if (event->start)
    163    {
    164      active_features.push (event->feature);
    165    } else {
    166      feature_info_t *feature = active_features.lsearch (event->feature);
    167      if (feature)
    168 active_features.remove_ordered (feature - active_features.arrayZ);
    169    }
    170  }
    171 
    172  for (auto &chain_flags : m.chain_flags)
    173    // With our above setup this value is one less than desired; adjust it.
    174    chain_flags.tail().cluster_last = HB_FEATURE_GLOBAL_END;
    175 }
    176 
    177 
    178 #endif