@@ -26,6 +26,18 @@ class cmap extends Table {
2626 "offset " => self ::uint32,
2727 );
2828
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+
2941 private static $ subtable_v4_format = array (
3042 "length " => self ::uint16,
3143 "language " => self ::uint16,
@@ -38,7 +50,7 @@ class cmap extends Table {
3850 private static $ subtable_v12_format = array (
3951 "length " => self ::uint32,
4052 "language " => self ::uint32,
41- "ngroups " => self ::uint32
53+ "ngroups " => self ::uint32
4254 );
4355
4456 protected function _parse () {
@@ -60,105 +72,170 @@ protected function _parse() {
6072
6173 $ subtable ["format " ] = $ font ->readUInt16 ();
6274
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 ++;
89- }
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-
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 );
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 2 ;
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+ }
125105 }
126106
127- for ($ c = $ c1 ; $ c <= $ c2 ; $ c ++) {
128- if ($ c === 0xFFFF ) {
129- continue ;
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+ }
130136 }
137+ }
131138
132- if ($ ro == 0 ) {
133- $ 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 );
134173 }
135- else {
136- $ offset = ($ c - $ c1 ) * 2 + $ ro ;
137- $ offset = $ ro_start + 2 * $ i + $ offset ;
138-
139- $ gid = 0 ;
140- if ($ font ->seek ($ offset ) === true ) {
141- $ gid = $ font ->readUInt16 ();
174+
175+ for ($ c = $ c1 ; $ c <= $ c2 ; $ c ++) {
176+ if ($ c === 0xFFFF ) {
177+ continue ;
142178 }
143-
144- if ($ gid != 0 ) {
145- $ gid = ($ gid + $ d ) & 0xFFFF ;
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 ;
146199 }
147200 }
148-
149- if ($ gid >= 0 ) {
150- $ 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 ++;
151230 }
152231 }
153- }
154-
155- $ subtable += array (
156- "endCode " => $ endCode ,
157- "startCode " => $ startCode ,
158- "idDelta " => $ idDelta ,
159- "idRangeOffset " => $ idRangeOffset ,
160- "glyphIndexArray " => $ glyphIndexArray ,
161- );
232+
233+ $ subtable += array (
234+ "startCode " => $ startCodes ,
235+ "endCode " => $ endCodes ,
236+ "glyphIndexArray " => $ glyphIndexArray ,
237+ );
238+ break ;
162239 }
163240 }
164241
0 commit comments