1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
23 * Author: Alexander Gelfenbain
41 #include <rtl/ustring.hxx>
42 #include <o3tl/safeint.hxx>
43 #include <osl/endian.h>
49 /*- module identification */
51 static const char *modname
= "SunTypeTools-TT";
52 static const char *modver
= "1.0";
53 static const char *modextra
= "gelf";
55 /*- private functions, constants and data types */
57 enum PathSegmentType
{
72 explicit PSPathElement( PathSegmentType i_eType
) : type( i_eType
),
80 /*- In horizontal writing mode right sidebearing is calculated using this formula
81 *- rsb = aw - (lsb + xMax - xMin) -*/
87 sal_uInt16 aw
; /*- Advance Width (horizontal writing mode) */
88 sal_Int16 lsb
; /*- Left sidebearing (horizontal writing mode) */
89 sal_uInt16 ah
; /*- advance height (vertical writing mode) */
90 sal_Int16 tsb
; /*- top sidebearing (vertical writing mode) */
93 #define HFORMAT_LINELEN 64
97 char buffer
[HFORMAT_LINELEN
];
103 sal_uInt32 nGlyphs
; /* number of glyphs in the font + 1 */
104 sal_uInt32
*offs
; /* array of nGlyphs offsets */
107 static const sal_uInt32 T_true
= 0x74727565; /* 'true' */
108 static const sal_uInt32 T_ttcf
= 0x74746366; /* 'ttcf' */
109 static const sal_uInt32 T_otto
= 0x4f54544f; /* 'OTTO' */
111 /* standard TrueType table tags */
112 #define T_maxp 0x6D617870
113 #define T_glyf 0x676C7966
114 #define T_head 0x68656164
115 #define T_loca 0x6C6F6361
116 #define T_name 0x6E616D65
117 #define T_hhea 0x68686561
118 #define T_hmtx 0x686D7478
119 #define T_cmap 0x636D6170
120 #define T_vhea 0x76686561
121 #define T_vmtx 0x766D7478
122 #define T_OS2 0x4F532F32
123 #define T_post 0x706F7374
124 #define T_kern 0x6B65726E
125 #define T_cvt 0x63767420
126 #define T_prep 0x70726570
127 #define T_fpgm 0x6670676D
128 #define T_gsub 0x47535542
129 #define T_CFF 0x43464620
131 static void *smalloc(size_t size
)
133 void *res
= malloc(size
);
134 assert(res
!= nullptr);
138 static void *scalloc(size_t n
, size_t size
)
140 void *res
= calloc(n
, size
);
141 assert(res
!= nullptr);
145 /*- Data access methods for data stored in big-endian format */
146 static sal_Int16
GetInt16(const sal_uInt8
*ptr
, size_t offset
)
149 assert(ptr
!= nullptr);
151 t
= (ptr
+offset
)[0] << 8 | (ptr
+offset
)[1];
156 static sal_uInt16
GetUInt16(const sal_uInt8
*ptr
, size_t offset
)
159 assert(ptr
!= nullptr);
161 t
= (ptr
+offset
)[0] << 8 | (ptr
+offset
)[1];
166 static sal_Int32
GetInt32(const sal_uInt8
*ptr
, size_t offset
)
169 assert(ptr
!= nullptr);
171 t
= (ptr
+offset
)[0] << 24 | (ptr
+offset
)[1] << 16 |
172 (ptr
+offset
)[2] << 8 | (ptr
+offset
)[3];
177 static sal_uInt32
GetUInt32(const sal_uInt8
*ptr
, size_t offset
)
180 assert(ptr
!= nullptr);
182 t
= (ptr
+offset
)[0] << 24 | (ptr
+offset
)[1] << 16 |
183 (ptr
+offset
)[2] << 8 | (ptr
+offset
)[3];
188 #if defined(OSL_BIGENDIAN)
189 #define Int16FromMOTA(a) (a)
190 #define Int32FromMOTA(a) (a)
192 static sal_uInt16
Int16FromMOTA(sal_uInt16 a
) {
193 return (sal_uInt16
) (((sal_uInt8
)((a
) >> 8)) | ((sal_uInt8
)(a
) << 8));
195 static sal_uInt32
Int32FromMOTA(sal_uInt32 a
) {
196 return ((a
>>24)&0xFF) | (((a
>>8)&0xFF00) | ((a
&0xFF00)<<8) | ((a
&0xFF)<<24));
200 static F16Dot16
fixedMul(F16Dot16 a
, F16Dot16 b
)
207 sign
= (a
& 0x80000000) ^ (b
& 0x80000000);
218 /* if (res > 0x7FFF) assert(!"fixedMul: F16Dot16 overflow"); */
221 res
+= a1
* b2
+ b1
* a2
+ ((b1
* b2
) >> 16);
223 return sign
? -res
: res
;
226 static F16Dot16
fixedDiv(F16Dot16 a
, F16Dot16 b
)
232 sign
= (a
& 0x80000000) ^ (b
& 0x80000000);
239 /* if (f > 0x7FFFF) assert(!"fixedDiv: F16Dot16 overflow"); */
246 res
= (f
<< 16) + (r
<< 16) / b
;
248 return sign
? -res
: res
;
251 /*- returns a * b / c -*/
252 /* XXX provide a real implementation that preserves accuracy */
253 static F16Dot16
fixedMulDiv(F16Dot16 a
, F16Dot16 b
, F16Dot16 c
)
257 res
= fixedMul(a
, b
);
258 return fixedDiv(res
, c
);
261 /*- Translate units from TT to PS (standard 1/1000) -*/
262 static int XUnits(int unitsPerEm
, int n
)
264 return (n
* 1000) / unitsPerEm
;
267 static const sal_uInt8
* getTable( TrueTypeFont
*ttf
, sal_uInt32 ord
)
269 return ttf
->tables
[ord
];
272 static sal_uInt32
getTableSize(TrueTypeFont
*ttf
, sal_uInt32 ord
)
274 return ttf
->tlens
[ord
];
277 /* Hex Formatter functions */
278 static const char HexChars
[] = "0123456789ABCDEF";
280 static HexFmt
*HexFmtNew(FILE *outf
)
282 HexFmt
* res
= static_cast<HexFmt
*>(smalloc(sizeof(HexFmt
)));
283 res
->bufpos
= res
->total
= 0;
288 static bool HexFmtFlush(HexFmt
*_this
)
292 size_t nWritten
= fwrite(_this
->buffer
, 1, _this
->bufpos
, _this
->o
);
293 bRet
= nWritten
== _this
->bufpos
;
299 static void HexFmtOpenString(HexFmt
*_this
)
301 fputs("<\n", _this
->o
);
304 static void HexFmtCloseString(HexFmt
*_this
)
307 fputs("00\n>\n", _this
->o
);
310 static void HexFmtDispose(HexFmt
*_this
)
316 static void HexFmtBlockWrite(HexFmt
*_this
, const void *ptr
, sal_uInt32 size
)
321 if (_this
->total
+ size
> 65534) {
323 HexFmtCloseString(_this
);
325 HexFmtOpenString(_this
);
327 for (i
=0; i
<size
; i
++) {
328 Ch
= static_cast<sal_uInt8
const *>(ptr
)[i
];
329 _this
->buffer
[_this
->bufpos
++] = HexChars
[Ch
>> 4];
330 _this
->buffer
[_this
->bufpos
++] = HexChars
[Ch
& 0xF];
331 if (_this
->bufpos
== HFORMAT_LINELEN
) {
333 fputc('\n', _this
->o
);
337 _this
->total
+= size
;
340 /* Outline Extraction functions */
342 /* fills the aw and lsb entries of the TTGlyphMetrics structure from hmtx table -*/
343 static void GetMetrics(TrueTypeFont
*ttf
, sal_uInt32 glyphID
, TTGlyphMetrics
*metrics
)
345 const sal_uInt8
* table
= getTable( ttf
, O_hmtx
);
347 metrics
->aw
= metrics
->lsb
= metrics
->ah
= metrics
->tsb
= 0;
348 if (!table
|| !ttf
->numberOfHMetrics
) return;
350 if (glyphID
< ttf
->numberOfHMetrics
) {
351 metrics
->aw
= GetUInt16(table
, 4 * glyphID
);
352 metrics
->lsb
= GetInt16(table
, 4 * glyphID
+ 2);
354 metrics
->aw
= GetUInt16(table
, 4 * (ttf
->numberOfHMetrics
- 1));
355 metrics
->lsb
= GetInt16(table
+ ttf
->numberOfHMetrics
* 4, (glyphID
- ttf
->numberOfHMetrics
) * 2);
358 table
= getTable(ttf
, O_vmtx
);
359 if( !table
|| !ttf
->numOfLongVerMetrics
)
362 if (glyphID
< ttf
->numOfLongVerMetrics
) {
363 metrics
->ah
= GetUInt16(table
, 4 * glyphID
);
364 metrics
->tsb
= GetInt16(table
, 4 * glyphID
+ 2);
366 metrics
->ah
= GetUInt16(table
, 4 * (ttf
->numOfLongVerMetrics
- 1));
367 metrics
->tsb
= GetInt16(table
+ ttf
->numOfLongVerMetrics
* 4, (glyphID
- ttf
->numOfLongVerMetrics
) * 2);
371 static int GetTTGlyphOutline(TrueTypeFont
*, sal_uInt32
, ControlPoint
**, TTGlyphMetrics
*, std::vector
< sal_uInt32
>* );
373 /* returns the number of control points, allocates the pointArray */
374 static int GetSimpleTTOutline(TrueTypeFont
*ttf
, sal_uInt32 glyphID
, ControlPoint
**pointArray
, TTGlyphMetrics
*metrics
)
376 const sal_uInt8
* table
= getTable(ttf
, O_glyf
);
377 const sal_uInt32 nTableSize
= getTableSize(ttf
, O_glyf
);
381 *pointArray
= nullptr;
383 /* printf("GetSimpleTTOutline(%d)\n", glyphID); */
385 if( glyphID
>= ttf
->nglyphs
) /*- glyph is not present in the font */
387 const sal_uInt8
* ptr
= table
+ ttf
->goffsets
[glyphID
];
388 const sal_Int16 numberOfContours
= GetInt16(ptr
, 0);
389 if( numberOfContours
<= 0 ) /*- glyph is not simple */
392 if (metrics
) { /*- GetCompoundTTOutline() calls this function with NULL metrics -*/
393 metrics
->xMin
= GetInt16(ptr
, 2);
394 metrics
->yMin
= GetInt16(ptr
, 4);
395 metrics
->xMax
= GetInt16(ptr
, 6);
396 metrics
->yMax
= GetInt16(ptr
, 8);
397 GetMetrics(ttf
, glyphID
, metrics
);
400 /* determine the last point and be extra safe about it. But probably this code is not needed */
401 sal_uInt16 lastPoint
=0;
402 const sal_Int32 nMaxContours
= (nTableSize
- 10)/2;
403 if (numberOfContours
> nMaxContours
)
405 for (i
=0; i
<numberOfContours
; i
++)
407 const sal_uInt16 t
= GetUInt16(ptr
, 10+i
*2);
412 sal_uInt16 instLen
= GetUInt16(ptr
, 10 + numberOfContours
*2);
413 sal_uInt32 nOffset
= 10 + 2 * numberOfContours
+ 2 + instLen
;
414 if (nOffset
> nTableSize
)
416 const sal_uInt8
* p
= ptr
+ nOffset
;
418 const sal_uInt32 nBytesRemaining
= nTableSize
- nOffset
;
419 const sal_uInt16 palen
= lastPoint
+1;
421 //at a minimum its one byte per entry
422 if (palen
> nBytesRemaining
|| lastPoint
> nBytesRemaining
-1)
424 SAL_WARN("vcl.fonts", "Font " << OUString::createFromAscii(ttf
->fname
) <<
425 "claimed a palen of "
426 << palen
<< " but max bytes remaining is " << nBytesRemaining
);
430 ControlPoint
* pa
= static_cast<ControlPoint
*>(calloc(palen
, sizeof(ControlPoint
)));
433 while (i
<= lastPoint
) {
434 pa
[i
++].flags
= (sal_uInt32
) (flag
= *p
++);
435 if (flag
& 8) { /*- repeat flag */
437 for (j
=0; j
<n
; j
++) {
438 if (i
> lastPoint
) { /*- if the font is really broken */
442 pa
[i
++].flags
= flag
;
447 /*- Process the X coordinate */
449 for (i
= 0; i
<= lastPoint
; i
++) {
450 if (pa
[i
].flags
& 0x02) {
451 if (pa
[i
].flags
& 0x10) {
456 } else if ( !(pa
[i
].flags
& 0x10)) {
460 pa
[i
].x
= (sal_Int16
)z
;
463 /*- Process the Y coordinate */
465 for (i
= 0; i
<= lastPoint
; i
++) {
466 if (pa
[i
].flags
& 0x04) {
467 if (pa
[i
].flags
& 0x20) {
472 } else if ( !(pa
[i
].flags
& 0x20)) {
476 pa
[i
].y
= (sal_Int16
)z
;
479 for (i
=0; i
<numberOfContours
; i
++) {
480 sal_uInt16 offset
= GetUInt16(ptr
, 10 + i
* 2);
481 SAL_WARN_IF(offset
>= palen
, "vcl.fonts", "Font " << OUString::createFromAscii(ttf
->fname
) <<
482 " contour " << i
<< " claimed an illegal offset of "
483 << offset
<< " but max offset is " << palen
-1);
486 pa
[offset
].flags
|= 0x00008000; /*- set the end contour flag */
490 return lastPoint
+ 1;
493 static int GetCompoundTTOutline(TrueTypeFont
*ttf
, sal_uInt32 glyphID
, ControlPoint
**pointArray
, TTGlyphMetrics
*metrics
, std::vector
< sal_uInt32
>& glyphlist
)
495 sal_uInt16 flags
, index
;
496 sal_Int16 e
, f
, numberOfContours
;
497 const sal_uInt8
* table
= getTable( ttf
, O_glyf
);
498 std::vector
<ControlPoint
> myPoints
;
499 ControlPoint
*nextComponent
, *pa
;
501 F16Dot16 a
= 0x10000, b
= 0, c
= 0, d
= 0x10000, m
, n
, abs1
, abs2
, abs3
;
503 *pointArray
= nullptr;
504 /* printf("GetCompoundTTOutline(%d)\n", glyphID); */
506 if (glyphID
>= ttf
->nglyphs
) /*- incorrect glyphID */
509 const sal_uInt8
* ptr
= table
+ ttf
->goffsets
[glyphID
];
510 if ((numberOfContours
= GetInt16(ptr
, 0)) != -1) /*- glyph is not compound */
514 metrics
->xMin
= GetInt16(ptr
, 2);
515 metrics
->yMin
= GetInt16(ptr
, 4);
516 metrics
->xMax
= GetInt16(ptr
, 6);
517 metrics
->yMax
= GetInt16(ptr
, 8);
518 GetMetrics(ttf
, glyphID
, metrics
);
524 flags
= GetUInt16(ptr
, 0);
525 /* printf("flags: 0x%X\n", flags); */
526 index
= GetUInt16(ptr
, 2);
529 if( std::find( glyphlist
.begin(), glyphlist
.end(), index
) != glyphlist
.end() )
531 #if OSL_DEBUG_LEVEL > 1
532 fprintf(stderr
, "Endless loop found in a compound glyph.\n");
533 fprintf(stderr
, "%d -> ", index
);
534 fprintf(stderr
," [");
535 for( std::vector
< sal_uInt32
>::const_iterator it
= glyphlist
.begin();
536 it
!= glyphlist
.end(); ++it
)
538 fprintf( stderr
,"%d ", (int) *it
);
540 fprintf(stderr
,"]\n");
545 glyphlist
.push_back( index
);
547 if ((np
= GetTTGlyphOutline(ttf
, index
, &nextComponent
, nullptr, &glyphlist
)) == 0)
549 /* XXX that probably indicates a corrupted font */
550 #if OSL_DEBUG_LEVEL > 1
551 fprintf(stderr
, "An empty compound!\n");
552 /* assert(!"An empty compound"); */
556 if( ! glyphlist
.empty() )
557 glyphlist
.pop_back();
559 if (flags
& USE_MY_METRICS
) {
560 if (metrics
) GetMetrics(ttf
, index
, metrics
);
563 if (flags
& ARG_1_AND_2_ARE_WORDS
) {
564 e
= GetInt16(ptr
, 0);
565 f
= GetInt16(ptr
, 2);
566 /* printf("ARG_1_AND_2_ARE_WORDS: %d %d\n", e & 0xFFFF, f & 0xFFFF); */
569 if (flags
& ARGS_ARE_XY_VALUES
) { /* args are signed */
570 e
= (sal_Int8
) *ptr
++;
571 f
= (sal_Int8
) *ptr
++;
572 /* printf("ARGS_ARE_XY_VALUES: %d %d\n", e & 0xFF, f & 0xFF); */
573 } else { /* args are unsigned */
574 /* printf("!ARGS_ARE_XY_VALUES\n"); */
584 if (flags
& WE_HAVE_A_SCALE
) {
585 a
= GetInt16(ptr
, 0) << 2;
588 } else if (flags
& WE_HAVE_AN_X_AND_Y_SCALE
) {
589 a
= GetInt16(ptr
, 0) << 2;
590 d
= GetInt16(ptr
, 2) << 2;
592 } else if (flags
& WE_HAVE_A_TWO_BY_TWO
) {
593 a
= GetInt16(ptr
, 0) << 2;
594 b
= GetInt16(ptr
, 2) << 2;
595 c
= GetInt16(ptr
, 4) << 2;
596 d
= GetInt16(ptr
, 6) << 2;
600 abs1
= (a
< 0) ? -a
: a
;
601 abs2
= (b
< 0) ? -b
: b
;
602 m
= (abs1
> abs2
) ? abs1
: abs2
;
604 if (abs3
< 0) abs3
= -abs3
;
605 if (abs3
<= 33) m
*= 2;
607 abs1
= (c
< 0) ? -c
: c
;
608 abs2
= (d
< 0) ? -d
: d
;
609 n
= (abs1
> abs2
) ? abs1
: abs2
;
611 if (abs3
< 0) abs3
= -abs3
;
612 if (abs3
<= 33) n
*= 2;
614 SAL_WARN_IF(np
&& !m
, "vcl.fonts", "Parsing error in " << OUString::createFromAscii(ttf
->fname
) <<
618 for (i
=0; i
<np
; i
++) {
621 cp
.flags
= nextComponent
[i
].flags
;
622 const sal_uInt16 x
= nextComponent
[i
].x
;
623 const sal_uInt16 y
= nextComponent
[i
].y
;
624 t
= fixedMulDiv(a
, x
<< 16, m
) + fixedMulDiv(c
, y
<< 16, m
) + (e
<< 16);
625 cp
.x
= (sal_Int16
)(fixedMul(t
, m
) >> 16);
626 t
= fixedMulDiv(b
, x
<< 16, n
) + fixedMulDiv(d
, y
<< 16, n
) + (f
<< 16);
627 cp
.y
= (sal_Int16
)(fixedMul(t
, n
) >> 16);
629 myPoints
.push_back( cp
);
635 } while (flags
& MORE_COMPONENTS
);
637 // #i123417# some fonts like IFAOGrec have no outline points in some compound glyphs
638 // so this unlikely but possible scenario should be handled gracefully
639 if( myPoints
.empty() )
642 np
= myPoints
.size();
644 pa
= static_cast<ControlPoint
*>(calloc(np
, sizeof(ControlPoint
)));
645 assert(pa
!= nullptr);
648 memcpy( pa
, &myPoints
[0], np
*sizeof(ControlPoint
) );
654 /* NOTE: GetTTGlyphOutline() returns -1 if the glyphID is incorrect,
655 * but Get{Simple|Compound}GlyphOutline returns 0 in such a case.
657 * NOTE: glyphlist is the stack of glyphs traversed while constructing
658 * a composite glyph. This is a safeguard against endless recursion
659 * in corrupted fonts.
661 static int GetTTGlyphOutline(TrueTypeFont
*ttf
, sal_uInt32 glyphID
, ControlPoint
**pointArray
, TTGlyphMetrics
*metrics
, std::vector
< sal_uInt32
>* glyphlist
)
663 const sal_uInt8
*table
= getTable( ttf
, O_glyf
);
664 sal_Int16 numberOfContours
;
666 *pointArray
= nullptr;
669 memset(metrics
, 0, sizeof(TTGlyphMetrics
)); /*- metrics is initialized to all zeroes */
672 if (glyphID
>= ttf
->nglyphs
) return -1; /**/
674 const sal_uInt8
* ptr
= table
+ ttf
->goffsets
[glyphID
];
675 int length
= ttf
->goffsets
[glyphID
+1] - ttf
->goffsets
[glyphID
];
677 if (length
== 0) { /*- empty glyphs still have hmtx and vmtx metrics values */
678 if (metrics
) GetMetrics(ttf
, glyphID
, metrics
);
682 numberOfContours
= GetInt16(ptr
, 0);
684 if (numberOfContours
>= 0)
686 res
=GetSimpleTTOutline(ttf
, glyphID
, pointArray
, metrics
);
690 std::vector
< sal_uInt32
> aPrivList
;
691 aPrivList
.push_back( glyphID
);
692 res
= GetCompoundTTOutline(ttf
, glyphID
, pointArray
, metrics
, glyphlist
? *glyphlist
: aPrivList
);
698 /*- returns the number of items in the path -*/
700 static int BSplineToPSPath(ControlPoint
*srcA
, int srcCount
, PSPathElement
**path
)
702 std::vector
< PSPathElement
> aPathList
;
704 PSPathElement
p( PS_NOOP
);
706 int x0
= 0, y0
= 0, x1
= 0, y1
= 0, x2
, y2
, curx
, cury
;
707 bool lastOff
= false; /*- last point was off-contour */
708 int scflag
= 1; /*- start contour flag */
709 bool ecflag
= false; /*- end contour flag */
710 int cp
= 0; /*- current point */
711 int StartContour
= 0, EndContour
= 1;
715 /* if (srcCount > 0) for(;;) */
716 while (srcCount
> 0) { /*- srcCount does not get changed inside the loop. */
720 while (!(srcA
[l
].flags
& 0x8000)) l
++;
722 if (StartContour
== EndContour
) {
723 if (cp
+ 1 < srcCount
) {
730 p
= PSPathElement(PS_MOVETO
);
731 if (!(srcA
[cp
].flags
& 1)) {
732 if (!(srcA
[EndContour
].flags
& 1)) {
733 p
.x1
= x0
= (srcA
[cp
].x
+ srcA
[EndContour
].x
+ 1) / 2;
734 p
.y1
= y0
= (srcA
[cp
].y
+ srcA
[EndContour
].y
+ 1) / 2;
736 p
.x1
= x0
= srcA
[EndContour
].x
;
737 p
.y1
= y0
= srcA
[EndContour
].y
;
740 p
.x1
= x0
= srcA
[cp
].x
;
741 p
.y1
= y0
= srcA
[cp
].y
;
744 aPathList
.push_back( p
);
752 if (srcA
[cp
].flags
& 1)
756 p
= PSPathElement(PS_CURVETO
);
757 p
.x1
= x0
+ (2 * (x1
- x0
) + 1) / 3;
758 p
.y1
= y0
+ (2 * (y1
- y0
) + 1) / 3;
759 p
.x2
= x1
+ (curx
- x1
+ 1) / 3;
760 p
.y2
= y1
+ (cury
- y1
+ 1) / 3;
763 aPathList
.push_back( p
);
767 if (!(x0
== curx
&& y0
== cury
))
768 { /* eliminate empty lines */
769 p
= PSPathElement(PS_LINETO
);
772 aPathList
.push_back( p
);
775 x0
= curx
; y0
= cury
; lastOff
= false;
781 x2
= (x1
+ curx
+ 1) / 2;
782 y2
= (y1
+ cury
+ 1) / 2;
783 p
= PSPathElement(PS_CURVETO
);
784 p
.x1
= x0
+ (2 * (x1
- x0
) + 1) / 3;
785 p
.y1
= y0
+ (2 * (y1
- y0
) + 1) / 3;
786 p
.x2
= x1
+ (x2
- x1
+ 1) / 3;
787 p
.y2
= y1
+ (y2
- y1
+ 1) / 3;
790 aPathList
.push_back( p
);
792 x1
= curx
; y1
= cury
;
794 x1
= curx
; y1
= cury
;
800 aPathList
.push_back( PSPathElement(PS_CLOSEPATH
) );
804 if (cp
>= srcCount
) break;
808 if (cp
== EndContour
) {
816 if( (nPathCount
= (int)aPathList
.size()) > 0)
818 *path
= static_cast<PSPathElement
*>(calloc(nPathCount
, sizeof(PSPathElement
)));
819 assert(*path
!= nullptr);
820 memcpy( *path
, &aPathList
[0], nPathCount
* sizeof(PSPathElement
) );
826 /*- Extracts a string from the name table and allocates memory for it -*/
828 static char *nameExtract( const sal_uInt8
* name
, int nTableSize
, int n
, int dbFlag
, sal_Unicode
** ucs2result
)
831 const sal_uInt8
* ptr
= name
+ GetUInt16(name
, 4) + GetUInt16(name
+ 6, 12 * n
+ 10);
832 int len
= GetUInt16(name
+6, 12 * n
+ 8);
835 const sal_uInt8
* end_table
= name
+nTableSize
;
836 const int available_space
= ptr
> end_table
? 0 : (end_table
- ptr
);
837 if( (len
<= 0) || len
> available_space
)
840 *ucs2result
= nullptr;
845 *ucs2result
= nullptr;
847 res
= static_cast<char*>(malloc(1 + len
/2));
848 assert(res
!= nullptr);
849 for (int i
= 0; i
< len
/2; i
++)
850 res
[i
] = *(ptr
+ i
* 2 + 1);
854 *ucs2result
= static_cast<sal_Unicode
*>(malloc( len
+2 ));
855 for (int i
= 0; i
< len
/2; i
++ )
856 (*ucs2result
)[i
] = GetUInt16( ptr
, 2*i
);
857 (*ucs2result
)[len
/2] = 0;
860 res
= static_cast<char*>(malloc(1 + len
));
861 assert(res
!= nullptr);
862 memcpy(res
, ptr
, len
);
869 static int findname( const sal_uInt8
*name
, sal_uInt16 n
, sal_uInt16 platformID
,
870 sal_uInt16 encodingID
, sal_uInt16 languageID
, sal_uInt16 nameID
)
872 if (n
== 0) return -1;
878 m1
= (platformID
<< 16) | encodingID
;
879 m2
= (languageID
<< 16) | nameID
;
882 const int i
= (l
+ r
) >> 1;
883 t1
= GetUInt32(name
+ 6, i
* 12 + 0);
884 t2
= GetUInt32(name
+ 6, i
* 12 + 4);
886 if (! ((m1
< t1
) || ((m1
== t1
) && (m2
< t2
)))) l
= i
+ 1;
887 if (! ((m1
> t1
) || ((m1
== t1
) && (m2
> t2
)))) r
= i
- 1;
897 /* XXX marlett.ttf uses (3, 0, 1033) instead of (3, 1, 1033) and does not have any Apple tables.
898 * Fix: if (3, 1, 1033) is not found - need to check for (3, 0, 1033)
900 * /d/fonts/ttzh_tw/Big5/Hanyi/ma6b5p uses (1, 0, 19) for English strings, instead of (1, 0, 0)
901 * and does not have (3, 1, 1033)
902 * Fix: if (1, 0, 0) and (3, 1, 1033) are not found need to look for (1, 0, *) - that will
903 * require a change in algorithm
905 * /d/fonts/fdltest/Korean/h2drrm has unsorted names and a an unknown (to me) Mac LanguageID,
906 * but (1, 0, 1042) strings usable
907 * Fix: change algorithm, and use (1, 0, *) if both standard Mac and MS strings are not found
910 static void GetNames(TrueTypeFont
*t
)
912 const sal_uInt8
* table
= getTable( t
, O_name
);
913 const sal_uInt32 nTableSize
= getTableSize(t
, O_name
);
917 #if OSL_DEBUG_LEVEL > 1
918 fprintf(stderr
, "O_name table too small\n");
923 sal_uInt16 n
= GetUInt16(table
, 2);
925 /* simple sanity check for name table entry count */
926 const size_t nMinRecordSize
= 12;
927 const size_t nSpaceAvailable
= nTableSize
- 6;
928 const size_t nMaxRecords
= nSpaceAvailable
/nMinRecordSize
;
929 if (n
>= nMaxRecords
)
933 bool bPSNameOK
= true;
935 /* PostScript name: preferred Microsoft */
937 if ((r
= findname(table
, n
, 3, 1, 0x0409, 6)) != -1)
938 t
->psname
= nameExtract(table
, nTableSize
, r
, 1, nullptr);
939 if ( ! t
->psname
&& (r
= findname(table
, n
, 1, 0, 0, 6)) != -1)
940 t
->psname
= nameExtract(table
, nTableSize
, r
, 0, nullptr);
941 if ( ! t
->psname
&& (r
= findname(table
, n
, 3, 0, 0x0409, 6)) != -1)
943 // some symbol fonts like Marlett have a 3,0 name!
944 t
->psname
= nameExtract(table
, nTableSize
, r
, 1, nullptr);
946 // for embedded font in Ghostscript PDFs
947 if ( ! t
->psname
&& (r
= findname(table
, n
, 2, 2, 0, 6)) != -1)
949 t
->psname
= nameExtract(table
, nTableSize
, r
, 0, nullptr);
955 char* pReverse
= t
->fname
+ strlen(t
->fname
);
956 /* take only last token of filename */
957 while(pReverse
!= t
->fname
&& *pReverse
!= '/') pReverse
--;
958 if(*pReverse
== '/') pReverse
++;
959 t
->psname
= strdup(pReverse
);
960 assert(t
->psname
!= nullptr);
961 for (i
=strlen(t
->psname
) - 1; i
> 0; i
--)
963 /*- Remove the suffix -*/
964 if (t
->psname
[i
] == '.' ) {
971 t
->psname
= strdup( "Unknown" );
974 /* Font family and subfamily names: preferred Apple */
976 if ((r
= findname(table
, n
, 0, 0, 0, 1)) != -1)
977 t
->family
= nameExtract(table
, nTableSize
, r
, 1, &t
->ufamily
);
978 if ( ! t
->family
&& (r
= findname(table
, n
, 3, 1, 0x0409, 1)) != -1)
979 t
->family
= nameExtract(table
, nTableSize
, r
, 1, &t
->ufamily
);
980 if ( ! t
->family
&& (r
= findname(table
, n
, 1, 0, 0, 1)) != -1)
981 t
->family
= nameExtract(table
, nTableSize
, r
, 0, nullptr);
982 if ( ! t
->family
&& (r
= findname(table
, n
, 3, 1, 0x0411, 1)) != -1)
983 t
->family
= nameExtract(table
, nTableSize
, r
, 1, &t
->ufamily
);
984 if ( ! t
->family
&& (r
= findname(table
, n
, 3, 0, 0x0409, 1)) != -1)
985 t
->family
= nameExtract(table
, nTableSize
, r
, 1, &t
->ufamily
);
988 t
->family
= strdup(t
->psname
);
989 assert(t
->family
!= nullptr);
992 t
->subfamily
= nullptr;
993 t
->usubfamily
= nullptr;
994 if ((r
= findname(table
, n
, 1, 0, 0, 2)) != -1)
995 t
->subfamily
= nameExtract(table
, nTableSize
, r
, 0, &t
->usubfamily
);
996 if ( ! t
->subfamily
&& (r
= findname(table
, n
, 3, 1, 0x0409, 2)) != -1)
997 t
->subfamily
= nameExtract(table
, nTableSize
, r
, 1, &t
->usubfamily
);
998 if ( ! t
->subfamily
)
1000 t
->subfamily
= strdup("");
1003 /* #i60349# sanity check psname
1004 * psname pratically has to be 7bit ascii and should not contains spaces
1005 * there is a class of broken fonts which do not fulfill that at all, so let's try
1006 * if the family name is 7bit ascii and take it instead if so
1009 for( i
= 0; t
->psname
[i
] != 0 && bPSNameOK
; i
++ )
1010 if( t
->psname
[ i
] < 33 || (t
->psname
[ i
] & 0x80) )
1014 /* check if family is a suitable replacement */
1015 if( t
->ufamily
&& t
->family
)
1017 bool bReplace
= true;
1019 for( i
= 0; t
->ufamily
[ i
] != 0 && bReplace
; i
++ )
1020 if( t
->ufamily
[ i
] < 33 || t
->ufamily
[ i
] > 127 )
1025 t
->psname
= strdup( t
->family
);
1032 CMAP_NOT_USABLE
= -1,
1033 CMAP_MS_Symbol
= 10,
1034 CMAP_MS_Unicode
= 11,
1035 CMAP_MS_ShiftJIS
= 12,
1038 CMAP_MS_Wansung
= 15,
1042 #define MISSING_GLYPH_INDEX 0
1045 * getGlyph[0246]() functions and friends are implemented by:
1046 * @author Manpreet Singh
1047 * getGlyph12() function and friends by:
1050 static sal_uInt32
getGlyph0(const sal_uInt8
* cmap
, sal_uInt32
, sal_uInt32 c
) {
1052 return *(cmap
+ 6 + c
);
1054 return MISSING_GLYPH_INDEX
;
1058 typedef struct _subHeader2
{
1059 sal_uInt16 firstCode
;
1060 sal_uInt16 entryCount
;
1062 sal_uInt16 idRangeOffset
;
1065 static sal_uInt32
getGlyph2(const sal_uInt8
*cmap
, const sal_uInt32 nMaxCmapSize
, sal_uInt32 c
) {
1066 sal_uInt16
const *CMAP2
= reinterpret_cast<sal_uInt16
const *>(cmap
);
1067 sal_uInt8 theHighByte
;
1069 sal_uInt8 theLowByte
;
1070 subHeader2
const * subHeader2s
;
1071 sal_uInt16
const * subHeader2Keys
;
1072 sal_uInt16 firstCode
;
1074 sal_uInt32 ToReturn
;
1076 theHighByte
= (sal_uInt8
)((c
>> 8) & 0x00ff);
1077 theLowByte
= (sal_uInt8
)(c
& 0x00ff);
1078 subHeader2Keys
= CMAP2
+ 3;
1079 subHeader2s
= reinterpret_cast<subHeader2
const *>(subHeader2Keys
+ 256);
1080 if(reinterpret_cast<sal_uInt8
const *>(&subHeader2Keys
[theHighByte
]) - cmap
< int(nMaxCmapSize
- 2))
1082 k
= Int16FromMOTA(subHeader2Keys
[theHighByte
]) / 8;
1083 // check if the subheader record fits into available space
1084 if((k
>= 0) && (reinterpret_cast<sal_uInt8
const *>(&subHeader2s
[k
]) - cmap
>= int(nMaxCmapSize
- sizeof(subHeader2
))))
1089 firstCode
= Int16FromMOTA(subHeader2s
[0].firstCode
);
1090 if(theLowByte
>= firstCode
&& theLowByte
< (firstCode
+ Int16FromMOTA(subHeader2s
[k
].entryCount
))) {
1091 sal_uInt16
const * pGlyph
= (&(subHeader2s
[0].idRangeOffset
))
1092 + (Int16FromMOTA(subHeader2s
[0].idRangeOffset
)/2) /* + offset */
1093 + theLowByte
/* + to_look */
1096 if (reinterpret_cast<sal_uInt8
const *>(pGlyph
) - cmap
< int(nMaxCmapSize
) - 4)
1099 return MISSING_GLYPH_INDEX
;
1101 return MISSING_GLYPH_INDEX
;
1104 firstCode
= Int16FromMOTA(subHeader2s
[k
].firstCode
);
1105 if(theLowByte
>= firstCode
&& theLowByte
< (firstCode
+ Int16FromMOTA(subHeader2s
[k
].entryCount
))) {
1106 ToReturn
= *((&(subHeader2s
[k
].idRangeOffset
))
1107 + (Int16FromMOTA(subHeader2s
[k
].idRangeOffset
)/2)
1108 + theLowByte
- firstCode
);
1110 return MISSING_GLYPH_INDEX
;
1112 ToReturn
+= Int16FromMOTA(subHeader2s
[k
].idDelta
);
1113 return (ToReturn
& 0xFFFF);
1116 return MISSING_GLYPH_INDEX
;
1119 return MISSING_GLYPH_INDEX
;
1123 static sal_uInt32
getGlyph6(const sal_uInt8
*cmap
, sal_uInt32
, sal_uInt32 c
) {
1124 sal_uInt16 firstCode
, lastCode
, count
;
1125 sal_uInt16
const *CMAP6
= reinterpret_cast<sal_uInt16
const *>(cmap
);
1127 firstCode
= Int16FromMOTA(*(CMAP6
+ 3));
1128 count
= Int16FromMOTA(*(CMAP6
+ 4));
1129 lastCode
= firstCode
+ count
- 1;
1130 if (c
< firstCode
|| c
> lastCode
) {
1131 return MISSING_GLYPH_INDEX
;
1133 return *((CMAP6
+ 5)/*glyphIdArray*/ + (c
- firstCode
));
1137 static sal_uInt16
GEbinsearch(sal_uInt16
const *ar
, sal_uInt16 length
, sal_uInt16 toSearch
) {
1138 signed int low
, high
, lastfound
= 0xffff;
1140 if(length
== (sal_uInt16
)0 || length
== (sal_uInt16
)0xFFFF) {
1141 return (sal_uInt16
)0xFFFF;
1145 while(high
>= low
) {
1146 int mid
= (high
+ low
)/2;
1147 res
= Int16FromMOTA(*(ar
+mid
));
1148 if(res
>= toSearch
) {
1155 return (sal_uInt16
)lastfound
;
1158 static sal_uInt32
getGlyph4(const sal_uInt8
*cmap
, const sal_uInt32 nMaxCmapSize
, sal_uInt32 c
) {
1161 sal_uInt16 segCount
;
1162 sal_uInt16
const * startCode
;
1163 sal_uInt16
const * endCode
;
1164 sal_uInt16
const * idDelta
;
1165 /* sal_uInt16 * glyphIdArray; */
1166 sal_uInt16
const * idRangeOffset
;
1167 /*sal_uInt16 * glyphIndexArray;*/
1168 sal_uInt16
const *CMAP4
= reinterpret_cast<sal_uInt16
const *>(cmap
);
1169 /* sal_uInt16 GEbinsearch(sal_uInt16 *ar, sal_uInt16 length, sal_uInt16 toSearch); */
1171 segCount
= Int16FromMOTA(*(CMAP4
+ 3))/2;
1172 endCode
= CMAP4
+ 7;
1173 i
= GEbinsearch(endCode
, segCount
, (sal_uInt16
)c
);
1175 if (i
== (sal_uInt16
) 0xFFFF) {
1176 return MISSING_GLYPH_INDEX
;
1178 startCode
= endCode
+ segCount
+ 1;
1180 if((reinterpret_cast<sal_uInt8
const *>(&startCode
[i
]) - cmap
>= int(nMaxCmapSize
- 2)) || Int16FromMOTA(startCode
[i
]) > c
) {
1181 return MISSING_GLYPH_INDEX
;
1183 idDelta
= startCode
+ segCount
;
1184 idRangeOffset
= idDelta
+ segCount
;
1185 /*glyphIndexArray = idRangeOffset + segCount;*/
1187 if((reinterpret_cast<sal_uInt8
const *>(&idRangeOffset
[i
]) - cmap
< int(nMaxCmapSize
- 2)) && Int16FromMOTA(idRangeOffset
[i
]) != 0) {
1188 sal_uInt16
const * pGlyphOffset
= &(idRangeOffset
[i
]) + (Int16FromMOTA(idRangeOffset
[i
])/2 + (c
- Int16FromMOTA(startCode
[i
])));
1189 if(reinterpret_cast<sal_uInt8
const *>(pGlyphOffset
) - cmap
>= int(nMaxCmapSize
- 2))
1190 return MISSING_GLYPH_INDEX
;
1191 c
= Int16FromMOTA(*pGlyphOffset
);
1194 ToReturn
= (Int16FromMOTA(idDelta
[i
]) + c
) & 0xFFFF;
1198 static sal_uInt32
getGlyph12(const sal_uInt8
*pCmap
, sal_uInt32
, sal_uInt32 cChar
) {
1199 const sal_uInt32
* pCMAP12
= reinterpret_cast<const sal_uInt32
*>(pCmap
);
1200 int nLength
= Int32FromMOTA( pCMAP12
[1] );
1201 int nGroups
= Int32FromMOTA( pCMAP12
[3] );
1203 int nUpper
= nGroups
;
1205 if( nUpper
> (nLength
-16)/12 )
1206 nUpper
= (nLength
-16)/12;
1208 /* binary search in "segmented coverage" subtable */
1209 while( nLower
< nUpper
) {
1210 int nIndex
= (nLower
+ nUpper
) / 2;
1211 const sal_uInt32
* pEntry
= &pCMAP12
[ 4 + 3*nIndex
];
1212 sal_uInt32 cStart
= Int32FromMOTA( pEntry
[0] );
1213 sal_uInt32 cLast
= Int32FromMOTA( pEntry
[1] );
1214 if( cChar
< cStart
)
1216 else if( cChar
> cLast
)
1217 nLower
= nIndex
+ 1;
1218 else { /* found matching entry! */
1219 sal_uInt32 nGlyph
= Int32FromMOTA( pEntry
[2] );
1220 nGlyph
+= cChar
- cStart
;
1225 return MISSING_GLYPH_INDEX
;
1228 static void FindCmap(TrueTypeFont
*ttf
)
1230 const sal_uInt8
* table
= getTable(ttf
, O_cmap
);
1231 sal_uInt32 table_size
= getTableSize(ttf
, O_cmap
);
1234 SAL_WARN("vcl.fonts", "Parsing error in " << OUString::createFromAscii(ttf
->fname
) <<
1235 "cmap table size too short");
1238 sal_uInt16 ncmaps
= GetUInt16(table
, 2);
1239 sal_uInt32 AppleUni
= 0; // Apple Unicode
1240 sal_uInt32 ThreeZero
= 0; /* MS Symbol */
1241 sal_uInt32 ThreeOne
= 0; /* MS UCS-2 */
1242 sal_uInt32 ThreeTwo
= 0; /* MS ShiftJIS */
1243 sal_uInt32 ThreeThree
= 0; /* MS Big5 */
1244 sal_uInt32 ThreeFour
= 0; /* MS PRC */
1245 sal_uInt32 ThreeFive
= 0; /* MS Wansung */
1246 sal_uInt32 ThreeSix
= 0; /* MS Johab */
1248 const sal_uInt32 remaining_table_size
= table_size
-4;
1249 const sal_uInt32 nMinRecordSize
= 8;
1250 const sal_uInt32 nMaxRecords
= remaining_table_size
/ nMinRecordSize
;
1251 if (ncmaps
> nMaxRecords
)
1253 SAL_WARN("vcl.fonts", "Parsing error in " << OUString::createFromAscii(ttf
->fname
) <<
1254 ": " << nMaxRecords
<< " max possible entries, but " <<
1255 ncmaps
<< " claimed, truncating");
1256 ncmaps
= nMaxRecords
;
1259 for (unsigned int i
= 0; i
< ncmaps
; i
++) {
1260 /* sanity check, cmap entry must lie within table */
1261 sal_uInt32 nLargestFixedOffsetPos
= 8 + i
* 8;
1262 sal_uInt32 nMinSize
= nLargestFixedOffsetPos
+ sizeof(sal_uInt32
);
1263 if (nMinSize
> table_size
)
1265 SAL_WARN( "vcl.fonts", "Font " << OUString::createFromAscii(ttf
->fname
) << " claimed to have "
1266 << ncmaps
<< " cmaps, but only space for " << i
);
1270 sal_uInt16 pID
= GetUInt16(table
, 4 + i
* 8);
1271 sal_uInt16 eID
= GetUInt16(table
, 6 + i
* 8);
1272 sal_uInt32 offset
= GetUInt32(table
, nLargestFixedOffsetPos
);
1274 /* sanity check, cmap must lie within file */
1275 if( (table
- ttf
->ptr
) + offset
> (sal_uInt32
)ttf
->fsize
)
1278 /* Unicode tables in Apple fonts */
1285 case 0: ThreeZero
= offset
; break;
1287 case 1: ThreeOne
= offset
; break;
1288 case 2: ThreeTwo
= offset
; break;
1289 case 3: ThreeThree
= offset
; break;
1290 case 4: ThreeFour
= offset
; break;
1291 case 5: ThreeFive
= offset
; break;
1292 case 6: ThreeSix
= offset
; break;
1297 // fall back to AppleUnicode if there are no ThreeOne/Threezero tables
1298 if( AppleUni
&& !ThreeZero
&& !ThreeOne
)
1299 ThreeOne
= AppleUni
;
1302 ttf
->cmapType
= CMAP_MS_Unicode
;
1303 ttf
->cmap
= table
+ ThreeOne
;
1304 } else if (ThreeTwo
) {
1305 ttf
->cmapType
= CMAP_MS_ShiftJIS
;
1306 ttf
->cmap
= table
+ ThreeTwo
;
1307 } else if (ThreeThree
) {
1308 ttf
->cmapType
= CMAP_MS_Big5
;
1309 ttf
->cmap
= table
+ ThreeThree
;
1310 } else if (ThreeFour
) {
1311 ttf
->cmapType
= CMAP_MS_PRC
;
1312 ttf
->cmap
= table
+ ThreeFour
;
1313 } else if (ThreeFive
) {
1314 ttf
->cmapType
= CMAP_MS_Wansung
;
1315 ttf
->cmap
= table
+ ThreeFive
;
1316 } else if (ThreeSix
) {
1317 ttf
->cmapType
= CMAP_MS_Johab
;
1318 ttf
->cmap
= table
+ ThreeSix
;
1319 } else if (ThreeZero
) {
1320 ttf
->cmapType
= CMAP_MS_Symbol
;
1321 ttf
->cmap
= table
+ ThreeZero
;
1323 ttf
->cmapType
= CMAP_NOT_USABLE
;
1324 ttf
->cmap
= nullptr;
1327 if (ttf
->cmapType
!= CMAP_NOT_USABLE
) {
1328 if( (ttf
->cmap
- ttf
->ptr
+ 2U) > static_cast<sal_uInt32
>(ttf
->fsize
) ) {
1329 ttf
->cmapType
= CMAP_NOT_USABLE
;
1330 ttf
->cmap
= nullptr;
1334 if (ttf
->cmapType
!= CMAP_NOT_USABLE
) {
1335 switch (GetUInt16(ttf
->cmap
, 0)) {
1336 case 0: ttf
->mapper
= getGlyph0
; break;
1337 case 2: ttf
->mapper
= getGlyph2
; break;
1338 case 4: ttf
->mapper
= getGlyph4
; break;
1339 case 6: ttf
->mapper
= getGlyph6
; break;
1340 case 12: ttf
->mapper
= getGlyph12
; break;
1342 #if OSL_DEBUG_LEVEL > 1
1343 /*- if the cmap table is really broken */
1344 printf("%s: %d is not a recognized cmap format.\n", ttf
->fname
, GetUInt16(ttf
->cmap
, 0));
1346 ttf
->cmapType
= CMAP_NOT_USABLE
;
1347 ttf
->cmap
= nullptr;
1348 ttf
->mapper
= nullptr;
1353 static void GetKern(TrueTypeFont
*ttf
)
1355 const sal_uInt8
* table
= getTable(ttf
, O_kern
);
1356 int nTableSize
= getTableSize(ttf
, O_kern
);
1357 const sal_uInt8
*ptr
;
1362 if (nTableSize
>= 4 && GetUInt16(table
, 0) == 0) { /* Traditional Microsoft style table with sal_uInt16 version and nTables fields */
1363 ttf
->nkern
= GetUInt16(table
, 2);
1364 ttf
->kerntype
= KT_MICROSOFT
;
1367 const sal_uInt32 remaining_table_size
= nTableSize
-4;
1368 const sal_uInt32 nMinRecordSize
= 2;
1369 const sal_uInt32 nMaxRecords
= remaining_table_size
/ nMinRecordSize
;
1370 if (ttf
->nkern
> nMaxRecords
)
1372 SAL_WARN("vcl.fonts", "Parsing error in " << OUString::createFromAscii(ttf
->fname
) <<
1373 ": " << nMaxRecords
<< " max possible entries, but " <<
1374 ttf
->nkern
<< " claimed, truncating");
1375 ttf
->nkern
= nMaxRecords
;
1378 ttf
->kerntables
= static_cast<const sal_uInt8
**>(calloc(ttf
->nkern
, sizeof(sal_uInt8
*)));
1379 assert(ttf
->kerntables
!= nullptr);
1381 for( unsigned i
= 0; i
< ttf
->nkern
; ++i
) {
1382 ttf
->kerntables
[i
] = ptr
;
1383 ptr
+= GetUInt16(ptr
, 2);
1385 if( ptr
> ttf
->ptr
+ttf
->fsize
)
1387 free( ttf
->kerntables
);
1394 if (nTableSize
>= 8 && GetUInt32(table
, 0) == 0x00010000) { /* MacOS style kern tables: fixed32 version and sal_uInt32 nTables fields */
1395 ttf
->nkern
= GetUInt32(table
, 4);
1396 ttf
->kerntype
= KT_APPLE_NEW
;
1399 const sal_uInt32 remaining_table_size
= nTableSize
-8;
1400 const sal_uInt32 nMinRecordSize
= 4;
1401 const sal_uInt32 nMaxRecords
= remaining_table_size
/ nMinRecordSize
;
1402 if (ttf
->nkern
> nMaxRecords
)
1404 SAL_WARN("vcl.fonts", "Parsing error in " << OUString::createFromAscii(ttf
->fname
) <<
1405 ": " << nMaxRecords
<< " max possible entries, but " <<
1406 ttf
->nkern
<< " claimed, truncating");
1407 ttf
->nkern
= nMaxRecords
;
1410 ttf
->kerntables
= static_cast<const sal_uInt8
**>(calloc(ttf
->nkern
, sizeof(sal_uInt8
*)));
1411 assert(ttf
->kerntables
!= nullptr);
1413 for( unsigned i
= 0; i
< ttf
->nkern
; ++i
) {
1414 ttf
->kerntables
[i
] = ptr
;
1415 ptr
+= GetUInt32(ptr
, 0);
1416 /* sanity check; there are some fonts that are broken in this regard */
1417 if( ptr
> ttf
->ptr
+ttf
->fsize
)
1419 free( ttf
->kerntables
);
1427 ttf
->kerntype
= KT_NONE
;
1428 ttf
->kerntables
= nullptr;
1433 /*- Public functions */
1435 int CountTTCFonts(const char* fname
)
1438 sal_uInt8 buffer
[12];
1439 FILE* fd
= fopen(fname
, "rb");
1441 if (fread(buffer
, 1, 12, fd
) == 12) {
1442 if(GetUInt32(buffer
, 0) == T_ttcf
)
1443 nFonts
= GetUInt32(buffer
, 8);
1450 static void allocTrueTypeFont( TrueTypeFont
** ttf
)
1452 *ttf
= static_cast<TrueTypeFont
*>(calloc(1,sizeof(TrueTypeFont
)));
1453 if( *ttf
!= nullptr )
1455 (*ttf
)->fname
= nullptr;
1457 (*ttf
)->ptr
= nullptr;
1458 (*ttf
)->nglyphs
= 0xFFFFFFFF;
1459 (*ttf
)->pGSubstitution
= nullptr;
1463 /* forward declaration for the two entry points to use*/
1464 static int doOpenTTFont( sal_uInt32 facenum
, TrueTypeFont
* t
);
1466 #if !defined(_WIN32)
1467 int OpenTTFontFile( const char* fname
, sal_uInt32 facenum
, TrueTypeFont
** ttf
)
1472 if (!fname
|| !*fname
) return SF_BADFILE
;
1474 allocTrueTypeFont( ttf
);
1478 (*ttf
)->fname
= strdup(fname
);
1479 if( ! (*ttf
)->fname
)
1485 fd
= open(fname
, O_RDONLY
);
1492 if (fstat(fd
, &st
) == -1) {
1497 (*ttf
)->fsize
= st
.st_size
;
1499 /* On Mac OS, most likely will happen if a Mac user renames a font file
1500 * to be .ttf when its really a Mac resource-based font.
1501 * Size will be 0, but fonts smaller than 4 bytes would be broken anyway.
1503 if ((*ttf
)->fsize
== 0) {
1508 if (((*ttf
)->ptr
= static_cast<sal_uInt8
*>(mmap(nullptr, (*ttf
)->fsize
, PROT_READ
, MAP_SHARED
, fd
, 0))) == MAP_FAILED
) {
1514 return doOpenTTFont( facenum
, *ttf
);
1517 if (fd
!= -1) close(fd
);
1518 /*- t and t->fname have been allocated! */
1519 free((*ttf
)->fname
);
1526 int OpenTTFontBuffer(const void* pBuffer
, sal_uInt32 nLen
, sal_uInt32 facenum
, TrueTypeFont
** ttf
)
1528 allocTrueTypeFont( ttf
);
1529 if( *ttf
== nullptr )
1532 (*ttf
)->fname
= nullptr;
1533 (*ttf
)->fsize
= nLen
;
1534 (*ttf
)->ptr
= const_cast<sal_uInt8
*>(static_cast<sal_uInt8
const *>(pBuffer
));
1536 return doOpenTTFont( facenum
, *ttf
);
1541 bool withinBounds(sal_uInt32 tdoffset
, sal_uInt32 moreoffset
, sal_uInt32 len
, sal_uInt32 available
)
1544 if (o3tl::checked_add(tdoffset
, moreoffset
, result
))
1546 if (o3tl::checked_add(result
, len
, result
))
1548 return result
<= available
;
1553 TrueTypeFont
* m_font
;
1555 TTFontCloser(TrueTypeFont
* t
)
1559 void clear() { m_font
= nullptr; }
1563 CloseTTFont(m_font
);
1569 static int doOpenTTFont( sal_uInt32 facenum
, TrueTypeFont
* t
)
1571 TTFontCloser
aCloseGuard(t
);
1577 sal_uInt32 length
, tag
;
1578 sal_uInt32 tdoffset
= 0; /* offset to TableDirectory in a TTC file. For TTF files is 0 */
1580 sal_uInt32 TTCTag
= GetInt32(t
->ptr
, 0);
1582 if ((TTCTag
== 0x00010000) || (TTCTag
== T_true
)) {
1584 } else if (TTCTag
== T_otto
) { /* PS-OpenType font */
1586 } else if (TTCTag
== T_ttcf
) { /* TrueType collection */
1587 if (!withinBounds(12, 4 * facenum
, sizeof(sal_uInt32
), t
->fsize
)) {
1590 sal_uInt32 Version
= GetUInt32(t
->ptr
, 4);
1591 if (Version
!= 0x00010000 && Version
!= 0x00020000) {
1594 if (facenum
>= GetUInt32(t
->ptr
, 8)) {
1597 tdoffset
= GetUInt32(t
->ptr
, 12 + 4 * facenum
);
1602 if (withinBounds(tdoffset
, 0, 4 + sizeof(sal_uInt16
), t
->fsize
)) {
1603 t
->ntables
= GetUInt16(t
->ptr
+ tdoffset
, 4);
1606 if (t
->ntables
>= 128 || t
->ntables
== 0) {
1610 t
->tables
= static_cast<const sal_uInt8
**>(calloc(NUM_TAGS
, sizeof(sal_uInt8
*)));
1611 assert(t
->tables
!= nullptr);
1612 t
->tlens
= static_cast<sal_uInt32
*>(calloc(NUM_TAGS
, sizeof(sal_uInt32
)));
1613 assert(t
->tlens
!= nullptr);
1615 /* parse the tables */
1616 for (i
=0; i
<(int)t
->ntables
; i
++) {
1618 const sal_uInt32 nStart
= tdoffset
+ 12;
1619 const sal_uInt32 nOffset
= 16 * i
;
1620 if (withinBounds(nStart
, nOffset
, sizeof(sal_uInt32
), t
->fsize
))
1621 tag
= GetUInt32(t
->ptr
+ nStart
, nOffset
);
1623 tag
= static_cast<sal_uInt32
>(-1);
1625 case T_maxp
: nIndex
= O_maxp
; break;
1626 case T_glyf
: nIndex
= O_glyf
; break;
1627 case T_head
: nIndex
= O_head
; break;
1628 case T_loca
: nIndex
= O_loca
; break;
1629 case T_name
: nIndex
= O_name
; break;
1630 case T_hhea
: nIndex
= O_hhea
; break;
1631 case T_hmtx
: nIndex
= O_hmtx
; break;
1632 case T_cmap
: nIndex
= O_cmap
; break;
1633 case T_vhea
: nIndex
= O_vhea
; break;
1634 case T_vmtx
: nIndex
= O_vmtx
; break;
1635 case T_OS2
: nIndex
= O_OS2
; break;
1636 case T_post
: nIndex
= O_post
; break;
1637 case T_kern
: nIndex
= O_kern
; break;
1638 case T_cvt
: nIndex
= O_cvt
; break;
1639 case T_prep
: nIndex
= O_prep
; break;
1640 case T_fpgm
: nIndex
= O_fpgm
; break;
1641 case T_gsub
: nIndex
= O_gsub
; break;
1642 case T_CFF
: nIndex
= O_CFF
; break;
1643 default: nIndex
= -1; break;
1646 if ((nIndex
>= 0) && withinBounds(nStart
, nOffset
, 12 + sizeof(sal_uInt32
), t
->fsize
)) {
1647 sal_uInt32 nTableOffset
= GetUInt32(t
->ptr
+ nStart
, nOffset
+ 8);
1648 length
= GetUInt32(t
->ptr
+ nStart
, nOffset
+ 12);
1649 t
->tables
[nIndex
] = t
->ptr
+ nTableOffset
;
1650 t
->tlens
[nIndex
] = length
;
1654 /* Fixup offsets when only a TTC extract was provided */
1655 if( facenum
== (sal_uInt32
)~0 ) {
1656 sal_uInt8
* pHead
= const_cast<sal_uInt8
*>(t
->tables
[O_head
]);
1660 /* limit Head candidate to TTC extract's limits */
1661 if( pHead
> t
->ptr
+ (t
->fsize
- 54) )
1662 pHead
= t
->ptr
+ (t
->fsize
- 54);
1663 /* TODO: find better method than searching head table's magic */
1664 sal_uInt8
* p
= nullptr;
1665 for( p
= pHead
+ 12; p
> t
->ptr
; --p
) {
1666 if( p
[0]==0x5F && p
[1]==0x0F && p
[2]==0x3C && p
[3]==0xF5 ) {
1667 int nDelta
= (pHead
+ 12) - p
;
1669 for( int j
= 0; j
< NUM_TAGS
; ++j
)
1671 *reinterpret_cast<char const **>(&t
->tables
[j
]) -= nDelta
;
1680 /* Check the table offsets after TTC correction */
1681 for (i
=0; i
<NUM_TAGS
; i
++) {
1682 /* sanity check: table must lay completely within the file
1683 * at this point one could check the checksum of all contained
1684 * tables, but this would be quite time intensive.
1685 * Try to fix tables, so we can cope with minor problems.
1688 if( t
->tables
[i
] < t
->ptr
)
1690 #if OSL_DEBUG_LEVEL > 1
1692 fprintf( stderr
, "font file %s has bad table offset %" SAL_PRI_PTRDIFFT
"d (tagnum=%d)\n", t
->fname
, (sal_uInt8
*)t
->tables
[i
]-t
->ptr
, i
);
1695 t
->tables
[i
] = nullptr;
1697 else if( const_cast<sal_uInt8
*>(t
->tables
[i
]) + t
->tlens
[i
] > t
->ptr
+ t
->fsize
)
1699 sal_PtrDiff nMaxLen
= (t
->ptr
+ t
->fsize
) - t
->tables
[i
];
1702 t
->tlens
[i
] = nMaxLen
;
1703 #if OSL_DEBUG_LEVEL > 1
1704 fprintf( stderr
, "font file %s has too big table (tagnum=%d)\n", t
->fname
, i
);
1709 /* At this point TrueTypeFont is constructed, now need to verify the font format
1710 and read the basic font properties */
1712 /* The following tables are absolutely required:
1713 * maxp, head, name, cmap
1716 if( !(getTable(t
, O_maxp
) && getTable(t
, O_head
) && getTable(t
, O_name
) && getTable(t
, O_cmap
)) ) {
1720 const sal_uInt8
* table
= getTable(t
, O_maxp
);
1721 sal_uInt32 table_size
= getTableSize(t
, O_maxp
);
1722 t
->nglyphs
= table_size
>= 6 ? GetUInt16(table
, 4) : 0;
1724 table
= getTable(t
, O_head
);
1725 table_size
= getTableSize(t
, O_head
);
1726 if (table_size
< 52) {
1729 t
->unitsPerEm
= GetUInt16(table
, 18);
1730 int indexfmt
= GetInt16(table
, 50);
1732 if( ((indexfmt
!= 0) && (indexfmt
!= 1)) || (t
->unitsPerEm
<= 0) ) {
1736 if( getTable(t
, O_glyf
) && getTable(t
, O_loca
) ) /* TTF or TTF-OpenType */
1738 int k
= (getTableSize(t
, O_loca
) / (indexfmt
? 4 : 2)) - 1;
1739 if( k
< (int)t
->nglyphs
) /* Hack for broken Chinese fonts */
1742 table
= getTable(t
, O_loca
);
1743 t
->goffsets
= static_cast<sal_uInt32
*>(calloc(1+t
->nglyphs
, sizeof(sal_uInt32
)));
1744 assert(t
->goffsets
!= nullptr);
1746 for( i
= 0; i
<= (int)t
->nglyphs
; ++i
)
1747 t
->goffsets
[i
] = indexfmt
? GetUInt32(table
, i
<< 2) : (sal_uInt32
)GetUInt16(table
, i
<< 1) << 1;
1748 } else if( getTable(t
, O_CFF
) ) { /* PS-OpenType */
1749 int k
= (getTableSize(t
, O_CFF
) / 2) - 1; /* set a limit here, presumably much lower than the table size, but establishes some sort of physical bound */
1750 if( k
< (int)t
->nglyphs
)
1752 t
->goffsets
= static_cast<sal_uInt32
*>(calloc(1+t
->nglyphs
, sizeof(sal_uInt32
)));
1753 /* TODO: implement to get subsetting */
1754 assert(t
->goffsets
!= nullptr);
1759 table
= getTable(t
, O_hhea
);
1760 table_size
= getTableSize(t
, O_hhea
);
1761 t
->numberOfHMetrics
= (table
&& table_size
>= 36) ? GetUInt16(table
, 34) : 0;
1763 table
= getTable(t
, O_vhea
);
1764 table_size
= getTableSize(t
, O_vhea
);
1765 t
->numOfLongVerMetrics
= (table
&& table_size
>= 36) ? GetUInt16(table
, 34) : 0;
1770 ReadGSUB( t
, 0, 0 );
1772 aCloseGuard
.clear();
1777 void CloseTTFont(TrueTypeFont
*ttf
)
1779 #if !defined(_WIN32)
1781 munmap(ttf
->ptr
, ttf
->fsize
);
1784 free(ttf
->goffsets
);
1788 free( ttf
->ufamily
);
1789 free(ttf
->subfamily
);
1790 if( ttf
->usubfamily
)
1791 free( ttf
->usubfamily
);
1794 free(ttf
->kerntables
);
1802 int GetTTGlyphPoints(TrueTypeFont
*ttf
, sal_uInt32 glyphID
, ControlPoint
**pointArray
)
1804 return GetTTGlyphOutline(ttf
, glyphID
, pointArray
, nullptr, nullptr);
1807 int GetTTGlyphComponents(TrueTypeFont
*ttf
, sal_uInt32 glyphID
, std::vector
< sal_uInt32
>& glyphlist
)
1811 if( glyphID
>= ttf
->nglyphs
)
1814 const sal_uInt8
* glyf
= getTable(ttf
, O_glyf
);
1815 const sal_uInt8
* ptr
= glyf
+ ttf
->goffsets
[glyphID
];
1816 const sal_uInt8
* nptr
= glyf
+ ttf
->goffsets
[glyphID
+1];
1820 glyphlist
.push_back( glyphID
);
1822 if (GetInt16(ptr
, 0) == -1) {
1823 sal_uInt16 flags
, index
;
1826 flags
= GetUInt16(ptr
, 0);
1827 index
= GetUInt16(ptr
, 2);
1830 n
+= GetTTGlyphComponents(ttf
, index
, glyphlist
);
1832 if (flags
& ARG_1_AND_2_ARE_WORDS
) {
1838 if (flags
& WE_HAVE_A_SCALE
) {
1840 } else if (flags
& WE_HAVE_AN_X_AND_Y_SCALE
) {
1842 } else if (flags
& WE_HAVE_A_TWO_BY_TWO
) {
1845 } while (flags
& MORE_COMPONENTS
);
1851 int CreateT3FromTTGlyphs(TrueTypeFont
*ttf
, FILE *outf
, const char *fname
,
1852 sal_uInt16
*glyphArray
, sal_uInt8
*encoding
, int nGlyphs
,
1856 PSPathElement
*path
;
1858 const sal_uInt8
* table
= getTable(ttf
, O_head
);
1859 TTGlyphMetrics metrics
;
1860 int UPEm
= ttf
->unitsPerEm
;
1862 const char *h01
= "%%!PS-AdobeFont-%d.%d-%d.%d\n";
1863 const char *h02
= "%% Creator: %s %s %s\n";
1864 const char *h09
= "%% Original font name: %s\n";
1868 "/PaintType 0 def\n"
1870 "/StrokeWidth 0 def\n";
1872 const char *h11
= "/FontName (%s) cvn def\n";
1875 const char *h12 = "%/UniqueID %d def\n";
1877 const char *h13
= "/FontMatrix [.001 0 0 .001 0 0] def\n";
1878 const char *h14
= "/FontBBox [%d %d %d %d] def\n";
1881 "/Encoding 256 array def\n"
1882 " 0 1 255 {Encoding exch /.notdef put} for\n";
1884 const char *h16
= " Encoding %d /glyph%d put\n";
1885 const char *h17
= "/XUID [103 0 0 16#%08X %d 16#%08X 16#%08X] def\n";
1887 const char *h30
= "/CharProcs %d dict def\n";
1888 const char *h31
= " CharProcs begin\n";
1889 const char *h32
= " /.notdef {} def\n";
1890 const char *h33
= " /glyph%d {\n";
1891 const char *h34
= " } bind def\n";
1892 const char *h35
= " end\n";
1896 " exch /CharProcs get exch\n"
1897 " 2 copy known not\n"
1898 " {pop /.notdef} if\n"
1902 " 1 index /Encoding get exch get\n"
1903 " 1 index /BuildGlyph get exec\n"
1905 "currentdict end\n";
1907 const char *h41
= "(%s) cvn exch definefont pop\n";
1909 if (!((nGlyphs
> 0) && (nGlyphs
<= 256))) return SF_GLYPHNUM
;
1910 if (!glyphArray
) return SF_BADARG
;
1911 if (!fname
) fname
= ttf
->psname
;
1913 fprintf(outf
, h01
, GetInt16(table
, 0), GetUInt16(table
, 2), GetInt16(table
, 4), GetUInt16(table
, 6));
1914 fprintf(outf
, h02
, modname
, modver
, modextra
);
1915 fprintf(outf
, h09
, ttf
->psname
);
1917 fprintf(outf
, "%s", h10
);
1918 fprintf(outf
, h11
, fname
);
1919 /* fprintf(outf, h12, 4000000); */
1922 * 103 0 0 C1 C2 C3 C4
1923 * C1 - CRC-32 of the entire source TrueType font
1924 * C2 - number of glyphs in the subset
1925 * C3 - CRC-32 of the glyph array
1926 * C4 - CRC-32 of the encoding array
1928 * All CRC-32 numbers are presented as hexadecimal numbers
1931 fprintf(outf
, h17
, rtl_crc32(0, ttf
->ptr
, ttf
->fsize
), nGlyphs
, rtl_crc32(0, glyphArray
, nGlyphs
* 2), rtl_crc32(0, encoding
, nGlyphs
));
1932 fprintf(outf
, "%s", h13
);
1933 fprintf(outf
, h14
, XUnits(UPEm
, GetInt16(table
, 36)), XUnits(UPEm
, GetInt16(table
, 38)), XUnits(UPEm
, GetInt16(table
, 40)), XUnits(UPEm
, GetInt16(table
, 42)));
1934 fprintf(outf
, "%s", h15
);
1936 for (i
= 0; i
< nGlyphs
; i
++) {
1937 fprintf(outf
, h16
, encoding
[i
], i
);
1940 fprintf(outf
, h30
, nGlyphs
+1);
1941 fprintf(outf
, "%s", h31
);
1942 fprintf(outf
, "%s", h32
);
1944 for (i
= 0; i
< nGlyphs
; i
++) {
1945 fprintf(outf
, h33
, i
);
1946 int r
= GetTTGlyphOutline(ttf
, glyphArray
[i
] < ttf
->nglyphs
? glyphArray
[i
] : 0, &pa
, &metrics
, nullptr);
1949 n
= BSplineToPSPath(pa
, r
, &path
);
1951 n
= 0; /* glyph might have zero contours but valid metrics ??? */
1953 if (r
< 0) { /* glyph is not present in the font - pa array was not allocated, so no need to free it */
1957 fprintf(outf
, "\t%d %d %d %d %d %d setcachedevice\n",
1958 wmode
== 0 ? XUnits(UPEm
, metrics
.aw
) : 0,
1959 wmode
== 0 ? 0 : -XUnits(UPEm
, metrics
.ah
),
1960 XUnits(UPEm
, metrics
.xMin
),
1961 XUnits(UPEm
, metrics
.yMin
),
1962 XUnits(UPEm
, metrics
.xMax
),
1963 XUnits(UPEm
, metrics
.yMax
));
1965 for (j
= 0; j
< n
; j
++)
1967 switch (path
[j
].type
)
1970 fprintf(outf
, "\t%d %d moveto\n", XUnits(UPEm
, path
[j
].x1
), XUnits(UPEm
, path
[j
].y1
));
1974 fprintf(outf
, "\t%d %d lineto\n", XUnits(UPEm
, path
[j
].x1
), XUnits(UPEm
, path
[j
].y1
));
1978 fprintf(outf
, "\t%d %d %d %d %d %d curveto\n", XUnits(UPEm
, path
[j
].x1
), XUnits(UPEm
, path
[j
].y1
), XUnits(UPEm
, path
[j
].x2
), XUnits(UPEm
, path
[j
].y2
), XUnits(UPEm
, path
[j
].x3
), XUnits(UPEm
, path
[j
].y3
));
1982 fprintf(outf
, "\tclosepath\n");
1988 if (n
> 0) fprintf(outf
, "\tfill\n"); /* if glyph is not a whitespace character */
1990 fprintf(outf
, "%s", h34
);
1995 fprintf(outf
, "%s", h35
);
1997 fprintf(outf
, "%s", h40
);
1998 fprintf(outf
, h41
, fname
);
2003 int CreateTTFromTTGlyphs(TrueTypeFont
*ttf
,
2005 sal_uInt16
*glyphArray
,
2006 sal_uInt8
*encoding
,
2012 TrueTypeCreator
*ttcr
;
2013 TrueTypeTable
*head
=nullptr, *hhea
=nullptr, *maxp
=nullptr, *cvt
=nullptr, *prep
=nullptr, *glyf
=nullptr, *fpgm
=nullptr, *cmap
=nullptr, *name
=nullptr, *post
= nullptr, *os2
= nullptr;
2017 TrueTypeCreatorNewEmpty(T_true
, &ttcr
);
2021 if (flags
& TTCF_AutoName
) {
2022 /* not implemented yet
2025 int n = GetTTNameRecords(ttf, &names);
2026 int n1 = 0, n2 = 0, n3 = 0, n4 = 0, n5 = 0, n6 = 0;
2028 sal_uInt8 suffix[32];
2029 sal_uInt32 c1 = crc32(glyphArray, nGlyphs * 2);
2030 sal_uInt32 c2 = crc32(encoding, nGlyphs);
2032 snprintf(suffix, 31, "S%08X%08X-%d", c1, c2, nGlyphs);
2034 name = TrueTypeTableNew_name(0, 0);
2035 for (i = 0; i < n; i++) {
2036 if (names[i].platformID == 1 && names[i].encodingID == 0 && names[i].languageID == 0 && names[i].nameID == 1) {
2038 memcpy(newname, names+i, sizeof(NameRecord));
2039 newname.slen = name[i].slen + strlen(suffix);
2041 const sal_uInt8 ptr
[] = {0,'T',0,'r',0,'u',0,'e',0,'T',0,'y',0,'p',0,'e',0,'S',0,'u',0,'b',0,'s',0,'e',0,'t'};
2042 NameRecord n1
= {1, 0, 0, 6, 14, const_cast<sal_uInt8
*>(reinterpret_cast<sal_uInt8
const *>("TrueTypeSubset"))};
2043 NameRecord n2
= {3, 1, 1033, 6, 28, nullptr};
2044 n2
.sptr
= const_cast<sal_uInt8
*>(ptr
);
2045 name
= TrueTypeTableNew_name(0, nullptr);
2049 if (nNameRecs
== 0) {
2051 int n
= GetTTNameRecords(ttf
, &names
);
2052 name
= TrueTypeTableNew_name(n
, names
);
2053 DisposeNameRecords(names
, n
);
2055 name
= TrueTypeTableNew_name(nNameRecs
, nr
);
2060 maxp
= TrueTypeTableNew_maxp(getTable(ttf
, O_maxp
), getTableSize(ttf
, O_maxp
));
2063 const sal_uInt8
* p
= getTable(ttf
, O_hhea
);
2065 hhea
= TrueTypeTableNew_hhea(GetUInt16(p
, 4), GetUInt16(p
, 6), GetUInt16(p
, 8), GetUInt16(p
, 18), GetUInt16(p
, 20));
2067 hhea
= TrueTypeTableNew_hhea(0, 0, 0, 0, 0);
2072 p
= getTable(ttf
, O_head
);
2073 assert(p
!= nullptr);
2074 head
= TrueTypeTableNew_head(GetUInt32(p
, 4),
2084 glyf
= TrueTypeTableNew_glyf();
2085 sal_uInt32
* gID
= static_cast<sal_uInt32
*>(scalloc(nGlyphs
, sizeof(sal_uInt32
)));
2087 for (i
= 0; i
< nGlyphs
; i
++) {
2088 gID
[i
] = glyfAdd(glyf
, GetTTRawGlyphData(ttf
, glyphArray
[i
]), ttf
);
2092 cmap
= TrueTypeTableNew_cmap();
2094 for (i
=0; i
< nGlyphs
; i
++) {
2095 cmapAdd(cmap
, 0x010000, encoding
[i
], gID
[i
]);
2099 if ((p
= getTable(ttf
, O_cvt
)) != nullptr) {
2100 cvt
= TrueTypeTableNew(T_cvt
, getTableSize(ttf
, O_cvt
), p
);
2104 if ((p
= getTable(ttf
, O_prep
)) != nullptr) {
2105 prep
= TrueTypeTableNew(T_prep
, getTableSize(ttf
, O_prep
), p
);
2109 if ((p
= getTable(ttf
, O_fpgm
)) != nullptr) {
2110 fpgm
= TrueTypeTableNew(T_fpgm
, getTableSize(ttf
, O_fpgm
), p
);
2114 if ((p
= getTable(ttf
, O_post
)) != nullptr) {
2115 post
= TrueTypeTableNew_post(0x00030000,
2121 post
= TrueTypeTableNew_post(0x00030000, 0, 0, 0, 0);
2124 if (flags
& TTCF_IncludeOS2
) {
2125 if ((p
= getTable(ttf
, O_OS2
)) != nullptr) {
2126 os2
= TrueTypeTableNew(T_OS2
, getTableSize(ttf
, O_OS2
), p
);
2130 AddTable(ttcr
, name
); AddTable(ttcr
, maxp
); AddTable(ttcr
, hhea
);
2131 AddTable(ttcr
, head
); AddTable(ttcr
, glyf
); AddTable(ttcr
, cmap
);
2132 AddTable(ttcr
, cvt
); AddTable(ttcr
, prep
); AddTable(ttcr
, fpgm
);
2133 AddTable(ttcr
, post
); AddTable(ttcr
, os2
);
2135 if ((res
= StreamToFile(ttcr
, fname
)) != SF_OK
) {
2136 #if OSL_DEBUG_LEVEL > 1
2137 fprintf(stderr
, "StreamToFile: error code: %d.\n", res
);
2141 TrueTypeCreatorDispose(ttcr
);
2147 static GlyphOffsets
*GlyphOffsetsNew(sal_uInt8
*sfntP
, sal_uInt32 sfntLen
)
2149 GlyphOffsets
* res
= static_cast<GlyphOffsets
*>(smalloc(sizeof(GlyphOffsets
)));
2150 sal_uInt8
*loca
= nullptr;
2151 sal_uInt16 i
, numTables
= GetUInt16(sfntP
, 4);
2152 sal_uInt32 locaLen
= 0;
2153 sal_Int16 indexToLocFormat
= 0;
2155 sal_uInt32 nMaxPossibleTables
= sfntLen
/ (3*sizeof(sal_uInt32
)); /*the three GetUInt32 calls*/
2156 if (numTables
> nMaxPossibleTables
)
2158 SAL_WARN( "vcl.fonts", "GlyphOffsetsNew claimed to have "
2159 << numTables
<< " tables, but that's impossibly large");
2160 numTables
= nMaxPossibleTables
;
2163 for (i
= 0; i
< numTables
; i
++) {
2164 sal_uInt32 nLargestFixedOffsetPos
= 12 + 16 * i
+ 12;
2165 sal_uInt32 nMinSize
= nLargestFixedOffsetPos
+ sizeof(sal_uInt32
);
2166 if (nMinSize
> sfntLen
)
2168 SAL_WARN( "vcl.fonts", "GlyphOffsetsNew claimed to have "
2169 << numTables
<< " tables, but only space for " << i
);
2173 sal_uInt32 tag
= GetUInt32(sfntP
, 12 + 16 * i
);
2174 sal_uInt32 off
= GetUInt32(sfntP
, 12 + 16 * i
+ 8);
2175 sal_uInt32 len
= GetUInt32(sfntP
, nLargestFixedOffsetPos
);
2177 if (tag
== T_loca
) {
2180 } else if (tag
== T_head
) {
2181 indexToLocFormat
= GetInt16(sfntP
+ off
, 50);
2185 res
->nGlyphs
= locaLen
/ ((indexToLocFormat
== 1) ? 4 : 2);
2186 assert(res
->nGlyphs
!= 0);
2187 res
->offs
= static_cast<sal_uInt32
*>(scalloc(res
->nGlyphs
, sizeof(sal_uInt32
)));
2189 for (i
= 0; i
< res
->nGlyphs
; i
++) {
2190 if (indexToLocFormat
== 1) {
2191 res
->offs
[i
] = GetUInt32(loca
, i
* 4);
2193 res
->offs
[i
] = GetUInt16(loca
, i
* 2) << 1;
2199 static void GlyphOffsetsDispose(GlyphOffsets
*_this
)
2207 static void DumpSfnts(FILE *outf
, sal_uInt8
*sfntP
, sal_uInt32 sfntLen
)
2211 SAL_WARN( "vcl.fonts", "DumpSfnts sfntLen is too short: "
2212 << sfntLen
<< " legal min is: " << 12);
2216 const sal_uInt32 nSpaceForTables
= sfntLen
- 12;
2217 const sal_uInt32 nTableSize
= 16;
2218 const sal_uInt32 nMaxPossibleTables
= nSpaceForTables
/nTableSize
;
2220 HexFmt
*h
= HexFmtNew(outf
);
2221 sal_uInt16 i
, numTables
= GetUInt16(sfntP
, 4);
2222 GlyphOffsets
*go
= GlyphOffsetsNew(sfntP
, sfntLen
);
2223 sal_uInt8 pad
[] = {0,0,0,0}; /* zeroes */
2225 if (numTables
> nMaxPossibleTables
)
2227 SAL_WARN( "vcl.fonts", "DumpSfnts claimed to have "
2228 << numTables
<< " tables, but only space for " << nMaxPossibleTables
);
2229 numTables
= nMaxPossibleTables
;
2232 assert(numTables
<= 9); /* Type42 has 9 required tables */
2234 sal_uInt32
* offs
= static_cast<sal_uInt32
*>(scalloc(numTables
, sizeof(sal_uInt32
)));
2236 fputs("/sfnts [", outf
);
2237 HexFmtOpenString(h
);
2238 HexFmtBlockWrite(h
, sfntP
, 12); /* stream out the Offset Table */
2239 HexFmtBlockWrite(h
, sfntP
+12, 16 * numTables
); /* stream out the Table Directory */
2241 for (i
=0; i
<numTables
; i
++)
2243 sal_uInt32 nLargestFixedOffsetPos
= 12 + 16 * i
+ 12;
2244 sal_uInt32 nMinSize
= nLargestFixedOffsetPos
+ sizeof(sal_uInt32
);
2245 if (nMinSize
> sfntLen
)
2247 SAL_WARN( "vcl.fonts", "DumpSfnts claimed to have "
2248 << numTables
<< " tables, but only space for " << i
);
2252 sal_uInt32 tag
= GetUInt32(sfntP
, 12 + 16 * i
);
2253 sal_uInt32 off
= GetUInt32(sfntP
, 12 + 16 * i
+ 8);
2256 SAL_WARN( "vcl.fonts", "DumpSfnts claims offset of "
2257 << off
<< " but max possible is " << sfntLen
);
2260 sal_uInt8
*pRecordStart
= sfntP
+ off
;
2261 sal_uInt32 len
= GetUInt32(sfntP
, nLargestFixedOffsetPos
);
2262 sal_uInt32 nMaxLenPossible
= sfntLen
- off
;
2263 if (len
> nMaxLenPossible
)
2265 SAL_WARN( "vcl.fonts", "DumpSfnts claims len of "
2266 << len
<< " but only space for " << nMaxLenPossible
);
2272 HexFmtBlockWrite(h
, pRecordStart
, len
);
2276 sal_uInt8
*glyf
= pRecordStart
;
2277 for (sal_uInt32 j
= 0; j
< go
->nGlyphs
- 1; j
++)
2279 sal_uInt32 o
= go
->offs
[j
];
2280 sal_uInt32 l
= go
->offs
[j
+ 1] - o
;
2281 HexFmtBlockWrite(h
, glyf
+ o
, l
);
2284 HexFmtBlockWrite(h
, pad
, (4 - (len
& 3)) & 3);
2286 HexFmtCloseString(h
);
2287 fputs("] def\n", outf
);
2288 GlyphOffsetsDispose(go
);
2293 int CreateT42FromTTGlyphs(TrueTypeFont
*ttf
,
2296 sal_uInt16
*glyphArray
,
2297 sal_uInt8
*encoding
,
2300 TrueTypeCreator
*ttcr
;
2301 TrueTypeTable
*head
=nullptr, *hhea
=nullptr, *maxp
=nullptr, *cvt
=nullptr, *prep
=nullptr, *glyf
=nullptr, *fpgm
=nullptr;
2305 sal_uInt32 ver
, rev
;
2309 int UPEm
= ttf
->unitsPerEm
;
2311 if (nGlyphs
>= 256) return SF_GLYPHNUM
;
2313 assert(psname
!= nullptr);
2315 TrueTypeCreatorNewEmpty(T_true
, &ttcr
);
2318 const sal_uInt8
* p
= getTable(ttf
, O_head
);
2319 const sal_uInt8
* headP
= p
;
2320 assert(p
!= nullptr);
2321 head
= TrueTypeTableNew_head(GetUInt32(p
, 4), GetUInt16(p
, 16), GetUInt16(p
, 18), p
+20, GetUInt16(p
, 44), GetUInt16(p
, 46), GetInt16(p
, 48));
2322 ver
= GetUInt32(p
, 0);
2323 rev
= GetUInt32(p
, 4);
2326 p
= getTable(ttf
, O_hhea
);
2328 hhea
= TrueTypeTableNew_hhea(GetUInt16(p
, 4), GetUInt16(p
, 6), GetUInt16(p
, 8), GetUInt16(p
, 18), GetUInt16(p
, 20));
2330 hhea
= TrueTypeTableNew_hhea(0, 0, 0, 0, 0);
2334 maxp
= TrueTypeTableNew_maxp(getTable(ttf
, O_maxp
), getTableSize(ttf
, O_maxp
));
2337 if ((p
= getTable(ttf
, O_cvt
)) != nullptr) {
2338 cvt
= TrueTypeTableNew(T_cvt
, getTableSize(ttf
, O_cvt
), p
);
2342 if ((p
= getTable(ttf
, O_prep
)) != nullptr) {
2343 prep
= TrueTypeTableNew(T_prep
, getTableSize(ttf
, O_prep
), p
);
2347 if ((p
= getTable(ttf
, O_fpgm
)) != nullptr) {
2348 fpgm
= TrueTypeTableNew(T_fpgm
, getTableSize(ttf
, O_fpgm
), p
);
2352 glyf
= TrueTypeTableNew_glyf();
2353 sal_uInt16
* gID
= static_cast<sal_uInt16
*>(scalloc(nGlyphs
, sizeof(sal_uInt32
)));
2355 for (i
= 0; i
< nGlyphs
; i
++) {
2356 gID
[i
] = (sal_uInt16
)glyfAdd(glyf
, GetTTRawGlyphData(ttf
, glyphArray
[i
]), ttf
);
2359 AddTable(ttcr
, head
); AddTable(ttcr
, hhea
); AddTable(ttcr
, maxp
); AddTable(ttcr
, cvt
);
2360 AddTable(ttcr
, prep
); AddTable(ttcr
, glyf
); AddTable(ttcr
, fpgm
);
2362 if ((res
= StreamToMemory(ttcr
, &sfntP
, &sfntLen
)) != SF_OK
) {
2363 TrueTypeCreatorDispose(ttcr
);
2368 fprintf(outf
, "%%!PS-TrueTypeFont-%d.%d-%d.%d\n", (int)(ver
>>16), (int)(ver
& 0xFFFF), (int)(rev
>>16), (int)(rev
& 0xFFFF));
2369 fprintf(outf
, "%%%%Creator: %s %s %s\n", modname
, modver
, modextra
);
2370 fprintf(outf
, "%%- Font subset generated from a source font file: '%s'\n", ttf
->fname
);
2371 fprintf(outf
, "%%- Original font name: %s\n", ttf
->psname
);
2372 fprintf(outf
, "%%- Original font family: %s\n", ttf
->family
);
2373 fprintf(outf
, "%%- Original font sub-family: %s\n", ttf
->subfamily
);
2374 fprintf(outf
, "11 dict begin\n");
2375 fprintf(outf
, "/FontName (%s) cvn def\n", psname
);
2376 fprintf(outf
, "/PaintType 0 def\n");
2377 fprintf(outf
, "/FontMatrix [1 0 0 1 0 0] def\n");
2378 fprintf(outf
, "/FontBBox [%d %d %d %d] def\n", XUnits(UPEm
, GetInt16(headP
, 36)), XUnits(UPEm
, GetInt16(headP
, 38)), XUnits(UPEm
, GetInt16(headP
, 40)), XUnits(UPEm
, GetInt16(headP
, 42)));
2379 fprintf(outf
, "/FontType 42 def\n");
2380 fprintf(outf
, "/Encoding 256 array def\n");
2381 fprintf(outf
, " 0 1 255 {Encoding exch /.notdef put} for\n");
2383 for (i
= 1; i
<nGlyphs
; i
++) {
2384 fprintf(outf
, "Encoding %d /glyph%u put\n", encoding
[i
], gID
[i
]);
2386 fprintf(outf
, "/XUID [103 0 1 16#%08X %u 16#%08X 16#%08X] def\n", (unsigned int)rtl_crc32(0, ttf
->ptr
, ttf
->fsize
), (unsigned int)nGlyphs
, (unsigned int)rtl_crc32(0, glyphArray
, nGlyphs
* 2), (unsigned int)rtl_crc32(0, encoding
, nGlyphs
));
2388 DumpSfnts(outf
, sfntP
, sfntLen
);
2390 /* dump charstrings */
2391 fprintf(outf
, "/CharStrings %d dict dup begin\n", nGlyphs
);
2392 fprintf(outf
, "/.notdef 0 def\n");
2393 for (i
= 1; i
< (int)glyfCount(glyf
); i
++) {
2394 fprintf(outf
,"/glyph%d %d def\n", i
, i
);
2396 fprintf(outf
, "end readonly def\n");
2398 fprintf(outf
, "FontName currentdict end definefont pop\n");
2399 TrueTypeCreatorDispose(ttcr
);
2405 int MapString(TrueTypeFont
*ttf
, sal_uInt16
*str
, int nchars
, sal_uInt16
*glyphArray
, bool bvertical
)
2410 if (ttf
->cmapType
== CMAP_NOT_USABLE
) return -1;
2411 if (!nchars
) return 0;
2413 if (glyphArray
== nullptr) {
2419 switch (ttf
->cmapType
) {
2420 case CMAP_MS_Symbol
:
2421 if( ttf
->mapper
== getGlyph0
) {
2423 for( i
= 0; i
< nchars
; i
++ ) {
2425 if( ( aChar
& 0xf000 ) == 0xf000 )
2430 else if( glyphArray
)
2431 memcpy(glyphArray
, str
, nchars
* 2);
2434 case CMAP_MS_Unicode
:
2435 if (glyphArray
!= nullptr) {
2436 memcpy(glyphArray
, str
, nchars
* 2);
2440 case CMAP_MS_ShiftJIS
: TranslateString12(str
, cp
, nchars
); break;
2441 case CMAP_MS_Big5
: TranslateString13(str
, cp
, nchars
); break;
2442 case CMAP_MS_PRC
: TranslateString14(str
, cp
, nchars
); break;
2443 case CMAP_MS_Wansung
: TranslateString15(str
, cp
, nchars
); break;
2444 case CMAP_MS_Johab
: TranslateString16(str
, cp
, nchars
); break;
2447 const sal_uInt32 nMaxCmapSize
= ttf
->ptr
+ ttf
->fsize
- ttf
->cmap
;
2448 for (i
= 0; i
< nchars
; i
++) {
2449 cp
[i
] = (sal_uInt16
)ttf
->mapper(ttf
->cmap
, nMaxCmapSize
, cp
[i
]);
2450 if (cp
[i
]!=0 && bvertical
)
2451 cp
[i
] = (sal_uInt16
)UseGSUB(ttf
,cp
[i
]);
2456 #if defined(_WIN32) || defined(MACOSX) || defined(IOS)
2457 sal_uInt16
MapChar(TrueTypeFont
*ttf
, sal_uInt16 ch
, bool bvertical
)
2459 switch (ttf
->cmapType
) {
2460 case CMAP_MS_Symbol
:
2462 const sal_uInt32 nMaxCmapSize
= ttf
->ptr
+ ttf
->fsize
- ttf
->cmap
;
2463 if( ttf
->mapper
== getGlyph0
&& ( ch
& 0xf000 ) == 0xf000 )
2465 return (sal_uInt16
)ttf
->mapper(ttf
->cmap
, nMaxCmapSize
, ch
);
2468 case CMAP_MS_Unicode
: break;
2469 case CMAP_MS_ShiftJIS
: ch
= TranslateChar12(ch
); break;
2470 case CMAP_MS_Big5
: ch
= TranslateChar13(ch
); break;
2471 case CMAP_MS_PRC
: ch
= TranslateChar14(ch
); break;
2472 case CMAP_MS_Wansung
: ch
= TranslateChar15(ch
); break;
2473 case CMAP_MS_Johab
: ch
= TranslateChar16(ch
); break;
2476 const sal_uInt32 nMaxCmapSize
= ttf
->ptr
+ ttf
->fsize
- ttf
->cmap
;
2477 ch
= (sal_uInt16
)ttf
->mapper(ttf
->cmap
, nMaxCmapSize
, ch
);
2478 if (ch
!=0 && bvertical
)
2479 ch
= (sal_uInt16
)UseGSUB(ttf
,ch
);
2485 int DoesVerticalSubstitution( TrueTypeFont
*ttf
, int bvertical
)
2489 nRet
= HasVerticalGSUB( ttf
);
2493 int GetTTGlyphCount( TrueTypeFont
* ttf
)
2495 return ttf
->nglyphs
;
2498 bool GetSfntTable( TrueTypeFont
* ttf
, int nSubtableIndex
,
2499 const sal_uInt8
** ppRawBytes
, int* pRawLength
)
2501 if( (nSubtableIndex
< 0) || (nSubtableIndex
>= NUM_TAGS
) )
2503 *pRawLength
= ttf
->tlens
[ nSubtableIndex
];
2504 *ppRawBytes
= ttf
->tables
[ nSubtableIndex
];
2505 bool bOk
= (*pRawLength
> 0) && (*ppRawBytes
!= nullptr);
2509 TTSimpleGlyphMetrics
*GetTTSimpleGlyphMetrics(TrueTypeFont
*ttf
, sal_uInt16
*glyphArray
, int nGlyphs
, bool vertical
)
2511 const sal_uInt8
* pTable
;
2516 n
= ttf
->numberOfHMetrics
;
2517 pTable
= getTable( ttf
, O_hmtx
);
2518 nTableSize
= getTableSize( ttf
, O_hmtx
);
2520 n
= ttf
->numOfLongVerMetrics
;
2521 pTable
= getTable( ttf
, O_vmtx
);
2522 nTableSize
= getTableSize( ttf
, O_vmtx
);
2525 if (!nGlyphs
|| !glyphArray
) return nullptr; /* invalid parameters */
2526 if (!n
|| !pTable
) return nullptr; /* the font does not contain the requested metrics */
2528 TTSimpleGlyphMetrics
* res
= static_cast<TTSimpleGlyphMetrics
*>(calloc(nGlyphs
, sizeof(TTSimpleGlyphMetrics
)));
2529 assert(res
!= nullptr);
2531 const int UPEm
= ttf
->unitsPerEm
;
2532 for( int i
= 0; i
< nGlyphs
; ++i
) {
2533 int nAdvOffset
, nLsbOffset
;
2534 sal_uInt16 glyphID
= glyphArray
[i
];
2537 nAdvOffset
= 4 * glyphID
;
2538 nLsbOffset
= nAdvOffset
+ 2;
2540 nAdvOffset
= 4 * (n
- 1);
2541 if( glyphID
< ttf
->nglyphs
)
2542 nLsbOffset
= 4 * n
+ 2 * (glyphID
- n
);
2543 else /* font is broken -> use lsb of last hmetrics */
2544 nLsbOffset
= nAdvOffset
+ 2;
2547 if( nAdvOffset
>= nTableSize
)
2548 res
[i
].adv
= 0; /* better than a crash for buggy fonts */
2550 res
[i
].adv
= static_cast<sal_uInt16
>(
2551 XUnits( UPEm
, GetUInt16( pTable
, nAdvOffset
) ) );
2553 if( nLsbOffset
>= nTableSize
)
2554 res
[i
].sb
= 0; /* better than a crash for buggy fonts */
2556 res
[i
].sb
= static_cast<sal_Int16
>(
2557 XUnits( UPEm
, GetInt16( pTable
, nLsbOffset
) ) );
2563 TTSimpleGlyphMetrics
*GetTTSimpleCharMetrics(TrueTypeFont
* ttf
, sal_uInt16 firstChar
, int nChars
, bool vertical
)
2565 TTSimpleGlyphMetrics
*res
= nullptr;
2568 sal_uInt16
* str
= static_cast<sal_uInt16
*>(malloc(nChars
* 2));
2569 assert(str
!= nullptr);
2571 for (i
=0; i
<nChars
; i
++) str
[i
] = (sal_uInt16
)(firstChar
+ i
);
2572 if ((n
= MapString(ttf
, str
, nChars
, nullptr, vertical
)) != -1) {
2573 res
= GetTTSimpleGlyphMetrics(ttf
, str
, n
, vertical
);
2581 // TODO, clean up table parsing and re-use it elsewhere in this file.
2582 void GetTTFontMterics(const std::vector
<uint8_t>& hhea
,
2583 const std::vector
<uint8_t>& os2
,
2584 TTGlobalFontInfo
*info
)
2586 /* There are 3 different versions of OS/2 table: original (68 bytes long),
2587 * Microsoft old (78 bytes long) and Microsoft new (86 bytes long,)
2588 * Apple's documentation recommends looking at the table length.
2590 * FIXME: horribly outdated comment and horrible code that uses hard-coded
2591 * offsets to read the table.
2593 if (os2
.size() > 76 + 2)
2595 info
->fsSelection
= GetUInt16(os2
.data(), 62);
2596 info
->typoAscender
= GetInt16(os2
.data(), 68);
2597 info
->typoDescender
= GetInt16(os2
.data(), 70);
2598 info
->typoLineGap
= GetInt16(os2
.data(), 72);
2599 info
->winAscent
= GetUInt16(os2
.data(), 74);
2600 info
->winDescent
= GetUInt16(os2
.data(), 76);
2603 if (hhea
.size() > 8 + 2) {
2604 info
->ascender
= GetInt16(hhea
.data(), 4);
2605 info
->descender
= GetInt16(hhea
.data(), 6);
2606 info
->linegap
= GetInt16(hhea
.data(), 8);
2610 void GetTTGlobalFontInfo(TrueTypeFont
*ttf
, TTGlobalFontInfo
*info
)
2612 int UPEm
= ttf
->unitsPerEm
;
2614 memset(info
, 0, sizeof(TTGlobalFontInfo
));
2616 info
->family
= ttf
->family
;
2617 info
->ufamily
= ttf
->ufamily
;
2618 info
->subfamily
= ttf
->subfamily
;
2619 info
->usubfamily
= ttf
->usubfamily
;
2620 info
->psname
= ttf
->psname
;
2621 info
->symbolEncoded
= (ttf
->cmapType
== CMAP_MS_Symbol
);
2623 const sal_uInt8
* table
= getTable(ttf
, O_OS2
);
2624 sal_uInt32 table_size
= getTableSize(ttf
, O_OS2
);
2625 if (table
&& table_size
>= 42) {
2626 info
->weight
= GetUInt16(table
, 4);
2627 info
->width
= GetUInt16(table
, 6);
2629 /* There are 3 different versions of OS/2 table: original (68 bytes long),
2630 * Microsoft old (78 bytes long) and Microsoft new (86 bytes long,)
2631 * Apple's documentation recommends looking at the table length.
2633 if (table_size
>= 78) {
2634 info
->typoAscender
= XUnits(UPEm
,GetInt16(table
, 68));
2635 info
->typoDescender
= XUnits(UPEm
, GetInt16(table
, 70));
2636 info
->typoLineGap
= XUnits(UPEm
, GetInt16(table
, 72));
2637 info
->winAscent
= XUnits(UPEm
, GetUInt16(table
, 74));
2638 info
->winDescent
= XUnits(UPEm
, GetUInt16(table
, 76));
2639 /* sanity check; some fonts treat winDescent as signed
2640 * violating the standard */
2641 if( info
->winDescent
> 5*UPEm
)
2642 info
->winDescent
= XUnits(UPEm
, GetInt16(table
, 76));
2644 memcpy(info
->panose
, table
+ 32, 10);
2645 info
->typeFlags
= GetUInt16( table
, 8 );
2646 if( getTable(ttf
, O_CFF
) )
2647 info
->typeFlags
|= TYPEFLAG_PS_OPENTYPE
;
2650 table
= getTable(ttf
, O_post
);
2651 if (table
&& getTableSize(ttf
, O_post
) >= 12+sizeof(sal_uInt32
)) {
2652 info
->pitch
= GetUInt32(table
, 12);
2653 info
->italicAngle
= GetInt32(table
, 4);
2656 table
= getTable(ttf
, O_head
); /* 'head' tables is always there */
2657 table_size
= getTableSize(ttf
, O_head
);
2658 if (table_size
>= 46) {
2659 info
->xMin
= XUnits(UPEm
, GetInt16(table
, 36));
2660 info
->yMin
= XUnits(UPEm
, GetInt16(table
, 38));
2661 info
->xMax
= XUnits(UPEm
, GetInt16(table
, 40));
2662 info
->yMax
= XUnits(UPEm
, GetInt16(table
, 42));
2663 info
->macStyle
= GetInt16(table
, 44);
2666 table
= getTable(ttf
, O_hhea
);
2667 table_size
= getTableSize(ttf
, O_hhea
);
2668 if (table
&& table_size
>= 10) {
2669 info
->ascender
= XUnits(UPEm
, GetInt16(table
, 4));
2670 info
->descender
= XUnits(UPEm
, GetInt16(table
, 6));
2671 info
->linegap
= XUnits(UPEm
, GetInt16(table
, 8));
2674 table
= getTable(ttf
, O_vhea
);
2677 GlyphData
*GetTTRawGlyphData(TrueTypeFont
*ttf
, sal_uInt32 glyphID
)
2679 const sal_uInt8
* glyf
= getTable(ttf
, O_glyf
);
2680 const sal_uInt8
* hmtx
= getTable(ttf
, O_hmtx
);
2683 if( glyphID
>= ttf
->nglyphs
)
2686 /* #127161# check the glyph offsets */
2687 sal_uInt32 length
= getTableSize( ttf
, O_glyf
);
2688 if( length
< ttf
->goffsets
[ glyphID
+1 ] )
2691 length
= ttf
->goffsets
[glyphID
+1] - ttf
->goffsets
[glyphID
];
2693 GlyphData
* d
= static_cast<GlyphData
*>(malloc(sizeof(GlyphData
))); assert(d
!= nullptr);
2696 const sal_uInt8
* srcptr
= glyf
+ ttf
->goffsets
[glyphID
];
2697 const size_t nChunkLen
= ((length
+ 1) & ~1);
2698 d
->ptr
= static_cast<sal_uInt8
*>(malloc(nChunkLen
)); assert(d
->ptr
!= nullptr);
2699 memcpy(d
->ptr
, srcptr
, length
);
2700 memset(d
->ptr
+ length
, 0, nChunkLen
- length
);
2701 d
->compflag
= (GetInt16( srcptr
, 0 ) < 0);
2704 d
->compflag
= false;
2707 d
->glyphID
= glyphID
;
2708 d
->nbytes
= (sal_uInt16
)((length
+ 1) & ~1);
2710 /* now calculate npoints and ncontours */
2712 n
= GetTTGlyphPoints(ttf
, glyphID
, &cp
);
2716 for (int i
= 0; i
< n
; i
++)
2718 if (cp
[i
].flags
& 0x8000)
2721 d
->npoints
= (sal_uInt16
)n
;
2722 d
->ncontours
= (sal_uInt16
)m
;
2729 /* get advance width and left sidebearing */
2730 if (glyphID
< ttf
->numberOfHMetrics
) {
2731 d
->aw
= GetUInt16(hmtx
, 4 * glyphID
);
2732 d
->lsb
= GetInt16(hmtx
, 4 * glyphID
+ 2);
2734 d
->aw
= GetUInt16(hmtx
, 4 * (ttf
->numberOfHMetrics
- 1));
2735 d
->lsb
= GetInt16(hmtx
+ ttf
->numberOfHMetrics
* 4, (glyphID
- ttf
->numberOfHMetrics
) * 2);
2741 int GetTTNameRecords(TrueTypeFont
*ttf
, NameRecord
**nr
)
2743 const sal_uInt8
* table
= getTable(ttf
, O_name
);
2744 int nTableSize
= getTableSize(ttf
, O_name
);
2748 #if OSL_DEBUG_LEVEL > 1
2749 fprintf(stderr
, "O_name table too small\n");
2754 sal_uInt16 n
= GetUInt16(table
, 2);
2755 int nStrBase
= GetUInt16(table
, 4);
2759 if (n
== 0) return 0;
2761 const sal_uInt32 remaining_table_size
= nTableSize
-6;
2762 const sal_uInt32 nMinRecordSize
= 12;
2763 const sal_uInt32 nMaxRecords
= remaining_table_size
/ nMinRecordSize
;
2764 if (n
> nMaxRecords
)
2766 SAL_WARN("vcl.fonts", "Parsing error in " << OUString::createFromAscii(ttf
->fname
) <<
2767 ": " << nMaxRecords
<< " max possible entries, but " <<
2768 n
<< " claimed, truncating");
2772 NameRecord
* rec
= static_cast<NameRecord
*>(calloc(n
, sizeof(NameRecord
)));
2774 for (i
= 0; i
< n
; i
++) {
2775 int nLargestFixedOffsetPos
= 6 + 10 + 12 * i
;
2776 int nMinSize
= nLargestFixedOffsetPos
+ sizeof(sal_uInt16
);
2777 if (nMinSize
> nTableSize
)
2779 SAL_WARN( "vcl.fonts", "Font " << OUString::createFromAscii(ttf
->fname
) << " claimed to have "
2780 << n
<< " name records, but only space for " << i
);
2785 rec
[i
].platformID
= GetUInt16(table
, 6 + 0 + 12 * i
);
2786 rec
[i
].encodingID
= GetUInt16(table
, 6 + 2 + 12 * i
);
2787 rec
[i
].languageID
= GetUInt16(table
, 6 + 4 + 12 * i
);
2788 rec
[i
].nameID
= GetUInt16(table
, 6 + 6 + 12 * i
);
2789 rec
[i
].slen
= GetUInt16(table
, 6 + 8 + 12 * i
);
2790 int nStrOffset
= GetUInt16(table
, nLargestFixedOffsetPos
);
2792 if( nStrBase
+nStrOffset
+rec
[i
].slen
>= nTableSize
) {
2793 rec
[i
].sptr
= nullptr;
2798 const sal_uInt8
* rec_string
= table
+ nStrBase
+ nStrOffset
;
2800 const sal_uInt8
* end_table
= ttf
->ptr
+ ttf
->fsize
;
2801 const size_t available_space
= rec_string
> end_table
? 0 : (end_table
- rec_string
);
2802 if (rec
[i
].slen
<= available_space
)
2804 rec
[i
].sptr
= static_cast<sal_uInt8
*>(malloc(rec
[i
].slen
)); assert(rec
[i
].sptr
!= nullptr);
2805 memcpy(rec
[i
].sptr
, rec_string
, rec
[i
].slen
);
2809 rec
[i
].sptr
= nullptr;
2813 rec
[i
].sptr
= nullptr;
2815 // some fonts have 3.0 names => fix them to 3.1
2816 if( (rec
[i
].platformID
== 3) && (rec
[i
].encodingID
== 0) )
2817 rec
[i
].encodingID
= 1;
2824 void DisposeNameRecords(NameRecord
* nr
, int n
)
2827 for (i
= 0; i
< n
; i
++) {
2828 if (nr
[i
].sptr
) free(nr
[i
].sptr
);
2833 template<size_t N
> void
2834 append(std::bitset
<N
> & rSet
, size_t const nOffset
, sal_uInt32
const nValue
)
2836 for (size_t i
= 0; i
< 32; ++i
)
2838 rSet
.set(nOffset
+ i
, (nValue
& (1 << i
)) != 0);
2843 boost::optional
<std::bitset
<UnicodeCoverage::MAX_UC_ENUM
>> &rUnicodeRange
,
2844 boost::optional
<std::bitset
<CodePageCoverage::MAX_CP_ENUM
>> &rCodePageRange
,
2845 const unsigned char* pTable
, size_t nLength
)
2848 // parse OS/2 header
2851 rUnicodeRange
= std::bitset
<UnicodeCoverage::MAX_UC_ENUM
>();
2852 append(rUnicodeRange
.get(), 0, GetUInt32(pTable
, 42));
2853 append(rUnicodeRange
.get(), 32, GetUInt32(pTable
, 46));
2854 append(rUnicodeRange
.get(), 64, GetUInt32(pTable
, 50));
2855 append(rUnicodeRange
.get(), 96, GetUInt32(pTable
, 54));
2859 rCodePageRange
= std::bitset
<CodePageCoverage::MAX_CP_ENUM
>();
2860 append(rCodePageRange
.get(), 0, GetUInt32(pTable
, 78));
2861 append(rCodePageRange
.get(), 32, GetUInt32(pTable
, 82));
2867 void getTTScripts(std::vector
< sal_uInt32
> &rScriptTags
, const unsigned char* pTable
, size_t nLength
)
2872 // parse GSUB/GPOS header
2873 const sal_uInt16 nOfsScriptList
= GetUInt16(pTable
, 4);
2875 // parse Script Table
2876 const sal_uInt16 nCntScript
= GetUInt16(pTable
, nOfsScriptList
);
2877 sal_uInt32 nCurrentPos
= nOfsScriptList
+2;
2878 for( sal_uInt16 nScriptIndex
= 0;
2879 nScriptIndex
< nCntScript
&& nLength
>= 6; ++nScriptIndex
,
2882 sal_uInt32 nTag
= GetUInt32(pTable
, nCurrentPos
);
2884 rScriptTags
.push_back(nTag
); // e.g. hani/arab/kana/hang
2887 std::sort(rScriptTags
.begin(), rScriptTags
.end());
2888 rScriptTags
.erase(std::unique(rScriptTags
.begin(), rScriptTags
.end()), rScriptTags
.end());
2893 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */