LibreOffice Module vcl (master) 1
sft.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20/*
21 * Sun Font Tools
22 *
23 * Author: Alexander Gelfenbain
24 *
25 */
26
27#include <assert.h>
28
29#include <stdlib.h>
30#include <string.h>
31#include <fcntl.h>
32#ifdef UNX
33#include <sys/mman.h>
34#include <sys/stat.h>
35#include <unistd.h>
36#endif
37#include <sft.hxx>
38#include <impfontcharmap.hxx>
39#ifdef SYSTEM_LIBFIXMATH
40#include <libfixmath/fix16.hpp>
41#else
42#include <tools/fix16.hxx>
43#endif
44#include "ttcr.hxx"
45#include "xlat.hxx"
46#include <rtl/crc.h>
47#include <rtl/ustring.hxx>
48#include <rtl/ustrbuf.hxx>
49#include <sal/log.hxx>
50#include <o3tl/safeint.hxx>
51#include <osl/endian.h>
52#include <osl/thread.h>
53#include <unotools/tempfile.hxx>
54#include <fontsubset.hxx>
55#include <algorithm>
56#include <memory>
57
58namespace vcl
59{
60
61/*- module identification */
62
63const char * const modname = "SunTypeTools-TT";
64const char * const modver = "1.0";
65const char * const modextra = "gelf";
66
67/*- private functions, constants and data types */
68
69namespace {
70
71enum PathSegmentType {
72 PS_NOOP = 0,
73 PS_MOVETO = 1,
74 PS_LINETO = 2,
75 PS_CURVETO = 3,
76 PS_CLOSEPATH = 4
77};
78
79struct PSPathElement
80{
81 PathSegmentType type;
82 int x1, y1;
83 int x2, y2;
84 int x3, y3;
85
86 explicit PSPathElement( PathSegmentType i_eType ) : type( i_eType ),
87 x1( 0 ), y1( 0 ),
88 x2( 0 ), y2( 0 ),
89 x3( 0 ), y3( 0 )
90 {
91 }
92
93 PSPathElement() : type( PS_NOOP ),
94 x1( 0 ), y1( 0 ),
95 x2( 0 ), y2( 0 ),
96 x3( 0 ), y3( 0 )
97 {
98 }
99};
100
101/*- In horizontal writing mode right sidebearing is calculated using this formula
102 *- rsb = aw - (lsb + xMax - xMin) -*/
103struct TTGlyphMetrics {
104 sal_Int16 xMin;
105 sal_Int16 yMin;
106 sal_Int16 xMax;
107 sal_Int16 yMax;
108 sal_uInt16 aw; /*- Advance Width (horizontal writing mode) */
109 sal_Int16 lsb; /*- Left sidebearing (horizontal writing mode) */
110 sal_uInt16 ah; /*- advance height (vertical writing mode) */
111};
112
113constexpr int HFORMAT_LINELEN = 64;
114
115class HexFmt {
116public:
117 HexFmt(SvStream *outf) : o(outf) {}
118 ~HexFmt()
119 {
120 Flush();
121 }
122 bool Flush();
123 void OpenString();
124 void CloseString();
125 void BlockWrite(const void *ptr, sal_uInt32 size);
126
127private:
128 SvStream *o;
129 char buffer[HFORMAT_LINELEN];
130 size_t bufpos = 0;
131 int total = 0;
132};
133
134class GlyphOffsets {
135public:
136 GlyphOffsets(sal_uInt8 *sfntP, sal_uInt32 sfntLen);
137 sal_uInt32 nGlyphs; /* number of glyphs in the font + 1 */
138 std::unique_ptr<sal_uInt32[]> offs; /* array of nGlyphs offsets */
139};
140
141}
142
143/*- Data access methods for data stored in big-endian format */
144static sal_Int16 GetInt16(const sal_uInt8 *ptr, size_t offset)
145{
146 sal_Int16 t;
147 assert(ptr != nullptr);
148
149 t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
150
151 return t;
152}
153
154static sal_uInt16 GetUInt16(const sal_uInt8 *ptr, size_t offset)
155{
156 sal_uInt16 t;
157 assert(ptr != nullptr);
158
159 t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
160
161 return t;
162}
163
164static sal_Int32 GetInt32(const sal_uInt8 *ptr, size_t offset)
165{
166 sal_Int32 t;
167 assert(ptr != nullptr);
168
169 t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
170 (ptr+offset)[2] << 8 | (ptr+offset)[3];
171
172 return t;
173}
174
175static sal_uInt32 GetUInt32(const sal_uInt8 *ptr, size_t offset)
176{
177 sal_uInt32 t;
178 assert(ptr != nullptr);
179
180 t = (ptr+offset)[0] << 24 | (ptr+offset)[1] << 16 |
181 (ptr+offset)[2] << 8 | (ptr+offset)[3];
182
183 return t;
184}
185
187{
188 return fix16_mul(a, b);
189}
190
192{
193 return fix16_div(a, b);
194}
195
196/*- returns a * b / c -*/
197/* XXX provide a real implementation that preserves accuracy */
199{
200 F16Dot16 res = fixedMul(a, b);
201 return fixedDiv(res, c);
202}
203
204/*- Translate units from TT to PS (standard 1/1000) -*/
205static int XUnits(int unitsPerEm, int n)
206{
207 return (n * 1000) / unitsPerEm;
208}
209
210static char toHex(sal_uInt8 nIndex)
211{
212 /* Hex Formatter functions */
213 static const char HexChars[] = "0123456789ABCDEF";
214 assert(nIndex < SAL_N_ELEMENTS(HexChars));
215 return HexChars[nIndex];
216}
217
218bool HexFmt::Flush()
219{
220 bool bRet = true;
221 if (bufpos) {
222 size_t nWritten = o->WriteBytes(buffer, bufpos);
223 bRet = nWritten == bufpos;
224 bufpos = 0;
225 }
226 return bRet;
227}
228
229void HexFmt::OpenString()
230{
231 o->WriteOString("<\n");
232}
233
234void HexFmt::CloseString()
235{
236 Flush();
237 o->WriteOString("00\n>\n");
238}
239
240void HexFmt::BlockWrite(const void *ptr, sal_uInt32 size)
241{
242 if (total + size > 65534) {
243 Flush();
244 CloseString();
245 total = 0;
246 OpenString();
247 }
248
249 for (sal_uInt32 i = 0; i < size; ++i) {
250 sal_uInt8 Ch = static_cast<sal_uInt8 const *>(ptr)[i];
251 buffer[bufpos++] = toHex(Ch >> 4);
252 buffer[bufpos++] = toHex(Ch & 0xF);
253 if (bufpos == HFORMAT_LINELEN) {
254 Flush();
255 o->WriteOString("\n");
256 }
257
258 }
259 total += size;
260}
261
262/* Outline Extraction functions */
263
264/* fills the aw and lsb entries of the TTGlyphMetrics structure from hmtx table -*/
265static void GetMetrics(AbstractTrueTypeFont const *ttf, sal_uInt32 glyphID, TTGlyphMetrics *metrics)
266{
267 sal_uInt32 nSize;
268 const sal_uInt8* table = ttf->table(O_hmtx, nSize);
269
270 metrics->aw = metrics->lsb = metrics->ah = 0;
271 if (!table || !ttf->horzMetricCount())
272 return;
273
274 if (glyphID < ttf->horzMetricCount())
275 {
276 metrics->aw = GetUInt16(table, 4 * glyphID);
277 metrics->lsb = GetInt16(table, 4 * glyphID + 2);
278 }
279 else
280 {
281 metrics->aw = GetUInt16(table, 4 * (ttf->horzMetricCount() - 1));
282 metrics->lsb = GetInt16(table + ttf->horzMetricCount() * 4, (glyphID - ttf->horzMetricCount()) * 2);
283 }
284
285 table = ttf->table(O_vmtx, nSize);
286 if (!table || !ttf->vertMetricCount())
287 return;
288
289 if (glyphID < ttf->vertMetricCount())
290 metrics->ah = GetUInt16(table, 4 * glyphID);
291 else
292 metrics->ah = GetUInt16(table, 4 * (ttf->vertMetricCount() - 1));
293}
294
295static int GetTTGlyphOutline(AbstractTrueTypeFont *, sal_uInt32 , std::vector<ControlPoint>&, TTGlyphMetrics *, std::vector< sal_uInt32 >* );
296
297/* returns the number of control points, allocates the pointArray */
298static int GetSimpleTTOutline(AbstractTrueTypeFont const *ttf, sal_uInt32 glyphID,
299 std::vector<ControlPoint>& pointArray, TTGlyphMetrics *metrics)
300{
301 sal_uInt32 nTableSize;
302 const sal_uInt8* table = ttf->table(O_glyf, nTableSize);
303 sal_uInt8 n;
304 int i, j, z;
305
306 pointArray.clear();
307
308 if (glyphID >= ttf->glyphCount())
309 return 0;
310
311 sal_uInt32 nGlyphOffset = ttf->glyphOffset(glyphID);
312 if (nGlyphOffset > nTableSize)
313 return 0;
314
315 const sal_uInt8* ptr = table + nGlyphOffset;
316 const sal_uInt32 nMaxGlyphSize = nTableSize - nGlyphOffset;
317 constexpr sal_uInt32 nContourOffset = 10;
318 if (nMaxGlyphSize < nContourOffset)
319 return 0;
320
321 const sal_Int16 numberOfContours = GetInt16(ptr, GLYF_numberOfContours_offset);
322 if( numberOfContours <= 0 ) /*- glyph is not simple */
323 return 0;
324
325 const sal_Int32 nMaxContours = (nMaxGlyphSize - nContourOffset)/2;
326 if (numberOfContours > nMaxContours)
327 return 0;
328
329 if (metrics) { /*- GetCompoundTTOutline() calls this function with NULL metrics -*/
330 metrics->xMin = GetInt16(ptr, GLYF_xMin_offset);
331 metrics->yMin = GetInt16(ptr, GLYF_yMin_offset);
332 metrics->xMax = GetInt16(ptr, GLYF_xMax_offset);
333 metrics->yMax = GetInt16(ptr, GLYF_yMax_offset);
334 GetMetrics(ttf, glyphID, metrics);
335 }
336
337 /* determine the last point and be extra safe about it. But probably this code is not needed */
338 sal_uInt16 lastPoint=0;
339 for (i=0; i<numberOfContours; i++)
340 {
341 const sal_uInt16 t = GetUInt16(ptr, nContourOffset + i * 2);
342 if (t > lastPoint)
343 lastPoint = t;
344 }
345
346 sal_uInt32 nInstLenOffset = nContourOffset + numberOfContours * 2;
347 if (nInstLenOffset + 2 > nMaxGlyphSize)
348 return 0;
349 sal_uInt16 instLen = GetUInt16(ptr, nInstLenOffset);
350
351 sal_uInt32 nOffset = nContourOffset + 2 * numberOfContours + 2 + instLen;
352 if (nOffset > nMaxGlyphSize)
353 return 0;
354 const sal_uInt8* p = ptr + nOffset;
355
356 sal_uInt32 nBytesRemaining = nMaxGlyphSize - nOffset;
357 const sal_uInt32 palen = lastPoint+1;
358
359 //at a minimum its one byte per entry
360 if (palen > nBytesRemaining || lastPoint > nBytesRemaining-1)
361 {
362 SAL_WARN("vcl.fonts", "Font " << OUString::createFromAscii(ttf->fileName()) <<
363 "claimed a palen of "
364 << palen << " but max bytes remaining is " << nBytesRemaining);
365 return 0;
366 }
367
368 std::vector<ControlPoint> pa(palen);
369
370 i = 0;
371 while (i <= lastPoint) {
372 if (!nBytesRemaining)
373 {
374 SAL_WARN("vcl.fonts", "short read");
375 break;
376 }
377 sal_uInt8 flag = *p++;
378 --nBytesRemaining;
379 pa[i++].flags = static_cast<sal_uInt32>(flag);
380 if (flag & 8) { /*- repeat flag */
381 if (!nBytesRemaining)
382 {
383 SAL_WARN("vcl.fonts", "short read");
384 break;
385 }
386 n = *p++;
387 --nBytesRemaining;
388 // coverity[tainted_data : FALSE] - i > lastPoint extra checks the n loop bound
389 for (j=0; j<n; j++) {
390 if (i > lastPoint) { /*- if the font is really broken */
391 return 0;
392 }
393 pa[i++].flags = flag;
394 }
395 }
396 }
397
398 /*- Process the X coordinate */
399 z = 0;
400 for (i = 0; i <= lastPoint; i++) {
401 if (pa[i].flags & 0x02) {
402 if (!nBytesRemaining)
403 {
404 SAL_WARN("vcl.fonts", "short read");
405 break;
406 }
407 if (pa[i].flags & 0x10) {
408 z += static_cast<int>(*p++);
409 } else {
410 z -= static_cast<int>(*p++);
411 }
412 --nBytesRemaining;
413 } else if ( !(pa[i].flags & 0x10)) {
414 if (nBytesRemaining < 2)
415 {
416 SAL_WARN("vcl.fonts", "short read");
417 break;
418 }
419 z += GetInt16(p, 0);
420 p += 2;
421 nBytesRemaining -= 2;
422 }
423 pa[i].x = static_cast<sal_Int16>(z);
424 }
425
426 /*- Process the Y coordinate */
427 z = 0;
428 for (i = 0; i <= lastPoint; i++) {
429 if (pa[i].flags & 0x04) {
430 if (!nBytesRemaining)
431 {
432 SAL_WARN("vcl.fonts", "short read");
433 break;
434 }
435 if (pa[i].flags & 0x20) {
436 z += *p++;
437 } else {
438 z -= *p++;
439 }
440 --nBytesRemaining;
441 } else if ( !(pa[i].flags & 0x20)) {
442 if (nBytesRemaining < 2)
443 {
444 SAL_WARN("vcl.fonts", "short read");
445 break;
446 }
447 z += GetInt16(p, 0);
448 p += 2;
449 nBytesRemaining -= 2;
450 }
451 pa[i].y = static_cast<sal_Int16>(z);
452 }
453
454 for (i=0; i<numberOfContours; i++) {
455 sal_uInt16 offset = GetUInt16(ptr, 10 + i * 2);
456 SAL_WARN_IF(offset >= palen, "vcl.fonts", "Font " << OUString::createFromAscii(ttf->fileName()) <<
457 " contour " << i << " claimed an illegal offset of "
458 << offset << " but max offset is " << palen-1);
459 if (offset >= palen)
460 continue;
461 pa[offset].flags |= 0x00008000; /*- set the end contour flag */
462 }
463
464 pointArray = std::move(pa);
465 return lastPoint + 1;
466}
467
468static F16Dot16 fromF2Dot14(sal_Int16 n)
469{
470 // Avoid undefined shift of negative values prior to C++2a:
471 return sal_uInt32(n) << 2;
472}
473
474static int GetCompoundTTOutline(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector<ControlPoint>& pointArray,
475 TTGlyphMetrics *metrics, std::vector<sal_uInt32>& glyphlist)
476{
477 sal_uInt16 flags, index;
478 sal_Int16 e, f;
479 sal_uInt32 nTableSize;
480 const sal_uInt8* table = ttf->table(O_glyf, nTableSize);
481 std::vector<ControlPoint> myPoints;
482 std::vector<ControlPoint> nextComponent;
483 int i, np;
484 F16Dot16 a = 0x10000, b = 0, c = 0, d = 0x10000, m, n, abs1, abs2, abs3;
485
486 pointArray.clear();
487
488 if (glyphID >= ttf->glyphCount())
489 return 0;
490
491 sal_uInt32 nGlyphOffset = ttf->glyphOffset(glyphID);
492 if (nGlyphOffset > nTableSize)
493 return 0;
494
495 const sal_uInt8* ptr = table + nGlyphOffset;
496 sal_uInt32 nAvailableBytes = nTableSize - nGlyphOffset;
497
498 if (GLYF_numberOfContours_offset + 2 > nAvailableBytes)
499 return 0;
500
501 if (GetInt16(ptr, GLYF_numberOfContours_offset) != -1) /* number of contours - glyph is not compound */
502 return 0;
503
504 if (metrics) {
505 metrics->xMin = GetInt16(ptr, GLYF_xMin_offset);
506 metrics->yMin = GetInt16(ptr, GLYF_yMin_offset);
507 metrics->xMax = GetInt16(ptr, GLYF_xMax_offset);
508 metrics->yMax = GetInt16(ptr, GLYF_yMax_offset);
509 GetMetrics(ttf, glyphID, metrics);
510 }
511
512 if (nAvailableBytes < 10)
513 {
514 SAL_WARN("vcl.fonts", "short read");
515 return 0;
516 }
517
518 ptr += 10;
519 nAvailableBytes -= 10;
520
521 do {
522
523 if (nAvailableBytes < 4)
524 {
525 SAL_WARN("vcl.fonts", "short read");
526 return 0;
527 }
528 flags = GetUInt16(ptr, 0);
529 /* printf("flags: 0x%X\n", flags); */
530 index = GetUInt16(ptr, 2);
531 ptr += 4;
532 nAvailableBytes -= 4;
533
534 if( std::find( glyphlist.begin(), glyphlist.end(), index ) != glyphlist.end() )
535 {
536 SAL_WARN("vcl.fonts", "Endless loop found in a compound glyph.");
537
538#if OSL_DEBUG_LEVEL > 1
539 std::ostringstream oss;
540 oss << index << " -> [";
541 for( const auto& rGlyph : glyphlist )
542 {
543 oss << (int) rGlyph << " ";
544 }
545 oss << "]";
546 SAL_INFO("vcl.fonts", oss.str());
547
548#endif
549 return 0;
550 }
551
552 glyphlist.push_back( index );
553
554 np = GetTTGlyphOutline(ttf, index, nextComponent, nullptr, &glyphlist);
555
556 if( ! glyphlist.empty() )
557 glyphlist.pop_back();
558
559 if (np == 0)
560 {
561 /* XXX that probably indicates a corrupted font */
562 SAL_WARN("vcl.fonts", "An empty compound!");
563 /* assert(!"An empty compound"); */
564 return 0;
565 }
566
567 if ((flags & USE_MY_METRICS) && metrics)
568 GetMetrics(ttf, index, metrics);
569
570 if (flags & ARG_1_AND_2_ARE_WORDS) {
571 if (nAvailableBytes < 4)
572 {
573 SAL_WARN("vcl.fonts", "short read");
574 return 0;
575 }
576 e = GetInt16(ptr, 0);
577 f = GetInt16(ptr, 2);
578 /* printf("ARG_1_AND_2_ARE_WORDS: %d %d\n", e & 0xFFFF, f & 0xFFFF); */
579 ptr += 4;
580 nAvailableBytes -= 4;
581 } else {
582 if (nAvailableBytes < 2)
583 {
584 SAL_WARN("vcl.fonts", "short read");
585 return 0;
586 }
587 if (flags & ARGS_ARE_XY_VALUES) { /* args are signed */
588 e = static_cast<sal_Int8>(*ptr++);
589 f = static_cast<sal_Int8>(*ptr++);
590 /* printf("ARGS_ARE_XY_VALUES: %d %d\n", e & 0xFF, f & 0xFF); */
591 } else { /* args are unsigned */
592 /* printf("!ARGS_ARE_XY_VALUES\n"); */
593 e = *ptr++;
594 f = *ptr++;
595 }
596 nAvailableBytes -= 2;
597 }
598
599 a = d = 0x10000;
600 b = c = 0;
601
602 if (flags & WE_HAVE_A_SCALE) {
603 if (nAvailableBytes < 2)
604 {
605 SAL_WARN("vcl.fonts", "short read");
606 return 0;
607 }
608 a = fromF2Dot14(GetInt16(ptr, 0));
609 d = a;
610 ptr += 2;
611 nAvailableBytes -= 2;
612 } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
613 if (nAvailableBytes < 4)
614 {
615 SAL_WARN("vcl.fonts", "short read");
616 return 0;
617 }
618 a = fromF2Dot14(GetInt16(ptr, 0));
619 d = fromF2Dot14(GetInt16(ptr, 2));
620 ptr += 4;
621 nAvailableBytes -= 4;
622 } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
623 if (nAvailableBytes < 8)
624 {
625 SAL_WARN("vcl.fonts", "short read");
626 return 0;
627 }
628 a = fromF2Dot14(GetInt16(ptr, 0));
629 b = fromF2Dot14(GetInt16(ptr, 2));
630 c = fromF2Dot14(GetInt16(ptr, 4));
631 d = fromF2Dot14(GetInt16(ptr, 6));
632 ptr += 8;
633 nAvailableBytes -= 8;
634 }
635
636 abs1 = (a < 0) ? -a : a;
637 abs2 = (b < 0) ? -b : b;
638 m = std::max(abs1, abs2);
639 abs3 = abs1 - abs2;
640 if (abs3 < 0) abs3 = -abs3;
641 if (abs3 <= 33) m *= 2;
642
643 abs1 = (c < 0) ? -c : c;
644 abs2 = (d < 0) ? -d : d;
645 n = std::max(abs1, abs2);
646 abs3 = abs1 - abs2;
647 if (abs3 < 0) abs3 = -abs3;
648 if (abs3 <= 33) n *= 2;
649
650 SAL_WARN_IF(np && (!m || !n), "vcl.fonts", "Parsing error in " << OUString::createFromAscii(ttf->fileName()) <<
651 ": divide by zero");
652
653 if (m != 0 && n != 0) {
654 for (i=0; i<np; i++) {
655 F16Dot16 t;
656 ControlPoint cp;
657 cp.flags = nextComponent[i].flags;
658 const sal_uInt16 x = nextComponent[i].x;
659 const sal_uInt16 y = nextComponent[i].y;
660 t = o3tl::saturating_add(o3tl::saturating_add(fixedMulDiv(a, x << 16, m), fixedMulDiv(c, y << 16, m)), sal_Int32(sal_uInt16(e) << 16));
661 cp.x = static_cast<sal_Int16>(fixedMul(t, m) >> 16);
662 t = o3tl::saturating_add(o3tl::saturating_add(fixedMulDiv(b, x << 16, n), fixedMulDiv(d, y << 16, n)), sal_Int32(sal_uInt16(f) << 16));
663 cp.y = static_cast<sal_Int16>(fixedMul(t, n) >> 16);
664
665 myPoints.push_back( cp );
666 }
667 }
668
669 if (myPoints.size() > SAL_MAX_UINT16) {
670 SAL_WARN("vcl.fonts", "number of points has to be limited to max value GlyphData::npoints can contain, abandon effort");
671 myPoints.clear();
672 break;
673 }
674
675 } while (flags & MORE_COMPONENTS);
676
677 // #i123417# some fonts like IFAOGrec have no outline points in some compound glyphs
678 // so this unlikely but possible scenario should be handled gracefully
679 if( myPoints.empty() )
680 return 0;
681
682 np = myPoints.size();
683
684 pointArray = std::move(myPoints);
685
686 return np;
687}
688
689/* NOTE: GetTTGlyphOutline() returns -1 if the glyphID is incorrect,
690 * but Get{Simple|Compound}GlyphOutline returns 0 in such a case.
691 *
692 * NOTE: glyphlist is the stack of glyphs traversed while constructing
693 * a composite glyph. This is a safeguard against endless recursion
694 * in corrupted fonts.
695 */
696static int GetTTGlyphOutline(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector<ControlPoint>& pointArray, TTGlyphMetrics *metrics, std::vector< sal_uInt32 >* glyphlist)
697{
698 sal_uInt32 glyflength;
699 const sal_uInt8 *table = ttf->table(O_glyf, glyflength);
700 sal_Int16 numberOfContours;
701 int res;
702 pointArray.clear();
703
704 if (metrics)
705 memset(metrics, 0, sizeof(TTGlyphMetrics));
706
707 if (glyphID >= ttf->glyphCount())
708 return -1;
709
710 sal_uInt32 nNextOffset = ttf->glyphOffset(glyphID + 1);
711 if (nNextOffset > glyflength)
712 return -1;
713
714 sal_uInt32 nOffset = ttf->glyphOffset(glyphID);
715 if (nOffset > nNextOffset)
716 return -1;
717
718 int length = nNextOffset - nOffset;
719 if (length == 0) { /*- empty glyphs still have hmtx and vmtx metrics values */
720 if (metrics) GetMetrics(ttf, glyphID, metrics);
721 return 0;
722 }
723
724 const sal_uInt8* ptr = table + nOffset;
725 const sal_uInt32 nMaxGlyphSize = glyflength - nOffset;
726
727 if (nMaxGlyphSize < 2)
728 return -1;
729
730 numberOfContours = GetInt16(ptr, 0);
731
732 if (numberOfContours >= 0)
733 {
734 res = GetSimpleTTOutline(ttf, glyphID, pointArray, metrics);
735 }
736 else
737 {
738 std::vector< sal_uInt32 > aPrivList { glyphID };
739 res = GetCompoundTTOutline(ttf, glyphID, pointArray, metrics, glyphlist ? *glyphlist : aPrivList );
740 }
741
742 return res;
743}
744
745/*- returns the number of items in the path -*/
746
747static int BSplineToPSPath(ControlPoint const *srcA, int srcCount, std::unique_ptr<PSPathElement[]>& path)
748{
749 std::vector< PSPathElement > aPathList;
750 int nPathCount = 0;
751 PSPathElement p( PS_NOOP );
752
753 int x0 = 0, y0 = 0, x1 = 0, y1 = 0, x2, y2, curx, cury;
754 bool lastOff = false; /*- last point was off-contour */
755 int scflag = 1; /*- start contour flag */
756 bool ecflag = false; /*- end contour flag */
757 int cp = 0; /*- current point */
758 int StartContour = 0, EndContour = 1;
759
760 path.reset();
761
762 /* if (srcCount > 0) for(;;) */
763 while (srcCount > 0) { /*- srcCount does not get changed inside the loop. */
764 if (scflag) {
765 int l = cp;
766 StartContour = cp;
767 while (!(srcA[l].flags & 0x8000)) l++;
768 EndContour = l;
769 if (StartContour == EndContour) {
770 if (cp + 1 < srcCount) {
771 cp++;
772 continue;
773 } else {
774 break;
775 }
776 }
777 p = PSPathElement(PS_MOVETO);
778 if (!(srcA[cp].flags & 1)) {
779 if (!(srcA[EndContour].flags & 1)) {
780 p.x1 = x0 = (srcA[cp].x + srcA[EndContour].x + 1) / 2;
781 p.y1 = y0 = (srcA[cp].y + srcA[EndContour].y + 1) / 2;
782 } else {
783 p.x1 = x0 = srcA[EndContour].x;
784 p.y1 = y0 = srcA[EndContour].y;
785 }
786 } else {
787 p.x1 = x0 = srcA[cp].x;
788 p.y1 = y0 = srcA[cp].y;
789 cp++;
790 }
791 aPathList.push_back( p );
792 lastOff = false;
793 scflag = 0;
794 }
795
796 curx = srcA[cp].x;
797 cury = srcA[cp].y;
798
799 if (srcA[cp].flags & 1)
800 {
801 if (lastOff)
802 {
803 p = PSPathElement(PS_CURVETO);
804 p.x1 = x0 + (2 * (x1 - x0) + 1) / 3;
805 p.y1 = y0 + (2 * (y1 - y0) + 1) / 3;
806 p.x2 = x1 + (curx - x1 + 1) / 3;
807 p.y2 = y1 + (cury - y1 + 1) / 3;
808 p.x3 = curx;
809 p.y3 = cury;
810 aPathList.push_back( p );
811 }
812 else
813 {
814 if (x0 != curx || y0 != cury)
815 { /* eliminate empty lines */
816 p = PSPathElement(PS_LINETO);
817 p.x1 = curx;
818 p.y1 = cury;
819 aPathList.push_back( p );
820 }
821 }
822 x0 = curx; y0 = cury; lastOff = false;
823 }
824 else
825 {
826 if (lastOff)
827 {
828 x2 = (x1 + curx + 1) / 2;
829 y2 = (y1 + cury + 1) / 2;
830 p = PSPathElement(PS_CURVETO);
831 p.x1 = x0 + (2 * (x1 - x0) + 1) / 3;
832 p.y1 = y0 + (2 * (y1 - y0) + 1) / 3;
833 p.x2 = x1 + (x2 - x1 + 1) / 3;
834 p.y2 = y1 + (y2 - y1 + 1) / 3;
835 p.x3 = x2;
836 p.y3 = y2;
837 aPathList.push_back( p );
838 x0 = x2; y0 = y2;
839 x1 = curx; y1 = cury;
840 } else {
841 x1 = curx; y1 = cury;
842 }
843 lastOff = true;
844 }
845
846 if (ecflag) {
847 aPathList.emplace_back(PS_CLOSEPATH );
848 scflag = 1;
849 ecflag = false;
850 cp = EndContour + 1;
851 if (cp >= srcCount) break;
852 continue;
853 }
854
855 if (cp == EndContour) {
856 cp = StartContour;
857 ecflag = true;
858 } else {
859 cp++;
860 }
861 }
862
863 if( (nPathCount = static_cast<int>(aPathList.size())) > 0)
864 {
865 path.reset(new PSPathElement[nPathCount]);
866 memcpy( path.get(), aPathList.data(), nPathCount * sizeof(PSPathElement) );
867 }
868
869 return nPathCount;
870}
871
872/*- Extracts a string from the name table and allocates memory for it -*/
873
874static OString nameExtract( const sal_uInt8* name, int nTableSize, int n, int dbFlag, OUString* ucs2result )
875{
876 OStringBuffer res;
877 const sal_uInt8* ptr = name + GetUInt16(name, 4) + GetUInt16(name + 6, 12 * n + 10);
878 int len = GetUInt16(name+6, 12 * n + 8);
879
880 // sanity check
881 const sal_uInt8* end_table = name+nTableSize;
882 const int available_space = ptr > end_table ? 0 : (end_table - ptr);
883 if( (len <= 0) || len > available_space)
884 {
885 if( ucs2result )
886 ucs2result->clear();
887 return OString();
888 }
889
890 if( ucs2result )
891 ucs2result->clear();
892 if (dbFlag) {
893 res.setLength(len/2);
894 for (int i = 0; i < len/2; i++)
895 {
896 res[i] = *(ptr + i * 2 + 1);
897 SAL_WARN_IF(res[i] == 0, "vcl.fonts", "font name is bogus");
898 }
899 if( ucs2result )
900 {
901 OUStringBuffer buf(len/2);
902 buf.setLength(len/2);
903 for (int i = 0; i < len/2; i++ )
904 {
905 buf[i] = GetUInt16( ptr, 2*i );
906 SAL_WARN_IF(buf[i] == 0, "vcl.fonts", "font name is bogus");
907 }
908 *ucs2result = buf.makeStringAndClear();
909 }
910 } else {
911 res.setLength(len);
912 memcpy(static_cast<void*>(const_cast<char*>(res.getStr())), ptr, len);
913 }
914
915 return res.makeStringAndClear();
916}
917
918static int findname( const sal_uInt8 *name, sal_uInt16 n, sal_uInt16 platformID,
919 sal_uInt16 encodingID, sal_uInt16 languageID, sal_uInt16 nameID )
920{
921 if (n == 0) return -1;
922
923 int l = 0, r = n-1;
924 sal_uInt32 t1, t2;
925 sal_uInt32 m1, m2;
926
927 m1 = (platformID << 16) | encodingID;
928 m2 = (languageID << 16) | nameID;
929
930 do {
931 const int i = (l + r) >> 1;
932 t1 = GetUInt32(name + 6, i * 12 + 0);
933 t2 = GetUInt32(name + 6, i * 12 + 4);
934
935 if (! ((m1 < t1) || ((m1 == t1) && (m2 < t2)))) l = i + 1;
936 if (! ((m1 > t1) || ((m1 == t1) && (m2 > t2)))) r = i - 1;
937 } while (l <= r);
938
939 if (l - r == 2) {
940 return l - 1;
941 }
942
943 return -1;
944}
945
946/* XXX marlett.ttf uses (3, 0, 1033) instead of (3, 1, 1033) and does not have any Apple tables.
947 * Fix: if (3, 1, 1033) is not found - need to check for (3, 0, 1033)
948 *
949 * /d/fonts/ttzh_tw/Big5/Hanyi/ma6b5p uses (1, 0, 19) for English strings, instead of (1, 0, 0)
950 * and does not have (3, 1, 1033)
951 * Fix: if (1, 0, 0) and (3, 1, 1033) are not found need to look for (1, 0, *) - that will
952 * require a change in algorithm
953 *
954 * /d/fonts/fdltest/Korean/h2drrm has unsorted names and an unknown (to me) Mac LanguageID,
955 * but (1, 0, 1042) strings usable
956 * Fix: change algorithm, and use (1, 0, *) if both standard Mac and MS strings are not found
957 */
958
960{
961 sal_uInt32 nTableSize;
962 const sal_uInt8* table = t->table(O_name, nTableSize);
963
964 if (nTableSize < 6)
965 {
966#if OSL_DEBUG_LEVEL > 1
967 SAL_WARN("vcl.fonts", "O_name table too small.");
968#endif
969 return;
970 }
971
972 sal_uInt16 n = GetUInt16(table, 2);
973
974 /* simple sanity check for name table entry count */
975 const size_t nMinRecordSize = 12;
976 const size_t nSpaceAvailable = nTableSize - 6;
977 const size_t nMaxRecords = nSpaceAvailable/nMinRecordSize;
978 if (n >= nMaxRecords)
979 n = 0;
980
981 int i, r;
982 bool bPSNameOK = true;
983
984 /* PostScript name: preferred Microsoft */
985 t->psname.clear();
986 if ((r = findname(table, n, 3, 1, 0x0409, 6)) != -1)
987 t->psname = nameExtract(table, nTableSize, r, 1, nullptr);
988 if ( t->psname.isEmpty() && (r = findname(table, n, 1, 0, 0, 6)) != -1)
989 t->psname = nameExtract(table, nTableSize, r, 0, nullptr);
990 if ( t->psname.isEmpty() && (r = findname(table, n, 3, 0, 0x0409, 6)) != -1)
991 {
992 // some symbol fonts like Marlett have a 3,0 name!
993 t->psname = nameExtract(table, nTableSize, r, 1, nullptr);
994 }
995 // for embedded font in Ghostscript PDFs
996 if ( t->psname.isEmpty() && (r = findname(table, n, 2, 2, 0, 6)) != -1)
997 {
998 t->psname = nameExtract(table, nTableSize, r, 0, nullptr);
999 }
1000 if ( t->psname.isEmpty() )
1001 {
1002 if (!t->fileName().empty())
1003 {
1004 const char* pReverse = t->fileName().data() + t->fileName().length();
1005 /* take only last token of filename */
1006 while (pReverse != t->fileName().data() && *pReverse != '/') pReverse--;
1007 if(*pReverse == '/') pReverse++;
1008 int nReverseLen = strlen(pReverse);
1009 for (i=nReverseLen - 1; i > 0; i--)
1010 {
1011 /*- Remove the suffix -*/
1012 if (*(pReverse + i) == '.' ) {
1013 nReverseLen = i;
1014 break;
1015 }
1016 }
1017 t->psname = OString(std::string_view(pReverse, nReverseLen));
1018 }
1019 else
1020 t->psname = "Unknown";
1021 }
1022
1023 /* Font family and subfamily names: preferred Apple */
1024 t->family.clear();
1025 if ((r = findname(table, n, 0, 0, 0, 1)) != -1)
1026 t->family = nameExtract(table, nTableSize, r, 1, &t->ufamily);
1027 if ( t->family.isEmpty() && (r = findname(table, n, 3, 1, 0x0409, 1)) != -1)
1028 t->family = nameExtract(table, nTableSize, r, 1, &t->ufamily);
1029 if ( t->family.isEmpty() && (r = findname(table, n, 1, 0, 0, 1)) != -1)
1030 t->family = nameExtract(table, nTableSize, r, 0, nullptr);
1031 if ( t->family.isEmpty() && (r = findname(table, n, 3, 1, 0x0411, 1)) != -1)
1032 t->family = nameExtract(table, nTableSize, r, 1, &t->ufamily);
1033 if ( t->family.isEmpty() && (r = findname(table, n, 3, 0, 0x0409, 1)) != -1)
1034 t->family = nameExtract(table, nTableSize, r, 1, &t->ufamily);
1035 if ( t->family.isEmpty() )
1036 t->family = t->psname;
1037
1038 t->subfamily.clear();
1039 t->usubfamily.clear();
1040 if ((r = findname(table, n, 1, 0, 0, 2)) != -1)
1041 t->subfamily = nameExtract(table, nTableSize, r, 0, &t->usubfamily);
1042 if ( t->subfamily.isEmpty() && (r = findname(table, n, 3, 1, 0x0409, 2)) != -1)
1043 t->subfamily = nameExtract(table, nTableSize, r, 1, &t->usubfamily);
1044
1045 /* #i60349# sanity check psname
1046 * psname practically has to be 7bit ASCII and should not contain spaces
1047 * there is a class of broken fonts which do not fulfill that at all, so let's try
1048 * if the family name is 7bit ASCII and take it instead if so
1049 */
1050 /* check psname */
1051 for( i = 0; i < t->psname.getLength() && bPSNameOK; i++ )
1052 if( t->psname[ i ] < 33 || (t->psname[ i ] & 0x80) )
1053 bPSNameOK = false;
1054 if( bPSNameOK )
1055 return;
1056
1057 /* check if family is a suitable replacement */
1058 if( t->ufamily.isEmpty() && t->family.isEmpty() )
1059 return;
1060
1061 bool bReplace = true;
1062
1063 for( i = 0; i < t->ufamily.getLength() && bReplace; i++ )
1064 if( t->ufamily[ i ] < 33 || t->ufamily[ i ] > 127 )
1065 bReplace = false;
1066 if( bReplace )
1067 {
1068 t->psname = t->family;
1069 }
1070}
1071
1072/*- Public functions */
1073
1074int CountTTCFonts(const char* fname)
1075{
1076 FILE* fd;
1077#ifdef LINUX
1078 int nFD;
1079 int n;
1080 if (sscanf(fname, "/:FD:/%d%n", &nFD, &n) == 1 && fname[n] == '\0')
1081 {
1082 lseek(nFD, 0, SEEK_SET);
1083 int nDupFd = dup(nFD);
1084 fd = nDupFd != -1 ? fdopen(nDupFd, "rb") : nullptr;
1085 }
1086 else
1087#endif
1088 fd = fopen(fname, "rb");
1089
1090 if (!fd)
1091 return 0;
1092
1093 int nFonts = 0;
1094 sal_uInt8 buffer[12];
1095 if (fread(buffer, 1, 12, fd) == 12) {
1096 if(GetUInt32(buffer, 0) == T_ttcf )
1097 nFonts = GetUInt32(buffer, 8);
1098 }
1099
1100 if (nFonts > 0)
1101 {
1102 fseek(fd, 0, SEEK_END);
1103 sal_uInt64 fileSize = ftell(fd);
1104
1105 //Feel free to calc the exact max possible number of fonts a file
1106 //could contain given its physical size. But this will clamp it to
1107 //a sane starting point
1108 //http://processingjs.nihongoresources.com/the_smallest_font/
1109 //https://github.com/grzegorzrolek/null-ttf
1110 const int nMaxFontsPossible = fileSize / 528;
1111 if (nFonts > nMaxFontsPossible)
1112 {
1113 SAL_WARN("vcl.fonts", "font file " << fname <<" claims to have "
1114 << nFonts << " fonts, but only "
1115 << nMaxFontsPossible << " are possible");
1116 nFonts = nMaxFontsPossible;
1117 }
1118 }
1119
1120 fclose(fd);
1121
1122 return nFonts;
1123}
1124
1125#if !defined(_WIN32)
1126SFErrCodes OpenTTFontFile(const char* fname, sal_uInt32 facenum, TrueTypeFont** ttf,
1127 const FontCharMapRef xCharMap)
1128{
1129 SFErrCodes ret;
1130 int fd = -1;
1131 struct stat st;
1132
1133 if (!fname || !*fname) return SFErrCodes::BadFile;
1134
1135 *ttf = new TrueTypeFont(fname, xCharMap);
1136 if( ! *ttf )
1137 return SFErrCodes::Memory;
1138
1139 if( (*ttf)->fileName().empty() )
1140 {
1141 ret = SFErrCodes::Memory;
1142 goto cleanup;
1143 }
1144
1145 int nFD;
1146 int n;
1147 if (sscanf(fname, "/:FD:/%d%n", &nFD, &n) == 1 && fname[n] == '\0')
1148 {
1149 lseek(nFD, 0, SEEK_SET);
1150 fd = dup(nFD);
1151 }
1152 else
1153 fd = open(fname, O_RDONLY);
1154
1155 if (fd == -1) {
1156 ret = SFErrCodes::BadFile;
1157 goto cleanup;
1158 }
1159
1160 if (fstat(fd, &st) == -1) {
1161 ret = SFErrCodes::FileIo;
1162 goto cleanup;
1163 }
1164
1165 (*ttf)->fsize = st.st_size;
1166
1167 /* On Mac OS, most likely will happen if a Mac user renames a font file
1168 * to be .ttf when it's really a Mac resource-based font.
1169 * Size will be 0, but fonts smaller than 4 bytes would be broken anyway.
1170 */
1171 if ((*ttf)->fsize == 0) {
1172 ret = SFErrCodes::BadFile;
1173 goto cleanup;
1174 }
1175
1176 if (((*ttf)->ptr = static_cast<sal_uInt8 *>(mmap(nullptr, (*ttf)->fsize, PROT_READ, MAP_SHARED, fd, 0))) == MAP_FAILED) {
1177 ret = SFErrCodes::Memory;
1178 goto cleanup;
1179 }
1180
1181 ret = (*ttf)->open(facenum);
1182
1183cleanup:
1184 if (fd != -1) close(fd);
1185 if (ret != SFErrCodes::Ok)
1186 {
1187 delete *ttf;
1188 *ttf = nullptr;
1189 }
1190 return ret;
1191}
1192#endif
1193
1194SFErrCodes OpenTTFontBuffer(const void* pBuffer, sal_uInt32 nLen, sal_uInt32 facenum, TrueTypeFont** ttf,
1195 const FontCharMapRef xCharMap)
1196{
1197 *ttf = new TrueTypeFont(nullptr, xCharMap);
1198 if( *ttf == nullptr )
1199 return SFErrCodes::Memory;
1200
1201 (*ttf)->fsize = nLen;
1202 (*ttf)->ptr = const_cast<sal_uInt8 *>(static_cast<sal_uInt8 const *>(pBuffer));
1203
1204 SFErrCodes ret = (*ttf)->open(facenum);
1205 if (ret != SFErrCodes::Ok)
1206 {
1207 delete *ttf;
1208 *ttf = nullptr;
1209 }
1210 return ret;
1211}
1212
1213namespace {
1214
1215bool withinBounds(sal_uInt32 tdoffset, sal_uInt32 moreoffset, sal_uInt32 len, sal_uInt32 available)
1216{
1217 sal_uInt32 result;
1218 if (o3tl::checked_add(tdoffset, moreoffset, result))
1219 return false;
1220 if (o3tl::checked_add(result, len, result))
1221 return false;
1222 return result <= available;
1223}
1224}
1225
1227 : m_nGlyphs(0xFFFFFFFF)
1228 , m_nHorzMetrics(0)
1229 , m_nVertMetrics(0)
1230 , m_nUnitsPerEm(0)
1231 , m_xCharMap(xCharMap)
1232 , m_bMicrosoftSymbolEncoded(false)
1233{
1234 if (pFileName)
1235 m_sFileName = pFileName;
1236}
1237
1239{
1240}
1241
1242TrueTypeFont::TrueTypeFont(const char* pFileName, const FontCharMapRef xCharMap)
1243 : AbstractTrueTypeFont(pFileName, xCharMap)
1244 , fsize(-1)
1245 , ptr(nullptr)
1246 , ntables(0)
1247{
1248}
1249
1251{
1252#if !defined(_WIN32)
1253 if (!fileName().empty())
1254 munmap(ptr, fsize);
1255#endif
1256}
1257
1258void CloseTTFont(TrueTypeFont* ttf) { delete ttf; }
1259
1261{
1262 SFErrCodes ret = indexGlyphData();
1263 if (ret != SFErrCodes::Ok)
1264 return ret;
1265
1266 GetNames(this);
1267
1268 return SFErrCodes::Ok;
1269}
1270
1271sal_uInt32 AbstractTrueTypeFont::glyphOffset(sal_uInt32 glyphID) const
1272{
1273 if (m_aGlyphOffsets.empty()) // the O_CFF and Bitmap cases
1274 return 0;
1275 return m_aGlyphOffsets[glyphID];
1276}
1277
1279{
1281 return SFErrCodes::TtFormat;
1282
1283 sal_uInt32 table_size;
1284 const sal_uInt8* table = this->table(O_maxp, table_size);
1285 m_nGlyphs = table_size >= 6 ? GetUInt16(table, 4) : 0;
1286
1287 table = this->table(O_head, table_size);
1288 if (table_size < HEAD_Length)
1289 return SFErrCodes::TtFormat;
1290
1293
1294 if (((indexfmt != 0) && (indexfmt != 1)) || (m_nUnitsPerEm <= 0))
1295 return SFErrCodes::TtFormat;
1296
1297 if (hasTable(O_glyf) && (table = this->table(O_loca, table_size))) /* TTF or TTF-OpenType */
1298 {
1299 int k = (table_size / (indexfmt ? 4 : 2)) - 1;
1300 if (k < static_cast<int>(m_nGlyphs)) /* Hack for broken Chinese fonts */
1301 m_nGlyphs = k;
1302
1303 m_aGlyphOffsets.clear();
1304 m_aGlyphOffsets.reserve(m_nGlyphs + 1);
1305 for (int i = 0; i <= static_cast<int>(m_nGlyphs); ++i)
1306 m_aGlyphOffsets.push_back(indexfmt ? GetUInt32(table, i << 2) : static_cast<sal_uInt32>(GetUInt16(table, i << 1)) << 1);
1307 }
1308 else if (this->table(O_CFF, table_size)) /* PS-OpenType */
1309 {
1310 int k = (table_size / 2) - 1; /* set a limit here, presumably much lower than the table size, but establishes some sort of physical bound */
1311 if (k < static_cast<int>(m_nGlyphs))
1312 m_nGlyphs = k;
1313
1314 m_aGlyphOffsets.clear();
1315 /* TODO: implement to get subsetting */
1316 }
1317 else {
1318 // Bitmap font, accept for now.
1319 // TODO: We only need this for fonts with CBDT table since they usually
1320 // lack glyf or CFF table, the check should be more specific, or better
1321 // non-subsetting code should not be calling this.
1322 m_aGlyphOffsets.clear();
1323 }
1324
1325 table = this->table(O_hhea, table_size);
1326 m_nHorzMetrics = (table && table_size >= 36) ? GetUInt16(table, 34) : 0;
1327
1328 table = this->table(O_vhea, table_size);
1329 m_nVertMetrics = (table && table_size >= 36) ? GetUInt16(table, 34) : 0;
1330
1331 if (!m_xCharMap.is())
1332 {
1333 table = this->table(O_cmap, table_size);
1335 }
1336 else
1337 m_bMicrosoftSymbolEncoded = m_xCharMap->isMicrosoftSymbolMap();
1338
1339 return SFErrCodes::Ok;
1340}
1341
1343{
1344 if (fsize < 4)
1345 return SFErrCodes::TtFormat;
1346
1347 int i;
1348 sal_uInt32 length, tag;
1349 sal_uInt32 tdoffset = 0; /* offset to TableDirectory in a TTC file. For TTF files is 0 */
1350
1351 sal_uInt32 TTCTag = GetInt32(ptr, 0);
1352
1353 if ((TTCTag == 0x00010000) || (TTCTag == T_true)) {
1354 tdoffset = 0;
1355 } else if (TTCTag == T_otto) { /* PS-OpenType font */
1356 tdoffset = 0;
1357 } else if (TTCTag == T_ttcf) { /* TrueType collection */
1358 if (!withinBounds(12, 4 * facenum, sizeof(sal_uInt32), fsize))
1359 return SFErrCodes::FontNo;
1360 sal_uInt32 Version = GetUInt32(ptr, 4);
1361 if (Version != 0x00010000 && Version != 0x00020000) {
1362 return SFErrCodes::TtFormat;
1363 }
1364 if (facenum >= GetUInt32(ptr, 8))
1365 return SFErrCodes::FontNo;
1366 tdoffset = GetUInt32(ptr, 12 + 4 * facenum);
1367 } else {
1368 return SFErrCodes::TtFormat;
1369 }
1370
1371 if (withinBounds(tdoffset, 0, 4 + sizeof(sal_uInt16), fsize))
1372 ntables = GetUInt16(ptr + tdoffset, 4);
1373
1374 if (ntables >= 128 || ntables == 0)
1375 return SFErrCodes::TtFormat;
1376
1377 /* parse the tables */
1378 for (i = 0; i < static_cast<int>(ntables); i++)
1379 {
1380 int nIndex;
1381 const sal_uInt32 nStart = tdoffset + 12;
1382 const sal_uInt32 nOffset = 16 * i;
1383 if (withinBounds(nStart, nOffset, sizeof(sal_uInt32), fsize))
1384 tag = GetUInt32(ptr + nStart, nOffset);
1385 else
1386 tag = static_cast<sal_uInt32>(-1);
1387 switch( tag ) {
1388 case T_maxp: nIndex = O_maxp; break;
1389 case T_glyf: nIndex = O_glyf; break;
1390 case T_head: nIndex = O_head; break;
1391 case T_loca: nIndex = O_loca; break;
1392 case T_name: nIndex = O_name; break;
1393 case T_hhea: nIndex = O_hhea; break;
1394 case T_hmtx: nIndex = O_hmtx; break;
1395 case T_cmap: nIndex = O_cmap; break;
1396 case T_vhea: nIndex = O_vhea; break;
1397 case T_vmtx: nIndex = O_vmtx; break;
1398 case T_OS2 : nIndex = O_OS2; break;
1399 case T_post: nIndex = O_post; break;
1400 case T_cvt : nIndex = O_cvt; break;
1401 case T_prep: nIndex = O_prep; break;
1402 case T_fpgm: nIndex = O_fpgm; break;
1403 case T_CFF: nIndex = O_CFF; break;
1404 default: nIndex = -1; break;
1405 }
1406
1407 if ((nIndex >= 0) && withinBounds(nStart, nOffset, 12 + sizeof(sal_uInt32), fsize))
1408 {
1409 sal_uInt32 nTableOffset = GetUInt32(ptr + nStart, nOffset + 8);
1410 length = GetUInt32(ptr + nStart, nOffset + 12);
1411 m_aTableList[nIndex].pData = ptr + nTableOffset;
1412 m_aTableList[nIndex].nSize = length;
1413 }
1414 }
1415
1416 /* Fixup offsets when only a TTC extract was provided */
1417 if (facenum == sal_uInt32(~0))
1418 {
1419 sal_uInt8* pHead = const_cast<sal_uInt8*>(m_aTableList[O_head].pData);
1420 if (!pHead)
1421 return SFErrCodes::TtFormat;
1422
1423 /* limit Head candidate to TTC extract's limits */
1424 if (pHead > ptr + (fsize - 54))
1425 pHead = ptr + (fsize - 54);
1426
1427 /* TODO: find better method than searching head table's magic */
1428 sal_uInt8* p = nullptr;
1429 for (p = pHead + 12; p > ptr; --p)
1430 {
1431 if( p[0]==0x5F && p[1]==0x0F && p[2]==0x3C && p[3]==0xF5 ) {
1432 int nDelta = (pHead + 12) - p;
1433 if( nDelta )
1434 for( int j = 0; j < NUM_TAGS; ++j )
1435 if (hasTable(j))
1436 m_aTableList[j].pData -= nDelta;
1437 break;
1438 }
1439 }
1440 if (p <= ptr)
1441 return SFErrCodes::TtFormat;
1442 }
1443
1444 /* Check the table offsets after TTC correction */
1445 for (i=0; i<NUM_TAGS; i++) {
1446 /* sanity check: table must lay completely within the file
1447 * at this point one could check the checksum of all contained
1448 * tables, but this would be quite time intensive.
1449 * Try to fix tables, so we can cope with minor problems.
1450 */
1451
1452 if (m_aTableList[i].pData < ptr)
1453 {
1454#if OSL_DEBUG_LEVEL > 1
1455 SAL_WARN_IF(m_aTableList[i].pData, "vcl.fonts", "font file " << fileName()
1456 << " has bad table offset "
1458 << "d (tagnum=" << i << ").");
1459#endif
1460 m_aTableList[i].nSize = 0;
1461 m_aTableList[i].pData = nullptr;
1462 }
1463 else if (const_cast<sal_uInt8*>(m_aTableList[i].pData) + m_aTableList[i].nSize > ptr + fsize)
1464 {
1465 sal_PtrDiff nMaxLen = (ptr + fsize) - m_aTableList[i].pData;
1466 if( nMaxLen < 0 )
1467 nMaxLen = 0;
1468 m_aTableList[i].nSize = nMaxLen;
1469#if OSL_DEBUG_LEVEL > 1
1470 SAL_WARN("vcl.fonts", "font file " << fileName()
1471 << " has too big table (tagnum=" << i << ").");
1472#endif
1473 }
1474 }
1475
1476 /* At this point TrueTypeFont is constructed, now need to verify the font format
1477 and read the basic font properties */
1478
1480}
1481
1482int GetTTGlyphPoints(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector<ControlPoint>& pointArray)
1483{
1484 return GetTTGlyphOutline(ttf, glyphID, pointArray, nullptr, nullptr);
1485}
1486
1487int GetTTGlyphComponents(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 >& glyphlist)
1488{
1489 int n = 1;
1490
1491 if (glyphID >= ttf->glyphCount())
1492 return 0;
1493
1494 sal_uInt32 glyflength;
1495 const sal_uInt8* glyf = ttf->table(O_glyf, glyflength);
1496
1497 sal_uInt32 nNextOffset = ttf->glyphOffset(glyphID + 1);
1498 if (nNextOffset > glyflength)
1499 return 0;
1500
1501 sal_uInt32 nOffset = ttf->glyphOffset(glyphID);
1502 if (nOffset > nNextOffset)
1503 return 0;
1504
1505 if (std::find(glyphlist.begin(), glyphlist.end(), glyphID) != glyphlist.end())
1506 {
1507 SAL_WARN("vcl.fonts", "Endless loop found in a compound glyph.");
1508 return 0;
1509 }
1510
1511 glyphlist.push_back( glyphID );
1512
1513 // Empty glyph.
1514 if (nOffset == nNextOffset)
1515 return n;
1516
1517 const auto* ptr = glyf + nOffset;
1518 sal_uInt32 nRemainingData = glyflength - nOffset;
1519
1520 if (nRemainingData >= 10 && GetInt16(ptr, 0) == -1) {
1521 sal_uInt16 flags, index;
1522 ptr += 10;
1523 nRemainingData -= 10;
1524 do {
1525 if (nRemainingData < 4)
1526 {
1527 SAL_WARN("vcl.fonts", "short read");
1528 break;
1529 }
1530 flags = GetUInt16(ptr, 0);
1531 index = GetUInt16(ptr, 2);
1532
1533 ptr += 4;
1534 nRemainingData -= 4;
1535 n += GetTTGlyphComponents(ttf, index, glyphlist);
1536
1537 sal_uInt32 nAdvance;
1538 if (flags & ARG_1_AND_2_ARE_WORDS) {
1539 nAdvance = 4;
1540 } else {
1541 nAdvance = 2;
1542 }
1543
1544 if (flags & WE_HAVE_A_SCALE) {
1545 nAdvance += 2;
1546 } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
1547 nAdvance += 4;
1548 } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
1549 nAdvance += 8;
1550 }
1551 if (nRemainingData < nAdvance)
1552 {
1553 SAL_WARN("vcl.fonts", "short read");
1554 break;
1555 }
1556 ptr += nAdvance;
1557 nRemainingData -= nAdvance;
1558 } while (flags & MORE_COMPONENTS);
1559 }
1560
1561 return n;
1562}
1563
1565 sal_uInt16 const *glyphArray, sal_uInt8 *encoding, int nGlyphs,
1566 int wmode)
1567{
1568 std::vector<ControlPoint> pa;
1569 std::unique_ptr<PSPathElement[]> path;
1570 int i, j, n;
1571 sal_uInt32 nSize;
1572 const sal_uInt8* table = ttf->table(O_head, nSize);
1573 TTGlyphMetrics metrics;
1574 int UPEm = ttf->unitsPerEm();
1575
1576 const char * const h01 = "%%!PS-AdobeFont-%d.%d-%d.%d\n";
1577 const char * const h02 = "%% Creator: %s %s %s\n";
1578 const char * const h09 = "%% Original font name: %s\n";
1579
1580 const char * const h10 =
1581 "30 dict begin\n"
1582 "/PaintType 0 def\n"
1583 "/FontType 3 def\n"
1584 "/StrokeWidth 0 def\n";
1585
1586 const char * const h11 = "/FontName (%s) cvn def\n";
1587
1588 /*
1589 const char *h12 = "%/UniqueID %d def\n";
1590 */
1591 const char * const h13 = "/FontMatrix [.001 0 0 .001 0 0] def\n";
1592 const char * const h14 = "/FontBBox [%d %d %d %d] def\n";
1593
1594 const char * const h15=
1595 "/Encoding 256 array def\n"
1596 " 0 1 255 {Encoding exch /.notdef put} for\n";
1597
1598 const char * const h16 = " Encoding %d /glyph%d put\n";
1599 const char * const h17 = "/XUID [103 0 0 16#%08" SAL_PRIXUINT32 " %d 16#%08" SAL_PRIXUINT32 " 16#%08" SAL_PRIXUINT32 "] def\n";
1600
1601 const char * const h30 = "/CharProcs %d dict def\n";
1602 const char * const h31 = " CharProcs begin\n";
1603 const char * const h32 = " /.notdef {} def\n";
1604 const char * const h33 = " /glyph%d {\n";
1605 const char * const h34 = " } bind def\n";
1606 const char * const h35 = " end\n";
1607
1608 const char * const h40 =
1609 "/BuildGlyph {\n"
1610 " exch /CharProcs get exch\n"
1611 " 2 copy known not\n"
1612 " {pop /.notdef} if\n"
1613 " get exec\n"
1614 "} bind def\n"
1615 "/BuildChar {\n"
1616 " 1 index /Encoding get exch get\n"
1617 " 1 index /BuildGlyph get exec\n"
1618 "} bind def\n"
1619 "currentdict end\n";
1620
1621 const char * const h41 = "(%s) cvn exch definefont pop\n";
1622
1623 if ((nGlyphs <= 0) || (nGlyphs > 256)) return SFErrCodes::GlyphNum;
1624 if (!glyphArray) return SFErrCodes::BadArg;
1625 if (!fname) fname = ttf->psname.getStr();
1626
1627 constexpr int bufmax = 256;
1628 char buf[bufmax];
1629
1630 snprintf(buf, bufmax, h01, GetInt16(table, 0), GetUInt16(table, 2), GetInt16(table, 4), GetUInt16(table, 6));
1631 outf->WriteOString(buf);
1632 snprintf(buf, bufmax, h02, modname, modver, modextra);
1633 outf->WriteOString(buf);
1634 snprintf(buf, bufmax, h09, ttf->psname.getStr());
1635 outf->WriteOString(buf);
1636
1637 snprintf(buf, bufmax, "%s", h10);
1638 outf->WriteOString(buf);
1639 snprintf(buf, bufmax, h11, fname);
1640 outf->WriteOString(buf);
1641/* snprintf(buf, bufmax, h12, 4000000); */
1642
1643 /* XUID generation:
1644 * 103 0 0 C1 C2 C3 C4
1645 * C1 - CRC-32 of the entire source TrueType font
1646 * C2 - number of glyphs in the subset
1647 * C3 - CRC-32 of the glyph array
1648 * C4 - CRC-32 of the encoding array
1649 *
1650 * All CRC-32 numbers are presented as hexadecimal numbers
1651 */
1652
1653 snprintf(buf, bufmax, h17, rtl_crc32(0, ttf->ptr, ttf->fsize), nGlyphs, rtl_crc32(0, glyphArray, nGlyphs * 2), rtl_crc32(0, encoding, nGlyphs));
1654 outf->WriteOString(buf);
1655 snprintf(buf, bufmax, "%s", h13);
1656 outf->WriteOString(buf);
1657 snprintf(buf, bufmax, h14, XUnits(UPEm, GetInt16(table, 36)), XUnits(UPEm, GetInt16(table, 38)), XUnits(UPEm, GetInt16(table, 40)), XUnits(UPEm, GetInt16(table, 42)));
1658 outf->WriteOString(buf);
1659 snprintf(buf, bufmax, "%s", h15);
1660 outf->WriteOString(buf);
1661
1662 for (i = 0; i < nGlyphs; i++) {
1663 snprintf(buf, bufmax, h16, encoding[i], i);
1664 outf->WriteOString(buf);
1665 }
1666
1667 snprintf(buf, bufmax, h30, nGlyphs+1);
1668 outf->WriteOString(buf);
1669 snprintf(buf, bufmax, "%s", h31);
1670 outf->WriteOString(buf);
1671 snprintf(buf, bufmax, "%s", h32);
1672 outf->WriteOString(buf);
1673
1674 for (i = 0; i < nGlyphs; i++) {
1675 snprintf(buf, bufmax, h33, i);
1676 outf->WriteOString(buf);
1677 int r = GetTTGlyphOutline(ttf, glyphArray[i] < ttf->glyphCount() ? glyphArray[i] : 0, pa, &metrics, nullptr);
1678
1679 if (r > 0) {
1680 n = BSplineToPSPath(pa.data(), r, path);
1681 } else {
1682 n = 0; /* glyph might have zero contours but valid metrics ??? */
1683 path = nullptr;
1684 if (r < 0) { /* glyph is not present in the font - pa array was not allocated, so no need to free it */
1685 continue;
1686 }
1687 }
1688 snprintf(buf, bufmax, "\t%d %d %d %d %d %d setcachedevice\n",
1689 wmode == 0 ? XUnits(UPEm, metrics.aw) : 0,
1690 wmode == 0 ? 0 : -XUnits(UPEm, metrics.ah),
1691 XUnits(UPEm, metrics.xMin),
1692 XUnits(UPEm, metrics.yMin),
1693 XUnits(UPEm, metrics.xMax),
1694 XUnits(UPEm, metrics.yMax));
1695 outf->WriteOString(buf);
1696
1697 for (j = 0; j < n; j++)
1698 {
1699 switch (path[j].type)
1700 {
1701 case PS_MOVETO:
1702 snprintf(buf, bufmax, "\t%d %d moveto\n", XUnits(UPEm, path[j].x1), XUnits(UPEm, path[j].y1));
1703 outf->WriteOString(buf);
1704 break;
1705
1706 case PS_LINETO:
1707 snprintf(buf, bufmax, "\t%d %d lineto\n", XUnits(UPEm, path[j].x1), XUnits(UPEm, path[j].y1));
1708 outf->WriteOString(buf);
1709 break;
1710
1711 case PS_CURVETO:
1712 snprintf(buf, bufmax, "\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));
1713 outf->WriteOString(buf);
1714 break;
1715
1716 case PS_CLOSEPATH:
1717 snprintf(buf, bufmax, "\tclosepath\n");
1718 outf->WriteOString(buf);
1719 break;
1720 case PS_NOOP:
1721 break;
1722 }
1723 }
1724 if (n > 0)
1725 {
1726 snprintf(buf, bufmax, "\tfill\n"); /* if glyph is not a whitespace character */
1727 outf->WriteOString(buf);
1728 }
1729
1730 snprintf(buf, bufmax, "%s", h34);
1731 outf->WriteOString(buf);
1732
1733 path.reset();
1734 }
1735 snprintf(buf, bufmax, "%s", h35);
1736 outf->WriteOString(buf);
1737
1738 snprintf(buf, bufmax, "%s", h40);
1739 outf->WriteOString(buf);
1740 snprintf(buf, bufmax, h41, fname);
1741 outf->WriteOString(buf);
1742
1743 return SFErrCodes::Ok;
1744}
1745
1747 std::vector<sal_uInt8>& rOutBuffer,
1748 sal_uInt16 const *glyphArray,
1749 sal_uInt8 const *encoding,
1750 int nGlyphs)
1751{
1752 std::unique_ptr<TrueTypeTableGeneric> cvt, prep, fpgm, os2;
1753 std::unique_ptr<TrueTypeTableName> name;
1754 std::unique_ptr<TrueTypeTableMaxp> maxp;
1755 std::unique_ptr<TrueTypeTableHhea> hhea;
1756 std::unique_ptr<TrueTypeTableHead> head;
1757 std::unique_ptr<TrueTypeTableGlyf> glyf;
1758 std::unique_ptr<TrueTypeTableCmap> cmap;
1759 std::unique_ptr<TrueTypeTablePost> post;
1760 int i;
1761 SFErrCodes res;
1762
1763 TrueTypeCreator ttcr(T_true);
1764
1767 std::vector<NameRecord> names;
1768 GetTTNameRecords(ttf, names);
1769 name.reset(new TrueTypeTableName(std::move(names)));
1770
1772 sal_uInt32 nTableSize;
1773 const sal_uInt8* p = ttf->table(O_maxp, nTableSize);
1774 maxp.reset(new TrueTypeTableMaxp(p, nTableSize));
1775
1777 p = ttf->table(O_hhea, nTableSize);
1778 if (p && nTableSize >= HHEA_caretSlopeRun_offset + 2)
1780 else
1781 hhea.reset(new TrueTypeTableHhea(0, 0, 0, 0, 0));
1782
1785 p = ttf->table(O_head, nTableSize);
1786 assert(p != nullptr);
1794
1797 glyf.reset(new TrueTypeTableGlyf());
1798 std::unique_ptr<sal_uInt32[]> gID(new sal_uInt32[nGlyphs]);
1799
1800 for (i = 0; i < nGlyphs; i++) {
1801 gID[i] = glyf->glyfAdd(GetTTRawGlyphData(ttf, glyphArray[i]), ttf);
1802 }
1803
1805 cmap.reset(new TrueTypeTableCmap());
1806
1807 for (i=0; i < nGlyphs; i++) {
1808 cmap->cmapAdd(0x010000, encoding[i], gID[i]);
1809 }
1810
1812 if ((p = ttf->table(O_cvt, nTableSize)) != nullptr)
1813 cvt.reset(new TrueTypeTableGeneric(T_cvt, nTableSize, p));
1814
1816 if ((p = ttf->table(O_prep, nTableSize)) != nullptr)
1817 prep.reset(new TrueTypeTableGeneric(T_prep, nTableSize, p));
1818
1820 if ((p = ttf->table(O_fpgm, nTableSize)) != nullptr)
1821 fpgm.reset(new TrueTypeTableGeneric(T_fpgm, nTableSize, p));
1822
1824 if ((p = ttf->table(O_post, nTableSize)) != nullptr)
1825 {
1826 sal_Int32 nItalic = (POST_italicAngle_offset + 4 < nTableSize) ?
1828 sal_Int16 nPosition = (POST_underlinePosition_offset + 2 < nTableSize) ?
1830 sal_Int16 nThickness = (POST_underlineThickness_offset + 2 < nTableSize) ?
1832 sal_uInt32 nFixedPitch = (POST_isFixedPitch_offset + 4 < nTableSize) ?
1834
1835 post.reset(new TrueTypeTablePost(0x00030000,
1836 nItalic, nPosition,
1837 nThickness, nFixedPitch));
1838 }
1839 else
1840 post.reset(new TrueTypeTablePost(0x00030000, 0, 0, 0, 0));
1841
1842 ttcr.AddTable(std::move(name)); ttcr.AddTable(std::move(maxp)); ttcr.AddTable(std::move(hhea));
1843 ttcr.AddTable(std::move(head)); ttcr.AddTable(std::move(glyf)); ttcr.AddTable(std::move(cmap));
1844 ttcr.AddTable(std::move(cvt)); ttcr.AddTable(std::move(prep)); ttcr.AddTable(std::move(fpgm));
1845 ttcr.AddTable(std::move(post)); ttcr.AddTable(std::move(os2));
1846
1847 res = ttcr.StreamToMemory(rOutBuffer);
1848#if OSL_DEBUG_LEVEL > 1
1849 SAL_WARN_IF(res != SFErrCodes::Ok, "vcl.fonts", "StreamToMemory: error code: "
1850 << (int) res << ".");
1851#endif
1852
1853 return res;
1854}
1855
1856namespace
1857{
1858void FillFontSubsetInfo(AbstractTrueTypeFont* ttf, FontSubsetInfo& rInfo)
1859{
1860 TTGlobalFontInfo aTTInfo;
1861 GetTTGlobalFontInfo(ttf, &aTTInfo);
1862
1863 rInfo.m_aPSName = OUString::fromUtf8(aTTInfo.psname);
1865 rInfo.m_aFontBBox
1866 = tools::Rectangle(Point(aTTInfo.xMin, aTTInfo.yMin), Point(aTTInfo.xMax, aTTInfo.yMax));
1867 rInfo.m_nCapHeight = aTTInfo.yMax; // Well ...
1868 rInfo.m_nAscent = aTTInfo.winAscent;
1869 rInfo.m_nDescent = aTTInfo.winDescent;
1870
1871 // mac fonts usually do not have an OS2-table
1872 // => get valid ascent/descent values from other tables
1873 if (!rInfo.m_nAscent)
1874 rInfo.m_nAscent = +aTTInfo.typoAscender;
1875 if (!rInfo.m_nAscent)
1876 rInfo.m_nAscent = +aTTInfo.ascender;
1877 if (!rInfo.m_nDescent)
1878 rInfo.m_nDescent = +aTTInfo.typoDescender;
1879 if (!rInfo.m_nDescent)
1880 rInfo.m_nDescent = -aTTInfo.descender;
1881
1882 rInfo.m_bFilled = true;
1883}
1884
1885bool CreateCFFfontSubset(const unsigned char* pFontBytes, int nByteLength,
1886 std::vector<sal_uInt8>& rOutBuffer, const sal_GlyphId* pGlyphIds,
1887 const sal_uInt8* pEncoding, int nGlyphCount, FontSubsetInfo& rInfo)
1888{
1889 utl::TempFileFast aTempFile;
1890 SvStream* pStream = aTempFile.GetStream(StreamMode::READWRITE);
1891
1892 rInfo.LoadFont(FontType::CFF_FONT, pFontBytes, nByteLength);
1893 bool bRet = rInfo.CreateFontSubset(FontType::TYPE1_PFB, pStream, nullptr, pGlyphIds, pEncoding,
1894 nGlyphCount);
1895
1896 if (bRet)
1897 {
1898 rOutBuffer.resize(pStream->TellEnd());
1899 pStream->Seek(0);
1900 auto nRead = pStream->ReadBytes(rOutBuffer.data(), rOutBuffer.size());
1901 if (nRead != rOutBuffer.size())
1902 {
1903 rOutBuffer.clear();
1904 return false;
1905 }
1906 }
1907
1908 return bRet;
1909}
1910}
1911
1912bool CreateTTFfontSubset(vcl::AbstractTrueTypeFont& rTTF, std::vector<sal_uInt8>& rOutBuffer,
1913 const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding,
1914 const int nOrigGlyphCount, FontSubsetInfo& rInfo)
1915{
1916 // Get details about the subset font.
1917 FillFontSubsetInfo(&rTTF, rInfo);
1918
1919 // Shortcut for CFF-subsetting.
1920 sal_uInt32 nCFF;
1921 const sal_uInt8* pCFF = rTTF.table(O_CFF, nCFF);
1922 if (nCFF)
1923 return CreateCFFfontSubset(pCFF, nCFF, rOutBuffer, pGlyphIds, pEncoding,
1924 nOrigGlyphCount, rInfo);
1925
1926 // Multiple questions:
1927 // - Why is there a glyph limit?
1928 // MacOS used to handle 257 glyphs...
1929 // Also the much more complex PrintFontManager variant has this limit.
1930 // Also the very first implementation has the limit in
1931 // commit 8789ed701e98031f2a1657ea0dfd6f7a0b050992
1932 // - Why doesn't the PrintFontManager care about the fake glyph? It
1933 // is used on all unx platforms to create the subset font.
1934 // - Should the SAL_WARN actually be asserts, like on MacOS?
1935 if (nOrigGlyphCount > 256)
1936 {
1937 SAL_WARN("vcl.fonts", "too many glyphs for subsetting");
1938 return false;
1939 }
1940
1941 int nGlyphCount = nOrigGlyphCount;
1942 sal_uInt16 aShortIDs[256];
1943 sal_uInt8 aTempEncs[256];
1944
1945 // handle the undefined / first font glyph
1946 int nNotDef = -1, i;
1947 for (i = 0; i < nGlyphCount; ++i)
1948 {
1949 aTempEncs[i] = pEncoding[i];
1950 aShortIDs[i] = static_cast<sal_uInt16>(pGlyphIds[i]);
1951 if (!aShortIDs[i])
1952 if (nNotDef < 0)
1953 nNotDef = i;
1954 }
1955
1956 // nNotDef glyph must be in pos 0 => swap glyphids
1957 if (nNotDef != 0)
1958 {
1959 if (nNotDef < 0)
1960 {
1961 if (nGlyphCount == 256)
1962 {
1963 SAL_WARN("vcl.fonts", "too many glyphs for subsetting");
1964 return false;
1965 }
1966 nNotDef = nGlyphCount++;
1967 }
1968
1969 aShortIDs[nNotDef] = aShortIDs[0];
1970 aTempEncs[nNotDef] = aTempEncs[0];
1971 aShortIDs[0] = 0;
1972 aTempEncs[0] = 0;
1973 }
1974
1975 // write subset into destination file
1976 return (CreateTTFromTTGlyphs(&rTTF, rOutBuffer, aShortIDs, aTempEncs, nGlyphCount)
1978}
1979
1980GlyphOffsets::GlyphOffsets(sal_uInt8 *sfntP, sal_uInt32 sfntLen)
1981{
1982 sal_uInt8 *loca = nullptr;
1983 sal_uInt16 numTables = GetUInt16(sfntP, 4);
1984 sal_uInt32 locaLen = 0;
1985 sal_Int16 indexToLocFormat = 0;
1986
1987 sal_uInt32 nMaxPossibleTables = sfntLen / (3*sizeof(sal_uInt32)); /*the three GetUInt32 calls*/
1988 if (numTables > nMaxPossibleTables)
1989 {
1990 SAL_WARN( "vcl.fonts", "GlyphOffsetsNew claimed to have "
1991 << numTables << " tables, but that's impossibly large");
1992 numTables = nMaxPossibleTables;
1993 }
1994
1995 for (sal_uInt16 i = 0; i < numTables; i++) {
1996 sal_uInt32 nLargestFixedOffsetPos = 12 + 16 * i + 12;
1997 sal_uInt32 nMinSize = nLargestFixedOffsetPos + sizeof(sal_uInt32);
1998 if (nMinSize > sfntLen)
1999 {
2000 SAL_WARN( "vcl.fonts", "GlyphOffsetsNew claimed to have "
2001 << numTables << " tables, but only space for " << i);
2002 break;
2003 }
2004
2005 sal_uInt32 tag = GetUInt32(sfntP, 12 + 16 * i);
2006 sal_uInt32 off = GetUInt32(sfntP, 12 + 16 * i + 8);
2007 sal_uInt32 len = GetUInt32(sfntP, nLargestFixedOffsetPos);
2008
2009 if (tag == T_loca) {
2010 loca = sfntP + off;
2011 locaLen = len;
2012 } else if (tag == T_head) {
2013 indexToLocFormat = GetInt16(sfntP + off, 50);
2014 }
2015 }
2016
2017 this->nGlyphs = locaLen / ((indexToLocFormat == 1) ? 4 : 2);
2018 assert(this->nGlyphs != 0);
2019 this->offs = std::make_unique<sal_uInt32[]>(this->nGlyphs);
2020
2021 for (sal_uInt32 i = 0; i < this->nGlyphs; i++) {
2022 if (indexToLocFormat == 1) {
2023 this->offs[i] = GetUInt32(loca, i * 4);
2024 } else {
2025 this->offs[i] = GetUInt16(loca, i * 2) << 1;
2026 }
2027 }
2028}
2029
2030static void DumpSfnts(SvStream *outf, sal_uInt8 *sfntP, sal_uInt32 sfntLen)
2031{
2032 if (sfntLen < 12)
2033 {
2034 SAL_WARN( "vcl.fonts", "DumpSfnts sfntLen is too short: "
2035 << sfntLen << " legal min is: " << 12);
2036 return;
2037 }
2038
2039 const sal_uInt32 nSpaceForTables = sfntLen - 12;
2040 const sal_uInt32 nTableSize = 16;
2041 const sal_uInt32 nMaxPossibleTables = nSpaceForTables/nTableSize;
2042
2043 HexFmt h(outf);
2044 sal_uInt16 i, numTables = GetUInt16(sfntP, 4);
2045 GlyphOffsets go(sfntP, sfntLen);
2046 sal_uInt8 const pad[] = {0,0,0,0}; /* zeroes */
2047
2048 if (numTables > nMaxPossibleTables)
2049 {
2050 SAL_WARN( "vcl.fonts", "DumpSfnts claimed to have "
2051 << numTables << " tables, but only space for " << nMaxPossibleTables);
2052 numTables = nMaxPossibleTables;
2053 }
2054
2055 assert(numTables <= 9); /* Type42 has 9 required tables */
2056
2057 std::unique_ptr<sal_uInt32[]> offs(new sal_uInt32[numTables]);
2058
2059 outf->WriteOString("/sfnts [");
2060 h.OpenString();
2061 h.BlockWrite(sfntP, 12); /* stream out the Offset Table */
2062 h.BlockWrite(sfntP+12, 16 * numTables); /* stream out the Table Directory */
2063
2064 for (i=0; i<numTables; i++)
2065 {
2066 sal_uInt32 nLargestFixedOffsetPos = 12 + 16 * i + 12;
2067 sal_uInt32 nMinSize = nLargestFixedOffsetPos + sizeof(sal_uInt32);
2068 if (nMinSize > sfntLen)
2069 {
2070 SAL_WARN( "vcl.fonts", "DumpSfnts claimed to have "
2071 << numTables << " tables, but only space for " << i);
2072 break;
2073 }
2074
2075 sal_uInt32 tag = GetUInt32(sfntP, 12 + 16 * i);
2076 sal_uInt32 off = GetUInt32(sfntP, 12 + 16 * i + 8);
2077 if (off > sfntLen)
2078 {
2079 SAL_WARN( "vcl.fonts", "DumpSfnts claims offset of "
2080 << off << " but max possible is " << sfntLen);
2081 break;
2082 }
2083 sal_uInt8 *pRecordStart = sfntP + off;
2084 sal_uInt32 len = GetUInt32(sfntP, nLargestFixedOffsetPos);
2085 sal_uInt32 nMaxLenPossible = sfntLen - off;
2086 if (len > nMaxLenPossible)
2087 {
2088 SAL_WARN( "vcl.fonts", "DumpSfnts claims len of "
2089 << len << " but only space for " << nMaxLenPossible);
2090 break;
2091 }
2092
2093 if (tag != T_glyf)
2094 {
2095 h.BlockWrite(pRecordStart, len);
2096 }
2097 else
2098 {
2099 sal_uInt8 *glyf = pRecordStart;
2100 sal_uInt8 *eof = pRecordStart + nMaxLenPossible;
2101 for (sal_uInt32 j = 0; j < go.nGlyphs - 1; j++)
2102 {
2103 sal_uInt32 nStartOffset = go.offs[j];
2104 sal_uInt8 *pSubRecordStart = glyf + nStartOffset;
2105 if (pSubRecordStart > eof)
2106 {
2107 SAL_WARN( "vcl.fonts", "DumpSfnts start glyf claims offset of "
2108 << pSubRecordStart - sfntP << " but max possible is " << eof - sfntP);
2109 break;
2110 }
2111
2112 sal_uInt32 nEndOffset = go.offs[j + 1];
2113 sal_uInt8 *pSubRecordEnd = glyf + nEndOffset;
2114 if (pSubRecordEnd > eof)
2115 {
2116 SAL_WARN( "vcl.fonts", "DumpSfnts end glyf offset of "
2117 << pSubRecordEnd - sfntP << " but max possible is " << eof - sfntP);
2118 break;
2119 }
2120
2121 sal_uInt32 l = pSubRecordEnd - pSubRecordStart;
2122 h.BlockWrite(pSubRecordStart, l);
2123 }
2124 }
2125 h.BlockWrite(pad, (4 - (len & 3)) & 3);
2126 }
2127 h.CloseString();
2128 outf->WriteOString("] def\n");
2129}
2130
2132 SvStream *outf,
2133 const char *psname,
2134 sal_uInt16 const *glyphArray,
2135 sal_uInt8 *encoding,
2136 int nGlyphs)
2137{
2138 std::unique_ptr<TrueTypeTable> head, hhea, maxp, cvt, prep, fpgm;
2139 std::unique_ptr<TrueTypeTableGlyf> glyf;
2140 int i;
2141 SFErrCodes res;
2142
2143 sal_uInt16 ver;
2144 sal_Int32 rev;
2145
2146 int UPEm = ttf->unitsPerEm();
2147
2148 if (nGlyphs >= 256) return SFErrCodes::GlyphNum;
2149
2150 assert(psname != nullptr);
2151
2152 TrueTypeCreator ttcr(T_true);
2153
2154 /* head */
2155 sal_uInt32 nTableSize;
2156 const sal_uInt8* p = ttf->table(O_head, nTableSize);
2157 const sal_uInt8* headP = p;
2158 assert(p != nullptr);
2162
2164 p = ttf->table(O_hhea, nTableSize);
2165 if (p)
2167 else
2168 hhea.reset(new TrueTypeTableHhea(0, 0, 0, 0, 0));
2169
2171 p = ttf->table(O_maxp, nTableSize);
2172 maxp.reset(new TrueTypeTableMaxp(p, nTableSize));
2173
2175 if ((p = ttf->table(O_cvt, nTableSize)) != nullptr)
2176 cvt.reset(new TrueTypeTableGeneric(T_cvt, nTableSize, p));
2177
2179 if ((p = ttf->table(O_prep, nTableSize)) != nullptr)
2180 prep.reset(new TrueTypeTableGeneric(T_prep, nTableSize, p));
2181
2183 if ((p = ttf->table(O_fpgm, nTableSize)) != nullptr)
2184 fpgm.reset(new TrueTypeTableGeneric(T_fpgm, nTableSize, p));
2185
2187 glyf.reset(new TrueTypeTableGlyf());
2188 std::unique_ptr<sal_uInt16[]> gID(new sal_uInt16[nGlyphs]);
2189
2190 for (i = 0; i < nGlyphs; i++) {
2191 gID[i] = static_cast<sal_uInt16>(glyf->glyfAdd(GetTTRawGlyphData(ttf, glyphArray[i]), ttf));
2192 }
2193
2194 const int nGlyfCount = static_cast<int>(glyf->glyfCount());
2195
2196 ttcr.AddTable(std::move(head)); ttcr.AddTable(std::move(hhea)); ttcr.AddTable(std::move(maxp)); ttcr.AddTable(std::move(cvt));
2197 ttcr.AddTable(std::move(prep)); ttcr.AddTable(std::move(glyf)); ttcr.AddTable(std::move(fpgm));
2198
2199 std::vector<sal_uInt8> aOutBuffer;
2200 if ((res = ttcr.StreamToMemory(aOutBuffer)) != SFErrCodes::Ok) {
2201 return res;
2202 }
2203
2204 constexpr int bufmax = 256;
2205 char buf[bufmax];
2206
2207 snprintf(buf, bufmax, "%%!PS-TrueTypeFont-%d.%d-%d.%d\n", static_cast<int>(ver), static_cast<int>(ver & 0xFF), static_cast<int>(rev>>16), static_cast<int>(rev & 0xFFFF));
2208 outf->WriteOString(buf);
2209 snprintf(buf, bufmax, "%%%%Creator: %s %s %s\n", modname, modver, modextra);
2210 outf->WriteOString(buf);
2211 snprintf(buf, bufmax, "%%- Font subset generated from a source font file: '%s'\n", ttf->fileName().data());
2212 outf->WriteOString(buf);
2213 snprintf(buf, bufmax, "%%- Original font name: %s\n", ttf->psname.getStr());
2214 outf->WriteOString(buf);
2215 snprintf(buf, bufmax, "%%- Original font family: %s\n", ttf->family.getStr());
2216 outf->WriteOString(buf);
2217 snprintf(buf, bufmax, "%%- Original font sub-family: %s\n", ttf->subfamily.getStr());
2218 outf->WriteOString(buf);
2219 snprintf(buf, bufmax, "11 dict begin\n");
2220 outf->WriteOString(buf);
2221 snprintf(buf, bufmax, "/FontName (%s) cvn def\n", psname);
2222 outf->WriteOString(buf);
2223 snprintf(buf, bufmax, "/PaintType 0 def\n");
2224 outf->WriteOString(buf);
2225 snprintf(buf, bufmax, "/FontMatrix [1 0 0 1 0 0] def\n");
2226 outf->WriteOString(buf);
2227 snprintf(buf, bufmax, "/FontBBox [%d %d %d %d] def\n", XUnits(UPEm, GetInt16(headP, HEAD_xMin_offset)), XUnits(UPEm, GetInt16(headP, HEAD_yMin_offset)), XUnits(UPEm, GetInt16(headP, HEAD_xMax_offset)), XUnits(UPEm, GetInt16(headP, HEAD_yMax_offset)));
2228 outf->WriteOString(buf);
2229 snprintf(buf, bufmax, "/FontType 42 def\n");
2230 outf->WriteOString(buf);
2231 snprintf(buf, bufmax, "/Encoding 256 array def\n");
2232 outf->WriteOString(buf);
2233 snprintf(buf, bufmax, " 0 1 255 {Encoding exch /.notdef put} for\n");
2234 outf->WriteOString(buf);
2235
2236 for (i = 1; i<nGlyphs; i++) {
2237 snprintf(buf, bufmax, "Encoding %d /glyph%u put\n", encoding[i], gID[i]);
2238 outf->WriteOString(buf);
2239 }
2240 snprintf(buf, bufmax, "/XUID [103 0 1 16#%08X %u 16#%08X 16#%08X] def\n", static_cast<unsigned int>(rtl_crc32(0, ttf->ptr, ttf->fsize)), static_cast<unsigned int>(nGlyphs), static_cast<unsigned int>(rtl_crc32(0, glyphArray, nGlyphs * 2)), static_cast<unsigned int>(rtl_crc32(0, encoding, nGlyphs)));
2241 outf->WriteOString(buf);
2242
2243 DumpSfnts(outf, aOutBuffer.data(), aOutBuffer.size());
2244
2245 /* dump charstrings */
2246 snprintf(buf, bufmax, "/CharStrings %d dict dup begin\n", nGlyphs);
2247 outf->WriteOString(buf);
2248 snprintf(buf, bufmax, "/.notdef 0 def\n");
2249 outf->WriteOString(buf);
2250 for (i = 1; i < nGlyfCount; i++) {
2251 snprintf(buf, bufmax, "/glyph%d %d def\n", i, i);
2252 outf->WriteOString(buf);
2253 }
2254 snprintf(buf, bufmax, "end readonly def\n");
2255 outf->WriteOString(buf);
2256
2257 snprintf(buf, bufmax, "FontName currentdict end definefont pop\n");
2258 outf->WriteOString(buf);
2259
2260 return SFErrCodes::Ok;
2261}
2262
2263bool GetTTGlobalFontHeadInfo(const AbstractTrueTypeFont *ttf, int& xMin, int& yMin, int& xMax, int& yMax, sal_uInt16& macStyle)
2264{
2265 sal_uInt32 table_size;
2266 const sal_uInt8* table = ttf->table(O_head, table_size);
2267 if (table_size < 46)
2268 return false;
2269
2270 const int UPEm = ttf->unitsPerEm();
2271 if (UPEm == 0)
2272 return false;
2273 xMin = XUnits(UPEm, GetInt16(table, HEAD_xMin_offset));
2274 yMin = XUnits(UPEm, GetInt16(table, HEAD_yMin_offset));
2275 xMax = XUnits(UPEm, GetInt16(table, HEAD_xMax_offset));
2276 yMax = XUnits(UPEm, GetInt16(table, HEAD_yMax_offset));
2278 return true;
2279}
2280
2282{
2283 int UPEm = ttf->unitsPerEm();
2284
2285 info->family = ttf->family;
2286 info->ufamily = ttf->ufamily;
2287 info->subfamily = ttf->subfamily;
2288 info->usubfamily = ttf->usubfamily;
2289 info->psname = ttf->psname;
2291
2292 sal_uInt32 table_size;
2293 const sal_uInt8* table = ttf->table(O_OS2, table_size);
2294 if (table_size >= 42)
2295 {
2298
2299 if (table_size >= OS2_V0_length && UPEm != 0) {
2305 /* sanity check; some fonts treat winDescent as signed
2306 * violating the standard */
2307 if( info->winDescent > 5*UPEm )
2309 }
2312 }
2313
2314 table = ttf->table(O_post, table_size);
2315 if (table_size >= 12 + sizeof(sal_uInt32))
2316 {
2319 }
2320
2321 GetTTGlobalFontHeadInfo(ttf, info->xMin, info->yMin, info->xMax, info->yMax, info->macStyle);
2322
2323 table = ttf->table(O_hhea, table_size);
2324 if (table_size >= 10 && UPEm != 0)
2325 {
2329 }
2330}
2331
2332std::unique_ptr<GlyphData> GetTTRawGlyphData(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID)
2333{
2334 if (glyphID >= ttf->glyphCount())
2335 return nullptr;
2336
2337 sal_uInt32 hmtxlength;
2338 const sal_uInt8* hmtx = ttf->table(O_hmtx, hmtxlength);
2339
2340 if (!hmtxlength)
2341 return nullptr;
2342
2343 sal_uInt32 glyflength;
2344 const sal_uInt8* glyf = ttf->table(O_glyf, glyflength);
2345 int n;
2346
2347 /* #127161# check the glyph offsets */
2348 sal_uInt32 nNextOffset = ttf->glyphOffset(glyphID + 1);
2349 if (nNextOffset > glyflength)
2350 return nullptr;
2351
2352 sal_uInt32 nOffset = ttf->glyphOffset(glyphID);
2353 if (nOffset > nNextOffset)
2354 return nullptr;
2355
2356 sal_uInt32 length = nNextOffset - nOffset;
2357
2358 std::unique_ptr<GlyphData> d(new GlyphData);
2359
2360 if (length > 0) {
2361 const sal_uInt8* srcptr = glyf + ttf->glyphOffset(glyphID);
2362 const size_t nChunkLen = ((length + 1) & ~1);
2363 d->ptr.reset(new sal_uInt8[nChunkLen]);
2364 memcpy(d->ptr.get(), srcptr, length);
2365 memset(d->ptr.get() + length, 0, nChunkLen - length);
2366 d->compflag = (GetInt16( srcptr, 0 ) < 0);
2367 } else {
2368 d->ptr = nullptr;
2369 d->compflag = false;
2370 }
2371
2372 d->glyphID = glyphID;
2373 d->nbytes = static_cast<sal_uInt16>((length + 1) & ~1);
2374
2375 /* now calculate npoints and ncontours */
2376 std::vector<ControlPoint> cp;
2377 n = GetTTGlyphPoints(ttf, glyphID, cp);
2378 if (n > 0)
2379 {
2380 int m = 0;
2381 for (int i = 0; i < n; i++)
2382 {
2383 if (cp[i].flags & 0x8000)
2384 m++;
2385 }
2386 d->npoints = static_cast<sal_uInt16>(n);
2387 d->ncontours = static_cast<sal_uInt16>(m);
2388 } else {
2389 d->npoints = 0;
2390 d->ncontours = 0;
2391 }
2392
2393 /* get advance width and left sidebearing */
2394 sal_uInt32 nAwOffset;
2395 sal_uInt32 nLsboffset;
2396 if (glyphID < ttf->horzMetricCount()) {
2397 nAwOffset = 4 * glyphID;
2398 nLsboffset = 4 * glyphID + 2;
2399 } else {
2400 nAwOffset = 4 * (ttf->horzMetricCount() - 1);
2401 nLsboffset = (ttf->horzMetricCount() * 4) + ((glyphID - ttf->horzMetricCount()) * 2);
2402 }
2403
2404 if (nAwOffset + 2 <= hmtxlength)
2405 d->aw = GetUInt16(hmtx, nAwOffset);
2406 else
2407 {
2408 SAL_WARN("vcl.fonts", "hmtx offset " << nAwOffset << " not available");
2409 d->aw = 0;
2410 }
2411 if (nLsboffset + 2 <= hmtxlength)
2412 d->lsb = GetInt16(hmtx, nLsboffset);
2413 else
2414 {
2415 SAL_WARN("vcl.fonts", "hmtx offset " << nLsboffset << " not available");
2416 d->lsb = 0;
2417 }
2418
2419 return d;
2420}
2421
2422void GetTTNameRecords(AbstractTrueTypeFont const *ttf, std::vector<NameRecord>& nr)
2423{
2424 sal_uInt32 nTableSize;
2425 const sal_uInt8* table = ttf->table(O_name, nTableSize);
2426
2427 nr.clear();
2428
2429 if (nTableSize < 6)
2430 {
2431#if OSL_DEBUG_LEVEL > 1
2432 SAL_WARN("vcl.fonts", "O_name table too small.");
2433#endif
2434 return;
2435 }
2436
2437 sal_uInt16 n = GetUInt16(table, 2);
2438 sal_uInt32 nStrBase = GetUInt16(table, 4);
2439 int i;
2440
2441 if (n == 0) return;
2442
2443 const sal_uInt32 remaining_table_size = nTableSize-6;
2444 const sal_uInt32 nMinRecordSize = 12;
2445 const sal_uInt32 nMaxRecords = remaining_table_size / nMinRecordSize;
2446 if (n > nMaxRecords)
2447 {
2448 SAL_WARN("vcl.fonts", "Parsing error in " << OUString::createFromAscii(ttf->fileName()) <<
2449 ": " << nMaxRecords << " max possible entries, but " <<
2450 n << " claimed, truncating");
2451 n = nMaxRecords;
2452 }
2453
2454 nr.resize(n);
2455
2456 for (i = 0; i < n; i++) {
2457 sal_uInt32 nLargestFixedOffsetPos = 6 + 10 + 12 * i;
2458 sal_uInt32 nMinSize = nLargestFixedOffsetPos + sizeof(sal_uInt16);
2459 if (nMinSize > nTableSize)
2460 {
2461 SAL_WARN( "vcl.fonts", "Font " << OUString::createFromAscii(ttf->fileName()) << " claimed to have "
2462 << n << " name records, but only space for " << i);
2463 break;
2464 }
2465
2466 nr[i].platformID = GetUInt16(table, 6 + 0 + 12 * i);
2467 nr[i].encodingID = GetUInt16(table, 6 + 2 + 12 * i);
2468 nr[i].languageID = LanguageType(GetUInt16(table, 6 + 4 + 12 * i));
2469 nr[i].nameID = GetUInt16(table, 6 + 6 + 12 * i);
2470 sal_uInt16 slen = GetUInt16(table, 6 + 8 + 12 * i);
2471 sal_uInt32 nStrOffset = GetUInt16(table, nLargestFixedOffsetPos);
2472 if (slen) {
2473 if (nStrBase + nStrOffset + slen >= nTableSize)
2474 continue;
2475
2476 const sal_uInt32 rec_string = nStrBase + nStrOffset;
2477 const size_t available_space = rec_string > nTableSize ? 0 : (nTableSize - rec_string);
2478 if (slen <= available_space)
2479 {
2480 nr[i].sptr.resize(slen);
2481 memcpy(nr[i].sptr.data(), table + rec_string, slen);
2482 }
2483 }
2484 // some fonts have 3.0 names => fix them to 3.1
2485 if( (nr[i].platformID == 3) && (nr[i].encodingID == 0) )
2486 nr[i].encodingID = 1;
2487 }
2488}
2489
2490template<size_t N> static void
2491append(std::bitset<N> & rSet, size_t const nOffset, sal_uInt32 const nValue)
2492{
2493 for (size_t i = 0; i < 32; ++i)
2494 {
2495 rSet.set(nOffset + i, (nValue & (1U << i)) != 0);
2496 }
2497}
2498
2500 std::optional<std::bitset<UnicodeCoverage::MAX_UC_ENUM>> &rUnicodeRange,
2501 std::optional<std::bitset<CodePageCoverage::MAX_CP_ENUM>> &rCodePageRange,
2502 const unsigned char* pTable, size_t nLength)
2503{
2504 bool bRet = false;
2505 // parse OS/2 header
2507 {
2508 rUnicodeRange = std::bitset<UnicodeCoverage::MAX_UC_ENUM>();
2509 append(*rUnicodeRange, 0, GetUInt32(pTable, OS2_ulUnicodeRange1_offset));
2510 append(*rUnicodeRange, 32, GetUInt32(pTable, OS2_ulUnicodeRange2_offset));
2511 append(*rUnicodeRange, 64, GetUInt32(pTable, OS2_ulUnicodeRange3_offset));
2512 append(*rUnicodeRange, 96, GetUInt32(pTable, OS2_ulUnicodeRange4_offset));
2513 bRet = true;
2514 if (nLength >= OS2_V1_length)
2515 {
2516 rCodePageRange = std::bitset<CodePageCoverage::MAX_CP_ENUM>();
2517 append(*rCodePageRange, 0, GetUInt32(pTable, OS2_ulCodePageRange1_offset));
2518 append(*rCodePageRange, 32, GetUInt32(pTable, OS2_ulCodePageRange2_offset));
2519 }
2520 }
2521 return bRet;
2522}
2523
2524} // namespace vcl
2525
2526int TestFontSubset(const void* data, sal_uInt32 size)
2527{
2528 int nResult = -1;
2529 vcl::TrueTypeFont* pTTF = nullptr;
2530 if (OpenTTFontBuffer(data, size, 0, &pTTF) == vcl::SFErrCodes::Ok)
2531 {
2533 GetTTGlobalFontInfo(pTTF, &aInfo);
2534
2535 sal_uInt16 aGlyphIds[ 256 ] = {};
2536 sal_uInt8 aEncoding[ 256 ] = {};
2537
2538 for (sal_uInt16 c = 32; c < 256; ++c)
2539 {
2540 aEncoding[c] = c;
2541 aGlyphIds[c] = c - 31;
2542 }
2543
2544 std::vector<sal_uInt8> aBuffer;
2545 CreateTTFromTTGlyphs(pTTF, aBuffer, aGlyphIds, aEncoding, 256);
2546
2547
2548 // cleanup
2549 CloseTTFont( pTTF );
2550 // success
2551 nResult = 0;
2552 }
2553
2554 return nResult;
2555}
2556
2557/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
double d
tools::Rectangle m_aFontBBox
Definition: fontsubset.hxx:71
OUString m_aPSName
Definition: fontsubset.hxx:67
FontType m_nFontType
font-type of subset result
Definition: fontsubset.hxx:72
void LoadFont(FontType eInFontType, const unsigned char *pFontBytes, int nByteLength)
Definition: fontsubset.cxx:51
bool CreateFontSubset(FontType nOutFontTypeMask, SvStream *pOutFile, const char *pOutFontName, const sal_GlyphId *pGlyphIds, const sal_uInt8 *pEncodedIds, int nReqGlyphCount)
Definition: fontsubset.cxx:69
int m_nAscent
all metrics in PS font units
Definition: fontsubset.hxx:68
virtual sal_uInt64 TellEnd()
SvStream & WriteOString(std::string_view rStr)
sal_uInt64 Seek(sal_uInt64 nPos)
std::size_t ReadBytes(void *pData, std::size_t nSize)
bool is() const
SvStream * GetStream(StreamMode eMode)
virtual bool hasTable(sal_uInt32 ord) const =0
sal_uInt32 m_nHorzMetrics
Definition: sft.hxx:694
virtual ~AbstractTrueTypeFont()
Definition: sft.cxx:1238
SFErrCodes initialize()
Definition: sft.cxx:1260
sal_uInt32 vertMetricCount() const
Definition: sft.hxx:714
std::string const & fileName() const
Definition: sft.hxx:710
bool m_bMicrosoftSymbolEncoded
Definition: sft.hxx:699
sal_uInt32 horzMetricCount() const
Definition: sft.hxx:713
sal_uInt32 m_nVertMetrics
Definition: sft.hxx:695
virtual const sal_uInt8 * table(sal_uInt32 ord, sal_uInt32 &size) const =0
sal_uInt32 m_nUnitsPerEm
Definition: sft.hxx:696
sal_uInt32 glyphCount() const
Definition: sft.hxx:711
sal_uInt32 m_nGlyphs
Definition: sft.hxx:693
sal_uInt32 glyphOffset(sal_uInt32 glyphID) const
Definition: sft.cxx:1271
bool IsMicrosoftSymbolEncoded() const
Definition: sft.hxx:716
FontCharMapRef m_xCharMap
Definition: sft.hxx:698
AbstractTrueTypeFont(const char *fileName=nullptr, const FontCharMapRef xCharMap=nullptr)
Definition: sft.cxx:1226
std::string m_sFileName
Definition: sft.hxx:692
std::vector< sal_uInt32 > m_aGlyphOffsets
Definition: sft.hxx:697
SFErrCodes indexGlyphData()
Definition: sft.cxx:1278
sal_uInt32 unitsPerEm() const
Definition: sft.hxx:715
SFErrCodes StreamToMemory(std::vector< sal_uInt8 > &rOutBuffer)
Writes a TrueType font generated by the TrueTypeCreator to a segment of memory that this method alloc...
Definition: ttcr.cxx:151
void AddTable(std::unique_ptr< TrueTypeTable > table)
Adds a TrueType table to the TrueType creator.
Definition: ttcr.cxx:131
const sal_uInt8 * table(sal_uInt32 ord, sal_uInt32 &size) const override
Definition: sft.hxx:752
~TrueTypeFont() override
Definition: sft.cxx:1250
sal_uInt8 * ptr
Definition: sft.hxx:740
sal_Int32 fsize
Definition: sft.hxx:739
bool hasTable(sal_uInt32 ord) const override
Definition: sft.hxx:748
TrueTypeFont(const char *pFileName=nullptr, const FontCharMapRef xCharMap=nullptr)
Definition: sft.cxx:1242
sal_uInt32 ntables
Definition: sft.hxx:741
SFErrCodes open(sal_uInt32 facenum)
Definition: sft.cxx:1342
std::array< struct TTFontTable_, NUM_TAGS > m_aTableList
Definition: sft.hxx:736
Creates a new empty 'cmap' table.
Definition: ttcr.hxx:240
Creates a new empty 'glyf' table.
Definition: ttcr.hxx:211
Creates a new 'head' table for a TrueType font.
Definition: ttcr.hxx:143
Creates a new 'hhea' table for a TrueType font.
Definition: ttcr.hxx:163
Creates a new 'maxp' table based on an existing maxp table.
Definition: ttcr.hxx:198
Creates a new 'name' table.
Definition: ttcr.hxx:262
Creates a new 'post' table of one of the supported formats.
Definition: ttcr.hxx:275
bool close
float y
float x
float z
TOOLS_DLLPUBLIC fix16_t fix16_mul(fix16_t inArg0, fix16_t inArg1)
TOOLS_DLLPUBLIC fix16_t fix16_div(fix16_t inArg0, fix16_t inArg1)
sal_Int16 nValue
bool HasMicrosoftSymbolCmap(const unsigned char *pCmap, int nLength)
Definition: fontcharmap.cxx:62
@ TYPE1_PFB
PSType1 Postscript Font Binary.
@ CFF_FONT
CFF-container with PSType2 glyphs.
@ SFNT_TTF
SFNT container with TrueType glyphs.
uint32_t sal_GlyphId
Definition: glyphid.hxx:24
SFErrCodes CreateTTFromTTGlyphs(AbstractTrueTypeFont *ttf, std::vector< sal_uInt8 > &rOutBuffer, sal_uInt16 const *glyphArray, sal_uInt8 const *encoding, int nGlyphs)
Generates a new TrueType font and dumps it to outf file.
Definition: sft.cxx:1746
void GetTTGlobalFontInfo(AbstractTrueTypeFont *ttf, TTGlobalFontInfo *info)
Returns global font information about the TrueType font.
Definition: sft.cxx:2281
SFErrCodes OpenTTFontBuffer(const void *pBuffer, sal_uInt32 nLen, sal_uInt32 facenum, TrueTypeFont **ttf, const FontCharMapRef xCharMap)
TrueTypeFont constructor.
Definition: sft.cxx:1194
int CountTTCFonts(const char *fname)
Get the number of fonts contained in a TrueType collection.
Definition: sft.cxx:1074
int GetTTGlyphPoints(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< ControlPoint > &pointArray)
Extracts TrueType control points, and stores them in an allocated array pointed to by *pointArray.
Definition: sft.cxx:1482
bool GetTTGlobalFontHeadInfo(const AbstractTrueTypeFont *ttf, int &xMin, int &yMin, int &xMax, int &yMax, sal_uInt16 &macStyle)
Returns part of the head table info, normally collected by GetTTGlobalFontInfo.
Definition: sft.cxx:2263
int GetTTGlyphComponents(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< sal_uInt32 > &glyphlist)
For a specified glyph adds all component glyphs IDs to the list and return their number.
Definition: sft.cxx:1487
void CloseTTFont(TrueTypeFont *ttf)
TrueTypeFont destructor.
Definition: sft.cxx:1258
std::unique_ptr< GlyphData > GetTTRawGlyphData(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID)
Extracts raw glyph data from the 'glyf' table and returns it in an allocated GlyphData structure.
Definition: sft.cxx:2332
SFErrCodes CreateT42FromTTGlyphs(TrueTypeFont *ttf, SvStream *outf, const char *psname, sal_uInt16 const *glyphArray, sal_uInt8 *encoding, int nGlyphs)
Generates a new PostScript Type42 font and dumps it to outf file.
Definition: sft.cxx:2131
void GetTTNameRecords(AbstractTrueTypeFont const *ttf, std::vector< NameRecord > &nr)
Extracts all Name Records from the font and stores them in an allocated array of NameRecord structs.
Definition: sft.cxx:2422
SFErrCodes OpenTTFontFile(const char *fname, sal_uInt32 facenum, TrueTypeFont **ttf, const FontCharMapRef xCharMap)
TrueTypeFont constructor.
Definition: sft.cxx:1126
SFErrCodes CreateT3FromTTGlyphs(TrueTypeFont *ttf, SvStream *outf, const char *fname, sal_uInt16 const *glyphArray, sal_uInt8 *encoding, int nGlyphs, int wmode)
Generates a new PostScript Type 3 font and dumps it to outf file.
Definition: sft.cxx:1564
const char * name
sal_Int32 nIndex
void * p
sal_Int64 n
uno_Any a
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
#define SAL_N_ELEMENTS(arr)
std::unique_ptr< sal_Int32[]> pData
@ table
size
tDoubleVectorPair cleanup(const css::uno::Sequence< double > &rXValues, const css::uno::Sequence< double > &rYValues, Pred aPred)
int i
index
m
std::enable_if< std::is_signed< T >::value, bool >::type checked_add(T a, T b, T &result)
constexpr T saturating_add(T a, T b)
constexpr int HHEA_ascender_offset
Definition: sft.hxx:313
constexpr int OS2_ulCodePageRange1_offset
Definition: sft.hxx:281
constexpr int OS2_ulUnicodeRange4_offset
Definition: sft.hxx:274
static void GetMetrics(AbstractTrueTypeFont const *ttf, sal_uInt32 glyphID, TTGlyphMetrics *metrics)
Definition: sft.cxx:265
constexpr int OS2_fsType_offset
Definition: sft.hxx:268
constexpr sal_uInt32 T_ttcf
Definition: sft.hxx:432
constexpr int O_vmtx
Definition: sft.hxx:681
constexpr int O_prep
Definition: sft.hxx:685
constexpr int O_fpgm
Definition: sft.hxx:686
constexpr int HHEA_lineGap_offset
Definition: sft.hxx:315
constexpr int OS2_typoDescender_offset
Definition: sft.hxx:277
static char toHex(sal_uInt8 nIndex)
Definition: sft.cxx:210
constexpr int HEAD_lowestRecPPEM_offset
Definition: sft.hxx:376
constexpr int OS2_Legacy_length
Definition: sft.hxx:262
constexpr int OS2_usWeightClass_offset
Definition: sft.hxx:266
constexpr int HEAD_fontRevision_offset
Definition: sft.hxx:366
constexpr sal_uInt32 T_post
Definition: sft.hxx:447
constexpr sal_uInt32 T_cvt
Definition: sft.hxx:448
constexpr sal_uInt32 T_vhea
Definition: sft.hxx:444
static OString nameExtract(const sal_uInt8 *name, int nTableSize, int n, int dbFlag, OUString *ucs2result)
Definition: sft.cxx:874
constexpr sal_uInt32 T_loca
Definition: sft.hxx:439
constexpr int HEAD_majorVersion_offset
Definition: sft.hxx:365
constexpr int OS2_winAscent_offset
Definition: sft.hxx:279
constexpr int HEAD_yMax_offset
Definition: sft.hxx:374
constexpr int HHEA_caretSlopeRise_offset
Definition: sft.hxx:316
constexpr sal_uInt32 T_otto
Definition: sft.hxx:433
constexpr int GLYF_xMax_offset
Definition: sft.hxx:428
SFErrCodes
Return value of OpenTTFont() and CreateT3FromTTGlyphs()
Definition: sft.hxx:65
@ FontNo
incorrect logical font number of a TTC font
@ TtFormat
incorrect TrueType font format
@ Memory
memory allocation error
@ FileIo
file I/O error
@ GlyphNum
incorrect number of glyphs
@ BadFile
file not found
@ BadArg
incorrect arguments
constexpr int OS2_typoAscender_offset
Definition: sft.hxx:276
struct TTGlobalFontInfo_ TTGlobalFontInfo
Return value of GetTTGlobalFontInfo()
Definition: salgdi.hxx:61
constexpr int OS2_typoLineGap_offset
Definition: sft.hxx:278
constexpr sal_uInt32 T_true
Definition: sft.hxx:431
constexpr sal_uInt32 T_prep
Definition: sft.hxx:449
constexpr sal_uInt32 T_glyf
Definition: sft.hxx:437
constexpr int O_OS2
Definition: sft.hxx:682
constexpr int O_vhea
Definition: sft.hxx:680
const char *const modextra
Definition: sft.cxx:65
constexpr int OS2_ulUnicodeRange3_offset
Definition: sft.hxx:273
static F16Dot16 fixedMul(F16Dot16 a, F16Dot16 b)
Definition: sft.cxx:186
static int XUnits(int unitsPerEm, int n)
Definition: sft.cxx:205
constexpr int GLYF_numberOfContours_offset
Definition: sft.hxx:425
constexpr int O_hhea
Definition: sft.hxx:677
const char *const modname
Definition: sft.cxx:63
constexpr int OS2_ulCodePageRange2_offset
Definition: sft.hxx:282
constexpr sal_uInt32 T_hhea
Definition: sft.hxx:441
constexpr int OS2_panoseNbBytes_offset
Definition: sft.hxx:270
constexpr int NUM_TAGS
Definition: sft.hxx:688
static void append(std::bitset< N > &rSet, size_t const nOffset, sal_uInt32 const nValue)
Definition: sft.cxx:2491
constexpr int OS2_ulUnicodeRange2_offset
Definition: sft.hxx:272
const char *const modver
Definition: sft.cxx:64
constexpr int HEAD_created_offset
Definition: sft.hxx:370
constexpr int GLYF_yMax_offset
Definition: sft.hxx:429
constexpr int HHEA_caretSlopeRun_offset
Definition: sft.hxx:317
static void DumpSfnts(SvStream *outf, sal_uInt8 *sfntP, sal_uInt32 sfntLen)
Definition: sft.cxx:2030
constexpr int O_cmap
Definition: sft.hxx:679
constexpr int HEAD_flags_offset
Definition: sft.hxx:368
static void GetNames(AbstractTrueTypeFont *t)
Definition: sft.cxx:959
constexpr int HEAD_unitsPerEm_offset
Definition: sft.hxx:369
constexpr int O_post
Definition: sft.hxx:683
bool getTTCoverage(std::optional< std::bitset< UnicodeCoverage::MAX_UC_ENUM > > &rUnicodeRange, std::optional< std::bitset< CodePageCoverage::MAX_CP_ENUM > > &rCodePageRange, const unsigned char *pTable, size_t nLength)
Definition: sft.cxx:2499
constexpr int O_loca
Definition: sft.hxx:675
constexpr int HEAD_xMax_offset
Definition: sft.hxx:373
constexpr sal_uInt32 T_head
Definition: sft.hxx:438
static sal_Int16 GetInt16(const sal_uInt8 *ptr, size_t offset)
Definition: sft.cxx:144
constexpr int HEAD_yMin_offset
Definition: sft.hxx:372
constexpr int HEAD_fontDirectionHint_offset
Definition: sft.hxx:377
constexpr int HEAD_xMin_offset
Definition: sft.hxx:371
static sal_uInt32 GetUInt32(const sal_uInt8 *ptr, size_t offset)
Definition: sft.cxx:175
constexpr int O_CFF
Definition: sft.hxx:687
constexpr int POST_isFixedPitch_offset
Definition: sft.hxx:334
constexpr int POST_underlinePosition_offset
Definition: sft.hxx:332
constexpr int GLYF_yMin_offset
Definition: sft.hxx:427
static F16Dot16 fixedDiv(F16Dot16 a, F16Dot16 b)
Definition: sft.cxx:191
bool CreateTTFfontSubset(vcl::AbstractTrueTypeFont &rTTF, std::vector< sal_uInt8 > &rOutBuffer, const sal_GlyphId *pGlyphIds, const sal_uInt8 *pEncoding, const int nOrigGlyphCount, FontSubsetInfo &rInfo)
Definition: sft.cxx:1912
constexpr int OS2_V1_length
Definition: sft.hxx:264
constexpr int POST_italicAngle_offset
Definition: sft.hxx:331
constexpr sal_uInt32 T_maxp
Definition: sft.hxx:436
constexpr sal_uInt32 T_OS2
Definition: sft.hxx:446
constexpr sal_uInt32 T_CFF
Definition: sft.hxx:451
constexpr int GLYF_xMin_offset
Definition: sft.hxx:426
constexpr int HEAD_indexToLocFormat_offset
Definition: sft.hxx:378
static F16Dot16 fromF2Dot14(sal_Int16 n)
Definition: sft.cxx:468
constexpr sal_uInt32 T_hmtx
Definition: sft.hxx:442
constexpr sal_uInt32 T_name
Definition: sft.hxx:440
constexpr int O_maxp
Definition: sft.hxx:672
constexpr int HEAD_macStyle_offset
Definition: sft.hxx:375
static int GetTTGlyphOutline(AbstractTrueTypeFont *, sal_uInt32, std::vector< ControlPoint > &, TTGlyphMetrics *, std::vector< sal_uInt32 > *)
Definition: sft.cxx:696
static sal_uInt16 GetUInt16(const sal_uInt8 *ptr, size_t offset)
Definition: sft.cxx:154
constexpr sal_uInt32 T_fpgm
Definition: sft.hxx:450
static sal_Int32 GetInt32(const sal_uInt8 *ptr, size_t offset)
Definition: sft.cxx:164
static int BSplineToPSPath(ControlPoint const *srcA, int srcCount, std::unique_ptr< PSPathElement[]> &path)
Definition: sft.cxx:747
constexpr int O_cvt
Definition: sft.hxx:684
constexpr int POST_underlineThickness_offset
Definition: sft.hxx:333
constexpr int HHEA_descender_offset
Definition: sft.hxx:314
static int GetCompoundTTOutline(AbstractTrueTypeFont *ttf, sal_uInt32 glyphID, std::vector< ControlPoint > &pointArray, TTGlyphMetrics *metrics, std::vector< sal_uInt32 > &glyphlist)
Definition: sft.cxx:474
constexpr int OS2_ulUnicodeRange1_offset
Definition: sft.hxx:271
constexpr int HEAD_Length
Definition: sft.hxx:363
static int findname(const sal_uInt8 *name, sal_uInt16 n, sal_uInt16 platformID, sal_uInt16 encodingID, sal_uInt16 languageID, sal_uInt16 nameID)
Definition: sft.cxx:918
constexpr int O_name
Definition: sft.hxx:676
constexpr int O_glyf
Definition: sft.hxx:673
constexpr int OS2_panose_offset
Definition: sft.hxx:269
constexpr int O_head
Definition: sft.hxx:674
constexpr sal_uInt32 T_cmap
Definition: sft.hxx:443
static int GetSimpleTTOutline(AbstractTrueTypeFont const *ttf, sal_uInt32 glyphID, std::vector< ControlPoint > &pointArray, TTGlyphMetrics *metrics)
Definition: sft.cxx:298
constexpr sal_uInt32 T_vmtx
Definition: sft.hxx:445
constexpr int OS2_winDescent_offset
Definition: sft.hxx:280
static F16Dot16 fixedMulDiv(F16Dot16 a, F16Dot16 b, F16Dot16 c)
Definition: sft.cxx:198
constexpr int OS2_usWidthClass_offset
Definition: sft.hxx:267
@ WE_HAVE_A_TWO_BY_TWO
Definition: sft.hxx:112
@ ARG_1_AND_2_ARE_WORDS
Definition: sft.hxx:106
@ WE_HAVE_A_SCALE
Definition: sft.hxx:109
@ MORE_COMPONENTS
Definition: sft.hxx:110
@ WE_HAVE_AN_X_AND_Y_SCALE
Definition: sft.hxx:111
@ USE_MY_METRICS
Definition: sft.hxx:114
@ ARGS_ARE_XY_VALUES
Definition: sft.hxx:107
constexpr int O_hmtx
Definition: sft.hxx:678
sal_Int32 F16Dot16
fixed: 16.16
Definition: sft.hxx:61
constexpr int OS2_V0_length
Definition: sft.hxx:263
sal_Int32 h
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
int TestFontSubset(const void *data, sal_uInt32 size)
Definition: sft.cxx:2526
Sun Font Tools.
static SfxItemSet & rSet
ControlPoint structure used by GetTTGlyphPoints()
Definition: sft.hxx:181
sal_Int16 y
Y coordinate in EmSquare units
Definition: sft.hxx:187
sal_Int16 x
X coordinate in EmSquare units
Definition: sft.hxx:186
sal_uInt32 flags
00000000 00000000 e0000000 bbbbbbbb
Definition: sft.hxx:182
Structure used by the TrueType Creator and GetRawGlyphData()
Definition: sft.hxx:126
Return value of GetTTGlobalFontInfo()
Definition: sft.hxx:150
int italicAngle
in counter-clockwise degrees * 65536
Definition: sft.hxx:160
OString family
family name
Definition: sft.hxx:151
int ascender
typographic ascent.
Definition: sft.hxx:165
int typoDescender
OS/2 portable typographic descender
Definition: sft.hxx:170
int yMin
global bounding box: yMin
Definition: sft.hxx:162
int winAscent
ascender metric for Windows
Definition: sft.hxx:172
int xMin
global bounding box: xMin
Definition: sft.hxx:161
int typoAscender
OS/2 portable typographic ascender
Definition: sft.hxx:169
sal_uInt8 panose[10]
PANOSE classification number
Definition: sft.hxx:175
int width
value of WidthClass or 0 if can't be determined
Definition: sft.hxx:158
int typoLineGap
OS/2 portable typographic line gap
Definition: sft.hxx:171
int weight
value of WeightClass or 0 if can't be determined
Definition: sft.hxx:157
int xMax
global bounding box: xMax
Definition: sft.hxx:163
sal_uInt32 typeFlags
type flags (copyright bits)
Definition: sft.hxx:176
OUString usubfamily
subfamily name UCS2
Definition: sft.hxx:154
int winDescent
descender metric for Windows
Definition: sft.hxx:173
OString psname
PostScript name
Definition: sft.hxx:155
int linegap
typographic line gap. Negative values are treated as zero in Win 3.1, System 6 and System 7.
Definition: sft.hxx:167
int descender
typographic descent.
Definition: sft.hxx:166
OUString ufamily
family name UCS2
Definition: sft.hxx:152
bool microsoftSymbolEncoded
true: MS symbol encoded
Definition: sft.hxx:174
int pitch
0: proportional font, otherwise: monospaced
Definition: sft.hxx:159
sal_uInt16 macStyle
macstyle bits from 'HEAD' table
Definition: sft.hxx:156
OString subfamily
subfamily name
Definition: sft.hxx:153
int yMax
global bounding box: yMax
Definition: sft.hxx:164
TrueType font creator.
unsigned char sal_uInt8
#define SAL_MAX_UINT16
signed char sal_Int8
Any result
ResultType type
std::unique_ptr< char[]> aBuffer
sal_Int32 nLength