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 .
24 #include "fontsubset.hxx"
26 #include <vcl/strhelper.hxx>
28 //#define IGNORE_HINTS
30 typedef unsigned char U8
;
31 typedef unsigned short U16
;
32 typedef long long S64
;
34 typedef sal_Int32 GlyphWidth
;
36 typedef float RealType
;
37 typedef RealType ValType
;
40 static const char* pStringIds
[] = {
41 /*0*/ ".notdef", "space", "exclam", "quotedbl",
42 "numbersign", "dollar", "percent", "ampersand",
43 "quoteright", "parenleft", "parenright", "asterisk",
44 "plus", "comma", "hyphen", "period",
45 /*16*/ "slash", "zero", "one", "two",
46 "three", "four", "five", "six",
47 "seven", "eight", "nine", "colon",
48 "semicolon", "less", "equal", "greater",
49 /*32*/ "question", "at", "A", "B",
53 /*48*/ "O", "P", "Q", "R",
56 "bracketleft", "backslash", "bracketright", "asciicircum",
57 /*64*/ "underscore", "quoteleft", "a", "b",
61 /*80*/ "o", "p", "q", "r",
64 "braceleft", "bar", "braceright", "asciitilde",
65 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
66 "yen", "florin", "section", "currency",
67 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
68 "guilsinglright", "fi", "fl", "endash",
69 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
70 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
71 "guillemotright", "ellipsis", "perthousand", "questiondown",
72 "grave", "acute", "circumflex", "tilde",
73 /*128*/ "macron", "breve", "dotaccent", "dieresis",
74 "ring", "cedilla", "hungarumlaut", "ogonek",
75 "caron", "emdash", "AE", "ordfeminine",
76 "Lslash", "Oslash", "OE", "ordmasculine",
77 /*144*/ "ae", "dotlessi", "lslash", "oslash",
78 "oe", "germandbls", "onesuperior", "logicalnot",
79 "mu", "trademark", "Eth", "onehalf",
80 "plusminus", "Thorn", "onequarter", "divide",
81 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
82 "twosuperior", "registered", "minus", "eth",
83 "multiply", "threesuperior", "copyright", "Aacute",
84 "Acircumflex", "Adieresis", "Agrave", "Aring",
85 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
86 "Edieresis", "Egrave", "Iacute", "Icircumflex",
87 "Idieresis", "Igrave", "Ntilde", "Oacute",
88 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
89 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
90 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
91 "aacute", "acircumflex", "adieresis", "agrave",
92 "aring", "atilde", "ccedilla", "eacute",
93 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
94 "icircumflex", "idieresis", "igrave", "ntilde",
95 "oacute", "ocircumflex", "odieresis", "ograve",
96 "otilde", "scaron", "uacute", "ucircumflex",
97 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
98 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
99 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
100 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
101 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
102 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
103 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
104 "questionsmall", "asuperior", "bsuperior", "centsuperior",
105 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
106 "msuperior", "nsuperior", "osuperior", "rsuperior",
107 "ssuperior", "tsuperior", "ff", "ffi",
108 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
109 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
110 "Csmall", "Dsmall", "Esmall", "Fsmall",
111 "Gsmall", "Hsmall", "Ismall", "Jsmall",
112 "Ksmall", "Lsmall", "Msmall", "Nsmall",
113 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
114 "Ssmall", "Tsmall", "Usmall", "Vsmall",
115 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
116 "colonmonetary", "onefitted", "rupia", "Tildesmall",
117 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
118 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
119 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
120 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
121 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
122 "onethird", "twothirds", "zerosuperior", "foursuperior",
123 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
124 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
125 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
126 "seveninferior", "eightinferior", "nineinferior", "centinferior",
127 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
128 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
129 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
130 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
131 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
132 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
133 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
134 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
135 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
136 "001.001", "001.002", "001.003", "Black",
137 /*384*/ "Bold", "Book", "Light", "Medium",
138 "Regular", "Roman", "Semibold"
141 // TOP DICT keywords (also covers PRIV DICT keywords)
142 static const char* pDictOps
[] = {
143 "sVersion", "sNotice", "sFullName", "sFamilyName",
144 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
145 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
146 "xESC", "nUniqueID", "aXUID", "nCharset",
147 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
148 "nDefaultWidthX", "nNominalWidthX", nullptr, nullptr,
149 nullptr, nullptr, nullptr, nullptr,
150 "shortint", "longint", "BCD", nullptr
153 // TOP DICT escapes (also covers PRIV DICT escapes)
154 static const char* pDictEscs
[] = {
155 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
156 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
157 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
158 "dStemSnapH", "dStemSnapV", "bForceBold", nullptr,
159 nullptr, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
160 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
161 nullptr, nullptr, nullptr, nullptr,
162 nullptr, nullptr, "rROS", "nCIDFontVersion",
163 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
164 "nFDArray", "nFDSelect", "sFontName"
167 static const char* pType1Ops
[] = {
168 nullptr, "2hstem", nullptr, "2vstem",
169 "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
170 "Crrcurveto", "0closepath", "Lcallsubr", "0return",
171 "xT1ESC", "2hsbw", "0endchar", nullptr,
172 nullptr, nullptr, nullptr, nullptr,
173 nullptr, "2rmoveto", "1hmoveto", nullptr,
174 nullptr, nullptr, nullptr, nullptr,
175 nullptr, nullptr, "4vhcurveto", "4hvcurveto"
178 static const char* pT1EscOps
[] = {
179 "0dotsection", "6vstem3", "6hstem3", nullptr,
180 nullptr, nullptr, "5seac", "4sbw",
181 nullptr, "1abs", "2add", "2sub",
182 "2div", nullptr, nullptr, nullptr,
183 "Gcallothersubr", "1pop", nullptr, nullptr,
184 nullptr, nullptr, nullptr, nullptr,
185 nullptr, nullptr, nullptr, nullptr,
186 nullptr, nullptr, nullptr, nullptr,
187 nullptr, "2setcurrentpoint"
194 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
195 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CLOSEPATH
=9,
196 CALLSUBR
=10, RETURN
=11, T1ESC
=12, HSBW
=13,
197 ENDCHAR
=14, RMOVETO
=21, HMOVETO
=22, VHCURVETO
=30,
203 DOTSECTION
=0, VSTEM3
=1, HSTEM3
=2, SEAC
=6,
204 SBW
=7, ABS
=9, ADD
=10, SUB
=11,
205 DIV
=12, CALLOTHERSUBR
=16, POP
=17, SETCURRENTPOINT
=33
209 static const char* pType2Ops
[] = {
210 nullptr, "hhstem", nullptr, "vvstem",
211 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
212 "Crrcurveto", nullptr, "Lcallsubr", "Xreturn",
213 "xT2ESC", nullptr, "eendchar", nullptr,
214 nullptr, nullptr, "Hhstemhm", "Khintmask",
215 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
216 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
217 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
220 static const char* pT2EscOps
[] = {
221 nullptr, nullptr, nullptr, "2and",
222 "2or", "1not", nullptr, nullptr,
223 nullptr, "1abs", "2add", "2sub",
224 "2div", nullptr, "1neg", "2eq",
225 nullptr, nullptr, "1drop", nullptr,
226 "1put", "1get", "4ifelse", "0random",
227 "2mul", nullptr, "1sqrt", "1dup",
228 "2exch", "Iindex", "Rroll", nullptr,
229 nullptr, nullptr, "7hflex", "Fflex",
237 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
238 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CALLSUBR
=10,
239 RETURN
=11, T2ESC
=12, ENDCHAR
=14, HSTEMHM
=18,
240 HINTMASK
=19, CNTRMASK
=20, RMOVETO
=21, HMOVETO
=22,
241 VSTEMHM
=23, RCURVELINE
=24, RLINECURVE
=25, VVCURVETO
=26,
242 HHCURVETO
=27, SHORTINT
=28, CALLGSUBR
=29, VHCURVETO
=30,
248 AND
=3, OR
=4, NOT
=5, ABS
=9,
249 ADD
=10, SUB
=11, DIV
=12, NEG
=14,
250 EQ
=15, DROP
=18, PUT
=20, GET
=21,
251 IFELSE
=22, RANDOM
=23, MUL
=24, SQRT
=26,
252 DUP
=27, EXCH
=28, INDEX
=29, ROLL
=30,
253 HFLEX
=34, FLEX
=35, HFLEX1
=36, FLEX1
=37
259 explicit CffGlobal();
264 int mnStringIdxCount
;
270 int mnGlobalSubrBase
;
271 int mnGlobalSubrCount
;
272 int mnGlobalSubrBias
;
277 std::vector
<ValType
> maFontBBox
;
278 std::vector
<ValType
> maFontMatrix
;
293 int mnLocalSubrCount
;
296 ValType maNominalWidth
;
297 ValType maDefaultWidth
;
299 // ATM hinting related values
302 std::vector
<ValType
> maStemSnapH
;
303 std::vector
<ValType
> maStemSnapV
;
304 std::vector
<ValType
> maBlueValues
;
305 std::vector
<ValType
> maOtherBlues
;
306 std::vector
<ValType
> maFamilyBlues
;
307 std::vector
<ValType
> maFamilyOtherBlues
;
308 RealType mfBlueScale
;
309 RealType mfBlueShift
;
311 RealType mfExpFactor
;
316 class CffSubsetterContext
320 static const int NMAXSTACK
= 48; // see CFF.appendixB
321 static const int NMAXHINTS
= 2*96; // see CFF.appendixB
322 static const int NMAXTRANS
= 32; // see CFF.appendixB
324 explicit CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
);
326 bool initialCffRead();
327 bool emitAsType1( class Type1Emitter
&,
328 const sal_GlyphId
* pGlyphIds
, const U8
* pEncoding
,
329 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& );
331 // used by charstring converter
332 void setCharStringType( int);
334 int convert2Type1Ops( CffLocal
*, const U8
* pType2Ops
, int nType2Len
, U8
* pType1Ops
);
336 void convertOneTypeOp();
337 void convertOneTypeEsc();
338 void callType2Subr( bool bGlobal
, int nSubrNumber
);
339 sal_Int32
getReadOfs() const { return (sal_Int32
)(mpReadPtr
- mpBasePtr
);}
350 sal_Int32 mnCntrMask
;
353 int seekIndexData( int nIndexBase
, int nDataIndex
);
354 void seekIndexEnd( int nIndexBase
);
357 const char** mpCharStringOps
;
358 const char** mpCharStringEscs
;
360 CffLocal maCffLocal
[256];
361 CffLocal
* mpCffLocal
;
364 RealType
readRealVal();
365 const char* getString( int nStringID
);
366 int getFDSelect( int nGlyphIndex
) const;
367 int getGlyphSID( int nGlyphIndex
) const;
368 const char* getGlyphName( int nGlyphIndex
);
371 void writeType1Val( ValType
);
372 void writeTypeOp( int nTypeOp
);
373 void writeTypeEsc( int nTypeOp
);
374 void writeCurveTo( int nStackPos
, int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
);
375 void pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
=0);
376 void popAll2Write( int nTypeOp
);
378 public: // TODO: is public really needed?
379 // accessing the value stack
380 // TODO: add more checks
381 void push( ValType nVal
) { mnValStack
[ mnStackIdx
++] = nVal
;}
382 ValType
popVal() { return ((mnStackIdx
>0) ? mnValStack
[ --mnStackIdx
] : 0);}
383 ValType
getVal( int nIndex
) const { return mnValStack
[ nIndex
];}
385 int size() const { return mnStackIdx
;}
386 void clear() { mnStackIdx
= 0;}
388 // accessing the charstring hints
389 void addHints( bool bVerticalHints
);
391 // accessing other charstring specifics
392 bool hasCharWidth() const { return (maCharWidth
> 0);}
393 ValType
getCharWidth() const { return maCharWidth
;}
394 void setNominalWidth( ValType aWidth
) { mpCffLocal
->maNominalWidth
= aWidth
;}
395 void setDefaultWidth( ValType aWidth
) { mpCffLocal
->maDefaultWidth
= aWidth
;}
396 void updateWidth( bool bUseFirstVal
);
399 // typeop execution context
401 ValType mnValStack
[ NMAXSTACK
+4];
402 ValType mnTransVals
[ NMAXTRANS
];
406 ValType mnHintStack
[ NMAXHINTS
];
411 CffSubsetterContext::CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
)
412 : mpBasePtr( pBasePtr
)
413 , mpBaseEnd( pBasePtr
+nBaseLen
)
416 , mpWritePtr(nullptr)
418 , mbIgnoreHints(false)
420 , mpCharStringOps(nullptr)
421 , mpCharStringEscs(nullptr)
430 // setCharStringType( 1);
431 // TODO: new CffLocal[ mnFDAryCount];
432 mpCffLocal
= &maCffLocal
[0];
435 inline int CffSubsetterContext::popInt()
437 const ValType aVal
= popVal();
438 const int nInt
= static_cast<int>(aVal
);
439 assert( nInt
== aVal
);
443 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal
)
445 #if 1 // TODO: is this still needed?
446 // the first value is not a hint but the charwidth
451 maCharWidth
= mpCffLocal
->maNominalWidth
+ mnValStack
[0];
452 // remove bottom stack entry
454 for( int i
= 0; i
< mnStackIdx
; ++i
)
455 mnValStack
[ i
] = mnValStack
[ i
+1];
457 maCharWidth
= mpCffLocal
->maDefaultWidth
;
461 void CffSubsetterContext::addHints( bool bVerticalHints
)
463 // the first charstring value may a charwidth instead of a charwidth
464 updateWidth( (mnStackIdx
& 1) != 0);
465 // return early (e.g. no implicit hints for hintmask)
469 // copy the remaining values to the hint arrays
470 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
471 if( mnStackIdx
& 1) --mnStackIdx
;//#######
472 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
474 assert( (mnHintSize
+ mnStackIdx
) <= 2*NMAXHINTS
);
477 mnHintSize
+= mnStackIdx
;
479 ValType nHintOfs
= 0;
480 for( int i
= 0; i
< mnStackIdx
; ++i
) {
481 nHintOfs
+= mnValStack
[ i
];
482 mnHintStack
[ mnHintSize
++] = nHintOfs
;
484 #endif // IGNORE_HINTS
486 mnHorzHintSize
= mnHintSize
;
488 // clear all values from the stack
492 void CffSubsetterContext::setCharStringType( int nVal
)
495 case 1: mpCharStringOps
=pType1Ops
; mpCharStringEscs
=pT1EscOps
; break;
496 case 2: mpCharStringOps
=pType2Ops
; mpCharStringEscs
=pT2EscOps
; break;
497 default: fprintf( stderr
, "Unknown CharstringType=%d\n",nVal
); break;
501 void CffSubsetterContext::readDictOp()
503 const U8 c
= *mpReadPtr
;
505 int nOpId
= *(mpReadPtr
++);
506 const char* pCmdName
= nullptr;
508 pCmdName
= pDictOps
[nOpId
];
510 const U8 nExtId
= *(mpReadPtr
++);
512 pCmdName
= pDictEscs
[nExtId
];
513 nOpId
= 900 + nExtId
;
516 if (!pCmdName
) // skip reserved operators
519 //TODO: if( nStackIdx > 0)
522 default: fprintf( stderr
, "unsupported DictOp.type=\'%c\'\n", *pCmdName
); break;
526 case 915: mpCffLocal
->mbForceBold
= nInt
; break; // "ForceBold"
527 default: break; // TODO: handle more boolean dictops?
530 case 'n': { // dict-op number
531 ValType nVal
= popVal();
532 nInt
= static_cast<int>(nVal
);
534 case 10: mpCffLocal
->maStemStdHW
= nVal
; break; // "StdHW"
535 case 11: mpCffLocal
->maStemStdVW
= nVal
; break; // "StdVW"
536 case 15: mnCharsetBase
= nInt
; break; // "charset"
537 case 16: mnEncodingBase
= nInt
; break; // "nEncoding"
538 case 17: mnCharStrBase
= nInt
; break; // "nCharStrings"
539 case 19: mpCffLocal
->mnLocalSubrOffs
= nInt
; break;// "nSubrs"
540 case 20: setDefaultWidth( nVal
); break; // "defaultWidthX"
541 case 21: setNominalWidth( nVal
); break; // "nominalWidthX"
542 case 909: mpCffLocal
->mfBlueScale
= nVal
; break; // "BlueScale"
543 case 910: mpCffLocal
->mfBlueShift
= nVal
; break; // "BlueShift"
544 case 911: mpCffLocal
->mfBlueFuzz
= nVal
; break; // "BlueFuzz"
545 case 912: mpCffLocal
->mfExpFactor
= nVal
; break; // "ExpansionFactor"
546 case 917: mpCffLocal
->mnLangGroup
= nInt
; break; // "LanguageGroup"
547 case 936: mnFontDictBase
= nInt
; break; // "nFDArray"
548 case 937: mnFDSelectBase
= nInt
; break; // "nFDSelect"
549 default: break; // TODO: handle more numeric dictops?
554 case 5: maFontBBox
.clear(); break; // "FontBBox"
555 case 907: maFontMatrix
.clear(); break; // "FontMatrix"
556 default: break; // TODO: reset other arrays?
558 for( int i
= 0; i
< size(); ++i
) {
559 ValType nVal
= getVal(i
);
561 case 5: maFontBBox
.push_back( nVal
); break; // "FontBBox"
562 case 907: maFontMatrix
.push_back( nVal
); break; // "FontMatrix"
563 default: break; // TODO: handle more array dictops?
568 case 'd': { // delta array
570 for( int i
= 0; i
< size(); ++i
) {
573 case 6: mpCffLocal
->maBlueValues
.push_back( nVal
); break; // "BlueValues"
574 case 7: mpCffLocal
->maOtherBlues
.push_back( nVal
); break; // "OtherBlues"
575 case 8: mpCffLocal
->maFamilyBlues
.push_back( nVal
); break; // "FamilyBlues"
576 case 9: mpCffLocal
->maFamilyOtherBlues
.push_back( nVal
); break;// "FamilyOtherBlues"
577 case 912: mpCffLocal
->maStemSnapH
.push_back( nVal
); break; // "StemSnapH"
578 case 913: mpCffLocal
->maStemSnapV
.push_back( nVal
); break; // "StemSnapV"
579 default: break; // TODO: handle more delta-array dictops?
584 case 's': // stringid (SID)
587 case 2: mnFullNameSID
= nInt
; break; // "FullName"
588 case 3: mnFamilyNameSID
= nInt
; break; // "FamilyName"
589 case 938: mnFontNameSID
= nInt
; break; // "FontName"
590 default: break; // TODO: handle more string dictops?
593 case 'P': // private dict
594 mpCffLocal
->mnPrivDictBase
= popInt();
595 mpCffLocal
->mnPrivDictSize
= popInt();
597 case 'r': { // ROS operands
598 int nSid1
= popInt();
599 int nSid2
= popInt();
600 (void)nSid1
; // TODO: use
601 (void)nSid2
; // TODO: use
605 case 't': // CharstringType
607 setCharStringType( nInt
);
610 } else if( (c
>= 32) || (c
== 28) ) {
613 } else if( c
== 29 ) { // longint
614 ++mpReadPtr
; // skip 29
615 int nS32
= mpReadPtr
[0] << 24;
616 nS32
+= mpReadPtr
[1] << 16;
617 nS32
+= mpReadPtr
[2] << 8;
618 nS32
+= mpReadPtr
[3] << 0;
619 if( (sizeof(nS32
) != 4) && (nS32
& (1U<<31)))
620 nS32
|= (~0U) << 31; // assuming 2s complement
622 ValType nVal
= static_cast<ValType
>(nS32
);
624 } else if( c
== 30) { // real number
625 ++mpReadPtr
; // skip 30
626 const RealType fReal
= readRealVal();
627 // push value onto stack
628 ValType nVal
= fReal
;
633 void CffSubsetterContext::read2push()
637 const U8
*& p
= mpReadPtr
;
640 short nS16
= (p
[1] << 8) + p
[2];
641 if( (sizeof(nS16
) != 2) && (nS16
& (1<<15)))
642 nS16
|= (~0U) << 15; // assuming 2s complement
645 } else if( c
<= 246 ) { // -107..+107
646 aVal
= static_cast<ValType
>(p
[0] - 139);
648 } else if( c
<= 250 ) { // +108..+1131
649 aVal
= static_cast<ValType
>(((p
[0] << 8) + p
[1]) - 63124);
651 } else if( c
<= 254 ) { // -108..-1131
652 aVal
= static_cast<ValType
>(64148 - ((p
[0] << 8) + p
[1]));
654 } else /*if( c == 255)*/ { // Fixed16.16
655 int nS32
= (p
[1] << 24) + (p
[2] << 16) + (p
[3] << 8) + p
[4];
656 if( (sizeof(nS32
) != 2) && (nS32
& (1U<<31)))
657 nS32
|= (~0U) << 31; // assuming 2s complement
658 aVal
= static_cast<ValType
>(nS32
* (1.0 / 0x10000));
665 void CffSubsetterContext::writeType1Val( ValType aVal
)
667 U8
* pOut
= mpWritePtr
;
669 int nInt
= static_cast<int>(aVal
);
670 if( (nInt
>= -107) && (nInt
<= +107)) {
671 *(pOut
++) = static_cast<U8
>(nInt
+ 139); // -107..+107
672 } else if( (nInt
>= -1131) && (nInt
<= +1131)) {
674 nInt
+= 63124; // +108..+1131
676 nInt
= 64148 - nInt
; // -108..-1131
677 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
678 *(pOut
++) = static_cast<U8
>(nInt
);
680 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
682 *(pOut
++) = static_cast<U8
>(nInt
>> 24);
683 *(pOut
++) = static_cast<U8
>(nInt
>> 16);
684 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
685 *(pOut
++) = static_cast<U8
>(nInt
);
691 inline void CffSubsetterContext::writeTypeOp( int nTypeOp
)
693 *(mpWritePtr
++) = static_cast<U8
>(nTypeOp
);
696 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc
)
698 *(mpWritePtr
++) = TYPE1OP::T1ESC
;
699 *(mpWritePtr
++) = static_cast<U8
>(nTypeEsc
);
702 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
)
704 for( int i
= 0; i
< mnStackIdx
;) {
705 for( int j
= 0; j
< nArgsPerTypo
; ++j
) {
706 const ValType aVal
= mnValStack
[i
+j
];
707 writeType1Val( aVal
);
710 writeTypeOp( nTypeOp
);
711 nTypeOp
^= nTypeXor
; // for toggling vlineto/hlineto
716 void CffSubsetterContext::popAll2Write( int nTypeOp
)
718 // pop in reverse order, then write
719 for( int i
= 0; i
< mnStackIdx
; ++i
) {
720 const ValType aVal
= mnValStack
[i
];
721 writeType1Val( aVal
);
724 writeTypeOp( nTypeOp
);
727 void CffSubsetterContext::writeCurveTo( int nStackPos
,
728 int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
)
730 // get the values from the stack
731 const ValType nDX1
= nIX1
? mnValStack
[ nStackPos
+nIX1
] : 0;
732 const ValType nDY1
= nIY1
? mnValStack
[ nStackPos
+nIY1
] : 0;
733 const ValType nDX2
= nIX2
? mnValStack
[ nStackPos
+nIX2
] : 0;
734 const ValType nDY2
= nIY2
? mnValStack
[ nStackPos
+nIY2
] : 0;
735 const ValType nDX3
= nIX3
? mnValStack
[ nStackPos
+nIX3
] : 0;
736 const ValType nDY3
= nIY3
? mnValStack
[ nStackPos
+nIY3
] : 0;
738 // emit the curveto operator and operands
739 // TODO: determine the most efficient curveto operator
740 // TODO: depending on type1op or type2op target
741 writeType1Val( nDX1
);
742 writeType1Val( nDY1
);
743 writeType1Val( nDX2
);
744 writeType1Val( nDY2
);
745 writeType1Val( nDX3
);
746 writeType1Val( nDY3
);
747 writeTypeOp( TYPE1OP::RCURVETO
);
750 void CffSubsetterContext::convertOneTypeOp()
752 const int nType2Op
= *(mpReadPtr
++);
754 int i
, nInt
; // prevent WAE for declarations inside switch cases
762 addHints( nType2Op
== TYPE2OP::VSTEM
);
764 for( i
= 0; i
< mnHintSize
; i
+=2 ) {
765 writeType1Val( mnHintStack
[i
]);
766 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
767 writeTypeOp( nType2Op
);
769 #endif // IGNORE_HINTS
771 case TYPE2OP::HSTEMHM
:
772 case TYPE2OP::VSTEMHM
:
773 addHints( nType2Op
== TYPE2OP::VSTEMHM
);
775 case TYPE2OP::CNTRMASK
:
776 // TODO: replace cntrmask with vstem3/hstem3
779 mpReadPtr
+= (mnHintSize
+ 15) / 16;
780 mbIgnoreHints
= true;
785 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
787 nMaskByte
= *(mpReadPtr
++);
790 if( !(nMaskByte
& nMaskBit
))
792 if( i
>= 8*(int)sizeof(mnCntrMask
))
793 mbIgnoreHints
= true;
796 mnCntrMask
|= (1U << i
);
801 case TYPE2OP::HINTMASK
:
804 mpReadPtr
+= (mnHintSize
+ 15) / 16;
807 sal_Int32 nHintMask
= 0;
808 int nCntrBits
[2] = {0,0};
811 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
813 nMaskByte
= *(mpReadPtr
++);
816 if( !(nMaskByte
& nMaskBit
))
818 if( i
>= 8*(int)sizeof(nHintMask
))
819 mbIgnoreHints
= true;
822 nHintMask
|= (1U << i
);
823 nCntrBits
[ i
< mnHorzHintSize
] += (mnCntrMask
>> i
) & 1;
826 mbIgnoreHints
|= (nCntrBits
[0] && (nCntrBits
[0] != 3));
827 mbIgnoreHints
|= (nCntrBits
[1] && (nCntrBits
[1] != 3));
831 for( i
= 0; i
< mnHintSize
; i
+=2) {
832 if( !(nHintMask
& (1U << i
)))
834 writeType1Val( mnHintStack
[i
]);
835 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
836 const bool bHorz
= (i
< mnHorzHintSize
);
837 if( !nCntrBits
[ bHorz
])
838 writeTypeOp( bHorz
? TYPE1OP::HSTEM
: TYPE1OP::VSTEM
);
839 else if( !--nCntrBits
[ bHorz
])
840 writeTypeEsc( bHorz
? TYPE1OP::HSTEM3
: TYPE1OP::VSTEM3
);
845 case TYPE2OP::CALLSUBR
:
846 case TYPE2OP::CALLGSUBR
:
849 const bool bGlobal
= (nType2Op
== TYPE2OP::CALLGSUBR
);
850 callType2Subr( bGlobal
, nInt
);
853 case TYPE2OP::RETURN
:
854 // TODO: check that we are in a subroutine
856 case TYPE2OP::VMOVETO
:
857 case TYPE2OP::HMOVETO
:
859 writeTypeOp( TYPE1OP::CLOSEPATH
);
861 updateWidth( size() > 1);
863 pop2MultiWrite( 1, nType2Op
);
865 case TYPE2OP::VLINETO
:
866 case TYPE2OP::HLINETO
:
867 pop2MultiWrite( 1, nType2Op
,
868 TYPE1OP::VLINETO
^ TYPE1OP::HLINETO
);
870 case TYPE2OP::RMOVETO
:
871 // TODO: convert rmoveto to vlineto/hlineto if possible
873 writeTypeOp( TYPE1OP::CLOSEPATH
);
875 updateWidth( size() > 2);
877 pop2MultiWrite( 2, nType2Op
);
879 case TYPE2OP::RLINETO
:
880 // TODO: convert rlineto to vlineto/hlineto if possible
881 pop2MultiWrite( 2, nType2Op
);
883 case TYPE2OP::RCURVETO
:
884 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
885 pop2MultiWrite( 6, nType2Op
);
887 case TYPE2OP::RCURVELINE
:
889 while( (i
+= 6) <= mnStackIdx
)
890 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
892 while( (i
+= 2) <= mnStackIdx
) {
893 writeType1Val( mnValStack
[i
-2]);
894 writeType1Val( mnValStack
[i
-1]);
895 writeTypeOp( TYPE2OP::RLINETO
);
899 case TYPE2OP::RLINECURVE
:
901 while( (i
+= 2) <= mnStackIdx
-6) {
902 writeType1Val( mnValStack
[i
-2]);
903 writeType1Val( mnValStack
[i
-1]);
904 writeTypeOp( TYPE2OP::RLINETO
);
907 while( (i
+= 6) <= mnStackIdx
)
908 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
911 case TYPE2OP::VHCURVETO
:
912 case TYPE2OP::HVCURVETO
:
914 bool bVert
= (nType2Op
== TYPE2OP::VHCURVETO
);
918 nInt
= static_cast<int>(mnValStack
[ --mnStackIdx
]);
919 while( (i
+= 4) <= mnStackIdx
) {
920 // TODO: use writeCurveTo()
921 if( bVert
) writeType1Val( 0 );
922 writeType1Val( mnValStack
[i
-4] );
923 if( !bVert
) writeType1Val( 0);
924 writeType1Val( mnValStack
[i
-3] );
925 writeType1Val( mnValStack
[i
-2] );
926 if( !bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
927 writeType1Val( mnValStack
[i
-1] );
928 if( bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
930 writeTypeOp( TYPE2OP::RCURVETO
);
935 case TYPE2OP::HHCURVETO
:
936 i
= (mnStackIdx
& 1);
937 while( (i
+= 4) <= mnStackIdx
) {
939 writeCurveTo( i
, -4, 0, -3, -2, -1, 0);
941 writeCurveTo( i
, -4, -5, -3, -2, -1, 0);
945 case TYPE2OP::VVCURVETO
:
946 i
= (mnStackIdx
& 1);
947 while( (i
+= 4) <= mnStackIdx
) {
949 writeCurveTo( i
, 0, -4, -3, -2, 0, -1);
951 writeCurveTo( i
, -5, -4, -3, -2, 0, -1);
955 case TYPE2OP::ENDCHAR
:
957 writeTypeOp( TYPE1OP::CLOSEPATH
);
959 updateWidth( size() >= 1);
960 // mbNeedClose = true;
961 writeTypeOp( TYPE1OP::ENDCHAR
);
964 if( ((nType2Op
>= 32) && (nType2Op
<= 255)) || (nType2Op
== 28)) {
968 popAll2Write( nType2Op
);
969 assert(false && "TODO?");
975 void CffSubsetterContext::convertOneTypeEsc()
977 const int nType2Esc
= *(mpReadPtr
++);
978 ValType
* pTop
= &mnValStack
[ mnStackIdx
-1];
982 assert( mnStackIdx
>= 2 );
983 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) & static_cast<int>(pTop
[-1]));
987 assert( mnStackIdx
>= 2 );
988 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) | static_cast<int>(pTop
[-1]));
992 assert( mnStackIdx
>= 1 );
993 pTop
[0] = ValType(pTop
[0] == 0);
996 assert( mnStackIdx
>= 1 );
1001 assert( mnStackIdx
>= 1 );
1005 assert( mnStackIdx
>= 2 );
1006 pTop
[0] += pTop
[-1];
1010 assert( mnStackIdx
>= 2 );
1011 pTop
[0] -= pTop
[-1];
1015 assert( mnStackIdx
>= 2 );
1017 pTop
[0] *= pTop
[-1];
1021 assert( mnStackIdx
>= 2 );
1023 pTop
[0] /= pTop
[-1];
1027 assert( mnStackIdx
>= 2 );
1028 pTop
[0] = ValType(pTop
[0] == pTop
[-1]);
1032 assert( mnStackIdx
>= 1 );
1035 case TYPE2OP::PUT
: {
1036 assert( mnStackIdx
>= 2 );
1037 const int nIdx
= static_cast<int>(pTop
[0]);
1038 assert( nIdx
>= 0 );
1039 assert( nIdx
< NMAXTRANS
);
1040 mnTransVals
[ nIdx
] = pTop
[-1];
1044 case TYPE2OP::GET
: {
1045 assert( mnStackIdx
>= 1 );
1046 const int nIdx
= static_cast<int>(pTop
[0]);
1047 assert( nIdx
>= 0 );
1048 assert( nIdx
< NMAXTRANS
);
1049 pTop
[0] = mnTransVals
[ nIdx
];
1052 case TYPE2OP::IFELSE
: {
1053 assert( mnStackIdx
>= 4 );
1054 if( pTop
[-1] > pTop
[0] )
1055 pTop
[-3] = pTop
[-2];
1059 case TYPE2OP::RANDOM
:
1060 pTop
[+1] = 1234; // TODO
1067 assert( mnStackIdx
>= 1 );
1071 case TYPE2OP::EXCH
: {
1072 assert( mnStackIdx
>= 2 );
1073 const ValType nVal
= pTop
[0];
1078 case TYPE2OP::INDEX
: {
1079 assert( mnStackIdx
>= 1 );
1080 const int nVal
= static_cast<int>(pTop
[0]);
1081 assert( nVal
>= 0 );
1082 assert( nVal
< mnStackIdx
-1 );
1083 pTop
[0] = pTop
[-1-nVal
];
1086 case TYPE2OP::ROLL
: {
1087 assert( mnStackIdx
>= 1 );
1088 const int nNum
= static_cast<int>(pTop
[0]);
1090 assert( nNum
< mnStackIdx
-2 );
1091 (void)nNum
; // TODO: implement
1092 const int nOfs
= static_cast<int>(pTop
[-1]);
1094 (void)nOfs
;// TODO: implement
1097 case TYPE2OP::HFLEX1
: {
1098 assert( mnStackIdx
== 9);
1100 writeCurveTo( mnStackIdx
, -9, -8, -7, -6, -5, 0);
1101 writeCurveTo( mnStackIdx
, -4, 0, -3, -2, -1, 0);
1102 // TODO: emulate hflex1 using othersubr call
1107 case TYPE2OP::HFLEX
: {
1108 assert( mnStackIdx
== 7);
1109 ValType
* pX
= &mnValStack
[ mnStackIdx
];
1111 pX
[+1] = -pX
[-5]; // temp: +dy5==-dy2
1112 writeCurveTo( mnStackIdx
, -7, 0, -6, -5, -4, 0);
1113 writeCurveTo( mnStackIdx
, -3, 0, -2, +1, -1, 0);
1114 // TODO: emulate hflex using othersubr call
1119 case TYPE2OP::FLEX
: {
1120 assert( mnStackIdx
== 13 );
1121 writeCurveTo( mnStackIdx
, -13, -12, -11, -10, -9, -8 );
1122 writeCurveTo( mnStackIdx
, -7, -6, -5, -4, -3, -2 );
1123 const ValType nFlexDepth
= mnValStack
[ mnStackIdx
-1 ];
1124 (void)nFlexDepth
; // ignoring nFlexDepth
1128 case TYPE2OP::FLEX1
: {
1129 assert( mnStackIdx
== 11 );
1130 // write the first part of the flex1-hinted curve
1131 writeCurveTo( mnStackIdx
, -11, -10, -9, -8, -7, -6 );
1133 // determine if nD6 is horizontal or vertical
1134 const int i
= mnStackIdx
;
1135 ValType nDeltaX
= mnValStack
[i
-11] + mnValStack
[i
-9] + mnValStack
[i
-7] + mnValStack
[i
-5] + mnValStack
[i
-3];
1136 if( nDeltaX
< 0 ) nDeltaX
= -nDeltaX
;
1137 ValType nDeltaY
= mnValStack
[i
-10] + mnValStack
[i
-8] + mnValStack
[i
-6] + mnValStack
[i
-4] + mnValStack
[i
-2];
1138 if( nDeltaY
< 0 ) nDeltaY
= -nDeltaY
;
1139 const bool bVertD6
= (nDeltaY
> nDeltaX
);
1141 // write the second part of the flex1-hinted curve
1143 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, -1, 0);
1145 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, 0, -1);
1150 fprintf( stderr
,"unhandled type2esc %d\n", nType2Esc
);
1156 void CffSubsetterContext::callType2Subr( bool bGlobal
, int nSubrNumber
)
1158 const U8
* const pOldReadPtr
= mpReadPtr
;
1159 const U8
* const pOldReadEnd
= mpReadEnd
;
1162 nSubrNumber
+= mnGlobalSubrBias
;
1163 seekIndexData( mnGlobalSubrBase
, nSubrNumber
);
1165 nSubrNumber
+= mpCffLocal
->mnLocalSubrBias
;
1166 seekIndexData( mpCffLocal
->mnLocalSubrBase
, nSubrNumber
);
1169 while( mpReadPtr
< mpReadEnd
)
1172 mpReadPtr
= pOldReadPtr
;
1173 mpReadEnd
= pOldReadEnd
;
1176 static const int MAX_T1OPS_SIZE
= 81920; // TODO: use dynamic value
1178 int CffSubsetterContext::convert2Type1Ops( CffLocal
* pCffLocal
, const U8
* const pT2Ops
, int nT2Len
, U8
* const pT1Ops
)
1180 mpCffLocal
= pCffLocal
;
1182 // prepare the charstring conversion
1183 mpWritePtr
= pT1Ops
;
1184 #if 1 // TODO: update caller
1185 U8 aType1Ops
[ MAX_T1OPS_SIZE
];
1187 mpWritePtr
= aType1Ops
;
1188 *const_cast<U8
**>(&pT1Ops
) = mpWritePtr
;
1193 // prepend random seed for T1crypt
1194 *(mpWritePtr
++) = 0x48;
1195 *(mpWritePtr
++) = 0x44;
1196 *(mpWritePtr
++) = 0x55;
1197 *(mpWritePtr
++) = ' ';
1198 #if 1 // convert the Type2 charstring to Type1
1200 mpReadEnd
= pT2Ops
+ nT2Len
;
1201 // prepend "hsbw" or "sbw"
1202 // TODO: only emit hsbw when charwidth is known
1203 // TODO: remove charwidth from T2 stack
1204 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
1205 writeType1Val( 1000/*###getCharWidth()###*/);
1206 writeTypeOp( TYPE1OP::HSBW
);
1207 mbNeedClose
= false;
1208 mbIgnoreHints
= false;
1209 mnHintSize
=mnHorzHintSize
=mnStackIdx
=0; maCharWidth
=-1;//#######
1211 while( mpReadPtr
< mpReadEnd
)
1214 // writeTypeOp( TYPE1OP::CLOSEPATH);
1216 // writeTypeOp( TYPE1OP::RETURN);
1217 #else // useful for manually encoding charstrings
1218 mpWritePtr
= pT1Ops
;
1219 mpWritePtr
+= sprintf( (char*)mpWritePtr
, "OOo_\x8b\x8c\x0c\x10\x0b");
1221 const int nType1Len
= mpWritePtr
- pT1Ops
;
1223 // encrypt the Type1 charstring
1224 int nRDCryptR
= 4330; // TODO: mnRDCryptSeed;
1225 for( U8
* p
= pT1Ops
; p
< mpWritePtr
; ++p
) {
1226 *p
^= (nRDCryptR
>> 8);
1227 nRDCryptR
= (*p
+ nRDCryptR
) * 52845 + 22719;
1233 RealType
CffSubsetterContext::readRealVal()
1235 // TODO: more thorough number validity test
1236 bool bComma
= false;
1240 RealType fReal
= +1.0;
1242 const U8 c
= *(mpReadPtr
++); // read nibbles
1243 // parse high nibble
1244 const U8 nH
= c
>> 4U;
1246 nNumber
= nNumber
* 10 + nH
;
1248 } else if( nH
== 10) { // comma
1251 } else if( nH
== 11) { // +exp
1255 } else if( nH
== 12) { // -exp
1259 } else if( nH
== 13) { // reserved
1260 // TODO: ignore or error?
1261 } else if( nH
== 14) // minus
1263 else if( nH
== 15) // end
1266 const U8 nL
= c
& 0x0F;
1268 nNumber
= nNumber
* 10 + nL
;
1270 } else if( nL
== 10) { // comma
1273 } else if( nL
== 11) { // +exp
1277 } else if( nL
== 12) { // -exp
1281 } else if( nL
== 13) { // reserved
1282 // TODO: ignore or error?
1283 } else if( nL
== 14) // minus
1285 else if( nL
== 15) // end
1292 if( !nExpSign
) { fReal
*= nNumber
;}
1293 else if( nExpSign
> 0) { nExpVal
+= static_cast<int>(nNumber
);}
1294 else if( nExpSign
< 0) { nExpVal
-= static_cast<int>(nNumber
);}
1297 if( !nExpVal
) { /*nothing to apply*/}
1298 else if( nExpVal
> 0) { while( --nExpVal
>= 0) fReal
*= 10.0;}
1299 else if( nExpVal
< 0) { while( ++nExpVal
<= 0) fReal
/= 10.0;}
1303 // prepare to access an element inside a CFF/CID index table
1304 int CffSubsetterContext::seekIndexData( int nIndexBase
, int nDataIndex
)
1306 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1309 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1310 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1311 if( nDataIndex
>= nDataCount
)
1313 const int nDataOfsSz
= mpReadPtr
[2];
1314 mpReadPtr
+= 3 + (nDataOfsSz
* nDataIndex
);
1316 switch( nDataOfsSz
) {
1317 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return -1;
1318 case 1: nOfs1
= mpReadPtr
[0]; break;
1319 case 2: nOfs1
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1320 case 3: nOfs1
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1321 case 4: nOfs1
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1323 mpReadPtr
+= nDataOfsSz
;
1326 switch( nDataOfsSz
) {
1327 case 1: nOfs2
= mpReadPtr
[0]; break;
1328 case 2: nOfs2
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1329 case 3: nOfs2
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1330 case 4: nOfs2
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1333 mpReadPtr
= mpBasePtr
+ (nIndexBase
+ 2) + nDataOfsSz
* (nDataCount
+ 1) + nOfs1
;
1334 mpReadEnd
= mpReadPtr
+ (nOfs2
- nOfs1
);
1335 assert( nOfs1
>= 0);
1336 assert( nOfs2
>= nOfs1
);
1337 assert( mpReadPtr
<= mpBaseEnd
);
1338 assert( mpReadEnd
<= mpBaseEnd
);
1339 return (nOfs2
- nOfs1
);
1342 // skip over a CFF/CID index table
1343 void CffSubsetterContext::seekIndexEnd( int nIndexBase
)
1345 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1346 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1347 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1348 const int nDataOfsSz
= mpReadPtr
[2];
1349 mpReadPtr
+= 3 + nDataOfsSz
* nDataCount
;
1350 assert( mpReadPtr
<= mpBaseEnd
);
1352 switch( nDataOfsSz
) {
1353 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return;
1354 case 1: nEndOfs
= mpReadPtr
[0]; break;
1355 case 2: nEndOfs
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1356 case 3: nEndOfs
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2];break;
1357 case 4: nEndOfs
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1359 mpReadPtr
+= nDataOfsSz
;
1360 mpReadPtr
+= nEndOfs
- 1;
1361 mpReadEnd
= mpBaseEnd
;
1362 assert( nEndOfs
>= 0);
1363 assert( mpReadEnd
<= mpBaseEnd
);
1366 // initialize FONTDICT specific values
1367 CffLocal::CffLocal()
1368 : mnPrivDictBase( 0)
1369 , mnPrivDictSize( 0)
1370 , mnLocalSubrOffs( 0)
1371 , mnLocalSubrBase( 0)
1372 , mnLocalSubrCount( 0)
1373 , mnLocalSubrBias( 0)
1374 , maNominalWidth( 0)
1375 , maDefaultWidth( 0)
1383 , mbForceBold( false)
1387 CffGlobal::CffGlobal()
1389 , mnNameIdxCount( 0)
1390 , mnStringIdxBase( 0)
1391 , mnStringIdxCount( 0)
1394 , mnCharStrCount( 0)
1395 , mnEncodingBase( 0)
1397 , mnGlobalSubrBase( 0)
1398 , mnGlobalSubrCount( 0)
1399 , mnGlobalSubrBias( 0)
1400 , mnFDSelectBase( 0)
1401 , mnFontDictBase( 0)
1405 , mnFamilyNameSID( 0)
1409 bool CffSubsetterContext::initialCffRead()
1411 // get the CFFHeader
1412 mpReadPtr
= mpBasePtr
;
1413 const U8 nVerMajor
= *(mpReadPtr
++);
1414 const U8 nVerMinor
= *(mpReadPtr
++);
1415 const U8 nHeaderSize
= *(mpReadPtr
++);
1416 const U8 nOffsetSize
= *(mpReadPtr
++);
1417 // TODO: is the version number useful for anything else?
1418 assert( (nVerMajor
== 1) && (nVerMinor
== 0));
1419 (void)(nVerMajor
+ nVerMinor
+ nOffsetSize
); // avoid compiler warnings
1421 // prepare access to the NameIndex
1422 mnNameIdxBase
= nHeaderSize
;
1423 mpReadPtr
= mpBasePtr
+ nHeaderSize
;
1424 mnNameIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1425 seekIndexEnd( mnNameIdxBase
);
1427 // get the TopDict index
1428 const sal_Int32 nTopDictBase
= getReadOfs();
1429 const int nTopDictCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1430 if( nTopDictCount
) {
1431 for( int i
= 0; i
< nTopDictCount
; ++i
) {
1432 seekIndexData( nTopDictBase
, i
);
1433 while( mpReadPtr
< mpReadEnd
)
1435 assert( mpReadPtr
== mpReadEnd
);
1439 // prepare access to the String index
1440 mnStringIdxBase
= getReadOfs();
1441 mnStringIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1442 seekIndexEnd( mnStringIdxBase
);
1444 // prepare access to the GlobalSubr index
1445 mnGlobalSubrBase
= getReadOfs();
1446 mnGlobalSubrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1447 mnGlobalSubrBias
= (mnGlobalSubrCount
<1240)?107:(mnGlobalSubrCount
<33900)?1131:32768;
1448 // skip past the last GlobalSubr entry
1449 // seekIndexEnd( mnGlobalSubrBase);
1451 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1452 // seekEncodingsEnd( mnEncodingBase);
1453 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1454 // seekCharsetsEnd( mnCharStrBase);
1455 // get/skip FDSelect (CID only) data
1457 // prepare access to the CharStrings index (we got the base from TOPDICT)
1458 mpReadPtr
= mpBasePtr
+ mnCharStrBase
;
1459 mnCharStrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1460 // seekIndexEnd( mnCharStrBase);
1462 // read the FDArray index (CID only)
1464 // assert( mnFontDictBase == tellRel());
1465 mpReadPtr
= mpBasePtr
+ mnFontDictBase
;
1466 mnFDAryCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1467 if (static_cast<size_t>(mnFDAryCount
) >= SAL_N_ELEMENTS(maCffLocal
))
1469 SAL_INFO("vcl.fonts", "CffSubsetterContext: too many CFF in font");
1473 // read FDArray details to get access to the PRIVDICTs
1474 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1475 mpCffLocal
= &maCffLocal
[i
];
1476 seekIndexData( mnFontDictBase
, i
);
1477 while( mpReadPtr
< mpReadEnd
)
1479 assert( mpReadPtr
== mpReadEnd
);
1483 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1484 mpCffLocal
= &maCffLocal
[i
];
1486 // get the PrivateDict index
1487 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1488 if( mpCffLocal
->mnPrivDictSize
!= 0) {
1489 assert( mpCffLocal
->mnPrivDictSize
> 0);
1490 // get the PrivDict data
1491 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnPrivDictBase
;
1492 mpReadEnd
= mpReadPtr
+ mpCffLocal
->mnPrivDictSize
;
1493 assert( mpReadEnd
<= mpBaseEnd
);
1494 // read PrivDict details
1495 while( mpReadPtr
< mpReadEnd
)
1499 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1500 if( mpCffLocal
->mnLocalSubrOffs
) {
1501 // read LocalSubrs summary
1502 mpCffLocal
->mnLocalSubrBase
= mpCffLocal
->mnPrivDictBase
+ mpCffLocal
->mnLocalSubrOffs
;
1503 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnLocalSubrBase
;
1504 const int nSubrCount
= (mpReadPtr
[0] << 8) + mpReadPtr
[1];
1505 mpCffLocal
->mnLocalSubrCount
= nSubrCount
;
1506 mpCffLocal
->mnLocalSubrBias
= (nSubrCount
<1240)?107:(nSubrCount
<33900)?1131:32768;
1507 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1511 // ignore the Notices info
1516 // get a cstring from a StringID
1517 const char* CffSubsetterContext::getString( int nStringID
)
1519 // get a standard string if possible
1520 const static int nStdStrings
= sizeof(pStringIds
)/sizeof(*pStringIds
);
1521 if( (nStringID
>= 0) && (nStringID
< nStdStrings
))
1522 return pStringIds
[ nStringID
];
1524 // else get the string from the StringIndex table
1525 const U8
* pReadPtr
= mpReadPtr
;
1526 const U8
* pReadEnd
= mpReadEnd
;
1527 nStringID
-= nStdStrings
;
1528 int nLen
= seekIndexData( mnStringIdxBase
, nStringID
);
1529 // assert( nLen >= 0);
1530 // TODO: just return the undecorated name
1531 // TODO: get rid of static char buffer
1532 static char aNameBuf
[ 2560];
1534 sprintf( aNameBuf
, "name[%d].notfound!", nStringID
);
1536 const int nMaxLen
= sizeof(aNameBuf
) - 1;
1537 if( nLen
>= nMaxLen
)
1539 for( int i
= 0; i
< nLen
; ++i
)
1540 aNameBuf
[i
] = *(mpReadPtr
++);
1541 aNameBuf
[ nLen
] = '\0';
1543 mpReadPtr
= pReadPtr
;
1544 mpReadEnd
= pReadEnd
;
1548 // access a CID's FDSelect table
1549 int CffSubsetterContext::getFDSelect( int nGlyphIndex
) const
1551 assert( nGlyphIndex
>= 0);
1552 assert( nGlyphIndex
< mnCharStrCount
);
1556 const U8
* pReadPtr
= mpBasePtr
+ mnFDSelectBase
;
1557 const U8 nFDSelFormat
= *(pReadPtr
++);
1558 switch( nFDSelFormat
) {
1559 case 0: { // FDSELECT format 0
1560 pReadPtr
+= nGlyphIndex
;
1561 const U8 nFDIdx
= *(pReadPtr
++);
1564 case 3: { // FDSELECT format 3
1565 const U16 nRangeCount
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1566 assert( nRangeCount
> 0);
1567 assert( nRangeCount
<= mnCharStrCount
);
1568 U16 nPrev
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1569 assert( nPrev
== 0);
1572 // TODO? binary search
1573 for( int i
= 0; i
< nRangeCount
; ++i
) {
1574 const U8 nFDIdx
= pReadPtr
[0];
1575 const U16 nNext
= (pReadPtr
[1]<<8) + pReadPtr
[2];
1576 assert( nPrev
< nNext
);
1577 if( nGlyphIndex
< nNext
)
1583 default: // invalid FDselect format
1584 fprintf( stderr
, "invalid CFF.FdselType=%d\n", nFDSelFormat
);
1592 int CffSubsetterContext::getGlyphSID( int nGlyphIndex
) const
1594 if( nGlyphIndex
== 0)
1595 return 0; // ".notdef"
1596 assert( nGlyphIndex
>= 0);
1597 assert( nGlyphIndex
< mnCharStrCount
);
1598 if( (nGlyphIndex
< 0) || (nGlyphIndex
>= mnCharStrCount
))
1601 // get the SID/CID from the Charset table
1602 const U8
* pReadPtr
= mpBasePtr
+ mnCharsetBase
;
1603 const U8 nCSetFormat
= *(pReadPtr
++);
1604 int nGlyphsToSkip
= nGlyphIndex
- 1;
1605 switch( nCSetFormat
) {
1606 case 0: // charset format 0
1607 pReadPtr
+= 2 * nGlyphsToSkip
;
1610 case 1: // charset format 1
1611 while( nGlyphsToSkip
>= 0) {
1612 const int nLeft
= pReadPtr
[2];
1613 if( nGlyphsToSkip
<= nLeft
)
1615 nGlyphsToSkip
-= nLeft
+ 1;
1619 case 2: // charset format 2
1620 while( nGlyphsToSkip
>= 0) {
1621 const int nLeft
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1622 if( nGlyphsToSkip
<= nLeft
)
1624 nGlyphsToSkip
-= nLeft
+ 1;
1629 fprintf( stderr
, "ILLEGAL CFF-Charset format %d\n", nCSetFormat
);
1633 int nSID
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1634 nSID
+= nGlyphsToSkip
;
1635 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1639 // NOTE: the result becomes invalid with the next call to this method
1640 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex
)
1642 // the first glyph is always the .notdef glyph
1643 const char* pGlyphName
= ".notdef";
1644 if( nGlyphIndex
== 0)
1647 // prepare a result buffer
1648 // TODO: get rid of static buffer
1649 static char aDefaultGlyphName
[64];
1650 pGlyphName
= aDefaultGlyphName
;
1652 // get the glyph specific name
1653 const int nSID
= getGlyphSID( nGlyphIndex
);
1654 if( nSID
< 0) // default glyph name
1655 sprintf( aDefaultGlyphName
, "gly%03d", nGlyphIndex
);
1656 else if( mbCIDFont
) // default glyph name in CIDs
1657 sprintf( aDefaultGlyphName
, "cid%03d", nSID
);
1658 else { // glyph name from string table
1659 const char* pSidName
= getString( nSID
);
1660 // check validity of glyph name
1662 const char* p
= pSidName
;
1663 while( (*p
>= '0') && (*p
<= 'z')) ++p
;
1664 if( (p
>= pSidName
+1) && (*p
== '\0'))
1665 pGlyphName
= pSidName
;
1667 // if needed invent a fallback name
1668 if( pGlyphName
!= pSidName
)
1669 sprintf( aDefaultGlyphName
, "bad%03d", nSID
);
1678 explicit Type1Emitter( FILE* pOutFile
, bool bPfbSubset
);
1680 void setSubsetName( const char* );
1682 size_t emitRawData( const char* pData
, size_t nLength
) const;
1685 void emitAllCrypted();
1686 int tellPos() const;
1687 void updateLen( int nTellPos
, size_t nLength
);
1688 void emitValVector( const char* pLineHead
, const char* pLineTail
, const std::vector
<ValType
>&);
1691 char maBuffer
[MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
1696 char maSubsetName
[256];
1701 Type1Emitter::Type1Emitter( FILE* pOutFile
, bool bPfbSubset
)
1702 : mpFileOut( pOutFile
)
1704 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1706 , mbPfbSubset( bPfbSubset
)
1709 maSubsetName
[0] = '\0';
1712 Type1Emitter::~Type1Emitter()
1716 mpFileOut
= nullptr;
1719 void Type1Emitter::setSubsetName( const char* pSubsetName
)
1721 maSubsetName
[0] = '\0';
1723 strncpy( maSubsetName
, pSubsetName
, sizeof(maSubsetName
));
1724 maSubsetName
[sizeof(maSubsetName
)-1] = '\0';
1727 int Type1Emitter::tellPos() const
1729 int nTellPos
= ftell( mpFileOut
);
1733 void Type1Emitter::updateLen( int nTellPos
, size_t nLength
)
1735 // update PFB segment header length
1737 cData
[0] = static_cast<U8
>(nLength
>> 0);
1738 cData
[1] = static_cast<U8
>(nLength
>> 8);
1739 cData
[2] = static_cast<U8
>(nLength
>> 16);
1740 cData
[3] = static_cast<U8
>(nLength
>> 24);
1741 const long nCurrPos
= ftell(mpFileOut
);
1744 if (fseek( mpFileOut
, nTellPos
, SEEK_SET
) != 0)
1746 fwrite(cData
, 1, sizeof(cData
), mpFileOut
);
1748 (void)fseek(mpFileOut
, nCurrPos
, SEEK_SET
);
1751 inline size_t Type1Emitter::emitRawData(const char* pData
, size_t nLength
) const
1753 return fwrite( pData
, 1, nLength
, mpFileOut
);
1756 inline void Type1Emitter::emitAllRaw()
1758 // writeout raw data
1759 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
1760 emitRawData( maBuffer
, mpPtr
- maBuffer
);
1761 // reset the raw buffer
1765 inline void Type1Emitter::emitAllHex()
1767 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
1768 for( const char* p
= maBuffer
; p
< mpPtr
;) {
1769 // convert binary chunk to hex
1770 char aHexBuf
[0x4000];
1771 char* pOut
= aHexBuf
;
1772 while( (p
< mpPtr
) && (pOut
< aHexBuf
+sizeof(aHexBuf
)-4)) {
1773 // convert each byte to hex
1774 char cNibble
= (*p
>> 4) & 0x0F;
1775 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1776 *(pOut
++) = cNibble
;
1777 cNibble
= *(p
++) & 0x0F;
1778 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1779 *(pOut
++) = cNibble
;
1780 // limit the line length
1781 if( (++mnHexLineCol
& 0x3F) == 0)
1784 // writeout hex-converted chunk
1785 emitRawData( aHexBuf
, pOut
-aHexBuf
);
1787 // reset the raw buffer
1791 void Type1Emitter::emitAllCrypted()
1794 for( char* p
= maBuffer
; p
< mpPtr
; ++p
) {
1795 *p
^= (mnEECryptR
>> 8);
1796 mnEECryptR
= (*reinterpret_cast<U8
*>(p
) + mnEECryptR
) * 52845 + 22719;
1799 // emit the t1crypt result
1806 // #i110387# quick-and-dirty double->ascii conversion
1807 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
1808 // also strip off trailing zeros in fraction while we are at it
1809 inline int dbl2str( char* pOut
, double fVal
)
1811 const int nLen
= psp::getValueOfDouble( pOut
, fVal
, 6);
1815 void Type1Emitter::emitValVector( const char* pLineHead
, const char* pLineTail
,
1816 const std::vector
<ValType
>& rVector
)
1818 // ignore empty vectors
1819 if( rVector
.empty())
1822 // emit the line head
1823 mpPtr
+= sprintf( mpPtr
, "%s", pLineHead
);
1824 // emit the vector values
1825 std::vector
<ValType
>::value_type aVal
= 0;
1826 for( std::vector
<ValType
>::const_iterator it
= rVector
.begin();;) {
1828 if( ++it
== rVector
.end() )
1830 mpPtr
+= dbl2str( mpPtr
, aVal
);
1833 // emit the last value
1834 mpPtr
+= dbl2str( mpPtr
, aVal
);
1835 // emit the line tail
1836 mpPtr
+= sprintf( mpPtr
, "%s", pLineTail
);
1839 bool CffSubsetterContext::emitAsType1( Type1Emitter
& rEmitter
,
1840 const sal_GlyphId
* pReqGlyphIds
, const U8
* pReqEncoding
,
1841 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rFSInfo
)
1843 // prepare some fontdirectory details
1844 static const int nUniqueIdBase
= 4100000; // using private-interchange UniqueIds
1845 static int nUniqueId
= nUniqueIdBase
;
1848 char* pFontName
= rEmitter
.maSubsetName
;
1850 if( mnFontNameSID
) {
1851 // get the fontname directly if available
1852 strncpy( pFontName
, getString( mnFontNameSID
), sizeof(rEmitter
.maSubsetName
) - 1);
1853 pFontName
[sizeof(rEmitter
.maSubsetName
) - 1] = 0;
1854 } else if( mnFullNameSID
) {
1855 // approximate fontname as fullname-whitespace
1856 const char* pI
= getString( mnFullNameSID
);
1857 char* pO
= pFontName
;
1858 const char* pLimit
= pFontName
+ sizeof(rEmitter
.maSubsetName
) - 1;
1859 while( pO
< pLimit
) {
1860 const char c
= *(pI
++);
1868 // fallback name of last resort
1869 strncpy( pFontName
, "DummyName", sizeof(rEmitter
.maSubsetName
));
1872 const char* pFullName
= pFontName
;
1873 const char* pFamilyName
= pFontName
;
1875 char*& pOut
= rEmitter
.mpPtr
; // convenience reference, TODO: cleanup
1877 // create a PFB+Type1 header
1878 if( rEmitter
.mbPfbSubset
) {
1879 static const char aPfbHeader
[] = "\x80\x01\x00\x00\x00\x00";
1880 rEmitter
.emitRawData( aPfbHeader
, sizeof(aPfbHeader
)-1);
1883 pOut
+= sprintf( pOut
, "%%!FontType1-1.0: %s 001.003\n", rEmitter
.maSubsetName
);
1885 pOut
+= sprintf( pOut
,
1886 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
1888 "/PaintType 0 def\n");
1889 pOut
+= sprintf( pOut
, "/FontName /%s def\n", rEmitter
.maSubsetName
);
1890 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
1892 if( maFontMatrix
.size() == 6)
1893 rEmitter
.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix
);
1894 else // emit default FontMatrix if needed
1895 pOut
+= sprintf( pOut
, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
1897 if( maFontBBox
.size() == 4)
1898 rEmitter
.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox
);
1899 else // emit default FontBBox if needed
1900 pOut
+= sprintf( pOut
, "/FontBBox {0 0 999 999}readonly def\n");
1901 // emit FONTINFO into TOPDICT
1902 pOut
+= sprintf( pOut
,
1903 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
1904 " /FullName (%s) readonly def\n"
1905 " /FamilyName (%s) readonly def\n"
1906 "end readonly def\n",
1907 pFullName
, pFamilyName
);
1909 pOut
+= sprintf( pOut
,
1910 "/Encoding 256 array\n"
1911 "0 1 255 {1 index exch /.notdef put} for\n");
1912 for( int i
= 1; (i
< nGlyphCount
) && (i
< 256); ++i
) {
1913 const char* pGlyphName
= getGlyphName( pReqGlyphIds
[i
]);
1914 pOut
+= sprintf( pOut
, "dup %d /%s put\n", pReqEncoding
[i
], pGlyphName
);
1916 pOut
+= sprintf( pOut
, "readonly def\n");
1917 pOut
+= sprintf( pOut
,
1918 // TODO: more topdict entries
1920 "currentfile eexec\n");
1923 rEmitter
.emitAllRaw();
1924 if( rEmitter
.mbPfbSubset
) {
1925 // update PFB header segment
1926 const int nPfbHeaderLen
= rEmitter
.tellPos() - 6;
1927 rEmitter
.updateLen( 2, nPfbHeaderLen
);
1929 // prepare start of eexec segment
1930 rEmitter
.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
1932 const int nEExecSegTell
= rEmitter
.tellPos();
1934 // which always starts with a privdict
1935 // count the privdict entries
1936 int nPrivEntryCount
= 9;
1937 #if !defined(IGNORE_HINTS)
1938 // emit blue hints only if non-default values
1939 nPrivEntryCount
+= int(!mpCffLocal
->maOtherBlues
.empty());
1940 nPrivEntryCount
+= int(!mpCffLocal
->maFamilyBlues
.empty());
1941 nPrivEntryCount
+= int(!mpCffLocal
->maFamilyOtherBlues
.empty());
1942 nPrivEntryCount
+= int(mpCffLocal
->mfBlueScale
!= 0.0);
1943 nPrivEntryCount
+= int(mpCffLocal
->mfBlueShift
!= 0.0);
1944 nPrivEntryCount
+= int(mpCffLocal
->mfBlueFuzz
!= 0.0);
1945 // emit stem hints only if non-default values
1946 nPrivEntryCount
+= int(mpCffLocal
->maStemStdHW
!= 0);
1947 nPrivEntryCount
+= int(mpCffLocal
->maStemStdVW
!= 0);
1948 nPrivEntryCount
+= int(!mpCffLocal
->maStemSnapH
.empty());
1949 nPrivEntryCount
+= int(!mpCffLocal
->maStemSnapV
.empty());
1950 // emit other hints only if non-default values
1951 nPrivEntryCount
+= int(mpCffLocal
->mfExpFactor
!= 0.0);
1952 nPrivEntryCount
+= int(mpCffLocal
->mnLangGroup
!= 0);
1953 nPrivEntryCount
+= int(mpCffLocal
->mnLangGroup
== 1);
1954 nPrivEntryCount
+= int(mpCffLocal
->mbForceBold
);
1955 #endif // IGNORE_HINTS
1956 // emit the privdict header
1957 pOut
+= sprintf( pOut
,
1959 "dup\n/Private %d dict dup begin\n"
1960 "/RD{string currentfile exch readstring pop}executeonly def\n"
1961 "/ND{noaccess def}executeonly def\n"
1962 "/NP{noaccess put}executeonly def\n"
1963 "/MinFeature{16 16}ND\n"
1964 "/password 5839 def\n", // TODO: mnRDCryptSeed?
1967 #if defined(IGNORE_HINTS)
1968 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // BlueValues are mandatory
1970 // emit blue hint related privdict entries
1971 if( !mpCffLocal
->maBlueValues
.empty())
1972 rEmitter
.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal
->maBlueValues
);
1974 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // default to empty BlueValues
1975 rEmitter
.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal
->maOtherBlues
);
1976 rEmitter
.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal
->maFamilyBlues
);
1977 rEmitter
.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal
->maFamilyOtherBlues
);
1979 if( mpCffLocal
->mfBlueScale
) {
1980 pOut
+= sprintf( pOut
, "/BlueScale ");
1981 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueScale
);
1982 pOut
+= sprintf( pOut
, " def\n");
1984 if( mpCffLocal
->mfBlueShift
) { // default BlueShift==7
1985 pOut
+= sprintf( pOut
, "/BlueShift ");
1986 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueShift
);
1987 pOut
+= sprintf( pOut
, " def\n");
1989 if( mpCffLocal
->mfBlueFuzz
) { // default BlueFuzz==1
1990 pOut
+= sprintf( pOut
, "/BlueFuzz ");
1991 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueFuzz
);
1992 pOut
+= sprintf( pOut
, " def\n");
1995 // emit stem hint related privdict entries
1996 if( mpCffLocal
->maStemStdHW
) {
1997 pOut
+= sprintf( pOut
, "/StdHW [");
1998 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdHW
);
1999 pOut
+= sprintf( pOut
, "] def\n");
2001 if( mpCffLocal
->maStemStdVW
) {
2002 pOut
+= sprintf( pOut
, "/StdVW [");
2003 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdVW
);
2004 pOut
+= sprintf( pOut
, "] def\n");
2006 rEmitter
.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal
->maStemSnapH
);
2007 rEmitter
.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal
->maStemSnapV
);
2010 if( mpCffLocal
->mbForceBold
)
2011 pOut
+= sprintf( pOut
, "/ForceBold true def\n");
2012 if( mpCffLocal
->mnLangGroup
!= 0)
2013 pOut
+= sprintf( pOut
, "/LanguageGroup %d def\n", mpCffLocal
->mnLangGroup
);
2014 if( mpCffLocal
->mnLangGroup
== 1) // compatibility with ancient printers
2015 pOut
+= sprintf( pOut
, "/RndStemUp false def\n");
2016 if( mpCffLocal
->mfExpFactor
) {
2017 pOut
+= sprintf( pOut
, "/ExpansionFactor ");
2018 pOut
+= dbl2str( pOut
, mpCffLocal
->mfExpFactor
);
2019 pOut
+= sprintf( pOut
, " def\n");
2021 #endif // IGNORE_HINTS
2023 // emit remaining privdict entries
2024 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
2025 // TODO?: more privdict entries?
2027 static const char aOtherSubrs
[] =
2029 "% Dummy code for faking flex hints\n"
2030 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2031 "{1183615869 systemdict /internaldict get exec\n"
2032 "dup /startlock known\n"
2033 "{/startlock get exec}\n"
2034 "{dup /strtlck known\n"
2035 "{/strtlck get exec}\n"
2036 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2038 memcpy( pOut
, aOtherSubrs
, sizeof(aOtherSubrs
)-1);
2039 pOut
+= sizeof(aOtherSubrs
)-1;
2041 // emit used GlobalSubr charstrings
2042 // these are the just the default subrs
2043 // TODO: do we need them as the flex hints are resolved differently?
2044 static const char aSubrs
[] =
2046 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2047 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2048 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2049 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2050 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2052 memcpy( pOut
, aSubrs
, sizeof(aSubrs
)-1);
2053 pOut
+= sizeof(aSubrs
)-1;
2055 // TODO: emit more GlobalSubr charstrings?
2056 // TODO: emit used LocalSubr charstrings?
2058 // emit the CharStrings for the requested glyphs
2059 pOut
+= sprintf( pOut
,
2060 "2 index /CharStrings %d dict dup begin\n", nGlyphCount
);
2061 rEmitter
.emitAllCrypted();
2062 for( int i
= 0; i
< nGlyphCount
; ++i
) {
2063 const int nCffGlyphId
= pReqGlyphIds
[i
];
2064 assert( (nCffGlyphId
>= 0) && (nCffGlyphId
< mnCharStrCount
));
2065 // get privdict context matching to the glyph
2066 const int nFDSelect
= getFDSelect( nCffGlyphId
);
2069 mpCffLocal
= &maCffLocal
[ nFDSelect
];
2070 // convert the Type2op charstring to its Type1op counterpart
2071 const int nT2Len
= seekIndexData( mnCharStrBase
, nCffGlyphId
);
2072 assert( nT2Len
> 0);
2073 U8 aType1Ops
[ MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
2074 const int nT1Len
= convert2Type1Ops( mpCffLocal
, mpReadPtr
, nT2Len
, aType1Ops
);
2075 // get the glyph name
2076 const char* pGlyphName
= getGlyphName( nCffGlyphId
);
2077 // emit the encrypted Type1op charstring
2078 pOut
+= sprintf( pOut
, "/%s %d RD ", pGlyphName
, nT1Len
);
2079 memcpy( pOut
, aType1Ops
, nT1Len
);
2081 pOut
+= sprintf( pOut
, " ND\n");
2082 rEmitter
.emitAllCrypted();
2083 // provide individual glyphwidths if requested
2084 if( pGlyphWidths
) {
2085 ValType aCharWidth
= getCharWidth();
2086 if( maFontMatrix
.size() >= 4)
2087 aCharWidth
*= 1000.0F
* maFontMatrix
[0];
2088 pGlyphWidths
[i
] = static_cast<GlyphWidth
>(aCharWidth
);
2091 pOut
+= sprintf( pOut
, "end end\nreadonly put\nput\n");
2092 pOut
+= sprintf( pOut
, "dup/FontName get exch definefont pop\n");
2093 pOut
+= sprintf( pOut
, "mark currentfile closefile\n");
2094 rEmitter
.emitAllCrypted();
2096 // mark stop of eexec encryption
2097 if( rEmitter
.mbPfbSubset
) {
2098 const int nEExecLen
= rEmitter
.tellPos() - nEExecSegTell
;
2099 rEmitter
.updateLen( nEExecSegTell
-4, nEExecLen
);
2102 // create PFB footer
2103 static const char aPfxFooter
[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2104 "0000000000000000000000000000000000000000000000000000000000000000\n"
2105 "0000000000000000000000000000000000000000000000000000000000000000\n"
2106 "0000000000000000000000000000000000000000000000000000000000000000\n"
2107 "0000000000000000000000000000000000000000000000000000000000000000\n"
2108 "0000000000000000000000000000000000000000000000000000000000000000\n"
2109 "0000000000000000000000000000000000000000000000000000000000000000\n"
2110 "0000000000000000000000000000000000000000000000000000000000000000\n"
2111 "0000000000000000000000000000000000000000000000000000000000000000\n"
2114 if( rEmitter
.mbPfbSubset
)
2115 rEmitter
.emitRawData( aPfxFooter
, sizeof(aPfxFooter
)-1);
2117 rEmitter
.emitRawData( aPfxFooter
+6, sizeof(aPfxFooter
)-9);
2119 // provide details to the subset requesters, TODO: move into own method?
2120 // note: Top and Bottom are flipped between Type1 and VCL
2121 // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
2122 ValType fXFactor
= 1.0;
2123 ValType fYFactor
= 1.0;
2124 if( maFontMatrix
.size() >= 4) {
2125 fXFactor
= 1000.0F
* maFontMatrix
[0];
2126 fYFactor
= 1000.0F
* maFontMatrix
[3];
2128 rFSInfo
.m_aFontBBox
= Rectangle( Point( static_cast<sal_Int32
>(maFontBBox
[0] * fXFactor
),
2129 static_cast<sal_Int32
>(maFontBBox
[1] * fYFactor
) ),
2130 Point( static_cast<sal_Int32
>(maFontBBox
[2] * fXFactor
),
2131 static_cast<sal_Int32
>(maFontBBox
[3] * fYFactor
) ) );
2132 // PDF-Spec says the values below mean the ink bounds!
2133 // TODO: use better approximations for these ink bounds
2134 rFSInfo
.m_nAscent
= +rFSInfo
.m_aFontBBox
.Bottom(); // for capital letters
2135 rFSInfo
.m_nDescent
= -rFSInfo
.m_aFontBBox
.Top(); // for all letters
2136 rFSInfo
.m_nCapHeight
= rFSInfo
.m_nAscent
; // for top-flat capital letters
2138 rFSInfo
.m_nFontType
= rEmitter
.mbPfbSubset
? FontSubsetInfo::TYPE1_PFB
: FontSubsetInfo::TYPE1_PFA
;
2139 rFSInfo
.m_aPSName
= OUString( rEmitter
.maSubsetName
, strlen(rEmitter
.maSubsetName
), RTL_TEXTENCODING_UTF8
);
2144 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth
* pOutGlyphWidths
)
2146 CffSubsetterContext
aCff( mpInFontBytes
, mnInByteLength
);
2147 bool bRC
= aCff
.initialCffRead();
2151 // emit Type1 subset from the CFF input
2152 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2153 const bool bPfbSubset
= (0 != (mnReqFontTypeMask
& FontSubsetInfo::TYPE1_PFB
));
2154 Type1Emitter
aType1Emitter( mpOutFile
, bPfbSubset
);
2155 aType1Emitter
.setSubsetName( mpReqFontName
);
2156 bRC
= aCff
.emitAsType1( aType1Emitter
,
2157 mpReqGlyphIds
, mpReqEncodedIds
,
2158 pOutGlyphWidths
, mnReqGlyphCount
, *this);
2162 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */