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