1*2d1272b8SAndroid Build Coastguard Worker /* 2*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2007,2008,2009 Red Hat, Inc. 3*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2012 Google, Inc. 4*2d1272b8SAndroid Build Coastguard Worker * 5*2d1272b8SAndroid Build Coastguard Worker * This is part of HarfBuzz, a text shaping library. 6*2d1272b8SAndroid Build Coastguard Worker * 7*2d1272b8SAndroid Build Coastguard Worker * Permission is hereby granted, without written agreement and without 8*2d1272b8SAndroid Build Coastguard Worker * license or royalty fees, to use, copy, modify, and distribute this 9*2d1272b8SAndroid Build Coastguard Worker * software and its documentation for any purpose, provided that the 10*2d1272b8SAndroid Build Coastguard Worker * above copyright notice and the following two paragraphs appear in 11*2d1272b8SAndroid Build Coastguard Worker * all copies of this software. 12*2d1272b8SAndroid Build Coastguard Worker * 13*2d1272b8SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14*2d1272b8SAndroid Build Coastguard Worker * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15*2d1272b8SAndroid Build Coastguard Worker * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16*2d1272b8SAndroid Build Coastguard Worker * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17*2d1272b8SAndroid Build Coastguard Worker * DAMAGE. 18*2d1272b8SAndroid Build Coastguard Worker * 19*2d1272b8SAndroid Build Coastguard Worker * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20*2d1272b8SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21*2d1272b8SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22*2d1272b8SAndroid Build Coastguard Worker * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23*2d1272b8SAndroid Build Coastguard Worker * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24*2d1272b8SAndroid Build Coastguard Worker * 25*2d1272b8SAndroid Build Coastguard Worker * Red Hat Author(s): Behdad Esfahbod 26*2d1272b8SAndroid Build Coastguard Worker * Google Author(s): Behdad Esfahbod 27*2d1272b8SAndroid Build Coastguard Worker */ 28*2d1272b8SAndroid Build Coastguard Worker 29*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_OPEN_FILE_HH 30*2d1272b8SAndroid Build Coastguard Worker #define HB_OPEN_FILE_HH 31*2d1272b8SAndroid Build Coastguard Worker 32*2d1272b8SAndroid Build Coastguard Worker #include "hb-open-type.hh" 33*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-head-table.hh" 34*2d1272b8SAndroid Build Coastguard Worker 35*2d1272b8SAndroid Build Coastguard Worker 36*2d1272b8SAndroid Build Coastguard Worker namespace OT { 37*2d1272b8SAndroid Build Coastguard Worker 38*2d1272b8SAndroid Build Coastguard Worker /* 39*2d1272b8SAndroid Build Coastguard Worker * 40*2d1272b8SAndroid Build Coastguard Worker * The OpenType Font File 41*2d1272b8SAndroid Build Coastguard Worker * 42*2d1272b8SAndroid Build Coastguard Worker */ 43*2d1272b8SAndroid Build Coastguard Worker 44*2d1272b8SAndroid Build Coastguard Worker 45*2d1272b8SAndroid Build Coastguard Worker /* 46*2d1272b8SAndroid Build Coastguard Worker * Organization of an OpenType Font 47*2d1272b8SAndroid Build Coastguard Worker */ 48*2d1272b8SAndroid Build Coastguard Worker 49*2d1272b8SAndroid Build Coastguard Worker struct OpenTypeFontFile; 50*2d1272b8SAndroid Build Coastguard Worker struct OpenTypeOffsetTable; 51*2d1272b8SAndroid Build Coastguard Worker struct TTCHeader; 52*2d1272b8SAndroid Build Coastguard Worker 53*2d1272b8SAndroid Build Coastguard Worker 54*2d1272b8SAndroid Build Coastguard Worker typedef struct TableRecord 55*2d1272b8SAndroid Build Coastguard Worker { cmpOT::TableRecord56*2d1272b8SAndroid Build Coastguard Worker int cmp (Tag t) const { return -t.cmp (tag); } 57*2d1272b8SAndroid Build Coastguard Worker cmpOT::TableRecord58*2d1272b8SAndroid Build Coastguard Worker HB_INTERNAL static int cmp (const void *pa, const void *pb) 59*2d1272b8SAndroid Build Coastguard Worker { 60*2d1272b8SAndroid Build Coastguard Worker const TableRecord *a = (const TableRecord *) pa; 61*2d1272b8SAndroid Build Coastguard Worker const TableRecord *b = (const TableRecord *) pb; 62*2d1272b8SAndroid Build Coastguard Worker return b->cmp (a->tag); 63*2d1272b8SAndroid Build Coastguard Worker } 64*2d1272b8SAndroid Build Coastguard Worker sanitizeOT::TableRecord65*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 66*2d1272b8SAndroid Build Coastguard Worker { 67*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 68*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this)); 69*2d1272b8SAndroid Build Coastguard Worker } 70*2d1272b8SAndroid Build Coastguard Worker 71*2d1272b8SAndroid Build Coastguard Worker Tag tag; /* 4-byte identifier. */ 72*2d1272b8SAndroid Build Coastguard Worker CheckSum checkSum; /* CheckSum for this table. */ 73*2d1272b8SAndroid Build Coastguard Worker Offset32 offset; /* Offset from beginning of TrueType font 74*2d1272b8SAndroid Build Coastguard Worker * file. */ 75*2d1272b8SAndroid Build Coastguard Worker HBUINT32 length; /* Length of this table. */ 76*2d1272b8SAndroid Build Coastguard Worker public: 77*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (16); 78*2d1272b8SAndroid Build Coastguard Worker } OpenTypeTable; 79*2d1272b8SAndroid Build Coastguard Worker 80*2d1272b8SAndroid Build Coastguard Worker typedef struct OpenTypeOffsetTable 81*2d1272b8SAndroid Build Coastguard Worker { 82*2d1272b8SAndroid Build Coastguard Worker friend struct OpenTypeFontFile; 83*2d1272b8SAndroid Build Coastguard Worker get_table_countOT::OpenTypeOffsetTable84*2d1272b8SAndroid Build Coastguard Worker unsigned int get_table_count () const { return tables.len; } get_tableOT::OpenTypeOffsetTable85*2d1272b8SAndroid Build Coastguard Worker const TableRecord& get_table (unsigned int i) const 86*2d1272b8SAndroid Build Coastguard Worker { return tables[i]; } get_table_tagsOT::OpenTypeOffsetTable87*2d1272b8SAndroid Build Coastguard Worker unsigned int get_table_tags (unsigned int start_offset, 88*2d1272b8SAndroid Build Coastguard Worker unsigned int *table_count, /* IN/OUT */ 89*2d1272b8SAndroid Build Coastguard Worker hb_tag_t *table_tags /* OUT */) const 90*2d1272b8SAndroid Build Coastguard Worker { 91*2d1272b8SAndroid Build Coastguard Worker if (table_count) 92*2d1272b8SAndroid Build Coastguard Worker { 93*2d1272b8SAndroid Build Coastguard Worker + tables.as_array ().sub_array (start_offset, table_count) 94*2d1272b8SAndroid Build Coastguard Worker | hb_map (&TableRecord::tag) 95*2d1272b8SAndroid Build Coastguard Worker | hb_sink (hb_array (table_tags, *table_count)) 96*2d1272b8SAndroid Build Coastguard Worker ; 97*2d1272b8SAndroid Build Coastguard Worker } 98*2d1272b8SAndroid Build Coastguard Worker return tables.len; 99*2d1272b8SAndroid Build Coastguard Worker } find_table_indexOT::OpenTypeOffsetTable100*2d1272b8SAndroid Build Coastguard Worker bool find_table_index (hb_tag_t tag, unsigned int *table_index) const 101*2d1272b8SAndroid Build Coastguard Worker { 102*2d1272b8SAndroid Build Coastguard Worker Tag t; 103*2d1272b8SAndroid Build Coastguard Worker t = tag; 104*2d1272b8SAndroid Build Coastguard Worker /* Use lfind for small fonts; there are fonts that have unsorted table entries; 105*2d1272b8SAndroid Build Coastguard Worker * those tend to work in other tools, so tolerate them. 106*2d1272b8SAndroid Build Coastguard Worker * https://github.com/harfbuzz/harfbuzz/issues/3065 */ 107*2d1272b8SAndroid Build Coastguard Worker if (tables.len < 16) 108*2d1272b8SAndroid Build Coastguard Worker return tables.lfind (t, table_index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); 109*2d1272b8SAndroid Build Coastguard Worker else 110*2d1272b8SAndroid Build Coastguard Worker return tables.bfind (t, table_index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); 111*2d1272b8SAndroid Build Coastguard Worker } get_table_by_tagOT::OpenTypeOffsetTable112*2d1272b8SAndroid Build Coastguard Worker const TableRecord& get_table_by_tag (hb_tag_t tag) const 113*2d1272b8SAndroid Build Coastguard Worker { 114*2d1272b8SAndroid Build Coastguard Worker unsigned int table_index; 115*2d1272b8SAndroid Build Coastguard Worker find_table_index (tag, &table_index); 116*2d1272b8SAndroid Build Coastguard Worker return get_table (table_index); 117*2d1272b8SAndroid Build Coastguard Worker } 118*2d1272b8SAndroid Build Coastguard Worker 119*2d1272b8SAndroid Build Coastguard Worker public: 120*2d1272b8SAndroid Build Coastguard Worker 121*2d1272b8SAndroid Build Coastguard Worker template <typename Iterator, 122*2d1272b8SAndroid Build Coastguard Worker hb_requires ((hb_is_source_of<Iterator, hb_pair_t<hb_tag_t, hb_blob_t *>>::value))> serializeOT::OpenTypeOffsetTable123*2d1272b8SAndroid Build Coastguard Worker bool serialize (hb_serialize_context_t *c, 124*2d1272b8SAndroid Build Coastguard Worker hb_tag_t sfnt_tag, 125*2d1272b8SAndroid Build Coastguard Worker Iterator it) 126*2d1272b8SAndroid Build Coastguard Worker { 127*2d1272b8SAndroid Build Coastguard Worker TRACE_SERIALIZE (this); 128*2d1272b8SAndroid Build Coastguard Worker /* Alloc 12 for the OTHeader. */ 129*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->extend_min (this))) return_trace (false); 130*2d1272b8SAndroid Build Coastguard Worker /* Write sfntVersion (bytes 0..3). */ 131*2d1272b8SAndroid Build Coastguard Worker sfnt_version = sfnt_tag; 132*2d1272b8SAndroid Build Coastguard Worker /* Take space for numTables, searchRange, entrySelector, RangeShift 133*2d1272b8SAndroid Build Coastguard Worker * and the TableRecords themselves. */ 134*2d1272b8SAndroid Build Coastguard Worker unsigned num_items = hb_len (it); 135*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!tables.serialize (c, num_items))) return_trace (false); 136*2d1272b8SAndroid Build Coastguard Worker 137*2d1272b8SAndroid Build Coastguard Worker const char *dir_end = (const char *) c->head; 138*2d1272b8SAndroid Build Coastguard Worker HBUINT32 *checksum_adjustment = nullptr; 139*2d1272b8SAndroid Build Coastguard Worker 140*2d1272b8SAndroid Build Coastguard Worker /* Write OffsetTables, alloc for and write actual table blobs. */ 141*2d1272b8SAndroid Build Coastguard Worker unsigned i = 0; 142*2d1272b8SAndroid Build Coastguard Worker for (hb_pair_t<hb_tag_t, hb_blob_t*> entry : it) 143*2d1272b8SAndroid Build Coastguard Worker { 144*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *blob = entry.second; 145*2d1272b8SAndroid Build Coastguard Worker unsigned len = blob->length; 146*2d1272b8SAndroid Build Coastguard Worker 147*2d1272b8SAndroid Build Coastguard Worker /* Allocate room for the table and copy it. */ 148*2d1272b8SAndroid Build Coastguard Worker char *start = (char *) c->allocate_size<void> (len, false); 149*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!start)) return false; 150*2d1272b8SAndroid Build Coastguard Worker 151*2d1272b8SAndroid Build Coastguard Worker TableRecord &rec = tables.arrayZ[i]; 152*2d1272b8SAndroid Build Coastguard Worker rec.tag = entry.first; 153*2d1272b8SAndroid Build Coastguard Worker rec.length = len; 154*2d1272b8SAndroid Build Coastguard Worker rec.offset = 0; 155*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->check_assign (rec.offset, 156*2d1272b8SAndroid Build Coastguard Worker (unsigned) ((char *) start - (char *) this), 157*2d1272b8SAndroid Build Coastguard Worker HB_SERIALIZE_ERROR_OFFSET_OVERFLOW))) 158*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 159*2d1272b8SAndroid Build Coastguard Worker 160*2d1272b8SAndroid Build Coastguard Worker if (likely (len)) 161*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (start, blob->data, len); 162*2d1272b8SAndroid Build Coastguard Worker 163*2d1272b8SAndroid Build Coastguard Worker /* 4-byte alignment. */ 164*2d1272b8SAndroid Build Coastguard Worker c->align (4); 165*2d1272b8SAndroid Build Coastguard Worker const char *end = (const char *) c->head; 166*2d1272b8SAndroid Build Coastguard Worker 167*2d1272b8SAndroid Build Coastguard Worker if (entry.first == HB_OT_TAG_head && 168*2d1272b8SAndroid Build Coastguard Worker (unsigned) (end - start) >= head::static_size) 169*2d1272b8SAndroid Build Coastguard Worker { 170*2d1272b8SAndroid Build Coastguard Worker head *h = (head *) start; 171*2d1272b8SAndroid Build Coastguard Worker checksum_adjustment = &h->checkSumAdjustment; 172*2d1272b8SAndroid Build Coastguard Worker *checksum_adjustment = 0; 173*2d1272b8SAndroid Build Coastguard Worker } 174*2d1272b8SAndroid Build Coastguard Worker 175*2d1272b8SAndroid Build Coastguard Worker rec.checkSum.set_for_data (start, end - start); 176*2d1272b8SAndroid Build Coastguard Worker i++; 177*2d1272b8SAndroid Build Coastguard Worker } 178*2d1272b8SAndroid Build Coastguard Worker 179*2d1272b8SAndroid Build Coastguard Worker tables.qsort (); 180*2d1272b8SAndroid Build Coastguard Worker 181*2d1272b8SAndroid Build Coastguard Worker if (checksum_adjustment) 182*2d1272b8SAndroid Build Coastguard Worker { 183*2d1272b8SAndroid Build Coastguard Worker CheckSum checksum; 184*2d1272b8SAndroid Build Coastguard Worker 185*2d1272b8SAndroid Build Coastguard Worker /* The following line is a slower version of the following block. */ 186*2d1272b8SAndroid Build Coastguard Worker //checksum.set_for_data (this, (const char *) c->head - (const char *) this); 187*2d1272b8SAndroid Build Coastguard Worker checksum.set_for_data (this, dir_end - (const char *) this); 188*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < num_items; i++) 189*2d1272b8SAndroid Build Coastguard Worker { 190*2d1272b8SAndroid Build Coastguard Worker TableRecord &rec = tables.arrayZ[i]; 191*2d1272b8SAndroid Build Coastguard Worker checksum = checksum + rec.checkSum; 192*2d1272b8SAndroid Build Coastguard Worker } 193*2d1272b8SAndroid Build Coastguard Worker 194*2d1272b8SAndroid Build Coastguard Worker *checksum_adjustment = 0xB1B0AFBAu - checksum; 195*2d1272b8SAndroid Build Coastguard Worker } 196*2d1272b8SAndroid Build Coastguard Worker 197*2d1272b8SAndroid Build Coastguard Worker return_trace (true); 198*2d1272b8SAndroid Build Coastguard Worker } 199*2d1272b8SAndroid Build Coastguard Worker sanitizeOT::OpenTypeOffsetTable200*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 201*2d1272b8SAndroid Build Coastguard Worker { 202*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 203*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && tables.sanitize (c)); 204*2d1272b8SAndroid Build Coastguard Worker } 205*2d1272b8SAndroid Build Coastguard Worker 206*2d1272b8SAndroid Build Coastguard Worker protected: 207*2d1272b8SAndroid Build Coastguard Worker Tag sfnt_version; /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */ 208*2d1272b8SAndroid Build Coastguard Worker BinSearchArrayOf<TableRecord> 209*2d1272b8SAndroid Build Coastguard Worker tables; 210*2d1272b8SAndroid Build Coastguard Worker public: 211*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_ARRAY (12, tables); 212*2d1272b8SAndroid Build Coastguard Worker } OpenTypeFontFace; 213*2d1272b8SAndroid Build Coastguard Worker 214*2d1272b8SAndroid Build Coastguard Worker 215*2d1272b8SAndroid Build Coastguard Worker /* 216*2d1272b8SAndroid Build Coastguard Worker * TrueType Collections 217*2d1272b8SAndroid Build Coastguard Worker */ 218*2d1272b8SAndroid Build Coastguard Worker 219*2d1272b8SAndroid Build Coastguard Worker struct TTCHeaderVersion1 220*2d1272b8SAndroid Build Coastguard Worker { 221*2d1272b8SAndroid Build Coastguard Worker friend struct TTCHeader; 222*2d1272b8SAndroid Build Coastguard Worker get_face_countOT::TTCHeaderVersion1223*2d1272b8SAndroid Build Coastguard Worker unsigned int get_face_count () const { return table.len; } get_faceOT::TTCHeaderVersion1224*2d1272b8SAndroid Build Coastguard Worker const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; } 225*2d1272b8SAndroid Build Coastguard Worker sanitizeOT::TTCHeaderVersion1226*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 227*2d1272b8SAndroid Build Coastguard Worker { 228*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 229*2d1272b8SAndroid Build Coastguard Worker return_trace (table.sanitize (c, this)); 230*2d1272b8SAndroid Build Coastguard Worker } 231*2d1272b8SAndroid Build Coastguard Worker 232*2d1272b8SAndroid Build Coastguard Worker protected: 233*2d1272b8SAndroid Build Coastguard Worker Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ 234*2d1272b8SAndroid Build Coastguard Worker FixedVersion<>version; /* Version of the TTC Header (1.0), 235*2d1272b8SAndroid Build Coastguard Worker * 0x00010000u */ 236*2d1272b8SAndroid Build Coastguard Worker Array32Of<Offset32To<OpenTypeOffsetTable>> 237*2d1272b8SAndroid Build Coastguard Worker table; /* Array of offsets to the OffsetTable for each font 238*2d1272b8SAndroid Build Coastguard Worker * from the beginning of the file */ 239*2d1272b8SAndroid Build Coastguard Worker public: 240*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_ARRAY (12, table); 241*2d1272b8SAndroid Build Coastguard Worker }; 242*2d1272b8SAndroid Build Coastguard Worker 243*2d1272b8SAndroid Build Coastguard Worker struct TTCHeader 244*2d1272b8SAndroid Build Coastguard Worker { 245*2d1272b8SAndroid Build Coastguard Worker friend struct OpenTypeFontFile; 246*2d1272b8SAndroid Build Coastguard Worker 247*2d1272b8SAndroid Build Coastguard Worker private: 248*2d1272b8SAndroid Build Coastguard Worker get_face_countOT::TTCHeader249*2d1272b8SAndroid Build Coastguard Worker unsigned int get_face_count () const 250*2d1272b8SAndroid Build Coastguard Worker { 251*2d1272b8SAndroid Build Coastguard Worker switch (u.header.version.major) { 252*2d1272b8SAndroid Build Coastguard Worker case 2: /* version 2 is compatible with version 1 */ 253*2d1272b8SAndroid Build Coastguard Worker case 1: hb_barrier (); return u.version1.get_face_count (); 254*2d1272b8SAndroid Build Coastguard Worker default:return 0; 255*2d1272b8SAndroid Build Coastguard Worker } 256*2d1272b8SAndroid Build Coastguard Worker } get_faceOT::TTCHeader257*2d1272b8SAndroid Build Coastguard Worker const OpenTypeFontFace& get_face (unsigned int i) const 258*2d1272b8SAndroid Build Coastguard Worker { 259*2d1272b8SAndroid Build Coastguard Worker switch (u.header.version.major) { 260*2d1272b8SAndroid Build Coastguard Worker case 2: /* version 2 is compatible with version 1 */ 261*2d1272b8SAndroid Build Coastguard Worker case 1: hb_barrier (); return u.version1.get_face (i); 262*2d1272b8SAndroid Build Coastguard Worker default:return Null (OpenTypeFontFace); 263*2d1272b8SAndroid Build Coastguard Worker } 264*2d1272b8SAndroid Build Coastguard Worker } 265*2d1272b8SAndroid Build Coastguard Worker sanitizeOT::TTCHeader266*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 267*2d1272b8SAndroid Build Coastguard Worker { 268*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 269*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!u.header.version.sanitize (c))) return_trace (false); 270*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 271*2d1272b8SAndroid Build Coastguard Worker switch (u.header.version.major) { 272*2d1272b8SAndroid Build Coastguard Worker case 2: /* version 2 is compatible with version 1 */ 273*2d1272b8SAndroid Build Coastguard Worker case 1: hb_barrier (); return_trace (u.version1.sanitize (c)); 274*2d1272b8SAndroid Build Coastguard Worker default:return_trace (true); 275*2d1272b8SAndroid Build Coastguard Worker } 276*2d1272b8SAndroid Build Coastguard Worker } 277*2d1272b8SAndroid Build Coastguard Worker 278*2d1272b8SAndroid Build Coastguard Worker protected: 279*2d1272b8SAndroid Build Coastguard Worker union { 280*2d1272b8SAndroid Build Coastguard Worker struct { 281*2d1272b8SAndroid Build Coastguard Worker Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ 282*2d1272b8SAndroid Build Coastguard Worker FixedVersion<>version; /* Version of the TTC Header (1.0 or 2.0), 283*2d1272b8SAndroid Build Coastguard Worker * 0x00010000u or 0x00020000u */ 284*2d1272b8SAndroid Build Coastguard Worker } header; 285*2d1272b8SAndroid Build Coastguard Worker TTCHeaderVersion1 version1; 286*2d1272b8SAndroid Build Coastguard Worker } u; 287*2d1272b8SAndroid Build Coastguard Worker }; 288*2d1272b8SAndroid Build Coastguard Worker 289*2d1272b8SAndroid Build Coastguard Worker /* 290*2d1272b8SAndroid Build Coastguard Worker * Mac Resource Fork 291*2d1272b8SAndroid Build Coastguard Worker * 292*2d1272b8SAndroid Build Coastguard Worker * http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html 293*2d1272b8SAndroid Build Coastguard Worker */ 294*2d1272b8SAndroid Build Coastguard Worker 295*2d1272b8SAndroid Build Coastguard Worker struct ResourceRecord 296*2d1272b8SAndroid Build Coastguard Worker { get_faceOT::ResourceRecord297*2d1272b8SAndroid Build Coastguard Worker const OpenTypeFontFace & get_face (const void *data_base) const 298*2d1272b8SAndroid Build Coastguard Worker { return * reinterpret_cast<const OpenTypeFontFace *> ((data_base+offset).arrayZ); } 299*2d1272b8SAndroid Build Coastguard Worker sanitizeOT::ResourceRecord300*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, 301*2d1272b8SAndroid Build Coastguard Worker const void *data_base) const 302*2d1272b8SAndroid Build Coastguard Worker { 303*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 304*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && 305*2d1272b8SAndroid Build Coastguard Worker offset.sanitize (c, data_base) && 306*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 307*2d1272b8SAndroid Build Coastguard Worker get_face (data_base).sanitize (c)); 308*2d1272b8SAndroid Build Coastguard Worker } 309*2d1272b8SAndroid Build Coastguard Worker 310*2d1272b8SAndroid Build Coastguard Worker protected: 311*2d1272b8SAndroid Build Coastguard Worker HBUINT16 id; /* Resource ID. */ 312*2d1272b8SAndroid Build Coastguard Worker HBINT16 nameOffset; /* Offset from beginning of resource name list 313*2d1272b8SAndroid Build Coastguard Worker * to resource name, -1 means there is none. */ 314*2d1272b8SAndroid Build Coastguard Worker HBUINT8 attrs; /* Resource attributes */ 315*2d1272b8SAndroid Build Coastguard Worker NNOffset24To<Array32Of<HBUINT8>> 316*2d1272b8SAndroid Build Coastguard Worker offset; /* Offset from beginning of data block to 317*2d1272b8SAndroid Build Coastguard Worker * data for this resource */ 318*2d1272b8SAndroid Build Coastguard Worker HBUINT32 reserved; /* Reserved for handle to resource */ 319*2d1272b8SAndroid Build Coastguard Worker public: 320*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (12); 321*2d1272b8SAndroid Build Coastguard Worker }; 322*2d1272b8SAndroid Build Coastguard Worker 323*2d1272b8SAndroid Build Coastguard Worker #define HB_TAG_sfnt HB_TAG ('s','f','n','t') 324*2d1272b8SAndroid Build Coastguard Worker 325*2d1272b8SAndroid Build Coastguard Worker struct ResourceTypeRecord 326*2d1272b8SAndroid Build Coastguard Worker { get_resource_countOT::ResourceTypeRecord327*2d1272b8SAndroid Build Coastguard Worker unsigned int get_resource_count () const 328*2d1272b8SAndroid Build Coastguard Worker { return tag == HB_TAG_sfnt ? resCountM1 + 1 : 0; } 329*2d1272b8SAndroid Build Coastguard Worker is_sfntOT::ResourceTypeRecord330*2d1272b8SAndroid Build Coastguard Worker bool is_sfnt () const { return tag == HB_TAG_sfnt; } 331*2d1272b8SAndroid Build Coastguard Worker get_resource_recordOT::ResourceTypeRecord332*2d1272b8SAndroid Build Coastguard Worker const ResourceRecord& get_resource_record (unsigned int i, 333*2d1272b8SAndroid Build Coastguard Worker const void *type_base) const 334*2d1272b8SAndroid Build Coastguard Worker { return (type_base+resourcesZ).as_array (get_resource_count ())[i]; } 335*2d1272b8SAndroid Build Coastguard Worker sanitizeOT::ResourceTypeRecord336*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, 337*2d1272b8SAndroid Build Coastguard Worker const void *type_base, 338*2d1272b8SAndroid Build Coastguard Worker const void *data_base) const 339*2d1272b8SAndroid Build Coastguard Worker { 340*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 341*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && 342*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 343*2d1272b8SAndroid Build Coastguard Worker resourcesZ.sanitize (c, type_base, 344*2d1272b8SAndroid Build Coastguard Worker get_resource_count (), 345*2d1272b8SAndroid Build Coastguard Worker data_base)); 346*2d1272b8SAndroid Build Coastguard Worker } 347*2d1272b8SAndroid Build Coastguard Worker 348*2d1272b8SAndroid Build Coastguard Worker protected: 349*2d1272b8SAndroid Build Coastguard Worker Tag tag; /* Resource type. */ 350*2d1272b8SAndroid Build Coastguard Worker HBUINT16 resCountM1; /* Number of resources minus 1. */ 351*2d1272b8SAndroid Build Coastguard Worker NNOffset16To<UnsizedArrayOf<ResourceRecord>> 352*2d1272b8SAndroid Build Coastguard Worker resourcesZ; /* Offset from beginning of resource type list 353*2d1272b8SAndroid Build Coastguard Worker * to reference item list for this type. */ 354*2d1272b8SAndroid Build Coastguard Worker public: 355*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (8); 356*2d1272b8SAndroid Build Coastguard Worker }; 357*2d1272b8SAndroid Build Coastguard Worker 358*2d1272b8SAndroid Build Coastguard Worker struct ResourceMap 359*2d1272b8SAndroid Build Coastguard Worker { get_face_countOT::ResourceMap360*2d1272b8SAndroid Build Coastguard Worker unsigned int get_face_count () const 361*2d1272b8SAndroid Build Coastguard Worker { 362*2d1272b8SAndroid Build Coastguard Worker unsigned int count = get_type_count (); 363*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 364*2d1272b8SAndroid Build Coastguard Worker { 365*2d1272b8SAndroid Build Coastguard Worker const ResourceTypeRecord& type = get_type_record (i); 366*2d1272b8SAndroid Build Coastguard Worker if (type.is_sfnt ()) 367*2d1272b8SAndroid Build Coastguard Worker return type.get_resource_count (); 368*2d1272b8SAndroid Build Coastguard Worker } 369*2d1272b8SAndroid Build Coastguard Worker return 0; 370*2d1272b8SAndroid Build Coastguard Worker } 371*2d1272b8SAndroid Build Coastguard Worker get_faceOT::ResourceMap372*2d1272b8SAndroid Build Coastguard Worker const OpenTypeFontFace& get_face (unsigned int idx, 373*2d1272b8SAndroid Build Coastguard Worker const void *data_base) const 374*2d1272b8SAndroid Build Coastguard Worker { 375*2d1272b8SAndroid Build Coastguard Worker unsigned int count = get_type_count (); 376*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 377*2d1272b8SAndroid Build Coastguard Worker { 378*2d1272b8SAndroid Build Coastguard Worker const ResourceTypeRecord& type = get_type_record (i); 379*2d1272b8SAndroid Build Coastguard Worker /* The check for idx < count is here because ResourceRecord is NOT null-safe. 380*2d1272b8SAndroid Build Coastguard Worker * Because an offset of 0 there does NOT mean null. */ 381*2d1272b8SAndroid Build Coastguard Worker if (type.is_sfnt () && idx < type.get_resource_count ()) 382*2d1272b8SAndroid Build Coastguard Worker return type.get_resource_record (idx, &(this+typeList)).get_face (data_base); 383*2d1272b8SAndroid Build Coastguard Worker } 384*2d1272b8SAndroid Build Coastguard Worker return Null (OpenTypeFontFace); 385*2d1272b8SAndroid Build Coastguard Worker } 386*2d1272b8SAndroid Build Coastguard Worker sanitizeOT::ResourceMap387*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *data_base) const 388*2d1272b8SAndroid Build Coastguard Worker { 389*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 390*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && 391*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 392*2d1272b8SAndroid Build Coastguard Worker typeList.sanitize (c, this, 393*2d1272b8SAndroid Build Coastguard Worker &(this+typeList), 394*2d1272b8SAndroid Build Coastguard Worker data_base)); 395*2d1272b8SAndroid Build Coastguard Worker } 396*2d1272b8SAndroid Build Coastguard Worker 397*2d1272b8SAndroid Build Coastguard Worker private: get_type_countOT::ResourceMap398*2d1272b8SAndroid Build Coastguard Worker unsigned int get_type_count () const { return (this+typeList).lenM1 + 1; } 399*2d1272b8SAndroid Build Coastguard Worker get_type_recordOT::ResourceMap400*2d1272b8SAndroid Build Coastguard Worker const ResourceTypeRecord& get_type_record (unsigned int i) const 401*2d1272b8SAndroid Build Coastguard Worker { return (this+typeList)[i]; } 402*2d1272b8SAndroid Build Coastguard Worker 403*2d1272b8SAndroid Build Coastguard Worker protected: 404*2d1272b8SAndroid Build Coastguard Worker HBUINT8 reserved0[16]; /* Reserved for copy of resource header */ 405*2d1272b8SAndroid Build Coastguard Worker HBUINT32 reserved1; /* Reserved for handle to next resource map */ 406*2d1272b8SAndroid Build Coastguard Worker HBUINT16 resreved2; /* Reserved for file reference number */ 407*2d1272b8SAndroid Build Coastguard Worker HBUINT16 attrs; /* Resource fork attribute */ 408*2d1272b8SAndroid Build Coastguard Worker NNOffset16To<ArrayOfM1<ResourceTypeRecord>> 409*2d1272b8SAndroid Build Coastguard Worker typeList; /* Offset from beginning of map to 410*2d1272b8SAndroid Build Coastguard Worker * resource type list */ 411*2d1272b8SAndroid Build Coastguard Worker Offset16 nameList; /* Offset from beginning of map to 412*2d1272b8SAndroid Build Coastguard Worker * resource name list */ 413*2d1272b8SAndroid Build Coastguard Worker public: 414*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (28); 415*2d1272b8SAndroid Build Coastguard Worker }; 416*2d1272b8SAndroid Build Coastguard Worker 417*2d1272b8SAndroid Build Coastguard Worker struct ResourceForkHeader 418*2d1272b8SAndroid Build Coastguard Worker { get_face_countOT::ResourceForkHeader419*2d1272b8SAndroid Build Coastguard Worker unsigned int get_face_count () const 420*2d1272b8SAndroid Build Coastguard Worker { return (this+map).get_face_count (); } 421*2d1272b8SAndroid Build Coastguard Worker get_faceOT::ResourceForkHeader422*2d1272b8SAndroid Build Coastguard Worker const OpenTypeFontFace& get_face (unsigned int idx, 423*2d1272b8SAndroid Build Coastguard Worker unsigned int *base_offset = nullptr) const 424*2d1272b8SAndroid Build Coastguard Worker { 425*2d1272b8SAndroid Build Coastguard Worker const OpenTypeFontFace &face = (this+map).get_face (idx, &(this+data)); 426*2d1272b8SAndroid Build Coastguard Worker if (base_offset) 427*2d1272b8SAndroid Build Coastguard Worker *base_offset = (const char *) &face - (const char *) this; 428*2d1272b8SAndroid Build Coastguard Worker return face; 429*2d1272b8SAndroid Build Coastguard Worker } 430*2d1272b8SAndroid Build Coastguard Worker sanitizeOT::ResourceForkHeader431*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 432*2d1272b8SAndroid Build Coastguard Worker { 433*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 434*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && 435*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 436*2d1272b8SAndroid Build Coastguard Worker data.sanitize (c, this, dataLen) && 437*2d1272b8SAndroid Build Coastguard Worker map.sanitize (c, this, &(this+data))); 438*2d1272b8SAndroid Build Coastguard Worker } 439*2d1272b8SAndroid Build Coastguard Worker 440*2d1272b8SAndroid Build Coastguard Worker protected: 441*2d1272b8SAndroid Build Coastguard Worker NNOffset32To<UnsizedArrayOf<HBUINT8>> 442*2d1272b8SAndroid Build Coastguard Worker data; /* Offset from beginning of resource fork 443*2d1272b8SAndroid Build Coastguard Worker * to resource data */ 444*2d1272b8SAndroid Build Coastguard Worker NNOffset32To<ResourceMap > 445*2d1272b8SAndroid Build Coastguard Worker map; /* Offset from beginning of resource fork 446*2d1272b8SAndroid Build Coastguard Worker * to resource map */ 447*2d1272b8SAndroid Build Coastguard Worker HBUINT32 dataLen; /* Length of resource data */ 448*2d1272b8SAndroid Build Coastguard Worker HBUINT32 mapLen; /* Length of resource map */ 449*2d1272b8SAndroid Build Coastguard Worker public: 450*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (16); 451*2d1272b8SAndroid Build Coastguard Worker }; 452*2d1272b8SAndroid Build Coastguard Worker 453*2d1272b8SAndroid Build Coastguard Worker /* 454*2d1272b8SAndroid Build Coastguard Worker * OpenType Font File 455*2d1272b8SAndroid Build Coastguard Worker */ 456*2d1272b8SAndroid Build Coastguard Worker 457*2d1272b8SAndroid Build Coastguard Worker struct OpenTypeFontFile 458*2d1272b8SAndroid Build Coastguard Worker { 459*2d1272b8SAndroid Build Coastguard Worker enum { 460*2d1272b8SAndroid Build Coastguard Worker CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */ 461*2d1272b8SAndroid Build Coastguard Worker TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */ 462*2d1272b8SAndroid Build Coastguard Worker TTCTag = HB_TAG ('t','t','c','f'), /* TrueType Collection */ 463*2d1272b8SAndroid Build Coastguard Worker DFontTag = HB_TAG ( 0 , 0 , 1 , 0 ), /* DFont Mac Resource Fork */ 464*2d1272b8SAndroid Build Coastguard Worker TrueTag = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */ 465*2d1272b8SAndroid Build Coastguard Worker Typ1Tag = HB_TAG ('t','y','p','1') /* Obsolete Apple Type1 font in SFNT container */ 466*2d1272b8SAndroid Build Coastguard Worker }; 467*2d1272b8SAndroid Build Coastguard Worker get_tagOT::OpenTypeFontFile468*2d1272b8SAndroid Build Coastguard Worker hb_tag_t get_tag () const { return u.tag; } 469*2d1272b8SAndroid Build Coastguard Worker get_face_countOT::OpenTypeFontFile470*2d1272b8SAndroid Build Coastguard Worker unsigned int get_face_count () const 471*2d1272b8SAndroid Build Coastguard Worker { 472*2d1272b8SAndroid Build Coastguard Worker switch (u.tag) { 473*2d1272b8SAndroid Build Coastguard Worker case CFFTag: /* All the non-collection tags */ 474*2d1272b8SAndroid Build Coastguard Worker case TrueTag: 475*2d1272b8SAndroid Build Coastguard Worker case Typ1Tag: 476*2d1272b8SAndroid Build Coastguard Worker case TrueTypeTag: return 1; 477*2d1272b8SAndroid Build Coastguard Worker case TTCTag: return u.ttcHeader.get_face_count (); 478*2d1272b8SAndroid Build Coastguard Worker case DFontTag: return u.rfHeader.get_face_count (); 479*2d1272b8SAndroid Build Coastguard Worker default: return 0; 480*2d1272b8SAndroid Build Coastguard Worker } 481*2d1272b8SAndroid Build Coastguard Worker } get_faceOT::OpenTypeFontFile482*2d1272b8SAndroid Build Coastguard Worker const OpenTypeFontFace& get_face (unsigned int i, unsigned int *base_offset = nullptr) const 483*2d1272b8SAndroid Build Coastguard Worker { 484*2d1272b8SAndroid Build Coastguard Worker if (base_offset) 485*2d1272b8SAndroid Build Coastguard Worker *base_offset = 0; 486*2d1272b8SAndroid Build Coastguard Worker switch (u.tag) { 487*2d1272b8SAndroid Build Coastguard Worker /* Note: for non-collection SFNT data we ignore index. This is because 488*2d1272b8SAndroid Build Coastguard Worker * Apple dfont container is a container of SFNT's. So each SFNT is a 489*2d1272b8SAndroid Build Coastguard Worker * non-TTC, but the index is more than zero. */ 490*2d1272b8SAndroid Build Coastguard Worker case CFFTag: /* All the non-collection tags */ 491*2d1272b8SAndroid Build Coastguard Worker case TrueTag: 492*2d1272b8SAndroid Build Coastguard Worker case Typ1Tag: 493*2d1272b8SAndroid Build Coastguard Worker case TrueTypeTag: return u.fontFace; 494*2d1272b8SAndroid Build Coastguard Worker case TTCTag: return u.ttcHeader.get_face (i); 495*2d1272b8SAndroid Build Coastguard Worker case DFontTag: return u.rfHeader.get_face (i, base_offset); 496*2d1272b8SAndroid Build Coastguard Worker default: return Null (OpenTypeFontFace); 497*2d1272b8SAndroid Build Coastguard Worker } 498*2d1272b8SAndroid Build Coastguard Worker } 499*2d1272b8SAndroid Build Coastguard Worker 500*2d1272b8SAndroid Build Coastguard Worker template <typename Iterator, 501*2d1272b8SAndroid Build Coastguard Worker hb_requires ((hb_is_source_of<Iterator, hb_pair_t<hb_tag_t, hb_blob_t *>>::value))> serialize_singleOT::OpenTypeFontFile502*2d1272b8SAndroid Build Coastguard Worker bool serialize_single (hb_serialize_context_t *c, 503*2d1272b8SAndroid Build Coastguard Worker hb_tag_t sfnt_tag, 504*2d1272b8SAndroid Build Coastguard Worker Iterator items) 505*2d1272b8SAndroid Build Coastguard Worker { 506*2d1272b8SAndroid Build Coastguard Worker TRACE_SERIALIZE (this); 507*2d1272b8SAndroid Build Coastguard Worker assert (sfnt_tag != TTCTag); 508*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->extend_min (this))) return_trace (false); 509*2d1272b8SAndroid Build Coastguard Worker return_trace (u.fontFace.serialize (c, sfnt_tag, items)); 510*2d1272b8SAndroid Build Coastguard Worker } 511*2d1272b8SAndroid Build Coastguard Worker sanitizeOT::OpenTypeFontFile512*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 513*2d1272b8SAndroid Build Coastguard Worker { 514*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 515*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!u.tag.sanitize (c))) return_trace (false); 516*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 517*2d1272b8SAndroid Build Coastguard Worker switch (u.tag) { 518*2d1272b8SAndroid Build Coastguard Worker case CFFTag: /* All the non-collection tags */ 519*2d1272b8SAndroid Build Coastguard Worker case TrueTag: 520*2d1272b8SAndroid Build Coastguard Worker case Typ1Tag: 521*2d1272b8SAndroid Build Coastguard Worker case TrueTypeTag: return_trace (u.fontFace.sanitize (c)); 522*2d1272b8SAndroid Build Coastguard Worker case TTCTag: return_trace (u.ttcHeader.sanitize (c)); 523*2d1272b8SAndroid Build Coastguard Worker case DFontTag: return_trace (u.rfHeader.sanitize (c)); 524*2d1272b8SAndroid Build Coastguard Worker default: return_trace (true); 525*2d1272b8SAndroid Build Coastguard Worker } 526*2d1272b8SAndroid Build Coastguard Worker } 527*2d1272b8SAndroid Build Coastguard Worker 528*2d1272b8SAndroid Build Coastguard Worker protected: 529*2d1272b8SAndroid Build Coastguard Worker union { 530*2d1272b8SAndroid Build Coastguard Worker Tag tag; /* 4-byte identifier. */ 531*2d1272b8SAndroid Build Coastguard Worker OpenTypeFontFace fontFace; 532*2d1272b8SAndroid Build Coastguard Worker TTCHeader ttcHeader; 533*2d1272b8SAndroid Build Coastguard Worker ResourceForkHeader rfHeader; 534*2d1272b8SAndroid Build Coastguard Worker } u; 535*2d1272b8SAndroid Build Coastguard Worker public: 536*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_UNION (4, tag); 537*2d1272b8SAndroid Build Coastguard Worker }; 538*2d1272b8SAndroid Build Coastguard Worker 539*2d1272b8SAndroid Build Coastguard Worker 540*2d1272b8SAndroid Build Coastguard Worker } /* namespace OT */ 541*2d1272b8SAndroid Build Coastguard Worker 542*2d1272b8SAndroid Build Coastguard Worker 543*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_OPEN_FILE_HH */ 544