| 1 | /* | 
|---|
| 2 | * Copyright © 2014  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): Behdad Esfahbod | 
|---|
| 25 | */ | 
|---|
| 26 |  | 
|---|
| 27 | #ifndef HB_OT_CMAP_TABLE_HH | 
|---|
| 28 | #define HB_OT_CMAP_TABLE_HH | 
|---|
| 29 |  | 
|---|
| 30 | #include "hb-open-type.hh" | 
|---|
| 31 | #include "hb-set.hh" | 
|---|
| 32 |  | 
|---|
| 33 | /* | 
|---|
| 34 | * cmap -- Character to Glyph Index Mapping | 
|---|
| 35 | * https://docs.microsoft.com/en-us/typography/opentype/spec/cmap | 
|---|
| 36 | */ | 
|---|
| 37 | #define HB_OT_TAG_cmap HB_TAG('c','m','a','p') | 
|---|
| 38 |  | 
|---|
| 39 | namespace OT { | 
|---|
| 40 |  | 
|---|
| 41 |  | 
|---|
| 42 | struct CmapSubtableFormat0 | 
|---|
| 43 | { | 
|---|
| 44 | bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const | 
|---|
| 45 | { | 
|---|
| 46 | hb_codepoint_t gid = codepoint < 256 ? glyphIdArray[codepoint] : 0; | 
|---|
| 47 | if (!gid) | 
|---|
| 48 | return false; | 
|---|
| 49 | *glyph = gid; | 
|---|
| 50 | return true; | 
|---|
| 51 | } | 
|---|
| 52 | void collect_unicodes (hb_set_t *out) const | 
|---|
| 53 | { | 
|---|
| 54 | for (unsigned int i = 0; i < 256; i++) | 
|---|
| 55 | if (glyphIdArray[i]) | 
|---|
| 56 | out->add (i); | 
|---|
| 57 | } | 
|---|
| 58 |  | 
|---|
| 59 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 60 | { | 
|---|
| 61 | TRACE_SANITIZE (this); | 
|---|
| 62 | return_trace (c->check_struct (this)); | 
|---|
| 63 | } | 
|---|
| 64 |  | 
|---|
| 65 | protected: | 
|---|
| 66 | HBUINT16      format;         /* Format number is set to 0. */ | 
|---|
| 67 | HBUINT16      length;         /* Byte length of this subtable. */ | 
|---|
| 68 | HBUINT16      language;       /* Ignore. */ | 
|---|
| 69 | HBUINT8       glyphIdArray[256];/* An array that maps character | 
|---|
| 70 | * code to glyph index values. */ | 
|---|
| 71 | public: | 
|---|
| 72 | DEFINE_SIZE_STATIC (6 + 256); | 
|---|
| 73 | }; | 
|---|
| 74 |  | 
|---|
| 75 | struct CmapSubtableFormat4 | 
|---|
| 76 | { | 
|---|
| 77 | struct segment_plan | 
|---|
| 78 | { | 
|---|
| 79 | HBUINT16 start_code; | 
|---|
| 80 | HBUINT16 end_code; | 
|---|
| 81 | bool use_delta; | 
|---|
| 82 | }; | 
|---|
| 83 |  | 
|---|
| 84 | bool serialize (hb_serialize_context_t *c, | 
|---|
| 85 | const hb_subset_plan_t *plan, | 
|---|
| 86 | const hb_vector_t<segment_plan> &segments) | 
|---|
| 87 | { | 
|---|
| 88 | TRACE_SERIALIZE (this); | 
|---|
| 89 |  | 
|---|
| 90 | if (unlikely (!c->extend_min (*this))) return_trace (false); | 
|---|
| 91 |  | 
|---|
| 92 | this->format.set (4); | 
|---|
| 93 | this->length.set (get_sub_table_size (segments)); | 
|---|
| 94 |  | 
|---|
| 95 | this->segCountX2.set (segments.length * 2); | 
|---|
| 96 | this->entrySelector.set (MAX (1u, hb_bit_storage (segments.length)) - 1); | 
|---|
| 97 | this->searchRange.set (2 * (1u << this->entrySelector)); | 
|---|
| 98 | this->rangeShift.set (segments.length * 2 > this->searchRange | 
|---|
| 99 | ? 2 * segments.length - this->searchRange | 
|---|
| 100 | : 0); | 
|---|
| 101 |  | 
|---|
| 102 | HBUINT16 *end_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length); | 
|---|
| 103 | c->allocate_size<HBUINT16> (HBUINT16::static_size); // 2 bytes of padding. | 
|---|
| 104 | HBUINT16 *start_count = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length); | 
|---|
| 105 | HBINT16 *id_delta = c->allocate_size<HBINT16> (HBUINT16::static_size * segments.length); | 
|---|
| 106 | HBUINT16 *id_range_offset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segments.length); | 
|---|
| 107 |  | 
|---|
| 108 | if (id_range_offset == nullptr) | 
|---|
| 109 | return_trace (false); | 
|---|
| 110 |  | 
|---|
| 111 | for (unsigned int i = 0; i < segments.length; i++) | 
|---|
| 112 | { | 
|---|
| 113 | end_count[i].set (segments[i].end_code); | 
|---|
| 114 | start_count[i].set (segments[i].start_code); | 
|---|
| 115 | if (segments[i].use_delta) | 
|---|
| 116 | { | 
|---|
| 117 | hb_codepoint_t cp = segments[i].start_code; | 
|---|
| 118 | hb_codepoint_t start_gid = 0; | 
|---|
| 119 | if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF)) | 
|---|
| 120 | return_trace (false); | 
|---|
| 121 | id_delta[i].set (start_gid - segments[i].start_code); | 
|---|
| 122 | } else { | 
|---|
| 123 | id_delta[i].set (0); | 
|---|
| 124 | unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1; | 
|---|
| 125 | HBUINT16 *glyph_id_array = c->allocate_size<HBUINT16> (HBUINT16::static_size * num_codepoints); | 
|---|
| 126 | if (glyph_id_array == nullptr) | 
|---|
| 127 | return_trace (false); | 
|---|
| 128 | // From the cmap spec: | 
|---|
| 129 | // | 
|---|
| 130 | // id_range_offset[i]/2 | 
|---|
| 131 | // + (cp - segments[i].start_code) | 
|---|
| 132 | // + (id_range_offset + i) | 
|---|
| 133 | // = | 
|---|
| 134 | // glyph_id_array + (cp - segments[i].start_code) | 
|---|
| 135 | // | 
|---|
| 136 | // So, solve for id_range_offset[i]: | 
|---|
| 137 | // | 
|---|
| 138 | // id_range_offset[i] | 
|---|
| 139 | // = | 
|---|
| 140 | // 2 * (glyph_id_array - id_range_offset - i) | 
|---|
| 141 | id_range_offset[i].set (2 * ( | 
|---|
| 142 | glyph_id_array - id_range_offset - i)); | 
|---|
| 143 | for (unsigned int j = 0; j < num_codepoints; j++) | 
|---|
| 144 | { | 
|---|
| 145 | hb_codepoint_t cp = segments[i].start_code + j; | 
|---|
| 146 | hb_codepoint_t new_gid; | 
|---|
| 147 | if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) | 
|---|
| 148 | return_trace (false); | 
|---|
| 149 | glyph_id_array[j].set (new_gid); | 
|---|
| 150 | } | 
|---|
| 151 | } | 
|---|
| 152 | } | 
|---|
| 153 |  | 
|---|
| 154 | return_trace (true); | 
|---|
| 155 | } | 
|---|
| 156 |  | 
|---|
| 157 | static size_t get_sub_table_size (const hb_vector_t<segment_plan> &segments) | 
|---|
| 158 | { | 
|---|
| 159 | size_t segment_size = 0; | 
|---|
| 160 | for (unsigned int i = 0; i < segments.length; i++) | 
|---|
| 161 | { | 
|---|
| 162 | // Parallel array entries | 
|---|
| 163 | segment_size += | 
|---|
| 164 | 2  // end count | 
|---|
| 165 | + 2  // start count | 
|---|
| 166 | + 2  // delta | 
|---|
| 167 | + 2; // range offset | 
|---|
| 168 |  | 
|---|
| 169 | if (!segments[i].use_delta) | 
|---|
| 170 | // Add bytes for the glyph index array entries for this segment. | 
|---|
| 171 | segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2; | 
|---|
| 172 | } | 
|---|
| 173 |  | 
|---|
| 174 | return min_size | 
|---|
| 175 | + 2 // Padding | 
|---|
| 176 | + segment_size; | 
|---|
| 177 | } | 
|---|
| 178 |  | 
|---|
| 179 | static bool create_sub_table_plan (const hb_subset_plan_t *plan, | 
|---|
| 180 | hb_vector_t<segment_plan> *segments) | 
|---|
| 181 | { | 
|---|
| 182 | segment_plan *segment = nullptr; | 
|---|
| 183 | hb_codepoint_t last_gid = 0; | 
|---|
| 184 |  | 
|---|
| 185 | hb_codepoint_t cp = HB_SET_VALUE_INVALID; | 
|---|
| 186 | while (plan->unicodes->next (&cp)) { | 
|---|
| 187 | hb_codepoint_t new_gid; | 
|---|
| 188 | if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) | 
|---|
| 189 | { | 
|---|
| 190 | DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); | 
|---|
| 191 | return false; | 
|---|
| 192 | } | 
|---|
| 193 |  | 
|---|
| 194 | /* Stop adding to cmap if we are now outside of unicode BMP. */ | 
|---|
| 195 | if (cp > 0xFFFF) break; | 
|---|
| 196 |  | 
|---|
| 197 | if (!segment || | 
|---|
| 198 | cp != segment->end_code + 1u) | 
|---|
| 199 | { | 
|---|
| 200 | segment = segments->push (); | 
|---|
| 201 | segment->start_code.set (cp); | 
|---|
| 202 | segment->end_code.set (cp); | 
|---|
| 203 | segment->use_delta = true; | 
|---|
| 204 | } else { | 
|---|
| 205 | segment->end_code.set (cp); | 
|---|
| 206 | if (last_gid + 1u != new_gid) | 
|---|
| 207 | // gid's are not consecutive in this segment so delta | 
|---|
| 208 | // cannot be used. | 
|---|
| 209 | segment->use_delta = false; | 
|---|
| 210 | } | 
|---|
| 211 |  | 
|---|
| 212 | last_gid = new_gid; | 
|---|
| 213 | } | 
|---|
| 214 |  | 
|---|
| 215 | // There must be a final entry with end_code == 0xFFFF. Check if we need to add one. | 
|---|
| 216 | if (segment == nullptr || segment->end_code != 0xFFFF) | 
|---|
| 217 | { | 
|---|
| 218 | segment = segments->push (); | 
|---|
| 219 | segment->start_code.set (0xFFFF); | 
|---|
| 220 | segment->end_code.set (0xFFFF); | 
|---|
| 221 | segment->use_delta = true; | 
|---|
| 222 | } | 
|---|
| 223 |  | 
|---|
| 224 | return true; | 
|---|
| 225 | } | 
|---|
| 226 |  | 
|---|
| 227 | struct accelerator_t | 
|---|
| 228 | { | 
|---|
| 229 | accelerator_t () {} | 
|---|
| 230 | accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); } | 
|---|
| 231 | ~accelerator_t () { fini (); } | 
|---|
| 232 |  | 
|---|
| 233 | void init (const CmapSubtableFormat4 *subtable) | 
|---|
| 234 | { | 
|---|
| 235 | segCount = subtable->segCountX2 / 2; | 
|---|
| 236 | endCount = subtable->values.arrayZ; | 
|---|
| 237 | startCount = endCount + segCount + 1; | 
|---|
| 238 | idDelta = startCount + segCount; | 
|---|
| 239 | idRangeOffset = idDelta + segCount; | 
|---|
| 240 | glyphIdArray = idRangeOffset + segCount; | 
|---|
| 241 | glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; | 
|---|
| 242 | } | 
|---|
| 243 | void fini () {} | 
|---|
| 244 |  | 
|---|
| 245 | bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const | 
|---|
| 246 | { | 
|---|
| 247 | /* Custom two-array bsearch. */ | 
|---|
| 248 | int min = 0, max = (int) this->segCount - 1; | 
|---|
| 249 | const HBUINT16 *startCount = this->startCount; | 
|---|
| 250 | const HBUINT16 *endCount = this->endCount; | 
|---|
| 251 | unsigned int i; | 
|---|
| 252 | while (min <= max) | 
|---|
| 253 | { | 
|---|
| 254 | int mid = ((unsigned int) min + (unsigned int) max) / 2; | 
|---|
| 255 | if (codepoint < startCount[mid]) | 
|---|
| 256 | max = mid - 1; | 
|---|
| 257 | else if (codepoint > endCount[mid]) | 
|---|
| 258 | min = mid + 1; | 
|---|
| 259 | else | 
|---|
| 260 | { | 
|---|
| 261 | i = mid; | 
|---|
| 262 | goto found; | 
|---|
| 263 | } | 
|---|
| 264 | } | 
|---|
| 265 | return false; | 
|---|
| 266 |  | 
|---|
| 267 | found: | 
|---|
| 268 | hb_codepoint_t gid; | 
|---|
| 269 | unsigned int rangeOffset = this->idRangeOffset[i]; | 
|---|
| 270 | if (rangeOffset == 0) | 
|---|
| 271 | gid = codepoint + this->idDelta[i]; | 
|---|
| 272 | else | 
|---|
| 273 | { | 
|---|
| 274 | /* Somebody has been smoking... */ | 
|---|
| 275 | unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; | 
|---|
| 276 | if (unlikely (index >= this->glyphIdArrayLength)) | 
|---|
| 277 | return false; | 
|---|
| 278 | gid = this->glyphIdArray[index]; | 
|---|
| 279 | if (unlikely (!gid)) | 
|---|
| 280 | return false; | 
|---|
| 281 | gid += this->idDelta[i]; | 
|---|
| 282 | } | 
|---|
| 283 | gid &= 0xFFFFu; | 
|---|
| 284 | if (!gid) | 
|---|
| 285 | return false; | 
|---|
| 286 | *glyph = gid; | 
|---|
| 287 | return true; | 
|---|
| 288 | } | 
|---|
| 289 | static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) | 
|---|
| 290 | { | 
|---|
| 291 | return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); | 
|---|
| 292 | } | 
|---|
| 293 | void collect_unicodes (hb_set_t *out) const | 
|---|
| 294 | { | 
|---|
| 295 | unsigned int count = this->segCount; | 
|---|
| 296 | if (count && this->startCount[count - 1] == 0xFFFFu) | 
|---|
| 297 | count--; /* Skip sentinel segment. */ | 
|---|
| 298 | for (unsigned int i = 0; i < count; i++) | 
|---|
| 299 | { | 
|---|
| 300 | unsigned int rangeOffset = this->idRangeOffset[i]; | 
|---|
| 301 | if (rangeOffset == 0) | 
|---|
| 302 | out->add_range (this->startCount[i], this->endCount[i]); | 
|---|
| 303 | else | 
|---|
| 304 | { | 
|---|
| 305 | for (hb_codepoint_t codepoint = this->startCount[i]; | 
|---|
| 306 | codepoint <= this->endCount[i]; | 
|---|
| 307 | codepoint++) | 
|---|
| 308 | { | 
|---|
| 309 | unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; | 
|---|
| 310 | if (unlikely (index >= this->glyphIdArrayLength)) | 
|---|
| 311 | break; | 
|---|
| 312 | hb_codepoint_t gid = this->glyphIdArray[index]; | 
|---|
| 313 | if (unlikely (!gid)) | 
|---|
| 314 | continue; | 
|---|
| 315 | out->add (codepoint); | 
|---|
| 316 | } | 
|---|
| 317 | } | 
|---|
| 318 | } | 
|---|
| 319 | } | 
|---|
| 320 |  | 
|---|
| 321 | const HBUINT16 *endCount; | 
|---|
| 322 | const HBUINT16 *startCount; | 
|---|
| 323 | const HBUINT16 *idDelta; | 
|---|
| 324 | const HBUINT16 *idRangeOffset; | 
|---|
| 325 | const HBUINT16 *glyphIdArray; | 
|---|
| 326 | unsigned int segCount; | 
|---|
| 327 | unsigned int glyphIdArrayLength; | 
|---|
| 328 | }; | 
|---|
| 329 |  | 
|---|
| 330 | bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const | 
|---|
| 331 | { | 
|---|
| 332 | accelerator_t accel (this); | 
|---|
| 333 | return accel.get_glyph_func (&accel, codepoint, glyph); | 
|---|
| 334 | } | 
|---|
| 335 | void collect_unicodes (hb_set_t *out) const | 
|---|
| 336 | { | 
|---|
| 337 | accelerator_t accel (this); | 
|---|
| 338 | accel.collect_unicodes (out); | 
|---|
| 339 | } | 
|---|
| 340 |  | 
|---|
| 341 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 342 | { | 
|---|
| 343 | TRACE_SANITIZE (this); | 
|---|
| 344 | if (unlikely (!c->check_struct (this))) | 
|---|
| 345 | return_trace (false); | 
|---|
| 346 |  | 
|---|
| 347 | if (unlikely (!c->check_range (this, length))) | 
|---|
| 348 | { | 
|---|
| 349 | /* Some broken fonts have too long of a "length" value. | 
|---|
| 350 | * If that is the case, just change the value to truncate | 
|---|
| 351 | * the subtable at the end of the blob. */ | 
|---|
| 352 | uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535, | 
|---|
| 353 | (uintptr_t) (c->end - | 
|---|
| 354 | (char *) this)); | 
|---|
| 355 | if (!c->try_set (&length, new_length)) | 
|---|
| 356 | return_trace (false); | 
|---|
| 357 | } | 
|---|
| 358 |  | 
|---|
| 359 | return_trace (16 + 4 * (unsigned int) segCountX2 <= length); | 
|---|
| 360 | } | 
|---|
| 361 |  | 
|---|
| 362 |  | 
|---|
| 363 |  | 
|---|
| 364 | protected: | 
|---|
| 365 | HBUINT16      format;         /* Format number is set to 4. */ | 
|---|
| 366 | HBUINT16      length;         /* This is the length in bytes of the | 
|---|
| 367 | * subtable. */ | 
|---|
| 368 | HBUINT16      language;       /* Ignore. */ | 
|---|
| 369 | HBUINT16      segCountX2;     /* 2 x segCount. */ | 
|---|
| 370 | HBUINT16      searchRange;    /* 2 * (2**floor(log2(segCount))) */ | 
|---|
| 371 | HBUINT16      entrySelector;  /* log2(searchRange/2) */ | 
|---|
| 372 | HBUINT16      rangeShift;     /* 2 x segCount - searchRange */ | 
|---|
| 373 |  | 
|---|
| 374 | UnsizedArrayOf<HBUINT16> | 
|---|
| 375 | values; | 
|---|
| 376 | #if 0 | 
|---|
| 377 | HBUINT16      endCount[segCount];     /* End characterCode for each segment, | 
|---|
| 378 | * last=0xFFFFu. */ | 
|---|
| 379 | HBUINT16      reservedPad;            /* Set to 0. */ | 
|---|
| 380 | HBUINT16      startCount[segCount];   /* Start character code for each segment. */ | 
|---|
| 381 | HBINT16               idDelta[segCount];      /* Delta for all character codes in segment. */ | 
|---|
| 382 | HBUINT16      idRangeOffset[segCount];/* Offsets into glyphIdArray or 0 */ | 
|---|
| 383 | UnsizedArrayOf<HBUINT16> | 
|---|
| 384 | glyphIdArray;   /* Glyph index array (arbitrary length) */ | 
|---|
| 385 | #endif | 
|---|
| 386 |  | 
|---|
| 387 | public: | 
|---|
| 388 | DEFINE_SIZE_ARRAY (14, values); | 
|---|
| 389 | }; | 
|---|
| 390 |  | 
|---|
| 391 | struct CmapSubtableLongGroup | 
|---|
| 392 | { | 
|---|
| 393 | friend struct CmapSubtableFormat12; | 
|---|
| 394 | friend struct CmapSubtableFormat13; | 
|---|
| 395 | template<typename U> | 
|---|
| 396 | friend struct CmapSubtableLongSegmented; | 
|---|
| 397 | friend struct cmap; | 
|---|
| 398 |  | 
|---|
| 399 | int cmp (hb_codepoint_t codepoint) const | 
|---|
| 400 | { | 
|---|
| 401 | if (codepoint < startCharCode) return -1; | 
|---|
| 402 | if (codepoint > endCharCode)   return +1; | 
|---|
| 403 | return 0; | 
|---|
| 404 | } | 
|---|
| 405 |  | 
|---|
| 406 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 407 | { | 
|---|
| 408 | TRACE_SANITIZE (this); | 
|---|
| 409 | return_trace (c->check_struct (this)); | 
|---|
| 410 | } | 
|---|
| 411 |  | 
|---|
| 412 | private: | 
|---|
| 413 | HBUINT32              startCharCode;  /* First character code in this group. */ | 
|---|
| 414 | HBUINT32              endCharCode;    /* Last character code in this group. */ | 
|---|
| 415 | HBUINT32              glyphID;        /* Glyph index; interpretation depends on | 
|---|
| 416 | * subtable format. */ | 
|---|
| 417 | public: | 
|---|
| 418 | DEFINE_SIZE_STATIC (12); | 
|---|
| 419 | }; | 
|---|
| 420 | DECLARE_NULL_NAMESPACE_BYTES (OT, CmapSubtableLongGroup); | 
|---|
| 421 |  | 
|---|
| 422 | template <typename UINT> | 
|---|
| 423 | struct CmapSubtableTrimmed | 
|---|
| 424 | { | 
|---|
| 425 | bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const | 
|---|
| 426 | { | 
|---|
| 427 | /* Rely on our implicit array bound-checking. */ | 
|---|
| 428 | hb_codepoint_t gid = glyphIdArray[codepoint - startCharCode]; | 
|---|
| 429 | if (!gid) | 
|---|
| 430 | return false; | 
|---|
| 431 | *glyph = gid; | 
|---|
| 432 | return true; | 
|---|
| 433 | } | 
|---|
| 434 | void collect_unicodes (hb_set_t *out) const | 
|---|
| 435 | { | 
|---|
| 436 | hb_codepoint_t start = startCharCode; | 
|---|
| 437 | unsigned int count = glyphIdArray.len; | 
|---|
| 438 | for (unsigned int i = 0; i < count; i++) | 
|---|
| 439 | if (glyphIdArray[i]) | 
|---|
| 440 | out->add (start + i); | 
|---|
| 441 | } | 
|---|
| 442 |  | 
|---|
| 443 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 444 | { | 
|---|
| 445 | TRACE_SANITIZE (this); | 
|---|
| 446 | return_trace (c->check_struct (this) && glyphIdArray.sanitize (c)); | 
|---|
| 447 | } | 
|---|
| 448 |  | 
|---|
| 449 | protected: | 
|---|
| 450 | UINT          formatReserved; /* Subtable format and (maybe) padding. */ | 
|---|
| 451 | UINT          length;         /* Byte length of this subtable. */ | 
|---|
| 452 | UINT          language;       /* Ignore. */ | 
|---|
| 453 | UINT          startCharCode;  /* First character code covered. */ | 
|---|
| 454 | ArrayOf<GlyphID, UINT> | 
|---|
| 455 | glyphIdArray;   /* Array of glyph index values for character | 
|---|
| 456 | * codes in the range. */ | 
|---|
| 457 | public: | 
|---|
| 458 | DEFINE_SIZE_ARRAY (5 * sizeof (UINT), glyphIdArray); | 
|---|
| 459 | }; | 
|---|
| 460 |  | 
|---|
| 461 | struct CmapSubtableFormat6  : CmapSubtableTrimmed<HBUINT16> {}; | 
|---|
| 462 | struct CmapSubtableFormat10 : CmapSubtableTrimmed<HBUINT32 > {}; | 
|---|
| 463 |  | 
|---|
| 464 | template <typename T> | 
|---|
| 465 | struct CmapSubtableLongSegmented | 
|---|
| 466 | { | 
|---|
| 467 | friend struct cmap; | 
|---|
| 468 |  | 
|---|
| 469 | bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const | 
|---|
| 470 | { | 
|---|
| 471 | hb_codepoint_t gid = T::group_get_glyph (groups.bsearch (codepoint), codepoint); | 
|---|
| 472 | if (!gid) | 
|---|
| 473 | return false; | 
|---|
| 474 | *glyph = gid; | 
|---|
| 475 | return true; | 
|---|
| 476 | } | 
|---|
| 477 |  | 
|---|
| 478 | void collect_unicodes (hb_set_t *out) const | 
|---|
| 479 | { | 
|---|
| 480 | for (unsigned int i = 0; i < this->groups.len; i++) { | 
|---|
| 481 | out->add_range (this->groups[i].startCharCode, | 
|---|
| 482 | MIN ((hb_codepoint_t) this->groups[i].endCharCode, | 
|---|
| 483 | (hb_codepoint_t) HB_UNICODE_MAX)); | 
|---|
| 484 | } | 
|---|
| 485 | } | 
|---|
| 486 |  | 
|---|
| 487 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 488 | { | 
|---|
| 489 | TRACE_SANITIZE (this); | 
|---|
| 490 | return_trace (c->check_struct (this) && groups.sanitize (c)); | 
|---|
| 491 | } | 
|---|
| 492 |  | 
|---|
| 493 | bool serialize (hb_serialize_context_t *c, | 
|---|
| 494 | const hb_vector_t<CmapSubtableLongGroup> &group_data) | 
|---|
| 495 | { | 
|---|
| 496 | TRACE_SERIALIZE (this); | 
|---|
| 497 | if (unlikely (!c->extend_min (*this))) return_trace (false); | 
|---|
| 498 | if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false); | 
|---|
| 499 | return true; | 
|---|
| 500 | } | 
|---|
| 501 |  | 
|---|
| 502 | protected: | 
|---|
| 503 | HBUINT16      format;         /* Subtable format; set to 12. */ | 
|---|
| 504 | HBUINT16      reserved;       /* Reserved; set to 0. */ | 
|---|
| 505 | HBUINT32      length;         /* Byte length of this subtable. */ | 
|---|
| 506 | HBUINT32      language;       /* Ignore. */ | 
|---|
| 507 | SortedArrayOf<CmapSubtableLongGroup, HBUINT32> | 
|---|
| 508 | groups;         /* Groupings. */ | 
|---|
| 509 | public: | 
|---|
| 510 | DEFINE_SIZE_ARRAY (16, groups); | 
|---|
| 511 | }; | 
|---|
| 512 |  | 
|---|
| 513 | struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12> | 
|---|
| 514 | { | 
|---|
| 515 | static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, | 
|---|
| 516 | hb_codepoint_t u) | 
|---|
| 517 | { return likely (group.startCharCode <= group.endCharCode) ? | 
|---|
| 518 | group.glyphID + (u - group.startCharCode) : 0; } | 
|---|
| 519 |  | 
|---|
| 520 |  | 
|---|
| 521 | bool serialize (hb_serialize_context_t *c, | 
|---|
| 522 | const hb_vector_t<CmapSubtableLongGroup> &groups) | 
|---|
| 523 | { | 
|---|
| 524 | if (unlikely (!c->extend_min (*this))) return false; | 
|---|
| 525 |  | 
|---|
| 526 | this->format.set (12); | 
|---|
| 527 | this->reserved.set (0); | 
|---|
| 528 | this->length.set (get_sub_table_size (groups)); | 
|---|
| 529 |  | 
|---|
| 530 | return CmapSubtableLongSegmented<CmapSubtableFormat12>::serialize (c, groups); | 
|---|
| 531 | } | 
|---|
| 532 |  | 
|---|
| 533 | static size_t get_sub_table_size (const hb_vector_t<CmapSubtableLongGroup> &groups) | 
|---|
| 534 | { | 
|---|
| 535 | return 16 + 12 * groups.length; | 
|---|
| 536 | } | 
|---|
| 537 |  | 
|---|
| 538 | static bool create_sub_table_plan (const hb_subset_plan_t *plan, | 
|---|
| 539 | hb_vector_t<CmapSubtableLongGroup> *groups) | 
|---|
| 540 | { | 
|---|
| 541 | CmapSubtableLongGroup *group = nullptr; | 
|---|
| 542 |  | 
|---|
| 543 | hb_codepoint_t cp = HB_SET_VALUE_INVALID; | 
|---|
| 544 | while (plan->unicodes->next (&cp)) { | 
|---|
| 545 | hb_codepoint_t new_gid; | 
|---|
| 546 | if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) | 
|---|
| 547 | { | 
|---|
| 548 | DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); | 
|---|
| 549 | return false; | 
|---|
| 550 | } | 
|---|
| 551 |  | 
|---|
| 552 | if (!group || !_is_gid_consecutive (group, cp, new_gid)) | 
|---|
| 553 | { | 
|---|
| 554 | group = groups->push (); | 
|---|
| 555 | group->startCharCode.set (cp); | 
|---|
| 556 | group->endCharCode.set (cp); | 
|---|
| 557 | group->glyphID.set (new_gid); | 
|---|
| 558 | } | 
|---|
| 559 | else group->endCharCode.set (cp); | 
|---|
| 560 | } | 
|---|
| 561 |  | 
|---|
| 562 | DEBUG_MSG(SUBSET, nullptr, "cmap"); | 
|---|
| 563 | for (unsigned int i = 0; i < groups->length; i++) { | 
|---|
| 564 | CmapSubtableLongGroup& group = (*groups)[i]; | 
|---|
| 565 | DEBUG_MSG(SUBSET, nullptr, "  %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode)); | 
|---|
| 566 | } | 
|---|
| 567 |  | 
|---|
| 568 | return true; | 
|---|
| 569 | } | 
|---|
| 570 |  | 
|---|
| 571 | private: | 
|---|
| 572 | static bool _is_gid_consecutive (CmapSubtableLongGroup *group, | 
|---|
| 573 | hb_codepoint_t cp, | 
|---|
| 574 | hb_codepoint_t new_gid) | 
|---|
| 575 | { | 
|---|
| 576 | return (cp - 1 == group->endCharCode) && | 
|---|
| 577 | new_gid == group->glyphID + (cp - group->startCharCode); | 
|---|
| 578 | } | 
|---|
| 579 |  | 
|---|
| 580 | }; | 
|---|
| 581 |  | 
|---|
| 582 | struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13> | 
|---|
| 583 | { | 
|---|
| 584 | static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group, | 
|---|
| 585 | hb_codepoint_t u HB_UNUSED) | 
|---|
| 586 | { return group.glyphID; } | 
|---|
| 587 | }; | 
|---|
| 588 |  | 
|---|
| 589 | typedef enum | 
|---|
| 590 | { | 
|---|
| 591 | GLYPH_VARIANT_NOT_FOUND = 0, | 
|---|
| 592 | GLYPH_VARIANT_FOUND = 1, | 
|---|
| 593 | GLYPH_VARIANT_USE_DEFAULT = 2 | 
|---|
| 594 | } glyph_variant_t; | 
|---|
| 595 |  | 
|---|
| 596 | struct UnicodeValueRange | 
|---|
| 597 | { | 
|---|
| 598 | int cmp (const hb_codepoint_t &codepoint) const | 
|---|
| 599 | { | 
|---|
| 600 | if (codepoint < startUnicodeValue) return -1; | 
|---|
| 601 | if (codepoint > startUnicodeValue + additionalCount) return +1; | 
|---|
| 602 | return 0; | 
|---|
| 603 | } | 
|---|
| 604 |  | 
|---|
| 605 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 606 | { | 
|---|
| 607 | TRACE_SANITIZE (this); | 
|---|
| 608 | return_trace (c->check_struct (this)); | 
|---|
| 609 | } | 
|---|
| 610 |  | 
|---|
| 611 | HBUINT24      startUnicodeValue;      /* First value in this range. */ | 
|---|
| 612 | HBUINT8       additionalCount;        /* Number of additional values in this | 
|---|
| 613 | * range. */ | 
|---|
| 614 | public: | 
|---|
| 615 | DEFINE_SIZE_STATIC (4); | 
|---|
| 616 | }; | 
|---|
| 617 |  | 
|---|
| 618 | struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32> | 
|---|
| 619 | { | 
|---|
| 620 | void collect_unicodes (hb_set_t *out) const | 
|---|
| 621 | { | 
|---|
| 622 | unsigned int count = len; | 
|---|
| 623 | for (unsigned int i = 0; i < count; i++) | 
|---|
| 624 | { | 
|---|
| 625 | hb_codepoint_t first = arrayZ[i].startUnicodeValue; | 
|---|
| 626 | hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount), | 
|---|
| 627 | (hb_codepoint_t) HB_UNICODE_MAX); | 
|---|
| 628 | out->add_range (first, last); | 
|---|
| 629 | } | 
|---|
| 630 | } | 
|---|
| 631 |  | 
|---|
| 632 | public: | 
|---|
| 633 | DEFINE_SIZE_ARRAY (4, *this); | 
|---|
| 634 | }; | 
|---|
| 635 |  | 
|---|
| 636 | struct UVSMapping | 
|---|
| 637 | { | 
|---|
| 638 | int cmp (const hb_codepoint_t &codepoint) const | 
|---|
| 639 | { | 
|---|
| 640 | return unicodeValue.cmp (codepoint); | 
|---|
| 641 | } | 
|---|
| 642 |  | 
|---|
| 643 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 644 | { | 
|---|
| 645 | TRACE_SANITIZE (this); | 
|---|
| 646 | return_trace (c->check_struct (this)); | 
|---|
| 647 | } | 
|---|
| 648 |  | 
|---|
| 649 | HBUINT24      unicodeValue;   /* Base Unicode value of the UVS */ | 
|---|
| 650 | GlyphID       glyphID;        /* Glyph ID of the UVS */ | 
|---|
| 651 | public: | 
|---|
| 652 | DEFINE_SIZE_STATIC (5); | 
|---|
| 653 | }; | 
|---|
| 654 |  | 
|---|
| 655 | struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32> | 
|---|
| 656 | { | 
|---|
| 657 | void collect_unicodes (hb_set_t *out) const | 
|---|
| 658 | { | 
|---|
| 659 | unsigned int count = len; | 
|---|
| 660 | for (unsigned int i = 0; i < count; i++) | 
|---|
| 661 | out->add (arrayZ[i].glyphID); | 
|---|
| 662 | } | 
|---|
| 663 |  | 
|---|
| 664 | public: | 
|---|
| 665 | DEFINE_SIZE_ARRAY (4, *this); | 
|---|
| 666 | }; | 
|---|
| 667 |  | 
|---|
| 668 | struct VariationSelectorRecord | 
|---|
| 669 | { | 
|---|
| 670 | glyph_variant_t get_glyph (hb_codepoint_t codepoint, | 
|---|
| 671 | hb_codepoint_t *glyph, | 
|---|
| 672 | const void *base) const | 
|---|
| 673 | { | 
|---|
| 674 | if ((base+defaultUVS).bfind (codepoint)) | 
|---|
| 675 | return GLYPH_VARIANT_USE_DEFAULT; | 
|---|
| 676 | const UVSMapping &nonDefault = (base+nonDefaultUVS).bsearch (codepoint); | 
|---|
| 677 | if (nonDefault.glyphID) | 
|---|
| 678 | { | 
|---|
| 679 | *glyph = nonDefault.glyphID; | 
|---|
| 680 | return GLYPH_VARIANT_FOUND; | 
|---|
| 681 | } | 
|---|
| 682 | return GLYPH_VARIANT_NOT_FOUND; | 
|---|
| 683 | } | 
|---|
| 684 |  | 
|---|
| 685 | void collect_unicodes (hb_set_t *out, const void *base) const | 
|---|
| 686 | { | 
|---|
| 687 | (base+defaultUVS).collect_unicodes (out); | 
|---|
| 688 | (base+nonDefaultUVS).collect_unicodes (out); | 
|---|
| 689 | } | 
|---|
| 690 |  | 
|---|
| 691 | int cmp (const hb_codepoint_t &variation_selector) const | 
|---|
| 692 | { | 
|---|
| 693 | return varSelector.cmp (variation_selector); | 
|---|
| 694 | } | 
|---|
| 695 |  | 
|---|
| 696 | bool sanitize (hb_sanitize_context_t *c, const void *base) const | 
|---|
| 697 | { | 
|---|
| 698 | TRACE_SANITIZE (this); | 
|---|
| 699 | return_trace (c->check_struct (this) && | 
|---|
| 700 | defaultUVS.sanitize (c, base) && | 
|---|
| 701 | nonDefaultUVS.sanitize (c, base)); | 
|---|
| 702 | } | 
|---|
| 703 |  | 
|---|
| 704 | HBUINT24      varSelector;    /* Variation selector. */ | 
|---|
| 705 | LOffsetTo<DefaultUVS> | 
|---|
| 706 | defaultUVS;     /* Offset to Default UVS Table.  May be 0. */ | 
|---|
| 707 | LOffsetTo<NonDefaultUVS> | 
|---|
| 708 | nonDefaultUVS;  /* Offset to Non-Default UVS Table.  May be 0. */ | 
|---|
| 709 | public: | 
|---|
| 710 | DEFINE_SIZE_STATIC (11); | 
|---|
| 711 | }; | 
|---|
| 712 |  | 
|---|
| 713 | struct CmapSubtableFormat14 | 
|---|
| 714 | { | 
|---|
| 715 | glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, | 
|---|
| 716 | hb_codepoint_t variation_selector, | 
|---|
| 717 | hb_codepoint_t *glyph) const | 
|---|
| 718 | { | 
|---|
| 719 | return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); | 
|---|
| 720 | } | 
|---|
| 721 |  | 
|---|
| 722 | void collect_variation_selectors (hb_set_t *out) const | 
|---|
| 723 | { | 
|---|
| 724 | unsigned int count = record.len; | 
|---|
| 725 | for (unsigned int i = 0; i < count; i++) | 
|---|
| 726 | out->add (record.arrayZ[i].varSelector); | 
|---|
| 727 | } | 
|---|
| 728 | void collect_variation_unicodes (hb_codepoint_t variation_selector, | 
|---|
| 729 | hb_set_t *out) const | 
|---|
| 730 | { | 
|---|
| 731 | record.bsearch (variation_selector).collect_unicodes (out, this); | 
|---|
| 732 | } | 
|---|
| 733 |  | 
|---|
| 734 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 735 | { | 
|---|
| 736 | TRACE_SANITIZE (this); | 
|---|
| 737 | return_trace (c->check_struct (this) && | 
|---|
| 738 | record.sanitize (c, this)); | 
|---|
| 739 | } | 
|---|
| 740 |  | 
|---|
| 741 | protected: | 
|---|
| 742 | HBUINT16      format;         /* Format number is set to 14. */ | 
|---|
| 743 | HBUINT32      length;         /* Byte length of this subtable. */ | 
|---|
| 744 | SortedArrayOf<VariationSelectorRecord, HBUINT32> | 
|---|
| 745 | record;         /* Variation selector records; sorted | 
|---|
| 746 | * in increasing order of `varSelector'. */ | 
|---|
| 747 | public: | 
|---|
| 748 | DEFINE_SIZE_ARRAY (10, record); | 
|---|
| 749 | }; | 
|---|
| 750 |  | 
|---|
| 751 | struct CmapSubtable | 
|---|
| 752 | { | 
|---|
| 753 | /* Note: We intentionally do NOT implement subtable formats 2 and 8. */ | 
|---|
| 754 |  | 
|---|
| 755 | bool get_glyph (hb_codepoint_t codepoint, | 
|---|
| 756 | hb_codepoint_t *glyph) const | 
|---|
| 757 | { | 
|---|
| 758 | switch (u.format) { | 
|---|
| 759 | case  0: return u.format0 .get_glyph (codepoint, glyph); | 
|---|
| 760 | case  4: return u.format4 .get_glyph (codepoint, glyph); | 
|---|
| 761 | case  6: return u.format6 .get_glyph (codepoint, glyph); | 
|---|
| 762 | case 10: return u.format10.get_glyph (codepoint, glyph); | 
|---|
| 763 | case 12: return u.format12.get_glyph (codepoint, glyph); | 
|---|
| 764 | case 13: return u.format13.get_glyph (codepoint, glyph); | 
|---|
| 765 | case 14: | 
|---|
| 766 | default: return false; | 
|---|
| 767 | } | 
|---|
| 768 | } | 
|---|
| 769 | void collect_unicodes (hb_set_t *out) const | 
|---|
| 770 | { | 
|---|
| 771 | switch (u.format) { | 
|---|
| 772 | case  0: u.format0 .collect_unicodes (out); return; | 
|---|
| 773 | case  4: u.format4 .collect_unicodes (out); return; | 
|---|
| 774 | case  6: u.format6 .collect_unicodes (out); return; | 
|---|
| 775 | case 10: u.format10.collect_unicodes (out); return; | 
|---|
| 776 | case 12: u.format12.collect_unicodes (out); return; | 
|---|
| 777 | case 13: u.format13.collect_unicodes (out); return; | 
|---|
| 778 | case 14: | 
|---|
| 779 | default: return; | 
|---|
| 780 | } | 
|---|
| 781 | } | 
|---|
| 782 |  | 
|---|
| 783 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 784 | { | 
|---|
| 785 | TRACE_SANITIZE (this); | 
|---|
| 786 | if (!u.format.sanitize (c)) return_trace (false); | 
|---|
| 787 | switch (u.format) { | 
|---|
| 788 | case  0: return_trace (u.format0 .sanitize (c)); | 
|---|
| 789 | case  4: return_trace (u.format4 .sanitize (c)); | 
|---|
| 790 | case  6: return_trace (u.format6 .sanitize (c)); | 
|---|
| 791 | case 10: return_trace (u.format10.sanitize (c)); | 
|---|
| 792 | case 12: return_trace (u.format12.sanitize (c)); | 
|---|
| 793 | case 13: return_trace (u.format13.sanitize (c)); | 
|---|
| 794 | case 14: return_trace (u.format14.sanitize (c)); | 
|---|
| 795 | default:return_trace (true); | 
|---|
| 796 | } | 
|---|
| 797 | } | 
|---|
| 798 |  | 
|---|
| 799 | public: | 
|---|
| 800 | union { | 
|---|
| 801 | HBUINT16              format;         /* Format identifier */ | 
|---|
| 802 | CmapSubtableFormat0   format0; | 
|---|
| 803 | CmapSubtableFormat4   format4; | 
|---|
| 804 | CmapSubtableFormat6   format6; | 
|---|
| 805 | CmapSubtableFormat10  format10; | 
|---|
| 806 | CmapSubtableFormat12  format12; | 
|---|
| 807 | CmapSubtableFormat13  format13; | 
|---|
| 808 | CmapSubtableFormat14  format14; | 
|---|
| 809 | } u; | 
|---|
| 810 | public: | 
|---|
| 811 | DEFINE_SIZE_UNION (2, format); | 
|---|
| 812 | }; | 
|---|
| 813 |  | 
|---|
| 814 |  | 
|---|
| 815 | struct EncodingRecord | 
|---|
| 816 | { | 
|---|
| 817 | int cmp (const EncodingRecord &other) const | 
|---|
| 818 | { | 
|---|
| 819 | int ret; | 
|---|
| 820 | ret = platformID.cmp (other.platformID); | 
|---|
| 821 | if (ret) return ret; | 
|---|
| 822 | ret = encodingID.cmp (other.encodingID); | 
|---|
| 823 | if (ret) return ret; | 
|---|
| 824 | return 0; | 
|---|
| 825 | } | 
|---|
| 826 |  | 
|---|
| 827 | bool sanitize (hb_sanitize_context_t *c, const void *base) const | 
|---|
| 828 | { | 
|---|
| 829 | TRACE_SANITIZE (this); | 
|---|
| 830 | return_trace (c->check_struct (this) && | 
|---|
| 831 | subtable.sanitize (c, base)); | 
|---|
| 832 | } | 
|---|
| 833 |  | 
|---|
| 834 | HBUINT16      platformID;     /* Platform ID. */ | 
|---|
| 835 | HBUINT16      encodingID;     /* Platform-specific encoding ID. */ | 
|---|
| 836 | LOffsetTo<CmapSubtable> | 
|---|
| 837 | subtable;       /* Byte offset from beginning of table to the subtable for this encoding. */ | 
|---|
| 838 | public: | 
|---|
| 839 | DEFINE_SIZE_STATIC (8); | 
|---|
| 840 | }; | 
|---|
| 841 |  | 
|---|
| 842 | struct cmap | 
|---|
| 843 | { | 
|---|
| 844 | static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; | 
|---|
| 845 |  | 
|---|
| 846 | struct subset_plan | 
|---|
| 847 | { | 
|---|
| 848 | size_t final_size () const | 
|---|
| 849 | { | 
|---|
| 850 | return 4 // header | 
|---|
| 851 | +  8 * 3 // 3 EncodingRecord | 
|---|
| 852 | +  CmapSubtableFormat4::get_sub_table_size (this->format4_segments) | 
|---|
| 853 | +  CmapSubtableFormat12::get_sub_table_size (this->format12_groups); | 
|---|
| 854 | } | 
|---|
| 855 |  | 
|---|
| 856 | hb_vector_t<CmapSubtableFormat4::segment_plan> format4_segments; | 
|---|
| 857 | hb_vector_t<CmapSubtableLongGroup> format12_groups; | 
|---|
| 858 | }; | 
|---|
| 859 |  | 
|---|
| 860 | bool _create_plan (const hb_subset_plan_t *plan, | 
|---|
| 861 | subset_plan *cmap_plan) const | 
|---|
| 862 | { | 
|---|
| 863 | if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments))) | 
|---|
| 864 | return false; | 
|---|
| 865 |  | 
|---|
| 866 | return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups); | 
|---|
| 867 | } | 
|---|
| 868 |  | 
|---|
| 869 | bool _subset (const hb_subset_plan_t *plan, | 
|---|
| 870 | const subset_plan &cmap_subset_plan, | 
|---|
| 871 | size_t dest_sz, | 
|---|
| 872 | void *dest) const | 
|---|
| 873 | { | 
|---|
| 874 | hb_serialize_context_t c (dest, dest_sz); | 
|---|
| 875 |  | 
|---|
| 876 | cmap *table = c.start_serialize<cmap> (); | 
|---|
| 877 | if (unlikely (!c.extend_min (*table))) | 
|---|
| 878 | { | 
|---|
| 879 | return false; | 
|---|
| 880 | } | 
|---|
| 881 |  | 
|---|
| 882 | table->version.set (0); | 
|---|
| 883 |  | 
|---|
| 884 | if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3))) | 
|---|
| 885 | return false; | 
|---|
| 886 |  | 
|---|
| 887 | // TODO(grieger): Convert the below to a for loop | 
|---|
| 888 |  | 
|---|
| 889 | // Format 4, Plat 0 Encoding Record | 
|---|
| 890 | EncodingRecord &format4_plat0_rec = table->encodingRecord[0]; | 
|---|
| 891 | format4_plat0_rec.platformID.set (0); // Unicode | 
|---|
| 892 | format4_plat0_rec.encodingID.set (3); | 
|---|
| 893 |  | 
|---|
| 894 | // Format 4, Plat 3 Encoding Record | 
|---|
| 895 | EncodingRecord &format4_plat3_rec = table->encodingRecord[1]; | 
|---|
| 896 | format4_plat3_rec.platformID.set (3); // Windows | 
|---|
| 897 | format4_plat3_rec.encodingID.set (1); // Unicode BMP | 
|---|
| 898 |  | 
|---|
| 899 | // Format 12 Encoding Record | 
|---|
| 900 | EncodingRecord &format12_rec = table->encodingRecord[2]; | 
|---|
| 901 | format12_rec.platformID.set (3); // Windows | 
|---|
| 902 | format12_rec.encodingID.set (10); // Unicode UCS-4 | 
|---|
| 903 |  | 
|---|
| 904 | // Write out format 4 sub table | 
|---|
| 905 | { | 
|---|
| 906 | CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table); | 
|---|
| 907 | format4_plat3_rec.subtable.set (format4_plat0_rec.subtable); | 
|---|
| 908 | subtable.u.format.set (4); | 
|---|
| 909 |  | 
|---|
| 910 | CmapSubtableFormat4 &format4 = subtable.u.format4; | 
|---|
| 911 | if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments))) | 
|---|
| 912 | return false; | 
|---|
| 913 | } | 
|---|
| 914 |  | 
|---|
| 915 | // Write out format 12 sub table. | 
|---|
| 916 | { | 
|---|
| 917 | CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table); | 
|---|
| 918 | subtable.u.format.set (12); | 
|---|
| 919 |  | 
|---|
| 920 | CmapSubtableFormat12 &format12 = subtable.u.format12; | 
|---|
| 921 | if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups))) | 
|---|
| 922 | return false; | 
|---|
| 923 | } | 
|---|
| 924 |  | 
|---|
| 925 | c.end_serialize (); | 
|---|
| 926 |  | 
|---|
| 927 | return true; | 
|---|
| 928 | } | 
|---|
| 929 |  | 
|---|
| 930 | bool subset (hb_subset_plan_t *plan) const | 
|---|
| 931 | { | 
|---|
| 932 | subset_plan cmap_subset_plan; | 
|---|
| 933 |  | 
|---|
| 934 | if (unlikely (!_create_plan (plan, &cmap_subset_plan))) | 
|---|
| 935 | { | 
|---|
| 936 | DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan."); | 
|---|
| 937 | return false; | 
|---|
| 938 | } | 
|---|
| 939 |  | 
|---|
| 940 | // We now know how big our blob needs to be | 
|---|
| 941 | size_t dest_sz = cmap_subset_plan.final_size (); | 
|---|
| 942 | void *dest = malloc (dest_sz); | 
|---|
| 943 | if (unlikely (!dest)) { | 
|---|
| 944 | DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz); | 
|---|
| 945 | return false; | 
|---|
| 946 | } | 
|---|
| 947 |  | 
|---|
| 948 | if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest))) | 
|---|
| 949 | { | 
|---|
| 950 | DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap."); | 
|---|
| 951 | free (dest); | 
|---|
| 952 | return false; | 
|---|
| 953 | } | 
|---|
| 954 |  | 
|---|
| 955 | // all done, write the blob into dest | 
|---|
| 956 | hb_blob_t *cmap_prime = hb_blob_create ((const char *) dest, | 
|---|
| 957 | dest_sz, | 
|---|
| 958 | HB_MEMORY_MODE_READONLY, | 
|---|
| 959 | dest, | 
|---|
| 960 | free); | 
|---|
| 961 | bool result =  plan->add_table (HB_OT_TAG_cmap, cmap_prime); | 
|---|
| 962 | hb_blob_destroy (cmap_prime); | 
|---|
| 963 | return result; | 
|---|
| 964 | } | 
|---|
| 965 |  | 
|---|
| 966 | const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const | 
|---|
| 967 | { | 
|---|
| 968 | if (symbol) *symbol = false; | 
|---|
| 969 |  | 
|---|
| 970 | const CmapSubtable *subtable; | 
|---|
| 971 |  | 
|---|
| 972 | /* 32-bit subtables. */ | 
|---|
| 973 | if ((subtable = this->find_subtable (3, 10))) return subtable; | 
|---|
| 974 | if ((subtable = this->find_subtable (0, 6))) return subtable; | 
|---|
| 975 | if ((subtable = this->find_subtable (0, 4))) return subtable; | 
|---|
| 976 |  | 
|---|
| 977 | /* 16-bit subtables. */ | 
|---|
| 978 | if ((subtable = this->find_subtable (3, 1))) return subtable; | 
|---|
| 979 | if ((subtable = this->find_subtable (0, 3))) return subtable; | 
|---|
| 980 | if ((subtable = this->find_subtable (0, 2))) return subtable; | 
|---|
| 981 | if ((subtable = this->find_subtable (0, 1))) return subtable; | 
|---|
| 982 | if ((subtable = this->find_subtable (0, 0))) return subtable; | 
|---|
| 983 |  | 
|---|
| 984 | /* Symbol subtable. */ | 
|---|
| 985 | if ((subtable = this->find_subtable (3, 0))) | 
|---|
| 986 | { | 
|---|
| 987 | if (symbol) *symbol = true; | 
|---|
| 988 | return subtable; | 
|---|
| 989 | } | 
|---|
| 990 |  | 
|---|
| 991 | /* Meh. */ | 
|---|
| 992 | return &Null (CmapSubtable); | 
|---|
| 993 | } | 
|---|
| 994 |  | 
|---|
| 995 | struct accelerator_t | 
|---|
| 996 | { | 
|---|
| 997 | void init (hb_face_t *face) | 
|---|
| 998 | { | 
|---|
| 999 | this->table = hb_sanitize_context_t ().reference_table<cmap> (face); | 
|---|
| 1000 | bool symbol; | 
|---|
| 1001 | this->subtable = table->find_best_subtable (&symbol); | 
|---|
| 1002 | this->subtable_uvs = &Null (CmapSubtableFormat14); | 
|---|
| 1003 | { | 
|---|
| 1004 | const CmapSubtable *st = table->find_subtable (0, 5); | 
|---|
| 1005 | if (st && st->u.format == 14) | 
|---|
| 1006 | subtable_uvs = &st->u.format14; | 
|---|
| 1007 | } | 
|---|
| 1008 |  | 
|---|
| 1009 | this->get_glyph_data = subtable; | 
|---|
| 1010 | if (unlikely (symbol)) | 
|---|
| 1011 | { | 
|---|
| 1012 | this->get_glyph_funcZ = get_glyph_from_symbol<CmapSubtable>; | 
|---|
| 1013 | } else { | 
|---|
| 1014 | switch (subtable->u.format) { | 
|---|
| 1015 | /* Accelerate format 4 and format 12. */ | 
|---|
| 1016 | default: | 
|---|
| 1017 | this->get_glyph_funcZ = get_glyph_from<CmapSubtable>; | 
|---|
| 1018 | break; | 
|---|
| 1019 | case 12: | 
|---|
| 1020 | this->get_glyph_funcZ = get_glyph_from<CmapSubtableFormat12>; | 
|---|
| 1021 | break; | 
|---|
| 1022 | case  4: | 
|---|
| 1023 | { | 
|---|
| 1024 | this->format4_accel.init (&subtable->u.format4); | 
|---|
| 1025 | this->get_glyph_data = &this->format4_accel; | 
|---|
| 1026 | this->get_glyph_funcZ = this->format4_accel.get_glyph_func; | 
|---|
| 1027 | } | 
|---|
| 1028 | break; | 
|---|
| 1029 | } | 
|---|
| 1030 | } | 
|---|
| 1031 | } | 
|---|
| 1032 |  | 
|---|
| 1033 | void fini () { this->table.destroy (); } | 
|---|
| 1034 |  | 
|---|
| 1035 | bool get_nominal_glyph (hb_codepoint_t  unicode, | 
|---|
| 1036 | hb_codepoint_t *glyph) const | 
|---|
| 1037 | { | 
|---|
| 1038 | if (unlikely (!this->get_glyph_funcZ)) return false; | 
|---|
| 1039 | return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); | 
|---|
| 1040 | } | 
|---|
| 1041 | unsigned int get_nominal_glyphs (unsigned int count, | 
|---|
| 1042 | const hb_codepoint_t *first_unicode, | 
|---|
| 1043 | unsigned int unicode_stride, | 
|---|
| 1044 | hb_codepoint_t *first_glyph, | 
|---|
| 1045 | unsigned int glyph_stride) const | 
|---|
| 1046 | { | 
|---|
| 1047 | if (unlikely (!this->get_glyph_funcZ)) return 0; | 
|---|
| 1048 |  | 
|---|
| 1049 | hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ; | 
|---|
| 1050 | const void *get_glyph_data = this->get_glyph_data; | 
|---|
| 1051 |  | 
|---|
| 1052 | unsigned int done; | 
|---|
| 1053 | for (done = 0; | 
|---|
| 1054 | done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph); | 
|---|
| 1055 | done++) | 
|---|
| 1056 | { | 
|---|
| 1057 | first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride); | 
|---|
| 1058 | first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride); | 
|---|
| 1059 | } | 
|---|
| 1060 | return done; | 
|---|
| 1061 | } | 
|---|
| 1062 |  | 
|---|
| 1063 | bool get_variation_glyph (hb_codepoint_t  unicode, | 
|---|
| 1064 | hb_codepoint_t  variation_selector, | 
|---|
| 1065 | hb_codepoint_t *glyph) const | 
|---|
| 1066 | { | 
|---|
| 1067 | switch (this->subtable_uvs->get_glyph_variant (unicode, | 
|---|
| 1068 | variation_selector, | 
|---|
| 1069 | glyph)) | 
|---|
| 1070 | { | 
|---|
| 1071 | case GLYPH_VARIANT_NOT_FOUND:   return false; | 
|---|
| 1072 | case GLYPH_VARIANT_FOUND:       return true; | 
|---|
| 1073 | case GLYPH_VARIANT_USE_DEFAULT: break; | 
|---|
| 1074 | } | 
|---|
| 1075 |  | 
|---|
| 1076 | return get_nominal_glyph (unicode, glyph); | 
|---|
| 1077 | } | 
|---|
| 1078 |  | 
|---|
| 1079 | void collect_unicodes (hb_set_t *out) const | 
|---|
| 1080 | { | 
|---|
| 1081 | subtable->collect_unicodes (out); | 
|---|
| 1082 | } | 
|---|
| 1083 | void collect_variation_selectors (hb_set_t *out) const | 
|---|
| 1084 | { | 
|---|
| 1085 | subtable_uvs->collect_variation_selectors (out); | 
|---|
| 1086 | } | 
|---|
| 1087 | void collect_variation_unicodes (hb_codepoint_t variation_selector, | 
|---|
| 1088 | hb_set_t *out) const | 
|---|
| 1089 | { | 
|---|
| 1090 | subtable_uvs->collect_variation_unicodes (variation_selector, out); | 
|---|
| 1091 | } | 
|---|
| 1092 |  | 
|---|
| 1093 | protected: | 
|---|
| 1094 | typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, | 
|---|
| 1095 | hb_codepoint_t codepoint, | 
|---|
| 1096 | hb_codepoint_t *glyph); | 
|---|
| 1097 |  | 
|---|
| 1098 | template <typename Type> | 
|---|
| 1099 | static bool get_glyph_from (const void *obj, | 
|---|
| 1100 | hb_codepoint_t codepoint, | 
|---|
| 1101 | hb_codepoint_t *glyph) | 
|---|
| 1102 | { | 
|---|
| 1103 | const Type *typed_obj = (const Type *) obj; | 
|---|
| 1104 | return typed_obj->get_glyph (codepoint, glyph); | 
|---|
| 1105 | } | 
|---|
| 1106 |  | 
|---|
| 1107 | template <typename Type> | 
|---|
| 1108 | static bool get_glyph_from_symbol (const void *obj, | 
|---|
| 1109 | hb_codepoint_t codepoint, | 
|---|
| 1110 | hb_codepoint_t *glyph) | 
|---|
| 1111 | { | 
|---|
| 1112 | const Type *typed_obj = (const Type *) obj; | 
|---|
| 1113 | if (likely (typed_obj->get_glyph (codepoint, glyph))) | 
|---|
| 1114 | return true; | 
|---|
| 1115 |  | 
|---|
| 1116 | if (codepoint <= 0x00FFu) | 
|---|
| 1117 | { | 
|---|
| 1118 | /* For symbol-encoded OpenType fonts, we duplicate the | 
|---|
| 1119 | * U+F000..F0FF range at U+0000..U+00FF.  That's what | 
|---|
| 1120 | * Windows seems to do, and that's hinted about at: | 
|---|
| 1121 | * https://docs.microsoft.com/en-us/typography/opentype/spec/recom | 
|---|
| 1122 | * under "Non-Standard (Symbol) Fonts". */ | 
|---|
| 1123 | return typed_obj->get_glyph (0xF000u + codepoint, glyph); | 
|---|
| 1124 | } | 
|---|
| 1125 |  | 
|---|
| 1126 | return false; | 
|---|
| 1127 | } | 
|---|
| 1128 |  | 
|---|
| 1129 | private: | 
|---|
| 1130 | hb_nonnull_ptr_t<const CmapSubtable> subtable; | 
|---|
| 1131 | hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs; | 
|---|
| 1132 |  | 
|---|
| 1133 | hb_cmap_get_glyph_func_t get_glyph_funcZ; | 
|---|
| 1134 | const void *get_glyph_data; | 
|---|
| 1135 |  | 
|---|
| 1136 | CmapSubtableFormat4::accelerator_t format4_accel; | 
|---|
| 1137 |  | 
|---|
| 1138 | hb_blob_ptr_t<cmap> table; | 
|---|
| 1139 | }; | 
|---|
| 1140 |  | 
|---|
| 1141 | protected: | 
|---|
| 1142 |  | 
|---|
| 1143 | const CmapSubtable *find_subtable (unsigned int platform_id, | 
|---|
| 1144 | unsigned int encoding_id) const | 
|---|
| 1145 | { | 
|---|
| 1146 | EncodingRecord key; | 
|---|
| 1147 | key.platformID.set (platform_id); | 
|---|
| 1148 | key.encodingID.set (encoding_id); | 
|---|
| 1149 |  | 
|---|
| 1150 | const EncodingRecord &result = encodingRecord.bsearch (key); | 
|---|
| 1151 | if (!result.subtable) | 
|---|
| 1152 | return nullptr; | 
|---|
| 1153 |  | 
|---|
| 1154 | return &(this+result.subtable); | 
|---|
| 1155 | } | 
|---|
| 1156 |  | 
|---|
| 1157 | public: | 
|---|
| 1158 |  | 
|---|
| 1159 | bool sanitize (hb_sanitize_context_t *c) const | 
|---|
| 1160 | { | 
|---|
| 1161 | TRACE_SANITIZE (this); | 
|---|
| 1162 | return_trace (c->check_struct (this) && | 
|---|
| 1163 | likely (version == 0) && | 
|---|
| 1164 | encodingRecord.sanitize (c, this)); | 
|---|
| 1165 | } | 
|---|
| 1166 |  | 
|---|
| 1167 | protected: | 
|---|
| 1168 | HBUINT16              version;        /* Table version number (0). */ | 
|---|
| 1169 | SortedArrayOf<EncodingRecord> | 
|---|
| 1170 | encodingRecord; /* Encoding tables. */ | 
|---|
| 1171 | public: | 
|---|
| 1172 | DEFINE_SIZE_ARRAY (4, encodingRecord); | 
|---|
| 1173 | }; | 
|---|
| 1174 |  | 
|---|
| 1175 | struct cmap_accelerator_t : cmap::accelerator_t {}; | 
|---|
| 1176 |  | 
|---|
| 1177 | } /* namespace OT */ | 
|---|
| 1178 |  | 
|---|
| 1179 |  | 
|---|
| 1180 | #endif /* HB_OT_CMAP_TABLE_HH */ | 
|---|
| 1181 |  | 
|---|