1 /*
2 Copyright (C) 2012, 2013, 2014 Johan Mattsson
3
4 This library is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 3 of the
7 License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13 */
14 using Gee;
15
16 namespace BirdFont {
17
18 public class CmapTable : OtfTable {
19
20 GlyfTable glyf_table;
21 CmapSubtableFormat4 cmap_format4 = new CmapSubtableFormat4 ();
22
23 public CmapTable(GlyfTable gt) {
24 glyf_table = gt;
25 id = "cmap";
26 }
27
28 public unichar get_char (uint32 i) {
29 return get_prefered_table ().get_char (i) ;
30 }
31
32 CmapSubtableFormat4 get_prefered_table () {
33 return cmap_format4;
34 }
35
36 public override string get_id () {
37 return "cmap";
38 }
39
40 public override void parse (FontData dis) throws GLib.Error {
41 uint16 version;
42 uint16 nsubtables;
43
44 uint16 platform;
45 uint16 encoding;
46 uint32 sub_offset;
47
48 return_if_fail (offset > 0 && length > 0);
49
50 dis.seek (offset);
51
52 version = dis.read_ushort ();
53 nsubtables = dis.read_ushort ();
54
55 printd (@"cmap version: $version\n");
56 printd (@"cmap subtables: $nsubtables\n");
57
58 if (version != 0) {
59 warning (@"Bad version for cmap table: $version expecting 0. Number of subtables: $nsubtables");
60 return;
61 }
62
63 for (uint i = 0; i < nsubtables; i++) {
64 platform = dis.read_ushort ();
65 encoding = dis.read_ushort ();
66 sub_offset = dis.read_ulong ();
67
68 if (platform == 3 && encoding == 1) {
69 printd (@"Parsing Unicode BMP (UCS-2) Platform: $platform Encoding: $encoding\n");
70 cmap_format4.offset = offset + sub_offset;
71 } else {
72 stderr.printf (@"Unknown cmap format. Platform: $platform Encoding: $encoding.\n");
73 }
74
75 if (encoding == 3) {
76 stderr.printf ("Font contains a cmap table with the obsolete encoding 3.\n");
77 }
78 }
79
80 if (cmap_format4.offset > 0) {
81 cmap_format4.parse (dis);
82 } else {
83 warning ("No cmap subtable4 found.");
84 }
85 }
86
87 /** Character to glyph mapping */
88 public void process (GlyfTable glyf_table) throws GLib.Error {
89 FontData fd = new FontData ();
90 CmapSubtableFormat0 cmap0 = new CmapSubtableFormat0 ();
91 CmapSubtableFormat4 cmap4 = new CmapSubtableFormat4 ();
92 CmapSubtableFormat12 cmap12 = new CmapSubtableFormat12 ();
93 uint16 n_encoding_tables;
94 ArrayList<CmapSubtable> cmap_tables = new ArrayList<CmapSubtable> ();
95
96 cmap0.generate_cmap_data (glyf_table);
97 cmap4.generate_cmap_data (glyf_table);
98 cmap12.generate_cmap_data (glyf_table);
99
100 cmap_tables.add(cmap0);
101 cmap_tables.add(cmap4);
102 cmap_tables.add(cmap12);
103
104 n_encoding_tables = (uint16) cmap_tables.size;
105
106 fd.add_u16 (0); // table version
107 fd.add_u16 (n_encoding_tables);
108
109 uint subtable_offset = 4 + 8 * cmap_tables.size;
110 foreach (CmapSubtable subtable in cmap_tables) {
111 fd.add_u16 (subtable.get_platform ());
112 fd.add_u16 (subtable.get_encoding ());
113 fd.add_ulong (subtable_offset);
114 subtable_offset += subtable.get_cmap_data ().length ();
115 }
116
117 foreach (CmapSubtable subtable in cmap_tables) {
118 fd.append (subtable.get_cmap_data ());
119 }
120
121 fd.pad ();
122
123 this.font_data = fd;
124 }
125 }
126
127 /** Largest power of two less than max. */
128 internal static uint16 largest_pow2 (uint16 max) {
129 uint16 x = 1;
130 uint16 l = 0;
131
132 while (x <= max) {
133 l = x;
134 x = x << 1;
135 }
136
137 return l;
138 }
139
140 /** Largest exponent for a power of two less than max. */
141 internal static uint16 largest_pow2_exponent (uint16 max) {
142 uint16 exp = 0;
143 uint16 l = 0;
144 uint16 x = 0;
145
146 while (x <= max) {
147 l = exp;
148 exp++;
149 x = 1 << exp;
150 }
151
152 return l;
153 }
154
155 }
156