1 /* 2 * Copyright © 2018 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): Garret Rieger, Roderick Sheeter 25 */ 26 27 #ifndef HB_SUBSET_PLAN_HH 28 #define HB_SUBSET_PLAN_HH 29 30 #include "hb.hh" 31 32 #include "hb-subset.h" 33 #include "hb-subset-input.hh" 34 #include "hb-subset-accelerator.hh" 35 36 #include "hb-map.hh" 37 #include "hb-bimap.hh" 38 #include "hb-set.hh" 39 40 namespace OT { 41 struct Feature; 42 } 43 44 struct os2_info_t { 45 hb_codepoint_t min_cmap_codepoint; 46 hb_codepoint_t max_cmap_codepoint; 47 }; 48 49 typedef struct os2_info_t os2_info_t; 50 51 struct head_maxp_info_t 52 { head_maxp_info_thead_maxp_info_t53 head_maxp_info_t () 54 :xMin (0x7FFF), xMax (-0x7FFF), yMin (0x7FFF), yMax (-0x7FFF), 55 maxPoints (0), maxContours (0), 56 maxCompositePoints (0), 57 maxCompositeContours (0), 58 maxComponentElements (0), 59 maxComponentDepth (0), 60 allXMinIsLsb (true) {} 61 62 int xMin; 63 int xMax; 64 int yMin; 65 int yMax; 66 unsigned maxPoints; 67 unsigned maxContours; 68 unsigned maxCompositePoints; 69 unsigned maxCompositeContours; 70 unsigned maxComponentElements; 71 unsigned maxComponentDepth; 72 bool allXMinIsLsb; 73 }; 74 75 typedef struct head_maxp_info_t head_maxp_info_t; 76 77 struct contour_point_t 78 { initcontour_point_t79 void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false) 80 { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; } 81 transformcontour_point_t82 void transform (const float (&matrix)[4]) 83 { 84 float x_ = x * matrix[0] + y * matrix[2]; 85 y = x * matrix[1] + y * matrix[3]; 86 x = x_; 87 } 88 add_deltacontour_point_t89 void add_delta (float delta_x, float delta_y) 90 { 91 x += delta_x; 92 y += delta_y; 93 } 94 95 HB_ALWAYS_INLINE translatecontour_point_t96 void translate (const contour_point_t &p) { x += p.x; y += p.y; } 97 98 99 float x; 100 float y; 101 uint8_t flag; 102 bool is_end_point; 103 }; 104 105 struct contour_point_vector_t : hb_vector_t<contour_point_t> 106 { extendcontour_point_vector_t107 void extend (const hb_array_t<contour_point_t> &a) 108 { 109 unsigned int old_len = length; 110 if (unlikely (!resize (old_len + a.length, false))) 111 return; 112 auto arrayZ = this->arrayZ + old_len; 113 unsigned count = a.length; 114 hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0])); 115 } 116 add_deltascontour_point_vector_t117 bool add_deltas (const hb_vector_t<float> deltas_x, 118 const hb_vector_t<float> deltas_y, 119 const hb_vector_t<bool> indices) 120 { 121 if (indices.length != deltas_x.length || 122 indices.length != deltas_y.length) 123 return false; 124 125 for (unsigned i = 0; i < indices.length; i++) 126 { 127 if (!indices.arrayZ[i]) continue; 128 arrayZ[i].add_delta (deltas_x.arrayZ[i], deltas_y.arrayZ[i]); 129 } 130 return true; 131 } 132 }; 133 134 namespace OT { 135 struct cff1_subset_accelerator_t; 136 struct cff2_subset_accelerator_t; 137 } 138 139 struct hb_subset_plan_t 140 { 141 HB_INTERNAL hb_subset_plan_t (hb_face_t *, 142 const hb_subset_input_t *input); 143 144 HB_INTERNAL ~hb_subset_plan_t(); 145 146 hb_object_header_t header; 147 148 bool successful; 149 unsigned flags; 150 bool attach_accelerator_data = false; 151 bool force_long_loca = false; 152 153 // The glyph subset 154 hb_map_t *codepoint_to_glyph; // Needs to be heap-allocated 155 156 // Old -> New glyph id mapping 157 hb_map_t *glyph_map; // Needs to be heap-allocated 158 hb_map_t *reverse_glyph_map; // Needs to be heap-allocated 159 160 // Plan is only good for a specific source/dest so keep them with it 161 hb_face_t *source; 162 #ifndef HB_NO_SUBSET_CFF 163 // These have to be immediately after source: 164 hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel; 165 hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel; 166 #endif 167 168 hb_face_t *dest; 169 170 unsigned int _num_output_glyphs; 171 172 bool all_axes_pinned; 173 bool pinned_at_default; 174 bool has_seac; 175 176 // whether to insert a catch-all FeatureVariationRecord 177 bool gsub_insert_catch_all_feature_variation_rec; 178 bool gpos_insert_catch_all_feature_variation_rec; 179 180 // whether GDEF ItemVariationStore is retained 181 mutable bool has_gdef_varstore; 182 183 #define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name; 184 #include "hb-subset-plan-member-list.hh" 185 #undef HB_SUBSET_PLAN_MEMBER 186 187 //recalculated head/maxp table info after instancing 188 mutable head_maxp_info_t head_maxp_info; 189 190 os2_info_t os2_info; 191 192 const hb_subset_accelerator_t* accelerator; 193 hb_subset_accelerator_t* inprogress_accelerator; 194 195 public: 196 197 template<typename T> 198 struct source_table_loader 199 { operator ()hb_subset_plan_t::source_table_loader200 hb_blob_ptr_t<T> operator () (hb_subset_plan_t *plan) 201 { 202 hb_lock_t lock (plan->accelerator ? &plan->accelerator->sanitized_table_cache_lock : nullptr); 203 204 auto *cache = plan->accelerator ? &plan->accelerator->sanitized_table_cache : &plan->sanitized_table_cache; 205 if (cache 206 && !cache->in_error () 207 && cache->has (+T::tableTag)) { 208 return hb_blob_reference (cache->get (+T::tableTag).get ()); 209 } 210 211 hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (plan->source)}; 212 hb_blob_t* ret = hb_blob_reference (table_blob.get ()); 213 214 if (likely (cache)) 215 cache->set (+T::tableTag, std::move (table_blob)); 216 217 return ret; 218 } 219 }; 220 221 template<typename T> source_tablehb_subset_plan_t222 auto source_table() HB_AUTO_RETURN (source_table_loader<T> {} (this)) 223 224 bool in_error () const { return !successful; } 225 check_successhb_subset_plan_t226 bool check_success(bool success) 227 { 228 successful = (successful && success); 229 return successful; 230 } 231 232 /* 233 * The set of input glyph ids which will be retained in the subset. 234 * Does NOT include ids kept due to retain_gids. You probably want to use 235 * glyph_map/reverse_glyph_map. 236 */ 237 inline const hb_set_t * glyphsethb_subset_plan_t238 glyphset () const 239 { 240 return &_glyphset; 241 } 242 243 /* 244 * The set of input glyph ids which will be retained in the subset. 245 */ 246 inline const hb_set_t * glyphset_gsubhb_subset_plan_t247 glyphset_gsub () const 248 { 249 return &_glyphset_gsub; 250 } 251 252 /* 253 * The total number of output glyphs in the final subset. 254 */ 255 inline unsigned int num_output_glyphshb_subset_plan_t256 num_output_glyphs () const 257 { 258 return _num_output_glyphs; 259 } 260 new_gid_for_codepointhb_subset_plan_t261 inline bool new_gid_for_codepoint (hb_codepoint_t codepoint, 262 hb_codepoint_t *new_gid) const 263 { 264 hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint); 265 if (old_gid == HB_MAP_VALUE_INVALID) 266 return false; 267 268 return new_gid_for_old_gid (old_gid, new_gid); 269 } 270 new_gid_for_old_gidhb_subset_plan_t271 inline bool new_gid_for_old_gid (hb_codepoint_t old_gid, 272 hb_codepoint_t *new_gid) const 273 { 274 hb_codepoint_t gid = glyph_map->get (old_gid); 275 if (gid == HB_MAP_VALUE_INVALID) 276 return false; 277 278 *new_gid = gid; 279 return true; 280 } 281 old_gid_for_new_gidhb_subset_plan_t282 inline bool old_gid_for_new_gid (hb_codepoint_t new_gid, 283 hb_codepoint_t *old_gid) const 284 { 285 hb_codepoint_t gid = reverse_glyph_map->get (new_gid); 286 if (gid == HB_MAP_VALUE_INVALID) 287 return false; 288 289 *old_gid = gid; 290 return true; 291 } 292 293 inline bool add_tablehb_subset_plan_t294 add_table (hb_tag_t tag, 295 hb_blob_t *contents) 296 { 297 if (HB_DEBUG_SUBSET) 298 { 299 hb_blob_t *source_blob = source->reference_table (tag); 300 DEBUG_MSG(SUBSET, nullptr, "add table %c%c%c%c, dest %u bytes, source %u bytes", 301 HB_UNTAG(tag), 302 hb_blob_get_length (contents), 303 hb_blob_get_length (source_blob)); 304 hb_blob_destroy (source_blob); 305 } 306 return hb_face_builder_add_table (dest, tag, contents); 307 } 308 }; 309 310 311 #endif /* HB_SUBSET_PLAN_HH */ 312