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