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 
  34 
  35 namespace OT {
  36 
  37 
  38 /*
  39  *
  40  * The OpenType Font File
  41  *
  42  */
  43 
  44 
  45 /*
  46  * Organization of an OpenType Font
  47  */
  48 
  49 struct OpenTypeFontFile;
  50 struct OffsetTable;
  51 struct TTCHeader;
  52 
  53 
  54 typedef struct TableRecord
  55 {
  56   int cmp (Tag t) const
  57   { return t.cmp (tag); }
  58 
  59   inline bool sanitize (hb_sanitize_context_t *c) const
  60   {
  61     TRACE_SANITIZE (this);
  62     return_trace (c->check_struct (this));
  63   }
  64 
  65   Tag           tag;            /* 4-byte identifier. */
  66   CheckSum      checkSum;       /* CheckSum for this table. */
  67   ULONG         offset;         /* Offset from beginning of TrueType font
  68                                  * file. */
  69   ULONG         length;         /* Length of this table. */
  70   public:
  71   DEFINE_SIZE_STATIC (16);
  72 } OpenTypeTable;
  73 
  74 typedef struct OffsetTable
  75 {
  76   friend struct OpenTypeFontFile;
  77 
  78   inline unsigned int get_table_count (void) const
  79   { return tables.len; }
  80   inline const TableRecord& get_table (unsigned int i) const
  81   {
  82     return tables[i];
  83   }
  84   inline unsigned int get_table_tags (unsigned int start_offset,
  85                                       unsigned int *table_count, /* IN/OUT */
  86                                       hb_tag_t     *table_tags /* OUT */) const
  87   {
  88     if (table_count)
  89     {
  90       if (start_offset >= tables.len)
  91         *table_count = 0;
  92       else
  93         *table_count = MIN<unsigned int> (*table_count, tables.len - start_offset);
  94 
  95       const TableRecord *sub_tables = tables.array + start_offset;
  96       unsigned int count = *table_count;
  97       for (unsigned int i = 0; i < count; i++)
  98         table_tags[i] = sub_tables[i].tag;
  99     }
 100     return tables.len;
 101   }
 102   inline bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
 103   {
 104     Tag t;
 105     t.set (tag);
 106     /* Linear-search for small tables to work around fonts with unsorted
 107      * table list. */
 108     int i = tables.len < 64 ? tables.lsearch (t) : tables.bsearch (t);
 109     if (table_index)
 110       *table_index = i == -1 ? Index::NOT_FOUND_INDEX : (unsigned int) i;
 111     return i != -1;
 112   }
 113   inline const TableRecord& get_table_by_tag (hb_tag_t tag) const
 114   {
 115     unsigned int table_index;
 116     find_table_index (tag, &table_index);
 117     return get_table (table_index);
 118   }
 119 
 120   public:
 121   inline bool sanitize (hb_sanitize_context_t *c) const
 122   {
 123     TRACE_SANITIZE (this);
 124     return_trace (c->check_struct (this) && tables.sanitize (c));
 125   }
 126 
 127   protected:
 128   Tag           sfnt_version;   /* '\0\001\0\00' if TrueType / 'OTTO' if CFF */
 129   BinSearchArrayOf<TableRecord>
 130                 tables;
 131   public:
 132   DEFINE_SIZE_ARRAY (12, tables);
 133 } OpenTypeFontFace;
 134 
 135 
 136 /*
 137  * TrueType Collections
 138  */
 139 
 140 struct TTCHeaderVersion1
 141 {
 142   friend struct TTCHeader;
 143 
 144   inline unsigned int get_face_count (void) const { return table.len; }
 145   inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
 146 
 147   inline bool sanitize (hb_sanitize_context_t *c) const
 148   {
 149     TRACE_SANITIZE (this);
 150     return_trace (table.sanitize (c, this));
 151   }
 152 
 153   protected:
 154   Tag           ttcTag;         /* TrueType Collection ID string: 'ttcf' */
 155   FixedVersion<>version;        /* Version of the TTC Header (1.0),
 156                                  * 0x00010000u */
 157   ArrayOf<LOffsetTo<OffsetTable>, ULONG>
 158                 table;          /* Array of offsets to the OffsetTable for each font
 159                                  * from the beginning of the file */
 160   public:
 161   DEFINE_SIZE_ARRAY (12, table);
 162 };
 163 
 164 struct TTCHeader
 165 {
 166   friend struct OpenTypeFontFile;
 167 
 168   private:
 169 
 170   inline unsigned int get_face_count (void) const
 171   {
 172     switch (u.header.version.major) {
 173     case 2: /* version 2 is compatible with version 1 */
 174     case 1: return u.version1.get_face_count ();
 175     default:return 0;
 176     }
 177   }
 178   inline const OpenTypeFontFace& get_face (unsigned int i) const
 179   {
 180     switch (u.header.version.major) {
 181     case 2: /* version 2 is compatible with version 1 */
 182     case 1: return u.version1.get_face (i);
 183     default:return Null(OpenTypeFontFace);
 184     }
 185   }
 186 
 187   inline bool sanitize (hb_sanitize_context_t *c) const
 188   {
 189     TRACE_SANITIZE (this);
 190     if (unlikely (!u.header.version.sanitize (c))) return_trace (false);
 191     switch (u.header.version.major) {
 192     case 2: /* version 2 is compatible with version 1 */
 193     case 1: return_trace (u.version1.sanitize (c));
 194     default:return_trace (true);
 195     }
 196   }
 197 
 198   protected:
 199   union {
 200   struct {
 201   Tag           ttcTag;         /* TrueType Collection ID string: 'ttcf' */
 202   FixedVersion<>version;        /* Version of the TTC Header (1.0 or 2.0),
 203                                  * 0x00010000u or 0x00020000u */
 204   }                     header;
 205   TTCHeaderVersion1     version1;
 206   } u;
 207 };
 208 
 209 
 210 /*
 211  * OpenType Font File
 212  */
 213 
 214 struct OpenTypeFontFile
 215 {
 216   static const hb_tag_t tableTag        = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */
 217 
 218   static const hb_tag_t CFFTag          = HB_TAG ('O','T','T','O'); /* OpenType with Postscript outlines */
 219   static const hb_tag_t TrueTypeTag     = HB_TAG ( 0 , 1 , 0 , 0 ); /* OpenType with TrueType outlines */
 220   static const hb_tag_t TTCTag          = HB_TAG ('t','t','c','f'); /* TrueType Collection */
 221   static const hb_tag_t TrueTag         = HB_TAG ('t','r','u','e'); /* Obsolete Apple TrueType */
 222   static const hb_tag_t Typ1Tag         = HB_TAG ('t','y','p','1'); /* Obsolete Apple Type1 font in SFNT container */
 223 
 224   inline hb_tag_t get_tag (void) const { return u.tag; }
 225 
 226   inline unsigned int get_face_count (void) const
 227   {
 228     switch (u.tag) {
 229     case CFFTag:        /* All the non-collection tags */
 230     case TrueTag:
 231     case Typ1Tag:
 232     case TrueTypeTag:   return 1;
 233     case TTCTag:        return u.ttcHeader.get_face_count ();
 234     default:            return 0;
 235     }
 236   }
 237   inline const OpenTypeFontFace& get_face (unsigned int i) const
 238   {
 239     switch (u.tag) {
 240     /* Note: for non-collection SFNT data we ignore index.  This is because
 241      * Apple dfont container is a container of SFNT's.  So each SFNT is a
 242      * non-TTC, but the index is more than zero. */
 243     case CFFTag:        /* All the non-collection tags */
 244     case TrueTag:
 245     case Typ1Tag:
 246     case TrueTypeTag:   return u.fontFace;
 247     case TTCTag:        return u.ttcHeader.get_face (i);
 248     default:            return Null(OpenTypeFontFace);
 249     }
 250   }
 251 
 252   inline bool sanitize (hb_sanitize_context_t *c) const
 253   {
 254     TRACE_SANITIZE (this);
 255     if (unlikely (!u.tag.sanitize (c))) return_trace (false);
 256     switch (u.tag) {
 257     case CFFTag:        /* All the non-collection tags */
 258     case TrueTag:
 259     case Typ1Tag:
 260     case TrueTypeTag:   return_trace (u.fontFace.sanitize (c));
 261     case TTCTag:        return_trace (u.ttcHeader.sanitize (c));
 262     default:            return_trace (true);
 263     }
 264   }
 265 
 266   protected:
 267   union {
 268   Tag                   tag;            /* 4-byte identifier. */
 269   OpenTypeFontFace      fontFace;
 270   TTCHeader             ttcHeader;
 271   } u;
 272   public:
 273   DEFINE_SIZE_UNION (4, tag);
 274 };
 275 
 276 
 277 } /* namespace OT */
 278 
 279 
 280 #endif /* HB_OPEN_FILE_PRIVATE_HH */