1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: pdffontparsertruetype.cpp
3 // Purpose:
4 // Author: Ulrich Telle
5 // Created: 2009-03-04
6 // Copyright: (c) Ulrich Telle
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 /// \file pdffontparsertruetype.cpp Implementation of TrueType/OpenType font parsing support 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/fontutil.h>
27 #include <wx/zstream.h>
28
29 #include "wx/pdffontdataopentype.h"
30 #include "wx/pdffontdatatruetype.h"
31 #include "wx/pdffontparsertruetype.h"
32 #include "wx/pdfencoding.h"
33
34 // --- Windows specific loading of TrueType font data
35
36 #ifdef __WXMSW__
37
38 #include <stdio.h>
39 #include <windows.h>
40
41 #include "wx/msw/private.h"
42
43 static USHORT
ReadUShort(BYTE * p)44 ReadUShort(BYTE* p)
45 {
46 return ((USHORT)p[0] << 8) + ((USHORT)p[1]);
47 }
48
49 static DWORD
ReadDWord(BYTE * p)50 ReadDWord(BYTE* p)
51 {
52 return ((LONG)p[0] << 24) + ((LONG)p[1] << 16) + ((LONG)p[2] << 8) + ((LONG)p[3]);
53 }
54
ReadTag(BYTE * p)55 static DWORD ReadTag(BYTE* p)
56 {
57 return ((LONG)p[3] << 24) + ((LONG)p[2] << 16) + ((LONG)p[1] << 8) + ((LONG)p[0]);
58 }
59
60 static void
WriteDWord(BYTE * p,DWORD dw)61 WriteDWord(BYTE* p, DWORD dw)
62 {
63 p[0] = (BYTE)((dw >> 24 ) & 0xFF);
64 p[1] = (BYTE)((dw >> 16 ) & 0xFF);
65 p[2] = (BYTE)((dw >> 8 ) & 0xFF);
66 p[3] = (BYTE)((dw ) & 0xFF);
67 }
68
69 static DWORD
RoundUpToDWord(DWORD val)70 RoundUpToDWord(DWORD val)
71 {
72 return (val + 3) & ~3;
73 }
74
75 #define TTC_FILE 0x66637474
76
77 const DWORD sizeOfFixedHeader = 12;
78 const DWORD offsetOfTableCount = 4;
79
80 const DWORD sizeOfTableEntry = 16;
81 const DWORD offsetOfTableTag = 0;
82 const DWORD offsetOfTableChecksum = 4;
83 const DWORD offsetOfTableOffset = 8;
84 const DWORD offsetOfTableLength = 12;
85
86 static bool
ExtractFontData(HDC hdc,DWORD & fontDataSize,BYTE * & fontData)87 ExtractFontData(HDC hdc, DWORD& fontDataSize, BYTE*& fontData)
88 {
89 bool ok = false;
90 fontData = NULL;
91 fontDataSize = 0;
92
93 // Check if font is in TrueType collection
94 if (GetFontData(hdc, TTC_FILE, 0, NULL, 0) != GDI_ERROR)
95 {
96 // Extract font data from TTC (TrueType Collection)
97 // 1. Read number of tables in the font (ushort value at offset 2)
98 USHORT nTables;
99 BYTE uShortBuf[2];
100 if (GetFontData(hdc, 0, 4, uShortBuf, 2) == GDI_ERROR)
101 {
102 wxLogError(wxString(wxS("ExtractFontData: ")) +
103 wxString::Format(_("Error %d on reading number of tables from TTC."), GetLastError()));
104 return false;
105 }
106 nTables = ReadUShort(uShortBuf);
107
108 // 2. Calculate memory needed for the whole font header and read it into buffer
109 DWORD headerSize = sizeOfFixedHeader + nTables * sizeOfTableEntry;
110 BYTE* fontHeader = new BYTE[headerSize];
111 if (!fontHeader)
112 {
113 wxLogError(wxString(wxS("ExtractFontData: ")) +
114 wxString(_("Out of memory while extracting from TTC.")));
115 return false;
116 }
117 if (GetFontData(hdc, 0, 0, fontHeader, headerSize) == GDI_ERROR)
118 {
119 delete [] fontHeader;
120 wxLogError(wxString(wxS("ExtractFontData: ")) +
121 wxString::Format(_("Error %d on reading font header from TTC."), GetLastError()));
122 return false;
123 }
124
125 // 3. Calculate total font size.
126 // Tables are padded to 4-byte boundaries, so length should be rounded up to dword.
127 DWORD bufferSize = headerSize;
128 USHORT i;
129 for (i = 0; i < nTables; i++)
130 {
131 DWORD tableLength = ReadDWord(fontHeader + sizeOfFixedHeader + i * sizeOfTableEntry + offsetOfTableLength);
132 if (i < nTables - 1)
133 {
134 bufferSize += RoundUpToDWord(tableLength);
135 }
136 else
137 {
138 bufferSize += tableLength;
139 }
140 }
141
142 // 4. Copying header into target buffer.
143 // Patch offsets with correct values while copying data.
144 BYTE* buffer = new BYTE[bufferSize];
145 if (buffer == NULL)
146 {
147 delete [] fontHeader;
148 wxLogError(wxString(wxS("ExtractFontData: ")) +
149 wxString(_("Out of memory while extracting from TTC.")));
150 return false;
151 }
152 memcpy(buffer, fontHeader, headerSize);
153
154 // 5. Get table data from GDI, write it into known place
155 // inside target buffer and fix offset value.
156 DWORD runningOffset = headerSize;
157
158 for (i = 0; i < nTables; i++)
159 {
160 BYTE* entryData = fontHeader + sizeOfFixedHeader + i * sizeOfTableEntry;
161 DWORD tableTag = ReadTag(entryData + offsetOfTableTag);
162 DWORD tableLength = ReadDWord(entryData + offsetOfTableLength);
163
164 // Write new offset for this table.
165 WriteDWord(buffer + sizeOfFixedHeader + i * sizeOfTableEntry + offsetOfTableOffset, runningOffset);
166
167 // Get font data from GDI and place it into target buffer
168 if (GetFontData(hdc, tableTag, 0, buffer + runningOffset, tableLength) == GDI_ERROR)
169 {
170 delete [] buffer;
171 delete [] fontHeader;
172 wxLogError(wxString(wxS("ExtractFontData: ")) +
173 wxString::Format(_("Error %d on reading table data from TTC."), GetLastError()));
174 return false;
175 }
176 runningOffset += tableLength;
177
178 // Pad tables (except last) with zero's
179 if (i < nTables - 1)
180 {
181 while (runningOffset % 4 != 0)
182 {
183 buffer[runningOffset] = 0;
184 ++runningOffset;
185 }
186 }
187 }
188 delete [] fontHeader;
189 fontDataSize = bufferSize;
190 fontData = buffer;
191 ok = true;
192 }
193 else
194 {
195 // Check if font is TrueType
196 DWORD bufferSize = GetFontData(hdc, 0, 0, NULL, 0);
197 if (bufferSize != GDI_ERROR)
198 {
199 BYTE* buffer = new BYTE[bufferSize];
200 if (buffer != NULL)
201 {
202 ok = (GetFontData(hdc, 0, 0, buffer, bufferSize) != GDI_ERROR);
203 if (ok)
204 {
205 fontDataSize = bufferSize;
206 fontData = buffer;
207 }
208 else
209 {
210 delete [] buffer;
211 wxLogError(wxString(wxS("ExtractFontData: ")) +
212 wxString::Format(_("Error %d on extracting font data."), GetLastError()));
213 }
214 }
215 else
216 {
217 wxLogError(wxString(wxS("ExtractFontData: ")) +
218 wxString(_("Out of memory.")));
219 }
220 }
221 }
222 return ok;
223 }
224
225 wxMemoryInputStream*
LoadTrueTypeFontStream(const wxFont & font)226 wxPdfFontParserTrueType::LoadTrueTypeFontStream(const wxFont& font)
227 {
228 wxMemoryInputStream* fontStream = NULL;
229 LOGFONT lf = font.GetNativeFontInfo()->lf;
230
231 HDC hdc = CreateCompatibleDC(0);
232 HFONT hFont = CreateFontIndirect(&lf);
233 /*HFONT oldfont = (HFONT)*/ SelectObject(hdc, hFont);
234
235 DWORD fontDataSize;
236 BYTE* fontData;
237 bool ok = ExtractFontData(hdc, fontDataSize, fontData);
238 if (ok)
239 {
240 wxMemoryOutputStream oStream;
241 oStream.Write(fontData, fontDataSize);
242 oStream.Close();
243 fontStream = new wxMemoryInputStream(oStream);
244 delete [] fontData;
245 }
246 DeleteDC(hdc);
247 DeleteObject(hFont);
248
249 return fontStream;
250 }
251
252 #endif
253
254 // --- Parsing of TrueType and OpenType
255
256 // The components of table 'head'.
257 class wxPdfFontHeader
258 {
259 public:
260 int m_flags;
261 int m_unitsPerEm;
262 short m_xMin;
263 short m_yMin;
264 short m_xMax;
265 short m_yMax;
266 int m_macStyle;
267 };
268
269 // The components of table 'hhea'.
270 class wxPdfHorizontalHeader
271 {
272 public:
273 short m_ascender;
274 short m_descender;
275 short m_lineGap;
276 int m_advanceWidthMax;
277 short m_minLeftSideBearing;
278 short m_minRightSideBearing;
279 short m_xMaxExtent;
280 short m_caretSlopeRise;
281 short m_caretSlopeRun;
282 int m_numberOfHMetrics;
283 };
284
285 // The components of table 'OS/2'.
286 class wxPdfWindowsMetrics
287 {
288 public:
289 short m_xAvgCharWidth;
290 int m_usWeightClass;
291 int m_usWidthClass;
292 short m_fsType;
293 short m_ySubscriptXSize;
294 short m_ySubscriptYSize;
295 short m_ySubscriptXOffset;
296 short m_ySubscriptYOffset;
297 short m_ySuperscriptXSize;
298 short m_ySuperscriptYSize;
299 short m_ySuperscriptXOffset;
300 short m_ySuperscriptYOffset;
301 short m_yStrikeoutSize;
302 short m_yStrikeoutPosition;
303 short m_sFamilyClass;
304 char m_panose[10];
305 char m_achVendID[4];
306 int m_fsSelection;
307 int m_usFirstCharIndex;
308 int m_usLastCharIndex;
309 short m_sTypoAscender;
310 short m_sTypoDescender;
311 short m_sTypoLineGap;
312 int m_usWinAscent;
313 int m_usWinDescent;
314 int m_ulCodePageRange1;
315 int m_ulCodePageRange2;
316 int m_sxHeight;
317 int m_sCapHeight;
318 };
319
320 #if 0
321 static const wxChar codePages[] =
322 {
323 /* 0 */ "1252 Latin 1", // wxFONTENCODING_CP1252
324 /* 1 */ "1250 Latin 2: Eastern Europe", // wxFONTENCODING_CP1250
325 /* 2 */ "1251 Cyrillic", // wxFONTENCODING_CP1251
326 /* 3 */ "1253 Greek", // wxFONTENCODING_CP1253
327 /* 4 */ "1254 Turkish", // wxFONTENCODING_CP1254
328 /* 5 */ "1255 Hebrew", // wxFONTENCODING_CP1255
329 /* 6 */ "1256 Arabic", // wxFONTENCODING_CP1256
330 /* 7 */ "1257 Windows Baltic", // wxFONTENCODING_CP1257
331 /* 8 */ "1258 Vietnamese", //
332 /* 9 */ null,
333 /* 10 */ null,
334 /* 11 */ null,
335 /* 12 */ null,
336 /* 13 */ null,
337 /* 14 */ null,
338 /* 15 */ null,
339 /* 16 */ "874 Thai", // wxFONTENCODING_CP874
340 /* 17 */ "932 JIS/Japan", // wxFONTENCODING_CP932
341 /* 18 */ "936 Chinese: Simplified", // wxFONTENCODING_CP936
342 /* 19 */ "949 Korean Wansung", // wxFONTENCODING_CP949
343 /* 20 */ "950 Chinese: Traditional", // wxFONTENCODING_CP950
344 /* 21 */ "1361 Korean Johab", //
345 /* 22 */ null,
346 /* 23 */ null,
347 /* 24 */ null,
348 /* 25 */ null,
349 /* 26 */ null,
350 /* 27 */ null,
351 /* 28 */ null,
352 /* 29 */ "Macintosh Character Set (US Roman)", //
353 /* 30 */ "OEM Character Set", //
354 /* 31 */ "Symbol Character Set", //
355 /* 0 */ null,
356 /* 1 */ null,
357 /* 2 */ null,
358 /* 3 */ null,
359 /* 4 */ null,
360 /* 5 */ null,
361 /* 6 */ null,
362 /* 7 */ null,
363 /* 8 */ null,
364 /* 9 */ null,
365 /* 10 */ null,
366 /* 11 */ null,
367 /* 12 */ null,
368 /* 13 */ null,
369 /* 14 */ null,
370 /* 15 */ null,
371 /* 16 */ "869 IBM Greek", //
372 /* 17 */ "866 MS-DOS Russian", // wxFONTENCODING_CP866
373 /* 18 */ "865 MS-DOS Nordic", //
374 /* 19 */ "864 Arabic", //
375 /* 20 */ "863 MS-DOS Canadian French", //
376 /* 21 */ "862 Hebrew", //
377 /* 22 */ "861 MS-DOS Icelandic", //
378 /* 23 */ "860 MS-DOS Portuguese", //
379 /* 24 */ "857 IBM Turkish", //
380 /* 25 */ "855 IBM Cyrillic", // wxFONTENCODING_CP855
381 /* 26 */ "852 Latin 2", // wxFONTENCODING_CP852
382 /* 27 */ "775 MS-DOS Baltic", //
383 /* 28 */ "737 Greek; former 437 G", //
384 /* 29 */ "708 Arabic; ASMO 708", //
385 /* 30 */ "850 WE/Latin 1", // wxFONTENCODING_CP850
386 /* 31 */ "437 US" // wxFONTENCODING_CP437
387 };
388 #endif
389
wxPdfFontParserTrueType()390 wxPdfFontParserTrueType::wxPdfFontParserTrueType()
391 : wxPdfFontParser()
392 {
393 m_tableDirectory = new wxPdfTableDirectory();
394 m_isFixedPitch = false;
395 m_cmap10 = NULL;
396 m_cmap31 = NULL;
397 m_cmapExt = NULL;
398 m_kp = NULL;
399 m_isMacCoreText = false;
400 m_savedStream = NULL;
401 }
402
~wxPdfFontParserTrueType()403 wxPdfFontParserTrueType::~wxPdfFontParserTrueType()
404 {
405 wxPdfCMap::iterator cMapIter;
406 if (m_cmap10 != NULL)
407 {
408 for (cMapIter = m_cmap10->begin(); cMapIter != m_cmap10->end(); cMapIter++)
409 {
410 if (cMapIter->second != NULL)
411 {
412 delete cMapIter->second;
413 }
414 }
415 delete m_cmap10;
416 }
417 if (m_cmap31 != NULL)
418 {
419 for (cMapIter = m_cmap31->begin(); cMapIter != m_cmap31->end(); cMapIter++)
420 {
421 if (cMapIter->second != NULL)
422 {
423 delete cMapIter->second;
424 }
425 }
426 delete m_cmap31;
427 }
428 if (m_cmapExt != NULL)
429 {
430 for (cMapIter = m_cmapExt->begin(); cMapIter != m_cmapExt->end(); cMapIter++)
431 {
432 if (cMapIter->second != NULL)
433 {
434 delete cMapIter->second;
435 }
436 }
437 delete m_cmapExt;
438 }
439
440 ClearTableDirectory();
441 delete m_tableDirectory;
442 }
443
444 void
ClearTableDirectory()445 wxPdfFontParserTrueType::ClearTableDirectory()
446 {
447 wxPdfTableDirectory::iterator entry = m_tableDirectory->begin();
448 for (entry = m_tableDirectory->begin(); entry != m_tableDirectory->end(); entry++)
449 {
450 if (entry->second != NULL)
451 {
452 delete entry->second;
453 entry->second = NULL;
454 }
455 }
456 }
457
458 void
LockTable(const wxString & tableName)459 wxPdfFontParserTrueType::LockTable(const wxString& tableName)
460 {
461 #if defined(__WXMAC__)
462 #if wxPDFMACOSX_HAS_CORE_TEXT
463 if (m_isMacCoreText)
464 {
465 wxCharBuffer asciiTableName = tableName.ToAscii();
466 const char* localTableName = asciiTableName;
467 CTFontTableTag tableTag = localTableName[0] << 24 |
468 localTableName[1] << 16 |
469 localTableName[2] << 8 |
470 localTableName[3];
471 m_tableRef.reset(CTFontCopyTable(m_fontRef, tableTag, 0));
472 const UInt8* tableData = CFDataGetBytePtr(m_tableRef);
473 CFIndex tableLen = CFDataGetLength(m_tableRef);
474 m_savedStream = m_inFont;
475 m_inFont = new wxMemoryInputStream((const char*) tableData, (size_t) tableLen);
476 }
477 #else
478 wxUnusedVar(tableName);
479 #endif
480 #else
481 wxUnusedVar(tableName);
482 #endif
483 }
484
485 void
ReleaseTable()486 wxPdfFontParserTrueType::ReleaseTable()
487 {
488 #if defined(__WXMAC__)
489 #if wxPDFMACOSX_HAS_CORE_TEXT
490 if (m_isMacCoreText)
491 {
492 delete m_inFont;
493 m_inFont = m_savedStream;
494 }
495 #endif
496 #endif
497 }
498
499 int
CalculateChecksum(const char * b,size_t length)500 wxPdfFontParserTrueType::CalculateChecksum(const char* b, size_t length)
501 {
502 size_t len = length / 4;
503 int d0 = 0;
504 int d1 = 0;
505 int d2 = 0;
506 int d3 = 0;
507 size_t ptr = 0;
508 size_t k;
509 for (k = 0; k < len; ++k)
510 {
511 d3 += (int)b[ptr++] & 0xff;
512 d2 += (int)b[ptr++] & 0xff;
513 d1 += (int)b[ptr++] & 0xff;
514 d0 += (int)b[ptr++] & 0xff;
515 }
516 return d0 + (d1 << 8) + (d2 << 16) + (d3 << 24);
517 }
518
519 int
GetCollectionFontCount(const wxString & fontFileName)520 wxPdfFontParserTrueType::GetCollectionFontCount(const wxString& fontFileName)
521 {
522 int count = 0;
523 wxFileName fileName(fontFileName);
524 wxFileSystem fs;
525
526 wxFSFile* fontFile = fs.OpenFile(wxFileSystem::FileNameToURL(fileName));
527 if (fontFile != NULL)
528 {
529 m_inFont = fontFile->GetStream();
530 m_inFont->SeekI(0);
531
532 // Check for TrueType collection
533 if (fileName.GetExt().Lower().IsSameAs(wxS("ttc")))
534 {
535 wxString mainTag = ReadString(4);
536 if (mainTag == wxS("ttcf"))
537 {
538 SkipBytes(4);
539 count = ReadInt();
540 }
541 }
542 delete fontFile;
543 }
544 return count;
545 }
546
547 wxPdfFontData*
IdentifyFont(const wxString & fontFileName,int fontIndex)548 wxPdfFontParserTrueType::IdentifyFont(const wxString& fontFileName, int fontIndex)
549 {
550 bool ok = true;
551 wxPdfFontData* fontData = NULL;
552 m_fileName = fontFileName;
553 wxFileName fileName(fontFileName);
554 wxFileSystem fs;
555
556 // Open font file
557 wxFSFile* fontFile = fs.OpenFile(wxFileSystem::FileNameToURL(fileName));
558 if (fontFile != NULL)
559 {
560 m_inFont = fontFile->GetStream();
561 m_inFont->SeekI(0);
562
563 // Check for TrueType collection
564 if (fileName.GetExt().Lower().IsSameAs(wxS("ttc")))
565 {
566 if (fontIndex >= 0)
567 {
568 wxString mainTag = ReadString(4);
569 if (mainTag == wxS("ttcf"))
570 {
571 SkipBytes(4);
572 int dirCount = ReadInt();
573 if (fontIndex < dirCount)
574 {
575 SkipBytes(fontIndex * 4);
576 m_directoryOffset = ReadInt();
577 }
578 else
579 {
580 wxLogError(wxString(wxS("wxPdfFontParserTrueType::IdentifyFont: ")) +
581 wxString::Format(_("Font index %d out of range for font file '%s'."), fontIndex, fontFileName.c_str()));
582 ok = false;
583 }
584 }
585 else
586 {
587 wxLogError(wxString(wxS("wxPdfFontParserTrueType::IdentifyFont: '")) +
588 wxString::Format(_("Font file '%s' not a valid TrueType collection (TTC) file."), fontFileName.c_str()));
589 ok = false;
590 }
591 }
592 else
593 {
594 wxLogError(wxString(wxS("wxPdfFontParserTrueType::IdentifyFont: ")) +
595 wxString::Format(_("Font index %d out of range for font file '%s'."), fontIndex, fontFileName.c_str()));
596 ok = false;
597 }
598 }
599 else
600 {
601 m_directoryOffset = 0;
602 fontIndex = 0;
603 }
604
605 // Identify single font
606 if (ok)
607 {
608 fontData = IdentifyFont();
609 if (fontData != NULL)
610 {
611 fontData->SetFontFileName(m_fileName);
612 fontData->SetFontIndex(fontIndex);
613 }
614 else
615 {
616 wxLogError(wxString(wxS("wxPdfFontParserTrueType::IdentifyFont: ")) +
617 wxString::Format(_("Reading of font directory failed for font file '%s'."), fontFileName.c_str()));
618 }
619 }
620 delete fontFile;
621 }
622 else
623 {
624 wxLogError(wxString(wxS("wxPdfFontParserTrueType::IdentifyFont: ")) +
625 wxString::Format(_("Font file '%s' not accessible."), fontFileName.c_str()));
626 }
627 return fontData;
628 }
629
630 #ifdef __WXMSW__
631 wxPdfFontData*
IdentifyFont(const wxFont & font)632 wxPdfFontParserTrueType::IdentifyFont(const wxFont& font)
633 {
634 bool ok = true;
635 wxPdfFontData* fontData = NULL;
636 m_fileName = wxEmptyString;
637
638 wxMemoryInputStream* fontStream = LoadTrueTypeFontStream(font);
639 if (fontStream != NULL)
640 {
641 m_inFont = fontStream;
642 m_inFont->SeekI(0);
643
644 m_directoryOffset = 0;
645
646 // Identify single font
647 if (ok)
648 {
649 fontData = IdentifyFont();
650 if (fontData != NULL)
651 {
652 fontData->SetFont(font);
653 fontData->SetFontIndex(0);
654 }
655 else
656 {
657 wxLogError(wxString(wxS("wxPdfFontParserTrueType::IdentifyFont: ")) +
658 wxString::Format(_("Reading of font directory failed for font file '%s'."), font.GetFaceName().c_str()));
659 }
660 }
661 delete fontStream;
662 }
663 else
664 {
665 wxLogError(wxString(wxS("wxPdfFontParserTrueType::IdentifyFont: ")) +
666 wxString::Format(_("Font file '%s' not accessible."), font.GetFaceName().c_str()));
667 }
668 return fontData;
669 }
670 #endif
671
672 #if defined(__WXMAC__)
673 wxPdfFontData*
IdentifyFont(const wxFont & font)674 wxPdfFontParserTrueType::IdentifyFont(const wxFont& font)
675 {
676 wxPdfFontData* fontData = NULL;
677 #if wxPDFMACOSX_HAS_CORE_TEXT
678 #if wxCHECK_VERSION(2,9,0)
679 // wxWidgets 2.9.x or higher
680 m_fontRef = font.OSXGetCTFont();
681 #else // wxWidgets 2.8.x
682 m_fontRef = (const void*) font.MacGetCTFont();
683 #endif
684
685 m_isMacCoreText = true;
686 m_fileName = wxEmptyString;
687
688 m_inFont = NULL;
689 m_directoryOffset = 0;
690
691 // Identify single font
692 fontData = IdentifyFont();
693 if (fontData != NULL)
694 {
695 fontData->SetFont(font);
696 fontData->SetFontIndex(0);
697 }
698 else
699 {
700 wxLogError(wxString(wxS("wxPdfFontParserTrueType::IdentifyFont: ")) +
701 wxString::Format(_("Reading of font directory failed for font file '%s'."), font.GetFaceName().c_str()));
702 }
703 #endif
704 return fontData;
705 }
706 #endif
707
708 wxPdfFontData*
IdentifyFont()709 wxPdfFontParserTrueType::IdentifyFont()
710 {
711 wxPdfFontData* fontData = NULL;
712 #if wxUSE_UNICODE
713 if (ReadTableDirectory())
714 {
715 if (CheckTables())
716 {
717 CheckCff();
718 if (m_cff)
719 {
720 wxPdfFontDataOpenTypeUnicode* otfFontData = new wxPdfFontDataOpenTypeUnicode();
721 otfFontData->SetCffOffset(m_cffOffset);
722 otfFontData->SetCffLength(m_cffLength);
723 fontData = otfFontData;
724 }
725 else
726 {
727 fontData = new wxPdfFontDataTrueTypeUnicode();
728 }
729
730 // Get PostScript name, font family, font names and font style
731 fontData->SetName(GetBaseFont());
732 fontData->SetFamily(GetEnglishName(1));
733 fontData->SetFullNames(GetUniqueNames(4));
734 fontData->SetStyle(GetEnglishName(2));
735 m_fontName = fontData->GetName();
736
737 CheckRestrictions();
738 fontData->SetEmbedSupported(m_embedAllowed);
739 fontData->SetSubsetSupported(m_subsetAllowed);
740 }
741 }
742 #endif
743 return fontData;
744 }
745
746 bool
LoadFontData(wxPdfFontData * fontData)747 wxPdfFontParserTrueType::LoadFontData(wxPdfFontData* fontData)
748 {
749 bool ok = false;
750 if (fontData != NULL)
751 {
752 wxFSFile* fontFile = NULL;
753 wxMemoryInputStream* fontStream = NULL;
754 m_inFont = NULL;
755 int fontIndex = fontData->GetFontIndex();
756 m_fileName = fontData->GetFontFileName();
757 m_fontName = fontData->GetName();
758 if (!m_fileName.IsEmpty())
759 {
760 wxFileName fileName(m_fileName);
761 wxFileSystem fs;
762 fontFile = fs.OpenFile(wxFileSystem::FileNameToURL(fileName));
763 if (fontFile != NULL)
764 {
765 m_inFont = fontFile->GetStream();
766 }
767 }
768 else
769 {
770 #if defined(__WXMSW__)
771 wxFont font = fontData->GetFont();
772 if (font.IsOk())
773 {
774 fontStream = LoadTrueTypeFontStream(font);
775 if (fontStream != NULL)
776 {
777 m_inFont = fontStream;
778 }
779 }
780 #elif defined(__WXMAC__)
781 #if wxPDFMACOSX_HAS_CORE_TEXT
782 wxFont font = fontData->GetFont();
783 if (font.IsOk())
784 {
785 #if wxCHECK_VERSION(2,9,0)
786 // wxWidgets 2.9.x or higher
787 m_fontRef = font.OSXGetCTFont();
788 #else // wxWidgets 2.8.x
789 m_fontRef = (const void*) font.MacGetCTFont();
790 #endif
791 m_isMacCoreText = true;
792 fontStream = new wxMemoryInputStream("dummy", 5);
793 m_inFont = fontStream;
794 }
795 #endif
796 #endif
797 }
798 if (m_inFont != NULL)
799 {
800 m_inFont->SeekI(0);
801
802 if (fontIndex >= 0)
803 {
804 // Check whether the font file is a TrueType collection
805 wxString mainTag = ReadString(4);
806 if (mainTag == wxS("ttcf"))
807 {
808 SkipBytes(4);
809 int dirCount = ReadInt();
810 if (fontIndex < dirCount)
811 {
812 SkipBytes(fontIndex * 4);
813 m_directoryOffset = ReadInt();
814 ok = true;
815 }
816 else
817 {
818 wxLogError(wxString(wxS("wxPdfFontParserTrueType::LoadFontData: ")) +
819 wxString::Format(_("Font index %d out of range for font file '%s'."), fontIndex, m_fileName.c_str()));
820 }
821 }
822 else
823 {
824 m_directoryOffset = 0;
825 ok = (fontIndex == 0);
826 if (!ok)
827 {
828 wxLogError(wxString(wxS("wxPdfFontParserTrueType::LoadFontData: '")) +
829 wxString::Format(_("Font file '%s' not a valid TrueType collection (TTC) file."), m_fileName.c_str()));
830 }
831 }
832 }
833 else
834 {
835 wxLogError(wxString(wxS("wxPdfFontParserTrueType::LoadFontData: ")) +
836 wxString::Format(_("Font index %d out of range for font file '%s'."), fontIndex, m_fileName.c_str()));
837 }
838
839 // Load data for a single font
840 if (ok)
841 {
842 if (ReadTableDirectory())
843 {
844 if (CheckTables())
845 {
846 CheckCff();
847 if (m_cff)
848 {
849 ok = fontData->GetType().IsSameAs(wxS("OpenTypeUnicode"));
850 }
851 else
852 {
853 ok = fontData->GetType().IsSameAs(wxS("TrueTypeUnicode"));
854 }
855 if (ok)
856 {
857 ok = PrepareFontData(fontData);
858 }
859 else
860 {
861 wxLogError(wxString(wxS("wxPdfFontParserTrueType::LoadFontData: ")) +
862 wxString::Format(_("Wrong font data type '%s' for font file '%s'."), fontData->GetType().c_str(), m_fileName.c_str()));
863 }
864 }
865 else
866 {
867 wxLogError(wxString(wxS("wxPdfFontParserTrueType::LoadFontData: ")) +
868 wxString::Format(_("Missing font tables for font file '%s'."), m_fileName.c_str()));
869 }
870 }
871 else
872 {
873 wxLogError(wxString(wxS("wxPdfFontParserTrueType::LoadFontData: ")) +
874 wxString::Format(_("Reading of font directory failed for font file '%s'."), m_fileName.c_str()));
875 }
876 }
877 if (fontFile != NULL)
878 {
879 delete fontFile;
880 }
881 if (fontStream != NULL)
882 {
883 delete fontStream;
884 }
885 }
886 else
887 {
888 wxLogError(wxString(wxS("wxPdfFontParserTrueType::LoadFontData: ")) +
889 wxString::Format(_("Font file '%s' not accessible."), m_fileName.c_str()));
890 }
891 }
892 else
893 {
894 wxLogError(wxString(wxS("wxPdfFontParserTrueType::LoadFontData: ")) +
895 wxString(_("No font data instance given.")));
896 }
897 return ok;
898 }
899
900 bool
PrepareFontData(wxPdfFontData * fontData)901 wxPdfFontParserTrueType::PrepareFontData(wxPdfFontData* fontData)
902 {
903 bool ok = ReadMaps();
904 if (ok)
905 {
906 wxPdfGlyphWidthMap* widths = new wxPdfGlyphWidthMap();
907 wxPdfChar2GlyphMap* glyphs = new wxPdfChar2GlyphMap();
908
909 wxPdfCMap* cMap;
910 if (m_cmapExt != NULL)
911 cMap = m_cmapExt;
912 else if (!m_fontSpecific && m_cmap31 != NULL)
913 cMap = m_cmap31;
914 else if (m_fontSpecific && m_cmap10 != NULL)
915 cMap = m_cmap10;
916 else if (m_cmap31 != NULL)
917 cMap = m_cmap31;
918 else
919 cMap = m_cmap10;
920 wxPdfCMap::iterator cMapIter;
921 int cc;
922 wxPdfCMapEntry* cMapEntry;
923 for (cMapIter = cMap->begin(); cMapIter != cMap->end(); cMapIter++)
924 {
925 cc = cMapIter->first;
926 cMapEntry = cMapIter->second;
927 (*widths)[cc] = cMapEntry->m_width;
928 (*glyphs)[cc] = cMapEntry->m_glyph;
929 }
930
931 fontData->SetGlyphWidthMap(widths);
932 fontData->SetChar2GlyphMap(glyphs);
933 fontData->SetGlyphWidths(m_glyphWidths);
934 fontData->SetKernPairMap(m_kp);
935 fontData->SetDescription(m_fd);
936 }
937
938 m_inFont->SeekI(0);
939 size_t len = (m_cff) ? m_cffLength : m_inFont->GetSize();
940 fontData->SetSize1(len);
941 #if wxUSE_UNICODE
942 fontData->CreateDefaultEncodingConv();
943 #endif
944 return ok;
945 }
946
947 bool
ReadTableDirectory()948 wxPdfFontParserTrueType::ReadTableDirectory()
949 {
950 ClearTableDirectory();
951 bool ok = true;
952 if (!m_isMacCoreText)
953 {
954 m_inFont->SeekI(m_directoryOffset);
955 int id = ReadInt();
956 // TrueType OpenType Mac TrueType
957 if (id == 0x00010000 || id == 0x4F54544F || id == 0x74727565)
958 {
959 int num_tables = ReadUShort();
960 SkipBytes(6);
961 int k;
962 for (k = 0; k < num_tables; ++k)
963 {
964 wxString tag = ReadString(4);
965 wxPdfTableDirectoryEntry* tableLocation = new wxPdfTableDirectoryEntry();
966 tableLocation->m_checksum = ReadInt();
967 tableLocation->m_offset = ReadInt();
968 tableLocation->m_length = ReadInt();
969 (*m_tableDirectory)[tag] = tableLocation;
970 }
971 }
972 else
973 {
974 if (!m_fileName.IsEmpty())
975 {
976 wxLogError(wxString(wxS("wxPdfFontParserTrueType::ReadTableDirectory: '")) +
977 wxString::Format(_("Font file '%s' not a valid TrueType (TTF) or OpenType (OTF) file."), m_fileName.c_str()));
978 }
979 ok = false;
980 }
981 }
982 else
983 {
984 #if defined(__WXMAC__)
985 #if wxPDFMACOSX_HAS_CORE_TEXT
986 CFArrayRef tables = CTFontCopyAvailableTables(m_fontRef, 0);
987 CFIndex nTables = CFArrayGetCount(tables);
988 CFIndex n;
989 for (n = 0; n < nTables; ++n)
990 {
991 CTFontTableTag tag = (CTFontTableTag)(uintptr_t) CFArrayGetValueAtIndex(tables, n);
992 CFDataRef tableRef = CTFontCopyTable(m_fontRef, tag, 0);
993 const UInt8* tableData = CFDataGetBytePtr(tableRef);
994 CFIndex tableLen = CFDataGetLength(tableRef);
995 int checksum = CalculateChecksum((const char*) tableData, (size_t) tableLen);
996 CFRelease(tableRef);
997 char asciiTag[5];
998 asciiTag[0] = (tag >> 24) & 0xff;
999 asciiTag[1] = (tag >> 16) & 0xff;
1000 asciiTag[2] = (tag >> 8) & 0xff;
1001 asciiTag[3] = tag & 0xff;
1002 asciiTag[4] = 0;
1003 wxString tableTag = wxString::FromAscii(asciiTag);
1004 wxPdfTableDirectoryEntry* tableLocation = new wxPdfTableDirectoryEntry();
1005 tableLocation->m_checksum = checksum;
1006 tableLocation->m_offset = 0;
1007 tableLocation->m_length = tableLen;
1008 (*m_tableDirectory)[tableTag] = tableLocation;
1009 }
1010 #else
1011 ok = false;
1012 #endif
1013 #endif
1014 }
1015 return ok;
1016 }
1017
1018 static const wxChar* checkTableNames[] = {
1019 wxS("cmap"), wxS("head"), wxS("hhea"), wxS("hmtx"), wxS("name"),
1020 wxS("post"),
1021 wxS("glyf"), wxS("loca"),
1022 NULL
1023 };
1024
1025 bool
CheckTables()1026 wxPdfFontParserTrueType::CheckTables()
1027 {
1028 bool ok = true;
1029 int maxTableCount = (m_tableDirectory->find(wxS("CFF ")) == m_tableDirectory->end()) ? 8 : 6;
1030 int tableCount = 0;
1031 while (ok && tableCount < maxTableCount && checkTableNames[tableCount] != NULL)
1032 {
1033 if (m_tableDirectory->find(checkTableNames[tableCount]) == m_tableDirectory->end())
1034 {
1035 ok = false;
1036 }
1037 ++tableCount;
1038 }
1039 return ok;
1040 }
1041
1042 void
CheckCff()1043 wxPdfFontParserTrueType::CheckCff()
1044 {
1045 wxPdfTableDirectoryEntry* tableLocation;
1046 wxPdfTableDirectory::iterator entry = m_tableDirectory->find(wxS("CFF "));
1047 if (entry != m_tableDirectory->end())
1048 {
1049 tableLocation = entry->second;
1050 m_cff = true;
1051 m_cffOffset = tableLocation->m_offset;
1052 m_cffLength = tableLocation->m_length;
1053 }
1054 else
1055 {
1056 m_cff = false;
1057 m_cffOffset = 0;
1058 m_cffLength = 0;
1059 }
1060 }
1061
1062 void
CheckRestrictions()1063 wxPdfFontParserTrueType::CheckRestrictions()
1064 {
1065 wxPdfTableDirectoryEntry* tableLocation;
1066 wxPdfTableDirectory::iterator entry = m_tableDirectory->find(wxS("OS/2"));
1067 if (entry != m_tableDirectory->end())
1068 {
1069 tableLocation = entry->second;
1070 LockTable(wxS("OS/2"));
1071 m_inFont->SeekI(tableLocation->m_offset+8);
1072 short fsType = ReadShort();
1073 bool rl = (fsType & 0x0002) != 0; // restricted license
1074 bool pp = (fsType & 0x0004) != 0; // preview and print embedding
1075 bool e = (fsType & 0x0008) != 0; // editable embedding
1076 bool ns = (fsType & 0x0100) != 0; // no subsetting
1077 bool b = (fsType & 0x0200) != 0; // bitmap embedding only
1078 m_embedAllowed = !((rl && !pp && !e) || b);
1079 m_subsetAllowed = !ns;
1080 ReleaseTable();
1081 }
1082 else
1083 {
1084 m_embedAllowed = true;
1085 m_subsetAllowed = true;
1086 }
1087 }
1088
1089 wxString
GetBaseFont()1090 wxPdfFontParserTrueType::GetBaseFont()
1091 {
1092 wxString fontName = wxEmptyString;
1093 wxPdfTableDirectoryEntry* tableLocation;
1094 wxPdfTableDirectory::iterator entry = m_tableDirectory->find(wxS("name"));
1095 if (entry != m_tableDirectory->end())
1096 {
1097 tableLocation = entry->second;
1098 LockTable(wxS("name"));
1099 m_inFont->SeekI(tableLocation->m_offset+2);
1100 int numRecords = ReadUShort();
1101 int startOfStorage = ReadUShort();
1102 int k;
1103 for (k = 0; k < numRecords; k++)
1104 {
1105 int platformID = ReadUShort();
1106 /* int platformEncodingID = */ ReadUShort();
1107 /* int languageID = */ ReadUShort();
1108 int nameID = ReadUShort();
1109 int length = ReadUShort();
1110 int offset = ReadUShort();
1111 if (nameID == 6)
1112 {
1113 m_inFont->SeekI(tableLocation->m_offset + startOfStorage + offset);
1114 if (platformID == 0 || platformID == 3)
1115 {
1116 fontName = ReadUnicodeString(length);
1117 }
1118 else
1119 {
1120 fontName = ReadString(length);
1121 }
1122 break;
1123 }
1124 }
1125 if (fontName.IsEmpty())
1126 {
1127 wxFileName::SplitPath(m_fileName, NULL, &fontName, NULL);
1128 fontName.Replace(wxS(" "), wxS("-"));
1129 }
1130 ReleaseTable();
1131 }
1132 else
1133 {
1134 wxLogError(wxString(wxS("wxPdfFontParserTrueType::GetBaseFont: "))+
1135 wxString::Format(_("Table 'name' does not exist in font file '%s'."), m_fileName.c_str()));
1136 }
1137 return fontName;
1138 }
1139
1140 bool
ReadMaps()1141 wxPdfFontParserTrueType::ReadMaps()
1142 {
1143 wxPdfFontHeader head;
1144 wxPdfHorizontalHeader hhea;
1145 wxPdfWindowsMetrics os_2;
1146 int realOS2TypoDescender;
1147
1148 wxPdfTableDirectoryEntry* tableLocation;
1149 wxPdfTableDirectory::iterator entry = m_tableDirectory->find(wxS("head"));
1150 if (entry == m_tableDirectory->end())
1151 {
1152 wxLogError(wxString(wxS("wxPdfFontParser::ReadMaps: ")) +
1153 wxString::Format(_("Table 'head' does not exist in '%s,%s'."), m_fileName.c_str(), m_style.c_str()));
1154 return false;
1155 }
1156 tableLocation = entry->second;
1157 LockTable(wxS("head"));
1158 m_inFont->SeekI(tableLocation->m_offset+16);
1159 head.m_flags = ReadUShort();
1160 head.m_unitsPerEm = ReadUShort();
1161 SkipBytes(16);
1162 head.m_xMin = ReadShort();
1163 head.m_yMin = ReadShort();
1164 head.m_xMax = ReadShort();
1165 head.m_yMax = ReadShort();
1166 head.m_macStyle = ReadUShort();
1167 ReleaseTable();
1168
1169 entry = m_tableDirectory->find(wxS("hhea"));
1170 if (entry == m_tableDirectory->end())
1171 {
1172 wxLogError(wxString(wxS("wxPdfFontParser::ReadMaps: ")) +
1173 wxString::Format(_("Table 'hhea' does not exist in '%s,%s'."), m_fileName.c_str(), m_style.c_str()));
1174 return false;
1175 }
1176 tableLocation = entry->second;
1177 LockTable(wxS("hhea"));
1178 m_inFont->SeekI(tableLocation->m_offset+4);
1179 hhea.m_ascender = ReadShort();
1180 hhea.m_descender = ReadShort();
1181 hhea.m_lineGap = ReadShort();
1182 hhea.m_advanceWidthMax = ReadUShort();
1183 hhea.m_minLeftSideBearing = ReadShort();
1184 hhea.m_minRightSideBearing = ReadShort();
1185 hhea.m_xMaxExtent = ReadShort();
1186 hhea.m_caretSlopeRise = ReadShort();
1187 hhea.m_caretSlopeRun = ReadShort();
1188 SkipBytes(12);
1189 hhea.m_numberOfHMetrics = ReadUShort();
1190 ReleaseTable();
1191
1192 entry = m_tableDirectory->find(wxS("OS/2"));
1193 if (entry != m_tableDirectory->end())
1194 {
1195 tableLocation = entry->second;
1196 LockTable(wxS("OS/2"));
1197 m_inFont->SeekI(tableLocation->m_offset);
1198 int version = ReadUShort();
1199 os_2.m_xAvgCharWidth = ReadShort();
1200 os_2.m_usWeightClass = ReadUShort();
1201 os_2.m_usWidthClass = ReadUShort();
1202 os_2.m_fsType = ReadShort();
1203 os_2.m_ySubscriptXSize = ReadShort();
1204 os_2.m_ySubscriptYSize = ReadShort();
1205 os_2.m_ySubscriptXOffset = ReadShort();
1206 os_2.m_ySubscriptYOffset = ReadShort();
1207 os_2.m_ySuperscriptXSize = ReadShort();
1208 os_2.m_ySuperscriptYSize = ReadShort();
1209 os_2.m_ySuperscriptXOffset = ReadShort();
1210 os_2.m_ySuperscriptYOffset = ReadShort();
1211 os_2.m_yStrikeoutSize = ReadShort();
1212 os_2.m_yStrikeoutPosition = ReadShort();
1213 os_2.m_sFamilyClass = ReadShort();
1214 m_inFont->Read(os_2.m_panose, 10);
1215 SkipBytes(16);
1216 m_inFont->Read(os_2.m_achVendID, 4);
1217 os_2.m_fsSelection = ReadUShort();
1218 os_2.m_usFirstCharIndex = ReadUShort();
1219 os_2.m_usLastCharIndex = ReadUShort();
1220 os_2.m_sTypoAscender = ReadShort();
1221 os_2.m_sTypoDescender = ReadShort();
1222 realOS2TypoDescender = os_2.m_sTypoDescender;
1223 if (os_2.m_sTypoDescender > 0)
1224 {
1225 os_2.m_sTypoDescender = (short)(-os_2.m_sTypoDescender);
1226 }
1227 os_2.m_sTypoLineGap = ReadShort();
1228 os_2.m_usWinAscent = ReadUShort();
1229 os_2.m_usWinDescent = ReadUShort();
1230 os_2.m_ulCodePageRange1 = 0;
1231 os_2.m_ulCodePageRange2 = 0;
1232 if (version > 0)
1233 {
1234 os_2.m_ulCodePageRange1 = ReadInt();
1235 os_2.m_ulCodePageRange2 = ReadInt();
1236 }
1237 if (version > 1)
1238 {
1239 os_2.m_sxHeight = ReadShort();
1240 os_2.m_sCapHeight = ReadShort();
1241 }
1242 else
1243 {
1244 os_2.m_sxHeight = 0;
1245 os_2.m_sCapHeight = (int)(0.7 * head.m_unitsPerEm);
1246 }
1247 ReleaseTable();
1248 m_fd.SetOpenTypeMetrics(
1249 (int) (hhea.m_ascender * 1000 / head.m_unitsPerEm),
1250 (int) (hhea.m_descender * 1000 / head.m_unitsPerEm),
1251 (int) (hhea.m_lineGap * 1000 / head.m_unitsPerEm),
1252 (int) (os_2.m_sTypoAscender * 1000 / head.m_unitsPerEm),
1253 (int) (realOS2TypoDescender * 1000 / head.m_unitsPerEm),
1254 (int) (os_2.m_sTypoLineGap * 1000 / head.m_unitsPerEm),
1255 (int) (os_2.m_usWinAscent * 1000 / head.m_unitsPerEm),
1256 (int) (os_2.m_usWinDescent * 1000 / head.m_unitsPerEm)
1257 );
1258 }
1259 else
1260 {
1261 // TODO: check definition of hhea values, convert if necessary
1262 os_2.m_sTypoAscender = hhea.m_ascender;
1263 os_2.m_sTypoDescender = hhea.m_descender;
1264 if (os_2.m_sTypoDescender > 0)
1265 {
1266 os_2.m_sTypoDescender = (short)(-os_2.m_sTypoDescender);
1267 }
1268 os_2.m_sxHeight = 0;
1269 os_2.m_sCapHeight = (int)(0.7 * head.m_unitsPerEm);
1270 if (os_2.m_sCapHeight > os_2.m_sTypoAscender)
1271 {
1272 os_2.m_sCapHeight = os_2.m_sTypoAscender;
1273 }
1274 }
1275
1276 int underlinePosition = -100;
1277 int underlineThickness = 50;
1278
1279 double italicAngle;
1280 entry = m_tableDirectory->find(wxS("post"));
1281 if (entry == m_tableDirectory->end())
1282 {
1283 static double pi = 4. * atan(1.0);
1284 double caretSlopeRun = (double) hhea.m_caretSlopeRun;
1285 double caretSlopeRise = (double) hhea.m_caretSlopeRise;
1286 italicAngle = -atan2(caretSlopeRun, caretSlopeRise) * 180. / pi;
1287 }
1288 else
1289 {
1290 tableLocation = entry->second;
1291 LockTable(wxS("post"));
1292 m_inFont->SeekI(tableLocation->m_offset+4);
1293 short mantissa = ReadShort();
1294 int fraction = ReadUShort();
1295 italicAngle = (double) mantissa + (double) fraction / 16384.0;
1296 underlinePosition = ReadShort();
1297 underlineThickness = ReadShort();
1298 m_isFixedPitch = ReadInt() != 0;
1299 ReleaseTable();
1300 }
1301
1302 ReadGlyphWidths(hhea.m_numberOfHMetrics, head.m_unitsPerEm);
1303 ReadKerning(head.m_unitsPerEm);
1304
1305 m_fd.SetAscent((int) (os_2.m_sTypoAscender * 1000 / head.m_unitsPerEm));
1306 m_fd.SetDescent((int) (os_2.m_sTypoDescender * 1000 / head.m_unitsPerEm));
1307 m_fd.SetCapHeight((int) (os_2.m_sCapHeight * 1000 / head.m_unitsPerEm));
1308 m_fd.SetXHeight((int) (os_2.m_sxHeight * 1000 / head.m_unitsPerEm));
1309 m_fd.SetItalicAngle((int) italicAngle);
1310 m_fd.SetStemV(80);
1311 m_fd.SetUnderlinePosition((int) (underlinePosition * 1000 / head.m_unitsPerEm));
1312 m_fd.SetUnderlineThickness((int) (underlineThickness * 1000 / head.m_unitsPerEm));
1313 m_fd.SetMissingWidth(GetGlyphWidth(0));
1314
1315 #if 0
1316 int m_stemV; ///< StemV
1317 #endif
1318
1319 int flags = 0;
1320 if (m_isFixedPitch)
1321 {
1322 flags |= 1;
1323 }
1324 if ((head.m_macStyle & 2) != 0)
1325 {
1326 flags |= 64;
1327 }
1328 if ((head.m_macStyle & 1) != 0)
1329 {
1330 flags |= 262144;
1331 }
1332 m_fd.SetFlags(flags);
1333
1334 wxString fbb = wxString::Format(wxS("[%d %d %d %d]"),
1335 (int) (head.m_xMin * 1000 / head.m_unitsPerEm),
1336 (int) (head.m_yMin * 1000 / head.m_unitsPerEm),
1337 (int) (head.m_xMax * 1000 / head.m_unitsPerEm),
1338 (int) (head.m_yMax * 1000 / head.m_unitsPerEm));
1339 m_fd.SetFontBBox(fbb);
1340
1341 entry = m_tableDirectory->find(wxS("cmap"));
1342 if (entry == m_tableDirectory->end())
1343 {
1344 wxLogError(wxString(wxS("wxPdfFontParser::ReadMaps: ")) +
1345 wxString::Format(_("Table 'cmap' does not exist in '%s,%s'."), m_fileName.c_str(), m_style.c_str()));
1346 return false;
1347 }
1348 tableLocation = entry->second;
1349 LockTable(wxS("cmap"));
1350 m_inFont->SeekI(tableLocation->m_offset);
1351 SkipBytes(2);
1352 int num_tables = ReadUShort();
1353 m_fontSpecific = false;
1354 int map10 = 0;
1355 int map31 = 0;
1356 int map30 = 0;
1357 int mapExt = 0;
1358 int k;
1359 for (k = 0; k < num_tables; ++k)
1360 {
1361 int platId = ReadUShort();
1362 int platSpecId = ReadUShort();
1363 int offset = ReadInt();
1364 if (platId == 3 && platSpecId == 0)
1365 {
1366 m_fontSpecific = true;
1367 map30 = offset;
1368 }
1369 else if (platId == 3 && platSpecId == 1)
1370 {
1371 map31 = offset;
1372 }
1373 else if (platId == 3 && platSpecId == 10)
1374 {
1375 mapExt = offset;
1376 }
1377 else if (platId == 1 && platSpecId == 0)
1378 {
1379 map10 = offset;
1380 }
1381 else if (platId == 0) // Apple Unicode
1382 {
1383 // Formats 0, 2, 4, 6, 8, 10, 12
1384 if (platSpecId < 4)
1385 {
1386 map31 = offset;
1387 }
1388 else if (platSpecId == 4) // UCS32
1389 {
1390 mapExt = offset;
1391 }
1392 }
1393 }
1394 if (map10 > 0 && map30 <= 0)
1395 {
1396 m_inFont->SeekI(tableLocation->m_offset + map10);
1397 int format = ReadUShort();
1398 switch (format)
1399 {
1400 case 0:
1401 m_cmap10 = ReadFormat0();
1402 break;
1403 case 4:
1404 m_cmap10 = ReadFormat4();
1405 break;
1406 case 6:
1407 m_cmap10 = ReadFormat6();
1408 break;
1409 }
1410 }
1411 if (map31 > 0)
1412 {
1413 m_inFont->SeekI(tableLocation->m_offset + map31);
1414 int format = ReadUShort();
1415 if (format == 4)
1416 {
1417 m_cmap31 = ReadFormat4();
1418 }
1419 }
1420 if (map30 > 0)
1421 {
1422 m_inFont->SeekI(tableLocation->m_offset + map30);
1423 int format = ReadUShort();
1424 if (format == 4)
1425 {
1426 m_cmap10 = ReadFormat4();
1427 }
1428 }
1429 if (mapExt > 0)
1430 {
1431 m_inFont->SeekI(tableLocation->m_offset + mapExt);
1432 int format = ReadUShort();
1433 switch (format)
1434 {
1435 case 0:
1436 m_cmapExt = ReadFormat0();
1437 break;
1438 case 4:
1439 m_cmapExt = ReadFormat4();
1440 break;
1441 case 6:
1442 m_cmapExt = ReadFormat6();
1443 break;
1444 case 12:
1445 m_cmapExt = ReadFormat12();
1446 break;
1447 }
1448 }
1449 ReleaseTable();
1450
1451 flags = m_fd.GetFlags();
1452 flags |= m_fontSpecific ? 4 : 32;
1453 m_fd.SetFlags(flags);
1454
1455 bool ok = (m_cmap10 != NULL) || (m_cmap31 != NULL) || (m_cmapExt != NULL);
1456 if (!ok)
1457 {
1458 wxLogError(wxString(wxS("wxPdfFontParserTrueType::ReadMaps: ")) +
1459 wxString::Format(_("No valid 'cmap' table found for font '%s'."), m_fontName.c_str()));
1460 }
1461
1462 return ok;
1463 }
1464
1465 bool
ReadGlyphWidths(int numberOfHMetrics,int unitsPerEm)1466 wxPdfFontParserTrueType::ReadGlyphWidths(int numberOfHMetrics, int unitsPerEm)
1467 {
1468 wxPdfTableDirectoryEntry* tableLocation;
1469 wxPdfTableDirectory::iterator entry = m_tableDirectory->find(wxS("hmtx"));
1470 if (entry == m_tableDirectory->end())
1471 {
1472 wxLogError(wxString(wxS("wxPdfFontParser::ReadGlyphWidths: ")) +
1473 wxString::Format(_("Table 'hmtx' does not exist in '%s,%s'."), m_fileName.c_str(), m_style.c_str()));
1474 return false;
1475 }
1476 tableLocation = entry->second;
1477 LockTable(wxS("hmtx"));
1478 m_inFont->SeekI(tableLocation->m_offset);
1479
1480 m_glyphWidths.SetCount(numberOfHMetrics);
1481 int k;
1482 for (k = 0; k < numberOfHMetrics; k++)
1483 {
1484 m_glyphWidths[k] = (ReadUShort() * 1000) / unitsPerEm;
1485 ReadUShort();
1486 }
1487 ReleaseTable();
1488 return true;
1489 }
1490
1491 wxPdfCMap*
ReadFormat0()1492 wxPdfFontParserTrueType::ReadFormat0()
1493 {
1494 wxPdfCMap* h = new wxPdfCMap();
1495 SkipBytes(4);
1496 int k;
1497 for (k = 0; k < 256; k++)
1498 {
1499 wxPdfCMapEntry* r = new wxPdfCMapEntry();
1500 r->m_glyph = (int) ReadByte();
1501 r->m_width = GetGlyphWidth(r->m_glyph);
1502 (*h)[k] = r;
1503 }
1504 return h;
1505 }
1506
1507 wxPdfCMap*
ReadFormat4()1508 wxPdfFontParserTrueType::ReadFormat4()
1509 {
1510 wxPdfCMap* h = new wxPdfCMap();
1511 int tableLength = ReadUShort();
1512 SkipBytes(2);
1513 int segCount = ReadUShort() / 2;
1514 int glyphIdCount = tableLength / 2 - 8 - segCount * 4;
1515 SkipBytes(6);
1516
1517 int* endCount = new int[segCount];
1518 int* startCount = new int[segCount];
1519 int* idDelta = new int[segCount];
1520 int* idRO = new int[segCount];
1521 int* glyphId = new int[glyphIdCount];
1522
1523 int k;
1524 for (k = 0; k < segCount; k++)
1525 {
1526 endCount[k] = ReadUShort();
1527 }
1528 SkipBytes(2);
1529 for (k = 0; k < segCount; k++)
1530 {
1531 startCount[k] = ReadUShort();
1532 }
1533 for (k = 0; k < segCount; k++)
1534 {
1535 idDelta[k] = ReadUShort();
1536 }
1537 for (k = 0; k < segCount; k++)
1538 {
1539 idRO[k] = ReadUShort();
1540 }
1541 for (k = 0; k < glyphIdCount; k++)
1542 {
1543 glyphId[k] = ReadUShort();
1544 }
1545 for (k = 0; k < segCount; k++)
1546 {
1547 int glyph;
1548 int j;
1549 for (j = startCount[k]; j <= endCount[k] && j != 0xFFFF; j++)
1550 {
1551 if (idRO[k] == 0)
1552 {
1553 glyph = (j + idDelta[k]) & 0xFFFF;
1554 }
1555 else
1556 {
1557 int idx = k + idRO[k] / 2 - segCount + j - startCount[k];
1558 if (idx >= glyphIdCount)
1559 continue;
1560 glyph = (glyphId[idx] + idDelta[k]) & 0xFFFF;
1561 }
1562 wxPdfCMapEntry* r = new wxPdfCMapEntry();
1563 r->m_glyph = glyph;
1564 r->m_width = GetGlyphWidth(r->m_glyph);
1565 int idx = m_fontSpecific ? ((j & 0xff00) == 0xf000 ? j & 0xff : j) : j;
1566 (*h)[idx] = r;
1567 // wxLogMessage(wxS("C %ld G %ld"), idx, glyph);
1568 }
1569 }
1570
1571 delete [] endCount;
1572 delete [] startCount;
1573 delete [] idDelta;
1574 delete [] idRO;
1575 delete [] glyphId;
1576
1577 return h;
1578 }
1579
1580 wxPdfCMap*
ReadFormat6()1581 wxPdfFontParserTrueType::ReadFormat6()
1582 {
1583 wxPdfCMap* h = new wxPdfCMap();
1584 SkipBytes(4);
1585 int startCode = ReadUShort();
1586 int codeCount = ReadUShort();
1587 int k;
1588 for (k = 0; k < codeCount; k++)
1589 {
1590 wxPdfCMapEntry* r = new wxPdfCMapEntry();
1591 r->m_glyph = ReadUShort();
1592 r->m_width = GetGlyphWidth(r->m_glyph);
1593 (*h)[k+startCode] = r;
1594 }
1595 return h;
1596 }
1597
1598 wxPdfCMap*
ReadFormat12()1599 wxPdfFontParserTrueType::ReadFormat12()
1600 {
1601 wxPdfCMap* h = new wxPdfCMap();
1602 SkipBytes(2);
1603 /* int tableLength = */ ReadInt();
1604 SkipBytes(4);
1605 int nGroups = ReadInt();
1606
1607 for (int k = 0; k < nGroups; k++)
1608 {
1609 int startCharCode = ReadInt();
1610 int endCharCode = ReadInt();
1611 int startGlyphID = ReadInt();
1612 int i;
1613 for (i = startCharCode; i <= endCharCode; ++i)
1614 {
1615 wxPdfCMapEntry* r = new wxPdfCMapEntry();
1616 r->m_glyph = startGlyphID;
1617 r->m_width = GetGlyphWidth(r->m_glyph);
1618 (*h)[i] = r;
1619 ++startGlyphID;
1620 }
1621 }
1622 return h;
1623 }
1624
1625 void
ReadKerning(int unitsPerEm)1626 wxPdfFontParserTrueType::ReadKerning(int unitsPerEm)
1627 {
1628 wxPdfTableDirectoryEntry* tableLocation;
1629 wxPdfTableDirectory::iterator entry = m_tableDirectory->find(wxS("kern"));
1630 if (entry != m_tableDirectory->end())
1631 {
1632 tableLocation = entry->second;
1633 LockTable(wxS("kern"));
1634 m_kp = new wxPdfKernPairMap();
1635 wxPdfKernWidthMap* kwMap = NULL;
1636 wxPdfKernWidthMap::iterator kw;
1637 wxUint32 u1, u2;
1638 wxUint32 u1prev = 0;
1639
1640 m_inFont->SeekI(tableLocation->m_offset+2);
1641 int nTables = ReadUShort();
1642 int checkpoint = tableLocation->m_offset + 4;
1643 int length = 0;
1644 int j, k;
1645 for (k = 0; k < nTables; ++k)
1646 {
1647 checkpoint += length;
1648 m_inFont->SeekI(checkpoint);
1649 SkipBytes(2);
1650 length = ReadUShort();
1651 int coverage = ReadUShort();
1652 if ((coverage & 0xfff7) == 0x0001)
1653 {
1654 int nPairs = ReadUShort();
1655 SkipBytes(6);
1656 for (j = 0; j < nPairs; ++j)
1657 {
1658 u1 = ReadUShort();
1659 u2 = ReadUShort();
1660 int value = ((int) ReadShort() * 1000) / unitsPerEm;
1661 if (u1 != u1prev)
1662 {
1663 u1prev = u1;
1664 wxPdfKernPairMap::iterator kp = (*m_kp).find(u1);
1665 if (kp == (*m_kp).end())
1666 {
1667 kwMap = new wxPdfKernWidthMap();
1668 (*m_kp)[u1] = kwMap;
1669 }
1670 else
1671 {
1672 kwMap = kp->second;
1673 }
1674 }
1675 (*kwMap)[u2] = value;
1676 }
1677 }
1678 }
1679 ReleaseTable();
1680 }
1681 }
1682
1683 int
GetGlyphWidth(unsigned int glyph)1684 wxPdfFontParserTrueType::GetGlyphWidth(unsigned int glyph)
1685 {
1686 if (glyph >= m_glyphWidths.GetCount())
1687 {
1688 glyph = (unsigned int) m_glyphWidths.GetCount() - 1;
1689 }
1690 return m_glyphWidths[glyph];
1691 }
1692
1693 wxArrayString
GetUniqueNames(int id)1694 wxPdfFontParserTrueType::GetUniqueNames(int id)
1695 {
1696 wxArrayString uniqueNames;
1697 wxArrayString names = GetNames(id);
1698 size_t j;
1699 for (j = 0; j < names.GetCount(); ++j)
1700 {
1701 if (uniqueNames.Index(names[j], false) == wxNOT_FOUND)
1702 {
1703 uniqueNames.Add(names[j]);
1704 }
1705 }
1706 return uniqueNames;
1707 }
1708
1709 wxArrayString
GetNames(int id,bool namesOnly)1710 wxPdfFontParserTrueType::GetNames(int id, bool namesOnly)
1711 {
1712 wxArrayString names;
1713 wxPdfTableDirectoryEntry* tableLocation;
1714 wxPdfTableDirectory::iterator entry = m_tableDirectory->find(wxS("name"));
1715 if (entry != m_tableDirectory->end())
1716 {
1717 tableLocation = entry->second;
1718 LockTable(wxS("name"));
1719 m_inFont->SeekI(tableLocation->m_offset+2);
1720 int numRecords = ReadUShort();
1721 int startOfStorage = ReadUShort();
1722 int k;
1723 for (k = 0; k < numRecords; k++)
1724 {
1725 int platformID = ReadUShort();
1726 int platformEncodingID = ReadUShort();
1727 int languageID = ReadUShort();
1728 int nameID = ReadUShort();
1729 int length = ReadUShort();
1730 int offset = ReadUShort();
1731 if (nameID == id)
1732 {
1733 off_t pos = m_inFont->TellI();
1734 m_inFont->SeekI(tableLocation->m_offset + startOfStorage + offset);
1735 wxString name;
1736 if (platformID == 0 || platformID == 3 || (platformID == 2 && platformEncodingID == 1))
1737 {
1738 name = ReadUnicodeString(length);
1739 }
1740 else
1741 {
1742 name = ReadString(length);
1743 }
1744 if (!namesOnly)
1745 {
1746 names.Add(wxString::Format(wxS("%d"), platformID));
1747 names.Add(wxString::Format(wxS("%d"), platformEncodingID));
1748 names.Add(wxString::Format(wxS("%d"), languageID));
1749 }
1750 names.Add(name);
1751 m_inFont->SeekI(pos);
1752 }
1753 }
1754 ReleaseTable();
1755 }
1756 else
1757 {
1758 wxLogError(wxString(wxS("wxPdfFontParser::GetNames: ")) +
1759 wxString::Format(_("Table 'name' does not exist in '%s,%s'."), m_fileName.c_str(), m_style.c_str()));
1760 }
1761 return names;
1762 }
1763
1764 wxString
GetEnglishName(int id)1765 wxPdfFontParserTrueType::GetEnglishName(int id)
1766 {
1767 wxString englishName = wxEmptyString;
1768 wxPdfTableDirectoryEntry* tableLocation;
1769 wxPdfTableDirectory::iterator entry = m_tableDirectory->find(wxS("name"));
1770 if (entry != m_tableDirectory->end())
1771 {
1772 tableLocation = entry->second;
1773 LockTable(wxS("name"));
1774 m_inFont->SeekI(tableLocation->m_offset+2);
1775 int numRecords = ReadUShort();
1776 int startOfStorage = ReadUShort();
1777 bool ready = false;
1778 int k;
1779 for (k = 0; !ready && (k < numRecords); k++)
1780 {
1781 int platformID = ReadUShort();
1782 int platformEncodingID = ReadUShort();
1783 int languageID = ReadUShort();
1784 int nameID = ReadUShort();
1785 int length = ReadUShort();
1786 int offset = ReadUShort();
1787 if (nameID == id)
1788 {
1789 off_t pos = m_inFont->TellI();
1790 m_inFont->SeekI(tableLocation->m_offset + startOfStorage + offset);
1791 wxString name;
1792 if (platformID == 0 || platformID == 3 || (platformID == 2 && platformEncodingID == 1))
1793 {
1794 name = ReadUnicodeString(length);
1795 }
1796 else
1797 {
1798 name = ReadString(length);
1799 }
1800 if (!ready)
1801 {
1802 if (languageID == 0)
1803 {
1804 englishName = name;
1805 ready = true;
1806 }
1807 else if (languageID == 1033)
1808 {
1809 englishName = name;
1810 }
1811 }
1812 m_inFont->SeekI(pos);
1813 }
1814 }
1815 ReleaseTable();
1816 }
1817 else
1818 {
1819 wxLogError(wxString(wxS("wxPdfFontParserTrueType::GetEnglishName: ")) +
1820 wxString::Format(_("Table 'name' does not exist in '%s,%s'."), m_fileName.c_str(), m_style.c_str()));
1821 }
1822 return englishName;
1823 }
1824