David PHAM-VAN

Fix font writer CMAP

1 # Changelog 1 # Changelog
2 2
  3 +
  4 +## 1.10.1
  5 +
  6 +- Fix TTF writer with more than 256 CMAP entries
  7 +
3 ## 1.10.0 8 ## 1.10.0
4 9
5 - Fix dependencies 10 - Fix dependencies
@@ -137,49 +137,52 @@ class TtfParser { @@ -137,49 +137,52 @@ class TtfParser {
137 for (int i = 0; i < numSubTables; i++) { 137 for (int i = 0; i < numSubTables; i++) {
138 final int offset = bytes.getUint32(basePosition + i * 8 + 8); 138 final int offset = bytes.getUint32(basePosition + i * 8 + 8);
139 final int format = bytes.getUint16(basePosition + offset); 139 final int format = bytes.getUint16(basePosition + offset);
140 - final int length = bytes.getUint16(basePosition + offset + 2);  
141 140
142 switch (format) { 141 switch (format) {
143 case 0: 142 case 0:
144 - _parseCMapFormat0(basePosition + offset + 4, length); 143 + _parseCMapFormat0(basePosition + offset + 2);
145 break; 144 break;
146 145
147 case 4: 146 case 4:
148 - _parseCMapFormat4(basePosition + offset + 4, length); 147 + _parseCMapFormat4(basePosition + offset + 2);
149 break; 148 break;
150 case 6: 149 case 6:
151 - _parseCMapFormat6(basePosition + offset + 4, length); 150 + _parseCMapFormat6(basePosition + offset + 2);
  151 + break;
  152 +
  153 + case 12:
  154 + _parseCMapFormat12(basePosition + offset + 2);
152 break; 155 break;
153 } 156 }
154 } 157 }
155 } 158 }
156 159
157 - void _parseCMapFormat0(int basePosition, int length) {  
158 - assert(length == 262); 160 + void _parseCMapFormat0(int basePosition) {
  161 + assert(bytes.getUint16(basePosition) == 262);
159 for (int i = 0; i < 256; i++) { 162 for (int i = 0; i < 256; i++) {
160 final int charCode = i; 163 final int charCode = i;
161 - final int glyphIndex = bytes.getUint8(basePosition + i); 164 + final int glyphIndex = bytes.getUint8(basePosition + i + 2);
162 if (glyphIndex > 0) { 165 if (glyphIndex > 0) {
163 charToGlyphIndexMap[charCode] = glyphIndex; 166 charToGlyphIndexMap[charCode] = glyphIndex;
164 } 167 }
165 } 168 }
166 } 169 }
167 170
168 - void _parseCMapFormat4(int basePosition, int length) {  
169 - final int segCount = bytes.getUint16(basePosition + 2) ~/ 2; 171 + void _parseCMapFormat4(int basePosition) {
  172 + final int segCount = bytes.getUint16(basePosition + 4) ~/ 2;
170 final List<int> endCodes = <int>[]; 173 final List<int> endCodes = <int>[];
171 for (int i = 0; i < segCount; i++) { 174 for (int i = 0; i < segCount; i++) {
172 - endCodes.add(bytes.getUint16(basePosition + i * 2 + 10)); 175 + endCodes.add(bytes.getUint16(basePosition + i * 2 + 12));
173 } 176 }
174 final List<int> startCodes = <int>[]; 177 final List<int> startCodes = <int>[];
175 for (int i = 0; i < segCount; i++) { 178 for (int i = 0; i < segCount; i++) {
176 - startCodes.add(bytes.getUint16(basePosition + (segCount + i) * 2 + 12)); 179 + startCodes.add(bytes.getUint16(basePosition + (segCount + i) * 2 + 14));
177 } 180 }
178 final List<int> idDeltas = <int>[]; 181 final List<int> idDeltas = <int>[];
179 for (int i = 0; i < segCount; i++) { 182 for (int i = 0; i < segCount; i++) {
180 - idDeltas.add(bytes.getUint16(basePosition + (segCount * 2 + i) * 2 + 12)); 183 + idDeltas.add(bytes.getUint16(basePosition + (segCount * 2 + i) * 2 + 14));
181 } 184 }
182 - final int idRangeOffsetBasePos = basePosition + segCount * 6 + 12; 185 + final int idRangeOffsetBasePos = basePosition + segCount * 6 + 14;
183 final List<int> idRangeOffsets = <int>[]; 186 final List<int> idRangeOffsets = <int>[];
184 for (int i = 0; i < segCount; i++) { 187 for (int i = 0; i < segCount; i++) {
185 idRangeOffsets.add(bytes.getUint16(idRangeOffsetBasePos + i * 2)); 188 idRangeOffsets.add(bytes.getUint16(idRangeOffsetBasePos + i * 2));
@@ -204,18 +207,35 @@ class TtfParser { @@ -204,18 +207,35 @@ class TtfParser {
204 } 207 }
205 } 208 }
206 209
207 - void _parseCMapFormat6(int basePosition, int length) {  
208 - final int firstCode = bytes.getUint16(basePosition + 2);  
209 - final int entryCount = bytes.getUint16(basePosition + 4); 210 + void _parseCMapFormat6(int basePosition) {
  211 + final int firstCode = bytes.getUint16(basePosition + 4);
  212 + final int entryCount = bytes.getUint16(basePosition + 6);
210 for (int i = 0; i < entryCount; i++) { 213 for (int i = 0; i < entryCount; i++) {
211 final int charCode = firstCode + i; 214 final int charCode = firstCode + i;
212 - final int glyphIndex = bytes.getUint16(basePosition + i * 2 + 6); 215 + final int glyphIndex = bytes.getUint16(basePosition + i * 2 + 8);
213 if (glyphIndex > 0) { 216 if (glyphIndex > 0) {
214 charToGlyphIndexMap[charCode] = glyphIndex; 217 charToGlyphIndexMap[charCode] = glyphIndex;
215 } 218 }
216 } 219 }
217 } 220 }
218 221
  222 + void _parseCMapFormat12(int basePosition) {
  223 + final int numGroups = bytes.getUint32(basePosition + 10);
  224 + assert(bytes.getUint32(basePosition + 2) == 12 * numGroups + 16);
  225 +
  226 + for (int i = 0; i < numGroups; i++) {
  227 + final int startCharCode = bytes.getUint32(basePosition + i * 12 + 14);
  228 + final int endCharCode = bytes.getUint32(basePosition + i * 12 + 18);
  229 + final int startGlyphID = bytes.getUint32(basePosition + i * 12 + 22);
  230 +
  231 + for (int j = startCharCode; j <= endCharCode; j++) {
  232 + assert(!charToGlyphIndexMap.containsKey(j) ||
  233 + charToGlyphIndexMap[j] == startGlyphID + j - startCharCode);
  234 + charToGlyphIndexMap[j] = startGlyphID + j - startCharCode;
  235 + }
  236 + }
  237 + }
  238 +
219 void _parseIndexes() { 239 void _parseIndexes() {
220 final int basePosition = tableOffsets[loca_table]; 240 final int basePosition = tableOffsets[loca_table];
221 final int numGlyphs = this.numGlyphs; 241 final int numGlyphs = this.numGlyphs;
@@ -196,14 +196,24 @@ class TtfWriter { @@ -196,14 +196,24 @@ class TtfWriter {
196 196
197 { 197 {
198 // CMAP table 198 // CMAP table
199 - final Uint8List cmap = Uint8List(_wordAlign(0x112, 4));  
200 - cmap.setAll(3, <int>[1, 0, 1, 0, 0, 0, 0, 0, 12, 0, 0, 1, 6]); 199 + const int len = 40;
  200 + final Uint8List cmap = Uint8List(_wordAlign(len, 4));
201 final ByteData cmapData = cmap.buffer.asByteData(); 201 final ByteData cmapData = cmap.buffer.asByteData();
202 - for (int i = 1; i < chars.length; i++) {  
203 - cmapData.setUint8(i + 18, i);  
204 - } 202 + cmapData.setUint16(0, 0); // Table version number
  203 + cmapData.setUint16(2, 1); // Number of encoding tables that follow.
  204 + cmapData.setUint16(4, 3); // Platform ID
  205 + cmapData.setUint16(6, 1); // Platform-specific encoding ID
  206 + cmapData.setUint32(8, 12); // Offset from beginning of table
  207 + cmapData.setUint16(12, 12); // Table format
  208 + cmapData.setUint32(16, 28); // Table length
  209 + cmapData.setUint32(20, 1); // Table language
  210 + cmapData.setUint32(24, 1); // numGroups
  211 + cmapData.setUint32(28, 32); // startCharCode
  212 + cmapData.setUint32(32, chars.length + 31); // endCharCode
  213 + cmapData.setUint32(36, 0); // startGlyphID
  214 +
205 tables[TtfParser.cmap_table] = cmap; 215 tables[TtfParser.cmap_table] = cmap;
206 - tablesLength[TtfParser.cmap_table] = 0x112; 216 + tablesLength[TtfParser.cmap_table] = len;
207 } 217 }
208 218
209 { 219 {
@@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl @@ -4,7 +4,7 @@ description: A pdf producer for Dart. It can create pdf files for both web or fl
4 homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf 4 homepage: https://github.com/DavBfr/dart_pdf/tree/master/pdf
5 repository: https://github.com/DavBfr/dart_pdf 5 repository: https://github.com/DavBfr/dart_pdf
6 issue_tracker: https://github.com/DavBfr/dart_pdf/issues 6 issue_tracker: https://github.com/DavBfr/dart_pdf/issues
7 -version: 1.10.0 7 +version: 1.10.1
8 8
9 environment: 9 environment:
10 sdk: ">=2.3.0 <3.0.0" 10 sdk: ">=2.3.0 <3.0.0"