1 /*
2  * Copyright 2011 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_
18 #define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_
19 
20 // type.h needs to be included first because of building issues on Windows
21 // Type aliases we delcare are defined in other headers and make the build
22 // fail otherwise.
23 #include "sfntly/port/type.h"
24 #include <vector>
25 #include <map>
26 
27 #include "sfntly/port/refcount.h"
28 #include "sfntly/table/subtable.h"
29 #include "sfntly/table/subtable_container_table.h"
30 
31 namespace sfntly {
32 
33 // CMap subtable formats
34 struct CMapFormat {
35   enum {
36     kFormat0 = 0,
37     kFormat2 = 2,
38     kFormat4 = 4,
39     kFormat6 = 6,
40     kFormat8 = 8,
41     kFormat10 = 10,
42     kFormat12 = 12,
43     kFormat13 = 13,
44     kFormat14 = 14
45   };
46 };
47 
48 // A CMap table
49 class CMapTable : public SubTableContainerTable, public RefCounted<CMapTable> {
50 public:
51   // CMapTable::CMapId
52   struct CMapId {
53     int32_t platform_id;
54     int32_t encoding_id;
55     bool operator==(const CMapId& obj) const {
56       return platform_id == obj.platform_id && encoding_id == obj.encoding_id;
57     }
58   };
59   static CMapId WINDOWS_BMP;
60   static CMapId WINDOWS_UCS4;
61   static CMapId MAC_ROMAN;
62 
63   // CMapTable::CMapIdComparator
64   class CMapIdComparator {
65    public:
66     bool operator()(const CMapId& lhs, const CMapId& rhs) const;
67   };
68 
69   // A filter on cmap
70   // CMapTable::CMapFilter
71   class CMapFilter {
72    public:
73     // Test on whether the cmap is acceptable or not
74     // @param cmap_id the id of the cmap
75     // @return true if the cmap is acceptable; false otherwise
76     virtual bool accept(const CMapId& cmap_id) const = 0;
77     // Make gcc -Wnon-virtual-dtor happy.
~CMapFilter()78     virtual ~CMapFilter() {}
79   };
80 
81   // Filters CMaps by CMapId to implement CMapTable::get()
82   // wanted_id is the CMap we'd like to find.
83   // We compare the current CMap to it either by equality (==) or using a
84   // comparator.
85   // CMapTable::CMapIdFilter
86   class CMapIdFilter : public CMapFilter {
87    public:
88     explicit CMapIdFilter(const CMapId wanted_id);
89     CMapIdFilter(const CMapId wanted_id,
90                  const CMapIdComparator* comparator);
~CMapIdFilter()91     ~CMapIdFilter() {}
92     virtual bool accept(const CMapId& cmap_id) const;
93    private:
94     CMapIdFilter& operator=(const CMapIdFilter& that);
95     const CMapId wanted_id_;
96     const CMapIdComparator *comparator_;
97   };
98 
99   // The abstract base class for all cmaps.
100   //
101   // CMap equality is based on the equality of the (@link {@link CMapId} that
102   // defines the CMap. In the cmap table for a font there can only be one cmap
103   // with a given cmap id (pair of platform and encoding ids) no matter what the
104   // type of the cmap is.
105   //
106   // The cmap offers CharacterIterator to allow iteration over
107   // characters that are mapped by the cmap. This iteration mostly returns the
108   // characters mapped by the cmap. It will return all characters mapped by the
109   // cmap to anything but .notdef <b>but</b> it may return some that are not
110   // mapped or are mapped to .notdef. Various cmap tables provide ranges and
111   // such to describe characters for lookup but without going the full way to
112   // mapping to the glyph id it isn't always possible to tell if a character
113   // will end up with a valid glyph id. So, some of the characters returned from
114   // the Iterator may still end up pointing to the .notdef glyph. However, the
115   // number of such characters should be small in most cases with well designed
116   // cmaps.
117   class Builder;
118   class CMap : public SubTable {
119    public:
120     // CMapTable::CMap::Builder
121     class Builder : public SubTable::Builder {
122      public:
123       virtual ~Builder();
124 
125       CALLER_ATTACH static Builder*
126           GetBuilder(ReadableFontData* data,
127                      int32_t offset,
128                      const CMapId& cmap_id);
129       CALLER_ATTACH static Builder*
130           GetBuilder(int32_t format,
131                      const CMapId& cmap_id);
132 
133       // Note: yes, an object is returned on stack since it's small enough.
cmap_id()134       virtual CMapId cmap_id() { return cmap_id_; }
platform_id()135       virtual int32_t platform_id() { return cmap_id_.platform_id; }
encoding_id()136       virtual int32_t encoding_id() { return cmap_id_.encoding_id; }
format()137       virtual int32_t format() { return format_; }
language()138       virtual int32_t language() { return language_; }
set_language(int32_t language)139       virtual void set_language(int32_t language) { language_ = language; }
140 
141      protected:
142       Builder(ReadableFontData* data,
143               int32_t format,
144               const CMapId& cmap_id);
145       Builder(WritableFontData* data,
146               int32_t format,
147               const CMapId& cmap_id);
148 
149       virtual int32_t SubSerialize(WritableFontData* new_data);
150       virtual bool SubReadyToSerialize();
151       virtual int32_t SubDataSizeToSerialize();
152       virtual void SubDataSet();
153 
154      private:
155       int32_t format_;
156       CMapId cmap_id_;
157       int32_t language_;
158 
159       friend class CMapTable::Builder;
160     };
161     // Abstract CMap character iterator
162     // The fully qualified name is CMapTable::CMap::CharacterIterator
163     class CharacterIterator {
164      public:
~CharacterIterator()165       virtual ~CharacterIterator() {}
166       virtual bool HasNext() = 0;
167       // Returns -1 if there are no more characters to iterate through
168       // and exceptions are turned off
169       virtual int32_t Next() = 0;
170 
171      protected:
172       // Use the CMap::Iterator method below instead of directly requesting
173       // a CharacterIterator.
CharacterIterator()174       CharacterIterator() {}
175     };
176 
177     CMap(ReadableFontData* data, int32_t format, const CMapId& cmap_id);
178     virtual ~CMap();
179 
180     virtual CMap::CharacterIterator* Iterator() = 0;
181 
format()182     virtual int32_t format() { return format_; }
cmap_id()183     virtual CMapId cmap_id() { return cmap_id_; }
platform_id()184     virtual int32_t platform_id() { return cmap_id_.platform_id; }
encoding_id()185     virtual int32_t encoding_id() { return cmap_id_.encoding_id; }
186 
187     // Get the language of the cmap.
188     //
189     // Note on the language field in 'cmap' subtables: The language field must
190     // be set to zero for all cmap subtables whose platform IDs are other than
191     // Macintosh (platform ID 1). For cmap subtables whose platform IDs are
192     // Macintosh, set this field to the Macintosh language ID of the cmap
193     // subtable plus one, or to zero if the cmap subtable is not
194     // language-specific. For example, a Mac OS Turkish cmap subtable must set
195     // this field to 18, since the Macintosh language ID for Turkish is 17. A
196     // Mac OS Roman cmap subtable must set this field to 0, since Mac OS Roman
197     // is not a language-specific encoding.
198     //
199     // @return the language id
200     virtual int32_t Language() = 0;
201 
202     // Gets the glyph id for the character code provided.
203     // The character code provided must be in the encoding used by the cmap
204     // table.
205     virtual int32_t GlyphId(int32_t character) = 0;
206 
207    private:
208     int32_t format_;
209     CMapId cmap_id_;
210   };
211   typedef Ptr<CMap> CMapPtr;
212   typedef Ptr<CMap::Builder> CMapBuilderPtr;
213   typedef std::map<CMapId, CMapBuilderPtr, CMapIdComparator> CMapBuilderMap;
214 
215   // A cmap format 0 sub table
216   class CMapFormat0 : public CMap, public RefCounted<CMapFormat0> {
217    public:
218     // The fully qualified name is CMapTable::CMapFormat0::Builder
219     class Builder : public CMap::Builder,
220                     public RefCounted<Builder> {
221      public:
222       CALLER_ATTACH static Builder* NewInstance(ReadableFontData* data,
223                                                 int32_t offset,
224                                                 const CMapId& cmap_id);
225       CALLER_ATTACH static Builder* NewInstance(WritableFontData* data,
226                                                 int32_t offset,
227                                                 const CMapId& cmap_id);
228       CALLER_ATTACH static Builder* NewInstance(const CMapId& cmap_id);
229       virtual ~Builder();
230 
231      protected:
232       virtual CALLER_ATTACH FontDataTable*
233           SubBuildTable(ReadableFontData* data);
234 
235      private:
236       // When creating a new CMapFormat0 Builder, use NewInstance instead of
237       // the constructors! This avoids a memory leak when slicing the FontData.
238       Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id);
239       Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id);
240       Builder(const CMapId& cmap_id);
241     };
242 
243     // The fully qualified name is CMapTable::CMapFormat0::CharacterIterator
244     class CharacterIterator : public CMap::CharacterIterator {
245      public:
246       virtual ~CharacterIterator();
247       virtual bool HasNext();
248       virtual int32_t Next();
249 
250      private:
251       CharacterIterator(int32_t start, int32_t end);
252       friend class CMapFormat0;
253       int32_t character_, max_character_;
254     };
255 
256     virtual ~CMapFormat0();
257     virtual int32_t Language();
258     virtual int32_t GlyphId(int32_t character);
259     CMap::CharacterIterator* Iterator();
260 
261    private:
262     CMapFormat0(ReadableFontData* data, const CMapId& cmap_id);
263   };
264 
265   // A cmap format 2 sub table
266   // The format 2 cmap is used for multi-byte encodings such as SJIS,
267   // EUC-JP/KR/CN, Big5, etc.
268   class CMapFormat2 : public CMap, public RefCounted<CMapFormat2> {
269    public:
270     // CMapTable::CMapFormat2::Builder
271     class Builder : public CMap::Builder,
272                     public RefCounted<Builder> {
273      public:
274       Builder(ReadableFontData* data,
275               int32_t offset,
276               const CMapId& cmap_id);
277       Builder(WritableFontData* data,
278               int32_t offset,
279               const CMapId& cmap_id);
280       virtual ~Builder();
281 
282      protected:
283       virtual CALLER_ATTACH FontDataTable*
284           SubBuildTable(ReadableFontData* data);
285     };
286     // CMapTable::CMapFormat2::CharacterIterator
287     class CharacterIterator : public CMap::CharacterIterator {
288      public:
289       virtual ~CharacterIterator();
290       virtual bool hasNext();
291       virtual int32_t next();
292 
293      private:
294       CharacterIterator();
295     };
296 
297     virtual int32_t Language();
298     virtual int32_t GlyphId(int32_t character);
299 
300     // Returns how many bytes would be consumed by a lookup of this character
301     // with this cmap. This comes about because the cmap format 2 table is
302     // designed around multi-byte encodings such as SJIS, EUC-JP, Big5, etc.
303     // return the number of bytes consumed from this "character" - either 1 or 2
304     virtual int32_t BytesConsumed(int32_t character);
305 
306     virtual ~CMapFormat2();
307 
308    private:
309     CMapFormat2(ReadableFontData* data, const CMapId& cmap_id);
310 
311     int32_t SubHeaderOffset(int32_t sub_header_index);
312     int32_t FirstCode(int32_t sub_header_index);
313     int32_t EntryCount(int32_t sub_header_index);
314     int32_t IdRangeOffset(int32_t sub_header_index);
315     int32_t IdDelta(int32_t sub_header_index);
316     CMap::CharacterIterator* Iterator();
317   };
318 
319     // CMapTable::CMapFormat4
320   class CMapFormat4 : public CMap,
321                       public RefCounted<CMapFormat4> {
322    public:
323     // CMapTable::CMapFormat4::Builder
324     class Builder : public CMap::Builder,
325                     public RefCounted<Builder> {
326      public:
327         // CMapTable::CMapFormat4::Builder::Segment
328       class Segment : public RefCounted<Segment> {
329        public:
330         Segment();
331         explicit Segment(Segment* other);
332         Segment(int32_t start_count,
333                 int32_t end_count,
334                 int32_t id_delta,
335                 int32_t id_range_offset);
336         ~Segment();
337 
338         // @return the startCount
339         int32_t start_count();
340         // @param startCount the startCount to set
341         void set_start_count(int32_t start_count);
342         // @return the endCount
343         int32_t end_count();
344         // @param endcount the endCount to set
345         void set_end_count(int32_t end_count);
346         // @return the idDelta
347         int32_t id_delta();
348         // @param idDelta the idDelta to set
349         void set_id_delta(int32_t id_delta);
350         // @return the idRangeOffset
351         int32_t id_range_offset();
352         // @param idRangeOffset the idRangeOffset to set
353         void set_id_range_offset(int32_t id_range_offset);
354 
355         static CALLER_ATTACH
356         std::vector<Ptr<Segment> >*
357         DeepCopy(std::vector<Ptr<Segment> >* original);
358 
359        private:
360         int32_t start_count_;
361         int32_t end_count_;
362         int32_t id_delta_;
363         int32_t id_range_offset_;
364       };
365       typedef std::vector<Ptr<Segment> > SegmentList;
366 
367       static CALLER_ATTACH Builder* NewInstance(WritableFontData* data,
368                                                 int32_t offset,
369                                                 const CMapId& cmap_id);
370       static CALLER_ATTACH Builder* NewInstance(ReadableFontData* data,
371                                                 int32_t offset,
372                                                 const CMapId& cmap_id);
373       static CALLER_ATTACH Builder* NewInstance(const CMapId& cmap_id);
374       virtual ~Builder();
375       SegmentList* segments();
376       void set_segments(SegmentList* segments);
377       IntegerList* glyph_id_array();
378       void set_glyph_id_array(IntegerList* glyph_id_array);
379 
380      protected:
381       Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id);
382       Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id);
383       Builder(SegmentList* segments, IntegerList* glyph_id_array,
384               const CMapId& cmap_id);
385       explicit Builder(const CMapId& cmap_id);
386 
387       virtual CALLER_ATTACH FontDataTable* SubBuildTable(
388           ReadableFontData* data);
389       virtual void SubDataSet();
390       virtual int32_t SubDataSizeToSerialize();
391       virtual bool SubReadyToSerialize();
392       virtual int32_t SubSerialize(WritableFontData* new_data);
393 
394      private:
395       void Initialize(ReadableFontData* data);
396 
397       SegmentList segments_;
398       IntegerList glyph_id_array_;
399     };
400 
401     CMap::CharacterIterator* Iterator();
402     // CMapTable::CMapFormat4::CharacterIterator
403     class CharacterIterator : public CMap::CharacterIterator {
404      public:
405       bool HasNext();
406       int32_t Next();
~CharacterIterator()407       virtual ~CharacterIterator() {}
408 
409      private:
410       explicit CharacterIterator(CMapFormat4 *parent);
411       friend CMap::CharacterIterator* CMapFormat4::Iterator();
412 
413       CMapFormat4* parent_;
414       int32_t segment_index_;
415       int32_t first_char_in_segment_;
416       int32_t last_char_in_segment_;
417       int32_t next_char_;
418       bool next_char_set_;
419     };
420 
421     virtual int32_t GlyphId(int32_t character);
422 
423     // Lower level glyph code retrieval that requires processing the Format 4
424     // segments to use.
425     // @param segment the cmap segment
426     // @param startCode the start code for the segment
427     // @param character the character to be looked up
428     // @return the glyph id for the character; CMapTable.NOTDEF if not found
429     int32_t RetrieveGlyphId(int32_t segment,
430                             int32_t start_count,
431                             int32_t character);
432     virtual int32_t Language();
433 
434     // Get the count of the number of segments in this cmap.
435     // @return the number of segments
436     int32_t seg_count();
437     int32_t Length();
438     // Get the start code for a segment.
439     // @param segment the segment in the lookup table
440     // @return the start code for a segment
441     int32_t StartCode(int32_t segment);
442     // Get the end code for a segment.
443     // @param segment the segment in the look up table
444     // @return the end code for the segment
445     int32_t EndCode(int32_t segment);
446     // Get the id delta for a segment
447     // @param segment the segment in the look up table
448     // @return the id delta for the segment
449     int32_t IdDelta(int32_t segment);
450     // Get the id range offset for a segment
451     // @param segment the segment in the look up table
452     // @return the id range offset for the segment
453     int32_t IdRangeOffset(int32_t segment);
454     // Get the location of the id range offset for a segment
455     // @param segment the segment in the look up table
456     // @return the location of the id range offset for the segment
457     int32_t IdRangeOffsetLocation(int32_t segment);
458     // Declared above to allow friending inside CharacterIterator class.
459     // CMap::CharacterIterator* Iterator();
460     virtual ~CMapFormat4();
461 
462    protected:
463     CMapFormat4(ReadableFontData* data, const CMapId& cmap_id);
464 
465    private:
466     static int32_t Language(ReadableFontData* data);
467     static int32_t Length(ReadableFontData* data);
468     static int32_t SegCount(ReadableFontData* data);
469     static int32_t StartCode(ReadableFontData* data,
470                              int32_t seg_count,
471                              int32_t index);
472     static int32_t StartCodeOffset(int32_t seg_count);
473     static int32_t EndCode(ReadableFontData* data,
474                            int32_t seg_count,
475                            int32_t index);
476     static int32_t IdDelta(ReadableFontData* data,
477                            int32_t seg_count,
478                            int32_t index);
479     static int32_t IdDeltaOffset(int32_t seg_count);
480     static int32_t IdRangeOffset(ReadableFontData* data,
481                                  int32_t seg_count,
482                                  int32_t index);
483     static int32_t IdRangeOffsetOffset(int32_t seg_count);
484     static int32_t GlyphIdArrayOffset(int32_t seg_count);
485     // Refactored void to bool to work without exceptions.
486     bool IsValidIndex(int32_t segment);
487     int32_t GlyphIdArray(int32_t index);
488 
489     int32_t seg_count_;
490     int32_t start_code_offset_;
491     int32_t id_delta_offset_;
492     int32_t glyph_id_array_offset_;
493   };
494 
495   // CMapTable::Builder
496   class Builder : public SubTableContainerTable::Builder,
497                   public RefCounted<Builder> {
498    public:
499     // Constructor scope is public because C++ does not allow base class to
500     // instantiate derived class with protected constructors.
501     Builder(Header* header, WritableFontData* data);
502     Builder(Header* header, ReadableFontData* data);
503     virtual ~Builder();
504 
505     virtual int32_t SubSerialize(WritableFontData* new_data);
506     virtual bool SubReadyToSerialize();
507     virtual int32_t SubDataSizeToSerialize();
508     virtual void SubDataSet();
509     virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
510 
511     static CALLER_ATTACH Builder* CreateBuilder(Header* header,
512                                                 WritableFontData* data);
513 
514     CMap::Builder* NewCMapBuilder(const CMapId& cmap_id,
515                                   ReadableFontData* data);
516     // Create a new empty CMapBuilder of the type specified in the id.
517     CMap::Builder* NewCMapBuilder(int32_t format, const CMapId& cmap_id);
518     CMap::Builder* CMapBuilder(const CMapId& cmap_id);
519 
520     int32_t NumCMaps();
521     void SetVersion(int32_t version);
522 
523     CMapBuilderMap* GetCMapBuilders();
524 
525    protected:
526     static CALLER_ATTACH CMap::Builder* CMapBuilder(ReadableFontData* data,
527                                                     int32_t index);
528 
529    private:
530     void Initialize(ReadableFontData* data);
531     static int32_t NumCMaps(ReadableFontData* data);
532 
533     int32_t version_;
534     CMapBuilderMap cmap_builders_;
535   };
536   typedef Ptr<Builder> CMapTableBuilderPtr;
537 
538   class CMapIterator {
539    public:
540     // If filter is NULL, filter through all tables.
541     CMapIterator(CMapTable* table, const CMapFilter* filter);
542     bool HasNext();
543     CMap* Next();
544 
545    private:
546     int32_t table_index_;
547     const CMapFilter* filter_;
548     CMapTable* table_;
549   };
550 
551   // Make a CMapId from a platform_id, encoding_id pair
552   static CMapId NewCMapId(int32_t platform_id, int32_t encoding_id);
553   // Make a CMapId from another CMapId
554   static CMapId NewCMapId(const CMapId& obj);
555 
556   // Get the CMap with the specified parameters if it exists.
557   // Returns NULL otherwise.
558   CALLER_ATTACH CMap* GetCMap(const int32_t index);
559   CALLER_ATTACH CMap* GetCMap(const int32_t platform_id,
560                               const int32_t encoding_id);
561   CALLER_ATTACH CMap* GetCMap(const CMapId GetCMap_id);
562 
563   // Get the table version.
564   virtual int32_t Version();
565 
566   // Get the number of cmaps within the CMap table.
567   virtual int32_t NumCMaps();
568 
569   // Get the cmap id for the cmap with the given index.
570   // Note: yes, an object is returned on stack since it's small enough.
571   //       This function is renamed from cmapId to GetCMapId().
572   virtual CMapId GetCMapId(int32_t index);
573 
574   virtual int32_t PlatformId(int32_t index);
575   virtual int32_t EncodingId(int32_t index);
576 
577   // Get the offset in the table data for the cmap table with the given index.
578   // The offset is from the beginning of the table.
579   virtual int32_t Offset(int32_t index);
580 
581   virtual ~CMapTable();
582 
583   static const int32_t NOTDEF;
584 
585  private:
586   // Offsets to specific elements in the underlying data. These offsets are
587   // relative to the start of the table or the start of sub-blocks within
588   // the table.
589   struct Offset {
590     enum {
591       kVersion = 0,
592       kNumTables = 2,
593       kEncodingRecordStart = 4,
594 
595       // offsets relative to the encoding record
596       kEncodingRecordPlatformId = 0,
597       kEncodingRecordEncodingId = 2,
598       kEncodingRecordOffset = 4,
599       kEncodingRecordSize = 8,
600 
601       kFormat = 0,
602 
603       // Format 0: Byte encoding table
604       kFormat0Format = 0,
605       kFormat0Length = 2,
606       kFormat0Language = 4,
607       kFormat0GlyphIdArray = 6,
608 
609       // Format 2: High-byte mapping through table
610       kFormat2Format = 0,
611       kFormat2Length = 2,
612       kFormat2Language = 4,
613       kFormat2SubHeaderKeys = 6,
614       kFormat2SubHeaders = 518,
615       // offset relative to the subHeader structure
616       kFormat2SubHeader_firstCode = 0,
617       kFormat2SubHeader_entryCount = 2,
618       kFormat2SubHeader_idDelta = 4,
619       kFormat2SubHeader_idRangeOffset = 6,
620       kFormat2SubHeader_structLength = 8,
621 
622       // Format 4: Segment mapping to delta values
623       kFormat4Format = 0,
624       kFormat4Length = 2,
625       kFormat4Language = 4,
626       kFormat4SegCountX2 = 6,
627       kFormat4SearchRange = 8,
628       kFormat4EntrySelector = 10,
629       kFormat4RangeShift = 12,
630       kFormat4EndCount = 14,
631       kFormat4FixedSize = 16,
632 
633       // format 6: Trimmed table mapping
634       kFormat6Format = 0,
635       kFormat6Length = 2,
636       kFormat6Language = 4,
637       kFormat6FirstCode = 6,
638       kFormat6EntryCount = 8,
639       kFormat6GlyphIdArray = 10,
640 
641       // Format 8: mixed 16-bit and 32-bit coverage
642       kFormat8Format = 0,
643       kFormat8Length = 4,
644       kFormat8Language = 8,
645       kFormat8Is32 = 12,
646       kFormat8nGroups204 = 8204,
647       kFormat8Groups208 = 8208,
648       // offset relative to the group structure
649       kFormat8Group_startCharCode = 0,
650       kFormat8Group_endCharCode = 4,
651       kFormat8Group_startGlyphId = 8,
652       kFormat8Group_structLength = 12,
653 
654       // Format 10: Trimmed array
655       kFormat10Format = 0,
656       kFormat10Length = 4,
657       kFormat10Language = 8,
658       kFormat10StartCharCode = 12,
659       kFormat10NumChars = 16,
660       kFormat10Glyphs0 = 20,
661 
662       // Format 12: Segmented coverage
663       kFormat12Format = 0,
664       kFormat12Length = 4,
665       kFormat12Language = 8,
666       kFormat12nGroups = 12,
667       kFormat12Groups = 16,
668       kFormat12Groups_structLength = 12,
669       // offsets within the group structure
670       kFormat12_startCharCode = 0,
671       kFormat12_endCharCode = 4,
672       kFormat12_startGlyphId = 8,
673 
674       // Format 13: Last Resort Font
675       kFormat13Format = 0,
676       kFormat13Length = 4,
677       kFormat13Language = 8,
678       kFormat13nGroups = 12,
679       kFormat13Groups = 16,
680       kFormat13Groups_structLength = 12,
681       // offsets within the group structure
682       kFormat13_startCharCode = 0,
683       kFormat13_endCharCode = 4,
684       kFormat13_glyphId = 8,
685 
686       // Format 14: Unicode Variation Sequences
687       kFormat14Format = 0,
688       kFormat14Length = 2,
689 
690       // TODO(stuartg): finish tables
691       // Default UVS Table
692 
693       // Non-default UVS Table
694       kLast = -1
695     };
696   };
697 
698   CMapTable(Header* header, ReadableFontData* data);
699 
700   // Get the offset in the table data for the encoding record for the cmap with
701   // the given index. The offset is from the beginning of the table.
702   static int32_t OffsetForEncodingRecord(int32_t index);
703 };
704 typedef std::vector<CMapTable::CMapId> CMapIdList;
705 typedef Ptr<CMapTable> CMapTablePtr;
706 typedef std::vector<Ptr<CMapTable::CMapFormat4::Builder::Segment> > SegmentList;
707 }  // namespace sfntly
708 
709 #endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_
710