1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: pdffontsubsetcff.cpp
3 // Purpose:
4 // Author: Ulrich Telle
5 // Created: 2008-06-24
6 // Copyright: (c) Ulrich Telle
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 /// \file pdffontsubsetcff.cpp Implementation of subset support for CFF fonts
11
12 /*
13 * This Class subsets a CFF Type Font. The code is based on code and ideas from the iText project.
14 */
15
16 // For compilers that support precompilation, includes <wx.h>.
17 #include <wx/wxprec.h>
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include <wx/wx.h>
25 #endif
26
27 // includes
28
29 #include "wx/pdfarraytypes.h"
30 #include "wx/pdfcffdecoder.h"
31 #include "wx/pdfcffindex.h"
32 #include "wx/pdffontdata.h"
33 #include "wx/pdffontsubsetcff.h"
34
35 static int
CompareInts(int n1,int n2)36 CompareInts(int n1, int n2)
37 {
38 return n1 - n2;
39 }
40
41 // --- Implementation of OpenType Subset
42
43 // CFF Dict Operators
44 // If the high byte is 0 the command is encoded with a single byte.
45
46 enum {
47 BASEFONTNAME_OP = 0x0c16,
48 CHARSET_OP = 0x000f,
49 CHARSTRINGS_OP = 0x0011,
50 CIDCOUNT_OP = 0x0c22,
51 COPYRIGHT_OP = 0x0c00,
52 ENCODING_OP = 0x0010,
53 FAMILYNAME_OP = 0x0003,
54 FDARRAY_OP = 0x0c24,
55 FDSELECT_OP = 0x0c25,
56 FONTBBOX_OP = 0x0005,
57 FONTNAME_OP = 0x0c26,
58 FULLNAME_OP = 0x0002,
59 LOCAL_SUB_OP = 0x0013,
60 NOTICE_OP = 0x0001,
61 POSTSCRIPT_OP = 0x0c15,
62 PRIVATE_OP = 0x0012,
63 ROS_OP = 0x0c1e,
64 UNIQUEID_OP = 0x000d,
65 VERSION_OP = 0x0000,
66 WEIGHT_OP = 0x0004,
67 XUID_OP = 0x000e
68 };
69
70 class wxPdfCffFontObject
71 {
72 public:
wxPdfCffFontObject()73 wxPdfCffFontObject() {}
74 int m_type;
75 int m_intValue;
76 wxString m_strValue;
77 };
78
79 class wxPdfCffDictElement
80 {
81 public:
wxPdfCffDictElement(int op,wxInputStream * buf,int argStart,int argTotal)82 wxPdfCffDictElement(int op, wxInputStream* buf, int argStart, int argTotal)
83 {
84 m_operator = op;
85 m_argument = new wxPdfCffIndexElement(buf, argStart, argTotal);
86 m_argOffset = -1;
87 }
88
wxPdfCffDictElement(int op,wxPdfCffIndexElement * argument)89 wxPdfCffDictElement(int op, wxPdfCffIndexElement* argument)
90 {
91 m_operator = op;
92 m_argument = argument;
93 m_argOffset = -1;
94 }
95
~wxPdfCffDictElement()96 virtual ~wxPdfCffDictElement()
97 {
98 delete m_argument;
99 }
100
SetOperator(int op)101 void SetOperator(int op) { m_operator = op; }
GetOperator() const102 int GetOperator() const { return m_operator; }
GetArgument() const103 wxPdfCffIndexElement* GetArgument() const { return m_argument; }
GetArgumentLength() const104 int GetArgumentLength() const { return m_argument->GetLength(); }
SetArgumentOffset(int argOffset)105 void SetArgumentOffset(int argOffset) { m_argOffset = argOffset; }
GetArgumentOffset() const106 int GetArgumentOffset() const { return m_argOffset; }
107
108 private:
109 int m_operator;
110 wxPdfCffIndexElement* m_argument;
111 int m_argOffset;
112 };
113
wxPdfFontSubsetCff(const wxString & fileName)114 wxPdfFontSubsetCff::wxPdfFontSubsetCff(const wxString& fileName)
115 {
116 m_fileName = fileName;
117
118 m_topDict = new wxPdfCffDictionary();
119 m_privateDict = new wxPdfCffDictionary();
120
121 m_stringsIndex = new wxPdfCffIndexArray();
122 m_charstringsIndex = new wxPdfCffIndexArray();
123 m_globalSubrIndex = new wxPdfCffIndexArray();
124 m_localSubrIndex = new wxPdfCffIndexArray();
125
126 m_stringsSubsetIndex = new wxPdfCffIndexArray();
127 m_charstringsSubsetIndex = new wxPdfCffIndexArray();
128
129 m_hGlobalSubrsUsed = new wxPdfSortedArrayInt(CompareInts);
130 m_hLocalSubrsUsed = new wxPdfSortedArrayInt(CompareInts);
131 m_decoder = new wxPdfCffDecoder(m_globalSubrIndex, m_hGlobalSubrsUsed, &m_lGlobalSubrsUsed);
132 }
133
134 void
DestructDictionary(wxPdfCffDictionary * dict)135 wxPdfFontSubsetCff::DestructDictionary(wxPdfCffDictionary* dict)
136 {
137 wxPdfCffDictionary::iterator dictEntry = dict->begin();
138 for (dictEntry = dict->begin(); dictEntry != dict->end(); dictEntry++)
139 {
140 if (dictEntry->second != NULL)
141 {
142 delete dictEntry->second;
143 }
144 }
145 delete dict;
146 }
147
~wxPdfFontSubsetCff()148 wxPdfFontSubsetCff::~wxPdfFontSubsetCff()
149 {
150 if (m_fdDict.GetCount() > 0)
151 {
152 size_t j;
153 for (j = 0; j < m_fdDict.GetCount(); j++)
154 {
155 if (m_fdDict[j] != NULL)
156 {
157 DestructDictionary((wxPdfCffDictionary*) m_fdDict[j]);
158 }
159 }
160 m_fdDict.Clear();
161 }
162 if (m_fdPrivateDict.GetCount() > 0)
163 {
164 size_t j;
165 for (j = 0; j < m_fdPrivateDict.GetCount(); j++)
166 {
167 if (m_fdPrivateDict[j] != NULL)
168 {
169 DestructDictionary((wxPdfCffDictionary*) m_fdPrivateDict[j]);
170 }
171 }
172 m_fdPrivateDict.Clear();
173 }
174 if (m_fdLocalSubrIndex.GetCount() > 0)
175 {
176 size_t j;
177 for (j = 0; j < m_fdLocalSubrIndex.GetCount(); j++)
178 {
179 if (m_fdLocalSubrIndex[j] != NULL)
180 {
181 delete ((wxPdfCffIndexArray*) m_fdLocalSubrIndex[j]);
182 }
183 }
184 m_fdLocalSubrIndex.Clear();
185 }
186
187 DestructDictionary(m_topDict);
188 DestructDictionary(m_privateDict);
189
190 delete m_stringsIndex;
191 delete m_charstringsIndex;
192 delete m_globalSubrIndex;
193 delete m_localSubrIndex;
194 delete m_stringsSubsetIndex;
195 delete m_charstringsSubsetIndex;
196
197 delete m_hGlobalSubrsUsed;
198 delete m_hLocalSubrsUsed;
199
200 delete m_decoder;
201 }
202
203 wxMemoryOutputStream*
CreateSubset(wxInputStream * inFont,wxPdfChar2GlyphMap * usedGlyphs,bool includeCmap)204 wxPdfFontSubsetCff::CreateSubset(wxInputStream* inFont, wxPdfChar2GlyphMap* usedGlyphs, bool includeCmap)
205 {
206 m_inFont = inFont;
207 m_numGlyphsUsed = (int) usedGlyphs->size();
208 m_usedGlyphs.SetCount(m_numGlyphsUsed);
209 wxPdfChar2GlyphMap::const_iterator glyphIter;
210 for (glyphIter = usedGlyphs->begin(); glyphIter != usedGlyphs->end(); ++glyphIter)
211 {
212 m_usedGlyphs[glyphIter->second] = glyphIter->first;
213 }
214 m_includeCmap = includeCmap;
215 m_outFont = NULL;
216
217 bool ok = ReadCffFont();
218 if (ok)
219 {
220 GenerateFontSubset();
221 WriteFontSubset();
222 }
223
224 return m_outFont;
225 }
226
227 // --- Read original CFF stream
228
229 bool
ReadCffFont()230 wxPdfFontSubsetCff::ReadCffFont()
231 {
232 bool ok = ReadHeader(); // cairo_cff_font_read_header,
233 if (ok) ok = ReadFontName(); // cairo_cff_font_read_name,
234 if (ok) ok = ReadTopDict(); // cairo_cff_font_read_top_dict,
235 if (ok) ok = ReadStrings(); // cairo_cff_font_read_strings,
236 if (ok) ok = ReadGlobalSubroutines(); // cairo_cff_font_read_global_subroutines,
237 return ok;
238 }
239
240 bool
ReadFontIndex(wxPdfCffIndexArray * index)241 wxPdfFontSubsetCff::ReadFontIndex(wxPdfCffIndexArray* index)
242 {
243 int maxLength = GetSizeI();
244 if (TellI() + 2 > maxLength)
245 {
246 wxLogError(wxString(wxS("wxPdfCffSubset::ReadFontIndex: ")) +
247 wxString(_("Premature end of CFF stream reached while reading index count.")));
248 return false;
249 }
250 int count = ReadShort();
251 if (count > 0)
252 {
253 int offsetSize = ReadByte();
254 if (TellI() + (count+1)*offsetSize > maxLength)
255 {
256 wxLogError(wxString(wxS("wxPdfCffSubset::ReadFontIndex: ")) +
257 wxString(_("Premature end of CFF stream reached while reading index data.")));
258 return false;
259 }
260 int data = TellI() + offsetSize*(count+1) - 1;
261 int start = ReadOffset(offsetSize);
262 int end = 0;
263 int j;
264 for (j = 0; j < count; j++)
265 {
266 end = ReadOffset(offsetSize);
267 index->Add(wxPdfCffIndexElement(m_inFont, data+start, end-start));
268 start = end;
269 }
270 SeekI(data + end);
271 }
272 return true;
273 }
274
275 bool
ReadHeader()276 wxPdfFontSubsetCff::ReadHeader()
277 {
278 bool ok = GetSizeI() > 4;
279 if (ok)
280 {
281 SeekI(0);
282 ReadByte(); // Major
283 ReadByte(); // Minor
284 m_hdrSize = ReadByte();
285 ReadByte(); // OffSize
286 SeekI(m_hdrSize);
287 }
288 return ok;
289 }
290
291 bool
ReadFontName()292 wxPdfFontSubsetCff::ReadFontName()
293 {
294 // Original font name not used in subset. Skip name index.
295 wxPdfCffIndexArray index;
296 bool ok = ReadFontIndex(&index);
297 if (ok)
298 {
299 int currentPosition = TellI();
300 wxPdfCffIndexElement& element = index[0];
301 SeekI(element.GetOffset());
302 m_fontName = ReadString(element.GetLength());
303 m_fontName += wxS("-Subset");
304 SeekI(currentPosition);
305 }
306 return ok;
307 }
308
309 bool
ReadFontDict(wxPdfCffDictionary * dict,int dictOffset,int dictSize)310 wxPdfFontSubsetCff::ReadFontDict(wxPdfCffDictionary* dict, int dictOffset, int dictSize)
311 {
312 bool ok = true;
313 SeekI(dictOffset);
314 int end = dictOffset + dictSize;
315 int argStart, argSize, argTotal, op;
316 while (TellI() < end)
317 {
318 argStart = TellI();
319 argTotal = 0;
320 do
321 {
322 argSize = ReadOperandLength();
323 argTotal += argSize;
324 SeekI(argStart + argTotal);
325 }
326 while (argSize > 0);
327 op = ReadOperator();
328 wxPdfCffDictElement* dictElement = new wxPdfCffDictElement(op, m_inFont, argStart, argTotal);
329 (*dict)[op] = dictElement;
330 }
331 return ok;
332 }
333
334 wxPdfCffDictElement*
FindDictElement(wxPdfCffDictionary * dict,int key)335 wxPdfFontSubsetCff::FindDictElement(wxPdfCffDictionary* dict, int key)
336 {
337 wxPdfCffDictElement* dictElement = NULL;
338 wxPdfCffDictionary::iterator dictIter = dict->find(key);
339 if (dictIter != dict->end())
340 {
341 dictElement = dictIter->second;
342 }
343 return dictElement;
344 }
345
346 void
SetDictElementArgument(wxPdfCffDictionary * dict,int key,wxMemoryOutputStream & buffer)347 wxPdfFontSubsetCff::SetDictElementArgument(wxPdfCffDictionary* dict, int key, wxMemoryOutputStream& buffer)
348 {
349 wxPdfCffDictElement* dictElement = FindDictElement(dict, key);
350 if (dictElement != NULL)
351 {
352 dictElement->GetArgument()->SetBuffer(buffer);
353 }
354 else
355 {
356 wxPdfCffIndexElement* argument = new wxPdfCffIndexElement(buffer);
357 dictElement = new wxPdfCffDictElement(key, argument);
358 (*dict)[key] = dictElement;
359 }
360 }
361
362 void
RemoveDictElement(wxPdfCffDictionary * dict,int key)363 wxPdfFontSubsetCff::RemoveDictElement(wxPdfCffDictionary* dict, int key)
364 {
365 wxPdfCffDictionary::iterator dictIter = dict->find(key);
366 if (dictIter != dict->end())
367 {
368 delete dictIter->second;
369 dict->erase(dictIter);
370 }
371 }
372
373 bool
ReadFdSelect()374 wxPdfFontSubsetCff::ReadFdSelect()
375 {
376 bool ok = true;
377 int type, numRanges, first, last, fd, j, k;
378
379 m_fdSelect.SetCount(m_numGlyphs);
380
381 type = ReadByte();
382 if (type == 0)
383 {
384 for (j = 0; j < m_numGlyphs; j++)
385 {
386 m_fdSelect[j] = ReadByte();
387 }
388 }
389 else if (type == 3)
390 {
391 numRanges = ReadShort();
392 last = ReadShort();
393 for (k = 0; k < numRanges; k++)
394 {
395 first = last;
396 fd = ReadByte();
397 last = ReadShort();
398 for (j = first; j < last; j++)
399 {
400 m_fdSelect[j] = fd;
401 }
402 }
403 }
404 else
405 {
406 ok = false;
407 }
408 return ok;
409 }
410
411 bool
ReadPrivateDict(wxPdfCffDictionary * privateDict,wxPdfCffIndexArray * localSubrIndex,int offset,int size)412 wxPdfFontSubsetCff::ReadPrivateDict(wxPdfCffDictionary* privateDict, wxPdfCffIndexArray* localSubrIndex, int offset, int size)
413 {
414 bool ok = ReadFontDict(privateDict, offset, size);
415 if (ok)
416 {
417 wxPdfCffDictElement* localSubOp = FindDictElement(privateDict, LOCAL_SUB_OP);
418 if (localSubOp != NULL)
419 {
420 SeekI((localSubOp->GetArgument())->GetOffset());
421 int localSubOffset = DecodeInteger();
422 SeekI(offset+localSubOffset);
423 ok = ReadFontIndex(localSubrIndex);
424 if (ok)
425 {
426 wxMemoryOutputStream buffer;
427 EncodeIntegerMax(0, buffer);
428 SetDictElementArgument(privateDict, LOCAL_SUB_OP, buffer);
429 }
430 }
431 }
432 return ok;
433 }
434
435 bool
ReadCidFontDict()436 wxPdfFontSubsetCff::ReadCidFontDict()
437 {
438 wxPdfCffIndexArray index;
439 bool ok = ReadFontIndex(&index);
440
441 m_numFontDicts = (int) index.GetCount();
442 m_fdDict.SetCount(m_numFontDicts);
443 m_fdPrivateDict.SetCount(m_numFontDicts);
444 m_fdLocalSubrIndex.SetCount(m_numFontDicts);
445
446 int j, size, offset;
447 for (j = 0; ok && (j < m_numFontDicts); j++)
448 {
449 m_fdDict[j] = new wxPdfCffDictionary();
450 wxPdfCffIndexElement& element = index[j];
451 ok = ReadFontDict((wxPdfCffDictionary*) m_fdDict[j], element.GetOffset(), element.GetLength());
452 if (ok)
453 {
454 wxPdfCffDictElement* privateOp = FindDictElement((wxPdfCffDictionary*) m_fdDict[j], PRIVATE_OP);
455 ok = (privateOp == NULL);
456 if (ok)
457 {
458 SeekI((privateOp->GetArgument())->GetOffset());
459 size = DecodeInteger();
460 offset = DecodeInteger();
461 SeekI(offset);
462 m_fdPrivateDict[j] = new wxPdfCffDictionary();
463 m_fdLocalSubrIndex[j] = new wxPdfCffIndexArray();
464 ok = ReadPrivateDict((wxPdfCffDictionary*) m_fdPrivateDict[j], (wxPdfCffIndexArray*) m_fdLocalSubrIndex[j], offset, size);
465 if (ok)
466 {
467 wxMemoryOutputStream buffer;
468 EncodeIntegerMax(0, buffer);
469 EncodeIntegerMax(0, buffer);
470 SetDictElementArgument((wxPdfCffDictionary*) m_fdDict[j], PRIVATE_OP, buffer);
471 }
472 }
473 }
474 }
475 return ok;
476 }
477
478 bool
ReadTopDict()479 wxPdfFontSubsetCff::ReadTopDict()
480 {
481 wxPdfCffIndexArray index;
482 bool ok = ReadFontIndex(&index);
483 int savePosition = TellI();
484 // index now contains the top dictionary index
485
486 // Now search the first entry (of a multi font index)
487 if (!ok || index.IsEmpty())
488 {
489 return false;
490 }
491 wxPdfCffIndexElement& element = index[0];
492
493 ReadFontDict(m_topDict, element.GetOffset(), element.GetLength());
494
495 wxPdfCffDictElement* rosOp = FindDictElement(m_topDict, ROS_OP);
496 m_isCid = rosOp != NULL;
497
498 int offset, size;
499 wxPdfCffDictElement* charstringsOp = FindDictElement(m_topDict, CHARSTRINGS_OP);
500 ok = (charstringsOp != NULL);
501 if (ok)
502 {
503 SeekI((charstringsOp->GetArgument())->GetOffset());
504 offset = DecodeInteger();
505 SeekI(offset);
506 ok = ReadFontIndex(m_charstringsIndex);
507 }
508 if (!ok)
509 {
510 return false;
511 }
512 m_numGlyphs = (int) m_charstringsIndex->GetCount();
513
514 if (m_isCid)
515 {
516 wxPdfCffDictElement* fdselectOp = FindDictElement(m_topDict, FDSELECT_OP);
517 ok = (fdselectOp != NULL);
518 if (ok)
519 {
520 SeekI((fdselectOp->GetArgument())->GetOffset());
521 offset = DecodeInteger();
522 SeekI(offset);
523 ok = ReadFdSelect();
524 }
525 if (ok)
526 {
527 wxPdfCffDictElement* fdarrayOp = FindDictElement(m_topDict, FDARRAY_OP);
528 ok = (fdarrayOp != NULL);
529 if (ok)
530 {
531 SeekI((fdarrayOp->GetArgument())->GetOffset());
532 offset = DecodeInteger();
533 SeekI(offset);
534 ok = ReadCidFontDict();
535 }
536 }
537 }
538 else
539 {
540 wxPdfCffDictElement* privateOp = FindDictElement(m_topDict, PRIVATE_OP);
541 SeekI((privateOp->GetArgument())->GetOffset());
542 size = DecodeInteger();
543 offset = DecodeInteger();
544 SeekI(offset);
545 ok = ReadPrivateDict(m_privateDict, m_localSubrIndex, offset, size);
546 }
547
548 if (ok)
549 {
550 // Use maximum sized encoding to reserve space for later modification
551 wxMemoryOutputStream buffer;
552 EncodeIntegerMax(0, buffer);
553 SetDictElementArgument(m_topDict, CHARSTRINGS_OP, buffer);
554 SetDictElementArgument(m_topDict, FDSELECT_OP, buffer);
555 SetDictElementArgument(m_topDict, FDARRAY_OP, buffer);
556 SetDictElementArgument(m_topDict, CHARSET_OP, buffer);
557 RemoveDictElement(m_topDict, ENCODING_OP);
558 RemoveDictElement(m_topDict, PRIVATE_OP);
559 // Remove unique identifier operators as the subsetted font is not the same as the original font
560 RemoveDictElement(m_topDict, UNIQUEID_OP);
561 RemoveDictElement(m_topDict, XUID_OP);
562 }
563 SeekI(savePosition);
564 return ok;
565 }
566
567 bool
ReadStrings()568 wxPdfFontSubsetCff::ReadStrings()
569 {
570 return ReadFontIndex(m_stringsIndex);
571 }
572
573 bool
ReadGlobalSubroutines()574 wxPdfFontSubsetCff::ReadGlobalSubroutines()
575 {
576 return ReadFontIndex(m_globalSubrIndex);
577 }
578
579 void
SeekI(int offset)580 wxPdfFontSubsetCff::SeekI(int offset)
581 {
582 m_inFont->SeekI(offset);
583 }
584
585 int
TellI()586 wxPdfFontSubsetCff::TellI()
587 {
588 return (int) m_inFont->TellI();
589 }
590
591 void
SeekO(int offset)592 wxPdfFontSubsetCff::SeekO(int offset)
593 {
594 m_outFont->SeekO(offset);
595 }
596
597 int
TellO()598 wxPdfFontSubsetCff::TellO()
599 {
600 return (int) m_outFont->TellO();
601 }
602
603 int
GetSizeI()604 wxPdfFontSubsetCff::GetSizeI()
605 {
606 return (int) m_inFont->GetSize();
607 }
608
609 unsigned char
ReadByte()610 wxPdfFontSubsetCff::ReadByte()
611 {
612 unsigned char card8;
613 m_inFont->Read(&card8, 1);
614 return card8;
615 }
616
617 short
ReadShort()618 wxPdfFontSubsetCff::ReadShort()
619 {
620 // Read a 2-byte integer from file (big endian)
621 short i16;
622 m_inFont->Read(&i16, 2);
623 return wxINT16_SWAP_ON_LE(i16);
624 }
625
626 int
ReadInt()627 wxPdfFontSubsetCff::ReadInt()
628 {
629 // Read a 4-byte integer from file (big endian)
630 int i32;
631 m_inFont->Read(&i32, 4);
632 return wxINT32_SWAP_ON_LE(i32);
633 }
634
635 int
ReadOffset(int offSize)636 wxPdfFontSubsetCff::ReadOffset(int offSize)
637 {
638 int offset = 0;
639 int j;
640 for (j = 0; j < offSize; j++)
641 {
642 offset *= 256;
643 offset += (int) ReadByte();
644 }
645 return offset;
646 }
647
648 /* return 0 if not an operand */
649 int
ReadOperandLength()650 wxPdfFontSubsetCff::ReadOperandLength()
651 {
652 int operandLength = 0;
653 int begin = TellI();
654 unsigned char b0 = ReadByte();
655
656 if (b0 == 28)
657 {
658 operandLength = 3;
659 }
660 else if (b0 == 29)
661 {
662 operandLength = 5;
663 }
664 else if (b0 >= 32 && b0 <= 246)
665 {
666 operandLength = 1;
667 }
668 else if (b0 >= 247 && b0 <= 254)
669 {
670 operandLength = 2;
671 }
672 else if (b0 == 30)
673 {
674
675 while ((b0 & 0x0f) != 0x0f)
676 {
677 b0 = ReadByte();
678 }
679 operandLength = TellI() - begin;
680 }
681 return operandLength;
682 }
683
684 int
ReadOperator()685 wxPdfFontSubsetCff::ReadOperator()
686 {
687 int op = ReadByte();
688 if (op == 12)
689 {
690 op <<= 8;
691 op |= ReadByte();;
692 }
693 return op;
694 }
695
696 wxString
ReadString(int length)697 wxPdfFontSubsetCff::ReadString(int length)
698 {
699 wxString str = wxEmptyString;
700 if (length > 0)
701 {
702 char* buffer = new char[length];
703 m_inFont->Read(buffer, length);
704 int j;
705 for (j = 0; j < length; j++)
706 {
707 str.Append(buffer[j]);
708 }
709 delete [] buffer;
710 }
711 return str;
712 }
713
714 int
DecodeInteger()715 wxPdfFontSubsetCff::DecodeInteger()
716 {
717 int result = 0;
718 unsigned char b0, b1;
719
720 b0 = ReadByte();
721 if (b0 == 28)
722 {
723 result = ReadShort();
724 }
725 else if (b0 == 29)
726 {
727 result = ReadInt();
728 }
729 else if (b0 >= 32 && b0 <= 246)
730 {
731 result = b0 - 139;
732 }
733 else if (b0 >= 247 && b0 <= 250)
734 {
735 b1 = ReadByte();
736 result = (b0-247)*256 + b1 + 108;
737 }
738 else if (b0 >= 251 && b0 <= 254)
739 {
740 b1 = ReadByte();
741 result = -(b0-251)*256 - b1 - 108;
742 }
743 else
744 {
745 result = 0;
746 }
747 return result;
748 }
749
750 void
EncodeIntegerMax(int value,wxMemoryOutputStream & buffer)751 wxPdfFontSubsetCff::EncodeIntegerMax(int value, wxMemoryOutputStream& buffer)
752 {
753 char locBuffer[5];
754 locBuffer[0] = 29;
755 locBuffer[1] = (char)((value >> 24) & 0xff);
756 locBuffer[2] = (char)((value >> 16) & 0xff);
757 locBuffer[3] = (char)((value >> 8) & 0xff);
758 locBuffer[4] = (char)((value ) & 0xff);
759 buffer.Write(locBuffer, 5);
760 }
761
762 void
EncodeInteger(int value,wxMemoryOutputStream & buffer)763 wxPdfFontSubsetCff::EncodeInteger(int value, wxMemoryOutputStream& buffer)
764 {
765 char locBuffer[5];
766 size_t count;
767 if (value >= -107 && value <= 107)
768 {
769 locBuffer[0] = value + 139;
770 count = 1;
771 }
772 else if (value >= 108 && value <= 1131)
773 {
774 value -= 108;
775 locBuffer[0] = (char)(((value >> 8) + 247) & 0xff);
776 locBuffer[1] = (char)(((value ) ) & 0xff);
777 count = 2;
778 }
779 else if (value >= -1131 && value <= -108)
780 {
781 value = -value - 108;
782 locBuffer[0] = (char)(((value >> 8) + 251) & 0xff);
783 locBuffer[1] = (char)(((value ) ) & 0xff);
784 count = 2;
785 }
786 else if (value >= -32768 && value <= 32767)
787 {
788 locBuffer[0] = 28;
789 locBuffer[1] = (char)((value >> 8) & 0xff);
790 locBuffer[2] = (char)((value ) & 0xff);
791 count = 3;
792 }
793 else
794 {
795 locBuffer[0] = 29;
796 locBuffer[1] = (char)((value >> 24) & 0xff);
797 locBuffer[2] = (char)((value >> 16) & 0xff);
798 locBuffer[3] = (char)((value >> 8) & 0xff);
799 locBuffer[4] = (char)((value ) & 0xff);
800 count = 5;
801 }
802 buffer.Write(locBuffer, count);
803 }
804
805 // --- Generate subset
806
807 void
SetRosStrings()808 wxPdfFontSubsetCff::SetRosStrings()
809 {
810 int sid1, sid2;
811 sid1 = NUM_STD_STRINGS + (int) m_stringsSubsetIndex->GetCount();
812 wxPdfCffIndexElement* registry = new wxPdfCffIndexElement("Adobe");
813 m_stringsSubsetIndex->Add(registry);
814
815 sid2 = NUM_STD_STRINGS + (int) m_stringsSubsetIndex->GetCount();
816 wxPdfCffIndexElement* ordering = new wxPdfCffIndexElement("Identity");
817 m_stringsSubsetIndex->Add(ordering);
818
819 wxMemoryOutputStream rosBuffer;
820 EncodeInteger(sid1, rosBuffer);
821 EncodeInteger(sid2, rosBuffer);
822 EncodeInteger(0, rosBuffer);
823 SetDictElementArgument(m_topDict, ROS_OP, rosBuffer);
824
825 wxMemoryOutputStream cidBuffer;
826 EncodeInteger(m_numGlyphsUsed, cidBuffer);
827 SetDictElementArgument(m_topDict, CIDCOUNT_OP, cidBuffer);
828 }
829
830 void
SubsetCharstrings()831 wxPdfFontSubsetCff::SubsetCharstrings()
832 {
833 int numGlyphsUsed = (int) m_usedGlyphs.GetCount();
834 int usedGlyph;
835 for (int j = 0; j < numGlyphsUsed; j++)
836 {
837 usedGlyph = m_usedGlyphs[j];
838 m_charstringsSubsetIndex->Add((*m_charstringsIndex)[usedGlyph]);
839 }
840 }
841
842 void
SubsetFontDict()843 wxPdfFontSubsetCff::SubsetFontDict()
844 {
845 m_fdSelectSubset.SetCount(m_numGlyphsUsed);
846 m_fdSubsetMap.SetCount(m_numFontDicts);
847 m_privateDictOffset.SetCount(m_numFontDicts);
848 wxArrayInt reverseMap;
849 reverseMap.SetCount(m_numFontDicts);
850 int j;
851 for (j = 0; j < m_numFontDicts; j++)
852 {
853 reverseMap[j] = -1;
854 }
855 m_numSubsetFontDicts = 0;
856 int fd;
857 for (j = 0; j < m_numGlyphsUsed; j++)
858 {
859 fd = m_fdSelect[m_usedGlyphs[j]];
860 if (reverseMap[fd] < 0)
861 {
862 m_fdSubsetMap[m_numSubsetFontDicts] = fd;
863 reverseMap[fd] = m_numSubsetFontDicts++;
864 }
865 m_fdSelectSubset[j] = reverseMap[fd];
866 }
867 }
868
869 void
CreateCidFontDict()870 wxPdfFontSubsetCff::CreateCidFontDict()
871 {
872 m_numFontDicts = 1;
873 wxPdfCffDictionary* fdDict = new wxPdfCffDictionary();
874 m_fdDict.Add(fdDict);
875 m_fdSubsetMap.SetCount(1);
876 m_fdSubsetMap[0] = 0;
877 m_privateDictOffset.SetCount(1);
878 m_numSubsetFontDicts = 1;
879
880 wxMemoryOutputStream buffer;
881 EncodeIntegerMax(0, buffer);
882 EncodeIntegerMax(0, buffer);
883 SetDictElementArgument(fdDict, PRIVATE_OP, buffer);
884 }
885
886 void
SubsetDictString(wxPdfCffDictionary * dict,int op)887 wxPdfFontSubsetCff::SubsetDictString(wxPdfCffDictionary* dict, int op)
888 {
889 wxPdfCffDictElement* element = FindDictElement(dict, op);
890 if (element != NULL)
891 {
892 SeekI((element->GetArgument())->GetOffset());
893 int sid = DecodeInteger();
894 if (sid >= NUM_STD_STRINGS)
895 {
896 int sidNew = NUM_STD_STRINGS + (int) m_stringsSubsetIndex->GetCount();
897 m_stringsSubsetIndex->Add((*m_stringsIndex)[sid-NUM_STD_STRINGS]);
898 wxMemoryOutputStream buffer;
899 EncodeInteger(sidNew, buffer);
900 SetDictElementArgument(dict, op, buffer);
901 }
902 }
903 }
904
905 void
SubsetDictStrings(wxPdfCffDictionary * dict)906 wxPdfFontSubsetCff::SubsetDictStrings(wxPdfCffDictionary* dict)
907 {
908 static const int dictStrings[] = {
909 VERSION_OP, NOTICE_OP, COPYRIGHT_OP, FULLNAME_OP, FAMILYNAME_OP,
910 WEIGHT_OP, POSTSCRIPT_OP, BASEFONTNAME_OP, FONTNAME_OP,
911 -1
912 };
913 int j;
914 for (j = 0; dictStrings[j] >= 0; j++)
915 {
916 SubsetDictString(dict, dictStrings[j]);
917 }
918 }
919
920 void
SubsetStrings()921 wxPdfFontSubsetCff::SubsetStrings()
922 {
923 int j;
924 SubsetDictStrings(m_topDict);
925 if (m_isCid)
926 {
927 for (j = 0; j < m_numSubsetFontDicts; j++)
928 {
929 SubsetDictStrings((wxPdfCffDictionary*) m_fdDict[m_fdSubsetMap[j]]);
930 SubsetDictStrings((wxPdfCffDictionary*) m_fdPrivateDict[m_fdSubsetMap[j]]);
931 }
932 }
933 else
934 {
935 SubsetDictStrings(m_privateDict);
936 }
937 }
938
939 void
GenerateFontSubset()940 wxPdfFontSubsetCff::GenerateFontSubset()
941 {
942 FindLocalAndGlobalSubrsUsed();
943 SetRosStrings();
944 SubsetCharstrings();
945 if (m_isCid)
946 {
947 SubsetFontDict();
948 }
949 else
950 {
951 CreateCidFontDict();
952 }
953 SubsetStrings();
954 }
955
956 // --- Write subset
957
958 void
WriteInteger(int value,int size,wxMemoryOutputStream * buffer)959 wxPdfFontSubsetCff::WriteInteger(int value, int size, wxMemoryOutputStream* buffer)
960 {
961 char locBuffer[4];
962 int i = 0;
963 switch (size)
964 {
965 case 4:
966 locBuffer[i] = (char)((value >> 24) & 0xff);
967 i++;
968 case 3:
969 locBuffer[i] = (char)((value >> 16) & 0xff);
970 i++;
971 case 2:
972 locBuffer[i] = (char)((value >> 8) & 0xff);
973 i++;
974 case 1:
975 locBuffer[i] = (char)((value ) & 0xff);
976 i++;
977 default:
978 break;
979 }
980 buffer->Write(locBuffer, i);
981 }
982
983
984 void
WriteIndex(wxPdfCffIndexArray * index)985 wxPdfFontSubsetCff::WriteIndex(wxPdfCffIndexArray* index)
986 {
987 int numElements = (int) index->GetCount();
988 WriteInteger(numElements, 2, m_outFont);
989 if (numElements == 0)
990 {
991 return;
992 }
993 // Find maximum offset to determine offset size
994 int j, offsetSize;
995 int offset = 1;
996 for (j = 0; j < numElements; j++)
997 {
998 offset += (*index)[j].GetLength();
999 }
1000 if (offset < 0x100)
1001 {
1002 offsetSize = 1;
1003 }
1004 else if (offset < 0x10000)
1005 {
1006 offsetSize = 2;
1007 }
1008 else if (offset < 0x1000000)
1009 {
1010 offsetSize = 3;
1011 }
1012 else
1013 {
1014 offsetSize = 4;
1015 }
1016 WriteInteger(offsetSize, 1, m_outFont);
1017 offset = 1;
1018 WriteInteger(offset, offsetSize, m_outFont);
1019 for (j = 0; j < numElements; j++)
1020 {
1021 offset += (*index)[j].GetLength();
1022 WriteInteger(offset, offsetSize, m_outFont);
1023 }
1024 for (j = 0; j < numElements; j++)
1025 {
1026 (*index)[j].Emit(*m_outFont);
1027 }
1028 }
1029
1030 void
WriteHeader()1031 wxPdfFontSubsetCff::WriteHeader()
1032 {
1033 wxPdfCffIndexElement header(m_inFont, 0, m_hdrSize);
1034 header.Emit(*m_outFont);
1035 }
1036
1037 void
WriteName()1038 wxPdfFontSubsetCff::WriteName()
1039 {
1040 // TODO: Write subset font name
1041 //wxMemoryOutputStream nameBuffer;
1042 //nameBuffer.Write("font-name-dummy",strlen("font-name-dummy"));
1043 wxMemoryOutputStream buffer;
1044 int len = (int) m_fontName.Length();
1045 int j;
1046 for (j = 0; j < len; j++)
1047 {
1048 char ch = (char)(m_fontName[j]) & 0xff;
1049 buffer.Write(&ch, 1);
1050 }
1051 wxPdfCffIndexArray index;
1052 index.Add(wxPdfCffIndexElement(buffer));
1053 WriteIndex(&index);
1054 }
1055
1056 void
WriteTopDict()1057 wxPdfFontSubsetCff::WriteTopDict()
1058 {
1059 int offsetSize = 4;
1060 int offsetIndex;
1061 int dictStart, dictSize;
1062 WriteInteger(1, 2, m_outFont);
1063 WriteInteger(offsetSize, 1, m_outFont);
1064 WriteInteger(1, offsetSize, m_outFont);
1065 offsetIndex = TellO();
1066 WriteInteger(0, offsetSize, m_outFont);
1067 dictStart = TellO();
1068 WriteDict(m_topDict);
1069 int lastPosition = TellO();
1070 dictSize = lastPosition - dictStart + 1;
1071 SeekO(offsetIndex);
1072 WriteInteger(dictSize, offsetSize, m_outFont);
1073 SeekO(lastPosition);
1074 }
1075
1076 void
WriteDict(wxPdfCffDictionary * dict)1077 wxPdfFontSubsetCff::WriteDict(wxPdfCffDictionary* dict)
1078 {
1079 // If there is a ROS operator it has to be the first according to the CFF specification
1080 wxPdfCffDictElement* rosOp = FindDictElement(dict, ROS_OP);
1081 if (rosOp != NULL)
1082 {
1083 WriteDictOperator(rosOp);
1084 }
1085 wxPdfCffDictionary::iterator dictEntry = dict->begin();
1086 for (dictEntry = dict->begin(); dictEntry != dict->end(); dictEntry++)
1087 {
1088 // The ROS operator is handled separately
1089 if ((dictEntry->second)->GetOperator() != ROS_OP)
1090 {
1091 WriteDictOperator(dictEntry->second);
1092 }
1093 }
1094 }
1095
1096 void
WriteDictOperator(wxPdfCffDictElement * dictElement)1097 wxPdfFontSubsetCff::WriteDictOperator(wxPdfCffDictElement* dictElement)
1098 {
1099 int offset = TellO();
1100 dictElement->SetArgumentOffset(offset);
1101 dictElement->GetArgument()->Emit(*m_outFont);
1102 int op = dictElement->GetOperator();
1103 if (op & 0xff00)
1104 {
1105 WriteInteger((op >> 8) & 0xff, 1, m_outFont);
1106 }
1107 WriteInteger(op & 0xff, 1, m_outFont);
1108 }
1109
1110 void
WriteStrings()1111 wxPdfFontSubsetCff::WriteStrings()
1112 {
1113 WriteIndex(m_stringsSubsetIndex);
1114 }
1115
1116 void
WriteGlobalSubrs()1117 wxPdfFontSubsetCff::WriteGlobalSubrs()
1118 {
1119 WriteIndex(m_globalSubrIndex);
1120 }
1121
1122 /* Set the operand of the specified operator in the (already written)
1123 * top dict to point to the current position in the output
1124 * array. Operands updated with this function must have previously
1125 * been encoded with the 5-byte (max) integer encoding. */
1126 int
GetLocation(wxPdfCffDictionary * dict,int op)1127 wxPdfFontSubsetCff::GetLocation(wxPdfCffDictionary* dict, int op)
1128 {
1129 int offset = -1;
1130 wxPdfCffDictElement* dictElement = FindDictElement(dict, op);
1131 if (dictElement != NULL)
1132 {
1133 offset = dictElement->GetArgumentOffset();
1134 }
1135 return offset;
1136 }
1137
1138 void
SetTopDictOperatorToCurrentPosition(int op)1139 wxPdfFontSubsetCff::SetTopDictOperatorToCurrentPosition(int op)
1140 {
1141 int currentPosition = TellO();
1142 int offset = GetLocation(m_topDict, op);
1143 if (offset >= 0)
1144 {
1145 SeekO(offset);
1146 EncodeIntegerMax(currentPosition, *m_outFont);
1147 SeekO(currentPosition);
1148 }
1149 }
1150
1151 void
WriteCharset()1152 wxPdfFontSubsetCff::WriteCharset()
1153 {
1154 SetTopDictOperatorToCurrentPosition(CHARSET_OP);
1155 WriteInteger(2, 1, m_outFont);
1156 WriteInteger(1, 2, m_outFont);
1157 WriteInteger(m_numGlyphsUsed-2, 2, m_outFont);
1158 }
1159
1160 void
WriteFdSelect()1161 wxPdfFontSubsetCff::WriteFdSelect()
1162 {
1163 SetTopDictOperatorToCurrentPosition(FDSELECT_OP);
1164 if (m_isCid)
1165 {
1166 WriteInteger(0, 1, m_outFont);
1167 int j;
1168 for (j = 0; j < m_numGlyphsUsed; j++)
1169 {
1170 WriteInteger(m_fdSelectSubset[j], 1, m_outFont);
1171 }
1172 }
1173 else
1174 {
1175 WriteInteger(3, 1, m_outFont);
1176 WriteInteger(1, 2, m_outFont);
1177 WriteInteger(0, 2, m_outFont);
1178 WriteInteger(0, 1, m_outFont);
1179 WriteInteger(m_numGlyphsUsed, 2, m_outFont);
1180 }
1181 }
1182
1183 void
WriteCharStrings()1184 wxPdfFontSubsetCff::WriteCharStrings()
1185 {
1186 SetTopDictOperatorToCurrentPosition(CHARSTRINGS_OP);
1187 WriteIndex(m_charstringsSubsetIndex);
1188 }
1189
1190 void
WriteCidFontDict()1191 wxPdfFontSubsetCff::WriteCidFontDict()
1192 {
1193 int offsetSize = 4;
1194 SetTopDictOperatorToCurrentPosition(FDARRAY_OP);
1195 WriteInteger(m_numSubsetFontDicts, 2, m_outFont);
1196 WriteInteger(offsetSize, 1, m_outFont);
1197
1198 int offsetBase = TellO();
1199 WriteInteger(1, offsetSize, m_outFont);
1200 int j;
1201 for (j = 0; j < m_numSubsetFontDicts; j++)
1202 {
1203 WriteInteger(0, offsetSize, m_outFont);
1204 }
1205 int offset = 0;
1206 int offsetDict;
1207 for (j = 0; j < m_numSubsetFontDicts; j++)
1208 {
1209 WriteDict((wxPdfCffDictionary*) m_fdDict[m_fdSubsetMap[j]]);
1210 offsetDict = TellO();
1211 offset += offsetSize;
1212 SeekO(offsetBase+offset);
1213 WriteInteger(offsetDict-offsetBase+1, offsetSize, m_outFont);
1214 SeekO(offsetDict);
1215 }
1216 }
1217
1218 void
WritePrivateDict(int dictNum,wxPdfCffDictionary * parentDict,wxPdfCffDictionary * privateDict)1219 wxPdfFontSubsetCff::WritePrivateDict(int dictNum, wxPdfCffDictionary* parentDict, wxPdfCffDictionary* privateDict)
1220 {
1221 // Write private dict and update offset and size in top dict
1222 m_privateDictOffset[dictNum] = TellO();
1223 WriteDict(privateDict);
1224
1225 // private entry has two operands - size and offset
1226 int lastPosition = TellO();
1227 int size = lastPosition - m_privateDictOffset[dictNum];
1228 int offset = GetLocation(parentDict, PRIVATE_OP);
1229 SeekO(offset);
1230 EncodeIntegerMax(size, *m_outFont);
1231 EncodeIntegerMax(m_privateDictOffset[dictNum], *m_outFont);
1232 SeekO(lastPosition);
1233 }
1234
1235 void
WriteLocalSub(int dictNum,wxPdfCffDictionary * privateDict,wxPdfCffIndexArray * localSubrIndex)1236 wxPdfFontSubsetCff::WriteLocalSub(int dictNum, wxPdfCffDictionary* privateDict, wxPdfCffIndexArray* localSubrIndex)
1237 {
1238 if (localSubrIndex->GetCount() > 0)
1239 {
1240 // Write local subroutines and update offset in private dict
1241 // Local subroutines offset is relative to start of private dict
1242 int lastPosition = TellO();
1243 int offset = lastPosition - m_privateDictOffset[dictNum];
1244 int localSubOffset = GetLocation(privateDict, LOCAL_SUB_OP);
1245 SeekO(localSubOffset);
1246 EncodeIntegerMax(offset, *m_outFont);
1247 SeekO(lastPosition);
1248 WriteIndex(localSubrIndex);
1249 }
1250 }
1251
1252 void
WriteCidPrivateDictAndLocalSub()1253 wxPdfFontSubsetCff::WriteCidPrivateDictAndLocalSub()
1254 {
1255 if (m_isCid)
1256 {
1257 int j;
1258 for (j = 0; j < m_numSubsetFontDicts; j++)
1259 {
1260 WritePrivateDict(j, (wxPdfCffDictionary*) m_fdDict[m_fdSubsetMap[j]], (wxPdfCffDictionary*) m_fdPrivateDict[m_fdSubsetMap[j]]);
1261 }
1262 for (j = 0; j < m_numSubsetFontDicts; j++)
1263 {
1264 WriteLocalSub(j, (wxPdfCffDictionary*) m_fdPrivateDict[m_fdSubsetMap[j]], (wxPdfCffIndexArray*) m_fdLocalSubrIndex[m_fdSubsetMap[j]]);
1265 }
1266 }
1267 else
1268 {
1269 WritePrivateDict(0, (wxPdfCffDictionary*) m_fdDict[0], m_privateDict);
1270 WriteLocalSub(0, m_privateDict, m_localSubrIndex);
1271 }
1272 }
1273
1274 #include <wx/zstream.h>
1275
1276 void
WriteFontSubset()1277 wxPdfFontSubsetCff::WriteFontSubset()
1278 {
1279 m_outFont = new wxMemoryOutputStream();
1280 WriteHeader();
1281 WriteName();
1282 WriteTopDict();
1283 WriteStrings();
1284 WriteGlobalSubrs();
1285 WriteCharset();
1286 WriteFdSelect();
1287 WriteCharStrings();
1288 WriteCidFontDict();
1289 WriteCidPrivateDictAndLocalSub();
1290
1291 #if 0
1292 wxFileOutputStream cffSubset(wxS("cffsubset.dat"));
1293 wxMemoryInputStream tmp(*m_outFont);
1294 cffSubset.Write(tmp);
1295 cffSubset.Close();
1296 #endif
1297 #if 0
1298 wxLogMessage(wxS("-- Dump outFont --"));
1299 char locBuffer[1024];
1300 tmp.SeekI(0);
1301 int copyLength = tmp.GetLength();
1302 int bufferLength;
1303 while (copyLength > 0)
1304 {
1305 bufferLength = (copyLength > 1024) ? 1024 : copyLength;
1306 tmp.Read(locBuffer, bufferLength);
1307 copyLength -= bufferLength;
1308 wxString str;
1309 int kk;
1310 for (kk = 0; kk < bufferLength; kk++)
1311 {
1312 str += wxString::Format(wxS(" %d"), locBuffer[kk]);
1313 if (kk % 10 == 9)
1314 {
1315 wxLogDebug(str);
1316 str = wxEmptyString;
1317 }
1318 }
1319 if ((bufferLength-1) % 10 != 9)
1320 {
1321 wxLogDebug(str);
1322 }
1323 }
1324 #endif
1325 #if 0
1326 wxFileInputStream cairoIn(wxS("gfsdidot-test-cairo2.pdf"));
1327 cairoIn.SeekI(960);
1328 char cairoBuffer[18710];
1329 cairoIn.Read(cairoBuffer,18710);
1330 wxMemoryOutputStream cairoOut;
1331 cairoOut.Write(cairoBuffer,18710);
1332 cairoOut.Close();
1333 wxMemoryInputStream inCairo(cairoOut);
1334 wxZlibInputStream zinCairo(inCairo);
1335 wxFileOutputStream cairoCff(wxS("cairo-cff.dat"));
1336 cairoCff.Write(zinCairo);
1337 cairoCff.Close();
1338 #endif
1339 }
1340
1341 // -- Subset global and local subroutines
1342
1343 void
FindLocalAndGlobalSubrsUsed()1344 wxPdfFontSubsetCff::FindLocalAndGlobalSubrsUsed()
1345 {
1346 int nGlobalSubrs = (int) m_globalSubrIndex->GetCount();
1347 // Calc the Bias for the global subr index
1348 m_globalBias = m_decoder->CalcBias(nGlobalSubrs);
1349
1350 // If the font is CID then the lsubrs are divided into FontDicts.
1351 // for each FD array the lsubrs will be subsetted.
1352 if (m_isCid)
1353 {
1354 bool* fdDictUsed = new bool[m_numFontDicts];
1355 int j;
1356 for (j = 0; j < m_numFontDicts; j++)
1357 {
1358 fdDictUsed[j] = false;
1359 }
1360 int glyph, fd;
1361 for (j = 0; j < m_numGlyphsUsed; j++)
1362 {
1363 glyph = m_usedGlyphs[j];
1364 fd = m_fdSelect[glyph];
1365 fdDictUsed[fd] = true;
1366 }
1367 // For each FD array which is used subset the lsubr
1368 for (j = 0; j < m_numFontDicts; j++)
1369 {
1370 if (fdDictUsed[j])
1371 {
1372 wxPdfSortedArrayInt hSubrsUsed(CompareInts);
1373 wxArrayInt lSubrsUsed;
1374 //Scans the Charsting data storing the used Local and Global subroutines
1375 // by the glyphs. Scans the Subrs recursivley.
1376 FindSubrsUsed(j, *((wxPdfCffIndexArray*) m_fdLocalSubrIndex[j]), hSubrsUsed, lSubrsUsed);
1377 // Builds the New Local Subrs index
1378 SubsetSubrs(*((wxPdfCffIndexArray*) m_fdLocalSubrIndex[j]), hSubrsUsed);
1379 }
1380 }
1381 delete [] fdDictUsed;
1382 }
1383 else
1384 {
1385 //Scans the Charsting data storing the used Local and Global subroutines
1386 // by the glyphs. Scans the Subrs recursivley.
1387 FindSubrsUsed(-1, *m_localSubrIndex, *m_hLocalSubrsUsed, m_lLocalSubrsUsed);
1388 }
1389 // Subset the Global Subroutines
1390 // Scan the Global Subr Hashmap recursivly on the Gsubrs
1391 FindGlobalSubrsUsed();
1392 SubsetSubrs(*m_globalSubrIndex, *m_hGlobalSubrsUsed);
1393 if (!m_isCid)
1394 {
1395 SubsetSubrs(*m_localSubrIndex, *m_hLocalSubrsUsed);
1396 }
1397 }
1398
1399 void
SubsetSubrs(wxPdfCffIndexArray & subrIndex,wxPdfSortedArrayInt & subrsUsed)1400 wxPdfFontSubsetCff::SubsetSubrs(wxPdfCffIndexArray& subrIndex, wxPdfSortedArrayInt& subrsUsed)
1401 {
1402 size_t nSubrs = subrIndex.GetCount();
1403 if (nSubrs > 0)
1404 {
1405 size_t j;
1406 bool* isSubrUsed = new bool[nSubrs];
1407 int subr;
1408 for (j = 0; j < nSubrs; j++)
1409 {
1410 isSubrUsed[j] = false;
1411 }
1412 for (j = 0; j < subrsUsed.GetCount(); j++)
1413 {
1414 subr = subrsUsed[j];
1415 isSubrUsed[subr] = true;
1416 }
1417 wxMemoryOutputStream buffer;
1418 char subrReturnOp = SUBR_RETURN_OP;
1419 buffer.Write(&subrReturnOp, 1);
1420 buffer.Close();
1421 for (j = 0; j < nSubrs; j++)
1422 {
1423 if (!isSubrUsed[j])
1424 {
1425 wxPdfCffIndexElement& subrElement = subrIndex[j];
1426 subrElement.SetBuffer(buffer);
1427 }
1428 }
1429 delete [] isSubrUsed;
1430 }
1431 }
1432
1433 void
FindSubrsUsed(int fd,wxPdfCffIndexArray & localSubrIndex,wxPdfSortedArrayInt & hSubrsUsed,wxArrayInt & lSubrsUsed)1434 wxPdfFontSubsetCff::FindSubrsUsed(int fd, wxPdfCffIndexArray& localSubrIndex,
1435 wxPdfSortedArrayInt& hSubrsUsed, wxArrayInt& lSubrsUsed)
1436 {
1437 // Calc the Bias for the subr index
1438 int nSubrs = (int) localSubrIndex.GetCount();
1439 int localBias = m_decoder->CalcBias(nSubrs);
1440
1441 // For each glyph used find its GID, start & end pos
1442 size_t j;
1443 for (j = 0; j < m_usedGlyphs.GetCount(); j++)
1444 {
1445 int glyph = m_usedGlyphs.Item(j);
1446 int fdGlyph = (m_isCid) ? m_fdSelect[glyph] : -1;
1447
1448 if (fdGlyph == fd)
1449 {
1450 wxPdfCffIndexElement& charstring = (*m_charstringsIndex)[glyph];
1451 int beginChar = charstring.GetOffset();
1452 int endChar = beginChar + charstring.GetLength();
1453 m_decoder->ReadASubr(m_inFont, beginChar, endChar, m_globalBias, localBias, hSubrsUsed, lSubrsUsed, localSubrIndex);
1454 }
1455 }
1456 // For all Lsubrs used, check recusrivly for Lsubr & Gsubr used
1457 for (j = 0; j < lSubrsUsed.GetCount(); j++)
1458 {
1459 // Pop the subr value from the hash
1460 int subr = lSubrsUsed.Item(j);
1461 // Ensure the Lsubr call is valid
1462 if (subr < nSubrs && subr >= 0)
1463 {
1464 // Read and process the subr
1465 wxPdfCffIndexElement& localSub = localSubrIndex[subr];
1466 int start = localSub.GetOffset();
1467 int end = start + localSub.GetLength();
1468 m_decoder->ReadASubr(m_inFont, start, end, m_globalBias, localBias, hSubrsUsed, lSubrsUsed, localSubrIndex);
1469 }
1470 }
1471 }
1472
1473 void
FindGlobalSubrsUsed()1474 wxPdfFontSubsetCff::FindGlobalSubrsUsed()
1475 {
1476 int nGlobalSubrs = (int) m_globalSubrIndex->GetCount();
1477 int nLocalSubrs = (int) m_localSubrIndex->GetCount();
1478 int localBias = 0;
1479 size_t sizeOfNonCIDSubrsUsed = 0;
1480 if (!m_isCid)
1481 {
1482 // Calc the Bias for the local subr index
1483 localBias = m_decoder->CalcBias(nLocalSubrs);
1484 sizeOfNonCIDSubrsUsed = m_lLocalSubrsUsed.GetCount();
1485 }
1486
1487 // For each global subr used
1488 size_t k;
1489 for (k = 0; k < m_lGlobalSubrsUsed.GetCount(); k++)
1490 {
1491 //Pop the value + check valid
1492 int subr = m_lGlobalSubrsUsed.Item(k);
1493 if (subr < nGlobalSubrs && subr >= 0)
1494 {
1495 // Read the subr and process
1496 wxPdfCffIndexElement& globalSubr = (*m_globalSubrIndex)[subr];
1497 int start = globalSubr.GetOffset();
1498 int end = start + globalSubr.GetLength();
1499
1500 if (m_isCid)
1501 {
1502 wxPdfCffIndexArray dummy;
1503 m_decoder->ReadASubr(m_inFont, start, end, m_globalBias, 0, *m_hGlobalSubrsUsed, m_lGlobalSubrsUsed, dummy);
1504 }
1505 else
1506 {
1507 #if 0
1508 wxLogDebug(wxS("Call ReadASubr i=%d subr=%d"), i, subr);
1509 #endif
1510 m_decoder->ReadASubr(m_inFont, start, end, m_globalBias, localBias,
1511 *m_hLocalSubrsUsed, m_lLocalSubrsUsed, *m_localSubrIndex);
1512 if (sizeOfNonCIDSubrsUsed < m_lLocalSubrsUsed.GetCount())
1513 {
1514 size_t j;
1515 for (j = sizeOfNonCIDSubrsUsed; j < m_lLocalSubrsUsed.GetCount(); j++)
1516 {
1517 //Pop the value + check valid
1518 int lSubr = m_lLocalSubrsUsed.Item(j);
1519 #if 0
1520 wxLogDebug(wxS("Call ReadASubr j=%d subr=%d"), i, subr);
1521 #endif
1522 if (lSubr < nLocalSubrs && lSubr >= 0)
1523 {
1524 // Read the subr and process
1525 wxPdfCffIndexElement& localSubr = (*m_localSubrIndex)[lSubr];
1526 int lStart = localSubr.GetOffset();
1527 int lEnd = lStart + localSubr.GetLength();
1528 m_decoder->ReadASubr(m_inFont, lStart, lEnd, m_globalBias, localBias,
1529 *m_hLocalSubrsUsed, m_lLocalSubrsUsed, *m_localSubrIndex);
1530 }
1531 }
1532 sizeOfNonCIDSubrsUsed = m_lLocalSubrsUsed.GetCount();
1533 }
1534 }
1535 }
1536 }
1537 }
1538