@@ -26,6 +26,18 @@ class cmap extends Table {
26
26
"offset " => self ::uint32,
27
27
);
28
28
29
+ private static $ subtable_v2_format = array (
30
+ "length " => self ::uint16,
31
+ "language " => self ::uint16
32
+ );
33
+
34
+ private static $ subtable_v2_format_subheader = array (
35
+ "firstCode " => self ::uint16,
36
+ "entryCount " => self ::uint16,
37
+ "idDelta " => self ::int16,
38
+ "idRangeOffset " => self ::uint16
39
+ );
40
+
29
41
private static $ subtable_v4_format = array (
30
42
"length " => self ::uint16,
31
43
"language " => self ::uint16,
@@ -38,7 +50,7 @@ class cmap extends Table {
38
50
private static $ subtable_v12_format = array (
39
51
"length " => self ::uint32,
40
52
"language " => self ::uint32,
41
- "ngroups " => self ::uint32
53
+ "ngroups " => self ::uint32
42
54
);
43
55
44
56
protected function _parse () {
@@ -60,99 +72,170 @@ protected function _parse() {
60
72
61
73
$ subtable ["format " ] = $ font ->readUInt16 ();
62
74
63
- // @todo Only CMAP version 4 and 12
64
- if (($ subtable ["format " ] != 4 ) && ($ subtable ["format " ] != 12 )) {
65
- unset($ data ["subtables " ][$ i ]);
66
- $ data ["numberSubtables " ]--;
67
- continue ;
68
- }
69
-
70
- if ($ subtable ["format " ] == 12 ) {
71
-
72
- $ font ->readUInt16 ();
73
-
74
- $ subtable += $ font ->unpack (self ::$ subtable_v12_format );
75
-
76
- $ glyphIndexArray = array ();
77
- $ endCodes = array ();
78
- $ startCodes = array ();
79
-
80
- for ($ p = 0 ; $ p < $ subtable ['ngroups ' ]; $ p ++) {
81
-
82
- $ startCode = $ startCodes [] = $ font ->readUInt32 ();
83
- $ endCode = $ endCodes [] = $ font ->readUInt32 ();
84
- $ startGlyphCode = $ font ->readUInt32 ();
85
-
86
- for ($ c = $ startCode ; $ c <= $ endCode ; $ c ++) {
87
- $ glyphIndexArray [$ c ] = $ startGlyphCode ;
88
- $ startGlyphCode ++;
75
+ switch ($ subtable ["format " ]) {
76
+ case 0 :
77
+ case 6 :
78
+ case 8 :
79
+ case 10 :
80
+ case 13 :
81
+ case 14 :
82
+ unset($ data ["subtables " ][$ i ]);
83
+ $ data ["numberSubtables " ]--;
84
+ continue ;
85
+
86
+ case 2 :
87
+ $ subtable += $ font ->unpack (self ::$ subtable_v2_format );
88
+
89
+ $ subHeaderKeys = array_map (function ($ val ) { return $ val / 8 ; }, $ font ->readUInt16Many (256 ));
90
+ $ subHeaders = array ();
91
+
92
+ $ glyphIdArray = array ();
93
+ $ maxSubHeaderIndex = max ($ subHeaderKeys );
94
+ for ($ i = 0 ; $ i <= $ maxSubHeaderIndex ; $ i ++) {
95
+ $ subHeader = $ font ->unpack (self ::$ subtable_v2_format_subheader );
96
+ $ offset = $ font ->pos ();
97
+ $ subHeader ["glyphIdArrayOffset " ] = $ offset + $ subHeader ["idRangeOffset " ] - 2 ;
98
+ $ subHeaders [$ i ] = $ subHeader ;
99
+
100
+ if (!\array_key_exists ($ subHeader ["glyphIdArrayOffset " ], $ glyphIdArray ) || count ($ glyphIdArray [$ subHeader ["glyphIdArrayOffset " ]]) < $ subHeader ["entryCount " ]) {
101
+ $ font ->seek ($ subHeader ["glyphIdArrayOffset " ]);
102
+ $ glyphIdArray [$ subHeader ["glyphIdArrayOffset " ]] = $ font ->readUInt16Many ($ subHeader ["entryCount " ]);
103
+ $ font ->seek ($ offset );
104
+ }
89
105
}
90
- }
91
-
92
- $ subtable += array (
93
- "startCode " => $ startCodes ,
94
- "endCode " => $ endCodes ,
95
- "glyphIndexArray " => $ glyphIndexArray ,
96
- );
97
-
98
- }
99
- else if ($ subtable ["format " ] == 4 ) {
100
-
101
- $ subtable += $ font ->unpack (self ::$ subtable_v4_format );
102
106
103
- $ segCount = $ subtable ["segCountX2 " ] / 2 ;
104
- $ subtable ["segCount " ] = $ segCount ;
105
-
106
- $ endCode = $ font ->readUInt16Many ($ segCount );
107
-
108
- $ font ->readUInt16 (); // reservedPad
109
-
110
- $ startCode = $ font ->readUInt16Many ($ segCount );
111
- $ idDelta = $ font ->readInt16Many ($ segCount );
112
-
113
- $ ro_start = $ font ->pos ();
114
- $ idRangeOffset = $ font ->readUInt16Many ($ segCount );
115
-
116
- $ glyphIndexArray = array ();
117
- for ($ i = 0 ; $ i < $ segCount ; $ i ++) {
118
- $ c1 = $ startCode [$ i ];
119
- $ c2 = $ endCode [$ i ];
120
- $ d = $ idDelta [$ i ];
121
- $ ro = $ idRangeOffset [$ i ];
122
-
123
- if ($ ro > 0 ) {
124
- $ font ->seek ($ subtable ["offset " ] + 2 * $ i + $ ro );
107
+ $ glyphIndexArray = array ();
108
+ foreach ($ subHeaderKeys as $ highByte => $ subHeaderKey ) {
109
+ $ subHeader = $ subHeaders [$ subHeaderKey ];
110
+ if ($ subHeaderKey === 0 ) {
111
+ $ c = $ highByte ;
112
+ if ($ c < $ subHeader ["firstCode " ] || $ c >= ($ subHeader ["firstCode " ] + $ subHeader ["entryCount " ])) {
113
+ $ glyphIndexArray [$ c ] = 0 ;
114
+ continue ;
115
+ }
116
+ $ c = $ highByte ;
117
+ $ index = $ c - $ subHeader ["firstCode " ];
118
+ $ glyphId = $ glyphIdArray [$ subHeader ["glyphIdArrayOffset " ]][$ index ];
119
+ if ($ glyphId === 0 ) {
120
+ $ glyphIndexArray [$ c ] = 0 ;
121
+ } else {
122
+ $ glyphIndexArray [$ c ] = ($ glyphId + $ subHeader ["idDelta " ]) & 0xFFFF ;
123
+ }
124
+ } else {
125
+ for ($ index = 0 ; $ index < $ subHeader ["entryCount " ]; $ index ++) {
126
+ $ c = null ;
127
+ $ lowByte = $ subHeader ["firstCode " ] + $ index ;
128
+ $ c = (($ highByte & 0xFF ) << 8 ) | ($ lowByte & 0xFF );
129
+ $ glyphId = $ glyphIdArray [$ subHeader ["glyphIdArrayOffset " ]][$ index ];
130
+ if ($ glyphId === 0 ) {
131
+ $ glyphIndexArray [$ c ] = 0 ;
132
+ } else {
133
+ $ glyphIndexArray [$ c ] = ($ glyphId + $ subHeader ["idDelta " ]) & 0xFFFF ;
134
+ }
135
+ }
136
+ }
125
137
}
126
138
127
- for ($ c = $ c1 ; $ c <= $ c2 ; $ c ++) {
128
- if ($ ro == 0 ) {
129
- $ gid = ($ c + $ d ) & 0xFFFF ;
139
+ $ subtable += array (
140
+ "subHeaderKeys " => $ subHeaderKeys ,
141
+ "subHeaders " => $ subHeaders ,
142
+ "glyphIdArray " => $ glyphIdArray ,
143
+ "glyphIndexArray " => $ glyphIndexArray
144
+ );
145
+
146
+ break ;
147
+
148
+ case 4 :
149
+ $ subtable += $ font ->unpack (self ::$ subtable_v4_format );
150
+
151
+ $ segCount = $ subtable ["segCountX2 " ] / 2 ;
152
+ $ subtable ["segCount " ] = $ segCount ;
153
+
154
+ $ endCode = $ font ->readUInt16Many ($ segCount );
155
+
156
+ $ font ->readUInt16 (); // reservedPad
157
+
158
+ $ startCode = $ font ->readUInt16Many ($ segCount );
159
+ $ idDelta = $ font ->readInt16Many ($ segCount );
160
+
161
+ $ ro_start = $ font ->pos ();
162
+ $ idRangeOffset = $ font ->readUInt16Many ($ segCount );
163
+
164
+ $ glyphIndexArray = array ();
165
+ for ($ i = 0 ; $ i < $ segCount ; $ i ++) {
166
+ $ c1 = $ startCode [$ i ];
167
+ $ c2 = $ endCode [$ i ];
168
+ $ d = $ idDelta [$ i ];
169
+ $ ro = $ idRangeOffset [$ i ];
170
+
171
+ if ($ ro > 0 ) {
172
+ $ font ->seek ($ subtable ["offset " ] + 2 * $ i + $ ro );
130
173
}
131
- else {
132
- $ offset = ($ c - $ c1 ) * 2 + $ ro ;
133
- $ offset = $ ro_start + 2 * $ i + $ offset ;
134
-
135
- $ font ->seek ($ offset );
136
- $ gid = $ font ->readUInt16 ();
137
-
138
- if ($ gid != 0 ) {
139
- $ gid = ($ gid + $ d ) & 0xFFFF ;
174
+
175
+ for ($ c = $ c1 ; $ c <= $ c2 ; $ c ++) {
176
+ if ($ c === 0xFFFF ) {
177
+ continue ;
178
+ }
179
+
180
+ if ($ ro == 0 ) {
181
+ $ gid = ($ c + $ d ) & 0xFFFF ;
182
+ }
183
+ else {
184
+ $ offset = ($ c - $ c1 ) * 2 + $ ro ;
185
+ $ offset = $ ro_start + 2 * $ i + $ offset ;
186
+
187
+ $ gid = 0 ;
188
+ if ($ font ->seek ($ offset ) === true ) {
189
+ $ gid = $ font ->readUInt16 ();
190
+ }
191
+
192
+ if ($ gid != 0 ) {
193
+ $ gid = ($ gid + $ d ) & 0xFFFF ;
194
+ }
195
+ }
196
+
197
+ if ($ gid >= 0 ) {
198
+ $ glyphIndexArray [$ c ] = $ gid ;
140
199
}
141
200
}
142
-
143
- if ($ gid > 0 ) {
144
- $ glyphIndexArray [$ c ] = $ gid ;
201
+ }
202
+
203
+ $ subtable += array (
204
+ "endCode " => $ endCode ,
205
+ "startCode " => $ startCode ,
206
+ "idDelta " => $ idDelta ,
207
+ "idRangeOffset " => $ idRangeOffset ,
208
+ "glyphIndexArray " => $ glyphIndexArray
209
+ );
210
+ break ;
211
+
212
+ case 12 :
213
+ $ font ->readUInt16 ();
214
+
215
+ $ subtable += $ font ->unpack (self ::$ subtable_v12_format );
216
+
217
+ $ glyphIndexArray = array ();
218
+ $ endCodes = array ();
219
+ $ startCodes = array ();
220
+
221
+ for ($ p = 0 ; $ p < $ subtable ['ngroups ' ]; $ p ++) {
222
+
223
+ $ startCode = $ startCodes [] = $ font ->readUInt32 ();
224
+ $ endCode = $ endCodes [] = $ font ->readUInt32 ();
225
+ $ startGlyphCode = $ font ->readUInt32 ();
226
+
227
+ for ($ c = $ startCode ; $ c <= $ endCode ; $ c ++) {
228
+ $ glyphIndexArray [$ c ] = $ startGlyphCode ;
229
+ $ startGlyphCode ++;
145
230
}
146
231
}
147
- }
148
-
149
- $ subtable += array (
150
- "endCode " => $ endCode ,
151
- "startCode " => $ startCode ,
152
- "idDelta " => $ idDelta ,
153
- "idRangeOffset " => $ idRangeOffset ,
154
- "glyphIndexArray " => $ glyphIndexArray ,
155
- );
232
+
233
+ $ subtable += array (
234
+ "startCode " => $ startCodes ,
235
+ "endCode " => $ endCodes ,
236
+ "glyphIndexArray " => $ glyphIndexArray ,
237
+ );
238
+ break ;
156
239
}
157
240
}
158
241
0 commit comments