2965b46263a53bfa90af0d5c028546b81987e2e7
[platform/upstream/harfbuzz.git] / src / hb-open-file-private.hh
1 /*
2  * Copyright © 2007,2008,2009  Red Hat, Inc.
3  * Copyright © 2012  Google, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  *
25  * Red Hat Author(s): Behdad Esfahbod
26  * Google Author(s): Behdad Esfahbod
27  */
28
29 #ifndef HB_OPEN_FILE_PRIVATE_HH
30 #define HB_OPEN_FILE_PRIVATE_HH
31
32 #include "hb-open-type-private.hh"
33 #include "hb-ot-head-table.hh"
34
35
36 namespace OT {
37
38
39 /*
40  *
41  * The OpenType Font File
42  *
43  */
44
45
46 /*
47  * Organization of an OpenType Font
48  */
49
50 struct OpenTypeFontFile;
51 struct OffsetTable;
52 struct TTCHeader;
53
54
55 typedef struct TableRecord
56 {
57   int cmp (Tag t) const
58   { return -t.cmp (tag); }
59
60   static int cmp (const void *pa, const void *pb)
61   {
62     const TableRecord *a = (const TableRecord *) pa;
63     const TableRecord *b = (const TableRecord *) pb;
64     return b->cmp (a->tag);
65   }
66
67   inline bool sanitize (hb_sanitize_context_t *c) const
68   {
69     TRACE_SANITIZE (this);
70     return_trace (c->check_struct (this));
71   }
72
73   Tag           tag;            /* 4-byte identifier. */
74   CheckSum      checkSum;       /* CheckSum for this table. */
75   Offset32      offset;         /* Offset from beginning of TrueType font
76                                  * file. */
77   HBUINT32      length;         /* Length of this table. */
78   public:
79   DEFINE_SIZE_STATIC (16);
80 } OpenTypeTable;
81
82 typedef struct OffsetTable
83 {
84   friend struct OpenTypeFontFile;
85
86   inline unsigned int get_table_count (void) const
87   { return tables.len; }
88   inline const TableRecord& get_table (unsigned int i) const
89   {
90     return tables[i];
91   }
92   inline unsigned int get_table_tags (unsigned int  start_offset,
93                                       unsigned int *table_count, /* IN/OUT */
94                                       hb_tag_t     *table_tags /* OUT */) const
95   {
96     if (table_count)
97     {
98       if (start_offset >= tables.len)
99         *table_count = 0;
100       else
101         *table_count = MIN<unsigned int> (*table_count, tables.len - start_offset);
102
103       const TableRecord *sub_tables = tables.arrayZ + start_offset;
104       unsigned int count = *table_count;
105       for (unsigned int i = 0; i < count; i++)
106         table_tags[i] = sub_tables[i].tag;
107     }
108     return tables.len;
109   }
110   inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
111   {
112     Tag t;
113     t.set (tag);
114     /* Linear-search for small tables to work around fonts with unsorted
115      * table list. */
116     int i = tables.len < 64 ? tables.lsearch (t) : tables.bsearch (t);
117     if (table_index)
118       *table_index = i == -1 ? Index::NOT_FOUND_INDEX : (unsigned int) i;
119     return i != -1;
120   }
121   inline const TableRecord& get_table_by_tag (hb_tag_t tag) const
122   {
123     unsigned int table_index;
124     find_table_index (tag, &table_index);
125     return get_table (table_index);
126   }
127
128   public:
129
130   inline bool serialize (hb_serialize_context_t *c,
131                          hb_tag_t sfnt_tag,
132                          Supplier<hb_tag_t> &tags,
133                          Supplier<hb_blob_t *> &blobs,
134                          unsigned int table_count)
135   {
136     TRACE_SERIALIZE (this);
137     /* Alloc 12 for the OTHeader. */
138     if (unlikely (!c->extend_min (*this))) return_trace (false);
139     /* Write sfntVersion (bytes 0..3). */
140     sfnt_version.set (sfnt_tag);
141     /* Take space for numTables, searchRange, entrySelector, RangeShift
142      * and the TableRecords themselves.  */
143     if (unlikely (!tables.serialize (c, table_count))) return_trace (false);
144
145     const char *dir_end = (const char *) c->head;
146     HBUINT32 *checksum_adjustment = nullptr;
147
148     /* Write OffsetTables, alloc for and write actual table blobs. */
149     for (unsigned int i = 0; i < table_count; i++)
150     {
151       TableRecord &rec = tables.arrayZ[i];
152       hb_blob_t *blob = blobs[i];
153       rec.tag.set (tags[i]);
154       rec.length.set (hb_blob_get_length (blob));
155       rec.offset.serialize (c, this);
156
157       /* Allocate room for the table and copy it. */
158       char *start = (char *) c->allocate_size<void> (rec.length);
159       if (unlikely (!start)) {return false;}
160
161       memcpy (start, hb_blob_get_data (blob, nullptr), rec.length);
162
163       /* 4-byte allignment. */
164       if (rec.length % 4)
165         c->allocate_size<void> (4 - rec.length % 4);
166       const char *end = (const char *) c->head;
167
168       if (tags[i] == HB_OT_TAG_head && end - start >= head::static_size)
169       {
170         head *h = (head *) start;
171         checksum_adjustment = &h->checkSumAdjustment;
172         checksum_adjustment->set (0);
173       }
174
175       rec.checkSum.set_for_data (start, end - start);
176     }
177     tags += table_count;
178     blobs += table_count;
179
180     tables.qsort ();
181
182     if (checksum_adjustment)
183     {
184       CheckSum checksum;
185
186       /* The following line is a slower version of the following block. */
187       //checksum.set_for_data (this, (const char *) c->head - (const char *) this);
188       checksum.set_for_data (this, dir_end - (const char *) this);
189       for (unsigned int i = 0; i < table_count; i++)
190       {
191         TableRecord &rec = tables.arrayZ[i];
192         checksum.set (checksum + rec.checkSum);
193       }
194
195       checksum_adjustment->set (0xB1B0AFBAu - checksum);
196     }
197
198     return_trace (true);
199   }
200
201   inline bool sanitize (hb_sanitize_context_t *c) const
202   {
203     TRACE_SANITIZE (this);
204     return_trace (c->check_struct (this) && tables.sanitize (c));
205   }
206
207   protected:
208   Tag           sfnt_version;   /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
209   BinSearchArrayOf<TableRecord>
210                 tables;
211   public:
212   DEFINE_SIZE_ARRAY (12, tables);
213 } OpenTypeFontFace;
214
215
216 /*
217  * TrueType Collections
218  */
219
220 struct TTCHeaderVersion1
221 {
222   friend struct TTCHeader;
223
224   inline unsigned int get_face_count (void) const { return table.len; }
225   inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
226
227   inline bool sanitize (hb_sanitize_context_t *c) const
228   {
229     TRACE_SANITIZE (this);
230     return_trace (table.sanitize (c, this));
231   }
232
233   protected:
234   Tag           ttcTag;         /* TrueType Collection ID string: 'ttcf' */
235   FixedVersion<>version;        /* Version of the TTC Header (1.0),
236                                  * 0x00010000u */
237   LArrayOf<LOffsetTo<OffsetTable> >
238                 table;          /* Array of offsets to the OffsetTable for each font
239                                  * from the beginning of the file */
240   public:
241   DEFINE_SIZE_ARRAY (12, table);
242 };
243
244 struct TTCHeader
245 {
246   friend struct OpenTypeFontFile;
247
248   private:
249
250   inline unsigned int get_face_count (void) const
251   {
252     switch (u.header.version.major) {
253     case 2: /* version 2 is compatible with version 1 */
254     case 1: return u.version1.get_face_count ();
255     default:return 0;
256     }
257   }
258   inline const OpenTypeFontFace& get_face (unsigned int i) const
259   {
260     switch (u.header.version.major) {
261     case 2: /* version 2 is compatible with version 1 */
262     case 1: return u.version1.get_face (i);
263     default:return Null(OpenTypeFontFace);
264     }
265   }
266
267   inline bool sanitize (hb_sanitize_context_t *c) const
268   {
269     TRACE_SANITIZE (this);
270     if (unlikely (!u.header.version.sanitize (c))) return_trace (false);
271     switch (u.header.version.major) {
272     case 2: /* version 2 is compatible with version 1 */
273     case 1: return_trace (u.version1.sanitize (c));
274     default:return_trace (true);
275     }
276   }
277
278   protected:
279   union {
280   struct {
281   Tag           ttcTag;         /* TrueType Collection ID string: 'ttcf' */
282   FixedVersion<>version;        /* Version of the TTC Header (1.0 or 2.0),
283                                  * 0x00010000u or 0x00020000u */
284   }                     header;
285   TTCHeaderVersion1     version1;
286   } u;
287 };
288
289
290 /*
291  * OpenType Font File
292  */
293
294 struct OpenTypeFontFile
295 {
296   static const hb_tag_t tableTag        = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */
297
298   enum {
299     CFFTag              = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */
300     TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */
301     TTCTag              = HB_TAG ('t','t','c','f'), /* TrueType Collection */
302     TrueTag             = HB_TAG ('t','r','u','e'), /* Obsolete Apple TrueType */
303     Typ1Tag             = HB_TAG ('t','y','p','1')  /* Obsolete Apple Type1 font in SFNT container */
304   };
305
306   inline hb_tag_t get_tag (void) const { return u.tag; }
307
308   inline unsigned int get_face_count (void) const
309   {
310     switch (u.tag) {
311     case CFFTag:        /* All the non-collection tags */
312     case TrueTag:
313     case Typ1Tag:
314     case TrueTypeTag:   return 1;
315     case TTCTag:        return u.ttcHeader.get_face_count ();
316     default:            return 0;
317     }
318   }
319   inline const OpenTypeFontFace& get_face (unsigned int i) const
320   {
321     switch (u.tag) {
322     /* Note: for non-collection SFNT data we ignore index.  This is because
323      * Apple dfont container is a container of SFNT's.  So each SFNT is a
324      * non-TTC, but the index is more than zero. */
325     case CFFTag:        /* All the non-collection tags */
326     case TrueTag:
327     case Typ1Tag:
328     case TrueTypeTag:   return u.fontFace;
329     case TTCTag:        return u.ttcHeader.get_face (i);
330     default:            return Null(OpenTypeFontFace);
331     }
332   }
333
334   inline bool serialize_single (hb_serialize_context_t *c,
335                                 hb_tag_t sfnt_tag,
336                                 Supplier<hb_tag_t> &tags,
337                                 Supplier<hb_blob_t *> &blobs,
338                                 unsigned int table_count)
339   {
340     TRACE_SERIALIZE (this);
341     assert (sfnt_tag != TTCTag);
342     if (unlikely (!c->extend_min (*this))) return_trace (false);
343     return_trace (u.fontFace.serialize (c, sfnt_tag, tags, blobs, table_count));
344   }
345
346   inline bool sanitize (hb_sanitize_context_t *c) const
347   {
348     TRACE_SANITIZE (this);
349     if (unlikely (!u.tag.sanitize (c))) return_trace (false);
350     switch (u.tag) {
351     case CFFTag:        /* All the non-collection tags */
352     case TrueTag:
353     case Typ1Tag:
354     case TrueTypeTag:   return_trace (u.fontFace.sanitize (c));
355     case TTCTag:        return_trace (u.ttcHeader.sanitize (c));
356     default:            return_trace (true);
357     }
358   }
359
360   protected:
361   union {
362   Tag                   tag;            /* 4-byte identifier. */
363   OpenTypeFontFace      fontFace;
364   TTCHeader             ttcHeader;
365   } u;
366   public:
367   DEFINE_SIZE_UNION (4, tag);
368 };
369
370
371 } /* namespace OT */
372
373
374 #endif /* HB_OPEN_FILE_PRIVATE_HH */