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 <vcl/strhelper.hxx>
28 #include <sal/log.hxx>
31 typedef sal_uInt16 U16
;
32 typedef sal_Int64 S64
;
34 typedef double RealType
;
35 typedef RealType ValType
;
37 static const char* pStringIds
[] = {
38 /*0*/ ".notdef", "space", "exclam", "quotedbl",
39 "numbersign", "dollar", "percent", "ampersand",
40 "quoteright", "parenleft", "parenright", "asterisk",
41 "plus", "comma", "hyphen", "period",
42 /*16*/ "slash", "zero", "one", "two",
43 "three", "four", "five", "six",
44 "seven", "eight", "nine", "colon",
45 "semicolon", "less", "equal", "greater",
46 /*32*/ "question", "at", "A", "B",
50 /*48*/ "O", "P", "Q", "R",
53 "bracketleft", "backslash", "bracketright", "asciicircum",
54 /*64*/ "underscore", "quoteleft", "a", "b",
58 /*80*/ "o", "p", "q", "r",
61 "braceleft", "bar", "braceright", "asciitilde",
62 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
63 "yen", "florin", "section", "currency",
64 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
65 "guilsinglright", "fi", "fl", "endash",
66 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
67 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
68 "guillemotright", "ellipsis", "perthousand", "questiondown",
69 "grave", "acute", "circumflex", "tilde",
70 /*128*/ "macron", "breve", "dotaccent", "dieresis",
71 "ring", "cedilla", "hungarumlaut", "ogonek",
72 "caron", "emdash", "AE", "ordfeminine",
73 "Lslash", "Oslash", "OE", "ordmasculine",
74 /*144*/ "ae", "dotlessi", "lslash", "oslash",
75 "oe", "germandbls", "onesuperior", "logicalnot",
76 "mu", "trademark", "Eth", "onehalf",
77 "plusminus", "Thorn", "onequarter", "divide",
78 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
79 "twosuperior", "registered", "minus", "eth",
80 "multiply", "threesuperior", "copyright", "Aacute",
81 "Acircumflex", "Adieresis", "Agrave", "Aring",
82 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
83 "Edieresis", "Egrave", "Iacute", "Icircumflex",
84 "Idieresis", "Igrave", "Ntilde", "Oacute",
85 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
86 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
87 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
88 "aacute", "acircumflex", "adieresis", "agrave",
89 "aring", "atilde", "ccedilla", "eacute",
90 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
91 "icircumflex", "idieresis", "igrave", "ntilde",
92 "oacute", "ocircumflex", "odieresis", "ograve",
93 "otilde", "scaron", "uacute", "ucircumflex",
94 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
95 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
96 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
97 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
98 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
99 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
100 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
101 "questionsmall", "asuperior", "bsuperior", "centsuperior",
102 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
103 "msuperior", "nsuperior", "osuperior", "rsuperior",
104 "ssuperior", "tsuperior", "ff", "ffi",
105 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
106 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
107 "Csmall", "Dsmall", "Esmall", "Fsmall",
108 "Gsmall", "Hsmall", "Ismall", "Jsmall",
109 "Ksmall", "Lsmall", "Msmall", "Nsmall",
110 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
111 "Ssmall", "Tsmall", "Usmall", "Vsmall",
112 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
113 "colonmonetary", "onefitted", "rupia", "Tildesmall",
114 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
115 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
116 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
117 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
118 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
119 "onethird", "twothirds", "zerosuperior", "foursuperior",
120 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
121 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
122 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
123 "seveninferior", "eightinferior", "nineinferior", "centinferior",
124 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
125 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
126 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
127 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
128 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
129 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
130 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
131 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
132 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
133 "001.001", "001.002", "001.003", "Black",
134 /*384*/ "Bold", "Book", "Light", "Medium",
135 "Regular", "Roman", "Semibold"
138 // TOP DICT keywords (also covers PRIV DICT keywords)
139 static const char* pDictOps
[] = {
140 "sVersion", "sNotice", "sFullName", "sFamilyName",
141 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
142 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
143 "xESC", "nUniqueID", "aXUID", "nCharset",
144 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
145 "nDefaultWidthX", "nNominalWidthX", nullptr, nullptr,
146 nullptr, nullptr, nullptr, nullptr,
147 "shortint", "longint", "BCD", nullptr
150 // TOP DICT escapes (also covers PRIV DICT escapes)
151 static const char* pDictEscs
[] = {
152 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
153 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
154 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
155 "dStemSnapH", "dStemSnapV", "bForceBold", nullptr,
156 nullptr, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
157 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
158 nullptr, nullptr, nullptr, nullptr,
159 nullptr, nullptr, "rROS", "nCIDFontVersion",
160 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
161 "nFDArray", "nFDSelect", "sFontName"
168 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
169 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CLOSEPATH
=9,
170 CALLSUBR
=10, RETURN
=11, T1ESC
=12, HSBW
=13,
171 ENDCHAR
=14, RMOVETO
=21, HMOVETO
=22, VHCURVETO
=30,
177 DOTSECTION
=0, VSTEM3
=1, HSTEM3
=2, SEAC
=6,
178 SBW
=7, ABS
=9, ADD
=10, SUB
=11,
179 DIV
=12, CALLOTHERSUBR
=16, POP
=17, SETCURRENTPOINT
=33
187 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
188 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CALLSUBR
=10,
189 RETURN
=11, T2ESC
=12, ENDCHAR
=14, HSTEMHM
=18,
190 HINTMASK
=19, CNTRMASK
=20, RMOVETO
=21, HMOVETO
=22,
191 VSTEMHM
=23, RCURVELINE
=24, RLINECURVE
=25, VVCURVETO
=26,
192 HHCURVETO
=27, SHORTINT
=28, CALLGSUBR
=29, VHCURVETO
=30,
198 AND
=3, OR
=4, NOT
=5, ABS
=9,
199 ADD
=10, SUB
=11, DIV
=12, NEG
=14,
200 EQ
=15, DROP
=18, PUT
=20, GET
=21,
201 IFELSE
=22, RANDOM
=23, MUL
=24, SQRT
=26,
202 DUP
=27, EXCH
=28, INDEX
=29, ROLL
=30,
203 HFLEX
=34, FLEX
=35, HFLEX1
=36, FLEX1
=37
209 explicit CffGlobal();
217 int mnGlobalSubrBase
;
218 int mnGlobalSubrCount
;
219 int mnGlobalSubrBias
;
224 std::vector
<ValType
> maFontBBox
;
225 std::vector
<ValType
> maFontMatrix
;
241 ValType maNominalWidth
;
242 ValType maDefaultWidth
;
244 // ATM hinting related values
247 std::vector
<ValType
> maStemSnapH
;
248 std::vector
<ValType
> maStemSnapV
;
249 std::vector
<ValType
> maBlueValues
;
250 std::vector
<ValType
> maOtherBlues
;
251 std::vector
<ValType
> maFamilyBlues
;
252 std::vector
<ValType
> maFamilyOtherBlues
;
253 RealType mfBlueScale
;
254 RealType mfBlueShift
;
256 RealType mfExpFactor
;
261 class CffSubsetterContext
265 static const int NMAXSTACK
= 48; // see CFF.appendixB
266 static const int NMAXHINTS
= 2*96; // see CFF.appendixB
267 static const int NMAXTRANS
= 32; // see CFF.appendixB
269 explicit CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
);
271 bool initialCffRead();
272 void emitAsType1( class Type1Emitter
&,
273 const sal_GlyphId
* pGlyphIds
, const U8
* pEncoding
,
274 sal_Int32
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& );
277 int convert2Type1Ops( CffLocal
*, const U8
* pType2Ops
, int nType2Len
, U8
* pType1Ops
);
278 void convertOneTypeOp();
279 void convertOneTypeEsc();
280 void callType2Subr( bool bGlobal
, int nSubrNumber
);
281 sal_Int32
getReadOfs() const { return static_cast<sal_Int32
>(mpReadPtr
- mpBasePtr
);}
292 sal_Int32 mnCntrMask
;
294 int seekIndexData( int nIndexBase
, int nDataIndex
);
295 void seekIndexEnd( int nIndexBase
);
297 CffLocal maCffLocal
[256];
298 CffLocal
* mpCffLocal
;
301 RealType
readRealVal();
302 const char* getString( int nStringID
);
303 int getFDSelect( int nGlyphIndex
) const;
304 int getGlyphSID( int nGlyphIndex
) const;
305 const char* getGlyphName( int nGlyphIndex
);
308 void writeType1Val( ValType
);
309 void writeTypeOp( int nTypeOp
);
310 void writeTypeEsc( int nTypeOp
);
311 void writeCurveTo( int nStackPos
, int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
);
312 void pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
=0);
313 void popAll2Write( int nTypeOp
);
315 public: // TODO: is public really needed?
316 // accessing the value stack
317 // TODO: add more checks
318 void push( ValType nVal
) { mnValStack
[ mnStackIdx
++] = nVal
;}
319 ValType
popVal() { return ((mnStackIdx
>0) ? mnValStack
[ --mnStackIdx
] : 0);}
320 ValType
getVal( int nIndex
) const { return mnValStack
[ nIndex
];}
322 int size() const { return mnStackIdx
;}
323 void clear() { mnStackIdx
= 0;}
325 // accessing the charstring hints
326 void addHints( bool bVerticalHints
);
328 // accessing other charstring specifics
329 bool hasCharWidth() const { return (maCharWidth
> 0);}
330 ValType
getCharWidth() const { return maCharWidth
;}
331 void setNominalWidth( ValType aWidth
) { mpCffLocal
->maNominalWidth
= aWidth
;}
332 void setDefaultWidth( ValType aWidth
) { mpCffLocal
->maDefaultWidth
= aWidth
;}
333 void updateWidth( bool bUseFirstVal
);
336 // typeop execution context
338 ValType mnValStack
[ NMAXSTACK
+4];
339 ValType mnTransVals
[ NMAXTRANS
];
343 ValType mnHintStack
[ NMAXHINTS
];
348 CffSubsetterContext::CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
)
349 : mpBasePtr( pBasePtr
)
350 , mpBaseEnd( pBasePtr
+nBaseLen
)
353 , mpWritePtr(nullptr)
355 , mbIgnoreHints(false)
365 // setCharStringType( 1);
366 // TODO: new CffLocal[ mnFDAryCount];
367 mpCffLocal
= &maCffLocal
[0];
370 inline int CffSubsetterContext::popInt()
372 const ValType aVal
= popVal();
373 const int nInt
= static_cast<int>(aVal
);
374 assert( nInt
== aVal
);
378 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal
)
380 // the first value is not a hint but the charwidth
385 maCharWidth
= mpCffLocal
->maNominalWidth
+ mnValStack
[0];
386 // remove bottom stack entry
388 for( int i
= 0; i
< mnStackIdx
; ++i
)
389 mnValStack
[ i
] = mnValStack
[ i
+1];
391 maCharWidth
= mpCffLocal
->maDefaultWidth
;
395 void CffSubsetterContext::addHints( bool bVerticalHints
)
397 // the first charstring value may a charwidth instead of a charwidth
398 updateWidth( (mnStackIdx
& 1) != 0);
399 // return early (e.g. no implicit hints for hintmask)
403 // copy the remaining values to the hint arrays
404 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
405 if( mnStackIdx
& 1) --mnStackIdx
;//#######
406 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
408 assert( (mnHintSize
+ mnStackIdx
) <= 2*NMAXHINTS
);
410 ValType nHintOfs
= 0;
411 for( int i
= 0; i
< mnStackIdx
; ++i
) {
412 nHintOfs
+= mnValStack
[ i
];
413 mnHintStack
[ mnHintSize
++] = nHintOfs
;
417 mnHorzHintSize
= mnHintSize
;
419 // clear all values from the stack
423 void CffSubsetterContext::readDictOp()
425 const U8 c
= *mpReadPtr
;
427 int nOpId
= *(mpReadPtr
++);
428 const char* pCmdName
= nullptr;
430 pCmdName
= pDictOps
[nOpId
];
432 const U8 nExtId
= *(mpReadPtr
++);
434 pCmdName
= pDictEscs
[nExtId
];
435 nOpId
= 900 + nExtId
;
438 if (!pCmdName
) // skip reserved operators
441 //TODO: if( nStackIdx > 0)
444 default: fprintf( stderr
, "unsupported DictOp.type=\'%c\'\n", *pCmdName
); break;
448 case 915: mpCffLocal
->mbForceBold
= nInt
; break; // "ForceBold"
449 default: break; // TODO: handle more boolean dictops?
452 case 'n': { // dict-op number
453 ValType nVal
= popVal();
454 nInt
= static_cast<int>(nVal
);
456 case 10: mpCffLocal
->maStemStdHW
= nVal
; break; // "StdHW"
457 case 11: mpCffLocal
->maStemStdVW
= nVal
; break; // "StdVW"
458 case 15: mnCharsetBase
= nInt
; break; // "charset"
459 case 16: break; // "nEncoding"
460 case 17: mnCharStrBase
= nInt
; break; // "nCharStrings"
461 case 19: mpCffLocal
->mnLocalSubrOffs
= nInt
; break;// "nSubrs"
462 case 20: setDefaultWidth( nVal
); break; // "defaultWidthX"
463 case 21: setNominalWidth( nVal
); break; // "nominalWidthX"
464 case 909: mpCffLocal
->mfBlueScale
= nVal
; break; // "BlueScale"
465 case 910: mpCffLocal
->mfBlueShift
= nVal
; break; // "BlueShift"
466 case 911: mpCffLocal
->mfBlueFuzz
= nVal
; break; // "BlueFuzz"
467 case 912: mpCffLocal
->mfExpFactor
= nVal
; break; // "ExpansionFactor"
468 case 917: mpCffLocal
->mnLangGroup
= nInt
; break; // "LanguageGroup"
469 case 936: mnFontDictBase
= nInt
; break; // "nFDArray"
470 case 937: mnFDSelectBase
= nInt
; break; // "nFDSelect"
471 default: break; // TODO: handle more numeric dictops?
476 case 5: maFontBBox
.clear(); break; // "FontBBox"
477 case 907: maFontMatrix
.clear(); break; // "FontMatrix"
478 default: break; // TODO: reset other arrays?
480 for( int i
= 0; i
< size(); ++i
) {
481 ValType nVal
= getVal(i
);
483 case 5: maFontBBox
.push_back( nVal
); break; // "FontBBox"
484 case 907: maFontMatrix
.push_back( nVal
); break; // "FontMatrix"
485 default: break; // TODO: handle more array dictops?
490 case 'd': { // delta array
492 for( int i
= 0; i
< size(); ++i
) {
495 case 6: mpCffLocal
->maBlueValues
.push_back( nVal
); break; // "BlueValues"
496 case 7: mpCffLocal
->maOtherBlues
.push_back( nVal
); break; // "OtherBlues"
497 case 8: mpCffLocal
->maFamilyBlues
.push_back( nVal
); break; // "FamilyBlues"
498 case 9: mpCffLocal
->maFamilyOtherBlues
.push_back( nVal
); break;// "FamilyOtherBlues"
499 case 912: mpCffLocal
->maStemSnapH
.push_back( nVal
); break; // "StemSnapH"
500 case 913: mpCffLocal
->maStemSnapV
.push_back( nVal
); break; // "StemSnapV"
501 default: break; // TODO: handle more delta-array dictops?
506 case 's': // stringid (SID)
509 case 2: mnFullNameSID
= nInt
; break; // "FullName"
510 case 3: break; // "FamilyName"
511 case 938: mnFontNameSID
= nInt
; break; // "FontName"
512 default: break; // TODO: handle more string dictops?
515 case 'P': // private dict
516 mpCffLocal
->mnPrivDictBase
= popInt();
517 mpCffLocal
->mnPrivDictSize
= popInt();
519 case 'r': { // ROS operands
520 popInt(); // TODO: use sid1
521 popInt(); // TODO: use sid2
525 case 't': // CharstringType
529 } else if( (c
>= 32) || (c
== 28) ) {
532 } else if( c
== 29 ) { // longint
533 ++mpReadPtr
; // skip 29
534 sal_Int32 nS32
= mpReadPtr
[0] << 24;
535 nS32
+= mpReadPtr
[1] << 16;
536 nS32
+= mpReadPtr
[2] << 8;
537 nS32
+= mpReadPtr
[3] << 0;
539 ValType nVal
= static_cast<ValType
>(nS32
);
541 } else if( c
== 30) { // real number
542 ++mpReadPtr
; // skip 30
543 const RealType fReal
= readRealVal();
544 // push value onto stack
545 ValType nVal
= fReal
;
550 void CffSubsetterContext::read2push()
554 const U8
*& p
= mpReadPtr
;
557 sal_Int16 nS16
= (p
[1] << 8) + p
[2];
560 } else if( c
<= 246 ) { // -107..+107
561 aVal
= static_cast<ValType
>(p
[0] - 139);
563 } else if( c
<= 250 ) { // +108..+1131
564 aVal
= static_cast<ValType
>(((p
[0] << 8) + p
[1]) - 63124);
566 } else if( c
<= 254 ) { // -108..-1131
567 aVal
= static_cast<ValType
>(64148 - ((p
[0] << 8) + p
[1]));
569 } else /*if( c == 255)*/ { // Fixed16.16
570 int nS32
= (p
[1] << 24) + (p
[2] << 16) + (p
[3] << 8) + p
[4];
571 if( (sizeof(nS32
) != 2) && (nS32
& (1U<<31)))
572 nS32
|= (~0U) << 31; // assuming 2s complement
573 aVal
= static_cast<ValType
>(nS32
* (1.0 / 0x10000));
580 void CffSubsetterContext::writeType1Val( ValType aVal
)
582 U8
* pOut
= mpWritePtr
;
584 int nInt
= static_cast<int>(aVal
);
585 if( (nInt
>= -107) && (nInt
<= +107)) {
586 *(pOut
++) = static_cast<U8
>(nInt
+ 139); // -107..+107
587 } else if( (nInt
>= -1131) && (nInt
<= +1131)) {
589 nInt
+= 63124; // +108..+1131
591 nInt
= 64148 - nInt
; // -108..-1131
592 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
593 *(pOut
++) = static_cast<U8
>(nInt
);
595 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
597 *(pOut
++) = static_cast<U8
>(nInt
>> 24);
598 *(pOut
++) = static_cast<U8
>(nInt
>> 16);
599 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
600 *(pOut
++) = static_cast<U8
>(nInt
);
606 inline void CffSubsetterContext::writeTypeOp( int nTypeOp
)
608 *(mpWritePtr
++) = static_cast<U8
>(nTypeOp
);
611 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc
)
613 *(mpWritePtr
++) = TYPE1OP::T1ESC
;
614 *(mpWritePtr
++) = static_cast<U8
>(nTypeEsc
);
617 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
)
619 for( int i
= 0; i
< mnStackIdx
;) {
620 for( int j
= 0; j
< nArgsPerTypo
; ++j
) {
621 const ValType aVal
= mnValStack
[i
+j
];
622 writeType1Val( aVal
);
625 writeTypeOp( nTypeOp
);
626 nTypeOp
^= nTypeXor
; // for toggling vlineto/hlineto
631 void CffSubsetterContext::popAll2Write( int nTypeOp
)
633 // pop in reverse order, then write
634 for( int i
= 0; i
< mnStackIdx
; ++i
) {
635 const ValType aVal
= mnValStack
[i
];
636 writeType1Val( aVal
);
639 writeTypeOp( nTypeOp
);
642 void CffSubsetterContext::writeCurveTo( int nStackPos
,
643 int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
)
645 // get the values from the stack
646 const ValType nDX1
= nIX1
? mnValStack
[ nStackPos
+nIX1
] : 0;
647 const ValType nDY1
= nIY1
? mnValStack
[ nStackPos
+nIY1
] : 0;
648 const ValType nDX2
= nIX2
? mnValStack
[ nStackPos
+nIX2
] : 0;
649 const ValType nDY2
= nIY2
? mnValStack
[ nStackPos
+nIY2
] : 0;
650 const ValType nDX3
= nIX3
? mnValStack
[ nStackPos
+nIX3
] : 0;
651 const ValType nDY3
= nIY3
? mnValStack
[ nStackPos
+nIY3
] : 0;
653 // emit the curveto operator and operands
654 // TODO: determine the most efficient curveto operator
655 // TODO: depending on type1op or type2op target
656 writeType1Val( nDX1
);
657 writeType1Val( nDY1
);
658 writeType1Val( nDX2
);
659 writeType1Val( nDY2
);
660 writeType1Val( nDX3
);
661 writeType1Val( nDY3
);
662 writeTypeOp( TYPE1OP::RCURVETO
);
665 void CffSubsetterContext::convertOneTypeOp()
667 const int nType2Op
= *(mpReadPtr
++);
669 int i
, nInt
; // prevent WAE for declarations inside switch cases
677 addHints( nType2Op
== TYPE2OP::VSTEM
);
678 for( i
= 0; i
< mnHintSize
; i
+=2 ) {
679 writeType1Val( mnHintStack
[i
]);
680 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
681 writeTypeOp( nType2Op
);
684 case TYPE2OP::HSTEMHM
:
685 case TYPE2OP::VSTEMHM
:
686 addHints( nType2Op
== TYPE2OP::VSTEMHM
);
688 case TYPE2OP::CNTRMASK
:
689 // TODO: replace cntrmask with vstem3/hstem3
694 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
696 nMaskByte
= *(mpReadPtr
++);
699 if( !(nMaskByte
& nMaskBit
))
701 if( i
>= 8*int(sizeof(mnCntrMask
)))
702 mbIgnoreHints
= true;
705 mnCntrMask
|= (1U << i
);
709 case TYPE2OP::HINTMASK
:
712 sal_Int32 nHintMask
= 0;
713 int nCntrBits
[2] = {0,0};
716 int const MASK_BITS
= 8*sizeof(nHintMask
);
717 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
719 nMaskByte
= *(mpReadPtr
++);
722 if( !(nMaskByte
& nMaskBit
))
725 mbIgnoreHints
= true;
728 nHintMask
|= (1U << i
);
729 nCntrBits
[ i
< mnHorzHintSize
] += (mnCntrMask
>> i
) & 1;
732 mbIgnoreHints
|= (nCntrBits
[0] && (nCntrBits
[0] != 3));
733 mbIgnoreHints
|= (nCntrBits
[1] && (nCntrBits
[1] != 3));
737 for( i
= 0; i
< mnHintSize
; i
+=2) {
738 if(i
>= MASK_BITS
|| !(nHintMask
& (1U << i
)))
740 writeType1Val( mnHintStack
[i
]);
741 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
742 const bool bHorz
= (i
< mnHorzHintSize
);
743 if( !nCntrBits
[ bHorz
])
744 writeTypeOp( bHorz
? TYPE1OP::HSTEM
: TYPE1OP::VSTEM
);
745 else if( !--nCntrBits
[ bHorz
])
746 writeTypeEsc( bHorz
? TYPE1OP::HSTEM3
: TYPE1OP::VSTEM3
);
750 case TYPE2OP::CALLSUBR
:
751 case TYPE2OP::CALLGSUBR
:
754 const bool bGlobal
= (nType2Op
== TYPE2OP::CALLGSUBR
);
755 callType2Subr( bGlobal
, nInt
);
758 case TYPE2OP::RETURN
:
759 // TODO: check that we are in a subroutine
761 case TYPE2OP::VMOVETO
:
762 case TYPE2OP::HMOVETO
:
764 writeTypeOp( TYPE1OP::CLOSEPATH
);
766 updateWidth( size() > 1);
768 pop2MultiWrite( 1, nType2Op
);
770 case TYPE2OP::VLINETO
:
771 case TYPE2OP::HLINETO
:
772 pop2MultiWrite( 1, nType2Op
,
773 TYPE1OP::VLINETO
^ TYPE1OP::HLINETO
);
775 case TYPE2OP::RMOVETO
:
776 // TODO: convert rmoveto to vlineto/hlineto if possible
778 writeTypeOp( TYPE1OP::CLOSEPATH
);
780 updateWidth( size() > 2);
782 pop2MultiWrite( 2, nType2Op
);
784 case TYPE2OP::RLINETO
:
785 // TODO: convert rlineto to vlineto/hlineto if possible
786 pop2MultiWrite( 2, nType2Op
);
788 case TYPE2OP::RCURVETO
:
789 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
790 pop2MultiWrite( 6, nType2Op
);
792 case TYPE2OP::RCURVELINE
:
794 while( (i
+= 6) <= mnStackIdx
)
795 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
797 while( (i
+= 2) <= mnStackIdx
) {
798 writeType1Val( mnValStack
[i
-2]);
799 writeType1Val( mnValStack
[i
-1]);
800 writeTypeOp( TYPE2OP::RLINETO
);
804 case TYPE2OP::RLINECURVE
:
806 while( (i
+= 2) <= mnStackIdx
-6) {
807 writeType1Val( mnValStack
[i
-2]);
808 writeType1Val( mnValStack
[i
-1]);
809 writeTypeOp( TYPE2OP::RLINETO
);
812 while( (i
+= 6) <= mnStackIdx
)
813 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
816 case TYPE2OP::VHCURVETO
:
817 case TYPE2OP::HVCURVETO
:
819 bool bVert
= (nType2Op
== TYPE2OP::VHCURVETO
);
823 nInt
= static_cast<int>(mnValStack
[ --mnStackIdx
]);
824 while( (i
+= 4) <= mnStackIdx
) {
825 // TODO: use writeCurveTo()
826 if( bVert
) writeType1Val( 0 );
827 writeType1Val( mnValStack
[i
-4] );
828 if( !bVert
) writeType1Val( 0);
829 writeType1Val( mnValStack
[i
-3] );
830 writeType1Val( mnValStack
[i
-2] );
831 if( !bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
832 writeType1Val( mnValStack
[i
-1] );
833 if( bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
835 writeTypeOp( TYPE2OP::RCURVETO
);
840 case TYPE2OP::HHCURVETO
:
841 i
= (mnStackIdx
& 1);
842 while( (i
+= 4) <= mnStackIdx
) {
844 writeCurveTo( i
, -4, 0, -3, -2, -1, 0);
846 writeCurveTo( i
, -4, -5, -3, -2, -1, 0);
850 case TYPE2OP::VVCURVETO
:
851 i
= (mnStackIdx
& 1);
852 while( (i
+= 4) <= mnStackIdx
) {
854 writeCurveTo( i
, 0, -4, -3, -2, 0, -1);
856 writeCurveTo( i
, -5, -4, -3, -2, 0, -1);
860 case TYPE2OP::ENDCHAR
:
862 writeTypeOp( TYPE1OP::CLOSEPATH
);
864 updateWidth( size() >= 1);
865 // mbNeedClose = true;
866 writeTypeOp( TYPE1OP::ENDCHAR
);
869 if( ((nType2Op
>= 32) && (nType2Op
<= 255)) || (nType2Op
== 28)) {
873 popAll2Write( nType2Op
);
874 assert(false && "TODO?");
880 void CffSubsetterContext::convertOneTypeEsc()
882 const int nType2Esc
= *(mpReadPtr
++);
883 ValType
* pTop
= &mnValStack
[ mnStackIdx
-1];
887 assert( mnStackIdx
>= 2 );
888 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) & static_cast<int>(pTop
[-1]));
892 assert( mnStackIdx
>= 2 );
893 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) | static_cast<int>(pTop
[-1]));
897 assert( mnStackIdx
>= 1 );
898 pTop
[0] = ValType(pTop
[0] == 0);
901 assert( mnStackIdx
>= 1 );
906 assert( mnStackIdx
>= 1 );
910 assert( mnStackIdx
>= 2 );
915 assert( mnStackIdx
>= 2 );
920 assert( mnStackIdx
>= 2 );
926 assert( mnStackIdx
>= 2 );
932 assert( mnStackIdx
>= 2 );
933 pTop
[0] = ValType(pTop
[0] == pTop
[-1]);
937 assert( mnStackIdx
>= 1 );
941 assert( mnStackIdx
>= 2 );
942 const int nIdx
= static_cast<int>(pTop
[0]);
944 assert( nIdx
< NMAXTRANS
);
945 mnTransVals
[ nIdx
] = pTop
[-1];
950 assert( mnStackIdx
>= 1 );
951 const int nIdx
= static_cast<int>(pTop
[0]);
953 assert( nIdx
< NMAXTRANS
);
954 pTop
[0] = mnTransVals
[ nIdx
];
957 case TYPE2OP::IFELSE
: {
958 assert( mnStackIdx
>= 4 );
959 if( pTop
[-1] > pTop
[0] )
964 case TYPE2OP::RANDOM
:
965 pTop
[+1] = 1234; // TODO
972 assert( mnStackIdx
>= 1 );
976 case TYPE2OP::EXCH
: {
977 assert( mnStackIdx
>= 2 );
978 const ValType nVal
= pTop
[0];
983 case TYPE2OP::INDEX
: {
984 assert( mnStackIdx
>= 1 );
985 const int nVal
= static_cast<int>(pTop
[0]);
987 assert( nVal
< mnStackIdx
-1 );
988 pTop
[0] = pTop
[-1-nVal
];
991 case TYPE2OP::ROLL
: {
992 assert( mnStackIdx
>= 1 );
993 const int nNum
= static_cast<int>(pTop
[0]);
995 assert( nNum
< mnStackIdx
-2 );
996 (void)nNum
; // TODO: implement
997 // TODO: implement: const int nOfs = static_cast<int>(pTop[-1]);
1001 case TYPE2OP::HFLEX1
: {
1002 assert( mnStackIdx
== 9);
1004 writeCurveTo( mnStackIdx
, -9, -8, -7, -6, -5, 0);
1005 writeCurveTo( mnStackIdx
, -4, 0, -3, -2, -1, 0);
1006 // TODO: emulate hflex1 using othersubr call
1011 case TYPE2OP::HFLEX
: {
1012 assert( mnStackIdx
== 7);
1013 ValType
* pX
= &mnValStack
[ mnStackIdx
];
1015 pX
[+1] = -pX
[-5]; // temp: +dy5==-dy2
1016 writeCurveTo( mnStackIdx
, -7, 0, -6, -5, -4, 0);
1017 writeCurveTo( mnStackIdx
, -3, 0, -2, +1, -1, 0);
1018 // TODO: emulate hflex using othersubr call
1023 case TYPE2OP::FLEX
: {
1024 assert( mnStackIdx
== 13 );
1025 writeCurveTo( mnStackIdx
, -13, -12, -11, -10, -9, -8 );
1026 writeCurveTo( mnStackIdx
, -7, -6, -5, -4, -3, -2 );
1027 // ignoring ValType nFlexDepth = mnValStack[ mnStackIdx-1 ];
1031 case TYPE2OP::FLEX1
: {
1032 assert( mnStackIdx
== 11 );
1033 // write the first part of the flex1-hinted curve
1034 writeCurveTo( mnStackIdx
, -11, -10, -9, -8, -7, -6 );
1036 // determine if nD6 is horizontal or vertical
1037 const int i
= mnStackIdx
;
1038 ValType nDeltaX
= mnValStack
[i
-11] + mnValStack
[i
-9] + mnValStack
[i
-7] + mnValStack
[i
-5] + mnValStack
[i
-3];
1039 if( nDeltaX
< 0 ) nDeltaX
= -nDeltaX
;
1040 ValType nDeltaY
= mnValStack
[i
-10] + mnValStack
[i
-8] + mnValStack
[i
-6] + mnValStack
[i
-4] + mnValStack
[i
-2];
1041 if( nDeltaY
< 0 ) nDeltaY
= -nDeltaY
;
1042 const bool bVertD6
= (nDeltaY
> nDeltaX
);
1044 // write the second part of the flex1-hinted curve
1046 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, -1, 0);
1048 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, 0, -1);
1053 fprintf( stderr
,"unhandled type2esc %d\n", nType2Esc
);
1059 void CffSubsetterContext::callType2Subr( bool bGlobal
, int nSubrNumber
)
1061 const U8
* const pOldReadPtr
= mpReadPtr
;
1062 const U8
* const pOldReadEnd
= mpReadEnd
;
1065 nSubrNumber
+= mnGlobalSubrBias
;
1066 seekIndexData( mnGlobalSubrBase
, nSubrNumber
);
1068 nSubrNumber
+= mpCffLocal
->mnLocalSubrBias
;
1069 seekIndexData( mpCffLocal
->mnLocalSubrBase
, nSubrNumber
);
1072 while( mpReadPtr
< mpReadEnd
)
1075 mpReadPtr
= pOldReadPtr
;
1076 mpReadEnd
= pOldReadEnd
;
1079 static const int MAX_T1OPS_SIZE
= 81920; // TODO: use dynamic value
1081 int CffSubsetterContext::convert2Type1Ops( CffLocal
* pCffLocal
, const U8
* const pT2Ops
, int nT2Len
, U8
* const pT1Ops
)
1083 mpCffLocal
= pCffLocal
;
1085 // prepare the charstring conversion
1086 mpWritePtr
= pT1Ops
;
1087 U8 aType1Ops
[ MAX_T1OPS_SIZE
];
1089 mpWritePtr
= aType1Ops
;
1090 *const_cast<U8
**>(&pT1Ops
) = mpWritePtr
;
1092 // prepend random seed for T1crypt
1093 *(mpWritePtr
++) = 0x48;
1094 *(mpWritePtr
++) = 0x44;
1095 *(mpWritePtr
++) = 0x55;
1096 *(mpWritePtr
++) = ' ';
1098 // convert the Type2 charstring to Type1
1100 mpReadEnd
= pT2Ops
+ nT2Len
;
1101 // prepend "hsbw" or "sbw"
1102 // TODO: only emit hsbw when charwidth is known
1103 writeType1Val(0); // TODO: aSubsetterContext.getLeftSideBearing();
1104 U8
* pCharWidthPtr
=mpWritePtr
; // need to overwrite that later
1105 // pad out 5 bytes for the char width with default val 1000 (to be
1106 // filled with the actual value below)
1107 *(mpWritePtr
++) = 255;
1108 *(mpWritePtr
++) = static_cast<U8
>(0);
1109 *(mpWritePtr
++) = static_cast<U8
>(0);
1110 *(mpWritePtr
++) = static_cast<U8
>(250);
1111 *(mpWritePtr
++) = static_cast<U8
>(124);
1112 writeTypeOp(TYPE1OP::HSBW
);
1113 mbNeedClose
= false;
1114 mbIgnoreHints
= false;
1115 mnHintSize
=mnHorzHintSize
=mnStackIdx
=0; maCharWidth
=-1;//#######
1117 while( mpReadPtr
< mpReadEnd
)
1119 if( maCharWidth
!= -1 )
1121 // overwrite earlier charWidth value, which we only now have
1122 // parsed out of mpReadPtr buffer (by way of
1123 // convertOneTypeOp()s above)
1124 const int nInt
= static_cast<int>(maCharWidth
);
1125 *(pCharWidthPtr
++) = 255;
1126 *(pCharWidthPtr
++) = static_cast<U8
>(nInt
>> 24);
1127 *(pCharWidthPtr
++) = static_cast<U8
>(nInt
>> 16);
1128 *(pCharWidthPtr
++) = static_cast<U8
>(nInt
>> 8);
1129 *(pCharWidthPtr
++) = static_cast<U8
>(nInt
);
1132 const int nType1Len
= mpWritePtr
- pT1Ops
;
1134 // encrypt the Type1 charstring
1135 unsigned nRDCryptR
= 4330; // TODO: mnRDCryptSeed;
1136 for( U8
* p
= pT1Ops
; p
< mpWritePtr
; ++p
) {
1137 *p
^= (nRDCryptR
>> 8);
1138 nRDCryptR
= (*p
+ nRDCryptR
) * 52845 + 22719;
1144 RealType
CffSubsetterContext::readRealVal()
1146 // TODO: more thorough number validity test
1147 bool bComma
= false;
1151 RealType fReal
= +1.0;
1153 const U8 c
= *(mpReadPtr
++); // read nibbles
1154 // parse high nibble
1155 const U8 nH
= c
>> 4U;
1157 nNumber
= nNumber
* 10 + nH
;
1159 } else if( nH
== 10) { // comma
1162 } else if( nH
== 11) { // +exp
1166 } else if( nH
== 12) { // -exp
1170 } else if( nH
== 13) { // reserved
1171 // TODO: ignore or error?
1172 } else if( nH
== 14) // minus
1174 else if( nH
== 15) // end
1177 const U8 nL
= c
& 0x0F;
1179 nNumber
= nNumber
* 10 + nL
;
1181 } else if( nL
== 10) { // comma
1184 } else if( nL
== 11) { // +exp
1188 } else if( nL
== 12) { // -exp
1192 } else if( nL
== 13) { // reserved
1193 // TODO: ignore or error?
1194 } else if( nL
== 14) // minus
1196 else if( nL
== 15) // end
1203 if( !nExpSign
) { fReal
*= nNumber
;}
1204 else if( nExpSign
> 0) { nExpVal
+= static_cast<int>(nNumber
);}
1205 else if( nExpSign
< 0) { nExpVal
-= static_cast<int>(nNumber
);}
1208 if( !nExpVal
) { /*nothing to apply*/}
1209 else if( nExpVal
> 0) { while( --nExpVal
>= 0) fReal
*= 10.0;}
1210 else if( nExpVal
< 0) { while( ++nExpVal
<= 0) fReal
/= 10.0;}
1214 // prepare to access an element inside a CFF/CID index table
1215 int CffSubsetterContext::seekIndexData( int nIndexBase
, int nDataIndex
)
1217 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1220 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1221 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1222 if( nDataIndex
>= nDataCount
)
1224 const int nDataOfsSz
= mpReadPtr
[2];
1225 mpReadPtr
+= 3 + (nDataOfsSz
* nDataIndex
);
1227 switch( nDataOfsSz
) {
1228 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return -1;
1229 case 1: nOfs1
= mpReadPtr
[0]; break;
1230 case 2: nOfs1
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1231 case 3: nOfs1
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1232 case 4: nOfs1
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1234 mpReadPtr
+= nDataOfsSz
;
1237 switch( nDataOfsSz
) {
1238 case 1: nOfs2
= mpReadPtr
[0]; break;
1239 case 2: nOfs2
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1240 case 3: nOfs2
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1241 case 4: nOfs2
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1244 mpReadPtr
= mpBasePtr
+ (nIndexBase
+ 2) + nDataOfsSz
* (nDataCount
+ 1) + nOfs1
;
1245 mpReadEnd
= mpReadPtr
+ (nOfs2
- nOfs1
);
1246 assert( nOfs1
>= 0);
1247 assert( nOfs2
>= nOfs1
);
1248 assert( mpReadPtr
<= mpBaseEnd
);
1249 assert( mpReadEnd
<= mpBaseEnd
);
1250 return (nOfs2
- nOfs1
);
1253 // skip over a CFF/CID index table
1254 void CffSubsetterContext::seekIndexEnd( int nIndexBase
)
1256 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1257 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1258 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1259 const int nDataOfsSz
= mpReadPtr
[2];
1260 mpReadPtr
+= 3 + nDataOfsSz
* nDataCount
;
1261 assert( mpReadPtr
<= mpBaseEnd
);
1263 switch( nDataOfsSz
) {
1264 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return;
1265 case 1: nEndOfs
= mpReadPtr
[0]; break;
1266 case 2: nEndOfs
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1267 case 3: nEndOfs
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2];break;
1268 case 4: nEndOfs
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1270 mpReadPtr
+= nDataOfsSz
;
1271 mpReadPtr
+= nEndOfs
- 1;
1272 mpReadEnd
= mpBaseEnd
;
1273 assert( nEndOfs
>= 0);
1274 assert( mpReadEnd
<= mpBaseEnd
);
1277 // initialize FONTDICT specific values
1278 CffLocal::CffLocal()
1279 : mnPrivDictBase( 0)
1280 , mnPrivDictSize( 0)
1281 , mnLocalSubrOffs( 0)
1282 , mnLocalSubrBase( 0)
1283 , mnLocalSubrBias( 0)
1284 , maNominalWidth( 0)
1285 , maDefaultWidth( 0)
1293 , mbForceBold( false)
1297 CffGlobal::CffGlobal()
1299 , mnStringIdxBase( 0)
1302 , mnCharStrCount( 0)
1304 , mnGlobalSubrBase( 0)
1305 , mnGlobalSubrCount( 0)
1306 , mnGlobalSubrBias( 0)
1307 , mnFDSelectBase( 0)
1308 , mnFontDictBase( 0)
1315 bool CffSubsetterContext::initialCffRead()
1317 // get the CFFHeader
1318 mpReadPtr
= mpBasePtr
;
1319 const U8 nVerMajor
= *(mpReadPtr
++);
1320 const U8 nVerMinor
= *(mpReadPtr
++);
1321 const U8 nHeaderSize
= *(mpReadPtr
++);
1322 const U8 nOffsetSize
= *(mpReadPtr
++);
1323 // TODO: is the version number useful for anything else?
1324 assert( (nVerMajor
== 1) && (nVerMinor
== 0));
1325 (void)(nVerMajor
+ nVerMinor
+ nOffsetSize
); // avoid compiler warnings
1327 // prepare access to the NameIndex
1328 mnNameIdxBase
= nHeaderSize
;
1329 mpReadPtr
= mpBasePtr
+ nHeaderSize
;
1330 seekIndexEnd( mnNameIdxBase
);
1332 // get the TopDict index
1333 const sal_Int32 nTopDictBase
= getReadOfs();
1334 const int nTopDictCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1335 if( nTopDictCount
) {
1336 for( int i
= 0; i
< nTopDictCount
; ++i
) {
1337 seekIndexData( nTopDictBase
, i
);
1338 while( mpReadPtr
< mpReadEnd
)
1340 assert( mpReadPtr
== mpReadEnd
);
1344 // prepare access to the String index
1345 mnStringIdxBase
= getReadOfs();
1346 seekIndexEnd( mnStringIdxBase
);
1348 // prepare access to the GlobalSubr index
1349 mnGlobalSubrBase
= getReadOfs();
1350 mnGlobalSubrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1351 mnGlobalSubrBias
= (mnGlobalSubrCount
<1240)?107:(mnGlobalSubrCount
<33900)?1131:32768;
1352 // skip past the last GlobalSubr entry
1353 // seekIndexEnd( mnGlobalSubrBase);
1355 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1356 // seekEncodingsEnd( mnEncodingBase);
1357 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1358 // seekCharsetsEnd( mnCharStrBase);
1359 // get/skip FDSelect (CID only) data
1361 // prepare access to the CharStrings index (we got the base from TOPDICT)
1362 mpReadPtr
= mpBasePtr
+ mnCharStrBase
;
1363 mnCharStrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1364 // seekIndexEnd( mnCharStrBase);
1366 // read the FDArray index (CID only)
1368 // assert( mnFontDictBase == tellRel());
1369 mpReadPtr
= mpBasePtr
+ mnFontDictBase
;
1370 mnFDAryCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1371 if (static_cast<size_t>(mnFDAryCount
) >= SAL_N_ELEMENTS(maCffLocal
))
1373 SAL_INFO("vcl.fonts", "CffSubsetterContext: too many CFF in font");
1377 // read FDArray details to get access to the PRIVDICTs
1378 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1379 mpCffLocal
= &maCffLocal
[i
];
1380 seekIndexData( mnFontDictBase
, i
);
1381 while( mpReadPtr
< mpReadEnd
)
1383 assert( mpReadPtr
== mpReadEnd
);
1387 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1388 mpCffLocal
= &maCffLocal
[i
];
1390 // get the PrivateDict index
1391 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1392 if( mpCffLocal
->mnPrivDictSize
!= 0) {
1393 assert( mpCffLocal
->mnPrivDictSize
> 0);
1394 // get the PrivDict data
1395 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnPrivDictBase
;
1396 mpReadEnd
= mpReadPtr
+ mpCffLocal
->mnPrivDictSize
;
1397 assert( mpReadEnd
<= mpBaseEnd
);
1398 // read PrivDict details
1399 while( mpReadPtr
< mpReadEnd
)
1403 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1404 if( mpCffLocal
->mnLocalSubrOffs
) {
1405 // read LocalSubrs summary
1406 mpCffLocal
->mnLocalSubrBase
= mpCffLocal
->mnPrivDictBase
+ mpCffLocal
->mnLocalSubrOffs
;
1407 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnLocalSubrBase
;
1408 const int nSubrCount
= (mpReadPtr
[0] << 8) + mpReadPtr
[1];
1409 mpCffLocal
->mnLocalSubrBias
= (nSubrCount
<1240)?107:(nSubrCount
<33900)?1131:32768;
1410 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1414 // ignore the Notices info
1419 // get a cstring from a StringID
1420 const char* CffSubsetterContext::getString( int nStringID
)
1422 // get a standard string if possible
1423 const static int nStdStrings
= SAL_N_ELEMENTS(pStringIds
);
1424 if( (nStringID
>= 0) && (nStringID
< nStdStrings
))
1425 return pStringIds
[ nStringID
];
1427 // else get the string from the StringIndex table
1428 const U8
* pReadPtr
= mpReadPtr
;
1429 const U8
* pReadEnd
= mpReadEnd
;
1430 nStringID
-= nStdStrings
;
1431 int nLen
= seekIndexData( mnStringIdxBase
, nStringID
);
1432 // assert( nLen >= 0);
1433 // TODO: just return the undecorated name
1434 // TODO: get rid of static char buffer
1435 static char aNameBuf
[ 2560];
1437 sprintf( aNameBuf
, "name[%d].notfound!", nStringID
);
1439 const int nMaxLen
= sizeof(aNameBuf
) - 1;
1440 if( nLen
>= nMaxLen
)
1442 for( int i
= 0; i
< nLen
; ++i
)
1443 aNameBuf
[i
] = *(mpReadPtr
++);
1444 aNameBuf
[ nLen
] = '\0';
1446 mpReadPtr
= pReadPtr
;
1447 mpReadEnd
= pReadEnd
;
1451 // access a CID's FDSelect table
1452 int CffSubsetterContext::getFDSelect( int nGlyphIndex
) const
1454 assert( nGlyphIndex
>= 0);
1455 assert( nGlyphIndex
< mnCharStrCount
);
1459 const U8
* pReadPtr
= mpBasePtr
+ mnFDSelectBase
;
1460 const U8 nFDSelFormat
= *(pReadPtr
++);
1461 switch( nFDSelFormat
) {
1462 case 0: { // FDSELECT format 0
1463 pReadPtr
+= nGlyphIndex
;
1464 const U8 nFDIdx
= *(pReadPtr
++);
1467 case 3: { // FDSELECT format 3
1468 const U16 nRangeCount
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1469 assert( nRangeCount
> 0);
1470 assert( nRangeCount
<= mnCharStrCount
);
1471 U16 nPrev
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1472 assert( nPrev
== 0);
1475 // TODO? binary search
1476 for( int i
= 0; i
< nRangeCount
; ++i
) {
1477 const U8 nFDIdx
= pReadPtr
[0];
1478 const U16 nNext
= (pReadPtr
[1]<<8) + pReadPtr
[2];
1479 assert( nPrev
< nNext
);
1480 if( nGlyphIndex
< nNext
)
1486 default: // invalid FDselect format
1487 fprintf( stderr
, "invalid CFF.FdselType=%d\n", nFDSelFormat
);
1495 int CffSubsetterContext::getGlyphSID( int nGlyphIndex
) const
1497 if( nGlyphIndex
== 0)
1498 return 0; // ".notdef"
1499 assert( nGlyphIndex
>= 0);
1500 assert( nGlyphIndex
< mnCharStrCount
);
1501 if( (nGlyphIndex
< 0) || (nGlyphIndex
>= mnCharStrCount
))
1504 // get the SID/CID from the Charset table
1505 const U8
* pReadPtr
= mpBasePtr
+ mnCharsetBase
;
1506 const U8 nCSetFormat
= *(pReadPtr
++);
1507 int nGlyphsToSkip
= nGlyphIndex
- 1;
1508 switch( nCSetFormat
) {
1509 case 0: // charset format 0
1510 pReadPtr
+= 2 * nGlyphsToSkip
;
1513 case 1: // charset format 1
1514 while( nGlyphsToSkip
>= 0) {
1515 const int nLeft
= pReadPtr
[2];
1516 if( nGlyphsToSkip
<= nLeft
)
1518 nGlyphsToSkip
-= nLeft
+ 1;
1522 case 2: // charset format 2
1523 while( nGlyphsToSkip
>= 0) {
1524 const int nLeft
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1525 if( nGlyphsToSkip
<= nLeft
)
1527 nGlyphsToSkip
-= nLeft
+ 1;
1532 fprintf( stderr
, "ILLEGAL CFF-Charset format %d\n", nCSetFormat
);
1536 int nSID
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1537 nSID
+= nGlyphsToSkip
;
1538 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1542 // NOTE: the result becomes invalid with the next call to this method
1543 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex
)
1545 // the first glyph is always the .notdef glyph
1546 const char* pGlyphName
= ".notdef";
1547 if( nGlyphIndex
== 0)
1550 // prepare a result buffer
1551 // TODO: get rid of static buffer
1552 static char aDefaultGlyphName
[64];
1553 pGlyphName
= aDefaultGlyphName
;
1555 // get the glyph specific name
1556 const int nSID
= getGlyphSID( nGlyphIndex
);
1557 if( nSID
< 0) // default glyph name
1558 sprintf( aDefaultGlyphName
, "gly%03d", nGlyphIndex
);
1559 else if( mbCIDFont
) // default glyph name in CIDs
1560 sprintf( aDefaultGlyphName
, "cid%03d", nSID
);
1561 else { // glyph name from string table
1562 const char* pSidName
= getString( nSID
);
1563 // check validity of glyph name
1565 const char* p
= pSidName
;
1566 while( (*p
>= '0') && (*p
<= 'z')) ++p
;
1567 if( (p
>= pSidName
+1) && (*p
== '\0'))
1568 pGlyphName
= pSidName
;
1570 // if needed invent a fallback name
1571 if( pGlyphName
!= pSidName
)
1572 sprintf( aDefaultGlyphName
, "bad%03d", nSID
);
1581 explicit Type1Emitter( FILE* pOutFile
, bool bPfbSubset
);
1583 void setSubsetName( const char* );
1585 size_t emitRawData( const char* pData
, size_t nLength
) const;
1588 void emitAllCrypted();
1589 int tellPos() const;
1590 void updateLen( int nTellPos
, size_t nLength
);
1591 void emitValVector( const char* pLineHead
, const char* pLineTail
, const std::vector
<ValType
>&);
1594 char maBuffer
[MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
1595 unsigned mnEECryptR
;
1599 char maSubsetName
[256];
1600 bool const mbPfbSubset
;
1604 Type1Emitter::Type1Emitter( FILE* pOutFile
, bool bPfbSubset
)
1605 : mpFileOut( pOutFile
)
1607 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1609 , mbPfbSubset( bPfbSubset
)
1612 maSubsetName
[0] = '\0';
1615 Type1Emitter::~Type1Emitter()
1619 mpFileOut
= nullptr;
1622 void Type1Emitter::setSubsetName( const char* pSubsetName
)
1624 maSubsetName
[0] = '\0';
1626 strncpy( maSubsetName
, pSubsetName
, sizeof(maSubsetName
));
1627 maSubsetName
[sizeof(maSubsetName
)-1] = '\0';
1630 int Type1Emitter::tellPos() const
1632 int nTellPos
= ftell( mpFileOut
);
1636 void Type1Emitter::updateLen( int nTellPos
, size_t nLength
)
1638 // update PFB segment header length
1640 cData
[0] = static_cast<U8
>(nLength
>> 0);
1641 cData
[1] = static_cast<U8
>(nLength
>> 8);
1642 cData
[2] = static_cast<U8
>(nLength
>> 16);
1643 cData
[3] = static_cast<U8
>(nLength
>> 24);
1644 const long nCurrPos
= ftell(mpFileOut
);
1647 if (fseek( mpFileOut
, nTellPos
, SEEK_SET
) != 0)
1649 fwrite(cData
, 1, sizeof(cData
), mpFileOut
);
1650 (void)fseek(mpFileOut
, nCurrPos
, SEEK_SET
);
1653 inline size_t Type1Emitter::emitRawData(const char* pData
, size_t nLength
) const
1655 return fwrite( pData
, 1, nLength
, mpFileOut
);
1658 inline void Type1Emitter::emitAllRaw()
1660 // writeout raw data
1661 assert( (mpPtr
- maBuffer
) < int(sizeof(maBuffer
)));
1662 emitRawData( maBuffer
, mpPtr
- maBuffer
);
1663 // reset the raw buffer
1667 inline void Type1Emitter::emitAllHex()
1669 assert( (mpPtr
- maBuffer
) < int(sizeof(maBuffer
)));
1670 for( const char* p
= maBuffer
; p
< mpPtr
;) {
1671 // convert binary chunk to hex
1672 char aHexBuf
[0x4000];
1673 char* pOut
= aHexBuf
;
1674 while( (p
< mpPtr
) && (pOut
< aHexBuf
+sizeof(aHexBuf
)-4)) {
1675 // convert each byte to hex
1676 char cNibble
= (static_cast<unsigned char>(*p
) >> 4) & 0x0F;
1677 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1678 *(pOut
++) = cNibble
;
1679 cNibble
= *(p
++) & 0x0F;
1680 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1681 *(pOut
++) = cNibble
;
1682 // limit the line length
1683 if( (++mnHexLineCol
& 0x3F) == 0)
1686 // writeout hex-converted chunk
1687 emitRawData( aHexBuf
, pOut
-aHexBuf
);
1689 // reset the raw buffer
1693 void Type1Emitter::emitAllCrypted()
1696 for( char* p
= maBuffer
; p
< mpPtr
; ++p
) {
1697 *p
^= (mnEECryptR
>> 8);
1698 mnEECryptR
= (*reinterpret_cast<U8
*>(p
) + mnEECryptR
) * 52845 + 22719;
1701 // emit the t1crypt result
1708 // #i110387# quick-and-dirty double->ascii conversion
1709 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
1710 // also strip off trailing zeros in fraction while we are at it
1711 static int dbl2str( char* pOut
, double fVal
)
1713 const int nLen
= psp::getValueOfDouble( pOut
, fVal
, 6);
1717 void Type1Emitter::emitValVector( const char* pLineHead
, const char* pLineTail
,
1718 const std::vector
<ValType
>& rVector
)
1720 // ignore empty vectors
1721 if( rVector
.empty())
1724 // emit the line head
1725 mpPtr
+= sprintf( mpPtr
, "%s", pLineHead
);
1726 // emit the vector values
1727 std::vector
<ValType
>::value_type aVal
= 0;
1728 for( std::vector
<ValType
>::const_iterator it
= rVector
.begin();;) {
1730 if( ++it
== rVector
.end() )
1732 mpPtr
+= dbl2str( mpPtr
, aVal
);
1735 // emit the last value
1736 mpPtr
+= dbl2str( mpPtr
, aVal
);
1737 // emit the line tail
1738 mpPtr
+= sprintf( mpPtr
, "%s", pLineTail
);
1741 void CffSubsetterContext::emitAsType1( Type1Emitter
& rEmitter
,
1742 const sal_GlyphId
* pReqGlyphIds
, const U8
* pReqEncoding
,
1743 sal_Int32
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rFSInfo
)
1745 // prepare some fontdirectory details
1746 static const int nUniqueIdBase
= 4100000; // using private-interchange UniqueIds
1747 static int nUniqueId
= nUniqueIdBase
;
1750 char* pFontName
= rEmitter
.maSubsetName
;
1752 if( mnFontNameSID
) {
1753 // get the fontname directly if available
1754 strncpy( pFontName
, getString( mnFontNameSID
), sizeof(rEmitter
.maSubsetName
) - 1);
1755 pFontName
[sizeof(rEmitter
.maSubsetName
) - 1] = 0;
1756 } else if( mnFullNameSID
) {
1757 // approximate fontname as fullname-whitespace
1758 const char* pI
= getString( mnFullNameSID
);
1759 char* pO
= pFontName
;
1760 const char* pLimit
= pFontName
+ sizeof(rEmitter
.maSubsetName
) - 1;
1761 while( pO
< pLimit
) {
1762 const char c
= *(pI
++);
1770 // fallback name of last resort
1771 strncpy( pFontName
, "DummyName", sizeof(rEmitter
.maSubsetName
));
1774 const char* pFullName
= pFontName
;
1775 const char* pFamilyName
= pFontName
;
1777 char*& pOut
= rEmitter
.mpPtr
; // convenience reference, TODO: cleanup
1779 // create a PFB+Type1 header
1780 if( rEmitter
.mbPfbSubset
) {
1781 static const char aPfbHeader
[] = "\x80\x01\x00\x00\x00\x00";
1782 rEmitter
.emitRawData( aPfbHeader
, sizeof(aPfbHeader
)-1);
1785 pOut
+= sprintf( pOut
, "%%!FontType1-1.0: %s 001.003\n", rEmitter
.maSubsetName
);
1787 pOut
+= sprintf( pOut
,
1788 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
1790 "/PaintType 0 def\n");
1791 pOut
+= sprintf( pOut
, "/FontName /%s def\n", rEmitter
.maSubsetName
);
1792 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
1794 if( maFontMatrix
.size() == 6)
1795 rEmitter
.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix
);
1796 else // emit default FontMatrix if needed
1797 pOut
+= sprintf( pOut
, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
1799 if( maFontBBox
.size() == 4)
1800 rEmitter
.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox
);
1801 else // emit default FontBBox if needed
1802 pOut
+= sprintf( pOut
, "/FontBBox {0 0 999 999}readonly def\n");
1803 // emit FONTINFO into TOPDICT
1804 pOut
+= sprintf( pOut
,
1805 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
1806 " /FullName (%s) readonly def\n"
1807 " /FamilyName (%s) readonly def\n"
1808 "end readonly def\n",
1809 pFullName
, pFamilyName
);
1811 pOut
+= sprintf( pOut
,
1812 "/Encoding 256 array\n"
1813 "0 1 255 {1 index exch /.notdef put} for\n");
1814 for( int i
= 1; (i
< nGlyphCount
) && (i
< 256); ++i
) {
1815 const char* pGlyphName
= getGlyphName( pReqGlyphIds
[i
]);
1816 pOut
+= sprintf( pOut
, "dup %d /%s put\n", pReqEncoding
[i
], pGlyphName
);
1818 pOut
+= sprintf( pOut
, "readonly def\n");
1819 pOut
+= sprintf( pOut
,
1820 // TODO: more topdict entries
1822 "currentfile eexec\n");
1825 rEmitter
.emitAllRaw();
1826 if( rEmitter
.mbPfbSubset
) {
1827 // update PFB header segment
1828 const int nPfbHeaderLen
= rEmitter
.tellPos() - 6;
1829 rEmitter
.updateLen( 2, nPfbHeaderLen
);
1831 // prepare start of eexec segment
1832 rEmitter
.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
1834 const int nEExecSegTell
= rEmitter
.tellPos();
1836 // which always starts with a privdict
1837 // count the privdict entries
1838 int nPrivEntryCount
= 9;
1839 // emit blue hints only if non-default values
1840 nPrivEntryCount
+= int(!mpCffLocal
->maOtherBlues
.empty());
1841 nPrivEntryCount
+= int(!mpCffLocal
->maFamilyBlues
.empty());
1842 nPrivEntryCount
+= int(!mpCffLocal
->maFamilyOtherBlues
.empty());
1843 nPrivEntryCount
+= int(mpCffLocal
->mfBlueScale
!= 0.0);
1844 nPrivEntryCount
+= int(mpCffLocal
->mfBlueShift
!= 0.0);
1845 nPrivEntryCount
+= int(mpCffLocal
->mfBlueFuzz
!= 0.0);
1846 // emit stem hints only if non-default values
1847 nPrivEntryCount
+= int(mpCffLocal
->maStemStdHW
!= 0);
1848 nPrivEntryCount
+= int(mpCffLocal
->maStemStdVW
!= 0);
1849 nPrivEntryCount
+= int(!mpCffLocal
->maStemSnapH
.empty());
1850 nPrivEntryCount
+= int(!mpCffLocal
->maStemSnapV
.empty());
1851 // emit other hints only if non-default values
1852 nPrivEntryCount
+= int(mpCffLocal
->mfExpFactor
!= 0.0);
1853 nPrivEntryCount
+= int(mpCffLocal
->mnLangGroup
!= 0);
1854 nPrivEntryCount
+= int(mpCffLocal
->mnLangGroup
== 1);
1855 nPrivEntryCount
+= int(mpCffLocal
->mbForceBold
);
1856 // emit the privdict header
1857 pOut
+= sprintf( pOut
,
1859 "dup\n/Private %d dict dup begin\n"
1860 "/RD{string currentfile exch readstring pop}executeonly def\n"
1861 "/ND{noaccess def}executeonly def\n"
1862 "/NP{noaccess put}executeonly def\n"
1863 "/MinFeature{16 16}ND\n"
1864 "/password 5839 def\n", // TODO: mnRDCryptSeed?
1867 // emit blue hint related privdict entries
1868 if( !mpCffLocal
->maBlueValues
.empty())
1869 rEmitter
.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal
->maBlueValues
);
1871 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // default to empty BlueValues
1872 rEmitter
.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal
->maOtherBlues
);
1873 rEmitter
.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal
->maFamilyBlues
);
1874 rEmitter
.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal
->maFamilyOtherBlues
);
1876 if( mpCffLocal
->mfBlueScale
) {
1877 pOut
+= sprintf( pOut
, "/BlueScale ");
1878 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueScale
);
1879 pOut
+= sprintf( pOut
, " def\n");
1881 if( mpCffLocal
->mfBlueShift
) { // default BlueShift==7
1882 pOut
+= sprintf( pOut
, "/BlueShift ");
1883 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueShift
);
1884 pOut
+= sprintf( pOut
, " def\n");
1886 if( mpCffLocal
->mfBlueFuzz
) { // default BlueFuzz==1
1887 pOut
+= sprintf( pOut
, "/BlueFuzz ");
1888 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueFuzz
);
1889 pOut
+= sprintf( pOut
, " def\n");
1892 // emit stem hint related privdict entries
1893 if( mpCffLocal
->maStemStdHW
) {
1894 pOut
+= sprintf( pOut
, "/StdHW [");
1895 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdHW
);
1896 pOut
+= sprintf( pOut
, "] def\n");
1898 if( mpCffLocal
->maStemStdVW
) {
1899 pOut
+= sprintf( pOut
, "/StdVW [");
1900 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdVW
);
1901 pOut
+= sprintf( pOut
, "] def\n");
1903 rEmitter
.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal
->maStemSnapH
);
1904 rEmitter
.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal
->maStemSnapV
);
1907 if( mpCffLocal
->mbForceBold
)
1908 pOut
+= sprintf( pOut
, "/ForceBold true def\n");
1909 if( mpCffLocal
->mnLangGroup
!= 0)
1910 pOut
+= sprintf( pOut
, "/LanguageGroup %d def\n", mpCffLocal
->mnLangGroup
);
1911 if( mpCffLocal
->mnLangGroup
== 1) // compatibility with ancient printers
1912 pOut
+= sprintf( pOut
, "/RndStemUp false def\n");
1913 if( mpCffLocal
->mfExpFactor
) {
1914 pOut
+= sprintf( pOut
, "/ExpansionFactor ");
1915 pOut
+= dbl2str( pOut
, mpCffLocal
->mfExpFactor
);
1916 pOut
+= sprintf( pOut
, " def\n");
1919 // emit remaining privdict entries
1920 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
1921 // TODO?: more privdict entries?
1923 static const char aOtherSubrs
[] =
1925 "% Dummy code for faking flex hints\n"
1926 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
1927 "{1183615869 systemdict /internaldict get exec\n"
1928 "dup /startlock known\n"
1929 "{/startlock get exec}\n"
1930 "{dup /strtlck known\n"
1931 "{/strtlck get exec}\n"
1932 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
1934 memcpy( pOut
, aOtherSubrs
, sizeof(aOtherSubrs
)-1);
1935 pOut
+= sizeof(aOtherSubrs
)-1;
1937 // emit used GlobalSubr charstrings
1938 // these are the just the default subrs
1939 // TODO: do we need them as the flex hints are resolved differently?
1940 static const char aSubrs
[] =
1942 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
1943 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
1944 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
1945 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
1946 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
1948 memcpy( pOut
, aSubrs
, sizeof(aSubrs
)-1);
1949 pOut
+= sizeof(aSubrs
)-1;
1951 // TODO: emit more GlobalSubr charstrings?
1952 // TODO: emit used LocalSubr charstrings?
1954 // emit the CharStrings for the requested glyphs
1955 pOut
+= sprintf( pOut
,
1956 "2 index /CharStrings %d dict dup begin\n", nGlyphCount
);
1957 rEmitter
.emitAllCrypted();
1958 for( int i
= 0; i
< nGlyphCount
; ++i
) {
1959 const int nCffGlyphId
= pReqGlyphIds
[i
];
1960 assert( (nCffGlyphId
>= 0) && (nCffGlyphId
< mnCharStrCount
));
1961 // get privdict context matching to the glyph
1962 const int nFDSelect
= getFDSelect( nCffGlyphId
);
1965 mpCffLocal
= &maCffLocal
[ nFDSelect
];
1966 // convert the Type2op charstring to its Type1op counterpart
1967 const int nT2Len
= seekIndexData( mnCharStrBase
, nCffGlyphId
);
1968 assert( nT2Len
> 0);
1969 U8 aType1Ops
[ MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
1970 const int nT1Len
= convert2Type1Ops( mpCffLocal
, mpReadPtr
, nT2Len
, aType1Ops
);
1971 // get the glyph name
1972 const char* pGlyphName
= getGlyphName( nCffGlyphId
);
1973 // emit the encrypted Type1op charstring
1974 pOut
+= sprintf( pOut
, "/%s %d RD ", pGlyphName
, nT1Len
);
1975 memcpy( pOut
, aType1Ops
, nT1Len
);
1977 pOut
+= sprintf( pOut
, " ND\n");
1978 rEmitter
.emitAllCrypted();
1979 // provide individual glyphwidths if requested
1980 if( pGlyphWidths
) {
1981 ValType aCharWidth
= getCharWidth();
1982 if( maFontMatrix
.size() >= 4)
1983 aCharWidth
*= 1000.0F
* maFontMatrix
[0];
1984 pGlyphWidths
[i
] = static_cast<sal_Int32
>(aCharWidth
);
1987 pOut
+= sprintf( pOut
, "end end\nreadonly put\nput\n");
1988 pOut
+= sprintf( pOut
, "dup/FontName get exch definefont pop\n");
1989 pOut
+= sprintf( pOut
, "mark currentfile closefile\n");
1990 rEmitter
.emitAllCrypted();
1992 // mark stop of eexec encryption
1993 if( rEmitter
.mbPfbSubset
) {
1994 const int nEExecLen
= rEmitter
.tellPos() - nEExecSegTell
;
1995 rEmitter
.updateLen( nEExecSegTell
-4, nEExecLen
);
1998 // create PFB footer
1999 static const char aPfxFooter
[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2000 "0000000000000000000000000000000000000000000000000000000000000000\n"
2001 "0000000000000000000000000000000000000000000000000000000000000000\n"
2002 "0000000000000000000000000000000000000000000000000000000000000000\n"
2003 "0000000000000000000000000000000000000000000000000000000000000000\n"
2004 "0000000000000000000000000000000000000000000000000000000000000000\n"
2005 "0000000000000000000000000000000000000000000000000000000000000000\n"
2006 "0000000000000000000000000000000000000000000000000000000000000000\n"
2007 "0000000000000000000000000000000000000000000000000000000000000000\n"
2010 if( rEmitter
.mbPfbSubset
)
2011 rEmitter
.emitRawData( aPfxFooter
, sizeof(aPfxFooter
)-1);
2013 rEmitter
.emitRawData( aPfxFooter
+6, sizeof(aPfxFooter
)-9);
2015 // provide details to the subset requesters, TODO: move into own method?
2016 // note: Top and Bottom are flipped between Type1 and VCL
2017 // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
2018 ValType fXFactor
= 1.0;
2019 ValType fYFactor
= 1.0;
2020 if( maFontMatrix
.size() >= 4) {
2021 fXFactor
= 1000.0F
* maFontMatrix
[0];
2022 fYFactor
= 1000.0F
* maFontMatrix
[3];
2024 rFSInfo
.m_aFontBBox
= tools::Rectangle( Point( static_cast<sal_Int32
>(maFontBBox
[0] * fXFactor
),
2025 static_cast<sal_Int32
>(maFontBBox
[1] * fYFactor
) ),
2026 Point( static_cast<sal_Int32
>(maFontBBox
[2] * fXFactor
),
2027 static_cast<sal_Int32
>(maFontBBox
[3] * fYFactor
) ) );
2028 // PDF-Spec says the values below mean the ink bounds!
2029 // TODO: use better approximations for these ink bounds
2030 rFSInfo
.m_nAscent
= +rFSInfo
.m_aFontBBox
.Bottom(); // for capital letters
2031 rFSInfo
.m_nDescent
= -rFSInfo
.m_aFontBBox
.Top(); // for all letters
2032 rFSInfo
.m_nCapHeight
= rFSInfo
.m_nAscent
; // for top-flat capital letters
2034 rFSInfo
.m_nFontType
= rEmitter
.mbPfbSubset
? FontType::TYPE1_PFB
: FontType::TYPE1_PFA
;
2035 rFSInfo
.m_aPSName
= OUString( rEmitter
.maSubsetName
, strlen(rEmitter
.maSubsetName
), RTL_TEXTENCODING_UTF8
);
2038 bool FontSubsetInfo::CreateFontSubsetFromCff( sal_Int32
* pOutGlyphWidths
)
2040 CffSubsetterContext
aCff( mpInFontBytes
, mnInByteLength
);
2041 bool bRC
= aCff
.initialCffRead();
2045 // emit Type1 subset from the CFF input
2046 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2047 const bool bPfbSubset(mnReqFontTypeMask
& FontType::TYPE1_PFB
);
2048 Type1Emitter
aType1Emitter( mpOutFile
, bPfbSubset
);
2049 aType1Emitter
.setSubsetName( mpReqFontName
);
2050 aCff
.emitAsType1( aType1Emitter
,
2051 mpReqGlyphIds
, mpReqEncodedIds
,
2052 pOutGlyphWidths
, mnReqGlyphCount
, *this);
2056 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */