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 .
25 #include <fontsubset.hxx>
27 #include <o3tl/safeint.hxx>
28 #include <strhelper.hxx>
29 #include <sal/log.hxx>
32 typedef sal_uInt16 U16
;
33 typedef sal_Int64 S64
;
35 typedef double RealType
;
36 typedef RealType ValType
;
38 static const char* pStringIds
[] = {
39 /*0*/ ".notdef", "space", "exclam", "quotedbl",
40 "numbersign", "dollar", "percent", "ampersand",
41 "quoteright", "parenleft", "parenright", "asterisk",
42 "plus", "comma", "hyphen", "period",
43 /*16*/ "slash", "zero", "one", "two",
44 "three", "four", "five", "six",
45 "seven", "eight", "nine", "colon",
46 "semicolon", "less", "equal", "greater",
47 /*32*/ "question", "at", "A", "B",
51 /*48*/ "O", "P", "Q", "R",
54 "bracketleft", "backslash", "bracketright", "asciicircum",
55 /*64*/ "underscore", "quoteleft", "a", "b",
59 /*80*/ "o", "p", "q", "r",
62 "braceleft", "bar", "braceright", "asciitilde",
63 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
64 "yen", "florin", "section", "currency",
65 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
66 "guilsinglright", "fi", "fl", "endash",
67 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
68 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
69 "guillemotright", "ellipsis", "perthousand", "questiondown",
70 "grave", "acute", "circumflex", "tilde",
71 /*128*/ "macron", "breve", "dotaccent", "dieresis",
72 "ring", "cedilla", "hungarumlaut", "ogonek",
73 "caron", "emdash", "AE", "ordfeminine",
74 "Lslash", "Oslash", "OE", "ordmasculine",
75 /*144*/ "ae", "dotlessi", "lslash", "oslash",
76 "oe", "germandbls", "onesuperior", "logicalnot",
77 "mu", "trademark", "Eth", "onehalf",
78 "plusminus", "Thorn", "onequarter", "divide",
79 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
80 "twosuperior", "registered", "minus", "eth",
81 "multiply", "threesuperior", "copyright", "Aacute",
82 "Acircumflex", "Adieresis", "Agrave", "Aring",
83 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
84 "Edieresis", "Egrave", "Iacute", "Icircumflex",
85 "Idieresis", "Igrave", "Ntilde", "Oacute",
86 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
87 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
88 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
89 "aacute", "acircumflex", "adieresis", "agrave",
90 "aring", "atilde", "ccedilla", "eacute",
91 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
92 "icircumflex", "idieresis", "igrave", "ntilde",
93 "oacute", "ocircumflex", "odieresis", "ograve",
94 "otilde", "scaron", "uacute", "ucircumflex",
95 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
96 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
97 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
98 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
99 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
100 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
101 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
102 "questionsmall", "asuperior", "bsuperior", "centsuperior",
103 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
104 "msuperior", "nsuperior", "osuperior", "rsuperior",
105 "ssuperior", "tsuperior", "ff", "ffi",
106 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
107 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
108 "Csmall", "Dsmall", "Esmall", "Fsmall",
109 "Gsmall", "Hsmall", "Ismall", "Jsmall",
110 "Ksmall", "Lsmall", "Msmall", "Nsmall",
111 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
112 "Ssmall", "Tsmall", "Usmall", "Vsmall",
113 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
114 "colonmonetary", "onefitted", "rupia", "Tildesmall",
115 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
116 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
117 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
118 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
119 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
120 "onethird", "twothirds", "zerosuperior", "foursuperior",
121 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
122 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
123 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
124 "seveninferior", "eightinferior", "nineinferior", "centinferior",
125 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
126 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
127 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
128 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
129 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
130 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
131 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
132 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
133 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
134 "001.001", "001.002", "001.003", "Black",
135 /*384*/ "Bold", "Book", "Light", "Medium",
136 "Regular", "Roman", "Semibold"
139 // TOP DICT keywords (also covers PRIV DICT keywords)
140 static const char* pDictOps
[] = {
141 "sVersion", "sNotice", "sFullName", "sFamilyName",
142 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
143 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
144 "xESC", "nUniqueID", "aXUID", "nCharset",
145 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
146 "nDefaultWidthX", "nNominalWidthX", nullptr, nullptr,
147 nullptr, nullptr, nullptr, nullptr,
148 "shortint", "longint", "BCD", nullptr
151 // TOP DICT escapes (also covers PRIV DICT escapes)
152 static const char* pDictEscs
[] = {
153 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
154 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
155 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
156 "dStemSnapH", "dStemSnapV", "bForceBold", nullptr,
157 nullptr, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
158 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
159 nullptr, nullptr, nullptr, nullptr,
160 nullptr, nullptr, "rROS", "nCIDFontVersion",
161 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
162 "nFDArray", "nFDSelect", "sFontName"
171 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
172 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CLOSEPATH
=9,
173 CALLSUBR
=10, RETURN
=11, T1ESC
=12, HSBW
=13,
174 ENDCHAR
=14, RMOVETO
=21, HMOVETO
=22, VHCURVETO
=30,
180 DOTSECTION
=0, VSTEM3
=1, HSTEM3
=2, SEAC
=6,
181 SBW
=7, ABS
=9, ADD
=10, SUB
=11,
182 DIV
=12, CALLOTHERSUBR
=16, POP
=17, SETCURRENTPOINT
=33
190 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
191 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CALLSUBR
=10,
192 RETURN
=11, T2ESC
=12, ENDCHAR
=14, HSTEMHM
=18,
193 HINTMASK
=19, CNTRMASK
=20, RMOVETO
=21, HMOVETO
=22,
194 VSTEMHM
=23, RCURVELINE
=24, RLINECURVE
=25, VVCURVETO
=26,
195 HHCURVETO
=27, SHORTINT
=28, CALLGSUBR
=29, VHCURVETO
=30,
201 AND
=3, OR
=4, NOT
=5, ABS
=9,
202 ADD
=10, SUB
=11, DIV
=12, NEG
=14,
203 EQ
=15, DROP
=18, PUT
=20, GET
=21,
204 IFELSE
=22, RANDOM
=23, MUL
=24, SQRT
=26,
205 DUP
=27, EXCH
=28, INDEX
=29, ROLL
=30,
206 HFLEX
=34, FLEX
=35, HFLEX1
=36, FLEX1
=37
212 explicit CffGlobal();
220 int mnGlobalSubrBase
;
221 int mnGlobalSubrCount
;
222 int mnGlobalSubrBias
;
227 std::vector
<ValType
> maFontBBox
;
228 std::vector
<ValType
> maFontMatrix
;
244 ValType maNominalWidth
;
245 ValType maDefaultWidth
;
247 // ATM hinting related values
250 std::vector
<ValType
> maStemSnapH
;
251 std::vector
<ValType
> maStemSnapV
;
252 std::vector
<ValType
> maBlueValues
;
253 std::vector
<ValType
> maOtherBlues
;
254 std::vector
<ValType
> maFamilyBlues
;
255 std::vector
<ValType
> maFamilyOtherBlues
;
256 RealType mfBlueScale
;
257 RealType mfBlueShift
;
259 RealType mfExpFactor
;
264 class CffSubsetterContext
268 static const int NMAXSTACK
= 48; // see CFF.appendixB
269 static const int NMAXHINTS
= 2*96; // see CFF.appendixB
270 static const int NMAXTRANS
= 32; // see CFF.appendixB
272 explicit CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
);
274 bool initialCffRead();
275 void emitAsType1( class Type1Emitter
&,
276 const sal_GlyphId
* pGlyphIds
, const U8
* pEncoding
,
277 sal_Int32
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& );
280 int convert2Type1Ops( CffLocal
*, const U8
* pType2Ops
, int nType2Len
, U8
* pType1Ops
);
281 void convertOneTypeOp();
282 void convertOneTypeEsc();
283 void callType2Subr( bool bGlobal
, int nSubrNumber
);
284 sal_Int32
getReadOfs() const { return static_cast<sal_Int32
>(mpReadPtr
- mpBasePtr
);}
295 sal_Int32 mnCntrMask
;
297 int seekIndexData( int nIndexBase
, int nDataIndex
);
298 void seekIndexEnd( int nIndexBase
);
300 CffLocal maCffLocal
[256];
301 CffLocal
* mpCffLocal
;
304 RealType
readRealVal();
305 const char* getString( int nStringID
);
306 int getFDSelect( int nGlyphIndex
) const;
307 int getGlyphSID( int nGlyphIndex
) const;
308 const char* getGlyphName( int nGlyphIndex
);
311 void writeType1Val( ValType
);
312 void writeTypeOp( int nTypeOp
);
313 void writeTypeEsc( int nTypeOp
);
314 void writeCurveTo( int nStackPos
, int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
);
315 void pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
=0);
316 void popAll2Write( int nTypeOp
);
318 public: // TODO: is public really needed?
319 // accessing the value stack
320 // TODO: add more checks
321 void push( ValType nVal
) { mnValStack
[ mnStackIdx
++] = nVal
;}
322 ValType
popVal() { return ((mnStackIdx
>0) ? mnValStack
[ --mnStackIdx
] : 0);}
323 ValType
getVal( int nIndex
) const { return mnValStack
[ nIndex
];}
325 int size() const { return mnStackIdx
;}
326 void clear() { mnStackIdx
= 0;}
328 // accessing the charstring hints
329 void addHints( bool bVerticalHints
);
331 // accessing other charstring specifics
332 void updateWidth( bool bUseFirstVal
);
335 // typeop execution context
337 ValType mnValStack
[ NMAXSTACK
+4];
338 ValType mnTransVals
[ NMAXTRANS
];
342 ValType mnHintStack
[ NMAXHINTS
];
349 CffSubsetterContext::CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
)
350 : mpBasePtr( pBasePtr
)
351 , mpBaseEnd( pBasePtr
+nBaseLen
)
354 , mpWritePtr(nullptr)
356 , mbIgnoreHints(false)
366 // setCharStringType( 1);
367 // TODO: new CffLocal[ mnFDAryCount];
368 mpCffLocal
= &maCffLocal
[0];
371 inline int CffSubsetterContext::popInt()
373 const ValType aVal
= popVal();
374 const int nInt
= static_cast<int>(aVal
);
375 assert( nInt
== aVal
);
379 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal
)
381 // the first value is not a hint but the charwidth
386 maCharWidth
= mpCffLocal
->maNominalWidth
+ mnValStack
[0];
387 // remove bottom stack entry
389 for( int i
= 0; i
< mnStackIdx
; ++i
)
390 mnValStack
[ i
] = mnValStack
[ i
+1];
392 maCharWidth
= mpCffLocal
->maDefaultWidth
;
396 void CffSubsetterContext::addHints( bool bVerticalHints
)
398 // the first charstring value may a charwidth instead of a charwidth
399 updateWidth( (mnStackIdx
& 1) != 0);
400 // return early (e.g. no implicit hints for hintmask)
404 // copy the remaining values to the hint arrays
405 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
406 if( mnStackIdx
& 1) --mnStackIdx
;//#######
407 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
409 assert( (mnHintSize
+ mnStackIdx
) <= 2*NMAXHINTS
);
411 ValType nHintOfs
= 0;
412 for( int i
= 0; i
< mnStackIdx
; ++i
) {
413 nHintOfs
+= mnValStack
[ i
];
414 mnHintStack
[ mnHintSize
++] = nHintOfs
;
418 mnHorzHintSize
= mnHintSize
;
420 // clear all values from the stack
424 void CffSubsetterContext::readDictOp()
426 const U8 c
= *mpReadPtr
;
428 int nOpId
= *(mpReadPtr
++);
429 const char* pCmdName
= nullptr;
431 pCmdName
= pDictOps
[nOpId
];
433 const U8 nExtId
= *(mpReadPtr
++);
435 pCmdName
= pDictEscs
[nExtId
];
436 nOpId
= 900 + nExtId
;
439 if (!pCmdName
) // skip reserved operators
442 //TODO: if( nStackIdx > 0)
445 default: SAL_WARN("vcl.fonts", "unsupported DictOp.type='" << *pCmdName
<< "'."); break;
449 case 915: mpCffLocal
->mbForceBold
= nInt
; break; // "ForceBold"
450 default: break; // TODO: handle more boolean dictops?
453 case 'n': { // dict-op number
454 ValType nVal
= popVal();
455 nInt
= static_cast<int>(nVal
);
457 case 10: mpCffLocal
->maStemStdHW
= nVal
; break; // "StdHW"
458 case 11: mpCffLocal
->maStemStdVW
= nVal
; break; // "StdVW"
459 case 15: mnCharsetBase
= nInt
; break; // "charset"
460 case 16: break; // "nEncoding"
461 case 17: mnCharStrBase
= nInt
; break; // "nCharStrings"
462 case 19: mpCffLocal
->mnLocalSubrOffs
= nInt
; break;// "nSubrs"
463 case 20: mpCffLocal
->maDefaultWidth
= nVal
; break; // "defaultWidthX"
464 case 21: mpCffLocal
->maNominalWidth
= nVal
; break; // "nominalWidthX"
465 case 909: mpCffLocal
->mfBlueScale
= nVal
; break; // "BlueScale"
466 case 910: mpCffLocal
->mfBlueShift
= nVal
; break; // "BlueShift"
467 case 911: mpCffLocal
->mfBlueFuzz
= nVal
; break; // "BlueFuzz"
468 case 912: mpCffLocal
->mfExpFactor
= nVal
; break; // "ExpansionFactor"
469 case 917: mpCffLocal
->mnLangGroup
= nInt
; break; // "LanguageGroup"
470 case 936: mnFontDictBase
= nInt
; break; // "nFDArray"
471 case 937: mnFDSelectBase
= nInt
; break; // "nFDSelect"
472 default: break; // TODO: handle more numeric dictops?
477 case 5: maFontBBox
.clear(); break; // "FontBBox"
478 case 907: maFontMatrix
.clear(); break; // "FontMatrix"
479 default: break; // TODO: reset other arrays?
481 for( int i
= 0; i
< size(); ++i
) {
482 ValType nVal
= getVal(i
);
484 case 5: maFontBBox
.push_back( nVal
); break; // "FontBBox"
485 case 907: maFontMatrix
.push_back( nVal
); break; // "FontMatrix"
486 default: break; // TODO: handle more array dictops?
491 case 'd': { // delta array
493 for( int i
= 0; i
< size(); ++i
) {
496 case 6: mpCffLocal
->maBlueValues
.push_back( nVal
); break; // "BlueValues"
497 case 7: mpCffLocal
->maOtherBlues
.push_back( nVal
); break; // "OtherBlues"
498 case 8: mpCffLocal
->maFamilyBlues
.push_back( nVal
); break; // "FamilyBlues"
499 case 9: mpCffLocal
->maFamilyOtherBlues
.push_back( nVal
); break;// "FamilyOtherBlues"
500 case 912: mpCffLocal
->maStemSnapH
.push_back( nVal
); break; // "StemSnapH"
501 case 913: mpCffLocal
->maStemSnapV
.push_back( nVal
); break; // "StemSnapV"
502 default: break; // TODO: handle more delta-array dictops?
507 case 's': // stringid (SID)
510 case 2: mnFullNameSID
= nInt
; break; // "FullName"
511 case 3: break; // "FamilyName"
512 case 938: mnFontNameSID
= nInt
; break; // "FontName"
513 default: break; // TODO: handle more string dictops?
516 case 'P': // private dict
517 mpCffLocal
->mnPrivDictBase
= popInt();
518 mpCffLocal
->mnPrivDictSize
= popInt();
520 case 'r': { // ROS operands
521 popInt(); // TODO: use sid1
522 popInt(); // TODO: use sid2
526 case 't': // CharstringType
530 } else if( (c
>= 32) || (c
== 28) ) {
533 } else if( c
== 29 ) { // longint
534 ++mpReadPtr
; // skip 29
535 sal_Int32 nS32
= mpReadPtr
[0] << 24;
536 nS32
+= mpReadPtr
[1] << 16;
537 nS32
+= mpReadPtr
[2] << 8;
538 nS32
+= mpReadPtr
[3] << 0;
540 ValType nVal
= static_cast<ValType
>(nS32
);
542 } else if( c
== 30) { // real number
543 ++mpReadPtr
; // skip 30
544 const RealType fReal
= readRealVal();
545 // push value onto stack
546 ValType nVal
= fReal
;
551 void CffSubsetterContext::read2push()
555 const U8
*& p
= mpReadPtr
;
558 sal_Int16 nS16
= (p
[1] << 8) + p
[2];
561 } else if( c
<= 246 ) { // -107..+107
562 aVal
= static_cast<ValType
>(p
[0] - 139);
564 } else if( c
<= 250 ) { // +108..+1131
565 aVal
= static_cast<ValType
>(((p
[0] << 8) + p
[1]) - 63124);
567 } else if( c
<= 254 ) { // -108..-1131
568 aVal
= static_cast<ValType
>(64148 - ((p
[0] << 8) + p
[1]));
570 } else /*if( c == 255)*/ { // Fixed16.16
571 int nS32
= (p
[1] << 24) + (p
[2] << 16) + (p
[3] << 8) + p
[4];
572 if( (sizeof(nS32
) != 2) && (nS32
& (1U<<31)))
573 nS32
|= (~0U) << 31; // assuming 2s complement
574 aVal
= static_cast<ValType
>(nS32
* (1.0 / 0x10000));
581 void CffSubsetterContext::writeType1Val( ValType aVal
)
583 U8
* pOut
= mpWritePtr
;
585 int nInt
= static_cast<int>(aVal
);
586 if( (nInt
>= -107) && (nInt
<= +107)) {
587 *(pOut
++) = static_cast<U8
>(nInt
+ 139); // -107..+107
588 } else if( (nInt
>= -1131) && (nInt
<= +1131)) {
590 nInt
+= 63124; // +108..+1131
592 nInt
= 64148 - nInt
; // -108..-1131
593 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
594 *(pOut
++) = static_cast<U8
>(nInt
);
596 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
598 *(pOut
++) = static_cast<U8
>(nInt
>> 24);
599 *(pOut
++) = static_cast<U8
>(nInt
>> 16);
600 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
601 *(pOut
++) = static_cast<U8
>(nInt
);
607 inline void CffSubsetterContext::writeTypeOp( int nTypeOp
)
609 *(mpWritePtr
++) = static_cast<U8
>(nTypeOp
);
612 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc
)
614 *(mpWritePtr
++) = TYPE1OP::T1ESC
;
615 *(mpWritePtr
++) = static_cast<U8
>(nTypeEsc
);
618 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
)
620 for( int i
= 0; i
< mnStackIdx
;) {
621 for( int j
= 0; j
< nArgsPerTypo
; ++j
) {
622 const ValType aVal
= mnValStack
[i
+j
];
623 writeType1Val( aVal
);
626 writeTypeOp( nTypeOp
);
627 nTypeOp
^= nTypeXor
; // for toggling vlineto/hlineto
632 void CffSubsetterContext::popAll2Write( int nTypeOp
)
634 // pop in reverse order, then write
635 for( int i
= 0; i
< mnStackIdx
; ++i
) {
636 const ValType aVal
= mnValStack
[i
];
637 writeType1Val( aVal
);
640 writeTypeOp( nTypeOp
);
643 void CffSubsetterContext::writeCurveTo( int nStackPos
,
644 int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
)
646 // get the values from the stack
647 const ValType nDX1
= nIX1
? mnValStack
[ nStackPos
+nIX1
] : 0;
648 const ValType nDY1
= nIY1
? mnValStack
[ nStackPos
+nIY1
] : 0;
649 const ValType nDX2
= nIX2
? mnValStack
[ nStackPos
+nIX2
] : 0;
650 const ValType nDY2
= nIY2
? mnValStack
[ nStackPos
+nIY2
] : 0;
651 const ValType nDX3
= nIX3
? mnValStack
[ nStackPos
+nIX3
] : 0;
652 const ValType nDY3
= nIY3
? mnValStack
[ nStackPos
+nIY3
] : 0;
654 // emit the curveto operator and operands
655 // TODO: determine the most efficient curveto operator
656 // TODO: depending on type1op or type2op target
657 writeType1Val( nDX1
);
658 writeType1Val( nDY1
);
659 writeType1Val( nDX2
);
660 writeType1Val( nDY2
);
661 writeType1Val( nDX3
);
662 writeType1Val( nDY3
);
663 writeTypeOp( TYPE1OP::RCURVETO
);
666 void CffSubsetterContext::convertOneTypeOp()
668 const int nType2Op
= *(mpReadPtr
++);
670 int i
, nInt
; // prevent WAE for declarations inside switch cases
678 addHints( nType2Op
== TYPE2OP::VSTEM
);
679 for( i
= 0; i
< mnHintSize
; i
+=2 ) {
680 writeType1Val( mnHintStack
[i
]);
681 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
682 writeTypeOp( nType2Op
);
685 case TYPE2OP::HSTEMHM
:
686 case TYPE2OP::VSTEMHM
:
687 addHints( nType2Op
== TYPE2OP::VSTEMHM
);
689 case TYPE2OP::CNTRMASK
:
690 // TODO: replace cntrmask with vstem3/hstem3
695 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
697 nMaskByte
= *(mpReadPtr
++);
700 if( !(nMaskByte
& nMaskBit
))
702 if( i
>= 8*int(sizeof(mnCntrMask
)))
703 mbIgnoreHints
= true;
706 mnCntrMask
|= (1U << i
);
710 case TYPE2OP::HINTMASK
:
713 sal_Int32 nHintMask
= 0;
714 int nCntrBits
[2] = {0,0};
717 int const MASK_BITS
= 8*sizeof(nHintMask
);
718 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
720 nMaskByte
= *(mpReadPtr
++);
723 if( !(nMaskByte
& nMaskBit
))
726 mbIgnoreHints
= true;
729 nHintMask
|= (1U << i
);
730 nCntrBits
[ i
< mnHorzHintSize
] += (mnCntrMask
>> i
) & 1;
733 mbIgnoreHints
|= (nCntrBits
[0] && (nCntrBits
[0] != 3));
734 mbIgnoreHints
|= (nCntrBits
[1] && (nCntrBits
[1] != 3));
738 for( i
= 0; i
< mnHintSize
; i
+=2) {
739 if(i
>= MASK_BITS
|| !(nHintMask
& (1U << i
)))
741 writeType1Val( mnHintStack
[i
]);
742 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
743 const bool bHorz
= (i
< mnHorzHintSize
);
744 if( !nCntrBits
[ bHorz
])
745 writeTypeOp( bHorz
? TYPE1OP::HSTEM
: TYPE1OP::VSTEM
);
746 else if( !--nCntrBits
[ bHorz
])
747 writeTypeEsc( bHorz
? TYPE1OP::HSTEM3
: TYPE1OP::VSTEM3
);
751 case TYPE2OP::CALLSUBR
:
752 case TYPE2OP::CALLGSUBR
:
755 const bool bGlobal
= (nType2Op
== TYPE2OP::CALLGSUBR
);
756 callType2Subr( bGlobal
, nInt
);
759 case TYPE2OP::RETURN
:
760 // TODO: check that we are in a subroutine
762 case TYPE2OP::VMOVETO
:
763 case TYPE2OP::HMOVETO
:
765 writeTypeOp( TYPE1OP::CLOSEPATH
);
767 updateWidth( size() > 1);
769 pop2MultiWrite( 1, nType2Op
);
771 case TYPE2OP::VLINETO
:
772 case TYPE2OP::HLINETO
:
773 pop2MultiWrite( 1, nType2Op
,
774 TYPE1OP::VLINETO
^ TYPE1OP::HLINETO
);
776 case TYPE2OP::RMOVETO
:
777 // TODO: convert rmoveto to vlineto/hlineto if possible
779 writeTypeOp( TYPE1OP::CLOSEPATH
);
781 updateWidth( size() > 2);
783 pop2MultiWrite( 2, nType2Op
);
785 case TYPE2OP::RLINETO
:
786 // TODO: convert rlineto to vlineto/hlineto if possible
787 pop2MultiWrite( 2, nType2Op
);
789 case TYPE2OP::RCURVETO
:
790 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
791 pop2MultiWrite( 6, nType2Op
);
793 case TYPE2OP::RCURVELINE
:
795 while( (i
+= 6) <= mnStackIdx
)
796 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
798 while( (i
+= 2) <= mnStackIdx
) {
799 writeType1Val( mnValStack
[i
-2]);
800 writeType1Val( mnValStack
[i
-1]);
801 writeTypeOp( TYPE2OP::RLINETO
);
805 case TYPE2OP::RLINECURVE
:
807 while( (i
+= 2) <= mnStackIdx
-6) {
808 writeType1Val( mnValStack
[i
-2]);
809 writeType1Val( mnValStack
[i
-1]);
810 writeTypeOp( TYPE2OP::RLINETO
);
813 while( (i
+= 6) <= mnStackIdx
)
814 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
817 case TYPE2OP::VHCURVETO
:
818 case TYPE2OP::HVCURVETO
:
820 bool bVert
= (nType2Op
== TYPE2OP::VHCURVETO
);
824 nInt
= static_cast<int>(mnValStack
[ --mnStackIdx
]);
825 while( (i
+= 4) <= mnStackIdx
) {
826 // TODO: use writeCurveTo()
827 if( bVert
) writeType1Val( 0 );
828 writeType1Val( mnValStack
[i
-4] );
829 if( !bVert
) writeType1Val( 0);
830 writeType1Val( mnValStack
[i
-3] );
831 writeType1Val( mnValStack
[i
-2] );
832 if( !bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
833 writeType1Val( mnValStack
[i
-1] );
834 if( bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
836 writeTypeOp( TYPE2OP::RCURVETO
);
841 case TYPE2OP::HHCURVETO
:
842 i
= (mnStackIdx
& 1);
843 while( (i
+= 4) <= mnStackIdx
) {
845 writeCurveTo( i
, -4, 0, -3, -2, -1, 0);
847 writeCurveTo( i
, -4, -5, -3, -2, -1, 0);
851 case TYPE2OP::VVCURVETO
:
852 i
= (mnStackIdx
& 1);
853 while( (i
+= 4) <= mnStackIdx
) {
855 writeCurveTo( i
, 0, -4, -3, -2, 0, -1);
857 writeCurveTo( i
, -5, -4, -3, -2, 0, -1);
861 case TYPE2OP::ENDCHAR
:
863 writeTypeOp( TYPE1OP::CLOSEPATH
);
865 updateWidth( size() >= 1);
866 // mbNeedClose = true;
867 writeTypeOp( TYPE1OP::ENDCHAR
);
870 if( ((nType2Op
>= 32) && (nType2Op
<= 255)) || (nType2Op
== 28)) {
874 popAll2Write( nType2Op
);
875 assert(false && "TODO?");
881 void CffSubsetterContext::convertOneTypeEsc()
883 const int nType2Esc
= *(mpReadPtr
++);
884 ValType
* pTop
= &mnValStack
[ mnStackIdx
-1];
888 assert( mnStackIdx
>= 2 );
889 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) & static_cast<int>(pTop
[-1]));
893 assert( mnStackIdx
>= 2 );
894 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) | static_cast<int>(pTop
[-1]));
898 assert( mnStackIdx
>= 1 );
899 pTop
[0] = ValType(pTop
[0] == 0);
902 assert( mnStackIdx
>= 1 );
907 assert( mnStackIdx
>= 1 );
911 assert( mnStackIdx
>= 2 );
916 assert( mnStackIdx
>= 2 );
921 assert( mnStackIdx
>= 2 );
927 assert( mnStackIdx
>= 2 );
933 assert( mnStackIdx
>= 2 );
934 pTop
[0] = ValType(pTop
[0] == pTop
[-1]);
938 assert( mnStackIdx
>= 1 );
942 assert( mnStackIdx
>= 2 );
943 const int nIdx
= static_cast<int>(pTop
[0]);
945 assert( nIdx
< NMAXTRANS
);
946 mnTransVals
[ nIdx
] = pTop
[-1];
951 assert( mnStackIdx
>= 1 );
952 const int nIdx
= static_cast<int>(pTop
[0]);
954 assert( nIdx
< NMAXTRANS
);
955 pTop
[0] = mnTransVals
[ nIdx
];
958 case TYPE2OP::IFELSE
: {
959 assert( mnStackIdx
>= 4 );
960 if( pTop
[-1] > pTop
[0] )
965 case TYPE2OP::RANDOM
:
966 pTop
[+1] = 1234; // TODO
973 assert( mnStackIdx
>= 1 );
977 case TYPE2OP::EXCH
: {
978 assert( mnStackIdx
>= 2 );
979 const ValType nVal
= pTop
[0];
984 case TYPE2OP::INDEX
: {
985 assert( mnStackIdx
>= 1 );
986 const int nVal
= static_cast<int>(pTop
[0]);
988 assert( nVal
< mnStackIdx
-1 );
989 pTop
[0] = pTop
[-1-nVal
];
992 case TYPE2OP::ROLL
: {
993 assert( mnStackIdx
>= 1 );
994 const int nNum
= static_cast<int>(pTop
[0]);
996 assert( nNum
< mnStackIdx
-2 );
997 (void)nNum
; // TODO: implement
998 // TODO: implement: const int nOfs = static_cast<int>(pTop[-1]);
1002 case TYPE2OP::HFLEX1
: {
1003 assert( mnStackIdx
== 9);
1005 writeCurveTo( mnStackIdx
, -9, -8, -7, -6, -5, 0);
1006 writeCurveTo( mnStackIdx
, -4, 0, -3, -2, -1, 0);
1007 // TODO: emulate hflex1 using othersubr call
1012 case TYPE2OP::HFLEX
: {
1013 assert( mnStackIdx
== 7);
1014 ValType
* pX
= &mnValStack
[ mnStackIdx
];
1016 pX
[+1] = -pX
[-5]; // temp: +dy5==-dy2
1017 writeCurveTo( mnStackIdx
, -7, 0, -6, -5, -4, 0);
1018 writeCurveTo( mnStackIdx
, -3, 0, -2, +1, -1, 0);
1019 // TODO: emulate hflex using othersubr call
1024 case TYPE2OP::FLEX
: {
1025 assert( mnStackIdx
== 13 );
1026 writeCurveTo( mnStackIdx
, -13, -12, -11, -10, -9, -8 );
1027 writeCurveTo( mnStackIdx
, -7, -6, -5, -4, -3, -2 );
1028 // ignoring ValType nFlexDepth = mnValStack[ mnStackIdx-1 ];
1032 case TYPE2OP::FLEX1
: {
1033 assert( mnStackIdx
== 11 );
1034 // write the first part of the flex1-hinted curve
1035 writeCurveTo( mnStackIdx
, -11, -10, -9, -8, -7, -6 );
1037 // determine if nD6 is horizontal or vertical
1038 const int i
= mnStackIdx
;
1039 ValType nDeltaX
= mnValStack
[i
-11] + mnValStack
[i
-9] + mnValStack
[i
-7] + mnValStack
[i
-5] + mnValStack
[i
-3];
1040 if( nDeltaX
< 0 ) nDeltaX
= -nDeltaX
;
1041 ValType nDeltaY
= mnValStack
[i
-10] + mnValStack
[i
-8] + mnValStack
[i
-6] + mnValStack
[i
-4] + mnValStack
[i
-2];
1042 if( nDeltaY
< 0 ) nDeltaY
= -nDeltaY
;
1043 const bool bVertD6
= (nDeltaY
> nDeltaX
);
1045 // write the second part of the flex1-hinted curve
1047 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, -1, 0);
1049 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, 0, -1);
1054 SAL_WARN("vcl.fonts", "unhandled type2esc " << nType2Esc
);
1060 void CffSubsetterContext::callType2Subr( bool bGlobal
, int nSubrNumber
)
1062 const U8
* const pOldReadPtr
= mpReadPtr
;
1063 const U8
* const pOldReadEnd
= mpReadEnd
;
1066 nSubrNumber
+= mnGlobalSubrBias
;
1067 seekIndexData( mnGlobalSubrBase
, nSubrNumber
);
1069 nSubrNumber
+= mpCffLocal
->mnLocalSubrBias
;
1070 seekIndexData( mpCffLocal
->mnLocalSubrBase
, nSubrNumber
);
1073 while( mpReadPtr
< mpReadEnd
)
1076 mpReadPtr
= pOldReadPtr
;
1077 mpReadEnd
= pOldReadEnd
;
1080 const int MAX_T1OPS_SIZE
= 81920; // TODO: use dynamic value
1082 int CffSubsetterContext::convert2Type1Ops( CffLocal
* pCffLocal
, const U8
* const pT2Ops
, int nT2Len
, U8
* const pT1Ops
)
1084 mpCffLocal
= pCffLocal
;
1086 // prepare the charstring conversion
1087 mpWritePtr
= pT1Ops
;
1088 U8 aType1Ops
[ MAX_T1OPS_SIZE
];
1090 mpWritePtr
= aType1Ops
;
1091 *const_cast<U8
**>(&pT1Ops
) = mpWritePtr
;
1093 // prepend random seed for T1crypt
1094 *(mpWritePtr
++) = 0x48;
1095 *(mpWritePtr
++) = 0x44;
1096 *(mpWritePtr
++) = 0x55;
1097 *(mpWritePtr
++) = ' ';
1099 // convert the Type2 charstring to Type1
1101 mpReadEnd
= pT2Ops
+ nT2Len
;
1102 // prepend "hsbw" or "sbw"
1103 // TODO: only emit hsbw when charwidth is known
1104 writeType1Val(0); // TODO: aSubsetterContext.getLeftSideBearing();
1105 U8
* pCharWidthPtr
=mpWritePtr
; // need to overwrite that later
1106 // pad out 5 bytes for the char width with default val 1000 (to be
1107 // filled with the actual value below)
1108 *(mpWritePtr
++) = 255;
1109 *(mpWritePtr
++) = static_cast<U8
>(0);
1110 *(mpWritePtr
++) = static_cast<U8
>(0);
1111 *(mpWritePtr
++) = static_cast<U8
>(250);
1112 *(mpWritePtr
++) = static_cast<U8
>(124);
1113 writeTypeOp(TYPE1OP::HSBW
);
1114 mbNeedClose
= false;
1115 mbIgnoreHints
= false;
1116 mnHintSize
=mnHorzHintSize
=mnStackIdx
=0; maCharWidth
=-1;//#######
1118 while( mpReadPtr
< mpReadEnd
)
1120 if( maCharWidth
!= -1 )
1122 // overwrite earlier charWidth value, which we only now have
1123 // parsed out of mpReadPtr buffer (by way of
1124 // convertOneTypeOp()s above)
1125 const int nInt
= static_cast<int>(maCharWidth
);
1126 *(pCharWidthPtr
++) = 255;
1127 *(pCharWidthPtr
++) = static_cast<U8
>(nInt
>> 24);
1128 *(pCharWidthPtr
++) = static_cast<U8
>(nInt
>> 16);
1129 *(pCharWidthPtr
++) = static_cast<U8
>(nInt
>> 8);
1130 *(pCharWidthPtr
++) = static_cast<U8
>(nInt
);
1133 const int nType1Len
= mpWritePtr
- pT1Ops
;
1135 // encrypt the Type1 charstring
1136 unsigned nRDCryptR
= 4330; // TODO: mnRDCryptSeed;
1137 for( U8
* p
= pT1Ops
; p
< mpWritePtr
; ++p
) {
1138 *p
^= (nRDCryptR
>> 8);
1139 nRDCryptR
= (*p
+ nRDCryptR
) * 52845 + 22719;
1145 RealType
CffSubsetterContext::readRealVal()
1147 // TODO: more thorough number validity test
1148 bool bComma
= false;
1152 RealType fReal
= +1.0;
1154 const U8 c
= *(mpReadPtr
++); // read nibbles
1155 // parse high nibble
1156 const U8 nH
= c
>> 4U;
1158 nNumber
= nNumber
* 10 + nH
;
1160 } else if( nH
== 10) { // comma
1163 } else if( nH
== 11) { // +exp
1167 } else if( nH
== 12) { // -exp
1171 } else if( nH
== 13) { // reserved
1172 // TODO: ignore or error?
1173 } else if( nH
== 14) // minus
1175 else if( nH
== 15) // end
1178 const U8 nL
= c
& 0x0F;
1180 nNumber
= nNumber
* 10 + nL
;
1182 } else if( nL
== 10) { // comma
1185 } else if( nL
== 11) { // +exp
1189 } else if( nL
== 12) { // -exp
1193 } else if( nL
== 13) { // reserved
1194 // TODO: ignore or error?
1195 } else if( nL
== 14) // minus
1197 else if( nL
== 15) // end
1204 if( !nExpSign
) { fReal
*= nNumber
;}
1205 else if( nExpSign
> 0) { nExpVal
+= static_cast<int>(nNumber
);}
1206 else if( nExpSign
< 0) { nExpVal
-= static_cast<int>(nNumber
);}
1209 if( !nExpVal
) { /*nothing to apply*/}
1210 else if( nExpVal
> 0) { while( --nExpVal
>= 0) fReal
*= 10.0;}
1211 else if( nExpVal
< 0) { while( ++nExpVal
<= 0) fReal
/= 10.0;}
1215 // prepare to access an element inside a CFF/CID index table
1216 int CffSubsetterContext::seekIndexData( int nIndexBase
, int nDataIndex
)
1218 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1221 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1222 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1223 if( nDataIndex
>= nDataCount
)
1225 const int nDataOfsSz
= mpReadPtr
[2];
1226 mpReadPtr
+= 3 + (nDataOfsSz
* nDataIndex
);
1228 switch( nDataOfsSz
) {
1229 default: SAL_WARN("vcl.fonts", "\tINVALID nDataOfsSz=" << nDataOfsSz
); return -1;
1230 case 1: nOfs1
= mpReadPtr
[0]; break;
1231 case 2: nOfs1
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1232 case 3: nOfs1
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1233 case 4: nOfs1
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1235 mpReadPtr
+= nDataOfsSz
;
1238 switch( nDataOfsSz
) {
1239 case 1: nOfs2
= mpReadPtr
[0]; break;
1240 case 2: nOfs2
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1241 case 3: nOfs2
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1242 case 4: nOfs2
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1245 mpReadPtr
= mpBasePtr
+ (nIndexBase
+ 2) + nDataOfsSz
* (nDataCount
+ 1) + nOfs1
;
1246 mpReadEnd
= mpReadPtr
+ (nOfs2
- nOfs1
);
1247 assert( nOfs1
>= 0);
1248 assert( nOfs2
>= nOfs1
);
1249 assert( mpReadPtr
<= mpBaseEnd
);
1250 assert( mpReadEnd
<= mpBaseEnd
);
1251 return (nOfs2
- nOfs1
);
1254 // skip over a CFF/CID index table
1255 void CffSubsetterContext::seekIndexEnd( int nIndexBase
)
1257 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1258 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1259 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1260 const int nDataOfsSz
= mpReadPtr
[2];
1261 mpReadPtr
+= 3 + nDataOfsSz
* nDataCount
;
1262 assert( mpReadPtr
<= mpBaseEnd
);
1264 switch( nDataOfsSz
) {
1265 default: SAL_WARN("vcl.fonts", "\tINVALID nDataOfsSz=" << nDataOfsSz
); return;
1266 case 1: nEndOfs
= mpReadPtr
[0]; break;
1267 case 2: nEndOfs
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1268 case 3: nEndOfs
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2];break;
1269 case 4: nEndOfs
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1271 mpReadPtr
+= nDataOfsSz
;
1272 mpReadPtr
+= nEndOfs
- 1;
1273 mpReadEnd
= mpBaseEnd
;
1274 assert( nEndOfs
>= 0);
1275 assert( mpReadEnd
<= mpBaseEnd
);
1278 // initialize FONTDICT specific values
1279 CffLocal::CffLocal()
1280 : mnPrivDictBase( 0)
1281 , mnPrivDictSize( 0)
1282 , mnLocalSubrOffs( 0)
1283 , mnLocalSubrBase( 0)
1284 , mnLocalSubrBias( 0)
1285 , maNominalWidth( 0)
1286 , maDefaultWidth( 0)
1294 , mbForceBold( false)
1298 CffGlobal::CffGlobal()
1300 , mnStringIdxBase( 0)
1303 , mnCharStrCount( 0)
1305 , mnGlobalSubrBase( 0)
1306 , mnGlobalSubrCount( 0)
1307 , mnGlobalSubrBias( 0)
1308 , mnFDSelectBase( 0)
1309 , mnFontDictBase( 0)
1316 bool CffSubsetterContext::initialCffRead()
1318 // get the CFFHeader
1319 mpReadPtr
= mpBasePtr
;
1320 const U8 nVerMajor
= *(mpReadPtr
++);
1321 const U8 nVerMinor
= *(mpReadPtr
++);
1322 const U8 nHeaderSize
= *(mpReadPtr
++);
1323 const U8 nOffsetSize
= *(mpReadPtr
++);
1324 // TODO: is the version number useful for anything else?
1325 assert( (nVerMajor
== 1) && (nVerMinor
== 0));
1326 (void)(nVerMajor
+ nVerMinor
+ nOffsetSize
); // avoid compiler warnings
1328 // prepare access to the NameIndex
1329 mnNameIdxBase
= nHeaderSize
;
1330 mpReadPtr
= mpBasePtr
+ nHeaderSize
;
1331 seekIndexEnd( mnNameIdxBase
);
1333 // get the TopDict index
1334 const sal_Int32 nTopDictBase
= getReadOfs();
1335 const int nTopDictCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1336 if( nTopDictCount
) {
1337 for( int i
= 0; i
< nTopDictCount
; ++i
) {
1338 seekIndexData( nTopDictBase
, i
);
1339 while( mpReadPtr
< mpReadEnd
)
1341 assert( mpReadPtr
== mpReadEnd
);
1345 // prepare access to the String index
1346 mnStringIdxBase
= getReadOfs();
1347 seekIndexEnd( mnStringIdxBase
);
1349 // prepare access to the GlobalSubr index
1350 mnGlobalSubrBase
= getReadOfs();
1351 mnGlobalSubrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1352 mnGlobalSubrBias
= (mnGlobalSubrCount
<1240)?107:(mnGlobalSubrCount
<33900)?1131:32768;
1353 // skip past the last GlobalSubr entry
1354 // seekIndexEnd( mnGlobalSubrBase);
1356 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1357 // seekEncodingsEnd( mnEncodingBase);
1358 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1359 // seekCharsetsEnd( mnCharStrBase);
1360 // get/skip FDSelect (CID only) data
1362 // prepare access to the CharStrings index (we got the base from TOPDICT)
1363 mpReadPtr
= mpBasePtr
+ mnCharStrBase
;
1364 mnCharStrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1365 // seekIndexEnd( mnCharStrBase);
1367 // read the FDArray index (CID only)
1369 // assert( mnFontDictBase == tellRel());
1370 mpReadPtr
= mpBasePtr
+ mnFontDictBase
;
1371 mnFDAryCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1372 if (o3tl::make_unsigned(mnFDAryCount
) >= SAL_N_ELEMENTS(maCffLocal
))
1374 SAL_INFO("vcl.fonts", "CffSubsetterContext: too many CFF in font");
1378 // read FDArray details to get access to the PRIVDICTs
1379 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1380 mpCffLocal
= &maCffLocal
[i
];
1381 seekIndexData( mnFontDictBase
, i
);
1382 while( mpReadPtr
< mpReadEnd
)
1384 assert( mpReadPtr
== mpReadEnd
);
1388 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1389 mpCffLocal
= &maCffLocal
[i
];
1391 // get the PrivateDict index
1392 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1393 if( mpCffLocal
->mnPrivDictSize
!= 0) {
1394 assert( mpCffLocal
->mnPrivDictSize
> 0);
1395 // get the PrivDict data
1396 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnPrivDictBase
;
1397 mpReadEnd
= mpReadPtr
+ mpCffLocal
->mnPrivDictSize
;
1398 assert( mpReadEnd
<= mpBaseEnd
);
1399 // read PrivDict details
1400 while( mpReadPtr
< mpReadEnd
)
1404 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1405 if( mpCffLocal
->mnLocalSubrOffs
) {
1406 // read LocalSubrs summary
1407 mpCffLocal
->mnLocalSubrBase
= mpCffLocal
->mnPrivDictBase
+ mpCffLocal
->mnLocalSubrOffs
;
1408 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnLocalSubrBase
;
1409 const int nSubrCount
= (mpReadPtr
[0] << 8) + mpReadPtr
[1];
1410 mpCffLocal
->mnLocalSubrBias
= (nSubrCount
<1240)?107:(nSubrCount
<33900)?1131:32768;
1411 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1415 // ignore the Notices info
1420 // get a cstring from a StringID
1421 const char* CffSubsetterContext::getString( int nStringID
)
1423 // get a standard string if possible
1424 const static int nStdStrings
= SAL_N_ELEMENTS(pStringIds
);
1425 if( (nStringID
>= 0) && (nStringID
< nStdStrings
))
1426 return pStringIds
[ nStringID
];
1428 // else get the string from the StringIndex table
1429 const U8
* pReadPtr
= mpReadPtr
;
1430 const U8
* pReadEnd
= mpReadEnd
;
1431 nStringID
-= nStdStrings
;
1432 int nLen
= seekIndexData( mnStringIdxBase
, nStringID
);
1433 // assert( nLen >= 0);
1434 // TODO: just return the undecorated name
1435 // TODO: get rid of static char buffer
1436 static char aNameBuf
[ 2560];
1438 sprintf( aNameBuf
, "name[%d].notfound!", nStringID
);
1440 const int nMaxLen
= sizeof(aNameBuf
) - 1;
1441 if( nLen
>= nMaxLen
)
1443 for( int i
= 0; i
< nLen
; ++i
)
1444 aNameBuf
[i
] = *(mpReadPtr
++);
1445 aNameBuf
[ nLen
] = '\0';
1447 mpReadPtr
= pReadPtr
;
1448 mpReadEnd
= pReadEnd
;
1452 // access a CID's FDSelect table
1453 int CffSubsetterContext::getFDSelect( int nGlyphIndex
) const
1455 assert( nGlyphIndex
>= 0);
1456 assert( nGlyphIndex
< mnCharStrCount
);
1460 const U8
* pReadPtr
= mpBasePtr
+ mnFDSelectBase
;
1461 const U8 nFDSelFormat
= *(pReadPtr
++);
1462 switch( nFDSelFormat
) {
1463 case 0: { // FDSELECT format 0
1464 pReadPtr
+= nGlyphIndex
;
1465 const U8 nFDIdx
= *(pReadPtr
++);
1468 case 3: { // FDSELECT format 3
1469 const U16 nRangeCount
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1470 assert( nRangeCount
> 0);
1471 assert( nRangeCount
<= mnCharStrCount
);
1472 U16 nPrev
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1473 assert( nPrev
== 0);
1476 // TODO? binary search
1477 for( int i
= 0; i
< nRangeCount
; ++i
) {
1478 const U8 nFDIdx
= pReadPtr
[0];
1479 const U16 nNext
= (pReadPtr
[1]<<8) + pReadPtr
[2];
1480 assert( nPrev
< nNext
);
1481 if( nGlyphIndex
< nNext
)
1487 default: // invalid FDselect format
1488 SAL_WARN("vcl.fonts", "invalid CFF.FdselType=" << nFDSelFormat
);
1496 int CffSubsetterContext::getGlyphSID( int nGlyphIndex
) const
1498 if( nGlyphIndex
== 0)
1499 return 0; // ".notdef"
1500 assert( nGlyphIndex
>= 0);
1501 assert( nGlyphIndex
< mnCharStrCount
);
1502 if( (nGlyphIndex
< 0) || (nGlyphIndex
>= mnCharStrCount
))
1505 // get the SID/CID from the Charset table
1506 const U8
* pReadPtr
= mpBasePtr
+ mnCharsetBase
;
1507 const U8 nCSetFormat
= *(pReadPtr
++);
1508 int nGlyphsToSkip
= nGlyphIndex
- 1;
1509 switch( nCSetFormat
) {
1510 case 0: // charset format 0
1511 pReadPtr
+= 2 * nGlyphsToSkip
;
1514 case 1: // charset format 1
1515 while( nGlyphsToSkip
>= 0) {
1516 const int nLeft
= pReadPtr
[2];
1517 if( nGlyphsToSkip
<= nLeft
)
1519 nGlyphsToSkip
-= nLeft
+ 1;
1523 case 2: // charset format 2
1524 while( nGlyphsToSkip
>= 0) {
1525 const int nLeft
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1526 if( nGlyphsToSkip
<= nLeft
)
1528 nGlyphsToSkip
-= nLeft
+ 1;
1533 SAL_WARN("vcl.fonts", "ILLEGAL CFF-Charset format " << nCSetFormat
);
1537 int nSID
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1538 nSID
+= nGlyphsToSkip
;
1539 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1543 // NOTE: the result becomes invalid with the next call to this method
1544 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex
)
1546 // the first glyph is always the .notdef glyph
1547 const char* pGlyphName
= ".notdef";
1548 if( nGlyphIndex
== 0)
1551 // prepare a result buffer
1552 // TODO: get rid of static buffer
1553 static char aDefaultGlyphName
[64];
1554 pGlyphName
= aDefaultGlyphName
;
1556 // get the glyph specific name
1557 const int nSID
= getGlyphSID( nGlyphIndex
);
1558 if( nSID
< 0) // default glyph name
1559 sprintf( aDefaultGlyphName
, "gly%03d", nGlyphIndex
);
1560 else if( mbCIDFont
) // default glyph name in CIDs
1561 sprintf( aDefaultGlyphName
, "cid%03d", nSID
);
1562 else { // glyph name from string table
1563 const char* pSidName
= getString( nSID
);
1564 // check validity of glyph name
1566 const char* p
= pSidName
;
1567 while( (*p
>= '0') && (*p
<= 'z')) ++p
;
1568 if( (p
>= pSidName
+1) && (*p
== '\0'))
1569 pGlyphName
= pSidName
;
1571 // if needed invent a fallback name
1572 if( pGlyphName
!= pSidName
)
1573 sprintf( aDefaultGlyphName
, "bad%03d", nSID
);
1584 explicit Type1Emitter( FILE* pOutFile
, bool bPfbSubset
);
1586 void setSubsetName( const char* );
1588 size_t emitRawData( const char* pData
, size_t nLength
) const;
1591 void emitAllCrypted();
1592 int tellPos() const;
1593 void updateLen( int nTellPos
, size_t nLength
);
1594 void emitValVector( const char* pLineHead
, const char* pLineTail
, const std::vector
<ValType
>&);
1597 char maBuffer
[MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
1598 unsigned mnEECryptR
;
1602 char maSubsetName
[256];
1609 Type1Emitter::Type1Emitter( FILE* pOutFile
, bool bPfbSubset
)
1610 : mpFileOut( pOutFile
)
1612 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1614 , mbPfbSubset( bPfbSubset
)
1617 maSubsetName
[0] = '\0';
1620 Type1Emitter::~Type1Emitter()
1624 mpFileOut
= nullptr;
1627 void Type1Emitter::setSubsetName( const char* pSubsetName
)
1629 maSubsetName
[0] = '\0';
1631 strncpy( maSubsetName
, pSubsetName
, sizeof(maSubsetName
) - 1);
1632 maSubsetName
[sizeof(maSubsetName
)-1] = '\0';
1635 int Type1Emitter::tellPos() const
1637 int nTellPos
= ftell( mpFileOut
);
1641 void Type1Emitter::updateLen( int nTellPos
, size_t nLength
)
1643 // update PFB segment header length
1645 cData
[0] = static_cast<U8
>(nLength
>> 0);
1646 cData
[1] = static_cast<U8
>(nLength
>> 8);
1647 cData
[2] = static_cast<U8
>(nLength
>> 16);
1648 cData
[3] = static_cast<U8
>(nLength
>> 24);
1649 const tools::Long nCurrPos
= ftell(mpFileOut
);
1652 if (fseek( mpFileOut
, nTellPos
, SEEK_SET
) != 0)
1654 fwrite(cData
, 1, sizeof(cData
), mpFileOut
);
1655 (void)fseek(mpFileOut
, nCurrPos
, SEEK_SET
);
1658 inline size_t Type1Emitter::emitRawData(const char* pData
, size_t nLength
) const
1660 return fwrite( pData
, 1, nLength
, mpFileOut
);
1663 inline void Type1Emitter::emitAllRaw()
1665 // writeout raw data
1666 assert( (mpPtr
- maBuffer
) < int(sizeof(maBuffer
)));
1667 emitRawData( maBuffer
, mpPtr
- maBuffer
);
1668 // reset the raw buffer
1672 inline void Type1Emitter::emitAllHex()
1674 assert( (mpPtr
- maBuffer
) < int(sizeof(maBuffer
)));
1675 for( const char* p
= maBuffer
; p
< mpPtr
;) {
1676 // convert binary chunk to hex
1677 char aHexBuf
[0x4000];
1678 char* pOut
= aHexBuf
;
1679 while( (p
< mpPtr
) && (pOut
< aHexBuf
+sizeof(aHexBuf
)-4)) {
1680 // convert each byte to hex
1681 char cNibble
= (static_cast<unsigned char>(*p
) >> 4) & 0x0F;
1682 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1683 *(pOut
++) = cNibble
;
1684 cNibble
= *(p
++) & 0x0F;
1685 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1686 *(pOut
++) = cNibble
;
1687 // limit the line length
1688 if( (++mnHexLineCol
& 0x3F) == 0)
1691 // writeout hex-converted chunk
1692 emitRawData( aHexBuf
, pOut
-aHexBuf
);
1694 // reset the raw buffer
1698 void Type1Emitter::emitAllCrypted()
1701 for( char* p
= maBuffer
; p
< mpPtr
; ++p
) {
1702 *p
^= (mnEECryptR
>> 8);
1703 mnEECryptR
= (*reinterpret_cast<U8
*>(p
) + mnEECryptR
) * 52845 + 22719;
1706 // emit the t1crypt result
1713 // #i110387# quick-and-dirty double->ascii conversion
1714 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
1715 // also strip off trailing zeros in fraction while we are at it
1716 static int dbl2str( char* pOut
, double fVal
)
1718 const int nLen
= psp::getValueOfDouble( pOut
, fVal
, 6);
1722 void Type1Emitter::emitValVector( const char* pLineHead
, const char* pLineTail
,
1723 const std::vector
<ValType
>& rVector
)
1725 // ignore empty vectors
1726 if( rVector
.empty())
1729 // emit the line head
1730 mpPtr
+= sprintf( mpPtr
, "%s", pLineHead
);
1731 // emit the vector values
1732 std::vector
<ValType
>::value_type aVal
= 0;
1733 for( std::vector
<ValType
>::const_iterator it
= rVector
.begin();;) {
1735 if( ++it
== rVector
.end() )
1737 mpPtr
+= dbl2str( mpPtr
, aVal
);
1740 // emit the last value
1741 mpPtr
+= dbl2str( mpPtr
, aVal
);
1742 // emit the line tail
1743 mpPtr
+= sprintf( mpPtr
, "%s", pLineTail
);
1746 void CffSubsetterContext::emitAsType1( Type1Emitter
& rEmitter
,
1747 const sal_GlyphId
* pReqGlyphIds
, const U8
* pReqEncoding
,
1748 sal_Int32
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rFSInfo
)
1750 // prepare some fontdirectory details
1751 static const int nUniqueIdBase
= 4100000; // using private-interchange UniqueIds
1752 static int nUniqueId
= nUniqueIdBase
;
1755 char* pFontName
= rEmitter
.maSubsetName
;
1757 if( mnFontNameSID
) {
1758 // get the fontname directly if available
1759 strncpy( pFontName
, getString( mnFontNameSID
), sizeof(rEmitter
.maSubsetName
) - 1);
1760 pFontName
[sizeof(rEmitter
.maSubsetName
) - 1] = 0;
1761 } else if( mnFullNameSID
) {
1762 // approximate fontname as fullname-whitespace
1763 const char* pI
= getString( mnFullNameSID
);
1764 char* pO
= pFontName
;
1765 const char* pLimit
= pFontName
+ sizeof(rEmitter
.maSubsetName
) - 1;
1766 while( pO
< pLimit
) {
1767 const char c
= *(pI
++);
1775 // fallback name of last resort
1776 strncpy( pFontName
, "DummyName", sizeof(rEmitter
.maSubsetName
));
1779 const char* pFullName
= pFontName
;
1780 const char* pFamilyName
= pFontName
;
1782 char*& pOut
= rEmitter
.mpPtr
; // convenience reference, TODO: cleanup
1784 // create a PFB+Type1 header
1785 if( rEmitter
.mbPfbSubset
) {
1786 static const char aPfbHeader
[] = "\x80\x01\x00\x00\x00\x00";
1787 rEmitter
.emitRawData( aPfbHeader
, sizeof(aPfbHeader
)-1);
1790 pOut
+= sprintf( pOut
, "%%!FontType1-1.0: %s 001.003\n", rEmitter
.maSubsetName
);
1792 pOut
+= sprintf( pOut
,
1793 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
1795 "/PaintType 0 def\n");
1796 pOut
+= sprintf( pOut
, "/FontName /%s def\n", rEmitter
.maSubsetName
);
1797 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
1799 if( maFontMatrix
.size() == 6)
1800 rEmitter
.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix
);
1801 else // emit default FontMatrix if needed
1802 pOut
+= sprintf( pOut
, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
1804 if( maFontBBox
.size() == 4)
1805 rEmitter
.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox
);
1806 else // emit default FontBBox if needed
1807 pOut
+= sprintf( pOut
, "/FontBBox {0 0 999 999}readonly def\n");
1808 // emit FONTINFO into TOPDICT
1809 pOut
+= sprintf( pOut
,
1810 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
1811 " /FullName (%s) readonly def\n"
1812 " /FamilyName (%s) readonly def\n"
1813 "end readonly def\n",
1814 pFullName
, pFamilyName
);
1816 pOut
+= sprintf( pOut
,
1817 "/Encoding 256 array\n"
1818 "0 1 255 {1 index exch /.notdef put} for\n");
1819 for( int i
= 1; (i
< nGlyphCount
) && (i
< 256); ++i
) {
1820 const char* pGlyphName
= getGlyphName( pReqGlyphIds
[i
]);
1821 pOut
+= sprintf( pOut
, "dup %d /%s put\n", pReqEncoding
[i
], pGlyphName
);
1823 pOut
+= sprintf( pOut
, "readonly def\n");
1824 pOut
+= sprintf( pOut
,
1825 // TODO: more topdict entries
1827 "currentfile eexec\n");
1830 rEmitter
.emitAllRaw();
1831 if( rEmitter
.mbPfbSubset
) {
1832 // update PFB header segment
1833 const int nPfbHeaderLen
= rEmitter
.tellPos() - 6;
1834 rEmitter
.updateLen( 2, nPfbHeaderLen
);
1836 // prepare start of eexec segment
1837 rEmitter
.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
1839 const int nEExecSegTell
= rEmitter
.tellPos();
1841 // which always starts with a privdict
1842 // count the privdict entries
1843 int nPrivEntryCount
= 9;
1844 // emit blue hints only if non-default values
1845 nPrivEntryCount
+= int(!mpCffLocal
->maOtherBlues
.empty());
1846 nPrivEntryCount
+= int(!mpCffLocal
->maFamilyBlues
.empty());
1847 nPrivEntryCount
+= int(!mpCffLocal
->maFamilyOtherBlues
.empty());
1848 nPrivEntryCount
+= int(mpCffLocal
->mfBlueScale
!= 0.0);
1849 nPrivEntryCount
+= int(mpCffLocal
->mfBlueShift
!= 0.0);
1850 nPrivEntryCount
+= int(mpCffLocal
->mfBlueFuzz
!= 0.0);
1851 // emit stem hints only if non-default values
1852 nPrivEntryCount
+= int(mpCffLocal
->maStemStdHW
!= 0);
1853 nPrivEntryCount
+= int(mpCffLocal
->maStemStdVW
!= 0);
1854 nPrivEntryCount
+= int(!mpCffLocal
->maStemSnapH
.empty());
1855 nPrivEntryCount
+= int(!mpCffLocal
->maStemSnapV
.empty());
1856 // emit other hints only if non-default values
1857 nPrivEntryCount
+= int(mpCffLocal
->mfExpFactor
!= 0.0);
1858 nPrivEntryCount
+= int(mpCffLocal
->mnLangGroup
!= 0);
1859 nPrivEntryCount
+= int(mpCffLocal
->mnLangGroup
== 1);
1860 nPrivEntryCount
+= int(mpCffLocal
->mbForceBold
);
1861 // emit the privdict header
1862 pOut
+= sprintf( pOut
,
1864 "dup\n/Private %d dict dup begin\n"
1865 "/RD{string currentfile exch readstring pop}executeonly def\n"
1866 "/ND{noaccess def}executeonly def\n"
1867 "/NP{noaccess put}executeonly def\n"
1868 "/MinFeature{16 16}ND\n"
1869 "/password 5839 def\n", // TODO: mnRDCryptSeed?
1872 // emit blue hint related privdict entries
1873 if( !mpCffLocal
->maBlueValues
.empty())
1874 rEmitter
.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal
->maBlueValues
);
1876 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // default to empty BlueValues
1877 rEmitter
.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal
->maOtherBlues
);
1878 rEmitter
.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal
->maFamilyBlues
);
1879 rEmitter
.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal
->maFamilyOtherBlues
);
1881 if( mpCffLocal
->mfBlueScale
) {
1882 pOut
+= sprintf( pOut
, "/BlueScale ");
1883 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueScale
);
1884 pOut
+= sprintf( pOut
, " def\n");
1886 if( mpCffLocal
->mfBlueShift
) { // default BlueShift==7
1887 pOut
+= sprintf( pOut
, "/BlueShift ");
1888 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueShift
);
1889 pOut
+= sprintf( pOut
, " def\n");
1891 if( mpCffLocal
->mfBlueFuzz
) { // default BlueFuzz==1
1892 pOut
+= sprintf( pOut
, "/BlueFuzz ");
1893 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueFuzz
);
1894 pOut
+= sprintf( pOut
, " def\n");
1897 // emit stem hint related privdict entries
1898 if( mpCffLocal
->maStemStdHW
) {
1899 pOut
+= sprintf( pOut
, "/StdHW [");
1900 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdHW
);
1901 pOut
+= sprintf( pOut
, "] def\n");
1903 if( mpCffLocal
->maStemStdVW
) {
1904 pOut
+= sprintf( pOut
, "/StdVW [");
1905 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdVW
);
1906 pOut
+= sprintf( pOut
, "] def\n");
1908 rEmitter
.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal
->maStemSnapH
);
1909 rEmitter
.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal
->maStemSnapV
);
1912 if( mpCffLocal
->mbForceBold
)
1913 pOut
+= sprintf( pOut
, "/ForceBold true def\n");
1914 if( mpCffLocal
->mnLangGroup
!= 0)
1915 pOut
+= sprintf( pOut
, "/LanguageGroup %d def\n", mpCffLocal
->mnLangGroup
);
1916 if( mpCffLocal
->mnLangGroup
== 1) // compatibility with ancient printers
1917 pOut
+= sprintf( pOut
, "/RndStemUp false def\n");
1918 if( mpCffLocal
->mfExpFactor
) {
1919 pOut
+= sprintf( pOut
, "/ExpansionFactor ");
1920 pOut
+= dbl2str( pOut
, mpCffLocal
->mfExpFactor
);
1921 pOut
+= sprintf( pOut
, " def\n");
1924 // emit remaining privdict entries
1925 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
1926 // TODO?: more privdict entries?
1928 static const char aOtherSubrs
[] =
1930 "% Dummy code for faking flex hints\n"
1931 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
1932 "{1183615869 systemdict /internaldict get exec\n"
1933 "dup /startlock known\n"
1934 "{/startlock get exec}\n"
1935 "{dup /strtlck known\n"
1936 "{/strtlck get exec}\n"
1937 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
1939 memcpy( pOut
, aOtherSubrs
, sizeof(aOtherSubrs
)-1);
1940 pOut
+= sizeof(aOtherSubrs
)-1;
1942 // emit used GlobalSubr charstrings
1943 // these are the just the default subrs
1944 // TODO: do we need them as the flex hints are resolved differently?
1945 static const char aSubrs
[] =
1947 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
1948 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
1949 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
1950 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
1951 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
1953 memcpy( pOut
, aSubrs
, sizeof(aSubrs
)-1);
1954 pOut
+= sizeof(aSubrs
)-1;
1956 // TODO: emit more GlobalSubr charstrings?
1957 // TODO: emit used LocalSubr charstrings?
1959 // emit the CharStrings for the requested glyphs
1960 pOut
+= sprintf( pOut
,
1961 "2 index /CharStrings %d dict dup begin\n", nGlyphCount
);
1962 rEmitter
.emitAllCrypted();
1963 for( int i
= 0; i
< nGlyphCount
; ++i
) {
1964 const int nCffGlyphId
= pReqGlyphIds
[i
];
1965 assert( (nCffGlyphId
>= 0) && (nCffGlyphId
< mnCharStrCount
));
1966 // get privdict context matching to the glyph
1967 const int nFDSelect
= getFDSelect( nCffGlyphId
);
1970 mpCffLocal
= &maCffLocal
[ nFDSelect
];
1971 // convert the Type2op charstring to its Type1op counterpart
1972 const int nT2Len
= seekIndexData( mnCharStrBase
, nCffGlyphId
);
1973 assert( nT2Len
> 0);
1974 U8 aType1Ops
[ MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
1975 const int nT1Len
= convert2Type1Ops( mpCffLocal
, mpReadPtr
, nT2Len
, aType1Ops
);
1976 // get the glyph name
1977 const char* pGlyphName
= getGlyphName( nCffGlyphId
);
1978 // emit the encrypted Type1op charstring
1979 pOut
+= sprintf( pOut
, "/%s %d RD ", pGlyphName
, nT1Len
);
1980 memcpy( pOut
, aType1Ops
, nT1Len
);
1982 pOut
+= sprintf( pOut
, " ND\n");
1983 rEmitter
.emitAllCrypted();
1984 // provide individual glyphwidths if requested
1985 if( pGlyphWidths
) {
1986 ValType aCharWidth
= maCharWidth
;
1987 if( maFontMatrix
.size() >= 4)
1988 aCharWidth
*= 1000.0F
* maFontMatrix
[0];
1989 pGlyphWidths
[i
] = static_cast<sal_Int32
>(aCharWidth
);
1992 pOut
+= sprintf( pOut
, "end end\nreadonly put\nput\n");
1993 pOut
+= sprintf( pOut
, "dup/FontName get exch definefont pop\n");
1994 pOut
+= sprintf( pOut
, "mark currentfile closefile\n");
1995 rEmitter
.emitAllCrypted();
1997 // mark stop of eexec encryption
1998 if( rEmitter
.mbPfbSubset
) {
1999 const int nEExecLen
= rEmitter
.tellPos() - nEExecSegTell
;
2000 rEmitter
.updateLen( nEExecSegTell
-4, nEExecLen
);
2003 // create PFB footer
2004 static const char aPfxFooter
[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2005 "0000000000000000000000000000000000000000000000000000000000000000\n"
2006 "0000000000000000000000000000000000000000000000000000000000000000\n"
2007 "0000000000000000000000000000000000000000000000000000000000000000\n"
2008 "0000000000000000000000000000000000000000000000000000000000000000\n"
2009 "0000000000000000000000000000000000000000000000000000000000000000\n"
2010 "0000000000000000000000000000000000000000000000000000000000000000\n"
2011 "0000000000000000000000000000000000000000000000000000000000000000\n"
2012 "0000000000000000000000000000000000000000000000000000000000000000\n"
2015 if( rEmitter
.mbPfbSubset
)
2016 rEmitter
.emitRawData( aPfxFooter
, sizeof(aPfxFooter
)-1);
2018 rEmitter
.emitRawData( aPfxFooter
+6, sizeof(aPfxFooter
)-9);
2020 // provide details to the subset requesters, TODO: move into own method?
2021 // note: Top and Bottom are flipped between Type1 and VCL
2022 // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
2023 ValType fXFactor
= 1.0;
2024 ValType fYFactor
= 1.0;
2025 if( maFontMatrix
.size() >= 4) {
2026 fXFactor
= 1000.0F
* maFontMatrix
[0];
2027 fYFactor
= 1000.0F
* maFontMatrix
[3];
2029 rFSInfo
.m_aFontBBox
= tools::Rectangle( Point( static_cast<sal_Int32
>(maFontBBox
[0] * fXFactor
),
2030 static_cast<sal_Int32
>(maFontBBox
[1] * fYFactor
) ),
2031 Point( static_cast<sal_Int32
>(maFontBBox
[2] * fXFactor
),
2032 static_cast<sal_Int32
>(maFontBBox
[3] * fYFactor
) ) );
2033 // PDF-Spec says the values below mean the ink bounds!
2034 // TODO: use better approximations for these ink bounds
2035 rFSInfo
.m_nAscent
= +rFSInfo
.m_aFontBBox
.Bottom(); // for capital letters
2036 rFSInfo
.m_nDescent
= -rFSInfo
.m_aFontBBox
.Top(); // for all letters
2037 rFSInfo
.m_nCapHeight
= rFSInfo
.m_nAscent
; // for top-flat capital letters
2039 rFSInfo
.m_nFontType
= rEmitter
.mbPfbSubset
? FontType::TYPE1_PFB
: FontType::TYPE1_PFA
;
2040 rFSInfo
.m_aPSName
= OUString( rEmitter
.maSubsetName
, strlen(rEmitter
.maSubsetName
), RTL_TEXTENCODING_UTF8
);
2043 bool FontSubsetInfo::CreateFontSubsetFromCff( sal_Int32
* pOutGlyphWidths
)
2045 CffSubsetterContext
aCff( mpInFontBytes
, mnInByteLength
);
2046 bool bRC
= aCff
.initialCffRead();
2050 // emit Type1 subset from the CFF input
2051 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2052 const bool bPfbSubset(mnReqFontTypeMask
& FontType::TYPE1_PFB
);
2053 Type1Emitter
aType1Emitter( mpOutFile
, bPfbSubset
);
2054 aType1Emitter
.setSubsetName( mpReqFontName
);
2055 aCff
.emitAsType1( aType1Emitter
,
2056 mpReqGlyphIds
, mpReqEncodedIds
,
2057 pOutGlyphWidths
, mnReqGlyphCount
, *this);
2061 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */