1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        pdffontdatatruetype.cpp
3 // Purpose:
4 // Author:      Ulrich Telle
5 // Created:     2008-08-07
6 // Copyright:   (c) Ulrich Telle
7 // Licence:     wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 /// \file pdffontdatatruetype.cpp Implementation of wxPdfFontDataTrueType and wxPdfFontDataTrueTypeUnicode classes
11 
12 // For compilers that support precompilation, includes <wx.h>.
13 #include <wx/wxprec.h>
14 
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18 
19 #ifndef WX_PRECOMP
20 #include <wx/wx.h>
21 #endif
22 
23 // includes
24 #include <wx/filename.h>
25 #include <wx/filesys.h>
26 #include <wx/zstream.h>
27 
28 #include "wx/pdfarraytypes.h"
29 #include "wx/pdffontdatatruetype.h"
30 #include "wx/pdffontparser.h"
31 #include "wx/pdffontsubsettruetype.h"
32 #include "wx/pdffontvolt.h"
33 
34 // TrueType font
35 
wxPdfFontDataTrueType()36 wxPdfFontDataTrueType::wxPdfFontDataTrueType()
37   : wxPdfFontData()
38 {
39   m_type  = wxS("TrueType");
40   m_conv = NULL;
41 
42   m_embedRequired = false;
43   m_embedSupported = true;
44   m_subsetSupported = true;
45 }
46 
~wxPdfFontDataTrueType()47 wxPdfFontDataTrueType::~wxPdfFontDataTrueType()
48 {
49   if (m_conv != NULL)
50   {
51     delete m_conv;
52   }
53 }
54 
55 #if wxUSE_UNICODE
56 void
CreateDefaultEncodingConv()57 wxPdfFontDataTrueType::CreateDefaultEncodingConv()
58 {
59   // Unicode build needs charset conversion
60   if (m_conv == NULL)
61   {
62     if (m_enc.Length() > 0)
63     {
64       m_conv = new wxCSConv(m_enc);
65     }
66     else
67     {
68       m_conv = new wxCSConv(wxFONTENCODING_ISO8859_1);
69     }
70   }
71 }
72 #endif
73 
74 bool
LoadFontMetrics(wxXmlNode * root)75 wxPdfFontDataTrueType::LoadFontMetrics(wxXmlNode* root)
76 {
77   bool bName  = false,
78        bDesc  = false,
79        bFile  = true,
80        bSize  = true,
81        bWidth = false;
82   wxString value;
83   long number;
84   wxXmlNode *child = root->GetChildren();
85   while (child)
86   {
87     // parse the children
88     if (child->GetName() == wxS("font-name"))
89     {
90       m_name = GetNodeContent(child);
91       m_style = FindStyleFromName(m_name);
92       bName = m_name.Length() > 0;
93     }
94     else if (child->GetName() == wxS("encoding"))
95     {
96       m_enc = GetNodeContent(child);
97     }
98     else if (child->GetName() == wxS("description"))
99     {
100       bDesc = GetFontDescription(child, m_desc);
101     }
102     else if (child->GetName() == wxS("diff"))
103     {
104       m_diffs = GetNodeContent(child);
105     }
106     else if (child->GetName() == wxS("file"))
107     {
108 #if wxCHECK_VERSION(2,9,0)
109       value = child->GetAttribute(wxS("name"), wxS(""));
110 #else
111       value = child->GetPropVal(wxS("name"), wxS(""));
112 #endif
113       if (value.Length() > 0)
114       {
115         m_file = value;
116 #if wxCHECK_VERSION(2,9,0)
117         value = child->GetAttribute(wxS("originalsize"), wxS(""));
118 #else
119         value = child->GetPropVal(wxS("originalsize"), wxS(""));
120 #endif
121         if (value.Length() > 0 && value.ToLong(&number))
122         {
123           bFile = true;
124           m_size1 = number;
125         }
126         else
127         {
128           bFile = false;
129           m_file = wxS("");
130         }
131       }
132     }
133     else if (child->GetName() == wxS("widths"))
134     {
135 #if wxCHECK_VERSION(2,9,0)
136       wxString subsetting = child->GetAttribute(wxS("subsetting"), wxS("disabled"));
137 #else
138       wxString subsetting = child->GetPropVal(wxS("subsetting"), wxS("disabled"));
139 #endif
140       m_subsetSupported = (subsetting == wxS("enabled"));
141       bWidth = true;
142       m_cw = new wxPdfGlyphWidthMap();
143       if (m_subsetSupported)
144       {
145         m_gn = new wxPdfChar2GlyphMap();
146       }
147       const wxXmlNode *charNode = child->GetChildren();
148       while (charNode)
149       {
150         wxString strId, strGn, strWidth;
151         long charId, charWidth, glyph;
152         if (charNode->GetName() == wxS("char"))
153         {
154 #if wxCHECK_VERSION(2,9,0)
155           strId = charNode->GetAttribute(wxS("id"), wxS(""));
156           if (m_subsetSupported)
157           {
158             strGn = charNode->GetAttribute(wxS("gn"), wxS(""));
159           }
160           strWidth = charNode->GetAttribute(wxS("width"), wxS(""));
161 #else
162           strId = charNode->GetPropVal(wxS("id"), wxS(""));
163           if (m_subsetSupported)
164           {
165             strGn = charNode->GetPropVal(wxS("gn"), wxS(""));
166           }
167           strWidth = charNode->GetPropVal(wxS("width"), wxS(""));
168 #endif
169           if (strId.Length() > 0 && strId.ToLong(&charId) &&
170               strWidth.Length() > 0 && strWidth.ToLong(&charWidth))
171           {
172             (*m_cw)[charId] = charWidth;
173             if (m_subsetSupported)
174             {
175               if (strGn.Length() > 0 && strGn.ToLong(&glyph))
176               {
177                 (*m_gn)[charId] = glyph;
178               }
179               else
180               {
181                 (*m_gn)[charId] = 0;
182               }
183             }
184           }
185         }
186         charNode = charNode->GetNext();
187       }
188     }
189     child = child->GetNext();
190   }
191 
192 #if wxUSE_UNICODE
193   CreateDefaultEncodingConv();
194 #endif
195 
196   m_initialized = (bName && bDesc && bFile && bSize && bWidth);
197   if (m_initialized)
198   {
199     wxFileName fileName(m_file);
200     m_initialized = fileName.MakeAbsolute(m_path) && fileName.FileExists() && fileName.IsFileReadable();
201   }
202   return m_initialized;
203 }
204 
205 double
GetStringWidth(const wxString & s,const wxPdfEncoding * encoding,bool withKerning) const206 wxPdfFontDataTrueType::GetStringWidth(const wxString& s, const wxPdfEncoding* encoding, bool withKerning) const
207 {
208   wxUnusedVar(encoding);
209   // Get width of a string in the current font
210   double w = 0;
211 #if wxUSE_UNICODE
212   wxString t = ConvertToValid(s);
213   wxCharBuffer wcb(t.mb_str(*m_conv));
214   const char* str = (const char*) wcb;
215 #else
216   const char* str = s.c_str();
217 #endif
218 
219   wxPdfGlyphWidthMap::iterator charIter;
220   size_t i;
221   for (i = 0; i < s.Length(); i++)
222   {
223     charIter = m_cw->find((unsigned char) str[i]);
224     if (charIter != m_cw->end())
225     {
226       w += charIter->second;
227     }
228     else
229     {
230       w += m_desc.GetMissingWidth();
231     }
232   }
233   if (withKerning)
234   {
235     int kerningWidth = GetKerningWidth(s);
236     if (kerningWidth != 0)
237     {
238       w += (double) kerningWidth;
239     }
240   }
241   return w / 1000;
242 }
243 
244 bool
CanShow(const wxString & s,const wxPdfEncoding * encoding) const245 wxPdfFontDataTrueType::CanShow(const wxString& s, const wxPdfEncoding* encoding) const
246 {
247   wxUnusedVar(encoding);
248   bool canShow = true;
249 #if wxUSE_UNICODE
250   wxMBConv* conv = GetEncodingConv();
251   size_t len = conv->FromWChar(NULL, 0, s.wc_str(), s.length());
252   canShow = (len != wxCONV_FAILED);
253 #endif
254   return canShow;
255 }
256 
257 wxString
ConvertCID2GID(const wxString & s,const wxPdfEncoding * encoding,wxPdfSortedArrayInt * usedGlyphs,wxPdfChar2GlyphMap * subsetGlyphs) const258 wxPdfFontDataTrueType::ConvertCID2GID(const wxString& s,
259                                       const wxPdfEncoding* encoding,
260                                       wxPdfSortedArrayInt* usedGlyphs,
261                                       wxPdfChar2GlyphMap* subsetGlyphs) const
262 {
263   wxUnusedVar(encoding);
264   // Currently no cid to gid conversion is done
265   // only the list of used glyphs is updated
266   wxUnusedVar(subsetGlyphs);
267   if (usedGlyphs != NULL)
268   {
269     // Convert string according to the font encoding
270 #if wxUSE_UNICODE
271     size_t slen = s.length();
272     wxString t = ConvertToValid(s);
273     wxMBConv* conv = GetEncodingConv();
274     size_t len = conv->FromWChar(NULL, 0, t.wc_str(), slen);
275     char* mbstr = new char[len+3];
276     len = conv->FromWChar(mbstr, len+3, t.wc_str(), slen);
277 #else
278     size_t len = s.Length();;
279     char* mbstr = new char[len+1];
280     strcpy(mbstr,s.c_str());
281 #endif
282     // Update used glyph list
283     wxPdfChar2GlyphMap::const_iterator glyphIter;
284     size_t i;
285     for (i = 0; i < len; i++)
286     {
287       int ch = (int) mbstr[i];
288       glyphIter = m_gn->find(ch);
289       if (glyphIter != m_gn->end())
290       {
291         if (usedGlyphs->Index(glyphIter->second) == wxNOT_FOUND)
292         {
293           usedGlyphs->Add(glyphIter->second);
294         }
295       }
296     }
297     delete [] mbstr;
298   }
299   return s;
300 }
301 
302 wxString
GetWidthsAsString(bool subset,wxPdfSortedArrayInt * usedGlyphs,wxPdfChar2GlyphMap * subsetGlyphs) const303 wxPdfFontDataTrueType::GetWidthsAsString(bool subset, wxPdfSortedArrayInt* usedGlyphs, wxPdfChar2GlyphMap* subsetGlyphs) const
304 {
305   wxUnusedVar(subset);
306   wxUnusedVar(usedGlyphs);
307   wxUnusedVar(subsetGlyphs);
308   wxString s = wxString(wxS("["));
309   int i;
310   for (i = 32; i <= 255; i++)
311   {
312     s += wxString::Format(wxS("%u "), (*m_cw)[i]);
313   }
314   s += wxString(wxS("]"));
315   return s;
316 }
317 
318 size_t
WriteFontData(wxOutputStream * fontData,wxPdfSortedArrayInt * usedGlyphs,wxPdfChar2GlyphMap * subsetGlyphs)319 wxPdfFontDataTrueType::WriteFontData(wxOutputStream* fontData, wxPdfSortedArrayInt* usedGlyphs, wxPdfChar2GlyphMap* subsetGlyphs)
320 {
321   wxUnusedVar(subsetGlyphs);
322   size_t fontSize1 = 0;
323   bool compressed = false;
324   wxFileName fileName;
325   if (m_fontFileName.IsEmpty())
326   {
327     // Font data preprocessed by MakeFont
328     compressed = m_file.Lower().Right(2) == wxS(".z");
329     fileName = m_file;
330     fileName.MakeAbsolute(m_path);
331   }
332   else
333   {
334     fileName = m_fontFileName;
335   }
336 
337   // Open font file
338   wxFileSystem fs;
339   wxFSFile* fontFile = fs.OpenFile(wxFileSystem::FileNameToURL(fileName));
340   wxInputStream* fontStream = NULL;
341   if (fontFile)
342   {
343     fontStream = fontFile->GetStream();
344   }
345   else
346   {
347     // usually this should not happen since file accessability was already checked
348     wxLogError(wxString(wxS("wxPdfFontDataTrueType::WriteFontData: ")) +
349                wxString::Format(_("Font file '%s' not found."), fileName.GetFullPath().c_str()));
350   }
351 
352   if (fontStream != NULL)
353   {
354     if (usedGlyphs != NULL)
355     {
356       if (compressed)
357       {
358         // Uncompress font file
359         wxZlibInputStream zCompressed(*fontStream);
360         wxMemoryOutputStream zUncompressed;
361         zUncompressed.Write(zCompressed);
362         zUncompressed.Close();
363         fontStream = new wxMemoryInputStream(zUncompressed);
364       }
365 
366       // Assemble subset
367       wxPdfFontSubsetTrueType subset(fileName.GetFullPath(), m_fontIndex);
368       wxMemoryOutputStream* subsetStream = subset.CreateSubset(fontStream, usedGlyphs, true);
369       if (compressed)
370       {
371         delete fontStream;
372       }
373 
374       // Write font subset data
375       wxZlibOutputStream zFontData(*fontData);
376       wxMemoryInputStream tmp(*subsetStream);
377       fontSize1 = tmp.GetSize();
378       zFontData.Write(tmp);
379       zFontData.Close();
380       delete subsetStream;
381     }
382     else
383     {
384       if (!compressed)
385       {
386         fontSize1 = fontStream->GetSize();
387         wxZlibOutputStream zFontData(*fontData);
388         zFontData.Write(*fontStream);
389         zFontData.Close();
390       }
391       else
392       {
393         fontSize1 = GetSize1();
394         fontData->Write(*fontStream);
395       }
396     }
397   }
398 
399   if (fontFile != NULL)
400   {
401     delete fontFile;
402   }
403 
404   return fontSize1;
405 }
406 
407 #if wxUSE_UNICODE
408 
409 // TrueTypeUnicode font
410 
wxPdfFontDataTrueTypeUnicode()411 wxPdfFontDataTrueTypeUnicode::wxPdfFontDataTrueTypeUnicode()
412   : wxPdfFontData()
413 {
414   m_type = wxS("TrueTypeUnicode");
415   m_gw   = NULL;
416   m_conv = NULL;
417   m_volt = NULL;
418 
419   m_embedRequired = true;
420   m_embedSupported = true;
421   m_subsetSupported = true;
422 }
423 
~wxPdfFontDataTrueTypeUnicode()424 wxPdfFontDataTrueTypeUnicode::~wxPdfFontDataTrueTypeUnicode()
425 {
426   // delete m_cw;
427   if (m_conv != NULL)
428   {
429     delete m_conv;
430   }
431   if (m_gw != NULL)
432   {
433     delete m_gw;
434   }
435   if (m_volt != NULL)
436   {
437     delete m_volt;
438   }
439 }
440 
441 void
CreateDefaultEncodingConv()442 wxPdfFontDataTrueTypeUnicode::CreateDefaultEncodingConv()
443 {
444   if (m_conv == NULL)
445   {
446     m_conv = new wxMBConvUTF16BE();
447   }
448 }
449 
450 
451 bool
LoadFontMetrics(wxXmlNode * root)452 wxPdfFontDataTrueTypeUnicode::LoadFontMetrics(wxXmlNode* root)
453 {
454   bool bName  = false,
455        bDesc  = false,
456        bFile  = true,
457        bSize  = true,
458        bWidth = false;
459   wxString value;
460   long number;
461   wxXmlNode *child = root->GetChildren();
462   while (child)
463   {
464     // parse the children
465     if (child->GetName() == wxS("font-name"))
466     {
467       m_name = GetNodeContent(child);
468       m_style = FindStyleFromName(m_name);
469       bName = m_name.Length() > 0;
470     }
471     else if (child->GetName() == wxS("encoding"))
472     {
473       m_enc = GetNodeContent(child);
474     }
475     else if (child->GetName() == wxS("description"))
476     {
477       bDesc = GetFontDescription(child, m_desc);
478     }
479     else if (child->GetName() == wxS("diff"))
480     {
481       m_diffs = GetNodeContent(child);
482     }
483     else if (child->GetName() == wxS("file"))
484     {
485 #if wxCHECK_VERSION(2,9,0)
486       value = child->GetAttribute(wxS("ctg"), wxS(""));
487 #else
488       value = child->GetPropVal(wxS("ctg"), wxS(""));
489 #endif
490       if (value.Length() > 0)
491       {
492         bFile = true;
493         m_ctg = value;
494 #if wxCHECK_VERSION(2,9,0)
495         value = child->GetAttribute(wxS("name"), wxS(""));
496 #else
497         value = child->GetPropVal(wxS("name"), wxS(""));
498 #endif
499         if (value.Length() > 0)
500         {
501           m_file = value;
502 #if wxCHECK_VERSION(2,9,0)
503           value = child->GetAttribute(wxS("originalsize"), wxS(""));
504 #else
505           value = child->GetPropVal(wxS("originalsize"), wxS(""));
506 #endif
507           if (value.Length() > 0 && value.ToLong(&number))
508           {
509             bFile = true;
510             m_size1 = number;
511           }
512           else
513           {
514             bFile = false;
515             m_file = wxS("");
516           }
517         }
518       }
519       else
520       {
521         bFile = false;
522         m_file = wxS("");
523         m_ctg = wxS("");
524       }
525     }
526     else if (child->GetName() == wxS("widths"))
527     {
528       bWidth = true;
529       m_cw = new wxPdfGlyphWidthMap();
530       const wxXmlNode *charNode = child->GetChildren();
531       while (charNode)
532       {
533         wxString strId, strWidth;
534         long charId, charWidth;
535         if (charNode->GetName() == wxS("char"))
536         {
537 #if wxCHECK_VERSION(2,9,0)
538           strId = charNode->GetAttribute(wxS("id"), wxS(""));
539           strWidth = charNode->GetAttribute(wxS("width"), wxS(""));
540 #else
541           strId = charNode->GetPropVal(wxS("id"), wxS(""));
542           strWidth = charNode->GetPropVal(wxS("width"), wxS(""));
543 #endif
544           if (strId.Length() > 0 && strId.ToLong(&charId) &&
545               strWidth.Length() > 0 && strWidth.ToLong(&charWidth))
546           {
547             (*m_cw)[charId] = charWidth;
548           }
549         }
550         charNode = charNode->GetNext();
551       }
552     }
553     else if (child->GetName() == wxS("volt"))
554     {
555       m_volt = new wxPdfVolt();
556       m_volt->LoadVoltData(child);
557     }
558     child = child->GetNext();
559   }
560   CreateDefaultEncodingConv();
561 
562   m_initialized = (bName && bDesc && bFile && bSize && bWidth);
563   if (m_initialized)
564   {
565     wxFileName fileName(m_file);
566     m_initialized = fileName.MakeAbsolute(m_path) && fileName.FileExists() && fileName.IsFileReadable();
567     if (m_initialized)
568     {
569       fileName.Assign(m_ctg);
570       m_initialized = fileName.MakeAbsolute(m_path) && fileName.FileExists() && fileName.IsFileReadable();
571     }
572   }
573   if (m_initialized && m_gn == NULL)
574   {
575     // We now always need a cid to gid mapping whether subsetting is enabled or not
576     // So we read the CTG file produced by MakeFont and create the map
577     bool compressed = m_ctg.Lower().Right(2) == wxS(".z");
578     wxFileName fileName(m_ctg);
579     fileName.MakeAbsolute(m_path);
580     wxFileSystem fs;
581     wxFSFile* ctgFile = fs.OpenFile(wxFileSystem::FileNameToURL(fileName));
582     wxInputStream* ctgStream = NULL;
583     if (ctgFile)
584     {
585       ctgStream = ctgFile->GetStream();
586     }
587     else
588     {
589       m_initialized = false;
590       // usually this should not happen since file accessability was already checked
591       wxLogError(wxString(wxS("wxPdfFontDataTrueTypeUnicode::LoadFontMetrics: ")) +
592                  wxString::Format(_("CTG file '%s' not found."), fileName.GetFullPath().c_str()));
593     }
594     if (ctgStream)
595     {
596       size_t ctgLen;
597       unsigned char* cc2gn = NULL;
598       if (compressed)
599       {
600         wxZlibInputStream zin(*ctgStream);
601         wxMemoryOutputStream zout;
602         zout.Write(zin);
603         zout.Close();
604         wxMemoryInputStream cid2gidStream(zout);
605         ctgLen = cid2gidStream.GetSize();
606         cc2gn = new unsigned char[ctgLen];
607         cid2gidStream.Read(cc2gn, ctgLen);
608       }
609       else
610       {
611         ctgLen = ctgStream->GetSize();
612         cc2gn = new unsigned char[ctgLen];
613         ctgStream->Read(cc2gn, ctgLen);
614       }
615       delete ctgFile;
616 
617       // Create the cid to gid mapping
618       m_gn = new wxPdfChar2GlyphMap();
619       size_t charId;
620       for (charId = 0; charId < 0xFFFF; ++charId)
621       {
622         int glyph = (cc2gn[2*charId] << 8) + cc2gn[2*charId+1];
623         if (glyph != 0)
624         {
625           (*m_gn)[charId] = glyph;
626         }
627       }
628       delete [] cc2gn;
629     }
630   }
631   return m_initialized;
632 }
633 
634 bool
Initialize()635 wxPdfFontDataTrueTypeUnicode::Initialize()
636 {
637   bool ok = true;
638   if (!IsInitialized())
639   {
640     wxPdfFontParserTrueType fontParser;
641     ok = fontParser.LoadFontData(this);
642     m_initialized = ok;
643   }
644   return ok;
645 }
646 
647 wxString
ApplyVoltData(const wxString & s) const648 wxPdfFontDataTrueTypeUnicode::ApplyVoltData(const wxString& s) const
649 {
650   return (m_volt != NULL) ? m_volt->ProcessRules(s) : s;
651 }
652 
653 void
SetGlyphWidths(const wxPdfArrayUint16 & glyphWidths)654 wxPdfFontDataTrueTypeUnicode::SetGlyphWidths(const wxPdfArrayUint16& glyphWidths)
655 {
656   if (m_gw == NULL)
657   {
658     m_gw = new wxPdfArrayUint16;
659   }
660   *m_gw = glyphWidths;
661 }
662 
663 double
GetStringWidth(const wxString & s,const wxPdfEncoding * encoding,bool withKerning) const664 wxPdfFontDataTrueTypeUnicode::GetStringWidth(const wxString& s, const wxPdfEncoding* encoding, bool withKerning) const
665 {
666   wxUnusedVar(encoding);
667   // Get width of a string in the current font
668   double w = 0;
669 
670   wxPdfGlyphWidthMap::iterator charIter;
671   size_t i;
672   for (i = 0; i < s.Length(); i++)
673   {
674     charIter = m_cw->find(s[i]);
675     if (charIter != m_cw->end())
676     {
677       w += charIter->second;
678     }
679     else
680     {
681       w += m_desc.GetMissingWidth();
682     }
683   }
684   if (withKerning)
685   {
686     int kerningWidth = GetKerningWidth(s);
687     if (kerningWidth != 0)
688     {
689       w += (double) kerningWidth;
690     }
691   }
692   return w / 1000;
693 }
694 
695 bool
CanShow(const wxString & s,const wxPdfEncoding * encoding) const696 wxPdfFontDataTrueTypeUnicode::CanShow(const wxString& s, const wxPdfEncoding* encoding) const
697 {
698   wxUnusedVar(encoding);
699   bool canShow = true;
700   wxString::const_iterator ch;
701   for (ch = s.begin(); canShow && ch != s.end(); ++ch)
702   {
703     canShow = (m_gn->find(*ch) != m_gn->end());
704   }
705   return canShow;
706 }
707 
708 wxString
ConvertCID2GID(const wxString & s,const wxPdfEncoding * encoding,wxPdfSortedArrayInt * usedGlyphs,wxPdfChar2GlyphMap * subsetGlyphs) const709 wxPdfFontDataTrueTypeUnicode::ConvertCID2GID(const wxString& s,
710                                              const wxPdfEncoding* encoding,
711                                              wxPdfSortedArrayInt* usedGlyphs,
712                                              wxPdfChar2GlyphMap* subsetGlyphs) const
713 {
714   wxUnusedVar(encoding);
715   wxUnusedVar(subsetGlyphs);
716   bool doSubsetting = usedGlyphs != NULL;
717   wxString t;
718   wxPdfChar2GlyphMap::const_iterator charIter;
719   wxUint32 glyph;
720   wxString::const_iterator ch;
721   for (ch = s.begin(); ch != s.end(); ++ch)
722   {
723     // Handle surrogates
724     if ((*ch < 0xd800) || (*ch > 0xdfff))
725     {
726       charIter = m_gn->find(*ch);
727     }
728     else
729     {
730       wxUint32 c1 = *ch;
731       ++ch;
732       wxUint32 c2 = *ch;
733       if ((c2 < 0xdc00) || (c2 > 0xdfff))
734       {
735         charIter = m_gn->end();
736         --ch;
737       }
738       else
739       {
740         wxUint32 cc = ((c1 - 0xd7c0) << 10) + (c2 - 0xdc00);
741         charIter = m_gn->find(cc);
742       }
743     }
744     if (charIter != m_gn->end())
745     {
746       glyph = charIter->second;
747       if (doSubsetting)
748       {
749         if (usedGlyphs->Index(glyph) == wxNOT_FOUND)
750         {
751           usedGlyphs->Add(glyph);
752         }
753       }
754 #if wxCHECK_VERSION(2,9,0)
755       t.Append(wxUniChar(glyph));
756 #else
757       t.Append(wxChar(glyph));
758 #endif
759     }
760     else
761     {
762 #if wxCHECK_VERSION(2,9,0)
763       t.Append(wxUniChar(0));
764 #else
765       t.Append(wxChar(0));
766 #endif
767     }
768   }
769   return t;
770 }
771 
772 wxString
ConvertGlyph(wxUint32 glyph,const wxPdfEncoding * encoding,wxPdfSortedArrayInt * usedGlyphs,wxPdfChar2GlyphMap * subsetGlyphs) const773 wxPdfFontDataTrueTypeUnicode::ConvertGlyph(wxUint32 glyph,
774                                            const wxPdfEncoding* encoding,
775                                            wxPdfSortedArrayInt* usedGlyphs,
776                                            wxPdfChar2GlyphMap* subsetGlyphs) const
777 {
778   wxUnusedVar(encoding);
779   wxUnusedVar(subsetGlyphs);
780   wxString t = wxEmptyString;
781   if (m_gw != NULL && glyph < m_gw->size())
782   {
783     bool doSubsetting = usedGlyphs != NULL;
784     if (doSubsetting)
785     {
786       if (usedGlyphs->Index(glyph) == wxNOT_FOUND)
787       {
788         usedGlyphs->Add(glyph);
789       }
790     }
791 #if wxCHECK_VERSION(2,9,0)
792     t.Append(wxUniChar(glyph));
793 #else
794     t.Append(wxChar(glyph));
795 #endif
796   }
797   else
798   {
799 #if wxCHECK_VERSION(2,9,0)
800     t.Append(wxUniChar(0));
801 #else
802     t.Append(wxChar(0));
803 #endif
804   }
805   return t;
806 }
807 
808 wxString
GetWidthsAsString(bool subset,wxPdfSortedArrayInt * usedGlyphs,wxPdfChar2GlyphMap * subsetGlyphs) const809 wxPdfFontDataTrueTypeUnicode::GetWidthsAsString(bool subset, wxPdfSortedArrayInt* usedGlyphs, wxPdfChar2GlyphMap* subsetGlyphs) const
810 {
811   wxUnusedVar(subsetGlyphs);
812   wxString s = wxString(wxS("["));
813   wxUint32 glyph;
814   wxPdfChar2GlyphMap::const_iterator glyphIter;
815   wxPdfGlyphWidthMap::iterator charIter;
816   for (charIter = m_cw->begin(); charIter != m_cw->end(); charIter++)
817   {
818     glyphIter = m_gn->find(charIter->first);
819     if (glyphIter != m_gn->end())
820     {
821       glyph = glyphIter->second;
822     }
823     else
824     {
825       glyph = 0;
826     }
827     if (glyph != 0 && (!subset || usedGlyphs == NULL ||
828                        (subset && SubsetSupported() && (usedGlyphs->Index(glyph) != wxNOT_FOUND))))
829     {
830       // define a specific width for each individual CID
831       s += wxString::Format(wxS("%u [%u] "), glyph, charIter->second);
832     }
833   }
834   s += wxString(wxS("]"));
835   return s;
836 }
837 
838 size_t
WriteFontData(wxOutputStream * fontData,wxPdfSortedArrayInt * usedGlyphs,wxPdfChar2GlyphMap * subsetGlyphs)839 wxPdfFontDataTrueTypeUnicode::WriteFontData(wxOutputStream* fontData, wxPdfSortedArrayInt* usedGlyphs, wxPdfChar2GlyphMap* subsetGlyphs)
840 {
841   bool isMacCoreText = false;
842   bool deleteFontStream = false;
843   wxUnusedVar(subsetGlyphs);
844   size_t fontSize1 = 0;
845   wxFSFile* fontFile = NULL;
846   wxInputStream* fontStream = NULL;
847   bool compressed = false;
848   wxString fontFullPath = wxEmptyString;
849   wxFileName fileName;
850   if (m_fontFileName.IsEmpty())
851   {
852 #if defined(__WXMSW__)
853     if (m_file.IsEmpty() && m_font.IsOk())
854     {
855       fontStream = wxPdfFontParserTrueType::LoadTrueTypeFontStream(m_font);
856       deleteFontStream = true;
857     }
858     else
859 #elif defined(__WXMAC__)
860 #if wxPDFMACOSX_HAS_CORE_TEXT
861     if (m_file.IsEmpty() && m_font.IsOk())
862     {
863       fontStream = new wxMemoryInputStream("dummy", 5);
864       deleteFontStream = true;
865       isMacCoreText = true;
866     }
867     else
868 #endif
869 #endif
870     {
871       // Font data preprocessed by MakeFont
872       compressed = m_file.Lower().Right(2) == wxS(".z");
873       fileName = m_file;
874       fileName.MakeAbsolute(m_path);
875     }
876   }
877   else
878   {
879     fileName = m_fontFileName;
880   }
881 
882   if (fileName.IsOk())
883   {
884     // Open font file
885     wxFileSystem fs;
886     fontFile = fs.OpenFile(wxFileSystem::FileNameToURL(fileName));
887     if (fontFile)
888     {
889       fontStream = fontFile->GetStream();
890       deleteFontStream = false;
891       fontFullPath = fileName.GetFullPath();
892     }
893     else
894     {
895       // usually this should not happen since file accessability was already checked
896       wxLogError(wxString(wxS("wxPdfFontDataTrueTypeUnicode::WriteFontData: ")) +
897                  wxString::Format(_("Font file '%s' not found."), fileName.GetFullPath().c_str()));
898     }
899   }
900 
901   if (fontStream != NULL)
902   {
903     if (usedGlyphs != NULL)
904     {
905       if (compressed)
906       {
907         // Uncompress font file
908         wxZlibInputStream zCompressed(*fontStream);
909         wxMemoryOutputStream zUncompressed;
910         zUncompressed.Write(zCompressed);
911         zUncompressed.Close();
912         fontStream = new wxMemoryInputStream(zUncompressed);
913         deleteFontStream = true;
914       }
915 
916       // Assemble subset
917       wxPdfFontSubsetTrueType subset(fontFullPath, 0, isMacCoreText);
918 #if defined(__WXMAC__)
919 #if wxPDFMACOSX_HAS_CORE_TEXT
920       if (m_font.IsOk())
921       {
922         subset.SetCTFontRef(m_font);
923       }
924 #endif
925 #endif
926       wxMemoryOutputStream* subsetStream = subset.CreateSubset(fontStream, usedGlyphs, false);
927       if (deleteFontStream && fontStream != NULL)
928       {
929         delete fontStream;
930       }
931 
932       // Write font subset data
933       wxZlibOutputStream zFontData(*fontData);
934       wxMemoryInputStream tmp(*subsetStream);
935       fontSize1 = tmp.GetSize();
936       zFontData.Write(tmp);
937       zFontData.Close();
938       delete subsetStream;
939     }
940     else
941     {
942       if (!compressed)
943       {
944         fontSize1 = fontStream->GetSize();
945         wxZlibOutputStream zFontData(*fontData);
946         zFontData.Write(*fontStream);
947         zFontData.Close();
948       }
949       else
950       {
951         fontSize1 = GetSize1();
952         fontData->Write(*fontStream);
953       }
954     }
955   }
956 
957   if (fontFile != NULL)
958   {
959     delete fontFile;
960   }
961 
962   return fontSize1;
963 }
964 
965 size_t
WriteUnicodeMap(wxOutputStream * mapData,const wxPdfEncoding * encoding,wxPdfSortedArrayInt * usedGlyphs,wxPdfChar2GlyphMap * subsetGlyphs)966 wxPdfFontDataTrueTypeUnicode::WriteUnicodeMap(wxOutputStream* mapData,
967                                               const wxPdfEncoding* encoding,
968                                               wxPdfSortedArrayInt* usedGlyphs,
969                                               wxPdfChar2GlyphMap* subsetGlyphs)
970 {
971   wxUnusedVar(encoding);
972   wxUnusedVar(subsetGlyphs);
973   wxPdfGlyphList glyphList(wxPdfFontData::CompareGlyphListEntries);
974   wxPdfChar2GlyphMap::const_iterator charIter = m_gn->begin();
975   for (charIter = m_gn->begin(); charIter != m_gn->end(); ++charIter)
976   {
977     if (usedGlyphs != NULL)
978     {
979       if (usedGlyphs->Index(charIter->second) != wxNOT_FOUND)
980       {
981         wxPdfGlyphListEntry* glEntry = new wxPdfGlyphListEntry();
982         glEntry->m_gid = charIter->second;
983         glEntry->m_uid = charIter->first;
984         glyphList.Add(glEntry);
985       }
986     }
987     else
988     {
989       wxPdfGlyphListEntry* glEntry = new wxPdfGlyphListEntry();
990       glEntry->m_gid = charIter->second;
991       glEntry->m_uid = charIter->first;
992       glyphList.Add(glEntry);
993     }
994   }
995   wxMemoryOutputStream toUnicode;
996   WriteToUnicode(glyphList, toUnicode);
997   wxMemoryInputStream inUnicode(toUnicode);
998   wxZlibOutputStream zUnicodeMap(*mapData);
999   zUnicodeMap.Write(inUnicode);
1000   zUnicodeMap.Close();
1001 
1002   WX_CLEAR_ARRAY(glyphList);
1003 
1004   return 0;
1005 }
1006 
1007 #endif // wxUSE_UNICODE
1008