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