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 .
21 * TrueTypeCreator method implementation
27 #include <sal/log.hxx>
45 /*- Data access macros for data stored in big-endian or little-endian format */
46 static sal_Int16
GetInt16( const sal_uInt8
* ptr
, sal_uInt32 offset
)
48 assert(ptr
!= nullptr);
49 sal_Int16 t
= (ptr
+offset
)[0] << 8 | (ptr
+offset
)[1];
53 static sal_uInt16
GetUInt16( const sal_uInt8
* ptr
, sal_uInt32 offset
)
55 assert(ptr
!= nullptr);
56 sal_uInt16 t
= (ptr
+offset
)[0] << 8 | (ptr
+offset
)[1];
60 static void PutInt16(sal_Int16 val
, sal_uInt8
*ptr
, sal_uInt32 offset
)
62 assert(ptr
!= nullptr);
64 ptr
[offset
] = static_cast<sal_uInt8
>((val
>> 8) & 0xFF);
65 ptr
[offset
+1] = static_cast<sal_uInt8
>(val
& 0xFF);
68 static void PutUInt16(sal_uInt16 val
, sal_uInt8
*ptr
, sal_uInt32 offset
)
70 assert(ptr
!= nullptr);
72 ptr
[offset
] = static_cast<sal_uInt8
>((val
>> 8) & 0xFF);
73 ptr
[offset
+1] = static_cast<sal_uInt8
>(val
& 0xFF);
76 static void PutUInt32(sal_uInt32 val
, sal_uInt8
*ptr
, sal_uInt32 offset
)
78 assert(ptr
!= nullptr);
80 ptr
[offset
] = static_cast<sal_uInt8
>((val
>> 24) & 0xFF);
81 ptr
[offset
+1] = static_cast<sal_uInt8
>((val
>> 16) & 0xFF);
82 ptr
[offset
+2] = static_cast<sal_uInt8
>((val
>> 8) & 0xFF);
83 ptr
[offset
+3] = static_cast<sal_uInt8
>(val
& 0xFF);
86 static int TableEntryCompareF(const void *l
, const void *r
)
88 sal_uInt32
const ltag(static_cast<TableEntry
const*>(l
)->tag
);
89 sal_uInt32
const rtag(static_cast<TableEntry
const*>(r
)->tag
);
90 return (ltag
== rtag
) ? 0 : (ltag
< rtag
) ? -1 : 1;
94 struct NameRecordCompareF
96 bool operator()(const NameRecord
& l
, const NameRecord
& r
) const
98 if (l
.platformID
!= r
.platformID
) {
99 return l
.platformID
< r
.platformID
;
100 } else if (l
.encodingID
!= r
.encodingID
) {
101 return l
.encodingID
< r
.encodingID
;
102 } else if (l
.languageID
!= r
.languageID
) {
103 return l
.languageID
< r
.languageID
;
104 } else if (l
.nameID
!= r
.nameID
) {
105 return l
.nameID
< r
.nameID
;
112 static sal_uInt32
CheckSum(sal_uInt32
*ptr
, sal_uInt32 length
)
115 sal_uInt32
*endptr
= ptr
+ ((length
+ 3) & sal_uInt32(~3)) / 4;
117 while (ptr
< endptr
) sum
+= *ptr
++;
126 TrueTypeCreator::TrueTypeCreator(sal_uInt32 _tag
)
131 void TrueTypeCreator::AddTable(std::unique_ptr
<TrueTypeTable
> table
)
133 if (table
!= nullptr) {
134 this->m_tables
.push_back(std::move(table
));
138 void TrueTypeCreator::RemoveTable(sal_uInt32 tableTag
)
140 for (auto it
= this->m_tables
.begin(); it
!= this->m_tables
.end(); )
142 if ((*it
)->m_tag
== tableTag
)
144 it
= this->m_tables
.erase(it
);
151 SFErrCodes
TrueTypeCreator::StreamToMemory(std::vector
<sal_uInt8
>& rOutBuffer
)
153 sal_uInt16 searchRange
=1, entrySelector
=0, rangeShift
;
154 sal_uInt32 s
, offset
, checkSumAdjustment
= 0;
156 sal_uInt8
*head
= nullptr; /* saved pointer to the head table data for checkSumAdjustment calculation */
158 if (this->m_tables
.empty())
159 return SFErrCodes::TtFormat
;
163 /* ProcessTables() adds 'loca' and 'hmtx' */
165 sal_uInt16 numTables
= this->m_tables
.size();
167 std::unique_ptr
<TableEntry
[]> te(new TableEntry
[numTables
]);
170 for (auto const & e
: this->m_tables
)
172 e
->GetRawData(&te
[teIdx
]);
176 qsort(te
.get(), numTables
, sizeof(TableEntry
), TableEntryCompareF
);
181 } while (searchRange
<= numTables
);
185 rangeShift
= numTables
* 16 - searchRange
;
187 s
= offset
= 12 + 16 * numTables
;
189 for (int i
= 0; i
< numTables
; ++i
) {
190 s
+= (te
[i
].length
+ 3) & sal_uInt32(~3);
191 /* if ((te[i].length & 3) != 0) s += (4 - (te[i].length & 3)) & 3; */
194 rOutBuffer
.resize(s
);
195 sal_uInt8
* ttf
= rOutBuffer
.data();
198 PutUInt32(this->m_tag
, ttf
, 0);
199 PutUInt16(numTables
, ttf
, 4);
200 PutUInt16(searchRange
, ttf
, 6);
201 PutUInt16(entrySelector
, ttf
, 8);
202 PutUInt16(rangeShift
, ttf
, 10);
204 /* Table Directory */
205 for (int i
= 0; i
< numTables
; ++i
) {
206 PutUInt32(te
[i
].tag
, ttf
+ 12, 16 * i
);
207 PutUInt32(CheckSum(reinterpret_cast<sal_uInt32
*>(te
[i
].data
), te
[i
].length
), ttf
+ 12, 16 * i
+ 4);
208 PutUInt32(offset
, ttf
+ 12, 16 * i
+ 8);
209 PutUInt32(te
[i
].length
, ttf
+ 12, 16 * i
+ 12);
211 if (te
[i
].tag
== T_head
) {
215 memcpy(ttf
+offset
, te
[i
].data
, (te
[i
].length
+ 3) & sal_uInt32(~3) );
216 offset
+= (te
[i
].length
+ 3) & sal_uInt32(~3);
217 /* if ((te[i].length & 3) != 0) offset += (4 - (te[i].length & 3)) & 3; */
222 p
= reinterpret_cast<sal_uInt32
*>(ttf
);
223 for (int i
= 0; i
< static_cast<int>(s
) / 4; ++i
) checkSumAdjustment
+= p
[i
];
224 PutUInt32(0xB1B0AFBA - checkSumAdjustment
, head
, 8);
226 return SFErrCodes::Ok
;
230 * TrueTypeTable private methods
233 /* Table data points to
234 * --------------------------------------------
235 * generic tdata_generic struct
236 * 'head' HEAD_Length bytes of memory
237 * 'hhea' HHEA_Length bytes of memory
238 * 'loca' tdata_loca struct
239 * 'maxp' MAXP_Version1Length bytes of memory
240 * 'glyf' list of GlyphData structs (defined in sft.h)
241 * 'name' list of NameRecord structs (defined in sft.h)
242 * 'post' tdata_post struct
246 #define CMAP_SUBTABLE_INIT 10
247 #define CMAP_SUBTABLE_INCR 10
251 struct CmapSubTable
{
252 sal_uInt32 id
; /* subtable ID (platform/encoding ID) */
253 std::vector
<std::pair
<sal_uInt32
, sal_uInt32
>> mappings
; /* character to glyph mapping array */
259 sal_uInt32 n
; /* number of used CMAP sub-tables */
260 sal_uInt32 m
; /* number of allocated CMAP sub-tables */
261 std::unique_ptr
<CmapSubTable
[]> s
; /* sorted array of sub-tables */
265 sal_uInt32 nbytes
; /* number of bytes in loca table */
266 std::unique_ptr
<sal_uInt8
[]> ptr
; /* pointer to the data */
269 /* allocate memory for a TT table */
270 static std::unique_ptr
<sal_uInt8
[]> ttmalloc(sal_uInt32 nbytes
)
272 sal_uInt32 n
= (nbytes
+ 3) & sal_uInt32(~3);
273 return std::make_unique
<sal_uInt8
[]>(n
);
276 TrueTypeTable::~TrueTypeTable() {}
278 TrueTypeTableGeneric::~TrueTypeTableGeneric()
282 TrueTypeTableHead::~TrueTypeTableHead()
286 TrueTypeTableHhea::~TrueTypeTableHhea()
290 TrueTypeTableLoca::~TrueTypeTableLoca()
294 TrueTypeTableMaxp::~TrueTypeTableMaxp()
298 TrueTypeTableGlyf::~TrueTypeTableGlyf()
302 TrueTypeTableCmap::~TrueTypeTableCmap()
306 TrueTypeTableName::~TrueTypeTableName()
310 TrueTypeTablePost::~TrueTypeTablePost()
312 if (m_format
== 0x00030000) {
315 SAL_WARN("vcl.fonts", "Unsupported format of a 'post' table: "
320 << static_cast<int>(m_format
) << ".");
325 int TrueTypeTableGeneric::GetRawData(TableEntry
* te
)
327 te
->data
= this->m_ptr
.get();
328 te
->length
= this->m_nbytes
;
329 te
->tag
= this->m_tag
;
334 int TrueTypeTableHead::GetRawData(TableEntry
* te
)
336 te
->length
= HEAD_Length
;
337 te
->data
= this->m_head
.get();
343 int TrueTypeTableHhea::GetRawData(TableEntry
* te
)
345 te
->length
= HHEA_Length
;
346 te
->data
= this->m_hhea
.get();
352 int TrueTypeTableLoca::GetRawData(TableEntry
* te
)
354 assert(this->m_loca
!= nullptr);
356 if (m_loca
->nbytes
== 0) return TTCR_ZEROGLYPHS
;
358 te
->data
= m_loca
->ptr
.get();
359 te
->length
= m_loca
->nbytes
;
365 int TrueTypeTableMaxp::GetRawData(TableEntry
* te
)
367 te
->length
= MAXP_Version1Length
;
368 te
->data
= this->m_maxp
.get();
374 int TrueTypeTableGlyf::GetRawData(TableEntry
* te
)
376 sal_uInt32 n
, nbytes
= 0;
377 /* sal_uInt16 curID = 0; */ /* to check if glyph IDs are sequential and start from zero */
383 if (m_list
.size() == 0) return TTCR_ZEROGLYPHS
;
385 for (const std::unique_ptr
<GlyphData
>& pGlyph
: m_list
)
387 /* if (((GlyphData *) listCurrent(l))->glyphID != curID++) return TTCR_GLYPHSEQ; */
388 nbytes
+= pGlyph
->nbytes
;
391 m_rawdata
= ttmalloc(nbytes
);
393 auto p
= m_rawdata
.get();
394 for (const std::unique_ptr
<GlyphData
>& pGlyph
: m_list
)
398 memcpy(p
, pGlyph
->ptr
.get(), n
);
404 te
->data
= m_rawdata
.get();
411 static std::unique_ptr
<sal_uInt8
[]> PackCmapType0(CmapSubTable
const *s
, sal_uInt32
*length
)
413 std::unique_ptr
<sal_uInt8
[]> ptr(new sal_uInt8
[262]);
414 sal_uInt8
*p
= ptr
.get() + 6;
416 PutUInt16(0, ptr
.get(), 0);
417 PutUInt16(262, ptr
.get(), 2);
418 PutUInt16(0, ptr
.get(), 4);
420 for (sal_uInt32 i
= 0; i
< 256; i
++) {
422 for (const auto& [ch
, glyph
] : s
->mappings
) {
424 g
= static_cast<sal_uInt16
>(glyph
);
427 p
[i
] = static_cast<sal_uInt8
>(g
);
433 static std::unique_ptr
<sal_uInt8
[]> PackCmapType6(CmapSubTable
const *s
, sal_uInt32
*length
)
435 std::unique_ptr
<sal_uInt8
[]> ptr(new sal_uInt8
[s
->mappings
.size()*2 + 10]);
436 sal_uInt8
*p
= ptr
.get() + 10;
438 PutUInt16(6, ptr
.get(), 0);
439 PutUInt16(static_cast<sal_uInt16
>(s
->mappings
.size()*2+10), ptr
.get(), 2);
440 PutUInt16(0, ptr
.get(), 4);
441 PutUInt16(0, ptr
.get(), 6);
442 PutUInt16(static_cast<sal_uInt16
>(s
->mappings
.size()), ptr
.get(), 8 );
444 for (size_t i
= 0; i
< s
->mappings
.size(); i
++) {
446 for (const auto& [ch
, glyph
] : s
->mappings
) {
448 g
= static_cast<sal_uInt16
>(glyph
);
451 PutUInt16( g
, p
, 2*i
);
453 *length
= s
->mappings
.size()*2+10;
457 /* XXX it only handles Format 0 encoding tables */
458 static std::unique_ptr
<sal_uInt8
[]> PackCmap(CmapSubTable
const *s
, sal_uInt32
*length
)
460 if (s
->mappings
.back().second
> 0xff)
461 return PackCmapType6(s
, length
);
463 return PackCmapType0(s
, length
);
466 int TrueTypeTableCmap::GetRawData(TableEntry
* te
)
476 assert(m_cmap
->n
!= 0);
478 std::unique_ptr
<std::unique_ptr
<sal_uInt8
[]>[]> subtables(new std::unique_ptr
<sal_uInt8
[]>[m_cmap
->n
]);
479 std::unique_ptr
<sal_uInt32
[]> sizes(new sal_uInt32
[m_cmap
->n
]);
481 for (i
= 0; i
< m_cmap
->n
; i
++) {
482 subtables
[i
] = PackCmap(m_cmap
->s
.get()+i
, &l
);
487 cmapsize
= tlen
+ 4 + 8 * m_cmap
->n
;
488 this->m_rawdata
= ttmalloc(cmapsize
);
489 cmap
= this->m_rawdata
.get();
491 PutUInt16(0, cmap
, 0);
492 PutUInt16(static_cast<sal_uInt16
>(m_cmap
->n
), cmap
, 2);
493 coffset
= 4 + m_cmap
->n
* 8;
495 for (i
= 0; i
< m_cmap
->n
; i
++) {
496 PutUInt16(static_cast<sal_uInt16
>(m_cmap
->s
[i
].id
>> 16), cmap
+ 4, i
* 8);
497 PutUInt16(static_cast<sal_uInt16
>(m_cmap
->s
[i
].id
& 0xFF), cmap
+ 4, 2 + i
* 8);
498 PutUInt32(coffset
, cmap
+ 4, 4 + i
* 8);
499 memcpy(cmap
+ coffset
, subtables
[i
].get(), sizes
[i
]);
500 subtables
[i
].reset();
508 te
->length
= cmapsize
;
514 int TrueTypeTableName::GetRawData(TableEntry
* te
)
516 sal_Int16 i
=0, n
; /* number of Name Records */
524 if ((n
= static_cast<sal_Int16
>(m_list
.size())) == 0) return TTCR_NONAMES
;
526 std::vector
<NameRecord
> nr
= m_list
;
528 for (const NameRecord
& rName
: m_list
)
529 stringLen
+= rName
.sptr
.size();
531 if (stringLen
> 65535) {
532 return TTCR_NAMETOOLONG
;
535 std::sort(nr
.begin(), nr
.end(), NameRecordCompareF());
537 int nameLen
= stringLen
+ 12 * n
+ 6;
538 std::unique_ptr
<sal_uInt8
[]> name
= ttmalloc(nameLen
);
540 PutUInt16(0, name
.get(), 0);
541 PutUInt16(n
, name
.get(), 2);
542 PutUInt16(static_cast<sal_uInt16
>(6 + 12 * n
), name
.get(), 4);
547 for (i
= 0; i
< n
; i
++) {
548 PutUInt16(nr
[i
].platformID
, p1
, 0);
549 PutUInt16(nr
[i
].encodingID
, p1
, 2);
550 PutUInt16(static_cast<sal_uInt16
>(nr
[i
].languageID
), p1
, 4);
551 PutUInt16(nr
[i
].nameID
, p1
, 6);
552 PutUInt16(nr
[i
].sptr
.size(), p1
, 8);
553 PutUInt16(static_cast<sal_uInt16
>(p2
- (name
.get() + 6 + 12 * n
)), p1
, 10);
554 if (nr
[i
].sptr
.size()) {
555 memcpy(p2
, nr
[i
].sptr
.data(), nr
[i
].sptr
.size());
557 /* {int j; for(j=0; j<nr[i].slen; j++) printf("%c", nr[i].sptr[j]); printf("\n"); }; */
558 p2
+= nr
[i
].sptr
.size();
563 this->m_rawdata
= std::move(name
);
565 te
->data
= this->m_rawdata
.get();
566 te
->length
= static_cast<sal_uInt16
>(nameLen
);
569 /*{int j; for(j=0; j<nameLen; j++) printf("%c", name[j]); }; */
574 int TrueTypeTablePost::GetRawData(TableEntry
* te
)
576 std::unique_ptr
<sal_uInt8
[]> post
;
577 sal_uInt32 postLen
= 0;
580 this->m_rawdata
.reset();
582 if (m_format
== 0x00030000) {
584 post
= ttmalloc(postLen
);
585 PutUInt32(0x00030000, post
.get(), 0);
586 PutUInt32(m_italicAngle
, post
.get(), 4);
587 PutUInt16(m_underlinePosition
, post
.get(), 8);
588 PutUInt16(m_underlineThickness
, post
.get(), 10);
589 PutUInt16(static_cast<sal_uInt16
>(m_isFixedPitch
), post
.get(), 12);
592 SAL_WARN("vcl.fonts", "Unrecognized format of a post table: "
597 << static_cast<int>(m_format
) << ".");
598 ret
= TTCR_POSTFORMAT
;
601 this->m_rawdata
= std::move(post
);
602 te
->data
= this->m_rawdata
.get();
603 te
->length
= postLen
;
610 * TrueTypeTable public methods
613 /* Note: Type42 fonts only need these tables:
614 * head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm
616 * Microsoft required tables
617 * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post, OS/2
619 * Apple required tables
620 * cmap, glyf, head, hhea, hmtx, loca, maxp, name, post
624 TrueTypeTableGeneric::TrueTypeTableGeneric(sal_uInt32 tag
,
626 const sal_uInt8
* ptr
)
627 : TrueTypeTable(tag
),
631 m_ptr
= ttmalloc(nbytes
);
632 memcpy(m_ptr
.get(), ptr
, nbytes
);
636 TrueTypeTableGeneric::TrueTypeTableGeneric(sal_uInt32 tag
,
638 std::unique_ptr
<sal_uInt8
[]> ptr
)
639 : TrueTypeTable(tag
),
643 m_ptr
= std::move(ptr
);
647 TrueTypeTableHead::TrueTypeTableHead(sal_uInt32 fontRevision
,
649 sal_uInt16 unitsPerEm
,
650 const sal_uInt8
* created
,
652 sal_uInt16 lowestRecPPEM
,
653 sal_Int16 fontDirectionHint
)
654 : TrueTypeTable(T_head
)
655 , m_head(ttmalloc(HEAD_Length
))
657 assert(created
!= nullptr);
659 sal_uInt8
* ptr
= m_head
.get();
661 PutUInt32(0x00010000, ptr
, 0); /* version */
662 PutUInt32(fontRevision
, ptr
, 4);
663 PutUInt32(0x5F0F3CF5, ptr
, 12); /* magic number */
664 PutUInt16(flags
, ptr
, 16);
665 PutUInt16(unitsPerEm
, ptr
, 18);
666 memcpy(ptr
+20, created
, 8); /* Created Long Date */
667 memset(ptr
+28, 0, 8); /* Modified Long Date */
668 PutUInt16(macStyle
, ptr
, 44);
669 PutUInt16(lowestRecPPEM
, ptr
, 46);
670 PutUInt16(fontDirectionHint
, ptr
, 48);
671 PutUInt16(0, ptr
, 52); /* glyph data format: 0 */
674 TrueTypeTableHhea::TrueTypeTableHhea(sal_Int16 ascender
,
677 sal_Int16 caretSlopeRise
,
678 sal_Int16 caretSlopeRun
)
679 : TrueTypeTable(T_hhea
),
680 m_hhea(ttmalloc(HHEA_Length
))
682 sal_uInt8
* ptr
= m_hhea
.get();
684 PutUInt32(0x00010000, ptr
, 0); /* version */
685 PutUInt16(ascender
, ptr
, 4);
686 PutUInt16(descender
, ptr
, 6);
687 PutUInt16(linegap
, ptr
, 8);
688 PutUInt16(caretSlopeRise
, ptr
, 18);
689 PutUInt16(caretSlopeRun
, ptr
, 20);
690 PutUInt16(0, ptr
, 22); /* reserved 1 */
691 PutUInt16(0, ptr
, 24); /* reserved 2 */
692 PutUInt16(0, ptr
, 26); /* reserved 3 */
693 PutUInt16(0, ptr
, 28); /* reserved 4 */
694 PutUInt16(0, ptr
, 30); /* reserved 5 */
695 PutUInt16(0, ptr
, 32); /* metricDataFormat */
698 TrueTypeTableLoca::TrueTypeTableLoca()
699 : TrueTypeTable(T_loca
),
700 m_loca(new tdata_loca
)
702 this->m_loca
->nbytes
= 0;
703 this->m_loca
->ptr
= nullptr;
706 TrueTypeTableMaxp::TrueTypeTableMaxp( const sal_uInt8
* maxp
, int size
)
707 : TrueTypeTable(T_maxp
)
709 this->m_maxp
= ttmalloc(MAXP_Version1Length
);
711 if (maxp
&& size
== MAXP_Version1Length
) {
712 memcpy(this->m_maxp
.get(), maxp
, MAXP_Version1Length
);
716 TrueTypeTableGlyf::TrueTypeTableGlyf()
717 : TrueTypeTable(T_glyf
)
721 TrueTypeTableCmap::TrueTypeTableCmap()
722 : TrueTypeTable(T_cmap
)
723 , m_cmap(new table_cmap
)
726 m_cmap
->m
= CMAP_SUBTABLE_INIT
;
727 m_cmap
->s
.reset(new CmapSubTable
[CMAP_SUBTABLE_INIT
]);
730 TrueTypeTableName::TrueTypeTableName(std::vector
<NameRecord
> nr
)
731 : TrueTypeTable(T_name
)
732 , m_list(std::move(nr
))
736 TrueTypeTablePost::TrueTypeTablePost(sal_Int32 format
,
737 sal_Int32 italicAngle
,
738 sal_Int16 underlinePosition
,
739 sal_Int16 underlineThickness
,
740 sal_uInt32 isFixedPitch
)
741 : TrueTypeTable(T_post
)
743 assert(format
== 0x00030000); /* Only format 3.0 is supported at this time */
746 m_italicAngle
= italicAngle
;
747 m_underlinePosition
= underlinePosition
;
748 m_underlineThickness
= underlineThickness
;
749 m_isFixedPitch
= isFixedPitch
;
752 void TrueTypeTableCmap::cmapAdd(sal_uInt32 id
, sal_uInt32 c
, sal_uInt32 g
)
758 s
= m_cmap
->s
.get(); assert(s
!= nullptr);
762 for (i
= 0; i
< m_cmap
->n
; i
++) {
770 if (m_cmap
->n
== m_cmap
->m
) {
771 std::unique_ptr
<CmapSubTable
[]> tmp(new CmapSubTable
[m_cmap
->m
+ CMAP_SUBTABLE_INCR
]);
772 for (sal_uInt32 j
= 0; j
!= m_cmap
->m
; ++j
) {
773 tmp
[j
] = std::move(s
[j
]);
775 m_cmap
->m
+= CMAP_SUBTABLE_INCR
;
777 m_cmap
->s
= std::move(tmp
);
780 for (i
= 0; i
< m_cmap
->n
; i
++) {
781 if (s
[i
].id
> id
) break;
785 for (sal_uInt32 j
= m_cmap
->n
; j
!= i
; --j
) {
786 s
[j
+ 1] = std::move(s
[j
]);
795 s
[i
].mappings
.emplace_back(c
, g
);
798 sal_uInt32
TrueTypeTableGlyf::glyfAdd(std::unique_ptr
<GlyphData
> glyphdata
, AbstractTrueTypeFont
*fnt
)
800 sal_uInt32 currentID
;
801 int ret
, n
, ncomponents
;
803 if (!glyphdata
) return sal_uInt32(~0);
805 std::vector
< sal_uInt32
> glyphlist
;
807 ncomponents
= GetTTGlyphComponents(fnt
, glyphdata
->glyphID
, glyphlist
);
809 if (m_list
.size() > 0) {
810 ret
= n
= m_list
.back()->newID
+ 1;
814 glyphdata
->newID
= n
++;
815 m_list
.push_back(std::move(glyphdata
));
817 if (ncomponents
> 1 && glyphlist
.size() > 1 )
819 std::vector
< sal_uInt32
>::const_iterator it
= glyphlist
.begin();
821 /* glyphData->glyphID is always the first glyph on the list */
826 /* XXX expensive! should be rewritten with sorted arrays! */
827 for (const std::unique_ptr
<GlyphData
>& pGlyph
: m_list
)
829 if (pGlyph
->glyphID
== currentID
) {
836 std::unique_ptr
<GlyphData
> gd
= GetTTRawGlyphData(fnt
, currentID
);
838 m_list
.push_back(std::move(gd
));
840 } while( ++it
!= glyphlist
.end() );
846 TrueTypeTable
*TrueTypeCreator::FindTable(sal_uInt32 tableTag
)
848 for (const std::unique_ptr
<TrueTypeTable
>& p
: this->m_tables
)
849 if (p
->m_tag
== tableTag
) {
856 /* This function processes all the tables and synchronizes them before creating
857 * the output TrueType stream.
859 * *** It adds two TrueType tables to the font: 'loca' and 'hmtx' ***
863 * - Re-numbers glyph IDs and creates 'glyf', 'loca', and 'hmtx' tables.
864 * - Calculates xMin, yMin, xMax, and yMax and stores values in 'head' table.
865 * - Stores indexToLocFormat in 'head'
866 * - updates 'maxp' table
867 * - Calculates advanceWidthMax, minLSB, minRSB, xMaxExtent and numberOfHMetrics
871 void TrueTypeCreator::ProcessTables()
873 TrueTypeTableHhea
*hhea
= nullptr;
874 TrueTypeTableMaxp
*maxp
= nullptr;
875 TrueTypeTableHead
*head
= nullptr;
876 std::unique_ptr
<TrueTypeTableLoca
> loca
;
877 TrueTypeTableGlyf
*glyf
= nullptr;
878 sal_uInt32 nGlyphs
, locaLen
= 0, glyfLen
= 0;
879 sal_Int16 xMin
= 0, yMin
= 0, xMax
= 0, yMax
= 0;
881 sal_Int16 indexToLocFormat
;
882 std::unique_ptr
<sal_uInt8
[]> hmtxPtr
;
886 sal_uInt16 maxPoints
= 0, maxContours
= 0, maxCompositePoints
= 0, maxCompositeContours
= 0;
888 std::unique_ptr
<sal_uInt32
[]> gid
; /* array of old glyphIDs */
890 glyf
= static_cast<TrueTypeTableGlyf
*>(FindTable(T_glyf
));
891 std::vector
<std::unique_ptr
<GlyphData
>>& glyphlist
= glyf
->m_list
;
892 nGlyphs
= glyphlist
.size();
895 SAL_WARN("vcl.fonts", "no glyphs found in ProcessTables");
898 gid
.reset(new sal_uInt32
[nGlyphs
]);
903 /* XXX Need to make sure that composite glyphs do not break during glyph renumbering */
905 for (const std::unique_ptr
<GlyphData
>& gd
: glyphlist
)
907 glyfLen
+= gd
->nbytes
;
908 /* XXX if (gd->nbytes & 1) glyfLen++; */
910 assert(gd
->newID
== i
);
911 gid
[i
++] = gd
->glyphID
;
912 /* gd->glyphID = i++; */
914 /* printf("IDs: %d %d.\n", gd->glyphID, gd->newID); */
916 if (gd
->nbytes
>= 10) {
917 sal_Int16 z
= GetInt16(gd
->ptr
.get(), 2);
918 if (z
< xMin
) xMin
= z
;
920 z
= GetInt16(gd
->ptr
.get(), 4);
921 if (z
< yMin
) yMin
= z
;
923 z
= GetInt16(gd
->ptr
.get(), 6);
924 if (z
> xMax
) xMax
= z
;
926 z
= GetInt16(gd
->ptr
.get(), 8);
927 if (z
> yMax
) yMax
= z
;
930 if (!gd
->compflag
) { /* non-composite glyph */
931 if (gd
->npoints
> maxPoints
) maxPoints
= gd
->npoints
;
932 if (gd
->ncontours
> maxContours
) maxContours
= gd
->ncontours
;
933 } else { /* composite glyph */
934 if (gd
->npoints
> maxCompositePoints
) maxCompositePoints
= gd
->npoints
;
935 if (gd
->ncontours
> maxCompositeContours
) maxCompositeContours
= gd
->ncontours
;
940 indexToLocFormat
= (glyfLen
/ 2 > 0xFFFF) ? 1 : 0;
941 locaLen
= indexToLocFormat
? (nGlyphs
+ 1) << 2 : (nGlyphs
+ 1) << 1;
943 std::unique_ptr
<sal_uInt8
[]> glyfPtr
= ttmalloc(glyfLen
);
944 std::unique_ptr
<sal_uInt8
[]> locaPtr
= ttmalloc(locaLen
);
945 std::unique_ptr
<TTSimpleGlyphMetrics
[]> met(new TTSimpleGlyphMetrics
[nGlyphs
]);
950 for (const std::unique_ptr
<GlyphData
>& gd
: glyphlist
)
952 if (gd
->compflag
&& gd
->nbytes
> 10) { /* re-number all components */
953 sal_uInt16 flags
, index
;
954 sal_uInt8
*ptr
= gd
->ptr
.get() + 10;
955 size_t nRemaining
= gd
->nbytes
- 10;
959 SAL_WARN("vcl.fonts", "truncated font");
962 flags
= GetUInt16(ptr
, 0);
963 index
= GetUInt16(ptr
, 2);
965 /* XXX use the sorted array of old to new glyphID mapping and do a binary search */
967 for (j
= 0; j
< nGlyphs
; j
++) {
968 if (gid
[j
] == index
) {
972 /* printf("X: %d -> %d.\n", index, j); */
974 PutUInt16(static_cast<sal_uInt16
>(j
), ptr
, 2);
979 sal_uInt32 nAdvance
= 0;
980 if (flags
& ARG_1_AND_2_ARE_WORDS
) {
986 if (flags
& WE_HAVE_A_SCALE
) {
988 } else if (flags
& WE_HAVE_AN_X_AND_Y_SCALE
) {
990 } else if (flags
& WE_HAVE_A_TWO_BY_TWO
) {
994 if (nRemaining
< nAdvance
)
996 SAL_WARN("vcl.fonts", "truncated font");
1001 nRemaining
-= nAdvance
;
1003 } while (flags
& MORE_COMPONENTS
);
1006 if (gd
->nbytes
!= 0) {
1007 memcpy(p1
, gd
->ptr
.get(), gd
->nbytes
);
1009 if (indexToLocFormat
== 1) {
1010 PutUInt32(p1
- glyfPtr
.get(), p2
, 0);
1013 PutUInt16(static_cast<sal_uInt16
>((p1
- glyfPtr
.get()) >> 1), p2
, 0);
1018 /* fill the array of metrics */
1019 met
[i
].adv
= gd
->aw
;
1020 met
[i
].sb
= gd
->lsb
;
1026 if (indexToLocFormat
== 1) {
1027 PutUInt32(p1
- glyfPtr
.get(), p2
, 0);
1029 PutUInt16(static_cast<sal_uInt16
>((p1
- glyfPtr
.get()) >> 1), p2
, 0);
1032 glyf
->m_rawdata
= std::move(glyfPtr
);
1034 loca
.reset(new TrueTypeTableLoca());
1035 loca
->m_loca
->ptr
= std::move(locaPtr
);
1036 loca
->m_loca
->nbytes
= locaLen
;
1038 AddTable(std::move(loca
));
1040 head
= static_cast<TrueTypeTableHead
*>(FindTable(T_head
));
1041 sal_uInt8
* const pHeadData
= head
->m_head
.get();
1042 PutInt16(xMin
, pHeadData
, HEAD_xMin_offset
);
1043 PutInt16(yMin
, pHeadData
, HEAD_yMin_offset
);
1044 PutInt16(xMax
, pHeadData
, HEAD_xMax_offset
);
1045 PutInt16(yMax
, pHeadData
, HEAD_yMax_offset
);
1046 PutInt16(indexToLocFormat
, pHeadData
, HEAD_indexToLocFormat_offset
);
1048 maxp
= static_cast<TrueTypeTableMaxp
*>(FindTable(T_maxp
));
1050 sal_uInt8
* const pMaxpData
= maxp
->m_maxp
.get();
1051 PutUInt16(static_cast<sal_uInt16
>(nGlyphs
), pMaxpData
, MAXP_numGlyphs_offset
);
1052 PutUInt16(maxPoints
, pMaxpData
, MAXP_maxPoints_offset
);
1053 PutUInt16(maxContours
, pMaxpData
, MAXP_maxContours_offset
);
1054 PutUInt16(maxCompositePoints
, pMaxpData
, MAXP_maxCompositePoints_offset
);
1055 PutUInt16(maxCompositeContours
, pMaxpData
, MAXP_maxCompositeContours_offset
);
1058 * Generate an htmx table and update hhea table
1060 hhea
= static_cast<TrueTypeTableHhea
*>(FindTable(T_hhea
)); assert(hhea
!= nullptr);
1061 hheaPtr
= hhea
->m_hhea
.get();
1063 for (i
= nGlyphs
- 1; i
> 0; i
--) {
1064 if (met
[i
].adv
!= met
[i
-1].adv
) break;
1066 nlsb
= nGlyphs
- 1 - i
;
1068 hmtxSize
= (nGlyphs
- nlsb
) * 4 + nlsb
* 2;
1069 hmtxPtr
= ttmalloc(hmtxSize
);
1072 for (i
= 0; i
< nGlyphs
; i
++) {
1073 if (i
< nGlyphs
- nlsb
) {
1074 PutUInt16(met
[i
].adv
, p1
, 0);
1075 PutUInt16(met
[i
].sb
, p1
, 2);
1078 PutUInt16(met
[i
].sb
, p1
, 0);
1083 AddTable(std::make_unique
<TrueTypeTableGeneric
>(T_hmtx
, hmtxSize
, std::move(hmtxPtr
)));
1084 PutUInt16(static_cast<sal_uInt16
>(nGlyphs
- nlsb
), hheaPtr
, 34);
1088 * TrueTypeCreator destructor. It calls destructors for all TrueTypeTables added to it.
1090 TrueTypeCreator::~TrueTypeCreator()
1097 static sal_uInt32
mkTag(sal_uInt8 a
, sal_uInt8 b
, sal_uInt8 c
, sal_uInt8 d
) {
1098 return (a
<< 24) | (b
<< 16) | (c
<< 8) | d
;
1103 TrueTypeCreator
*ttcr
;
1104 sal_uInt8
*t1
, *t2
, *t3
, *t4
, *t5
, *t6
;
1106 TrueTypeCreatorNewEmpty(mkTag('t','r','u','e'), &ttcr
);
1108 t1
= malloc(1000); memset(t1
, 'a', 1000);
1109 t2
= malloc(2000); memset(t2
, 'b', 2000);
1110 t3
= malloc(3000); memset(t3
, 'c', 3000);
1111 t4
= malloc(4000); memset(t4
, 'd', 4000);
1112 t5
= malloc(5000); memset(t5
, 'e', 5000);
1113 t6
= malloc(6000); memset(t6
, 'f', 6000);
1115 AddTable(ttcr
, TrueTypeTableNew(T_maxp
, 1000, t1
));
1116 AddTable(ttcr
, TrueTypeTableNew(T_OS2
, 2000, t2
));
1117 AddTable(ttcr
, TrueTypeTableNew(T_cmap
, 3000, t3
));
1118 AddTable(ttcr
, TrueTypeTableNew(T_loca
, 4000, t4
));
1119 AddTable(ttcr
, TrueTypeTableNew(T_hhea
, 5000, t5
));
1120 AddTable(ttcr
, TrueTypeTableNew(T_glyf
, 6000, t6
));
1129 StreamToFile(ttcr
, "ttcrout.ttf");
1131 TrueTypeCreatorDispose(ttcr
);
1136 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */