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>
29 //#define IGNORE_HINTS
31 typedef unsigned char U8
;
32 typedef unsigned short U16
;
33 typedef long long S64
;
35 typedef sal_Int32 GlyphWidth
;
37 typedef float RealType
;
38 typedef RealType ValType
;
40 typedef std::vector
<ValType
> ValVector
;
42 // ====================================================================
44 static const char* pStringIds
[] = {
45 /*0*/ ".notdef", "space", "exclam", "quotedbl",
46 "numbersign", "dollar", "percent", "ampersand",
47 "quoteright", "parenleft", "parenright", "asterisk",
48 "plus", "comma", "hyphen", "period",
49 /*16*/ "slash", "zero", "one", "two",
50 "three", "four", "five", "six",
51 "seven", "eight", "nine", "colon",
52 "semicolon", "less", "equal", "greater",
53 /*32*/ "question", "at", "A", "B",
57 /*48*/ "O", "P", "Q", "R",
60 "bracketleft", "backslash", "bracketright", "asciicircum",
61 /*64*/ "underscore", "quoteleft", "a", "b",
65 /*80*/ "o", "p", "q", "r",
68 "braceleft", "bar", "braceright", "asciitilde",
69 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
70 "yen", "florin", "section", "currency",
71 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
72 "guilsinglright", "fi", "fl", "endash",
73 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
74 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
75 "guillemotright", "ellipsis", "perthousand", "questiondown",
76 "grave", "acute", "circumflex", "tilde",
77 /*128*/ "macron", "breve", "dotaccent", "dieresis",
78 "ring", "cedilla", "hungarumlaut", "ogonek",
79 "caron", "emdash", "AE", "ordfeminine",
80 "Lslash", "Oslash", "OE", "ordmasculine",
81 /*144*/ "ae", "dotlessi", "lslash", "oslash",
82 "oe", "germandbls", "onesuperior", "logicalnot",
83 "mu", "trademark", "Eth", "onehalf",
84 "plusminus", "Thorn", "onequarter", "divide",
85 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
86 "twosuperior", "registered", "minus", "eth",
87 "multiply", "threesuperior", "copyright", "Aacute",
88 "Acircumflex", "Adieresis", "Agrave", "Aring",
89 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
90 "Edieresis", "Egrave", "Iacute", "Icircumflex",
91 "Idieresis", "Igrave", "Ntilde", "Oacute",
92 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
93 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
94 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
95 "aacute", "acircumflex", "adieresis", "agrave",
96 "aring", "atilde", "ccedilla", "eacute",
97 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
98 "icircumflex", "idieresis", "igrave", "ntilde",
99 "oacute", "ocircumflex", "odieresis", "ograve",
100 "otilde", "scaron", "uacute", "ucircumflex",
101 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
102 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
103 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
104 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
105 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
106 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
107 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
108 "questionsmall", "asuperior", "bsuperior", "centsuperior",
109 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
110 "msuperior", "nsuperior", "osuperior", "rsuperior",
111 "ssuperior", "tsuperior", "ff", "ffi",
112 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
113 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
114 "Csmall", "Dsmall", "Esmall", "Fsmall",
115 "Gsmall", "Hsmall", "Ismall", "Jsmall",
116 "Ksmall", "Lsmall", "Msmall", "Nsmall",
117 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
118 "Ssmall", "Tsmall", "Usmall", "Vsmall",
119 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
120 "colonmonetary", "onefitted", "rupia", "Tildesmall",
121 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
122 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
123 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
124 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
125 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
126 "onethird", "twothirds", "zerosuperior", "foursuperior",
127 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
128 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
129 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
130 "seveninferior", "eightinferior", "nineinferior", "centinferior",
131 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
132 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
133 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
134 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
135 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
136 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
137 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
138 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
139 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
140 "001.001", "001.002", "001.003", "Black",
141 /*384*/ "Bold", "Book", "Light", "Medium",
142 "Regular", "Roman", "Semibold"
145 // --------------------------------------------------------------------
147 // --------------------------------------------------------------------
149 // TOP DICT keywords (also covers PRIV DICT keywords)
150 static const char* pDictOps
[] = {
151 "sVersion", "sNotice", "sFullName", "sFamilyName",
152 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
153 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
154 "xESC", "nUniqueID", "aXUID", "nCharset",
155 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
156 "nDefaultWidthX", "nNominalWidthX", NULL
, NULL
,
157 NULL
, NULL
, NULL
, NULL
,
158 "shortint", "longint", "BCD", NULL
161 // --------------------------------------------------------------------
163 // TOP DICT escapes (also covers PRIV DICT escapes)
164 static const char* pDictEscs
[] = {
165 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
166 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
167 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
168 "dStemSnapH", "dStemSnapV", "bForceBold", NULL
,
169 NULL
, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
170 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
171 NULL
, NULL
, NULL
, NULL
,
172 NULL
, NULL
, "rROS", "nCIDFontVersion",
173 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
174 "nFDArray", "nFDSelect", "sFontName"
177 // --------------------------------------------------------------------
179 static const char* pType1Ops
[] = {
180 NULL
, "2hstem", NULL
, "2vstem",
181 "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
182 "Crrcurveto", "0closepath", "Lcallsubr", "0return",
183 "xT1ESC", "2hsbw", "0endchar", NULL
,
184 NULL
, NULL
, NULL
, NULL
,
185 NULL
, "2rmoveto", "1hmoveto", NULL
,
186 NULL
, NULL
, NULL
, NULL
,
187 NULL
, NULL
, "4vhcurveto", "4hvcurveto"
190 // --------------------------------------------------------------------
192 static const char* pT1EscOps
[] = {
193 "0dotsection", "6vstem3", "6hstem3", NULL
,
194 NULL
, NULL
, "5seac", "4sbw",
195 NULL
, "1abs", "2add", "2sub",
196 "2div", NULL
, NULL
, NULL
,
197 "Gcallothersubr", "1pop", NULL
, NULL
,
198 NULL
, NULL
, NULL
, NULL
,
199 NULL
, NULL
, NULL
, NULL
,
200 NULL
, NULL
, NULL
, NULL
,
201 NULL
, "2setcurrentpoint"
204 // --------------------------------------------------------------------
210 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
211 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CLOSEPATH
=9,
212 CALLSUBR
=10, RETURN
=11, T1ESC
=12, HSBW
=13,
213 ENDCHAR
=14, RMOVETO
=21, HMOVETO
=22, VHCURVETO
=30,
219 DOTSECTION
=0, VSTEM3
=1, HSTEM3
=2, SEAC
=6,
220 SBW
=7, ABS
=9, ADD
=10, SUB
=11,
221 DIV
=12, CALLOTHERSUBR
=16, POP
=17, SETCURRENTPOINT
=33
225 // --------------------------------------------------------------------
227 static const char* pType2Ops
[] = {
228 NULL
, "hhstem", NULL
, "vvstem",
229 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
230 "Crrcurveto", NULL
, "Lcallsubr", "Xreturn",
231 "xT2ESC", NULL
, "eendchar", NULL
,
232 NULL
, NULL
, "Hhstemhm", "Khintmask",
233 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
234 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
235 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
238 // --------------------------------------------------------------------
240 static const char* pT2EscOps
[] = {
241 NULL
, NULL
, NULL
, "2and",
242 "2or", "1not", NULL
, NULL
,
243 NULL
, "1abs", "2add", "2sub",
244 "2div", NULL
, "1neg", "2eq",
245 NULL
, NULL
, "1drop", NULL
,
246 "1put", "1get", "4ifelse", "0random",
247 "2mul", NULL
, "1sqrt", "1dup",
248 "2exch", "Iindex", "Rroll", NULL
,
249 NULL
, NULL
, "7hflex", "Fflex",
253 // --------------------------------------------------------------------
259 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
260 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CALLSUBR
=10,
261 RETURN
=11, T2ESC
=12, ENDCHAR
=14, HSTEMHM
=18,
262 HINTMASK
=19, CNTRMASK
=20, RMOVETO
=21, HMOVETO
=22,
263 VSTEMHM
=23, RCURVELINE
=24, RLINECURVE
=25, VVCURVETO
=26,
264 HHCURVETO
=27, SHORTINT
=28, CALLGSUBR
=29, VHCURVETO
=30,
270 AND
=3, OR
=4, NOT
=5, ABS
=9,
271 ADD
=10, SUB
=11, DIV
=12, NEG
=14,
272 EQ
=15, DROP
=18, PUT
=20, GET
=21,
273 IFELSE
=22, RANDOM
=23, MUL
=24, SQRT
=26,
274 DUP
=27, EXCH
=28, INDEX
=29, ROLL
=30,
275 HFLEX
=34, FLEX
=35, HFLEX1
=36, FLEX1
=37
279 // ====================================================================
283 explicit CffGlobal();
288 int mnStringIdxCount
;
294 int mnGlobalSubrBase
;
295 int mnGlobalSubrCount
;
296 int mnGlobalSubrBias
;
301 ValVector maFontBBox
;
302 ValVector maFontMatrix
;
309 // ====================================================================
319 int mnLocalSubrCount
;
322 ValType maNominalWidth
;
323 ValType maDefaultWidth
;
325 // ATM hinting related values
328 ValVector maStemSnapH
;
329 ValVector maStemSnapV
;
330 ValVector maBlueValues
;
331 ValVector maOtherBlues
;
332 ValVector maFamilyBlues
;
333 ValVector maFamilyOtherBlues
;
334 RealType mfBlueScale
;
335 RealType mfBlueShift
;
337 RealType mfExpFactor
;
342 // ====================================================================
344 class SubsetterContext
347 virtual ~SubsetterContext( void);
348 virtual bool emitAsType1( class Type1Emitter
&,
349 const long* pGlyphIDs
, const U8
* pEncoding
,
350 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& ) = 0;
353 // --------------------------------------------------------------------
355 SubsetterContext::~SubsetterContext( void)
358 // ====================================================================
360 class CffSubsetterContext
361 : public SubsetterContext
365 static const int NMAXSTACK
= 48; // see CFF.appendixB
366 static const int NMAXHINTS
= 2*96; // see CFF.appendixB
367 static const int NMAXTRANS
= 32; // see CFF.appendixB
369 explicit CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
);
370 virtual ~CffSubsetterContext( void);
372 void initialCffRead( void);
373 bool emitAsType1( class Type1Emitter
&,
374 const long* pGlyphIDs
, const U8
* pEncoding
,
375 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& );
377 // used by charstring converter
378 void setCharStringType( int);
379 void fakeLocalSubrCount( int nLocalSubrs
) { maCffLocal
[0].mnLocalSubrCount
=nLocalSubrs
;}
381 int convert2Type1Ops( CffLocal
*, const U8
* pType2Ops
, int nType2Len
, U8
* pType1Ops
);
383 void convertOneTypeOp( void);
384 void convertOneTypeEsc( void);
385 void callType2Subr( bool bGlobal
, int nSubrNumber
);
386 long getReadOfs( void) const { return (long)(mpReadPtr
- mpBasePtr
);}
401 int seekIndexData( int nIndexBase
, int nDataIndex
);
402 void seekIndexEnd( int nIndexBase
);
405 const char** mpCharStringOps
;
406 const char** mpCharStringEscs
;
408 CffLocal maCffLocal
[16];
409 CffLocal
* mpCffLocal
;
411 void readDictOp( void);
412 RealType
readRealVal( void);
413 const char* getString( int nStringID
);
414 int getFDSelect( int nGlyphIndex
) const;
415 int getGlyphSID( int nGlyphIndex
) const;
416 const char* getGlyphName( int nGlyphIndex
);
418 void read2push( void);
419 void pop2write( void);
420 void writeType1Val( ValType
);
421 void writeTypeOp( int nTypeOp
);
422 void writeTypeEsc( int nTypeOp
);
423 void writeCurveTo( int nStackPos
, int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
);
424 void pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
=0);
425 void popAll2Write( int nTypeOp
);
427 public: // TODO: is public really needed?
428 // accessing the value stack
429 // TODO: add more checks
430 void push( ValType nVal
) { mnValStack
[ mnStackIdx
++] = nVal
;}
431 ValType
popVal( void) { return ((mnStackIdx
>0) ? mnValStack
[ --mnStackIdx
] : 0);}
432 ValType
peekVal( void) const { return ((mnStackIdx
>0) ? mnValStack
[ mnStackIdx
-1] : 0);}
433 ValType
getVal( int nIndex
) const { return mnValStack
[ nIndex
];}
435 int peekInt( void) const;
436 int getInt( int nIndex
) const;
437 int size( void) const { return mnStackIdx
;}
438 bool empty( void) const { return !mnStackIdx
;}
439 void clear( void) { mnStackIdx
= 0;}
441 // accessing the charstring hints
442 void addHints( bool bVerticalHints
);
443 int getHorzHintCount( void) const { return (mnHorzHintSize
/2);}
444 int getVertHintCount( void) const { return (mnHintSize
-mnHorzHintSize
)/2;}
446 // accessing other charstring specifics
447 bool hasCharWidth( void) const { return (maCharWidth
> 0);}
448 ValType
getCharWidth( void) const { return maCharWidth
;}
449 void setNominalWidth( ValType aWidth
) { mpCffLocal
->maNominalWidth
= aWidth
;}
450 void setDefaultWidth( ValType aWidth
) { mpCffLocal
->maDefaultWidth
= aWidth
;}
451 void updateWidth( bool bUseFirstVal
);
454 // typeop exceution context
456 ValType mnValStack
[ NMAXSTACK
+4];
457 ValType mnTransVals
[ NMAXTRANS
];
461 ValType mnHintStack
[ NMAXHINTS
];
466 // --------------------------------------------------------------------
468 CffSubsetterContext::CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
)
469 : mpBasePtr( pBasePtr
)
470 , mpBaseEnd( pBasePtr
+nBaseLen
)
476 // setCharStringType( 1);
477 // TODO: new CffLocal[ mnFDAryCount];
478 mpCffLocal
= &maCffLocal
[0];
481 // --------------------------------------------------------------------
483 CffSubsetterContext::~CffSubsetterContext( void)
485 // TODO: delete[] maCffLocal;
488 // --------------------------------------------------------------------
490 inline int CffSubsetterContext::popInt( void)
492 const ValType aVal
= popVal();
493 const int nInt
= static_cast<int>(aVal
);
494 assert( nInt
== aVal
);
498 // --------------------------------------------------------------------
500 inline int CffSubsetterContext::peekInt( void) const
502 const ValType aVal
= peekVal();
503 const int nInt
= static_cast<int>(aVal
);
504 assert( nInt
== aVal
);
508 // --------------------------------------------------------------------
510 inline int CffSubsetterContext::getInt( int nIndex
) const
512 const ValType aVal
= getVal( nIndex
);
513 const int nInt
= static_cast<int>(aVal
);
514 assert( nInt
== aVal
);
518 // --------------------------------------------------------------------
520 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal
)
522 #if 1 // TODO: is this still needed?
523 // the first value is not a hint but the charwidth
528 maCharWidth
= mpCffLocal
->maNominalWidth
+ mnValStack
[0];
529 // remove bottom stack entry
531 for( int i
= 0; i
< mnStackIdx
; ++i
)
532 mnValStack
[ i
] = mnValStack
[ i
+1];
534 maCharWidth
= mpCffLocal
->maDefaultWidth
;
538 // --------------------------------------------------------------------
540 void CffSubsetterContext::addHints( bool bVerticalHints
)
542 // the first charstring value may a charwidth instead of a charwidth
543 updateWidth( (mnStackIdx
& 1) != 0);
544 // return early (e.g. no implicit hints for hintmask)
548 // copy the remaining values to the hint arrays
549 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
550 if( mnStackIdx
& 1) --mnStackIdx
;//#######
551 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
553 assert( (mnHintSize
+ mnStackIdx
) <= 2*NMAXHINTS
);
556 mnHintSize
+= mnStackIdx
;
558 ValType nHintOfs
= 0;
559 for( int i
= 0; i
< mnStackIdx
; ++i
) {
560 nHintOfs
+= mnValStack
[ i
];
561 mnHintStack
[ mnHintSize
++] = nHintOfs
;
563 #endif // IGNORE_HINTS
565 mnHorzHintSize
= mnHintSize
;
567 // clear all values from the stack
571 // --------------------------------------------------------------------
573 void CffSubsetterContext::setCharStringType( int nVal
)
576 case 1: mpCharStringOps
=pType1Ops
; mpCharStringEscs
=pT1EscOps
; break;
577 case 2: mpCharStringOps
=pType2Ops
; mpCharStringEscs
=pT2EscOps
; break;
578 default: fprintf( stderr
, "Unknown CharstringType=%d\n",nVal
); break;
582 // --------------------------------------------------------------------
584 void CffSubsetterContext::readDictOp( void)
587 const U8 c
= *mpReadPtr
;
589 int nOpId
= *(mpReadPtr
++);
590 const char* pCmdName
= 0;
592 pCmdName
= pDictOps
[nOpId
];
594 const U8 nExtId
= *(mpReadPtr
++);
596 pCmdName
= pDictEscs
[nExtId
];
597 nOpId
= 900 + nExtId
;
600 if (!pCmdName
) // skip reserved operators
603 //TODO: if( nStackIdx > 0)
606 default: fprintf( stderr
, "unsupported DictOp.type=\'%c\'\n", *pCmdName
); break;
610 case 915: mpCffLocal
->mbForceBold
= nInt
; break; // "ForceBold"
611 default: break; // TODO: handle more boolean dictops?
614 case 'n': // dict-op number
616 nInt
= static_cast<int>(nVal
);
618 case 10: mpCffLocal
->maStemStdHW
= nVal
; break; // "StdHW"
619 case 11: mpCffLocal
->maStemStdVW
= nVal
; break; // "StdVW"
620 case 15: mnCharsetBase
= nInt
; break; // "charset"
621 case 16: mnEncodingBase
= nInt
; break; // "nEncoding"
622 case 17: mnCharStrBase
= nInt
; break; // "nCharStrings"
623 case 19: mpCffLocal
->mnLocalSubrOffs
= nInt
; break;// "nSubrs"
624 case 20: setDefaultWidth( nVal
); break; // "defaultWidthX"
625 case 21: setNominalWidth( nVal
); break; // "nominalWidthX"
626 case 909: mpCffLocal
->mfBlueScale
= nVal
; break; // "BlueScale"
627 case 910: mpCffLocal
->mfBlueShift
= nVal
; break; // "BlueShift"
628 case 911: mpCffLocal
->mfBlueFuzz
= nVal
; break; // "BlueFuzz"
629 case 912: mpCffLocal
->mfExpFactor
= nVal
; break; // "ExpansionFactor"
630 case 917: mpCffLocal
->mnLangGroup
= nInt
; break; // "LanguageGroup"
631 case 936: mnFontDictBase
= nInt
; break; // "nFDArray"
632 case 937: mnFDSelectBase
= nInt
; break; // "nFDSelect"
633 default: break; // TODO: handle more numeric dictops?
638 case 5: maFontBBox
.clear(); break; // "FontBBox"
639 case 907: maFontMatrix
.clear(); break; // "FontMatrix"
640 default: break; // TODO: reset other arrays?
642 for( int i
= 0; i
< size(); ++i
) {
645 case 5: maFontBBox
.push_back( nVal
); break; // "FontBBox"
646 case 907: maFontMatrix
.push_back( nVal
); break; // "FontMatrix"
647 default: break; // TODO: handle more array dictops?
652 case 'd': { // delta array
654 for( int i
= 0; i
< size(); ++i
) {
657 case 6: mpCffLocal
->maBlueValues
.push_back( nVal
); break; // "BlueValues"
658 case 7: mpCffLocal
->maOtherBlues
.push_back( nVal
); break; // "OtherBlues"
659 case 8: mpCffLocal
->maFamilyBlues
.push_back( nVal
); break; // "FamilyBlues"
660 case 9: mpCffLocal
->maFamilyOtherBlues
.push_back( nVal
); break;// "FamilyOtherBlues"
661 case 912: mpCffLocal
->maStemSnapH
.push_back( nVal
); break; // "StemSnapH"
662 case 913: mpCffLocal
->maStemSnapV
.push_back( nVal
); break; // "StemSnapV"
663 default: break; // TODO: handle more delta-array dictops?
668 case 's': // stringid (SID)
671 case 2: mnFullNameSID
= nInt
; break; // "FullName"
672 case 3: mnFamilyNameSID
= nInt
; break; // "FamilyName"
673 case 938: mnFontNameSID
= nInt
; break; // "FontName"
674 default: break; // TODO: handle more string dictops?
677 case 'P': // private dict
678 mpCffLocal
->mnPrivDictBase
= popInt();
679 mpCffLocal
->mnPrivDictSize
= popInt();
681 case 'r': { // ROS operands
682 int nSid1
= popInt();
683 int nSid2
= popInt();
684 (void)nSid1
; // TODO: use
685 (void)nSid2
; // TODO: use
689 case 't': // CharstringType
691 setCharStringType( nInt
);
698 if( (c
>= 32) || (c
== 28) ) {
701 } else if( c
== 29 ) { // longint
702 ++mpReadPtr
; // skip 29
703 int nS32
= mpReadPtr
[0] << 24;
704 nS32
+= mpReadPtr
[1] << 16;
705 nS32
+= mpReadPtr
[2] << 8;
706 nS32
+= mpReadPtr
[3] << 0;
707 if( (sizeof(nS32
) != 4) && (nS32
& (1<<31)))
708 nS32
|= (~0U) << 31; // assuming 2s complement
710 nVal
= static_cast<ValType
>(nS32
);
712 } else if( c
== 30) { // real number
713 ++mpReadPtr
; // skip 30
714 const RealType fReal
= readRealVal();
715 // push value onto stack
721 // --------------------------------------------------------------------
723 void CffSubsetterContext::read2push()
727 const U8
*& p
= mpReadPtr
;
730 short nS16
= (p
[1] << 8) + p
[2];
731 if( (sizeof(nS16
) != 2) && (nS16
& (1<<15)))
732 nS16
|= (~0U) << 15; // assuming 2s complement
735 } else if( c
<= 246 ) { // -107..+107
736 aVal
= static_cast<ValType
>(p
[0] - 139);
738 } else if( c
<= 250 ) { // +108..+1131
739 aVal
= static_cast<ValType
>(((p
[0] << 8) + p
[1]) - 63124);
741 } else if( c
<= 254 ) { // -108..-1131
742 aVal
= static_cast<ValType
>(64148 - ((p
[0] << 8) + p
[1]));
744 } else /*if( c == 255)*/ { // Fixed16.16
745 int nS32
= (p
[1] << 24) + (p
[2] << 16) + (p
[3] << 8) + p
[4];
746 if( (sizeof(nS32
) != 2) && (nS32
& (1<<31)))
747 nS32
|= (~0U) << 31; // assuming 2s complement
748 aVal
= static_cast<ValType
>(nS32
* (1.0 / 0x10000));
755 // --------------------------------------------------------------------
757 void CffSubsetterContext::writeType1Val( ValType aVal
)
759 U8
* pOut
= mpWritePtr
;
761 int nInt
= static_cast<int>(aVal
);
762 static const int nOutCharstrType
= 1;
763 if( (nInt
!= aVal
) && (nOutCharstrType
== 2)) {
764 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
765 *(pOut
++) = 255; // Fixed 16.16
766 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
767 *(pOut
++) = static_cast<U8
>(nInt
);
768 nInt
= static_cast<int>(aVal
* 0x10000) & 0xFFFF;
769 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
770 *(pOut
++) = static_cast<U8
>(nInt
);
771 } else if( (nInt
>= -107) && (nInt
<= +107)) {
772 *(pOut
++) = static_cast<U8
>(nInt
+ 139); // -107..+107
773 } else if( (nInt
>= -1131) && (nInt
<= +1131)) {
775 nInt
+= 63124; // +108..+1131
777 nInt
= 64148 - nInt
; // -108..-1131
778 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
779 *(pOut
++) = static_cast<U8
>(nInt
);
780 } else if( nOutCharstrType
== 1) {
781 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
783 *(pOut
++) = static_cast<U8
>(nInt
>> 24);
784 *(pOut
++) = static_cast<U8
>(nInt
>> 16);
785 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
786 *(pOut
++) = static_cast<U8
>(nInt
);
792 // --------------------------------------------------------------------
794 inline void CffSubsetterContext::pop2write( void)
796 const ValType aVal
= popVal();
797 writeType1Val( aVal
);
800 // --------------------------------------------------------------------
802 inline void CffSubsetterContext::writeTypeOp( int nTypeOp
)
804 *(mpWritePtr
++) = static_cast<U8
>(nTypeOp
);
807 // --------------------------------------------------------------------
809 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc
)
811 *(mpWritePtr
++) = TYPE1OP::T1ESC
;
812 *(mpWritePtr
++) = static_cast<U8
>(nTypeEsc
);
815 // --------------------------------------------------------------------
817 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
)
819 for( int i
= 0; i
< mnStackIdx
;) {
820 for( int j
= 0; j
< nArgsPerTypo
; ++j
) {
821 const ValType aVal
= mnValStack
[i
+j
];
822 writeType1Val( aVal
);
825 writeTypeOp( nTypeOp
);
826 nTypeOp
^= nTypeXor
; // for toggling vlineto/hlineto
831 // --------------------------------------------------------------------
833 void CffSubsetterContext::popAll2Write( int nTypeOp
)
835 // pop in reverse order, then write
836 for( int i
= 0; i
< mnStackIdx
; ++i
) {
837 const ValType aVal
= mnValStack
[i
];
838 writeType1Val( aVal
);
841 writeTypeOp( nTypeOp
);
844 // --------------------------------------------------------------------
846 void CffSubsetterContext::writeCurveTo( int nStackPos
,
847 int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
)
849 // get the values from the stack
850 const ValType nDX1
= nIX1
? mnValStack
[ nStackPos
+nIX1
] : 0;
851 const ValType nDY1
= nIY1
? mnValStack
[ nStackPos
+nIY1
] : 0;
852 const ValType nDX2
= nIX2
? mnValStack
[ nStackPos
+nIX2
] : 0;
853 const ValType nDY2
= nIY2
? mnValStack
[ nStackPos
+nIY2
] : 0;
854 const ValType nDX3
= nIX3
? mnValStack
[ nStackPos
+nIX3
] : 0;
855 const ValType nDY3
= nIY3
? mnValStack
[ nStackPos
+nIY3
] : 0;
857 // emit the curveto operator and operands
858 // TODO: determine the most efficient curveto operator
859 // TODO: depending on type1op or type2op target
860 writeType1Val( nDX1
);
861 writeType1Val( nDY1
);
862 writeType1Val( nDX2
);
863 writeType1Val( nDY2
);
864 writeType1Val( nDX3
);
865 writeType1Val( nDY3
);
866 writeTypeOp( TYPE1OP::RCURVETO
);
869 // --------------------------------------------------------------------
871 void CffSubsetterContext::convertOneTypeOp( void)
873 const int nType2Op
= *(mpReadPtr
++);
875 int i
, nInt
; // prevent WAE for declarations inside switch cases
883 addHints( nType2Op
== TYPE2OP::VSTEM
);
885 for( i
= 0; i
< mnHintSize
; i
+=2 ) {
886 writeType1Val( mnHintStack
[i
]);
887 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
888 writeTypeOp( nType2Op
);
890 #endif // IGNORE_HINTS
892 case TYPE2OP::HSTEMHM
:
893 case TYPE2OP::VSTEMHM
:
894 addHints( nType2Op
== TYPE2OP::VSTEMHM
);
896 case TYPE2OP::CNTRMASK
:
897 // TODO: replace cntrmask with vstem3/hstem3
900 mpReadPtr
+= (mnHintSize
+ 15) / 16;
901 mbIgnoreHints
= true;
906 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
908 nMaskByte
= *(mpReadPtr
++);
911 if( !(nMaskByte
& nMaskBit
))
913 if( i
>= 8*(int)sizeof(mnCntrMask
))
914 mbIgnoreHints
= true;
917 mnCntrMask
|= (1U << i
);
922 case TYPE2OP::HINTMASK
:
925 mpReadPtr
+= (mnHintSize
+ 15) / 16;
929 int nCntrBits
[2] = {0,0};
932 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
934 nMaskByte
= *(mpReadPtr
++);
937 if( !(nMaskByte
& nMaskBit
))
939 if( i
>= 8*(int)sizeof(nHintMask
))
940 mbIgnoreHints
= true;
943 nHintMask
|= (1U << i
);
944 nCntrBits
[ i
< mnHorzHintSize
] += (mnCntrMask
>> i
) & 1;
947 mbIgnoreHints
|= (nCntrBits
[0] && (nCntrBits
[0] != 3));
948 mbIgnoreHints
|= (nCntrBits
[1] && (nCntrBits
[1] != 3));
952 for( i
= 0; i
< mnHintSize
; i
+=2) {
953 if( !(nHintMask
& (1U << i
)))
955 writeType1Val( mnHintStack
[i
]);
956 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
957 const bool bHorz
= (i
< mnHorzHintSize
);
958 if( !nCntrBits
[ bHorz
])
959 writeTypeOp( bHorz
? TYPE1OP::HSTEM
: TYPE1OP::VSTEM
);
960 else if( !--nCntrBits
[ bHorz
])
961 writeTypeEsc( bHorz
? TYPE1OP::HSTEM3
: TYPE1OP::VSTEM3
);
966 case TYPE2OP::CALLSUBR
:
967 case TYPE2OP::CALLGSUBR
:
970 const bool bGlobal
= (nType2Op
== TYPE2OP::CALLGSUBR
);
971 callType2Subr( bGlobal
, nInt
);
974 case TYPE2OP::RETURN
:
975 // TODO: check that we are in a subroutine
977 case TYPE2OP::VMOVETO
:
978 case TYPE2OP::HMOVETO
:
980 writeTypeOp( TYPE1OP::CLOSEPATH
);
982 updateWidth( size() > 1);
984 pop2MultiWrite( 1, nType2Op
);
986 case TYPE2OP::VLINETO
:
987 case TYPE2OP::HLINETO
:
988 pop2MultiWrite( 1, nType2Op
,
989 TYPE1OP::VLINETO
^ TYPE1OP::HLINETO
);
991 case TYPE2OP::RMOVETO
:
992 // TODO: convert rmoveto to vlineto/hlineto if possible
994 writeTypeOp( TYPE1OP::CLOSEPATH
);
996 updateWidth( size() > 2);
998 pop2MultiWrite( 2, nType2Op
);
1000 case TYPE2OP::RLINETO
:
1001 // TODO: convert rlineto to vlineto/hlineto if possible
1002 pop2MultiWrite( 2, nType2Op
);
1004 case TYPE2OP::RCURVETO
:
1005 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
1006 pop2MultiWrite( 6, nType2Op
);
1008 case TYPE2OP::RCURVELINE
:
1010 while( (i
+= 6) <= mnStackIdx
)
1011 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
1013 while( (i
+= 2) <= mnStackIdx
) {
1014 writeType1Val( mnValStack
[i
-2]);
1015 writeType1Val( mnValStack
[i
-1]);
1016 writeTypeOp( TYPE2OP::RLINETO
);
1020 case TYPE2OP::RLINECURVE
:
1022 while( (i
+= 2) <= mnStackIdx
-6) {
1023 writeType1Val( mnValStack
[i
-2]);
1024 writeType1Val( mnValStack
[i
-1]);
1025 writeTypeOp( TYPE2OP::RLINETO
);
1028 while( (i
+= 6) <= mnStackIdx
)
1029 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
1032 case TYPE2OP::VHCURVETO
:
1033 case TYPE2OP::HVCURVETO
:
1035 bool bVert
= (nType2Op
== TYPE2OP::VHCURVETO
);
1038 if( mnStackIdx
& 1 )
1039 nInt
= static_cast<int>(mnValStack
[ --mnStackIdx
]);
1040 while( (i
+= 4) <= mnStackIdx
) {
1041 // TODO: use writeCurveTo()
1042 if( bVert
) writeType1Val( 0 );
1043 writeType1Val( mnValStack
[i
-4] );
1044 if( !bVert
) writeType1Val( 0);
1045 writeType1Val( mnValStack
[i
-3] );
1046 writeType1Val( mnValStack
[i
-2] );
1047 if( !bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
1048 writeType1Val( mnValStack
[i
-1] );
1049 if( bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
1051 writeTypeOp( TYPE2OP::RCURVETO
);
1056 case TYPE2OP::HHCURVETO
:
1057 i
= (mnStackIdx
& 1);
1058 while( (i
+= 4) <= mnStackIdx
) {
1060 writeCurveTo( i
, -4, 0, -3, -2, -1, 0);
1062 writeCurveTo( i
, -4, -5, -3, -2, -1, 0);
1066 case TYPE2OP::VVCURVETO
:
1067 i
= (mnStackIdx
& 1);
1068 while( (i
+= 4) <= mnStackIdx
) {
1070 writeCurveTo( i
, 0, -4, -3, -2, 0, -1);
1072 writeCurveTo( i
, -5, -4, -3, -2, 0, -1);
1076 case TYPE2OP::ENDCHAR
:
1078 writeTypeOp( TYPE1OP::CLOSEPATH
);
1080 updateWidth( size() >= 1);
1081 // mbNeedClose = true;
1082 writeTypeOp( TYPE1OP::ENDCHAR
);
1085 if( ((nType2Op
>= 32) && (nType2Op
<= 255)) || (nType2Op
== 28)) {
1089 popAll2Write( nType2Op
);
1090 assert( false); // TODO?
1096 // --------------------------------------------------------------------
1098 void CffSubsetterContext::convertOneTypeEsc( void)
1100 const int nType2Esc
= *(mpReadPtr
++);
1101 ValType
* pTop
= &mnValStack
[ mnStackIdx
-1];
1102 // convert each T2op
1103 switch( nType2Esc
) {
1105 assert( mnStackIdx
>= 2 );
1106 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) & static_cast<int>(pTop
[-1]));
1110 assert( mnStackIdx
>= 2 );
1111 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) | static_cast<int>(pTop
[-1]));
1115 assert( mnStackIdx
>= 1 );
1116 pTop
[0] = (pTop
[0] == 0);
1119 assert( mnStackIdx
>= 1 );
1124 assert( mnStackIdx
>= 1 );
1128 assert( mnStackIdx
>= 2 );
1129 pTop
[0] += pTop
[-1];
1133 assert( mnStackIdx
>= 2 );
1134 pTop
[0] -= pTop
[-1];
1138 assert( mnStackIdx
>= 2 );
1140 pTop
[0] *= pTop
[-1];
1144 assert( mnStackIdx
>= 2 );
1146 pTop
[0] /= pTop
[-1];
1150 assert( mnStackIdx
>= 2 );
1151 pTop
[0] = (pTop
[0] == pTop
[-1]);
1155 assert( mnStackIdx
>= 1 );
1158 case TYPE2OP::PUT
: {
1159 assert( mnStackIdx
>= 2 );
1160 const int nIdx
= static_cast<int>(pTop
[0]);
1161 assert( nIdx
>= 0 );
1162 assert( nIdx
< NMAXTRANS
);
1163 mnTransVals
[ nIdx
] = pTop
[-1];
1167 case TYPE2OP::GET
: {
1168 assert( mnStackIdx
>= 1 );
1169 const int nIdx
= static_cast<int>(pTop
[0]);
1170 assert( nIdx
>= 0 );
1171 assert( nIdx
< NMAXTRANS
);
1172 pTop
[0] = mnTransVals
[ nIdx
];
1175 case TYPE2OP::IFELSE
: {
1176 assert( mnStackIdx
>= 4 );
1177 if( pTop
[-1] > pTop
[0] )
1178 pTop
[-3] = pTop
[-2];
1182 case TYPE2OP::RANDOM
:
1183 pTop
[+1] = 1234; // TODO
1190 assert( mnStackIdx
>= 1 );
1194 case TYPE2OP::EXCH
: {
1195 assert( mnStackIdx
>= 2 );
1196 const ValType nVal
= pTop
[0];
1201 case TYPE2OP::INDEX
: {
1202 assert( mnStackIdx
>= 1 );
1203 const int nVal
= static_cast<int>(pTop
[0]);
1204 assert( nVal
>= 0 );
1205 assert( nVal
< mnStackIdx
-1 );
1206 pTop
[0] = pTop
[-1-nVal
];
1209 case TYPE2OP::ROLL
: {
1210 assert( mnStackIdx
>= 1 );
1211 const int nNum
= static_cast<int>(pTop
[0]);
1213 assert( nNum
< mnStackIdx
-2 );
1214 (void)nNum
; // TODO: implement
1215 const int nOfs
= static_cast<int>(pTop
[-1]);
1217 (void)nOfs
;// TODO: implement
1220 case TYPE2OP::HFLEX1
: {
1221 assert( mnStackIdx
== 9);
1223 writeCurveTo( mnStackIdx
, -9, -8, -7, -6, -5, 0);
1224 writeCurveTo( mnStackIdx
, -4, 0, -3, -2, -1, 0);
1225 // TODO: emulate hflex1 using othersubr call
1230 case TYPE2OP::HFLEX
: {
1231 assert( mnStackIdx
== 7);
1232 ValType
* pX
= &mnValStack
[ mnStackIdx
];
1234 pX
[+1] = -pX
[-5]; // temp: +dy5==-dy2
1235 writeCurveTo( mnStackIdx
, -7, 0, -6, -5, -4, 0);
1236 writeCurveTo( mnStackIdx
, -3, 0, -2, +1, -1, 0);
1237 // TODO: emulate hflex using othersubr call
1242 case TYPE2OP::FLEX
: {
1243 assert( mnStackIdx
== 13 );
1244 writeCurveTo( mnStackIdx
, -13, -12, -11, -10, -9, -8 );
1245 writeCurveTo( mnStackIdx
, -7, -6, -5, -4, -3, -2 );
1246 const ValType nFlexDepth
= mnValStack
[ mnStackIdx
-1 ];
1247 (void)nFlexDepth
; // ignoring nFlexDepth
1251 case TYPE2OP::FLEX1
: {
1252 assert( mnStackIdx
== 11 );
1253 // write the first part of the flex1-hinted curve
1254 writeCurveTo( mnStackIdx
, -11, -10, -9, -8, -7, -6 );
1256 // determine if nD6 is horizontal or vertical
1257 const int i
= mnStackIdx
;
1258 ValType nDeltaX
= mnValStack
[i
-11] + mnValStack
[i
-9] + mnValStack
[i
-7] + mnValStack
[i
-5] + mnValStack
[i
-3];
1259 if( nDeltaX
< 0 ) nDeltaX
= -nDeltaX
;
1260 ValType nDeltaY
= mnValStack
[i
-10] + mnValStack
[i
-8] + mnValStack
[i
-6] + mnValStack
[i
-4] + mnValStack
[i
-2];
1261 if( nDeltaY
< 0 ) nDeltaY
= -nDeltaY
;
1262 const bool bVertD6
= (nDeltaY
> nDeltaX
);
1264 // write the second part of the flex1-hinted curve
1266 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, -1, 0);
1268 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, 0, -1);
1273 fprintf( stderr
,"unhandled type2esc %d\n", nType2Esc
);
1279 // --------------------------------------------------------------------
1281 void CffSubsetterContext::callType2Subr( bool bGlobal
, int nSubrNumber
)
1283 const U8
* const pOldReadPtr
= mpReadPtr
;
1284 const U8
* const pOldReadEnd
= mpReadEnd
;
1287 nSubrNumber
+= mnGlobalSubrBias
;
1288 seekIndexData( mnGlobalSubrBase
, nSubrNumber
);
1290 nSubrNumber
+= mpCffLocal
->mnLocalSubrBias
;
1291 seekIndexData( mpCffLocal
->mnLocalSubrBase
, nSubrNumber
);
1294 while( mpReadPtr
< mpReadEnd
)
1297 mpReadPtr
= pOldReadPtr
;
1298 mpReadEnd
= pOldReadEnd
;
1301 // --------------------------------------------------------------------
1303 static const int MAX_T1OPS_SIZE
= 81920; // TODO: use dynamic value
1305 int CffSubsetterContext::convert2Type1Ops( CffLocal
* pCffLocal
, const U8
* const pT2Ops
, int nT2Len
, U8
* const pT1Ops
)
1307 mpCffLocal
= pCffLocal
;
1309 // prepare the charstring conversion
1310 mpWritePtr
= pT1Ops
;
1311 #if 1 // TODO: update caller
1312 U8 aType1Ops
[ MAX_T1OPS_SIZE
];
1314 mpWritePtr
= aType1Ops
;
1315 *const_cast<U8
**>(&pT1Ops
) = mpWritePtr
;
1320 // prepend random seed for T1crypt
1321 *(mpWritePtr
++) = 0x48;
1322 *(mpWritePtr
++) = 0x44;
1323 *(mpWritePtr
++) = 0x55;
1324 *(mpWritePtr
++) = ' ';
1325 #if 1 // convert the Type2 charstring to Type1
1327 mpReadEnd
= pT2Ops
+ nT2Len
;
1328 // prepend "hsbw" or "sbw"
1329 // TODO: only emit hsbw when charwidth is known
1330 // TODO: remove charwidth from T2 stack
1331 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
1332 writeType1Val( 1000/*###getCharWidth()###*/);
1333 writeTypeOp( TYPE1OP::HSBW
);
1335 mbNeedClose
= false;
1336 mbIgnoreHints
= false;
1337 mnHintSize
=mnHorzHintSize
=mnStackIdx
=0; maCharWidth
=-1;//#######
1339 while( mpReadPtr
< mpReadEnd
)
1342 // writeTypeOp( TYPE1OP::CLOSEPATH);
1344 // writeTypeOp( TYPE1OP::RETURN);
1346 mpWritePtr
= pT1Ops
+4;
1347 // create an "idiotproof" charstring
1349 writeType1Val( 800);
1350 writeTypeOp( TYPE1OP::HSBW
);
1352 writeTypeOp( TYPE1OP::HMOVETO
);
1353 writeType1Val( 650);
1354 writeType1Val( 100);
1355 writeTypeOp( TYPE1OP::RLINETO
);
1356 writeType1Val( -350);
1357 writeType1Val( 700);
1358 writeTypeOp( TYPE1OP::RLINETO
);
1359 writeTypeOp( TYPE1OP::CLOSEPATH
);
1360 writeTypeOp( TYPE1OP::ENDCHAR
);
1362 #else // useful for manually encoding charstrings
1363 mpWritePtr
= pT1Ops
;
1364 mpWritePtr
+= sprintf( (char*)mpWritePtr
, "OOo_\x8b\x8c\x0c\x10\x0b");
1366 const int nType1Len
= mpWritePtr
- pT1Ops
;
1368 // encrypt the Type1 charstring
1369 int nRDCryptR
= 4330; // TODO: mnRDCryptSeed;
1370 for( U8
* p
= pT1Ops
; p
< mpWritePtr
; ++p
) {
1371 *p
^= (nRDCryptR
>> 8);
1372 nRDCryptR
= (*(U8
*)p
+ nRDCryptR
) * 52845 + 22719;
1378 // --------------------------------------------------------------------
1380 RealType
CffSubsetterContext::readRealVal()
1382 // TODO: more thorough number validity test
1383 bool bComma
= false;
1387 RealType fReal
= +1.0;
1389 const U8 c
= *(mpReadPtr
++); // read nibbles
1390 // parse high nibble
1391 const U8 nH
= c
>> 4U;
1393 nNumber
= nNumber
* 10 + nH
;
1395 } else if( nH
== 10) { // comma
1398 } else if( nH
== 11) { // +exp
1402 } else if( nH
== 12) { // -exp
1406 } else if( nH
== 13) { // reserved
1407 // TODO: ignore or error?
1408 } else if( nH
== 14) // minus
1410 else if( nH
== 15) // end
1413 const U8 nL
= c
& 0x0F;
1415 nNumber
= nNumber
* 10 + nL
;
1417 } else if( nL
== 10) { // comma
1420 } else if( nL
== 11) { // +exp
1424 } else if( nL
== 12) { // -exp
1428 } else if( nL
== 13) { // reserved
1429 // TODO: ignore or error?
1430 } else if( nL
== 14) // minus
1432 else if( nL
== 15) // end
1439 if( !nExpSign
) { fReal
*= nNumber
;}
1440 else if( nExpSign
> 0) { nExpVal
+= static_cast<int>(nNumber
);}
1441 else if( nExpSign
< 0) { nExpVal
-= static_cast<int>(nNumber
);}
1444 if( !nExpVal
) { /*nothing to apply*/}
1445 else if( nExpVal
> 0) { while( --nExpVal
>= 0) fReal
*= 10.0;}
1446 else if( nExpVal
< 0) { while( ++nExpVal
<= 0) fReal
/= 10.0;}
1450 // --------------------------------------------------------------------
1452 // prepare to access an element inside a CFF/CID index table
1453 int CffSubsetterContext::seekIndexData( int nIndexBase
, int nDataIndex
)
1455 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1458 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1459 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1460 if( nDataIndex
>= nDataCount
)
1462 const int nDataOfsSz
= mpReadPtr
[2];
1463 mpReadPtr
+= 3 + (nDataOfsSz
* nDataIndex
);
1465 switch( nDataOfsSz
) {
1466 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return -1;
1467 case 1: nOfs1
= mpReadPtr
[0]; break;
1468 case 2: nOfs1
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1469 case 3: nOfs1
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1470 case 4: nOfs1
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1472 mpReadPtr
+= nDataOfsSz
;
1475 switch( nDataOfsSz
) {
1476 case 1: nOfs2
= mpReadPtr
[0]; break;
1477 case 2: nOfs2
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1478 case 3: nOfs2
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1479 case 4: nOfs2
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1482 mpReadPtr
= mpBasePtr
+ (nIndexBase
+ 2) + nDataOfsSz
* (nDataCount
+ 1) + nOfs1
;
1483 mpReadEnd
= mpReadPtr
+ (nOfs2
- nOfs1
);
1484 assert( nOfs1
>= 0);
1485 assert( nOfs2
>= nOfs1
);
1486 assert( mpReadPtr
<= mpBaseEnd
);
1487 assert( mpReadEnd
<= mpBaseEnd
);
1488 return (nOfs2
- nOfs1
);
1491 // --------------------------------------------------------------------
1493 // skip over a CFF/CID index table
1494 void CffSubsetterContext::seekIndexEnd( int nIndexBase
)
1496 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1497 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1498 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1499 const int nDataOfsSz
= mpReadPtr
[2];
1500 mpReadPtr
+= 3 + nDataOfsSz
* nDataCount
;
1501 assert( mpReadPtr
<= mpBaseEnd
);
1503 switch( nDataOfsSz
) {
1504 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return;
1505 case 1: nEndOfs
= mpReadPtr
[0]; break;
1506 case 2: nEndOfs
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1507 case 3: nEndOfs
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2];break;
1508 case 4: nEndOfs
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1510 mpReadPtr
+= nDataOfsSz
;
1511 mpReadPtr
+= nEndOfs
- 1;
1512 mpReadEnd
= mpBaseEnd
;
1513 assert( nEndOfs
>= 0);
1514 assert( mpReadEnd
<= mpBaseEnd
);
1517 // ====================================================================
1519 // initialize FONTDICT specific values
1520 CffLocal::CffLocal( void)
1521 : mnPrivDictBase( 0)
1522 , mnPrivDictSize( 0)
1523 , mnLocalSubrOffs( 0)
1524 , mnLocalSubrBase( 0)
1525 , mnLocalSubrCount( 0)
1526 , mnLocalSubrBias( 0)
1527 , maNominalWidth( 0)
1528 , maDefaultWidth( 0)
1536 , mbForceBold( false)
1538 maStemSnapH
.clear();
1539 maStemSnapV
.clear();
1540 maBlueValues
.clear();
1541 maOtherBlues
.clear();
1542 maFamilyBlues
.clear();
1543 maFamilyOtherBlues
.clear();
1546 // --------------------------------------------------------------------
1548 CffGlobal::CffGlobal( void)
1550 , mnNameIdxCount( 0)
1551 , mnStringIdxBase( 0)
1552 , mnStringIdxCount( 0)
1555 , mnCharStrCount( 0)
1556 , mnEncodingBase( 0)
1558 , mnGlobalSubrBase( 0)
1559 , mnGlobalSubrCount( 0)
1560 , mnGlobalSubrBias( 0)
1561 , mnFDSelectBase( 0)
1562 , mnFontDictBase( 0)
1566 , mnFamilyNameSID( 0)
1569 // TODO; maFontMatrix.clear();
1572 // --------------------------------------------------------------------
1574 void CffSubsetterContext::initialCffRead( void)
1576 // get the CFFHeader
1577 mpReadPtr
= mpBasePtr
;
1578 const U8 nVerMajor
= *(mpReadPtr
++);
1579 const U8 nVerMinor
= *(mpReadPtr
++);
1580 const U8 nHeaderSize
= *(mpReadPtr
++);
1581 const U8 nOffsetSize
= *(mpReadPtr
++);
1582 // TODO: is the version number useful for anything else?
1583 assert( (nVerMajor
== 1) && (nVerMinor
== 0));
1584 (void)(nVerMajor
+ nVerMinor
+ nOffsetSize
); // avoid compiler warnings
1586 // prepare access to the NameIndex
1587 mnNameIdxBase
= nHeaderSize
;
1588 mpReadPtr
= mpBasePtr
+ nHeaderSize
;
1589 mnNameIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1590 seekIndexEnd( mnNameIdxBase
);
1592 // get the TopDict index
1593 const long nTopDictBase
= getReadOfs();
1594 const int nTopDictCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1595 if( nTopDictCount
) {
1596 for( int i
= 0; i
< nTopDictCount
; ++i
) {
1597 seekIndexData( nTopDictBase
, i
);
1598 while( mpReadPtr
< mpReadEnd
)
1600 assert( mpReadPtr
== mpReadEnd
);
1604 // prepare access to the String index
1605 mnStringIdxBase
= getReadOfs();
1606 mnStringIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1607 seekIndexEnd( mnStringIdxBase
);
1609 // prepare access to the GlobalSubr index
1610 mnGlobalSubrBase
= getReadOfs();
1611 mnGlobalSubrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1612 mnGlobalSubrBias
= (mnGlobalSubrCount
<1240)?107:(mnGlobalSubrCount
<33900)?1131:32768;
1613 // skip past the last GlobalSubr entry
1614 // seekIndexEnd( mnGlobalSubrBase);
1616 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1617 // seekEncodingsEnd( mnEncodingBase);
1618 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1619 // seekCharsetsEnd( mnCharStrBase);
1620 // get/skip FDSelect (CID only) data
1622 // prepare access to the CharStrings index (we got the base from TOPDICT)
1623 mpReadPtr
= mpBasePtr
+ mnCharStrBase
;
1624 mnCharStrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1625 // seekIndexEnd( mnCharStrBase);
1627 // read the FDArray index (CID only)
1629 // assert( mnFontDictBase == tellRel());
1630 mpReadPtr
= mpBasePtr
+ mnFontDictBase
;
1631 mnFDAryCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1632 assert( mnFDAryCount
< (int)(sizeof(maCffLocal
)/sizeof(*maCffLocal
)));
1634 // read FDArray details to get access to the PRIVDICTs
1635 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1636 mpCffLocal
= &maCffLocal
[i
];
1637 seekIndexData( mnFontDictBase
, i
);
1638 while( mpReadPtr
< mpReadEnd
)
1640 assert( mpReadPtr
== mpReadEnd
);
1644 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1645 mpCffLocal
= &maCffLocal
[i
];
1647 // get the PrivateDict index
1648 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1649 if( mpCffLocal
->mnPrivDictSize
!= 0) {
1650 assert( mpCffLocal
->mnPrivDictSize
> 0);
1651 // get the PrivDict data
1652 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnPrivDictBase
;
1653 mpReadEnd
= mpReadPtr
+ mpCffLocal
->mnPrivDictSize
;
1654 assert( mpReadEnd
<= mpBaseEnd
);
1655 // read PrivDict details
1656 while( mpReadPtr
< mpReadEnd
)
1660 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1661 if( mpCffLocal
->mnLocalSubrOffs
) {
1662 // read LocalSubrs summary
1663 mpCffLocal
->mnLocalSubrBase
= mpCffLocal
->mnPrivDictBase
+ mpCffLocal
->mnLocalSubrOffs
;
1664 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnLocalSubrBase
;
1665 const int nSubrCount
= (mpReadPtr
[0] << 8) + mpReadPtr
[1];
1666 mpCffLocal
->mnLocalSubrCount
= nSubrCount
;
1667 mpCffLocal
->mnLocalSubrBias
= (nSubrCount
<1240)?107:(nSubrCount
<33900)?1131:32768;
1668 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1672 // ignore the Notices info
1675 // --------------------------------------------------------------------
1677 // get a cstring from a StringID
1678 const char* CffSubsetterContext::getString( int nStringID
)
1680 // get a standard string if possible
1681 const static int nStdStrings
= sizeof(pStringIds
)/sizeof(*pStringIds
);
1682 if( (nStringID
>= 0) && (nStringID
< nStdStrings
))
1683 return pStringIds
[ nStringID
];
1685 // else get the string from the StringIndex table
1686 const U8
* pReadPtr
= mpReadPtr
;
1687 const U8
* pReadEnd
= mpReadEnd
;
1688 nStringID
-= nStdStrings
;
1689 int nLen
= seekIndexData( mnStringIdxBase
, nStringID
);
1690 // assert( nLen >= 0);
1691 // TODO: just return the undecorated name
1692 // TODO: get rid of static char buffer
1693 static char aNameBuf
[ 2560];
1695 sprintf( aNameBuf
, "name[%d].notfound!", nStringID
);
1697 const int nMaxLen
= sizeof(aNameBuf
) - 1;
1698 if( nLen
>= nMaxLen
)
1700 for( int i
= 0; i
< nLen
; ++i
)
1701 aNameBuf
[i
] = *(mpReadPtr
++);
1702 aNameBuf
[ nLen
] = '\0';
1704 mpReadPtr
= pReadPtr
;
1705 mpReadEnd
= pReadEnd
;
1709 // --------------------------------------------------------------------
1711 // access a CID's FDSelect table
1712 int CffSubsetterContext::getFDSelect( int nGlyphIndex
) const
1714 assert( nGlyphIndex
>= 0);
1715 assert( nGlyphIndex
< mnCharStrCount
);
1719 const U8
* pReadPtr
= mpBasePtr
+ mnFDSelectBase
;
1720 const U8 nFDSelFormat
= *(pReadPtr
++);
1721 switch( nFDSelFormat
) {
1722 case 0: { // FDSELECT format 0
1723 pReadPtr
+= nGlyphIndex
;
1724 const U8 nFDIdx
= *(pReadPtr
++);
1727 case 3: { // FDSELECT format 3
1728 const U16 nRangeCount
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1729 assert( nRangeCount
> 0);
1730 assert( nRangeCount
<= mnCharStrCount
);
1731 U16 nPrev
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1732 assert( nPrev
== 0);
1735 // TODO? binary search
1736 for( int i
= 0; i
< nRangeCount
; ++i
) {
1737 const U8 nFDIdx
= pReadPtr
[0];
1738 const U16 nNext
= (pReadPtr
[1]<<8) + pReadPtr
[2];
1739 assert( nPrev
< nNext
);
1740 if( nGlyphIndex
< nNext
)
1746 default: // invalid FDselect format
1747 fprintf( stderr
, "invalid CFF.FdselType=%d\n", nFDSelFormat
);
1755 // --------------------------------------------------------------------
1757 int CffSubsetterContext::getGlyphSID( int nGlyphIndex
) const
1759 if( nGlyphIndex
== 0)
1760 return 0; // ".notdef"
1761 assert( nGlyphIndex
>= 0);
1762 assert( nGlyphIndex
< mnCharStrCount
);
1763 if( (nGlyphIndex
< 0) || (nGlyphIndex
>= mnCharStrCount
))
1766 // get the SID/CID from the Charset table
1767 const U8
* pReadPtr
= mpBasePtr
+ mnCharsetBase
;
1768 const U8 nCSetFormat
= *(pReadPtr
++);
1769 int nGlyphsToSkip
= nGlyphIndex
- 1;
1770 switch( nCSetFormat
) {
1771 case 0: // charset format 0
1772 pReadPtr
+= 2 * nGlyphsToSkip
;
1775 case 1: // charset format 1
1776 while( nGlyphsToSkip
>= 0) {
1777 const int nLeft
= pReadPtr
[2];
1778 if( nGlyphsToSkip
<= nLeft
)
1780 nGlyphsToSkip
-= nLeft
+ 1;
1784 case 2: // charset format 2
1785 while( nGlyphsToSkip
>= 0) {
1786 const int nLeft
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1787 if( nGlyphsToSkip
<= nLeft
)
1789 nGlyphsToSkip
-= nLeft
+ 1;
1794 fprintf( stderr
, "ILLEGAL CFF-Charset format %d\n", nCSetFormat
);
1798 int nSID
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1799 nSID
+= nGlyphsToSkip
;
1800 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1804 // --------------------------------------------------------------------
1806 // NOTE: the result becomes invalid with the next call to this method
1807 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex
)
1809 // the first glyph is always the .notdef glyph
1810 const char* pGlyphName
= ".notdef";
1811 if( nGlyphIndex
== 0)
1814 // prepare a result buffer
1815 // TODO: get rid of static buffer
1816 static char aDefaultGlyphName
[64];
1817 pGlyphName
= aDefaultGlyphName
;
1819 // get the glyph specific name
1820 const int nSID
= getGlyphSID( nGlyphIndex
);
1821 if( nSID
< 0) // default glyph name
1822 sprintf( aDefaultGlyphName
, "gly%03d", nGlyphIndex
);
1823 else if( mbCIDFont
) // default glyph name in CIDs
1824 sprintf( aDefaultGlyphName
, "cid%03d", nSID
);
1825 else { // glyph name from string table
1826 const char* pSidName
= getString( nSID
);
1827 // check validity of glyph name
1829 const char* p
= pSidName
;
1830 while( (*p
>= '0') && (*p
<= 'z')) ++p
;
1831 if( (p
>= pSidName
+1) && (*p
== '\0'))
1832 pGlyphName
= pSidName
;
1834 // if needed invent a fallback name
1835 if( pGlyphName
!= pSidName
)
1836 sprintf( aDefaultGlyphName
, "bad%03d", nSID
);
1842 // --------------------------------------------------------------------
1847 explicit Type1Emitter( FILE* pOutFile
, bool bPfbSubset
= true);
1848 /*virtual*/ ~Type1Emitter( void);
1849 void setSubsetName( const char* );
1851 size_t emitRawData( const char* pData
, size_t nLength
) const;
1852 void emitAllRaw( void);
1853 void emitAllHex( void);
1854 void emitAllCrypted( void);
1855 int tellPos( void) const;
1856 size_t updateLen( int nTellPos
, size_t nLength
);
1857 void emitValVector( const char* pLineHead
, const char* pLineTail
, const ValVector
&);
1860 bool mbCloseOutfile
;
1861 char maBuffer
[MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
1866 char maSubsetName
[256];
1871 // --------------------------------------------------------------------
1873 Type1Emitter::Type1Emitter( FILE* pOutFile
, bool bPfbSubset
)
1874 : mpFileOut( pOutFile
)
1875 , mbCloseOutfile( false)
1876 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1878 , mbPfbSubset( bPfbSubset
)
1881 maSubsetName
[0] = '\0';
1884 // --------------------------------------------------------------------
1886 Type1Emitter::~Type1Emitter( void)
1890 if( mbCloseOutfile
)
1895 // --------------------------------------------------------------------
1897 void Type1Emitter::setSubsetName( const char* pSubsetName
)
1899 maSubsetName
[0] = '\0';
1901 strncpy( maSubsetName
, pSubsetName
, sizeof(maSubsetName
));
1902 maSubsetName
[sizeof(maSubsetName
)-1] = '\0';
1905 // --------------------------------------------------------------------
1907 int Type1Emitter::tellPos( void) const
1909 int nTellPos
= ftell( mpFileOut
);
1913 // --------------------------------------------------------------------
1915 size_t Type1Emitter::updateLen( int nTellPos
, size_t nLength
)
1917 // update PFB segment header length
1919 cData
[0] = static_cast<U8
>(nLength
>> 0);
1920 cData
[1] = static_cast<U8
>(nLength
>> 8);
1921 cData
[2] = static_cast<U8
>(nLength
>> 16);
1922 cData
[3] = static_cast<U8
>(nLength
>> 24);
1923 const long nCurrPos
= ftell( mpFileOut
);
1924 fseek( mpFileOut
, nTellPos
, SEEK_SET
);
1925 size_t nWrote
= fwrite( cData
, 1, sizeof(cData
), mpFileOut
);
1927 fseek( mpFileOut
, nCurrPos
, SEEK_SET
);
1931 // --------------------------------------------------------------------
1933 inline size_t Type1Emitter::emitRawData(const char* pData
, size_t nLength
) const
1935 return fwrite( pData
, 1, nLength
, mpFileOut
);
1938 // --------------------------------------------------------------------
1940 inline void Type1Emitter::emitAllRaw( void)
1942 // writeout raw data
1943 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
1944 emitRawData( maBuffer
, mpPtr
- maBuffer
);
1945 // reset the raw buffer
1949 // --------------------------------------------------------------------
1951 inline void Type1Emitter::emitAllHex( void)
1953 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
1954 for( const char* p
= maBuffer
; p
< mpPtr
;) {
1955 // convert binary chunk to hex
1956 char aHexBuf
[0x4000];
1957 char* pOut
= aHexBuf
;
1958 while( (p
< mpPtr
) && (pOut
< aHexBuf
+sizeof(aHexBuf
)-4)) {
1959 // convert each byte to hex
1960 char cNibble
= (*p
>> 4) & 0x0F;
1961 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1962 *(pOut
++) = cNibble
;
1963 cNibble
= *(p
++) & 0x0F;
1964 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1965 *(pOut
++) = cNibble
;
1966 // limit the line length
1967 if( (++mnHexLineCol
& 0x3F) == 0)
1970 // writeout hex-converted chunk
1971 emitRawData( aHexBuf
, pOut
-aHexBuf
);
1973 // reset the raw buffer
1977 // --------------------------------------------------------------------
1979 void Type1Emitter::emitAllCrypted( void)
1982 for( char* p
= maBuffer
; p
< mpPtr
; ++p
) {
1983 *p
^= (mnEECryptR
>> 8);
1984 mnEECryptR
= (*(U8
*)p
+ mnEECryptR
) * 52845 + 22719;
1987 // emit the t1crypt result
1994 // --------------------------------------------------------------------
1996 // #i110387# quick-and-dirty double->ascii conversion
1997 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
1998 // also strip off trailing zeros in fraction while we are at it
1999 inline int dbl2str( char* pOut
, double fVal
, int nPrecision
=6)
2001 const int nLen
= psp::getValueOfDouble( pOut
, fVal
, nPrecision
);
2005 // --------------------------------------------------------------------
2007 void Type1Emitter::emitValVector( const char* pLineHead
, const char* pLineTail
,
2008 const ValVector
& rVector
)
2010 // ignore empty vectors
2011 if( rVector
.empty())
2014 // emit the line head
2015 mpPtr
+= sprintf( mpPtr
, "%s", pLineHead
);
2016 // emit the vector values
2017 ValVector::value_type aVal
= 0;
2018 for( ValVector::const_iterator it
= rVector
.begin();;) {
2020 if( ++it
== rVector
.end() )
2022 mpPtr
+= dbl2str( mpPtr
, aVal
);
2025 // emit the last value
2026 mpPtr
+= dbl2str( mpPtr
, aVal
);
2027 // emit the line tail
2028 mpPtr
+= sprintf( mpPtr
, "%s", pLineTail
);
2031 // --------------------------------------------------------------------
2033 bool CffSubsetterContext::emitAsType1( Type1Emitter
& rEmitter
,
2034 const long* pReqGlyphIDs
, const U8
* pReqEncoding
,
2035 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rFSInfo
)
2037 // prepare some fontdirectory details
2038 static const int nUniqueIdBase
= 4100000; // using private-interchange UniqueIds
2039 static int nUniqueId
= nUniqueIdBase
;
2042 char* pFontName
= rEmitter
.maSubsetName
;
2044 if( mnFontNameSID
) {
2045 // get the fontname directly if available
2046 strncpy( pFontName
, getString( mnFontNameSID
), sizeof(rEmitter
.maSubsetName
) - 1);
2047 pFontName
[sizeof(rEmitter
.maSubsetName
) - 1] = 0;
2048 } else if( mnFullNameSID
) {
2049 // approximate fontname as fullname-whitespace
2050 const char* pI
= getString( mnFullNameSID
);
2051 char* pO
= pFontName
;
2052 const char* pLimit
= pFontName
+ sizeof(rEmitter
.maSubsetName
) - 1;
2053 while( pO
< pLimit
) {
2054 const char c
= *(pI
++);
2062 // fallback name of last resort
2063 strncpy( pFontName
, "DummyName", sizeof(rEmitter
.maSubsetName
));
2066 const char* pFullName
= pFontName
;
2067 const char* pFamilyName
= pFontName
;
2069 char*& pOut
= rEmitter
.mpPtr
; // convenience reference, TODO: cleanup
2071 // create a PFB+Type1 header
2072 if( rEmitter
.mbPfbSubset
) {
2073 static const char aPfbHeader
[] = "\x80\x01\x00\x00\x00\x00";
2074 rEmitter
.emitRawData( aPfbHeader
, sizeof(aPfbHeader
)-1);
2077 pOut
+= sprintf( pOut
, "%%!FontType1-1.0: %s 001.003\n", rEmitter
.maSubsetName
);
2079 pOut
+= sprintf( pOut
,
2080 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
2082 "/PaintType 0 def\n");
2083 pOut
+= sprintf( pOut
, "/FontName /%s def\n", rEmitter
.maSubsetName
);
2084 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
2086 if( maFontMatrix
.size() == 6)
2087 rEmitter
.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix
);
2088 else // emit default FontMatrix if needed
2089 pOut
+= sprintf( pOut
, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
2091 if( maFontBBox
.size() == 4)
2092 rEmitter
.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox
);
2093 else // emit default FontBBox if needed
2094 pOut
+= sprintf( pOut
, "/FontBBox {0 0 999 999}readonly def\n");
2095 // emit FONTINFO into TOPDICT
2096 pOut
+= sprintf( pOut
,
2097 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
2098 " /FullName (%s) readonly def\n"
2099 " /FamilyName (%s) readonly def\n"
2100 "end readonly def\n",
2101 pFullName
, pFamilyName
);
2103 pOut
+= sprintf( pOut
,
2104 "/Encoding 256 array\n"
2105 "0 1 255 {1 index exch /.notdef put} for\n");
2106 for( int i
= 1; (i
< nGlyphCount
) && (i
< 256); ++i
) {
2107 const char* pGlyphName
= getGlyphName( pReqGlyphIDs
[i
]);
2108 pOut
+= sprintf( pOut
, "dup %d /%s put\n", pReqEncoding
[i
], pGlyphName
);
2110 pOut
+= sprintf( pOut
, "readonly def\n");
2111 pOut
+= sprintf( pOut
,
2112 // TODO: more topdict entries
2114 "currentfile eexec\n");
2117 rEmitter
.emitAllRaw();
2118 if( rEmitter
.mbPfbSubset
) {
2119 // update PFB header segment
2120 const int nPfbHeaderLen
= rEmitter
.tellPos() - 6;
2121 rEmitter
.updateLen( 2, nPfbHeaderLen
);
2123 // prepare start of eexec segment
2124 rEmitter
.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
2126 const int nEExecSegTell
= rEmitter
.tellPos();
2128 // which always starts with a privdict
2129 // count the privdict entries
2130 int nPrivEntryCount
= 9;
2131 #if !defined(IGNORE_HINTS)
2132 // emit blue hints only if non-default values
2133 nPrivEntryCount
+= !mpCffLocal
->maOtherBlues
.empty();
2134 nPrivEntryCount
+= !mpCffLocal
->maFamilyBlues
.empty();
2135 nPrivEntryCount
+= !mpCffLocal
->maFamilyOtherBlues
.empty();
2136 nPrivEntryCount
+= (mpCffLocal
->mfBlueScale
!= 0.0);
2137 nPrivEntryCount
+= (mpCffLocal
->mfBlueShift
!= 0.0);
2138 nPrivEntryCount
+= (mpCffLocal
->mfBlueFuzz
!= 0.0);
2139 // emit stem hints only if non-default values
2140 nPrivEntryCount
+= (mpCffLocal
->maStemStdHW
!= 0);
2141 nPrivEntryCount
+= (mpCffLocal
->maStemStdVW
!= 0);
2142 nPrivEntryCount
+= !mpCffLocal
->maStemSnapH
.empty();
2143 nPrivEntryCount
+= !mpCffLocal
->maStemSnapV
.empty();
2144 // emit other hints only if non-default values
2145 nPrivEntryCount
+= (mpCffLocal
->mfExpFactor
!= 0.0);
2146 nPrivEntryCount
+= (mpCffLocal
->mnLangGroup
!= 0);
2147 nPrivEntryCount
+= (mpCffLocal
->mnLangGroup
== 1);
2148 nPrivEntryCount
+= (mpCffLocal
->mbForceBold
!= false);
2149 #endif // IGNORE_HINTS
2150 // emit the privdict header
2151 pOut
+= sprintf( pOut
,
2153 "dup\n/Private %d dict dup begin\n"
2154 "/RD{string currentfile exch readstring pop}executeonly def\n"
2155 "/ND{noaccess def}executeonly def\n"
2156 "/NP{noaccess put}executeonly def\n"
2157 "/MinFeature{16 16}ND\n"
2158 "/password 5839 def\n", // TODO: mnRDCryptSeed?
2161 #if defined(IGNORE_HINTS)
2162 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // BlueValues are mandatory
2164 // emit blue hint related privdict entries
2165 if( !mpCffLocal
->maBlueValues
.empty())
2166 rEmitter
.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal
->maBlueValues
);
2168 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // default to empty BlueValues
2169 rEmitter
.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal
->maOtherBlues
);
2170 rEmitter
.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal
->maFamilyBlues
);
2171 rEmitter
.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal
->maFamilyOtherBlues
);
2173 if( mpCffLocal
->mfBlueScale
) {
2174 pOut
+= sprintf( pOut
, "/BlueScale ");
2175 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueScale
, 6);
2176 pOut
+= sprintf( pOut
, " def\n");
2178 if( mpCffLocal
->mfBlueShift
) { // default BlueShift==7
2179 pOut
+= sprintf( pOut
, "/BlueShift ");
2180 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueShift
);
2181 pOut
+= sprintf( pOut
, " def\n");
2183 if( mpCffLocal
->mfBlueFuzz
) { // default BlueFuzz==1
2184 pOut
+= sprintf( pOut
, "/BlueFuzz ");
2185 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueFuzz
);
2186 pOut
+= sprintf( pOut
, " def\n");
2189 // emit stem hint related privdict entries
2190 if( mpCffLocal
->maStemStdHW
) {
2191 pOut
+= sprintf( pOut
, "/StdHW [");
2192 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdHW
);
2193 pOut
+= sprintf( pOut
, "] def\n");
2195 if( mpCffLocal
->maStemStdVW
) {
2196 pOut
+= sprintf( pOut
, "/StdVW [");
2197 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdVW
);
2198 pOut
+= sprintf( pOut
, "] def\n");
2200 rEmitter
.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal
->maStemSnapH
);
2201 rEmitter
.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal
->maStemSnapV
);
2204 if( mpCffLocal
->mbForceBold
)
2205 pOut
+= sprintf( pOut
, "/ForceBold true def\n");
2206 if( mpCffLocal
->mnLangGroup
!= 0)
2207 pOut
+= sprintf( pOut
, "/LanguageGroup %d def\n", mpCffLocal
->mnLangGroup
);
2208 if( mpCffLocal
->mnLangGroup
== 1) // compatibility with ancient printers
2209 pOut
+= sprintf( pOut
, "/RndStemUp false def\n");
2210 if( mpCffLocal
->mfExpFactor
) {
2211 pOut
+= sprintf( pOut
, "/ExpansionFactor ");
2212 pOut
+= dbl2str( pOut
, mpCffLocal
->mfExpFactor
);
2213 pOut
+= sprintf( pOut
, " def\n");
2215 #endif // IGNORE_HINTS
2217 // emit remaining privdict entries
2218 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
2219 // TODO?: more privdict entries?
2221 static const char aOtherSubrs
[] =
2223 "% Dummy code for faking flex hints\n"
2224 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2225 "{1183615869 systemdict /internaldict get exec\n"
2226 "dup /startlock known\n"
2227 "{/startlock get exec}\n"
2228 "{dup /strtlck known\n"
2229 "{/strtlck get exec}\n"
2230 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2232 memcpy( pOut
, aOtherSubrs
, sizeof(aOtherSubrs
)-1);
2233 pOut
+= sizeof(aOtherSubrs
)-1;
2235 // emit used GlobalSubr charstrings
2236 // these are the just the default subrs
2237 // TODO: do we need them as the flex hints are resolved differently?
2238 static const char aSubrs
[] =
2240 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2241 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2242 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2243 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2244 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2246 memcpy( pOut
, aSubrs
, sizeof(aSubrs
)-1);
2247 pOut
+= sizeof(aSubrs
)-1;
2249 // TODO: emit more GlobalSubr charstrings?
2250 // TODO: emit used LocalSubr charstrings?
2252 // emit the CharStrings for the requested glyphs
2253 pOut
+= sprintf( pOut
,
2254 "2 index /CharStrings %d dict dup begin\n", nGlyphCount
);
2255 rEmitter
.emitAllCrypted();
2256 for( int i
= 0; i
< nGlyphCount
; ++i
) {
2257 const int nGlyphId
= pReqGlyphIDs
[i
];
2258 assert( (nGlyphId
>= 0) && (nGlyphId
< mnCharStrCount
));
2259 // get privdict context matching to the glyph
2260 const int nFDSelect
= getFDSelect( nGlyphId
);
2263 mpCffLocal
= &maCffLocal
[ nFDSelect
];
2264 // convert the Type2op charstring to its Type1op counterpart
2265 const int nT2Len
= seekIndexData( mnCharStrBase
, nGlyphId
);
2266 assert( nT2Len
> 0);
2267 U8 aType1Ops
[ MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
2268 const int nT1Len
= convert2Type1Ops( mpCffLocal
, mpReadPtr
, nT2Len
, aType1Ops
);
2269 // get the glyph name
2270 const char* pGlyphName
= getGlyphName( nGlyphId
);
2271 // emit the encrypted Type1op charstring
2272 pOut
+= sprintf( pOut
, "/%s %d RD ", pGlyphName
, nT1Len
);
2273 memcpy( pOut
, aType1Ops
, nT1Len
);
2275 pOut
+= sprintf( pOut
, " ND\n");
2276 rEmitter
.emitAllCrypted();
2277 // provide individual glyphwidths if requested
2278 if( pGlyphWidths
) {
2279 ValType aCharWidth
= getCharWidth();
2280 if( maFontMatrix
.size() >= 4)
2281 aCharWidth
*= 1000.0F
* maFontMatrix
[0];
2282 pGlyphWidths
[i
] = static_cast<GlyphWidth
>(aCharWidth
);
2285 pOut
+= sprintf( pOut
, "end end\nreadonly put\nput\n");
2286 pOut
+= sprintf( pOut
, "dup/FontName get exch definefont pop\n");
2287 pOut
+= sprintf( pOut
, "mark currentfile closefile\n");
2288 rEmitter
.emitAllCrypted();
2290 // mark stop of eexec encryption
2291 if( rEmitter
.mbPfbSubset
) {
2292 const int nEExecLen
= rEmitter
.tellPos() - nEExecSegTell
;
2293 rEmitter
.updateLen( nEExecSegTell
-4, nEExecLen
);
2296 // create PFB footer
2297 static const char aPfxFooter
[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2298 "0000000000000000000000000000000000000000000000000000000000000000\n"
2299 "0000000000000000000000000000000000000000000000000000000000000000\n"
2300 "0000000000000000000000000000000000000000000000000000000000000000\n"
2301 "0000000000000000000000000000000000000000000000000000000000000000\n"
2302 "0000000000000000000000000000000000000000000000000000000000000000\n"
2303 "0000000000000000000000000000000000000000000000000000000000000000\n"
2304 "0000000000000000000000000000000000000000000000000000000000000000\n"
2305 "0000000000000000000000000000000000000000000000000000000000000000\n"
2308 if( rEmitter
.mbPfbSubset
)
2309 rEmitter
.emitRawData( aPfxFooter
, sizeof(aPfxFooter
)-1);
2311 rEmitter
.emitRawData( aPfxFooter
+6, sizeof(aPfxFooter
)-9);
2313 // provide details to the subset requesters, TODO: move into own method?
2314 // note: Top and Bottom are flipped between Type1 and VCL
2315 // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
2316 ValType fXFactor
= 1.0;
2317 ValType fYFactor
= 1.0;
2318 if( maFontMatrix
.size() >= 4) {
2319 fXFactor
= 1000.0F
* maFontMatrix
[0];
2320 fYFactor
= 1000.0F
* maFontMatrix
[3];
2322 rFSInfo
.m_aFontBBox
= Rectangle( Point( static_cast<long>(maFontBBox
[0] * fXFactor
),
2323 static_cast<long>(maFontBBox
[1] * fYFactor
) ),
2324 Point( static_cast<long>(maFontBBox
[2] * fXFactor
),
2325 static_cast<long>(maFontBBox
[3] * fYFactor
) ) );
2326 // PDF-Spec says the values below mean the ink bounds!
2327 // TODO: use better approximations for these ink bounds
2328 rFSInfo
.m_nAscent
= +rFSInfo
.m_aFontBBox
.Bottom(); // for capital letters
2329 rFSInfo
.m_nDescent
= -rFSInfo
.m_aFontBBox
.Top(); // for all letters
2330 rFSInfo
.m_nCapHeight
= rFSInfo
.m_nAscent
; // for top-flat capital letters
2332 rFSInfo
.m_nFontType
= rEmitter
.mbPfbSubset
? FontSubsetInfo::TYPE1_PFB
: FontSubsetInfo::TYPE1_PFA
;
2333 rFSInfo
.m_aPSName
= String( rEmitter
.maSubsetName
, RTL_TEXTENCODING_UTF8
);
2338 // ====================================================================
2340 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth
* pOutGlyphWidths
)
2342 CffSubsetterContext
aCff( mpInFontBytes
, mnInByteLength
);
2343 aCff
.initialCffRead();
2345 // emit Type1 subset from the CFF input
2346 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2347 const bool bPfbSubset
= (0 != (mnReqFontTypeMask
& FontSubsetInfo::TYPE1_PFB
));
2348 Type1Emitter
aType1Emitter( mpOutFile
, bPfbSubset
);
2349 aType1Emitter
.setSubsetName( mpReqFontName
);
2350 bool bRC
= aCff
.emitAsType1( aType1Emitter
,
2351 mpReqGlyphIds
, mpReqEncodedIds
,
2352 pOutGlyphWidths
, mnReqGlyphCount
, *this);
2356 // ====================================================================
2358 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */