1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2009 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
35 #include <vcl/fontsubset.hxx>
37 //#define IGNORE_HINTS
39 typedef unsigned char U8
;
40 typedef unsigned short U16
;
41 typedef long long S64
;
43 typedef sal_Int32 GlyphWidth
;
45 typedef float RealType
;
46 typedef RealType ValType
;
48 typedef std::vector
<ValType
> ValVector
;
50 // ====================================================================
52 static const char* pStringIds
[] = {
53 /*0*/ ".notdef", "space", "exclam", "quotedbl",
54 "numbersign", "dollar", "percent", "ampersand",
55 "quoteright", "parenleft", "parenright", "asterisk",
56 "plus", "comma", "hyphen", "period",
57 /*16*/ "slash", "zero", "one", "two",
58 "three", "four", "five", "six",
59 "seven", "eight", "nine", "colon",
60 "semicolon", "less", "equal", "greater",
61 /*32*/ "question", "at", "A", "B",
65 /*48*/ "O", "P", "Q", "R",
68 "bracketleft", "backslash", "bracketright", "asciicircum",
69 /*64*/ "underscore", "quoteleft", "a", "b",
73 /*80*/ "o", "p", "q", "r",
76 "braceleft", "bar", "braceright", "asciitilde",
77 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
78 "yen", "florin", "section", "currency",
79 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
80 "guilsinglright", "fi", "fl", "endash",
81 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
82 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
83 "guillemotright", "ellipsis", "perthousand", "questiondown",
84 "grave", "acute", "circumflex", "tilde",
85 /*128*/ "macron", "breve", "dotaccent", "dieresis",
86 "ring", "cedilla", "hungarumlaut", "ogonek",
87 "caron", "endash", "AE", "ordfeminine",
88 "Lslash", "Oslash", "OE", "ordmasculine",
89 /*144*/ "ae", "dotlessi", "lslash", "oslash",
90 "oe", "germandbls", "onesuperior", "logicalnot",
91 "mu", "trademark", "Eth", "onehalf",
92 "plusminus", "Thorn", "onequarter", "divide",
93 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
94 "twosuperior", "registered", "minus", "eth",
95 "multiply", "threesuperior", "copyright", "Aacute",
96 "Acircumflex", "Adieresis", "Agrave", "Aring",
97 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
98 "Edieresis", "Egrave", "Iacute", "Icircumflex",
99 "Idieresis", "Igrave", "Ntilde", "Oacute",
100 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
101 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
102 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
103 "aacute", "acircumflex", "adieresis", "agrave",
104 "aring", "atilde", "ccedilla", "eacute",
105 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
106 "icircumflex", "idieresis", "igrave", "ntilde",
107 "oacute", "ocircumflex", "odieresis", "ograve",
108 "otilde", "scaron", "uacute", "ucircumflex",
109 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
110 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
111 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
112 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
113 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
114 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
115 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
116 "questionsmall", "asuperior", "bsuperior", "centsuperior",
117 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
118 "msuperior", "nsuperior", "osuperior", "rsuperior",
119 "ssuperior", "tsuperior", "ff", "ffi",
120 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
121 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
122 "Csmall", "Dsmall", "Esmall", "Fsmall",
123 "Gsmall", "Hsmall", "Ismall", "Jsmall",
124 "Ksmall", "Lsmall", "Msmall", "Nsmall",
125 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
126 "Ssmall", "Tsmall", "Usmall", "Vsmall",
127 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
128 "colonmonetary", "onefitted", "rupia", "Tildesmall",
129 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
130 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
131 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
132 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
133 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
134 "onethird", "twothirds", "zerosuperior", "foursuperior",
135 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
136 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
137 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
138 "seveninferior", "eightinferior", "nineinferior", "centinferior",
139 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
140 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
141 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
142 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
143 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
144 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
145 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
146 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
147 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
148 "001.001", "001.002", "001.003", "Black",
149 /*384*/ "Bold", "Book", "Light", "Medium",
150 "Regular", "Roman", "Semibold"
153 // --------------------------------------------------------------------
155 #if 0 // TODO: use them
156 static const char* pStdEncNames
[] = {
157 "ISOAdobe", "Expert", "ExpertSubSet"
161 // --------------------------------------------------------------------
163 // TOP DICT keywords (also covers PRIV DICT keywords)
164 static const char* pDictOps
[] = {
165 "sVersion", "sNotice", "sFullName", "sFamilyName",
166 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
167 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
168 "xESC", "nUniqueID", "aXUID", "nCharset",
169 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
170 "nDefaultWidthX", "nNominalWidthX", NULL
, NULL
,
171 NULL
, NULL
, NULL
, NULL
,
172 "shortint", "longint", "BCD", NULL
175 // --------------------------------------------------------------------
177 // TOP DICT escapes (also covers PRIV DICT escapes)
178 static const char* pDictEscs
[] = {
179 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
180 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
181 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
182 "dStemSnapH", "dStemSnapV", "bForceBold", NULL
,
183 NULL
, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
184 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
185 NULL
, NULL
, NULL
, NULL
,
186 NULL
, NULL
, "rROS", "nCIDFontVersion",
187 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
188 "nFDArray", "nFDSelect", "sFontName"
191 // --------------------------------------------------------------------
193 static const char* pType1Ops
[] = {
194 NULL
, "2hstem", NULL
, "2vstem",
195 "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
196 "Crrcurveto", "0closepath", "Lcallsubr", "0return",
197 "xT1ESC", "2hsbw", "0endchar", NULL
,
198 NULL
, NULL
, NULL
, NULL
,
199 NULL
, "2rmoveto", "1hmoveto", NULL
,
200 NULL
, NULL
, NULL
, NULL
,
201 NULL
, NULL
, "4vhcurveto", "4hvcurveto"
204 // --------------------------------------------------------------------
206 static const char* pT1EscOps
[] = {
207 "0dotsection", "6vstem3", "6hstem3", NULL
,
208 NULL
, NULL
, "5seac", "4sbw",
209 NULL
, "1abs", "2add", "2sub",
210 "2div", NULL
, NULL
, NULL
,
211 "Gcallothersubr", "1pop", NULL
, NULL
,
212 NULL
, NULL
, NULL
, NULL
,
213 NULL
, NULL
, NULL
, NULL
,
214 NULL
, NULL
, NULL
, NULL
,
215 NULL
, "2setcurrentpoint"
218 // --------------------------------------------------------------------
224 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
225 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CLOSEPATH
=9,
226 CALLSUBR
=10, RETURN
=11, T1ESC
=12, HSBW
=13,
227 ENDCHAR
=14, RMOVETO
=21, HMOVETO
=22, VHCURVETO
=30,
233 DOTSECTION
=0, VSTEM3
=1, HSTEM3
=2, SEAC
=6,
234 SBW
=7, ABS
=9, ADD
=10, SUB
=11,
235 DIV
=12, CALLOTHERSUBR
=16, POP
=17, SETCURRENTPOINT
=33
239 // --------------------------------------------------------------------
241 static const char* pType2Ops
[] = {
242 NULL
, "hhstem", NULL
, "vvstem",
243 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
244 "Crrcurveto", NULL
, "Lcallsubr", "Xreturn",
245 "xT2ESC", NULL
, "eendchar", NULL
,
246 NULL
, NULL
, "Hhstemhm", "Khintmask",
247 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
248 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
249 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
252 // --------------------------------------------------------------------
254 static const char* pT2EscOps
[] = {
255 NULL
, NULL
, NULL
, "2and",
256 "2or", "1not", NULL
, NULL
,
257 NULL
, "1abs", "2add", "2sub",
258 "2div", NULL
, "1neg", "2eq",
259 NULL
, NULL
, "1drop", NULL
,
260 "1put", "1get", "4ifelse", "0random",
261 "2mul", NULL
, "1sqrt", "1dup",
262 "2exch", "Iindex", "Rroll", NULL
,
263 NULL
, NULL
, "7hflex", "Fflex",
267 // --------------------------------------------------------------------
273 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
274 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CALLSUBR
=10,
275 RETURN
=11, T2ESC
=12, ENDCHAR
=14, HSTEMHM
=18,
276 HINTMASK
=19, CNTRMASK
=20, RMOVETO
=21, HMOVETO
=22,
277 VSTEMHM
=23, RCURVELINE
=24, RLINECURVE
=25, VVCURVETO
=26,
278 HHCURVETO
=27, SHORTINT
=28, CALLGSUBR
=29, VHCURVETO
=30,
284 AND
=3, OR
=4, NOT
=5, ABS
=9,
285 ADD
=10, SUB
=11, DIV
=12, NEG
=14,
286 EQ
=15, DROP
=18, PUT
=20, GET
=21,
287 IFELSE
=22, RANDOM
=23, MUL
=24, SQRT
=26,
288 DUP
=27, EXCH
=28, INDEX
=29, ROLL
=30,
289 HFLEX
=34, FLEX
=35, HFLEX1
=36, FLEX1
=37
293 // ====================================================================
297 explicit CffGlobal();
302 int mnStringIdxCount
;
308 int mnGlobalSubrBase
;
309 int mnGlobalSubrCount
;
310 int mnGlobalSubrBias
;
315 ValVector maFontBBox
;
316 ValVector maFontMatrix
;
323 // ====================================================================
333 int mnLocalSubrCount
;
338 // ATM hinting related values
341 ValVector maStemSnapH
;
342 ValVector maStemSnapV
;
343 ValVector maBlueValues
;
344 ValVector maOtherBlues
;
345 ValVector maFamilyBlues
;
346 ValVector maFamilyOtherBlues
;
347 RealType mfBlueScale
;
348 RealType mfBlueShift
;
350 RealType mfExpFactor
;
355 // ====================================================================
357 class SubsetterContext
360 virtual ~SubsetterContext( void);
361 virtual bool emitAsType1( class Type1Emitter
&,
362 const long* pGlyphIDs
, const U8
* pEncoding
,
363 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& ) = 0;
366 // --------------------------------------------------------------------
368 SubsetterContext::~SubsetterContext( void)
371 // ====================================================================
373 class CffSubsetterContext
374 : public SubsetterContext
378 static const int NMAXSTACK
= 48; // see CFF.appendixB
379 static const int NMAXHINTS
= 2*96; // see CFF.appendixB
380 static const int NMAXTRANS
= 32; // see CFF.appendixB
382 explicit CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
);
383 virtual ~CffSubsetterContext( void);
385 void initialCffRead( void);
386 bool emitAsType1( class Type1Emitter
&,
387 const long* pGlyphIDs
, const U8
* pEncoding
,
388 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& );
390 // used by charstring converter
391 void setCharStringType( int);
392 void fakeLocalSubrCount( int nLocalSubrs
) { maCffLocal
[0].mnLocalSubrCount
=nLocalSubrs
;}
393 void readCharString( const U8
* pTypeOps
, int nTypeLen
);
395 int convert2Type1Ops( CffLocal
*, const U8
* pType2Ops
, int nType2Len
, U8
* pType1Ops
);
397 void readTypeOp( CffSubsetterContext
&);
398 void convertOneTypeOp( void);
399 void convertOneTypeEsc( void);
400 void callType2Subr( bool bGlobal
, int nSubrNumber
);
401 long getReadOfs( void) const { return (long)(mpReadPtr
- mpBasePtr
);}
416 int seekIndexData( int nIndexBase
, int nDataIndex
);
417 void seekIndexEnd( int nIndexBase
);
420 const char** mpCharStringOps
;
421 const char** mpCharStringEscs
;
423 CffLocal maCffLocal
[16];
424 CffLocal
* mpCffLocal
;
426 void readDictOp( void);
427 RealType
readRealVal( void);
428 const char* getString( int nStringID
);
429 int getFDSelect( int nGlyphIndex
) const;
430 int getGlyphSID( int nGlyphIndex
) const;
431 const char* getGlyphName( int nGlyphIndex
);
433 void readTypeOp( void);
434 void read2push( void);
435 void pop2write( void);
436 void writeType1Val( ValType
);
437 void writeTypeOp( int nTypeOp
);
438 void writeTypeEsc( int nTypeOp
);
439 void writeCurveTo( int nStackPos
, int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
);
440 void pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
=0);
441 void popAll2Write( int nTypeOp
);
443 public: // TODO: is public really needed?
444 // accessing the value stack
445 // TODO: add more checks
446 void push( ValType nVal
) { mnValStack
[ mnStackIdx
++] = nVal
;}
447 ValType
popVal( void) { return ((mnStackIdx
>0) ? mnValStack
[ --mnStackIdx
] : 0);}
448 ValType
peekVal( void) const { return ((mnStackIdx
>0) ? mnValStack
[ mnStackIdx
-1] : 0);}
449 ValType
getVal( int nIndex
) const { return mnValStack
[ nIndex
];}
451 int peekInt( void) const;
452 int getInt( int nIndex
) const;
453 int size( void) const { return mnStackIdx
;}
454 bool empty( void) const { return !mnStackIdx
;}
455 void clear( void) { mnStackIdx
= 0;}
457 // accessing the charstring hints
458 void addHints( bool bVerticalHints
);
459 int getHorzHintCount( void) const { return (mnHorzHintSize
/2);}
460 int getVertHintCount( void) const { return (mnHintSize
-mnHorzHintSize
)/2;}
461 void getHintPair( int nIndex
, ValType
* nMin
, ValType
* nEnd
) const;
463 // accessing other charstring specifics
464 bool hasCharWidth( void) const { return (mnCharWidth
!= -1);}
465 int getCharWidth( void) const { return mnCharWidth
;}
466 void setNominalWidth( int nWidth
) { mpCffLocal
->mnNominalWidth
= nWidth
;}
467 void setDefaultWidth( int nWidth
) { mpCffLocal
->mnDefaultWidth
= nWidth
;}
468 void updateWidth( bool bUseFirstVal
);
471 // typeop exceution context
473 ValType mnValStack
[ NMAXSTACK
];
474 ValType mnTransVals
[ NMAXTRANS
];
478 ValType mnHintStack
[ NMAXHINTS
];
483 // --------------------------------------------------------------------
485 CffSubsetterContext::CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
)
486 : mpBasePtr( pBasePtr
)
487 , mpBaseEnd( pBasePtr
+nBaseLen
)
493 // setCharStringType( 1);
494 // TODO: new CffLocal[ mnFDAryCount];
495 mpCffLocal
= &maCffLocal
[0];
498 // --------------------------------------------------------------------
500 CffSubsetterContext::~CffSubsetterContext( void)
502 // TODO: delete[] maCffLocal;
505 // --------------------------------------------------------------------
507 inline int CffSubsetterContext::popInt( void)
509 const ValType aVal
= popVal();
510 const int nInt
= static_cast<int>(aVal
);
511 assert( nInt
== aVal
);
515 // --------------------------------------------------------------------
517 inline int CffSubsetterContext::peekInt( void) const
519 const ValType aVal
= peekVal();
520 const int nInt
= static_cast<int>(aVal
);
521 assert( nInt
== aVal
);
525 // --------------------------------------------------------------------
527 inline int CffSubsetterContext::getInt( int nIndex
) const
529 const ValType aVal
= getVal( nIndex
);
530 const int nInt
= static_cast<int>(aVal
);
531 assert( nInt
== aVal
);
535 // --------------------------------------------------------------------
537 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal
)
539 #if 1 // TODO: is this still needed?
540 // the first value is not a hint but the charwidth
545 mnCharWidth
= static_cast<int>(mpCffLocal
->mnNominalWidth
+ mnValStack
[0]);
546 // remove bottom stack entry
548 for( int i
= 0; i
< mnStackIdx
; ++i
)
549 mnValStack
[ i
] = mnValStack
[ i
+1];
551 mnCharWidth
= mpCffLocal
->mnDefaultWidth
;
555 // --------------------------------------------------------------------
557 void CffSubsetterContext::addHints( bool bVerticalHints
)
559 // the first charstring value may a charwidth instead of a charwidth
560 updateWidth( (mnStackIdx
& 1) != 0);
561 // return early (e.g. no implicit hints for hintmask)
565 // copy the remaining values to the hint arrays
566 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
567 if( mnStackIdx
& 1) --mnStackIdx
;//#######
568 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
570 assert( (mnHintSize
+ mnStackIdx
) <= 2*NMAXHINTS
);
573 mnHintSize
+= mnStackIdx
;
575 ValType nHintOfs
= 0;
576 for( int i
= 0; i
< mnStackIdx
; ++i
) {
577 nHintOfs
+= mnValStack
[ i
];
578 mnHintStack
[ mnHintSize
++] = nHintOfs
;
580 #endif // IGNORE_HINTS
582 mnHorzHintSize
= mnHintSize
;
584 // clear all values from the stack
588 // --------------------------------------------------------------------
590 void CffSubsetterContext::getHintPair( int nIndex
, ValType
* pMin
, ValType
* pEnd
) const
593 assert( nIndex
< mnHintSize
);
594 assert( nIndex
>= 0);
595 const ValType
* pHint
= &mnHintStack
[ nIndex
];
600 // --------------------------------------------------------------------
602 void CffSubsetterContext::setCharStringType( int nVal
)
605 case 1: mpCharStringOps
=pType1Ops
; mpCharStringEscs
=pT1EscOps
; break;
606 case 2: mpCharStringOps
=pType2Ops
; mpCharStringEscs
=pT2EscOps
; break;
607 default: fprintf( stderr
, "Unknown CharstringType=%d\n",nVal
); break;
611 // --------------------------------------------------------------------
613 void CffSubsetterContext::readCharString( const U8
* pTypeOps
, int nTypeLen
)
620 assert( nTypeLen
>= 0);
621 // assert( nEnd <= getLength());
622 mpReadPtr
= pTypeOps
;
623 mpReadEnd
= mpReadPtr
+ nTypeLen
;
624 // reset the execution context
625 while( mpReadPtr
< mpReadEnd
)
627 //### assert( tellRel() == nEnd);
630 // --------------------------------------------------------------------
632 void CffSubsetterContext::readDictOp( void)
636 const U8 c
= *mpReadPtr
;
638 int nOpId
= *(mpReadPtr
++);
639 const char* pCmdName
;
641 pCmdName
= pDictOps
[ nOpId
];
643 const U8 nExtId
= *(mpReadPtr
++);
644 pCmdName
= pDictEscs
[ nExtId
];
645 nOpId
= 900 + nExtId
;
648 //TODO: if( nStackIdx > 0)
650 default: fprintf( stderr
, "unsupported DictOp.type=\'%c\'\n", *pCmdName
); break;
654 case 915: mpCffLocal
->mbForceBold
= nInt
; break; // "ForceBold"
655 default: break; // TODO: handle more boolean dictops?
658 case 'n': // dict-op number
660 nInt
= static_cast<int>(nVal
);
662 case 10: mpCffLocal
->mnStemStdHW
= nInt
; break; // "StdHW"
663 case 11: mpCffLocal
->mnStemStdVW
= nInt
; break; // "StdVW"
664 case 15: mnCharsetBase
= nInt
; break; // "charset"
665 case 16: mnEncodingBase
= nInt
; break; // "nEncoding"
666 case 17: mnCharStrBase
= nInt
; break; // "nCharStrings"
667 case 19: mpCffLocal
->mnLocalSubrOffs
= nInt
; break;// "nSubrs"
668 case 20: setDefaultWidth( nInt
); break; // "defaultWidthX"
669 case 21: setNominalWidth( nInt
); break; // "nominalWidthX"
670 case 909: mpCffLocal
->mfBlueScale
= nVal
; break; // "BlueScale"
671 case 910: mpCffLocal
->mfBlueShift
= nVal
; break; // "BlueShift"
672 case 911: mpCffLocal
->mfBlueFuzz
= nVal
; break; // "BlueFuzz"
673 case 912: mpCffLocal
->mfExpFactor
= nVal
; break; // "ExpansionFactor"
674 case 917: mpCffLocal
->mnLangGroup
= nInt
; break; // "LanguageGroup"
675 case 936: mnFontDictBase
= nInt
; break; // "nFDArray"
676 case 937: mnFDSelectBase
= nInt
; break; // "nFDSelect"
677 default: break; // TODO: handle more numeric dictops?
682 case 5: maFontBBox
.clear(); break; // "FontBBox"
683 case 907: maFontMatrix
.clear(); break; // "FontMatrix"
684 default: break; // TODO: reset other arrays?
686 for( int i
= 0; i
< size(); ++i
) {
689 case 5: maFontBBox
.push_back( nVal
); break; // "FontBBox"
690 case 907: maFontMatrix
.push_back( nVal
); break; // "FontMatrix"
691 default: break; // TODO: handle more array dictops?
696 case 'd': { // delta array
698 for( int i
= 0; i
< size(); ++i
) {
701 case 6: mpCffLocal
->maBlueValues
.push_back( nVal
); break; // "BlueValues"
702 case 7: mpCffLocal
->maOtherBlues
.push_back( nVal
); break; // "OtherBlues"
703 case 8: mpCffLocal
->maFamilyBlues
.push_back( nVal
); break; // "FamilyBlues"
704 case 9: mpCffLocal
->maFamilyOtherBlues
.push_back( nVal
); break;// "FamilyOtherBlues"
705 case 912: mpCffLocal
->maStemSnapH
.push_back( nVal
); break; // "StemSnapH"
706 case 913: mpCffLocal
->maStemSnapV
.push_back( nVal
); break; // "StemSnapV"
707 default: break; // TODO: handle more delta-array dictops?
712 case 's': // stringid (SID)
715 case 2: mnFullNameSID
= nInt
; break; // "FullName"
716 case 3: mnFamilyNameSID
= nInt
; break; // "FamilyName"
717 case 938: mnFontNameSID
= nInt
; break; // "FontName"
718 default: break; // TODO: handle more string dictops?
721 case 'P': // private dict
722 mpCffLocal
->mnPrivDictBase
= popInt();
723 mpCffLocal
->mnPrivDictSize
= popInt();
725 case 'r': { // ROS operands
726 int nSid1
= popInt();
727 int nSid2
= popInt();
728 (void)nSid1
; // TODO: use
729 (void)nSid2
; // TODO: use
733 case 't': // CharstringType
735 setCharStringType( nInt
);
742 if( (c
>= 32) || (c
== 28) ) {
745 } else if( c
== 29 ) { // longint
746 ++mpReadPtr
; // skip 29
747 int nS32
= mpReadPtr
[0] << 24;
748 nS32
+= mpReadPtr
[1] << 16;
749 nS32
+= mpReadPtr
[2] << 8;
750 nS32
+= mpReadPtr
[3] << 0;
751 if( (sizeof(nS32
) != 4) && (nS32
& (1<<31)))
752 nS32
|= (~0U) << 31; // assuming 2s complement
754 nVal
= static_cast<ValType
>(nS32
);
756 } else if( c
== 30) { // real number
757 ++mpReadPtr
; // skip 30
758 const RealType fReal
= readRealVal();
759 // push value onto stack
765 // --------------------------------------------------------------------
767 void CffSubsetterContext::readTypeOp( void)
770 const U8 c
= *mpReadPtr
;
771 if( (c
<= 31) && (c
!= 28) ) {
772 const int nOpId
= *(mpReadPtr
++);
773 const char* pCmdName
;
775 pCmdName
= mpCharStringOps
[ nOpId
];
777 const int nExtId
= *(mpReadPtr
++);
778 pCmdName
= mpCharStringEscs
[ nExtId
];
783 // handle typeop parameters
784 int nMinStack
= -1, nMaxStack
= -1;
786 default: fprintf( stderr
, "unsupported TypeOp.type=\'%c\'\n", *pCmdName
); break;
787 case '.': nMinStack
= 0; nMaxStack
= 999; break;
788 case '0': nMinStack
= nMaxStack
= 0; break;
789 case '1': nMinStack
= nMaxStack
= 1; break;
790 case '2': nMinStack
= nMaxStack
= 2; break;
791 case '4': nMinStack
= nMaxStack
= 4; break;
792 case '5': nMinStack
= nMaxStack
= 5; break; // not used for Type2 ops
793 case '6': nMinStack
= nMaxStack
= 6; break;
794 case '7': nMinStack
= nMaxStack
= 7; break;
795 case '9': nMinStack
= nMaxStack
= 9; break;
796 case 'f': nMinStack
= nMaxStack
= 11; break;
797 case 'F': nMinStack
= nMaxStack
= 13; break;
798 case 'A': nMinStack
= 2; nMaxStack
= 999; break;
799 case 'C': nMinStack
= 6; nMaxStack
= 999; break;
800 case 'E': nMinStack
= 1; nMaxStack
= 999; break;
801 case 'G': nMinStack
= 1; nMaxStack
= 999; // global subr
805 case 'L': // local subr
806 nMinStack
= 1; nMaxStack
= 999;
810 case 'I': // operands for "index"
812 nMinStack
= nValStack
[ nStackIdx
-1];
813 if( nMinStack
< 0) nMinStack
= 0;
816 fprintf( stderr
, "TODO: Iindex op\n");
819 case 'R': // operands for "rol"
821 nMinStack
= nValStack
[ nStackIdx
-2];
823 fprintf( stderr
, "TODO: Rrol op\n");
825 case 'X': // operands for "return"
827 nMaxStack
= /*### (!bInSubrs)? 0 :###*/999;
829 case 'H': // "hstemhm"
832 nMinStack
= nMaxStack
= 0;
834 case 'V': // "vstemhm"
837 nMinStack
= nMaxStack
= 0;
839 case 'K': // "hintmask" or "cntrmask"
840 addHints( true); // implicit vstemhm
841 nMinStack
= nMaxStack
= 0;
844 updateWidth( (size() >= 1) && (size() != 4));
845 nMinStack
= nMaxStack
= 0;
847 fprintf( stderr
,"Deprecated SEAC-like endchar is not supported for CFF subsetting!\n"); // TODO: handle deprecated op
849 case 'm': // hmoveto or vmoveto
850 updateWidth( size() > 1);
852 nMaxStack
= nMinStack
;
855 updateWidth( size() > 2);
857 nMaxStack
= nMinStack
;
865 if( (c
>= 32) || (c
== 28)) {
871 // --------------------------------------------------------------------
873 void CffSubsetterContext::read2push()
877 const U8
*& p
= mpReadPtr
;
880 short nS16
= (p
[1] << 8) + p
[2];
881 if( (sizeof(nS16
) != 2) && (nS16
& (1<<15)))
882 nS16
|= (~0U) << 15; // assuming 2s complement
885 } else if( c
<= 246 ) { // -107..+107
886 aVal
= static_cast<ValType
>(p
[0] - 139);
888 } else if( c
<= 250 ) { // +108..+1131
889 aVal
= static_cast<ValType
>(((p
[0] << 8) + p
[1]) - 63124);
891 } else if( c
<= 254 ) { // -108..-1131
892 aVal
= static_cast<ValType
>(64148 - ((p
[0] << 8) + p
[1]));
894 } else /*if( c == 255)*/ { // Fixed16.16
895 int nS32
= (p
[1] << 24) + (p
[2] << 16) + (p
[3] << 8) + p
[4];
896 if( (sizeof(nS32
) != 2) && (nS32
& (1<<31)))
897 nS32
|= (~0U) << 31; // assuming 2s complement
898 aVal
= static_cast<ValType
>(nS32
* (1.0 / 0x10000));
905 // --------------------------------------------------------------------
907 void CffSubsetterContext::writeType1Val( ValType aVal
)
909 U8
* pOut
= mpWritePtr
;
911 int nInt
= static_cast<int>(aVal
);
912 static const int nOutCharstrType
= 1;
913 if( (nInt
!= aVal
) && (nOutCharstrType
== 2)) {
914 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
915 *(pOut
++) = 255; // Fixed 16.16
916 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
917 *(pOut
++) = static_cast<U8
>(nInt
);
918 nInt
= static_cast<int>(aVal
* 0x10000) & 0xFFFF;
919 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
920 *(pOut
++) = static_cast<U8
>(nInt
);
921 } else if( (nInt
>= -107) && (nInt
<= +107)) {
922 *(pOut
++) = static_cast<U8
>(nInt
+ 139); // -107..+107
923 } else if( (nInt
>= -1131) && (nInt
<= +1131)) {
925 nInt
+= 63124; // +108..+1131
927 nInt
= 64148 - nInt
; // -108..-1131
928 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
929 *(pOut
++) = static_cast<U8
>(nInt
);
930 } else if( nOutCharstrType
== 1) {
931 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
933 *(pOut
++) = static_cast<U8
>(nInt
>> 24);
934 *(pOut
++) = static_cast<U8
>(nInt
>> 16);
935 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
936 *(pOut
++) = static_cast<U8
>(nInt
);
942 // --------------------------------------------------------------------
944 inline void CffSubsetterContext::pop2write( void)
946 const ValType aVal
= popVal();
947 writeType1Val( aVal
);
950 // --------------------------------------------------------------------
952 inline void CffSubsetterContext::writeTypeOp( int nTypeOp
)
954 *(mpWritePtr
++) = static_cast<U8
>(nTypeOp
);
957 // --------------------------------------------------------------------
959 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc
)
961 *(mpWritePtr
++) = TYPE1OP::T1ESC
;
962 *(mpWritePtr
++) = static_cast<U8
>(nTypeEsc
);
965 // --------------------------------------------------------------------
967 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
)
969 for( int i
= 0; i
< mnStackIdx
;) {
970 for( int j
= 0; j
< nArgsPerTypo
; ++j
) {
971 const ValType aVal
= mnValStack
[i
+j
];
972 writeType1Val( aVal
);
975 writeTypeOp( nTypeOp
);
976 nTypeOp
^= nTypeXor
; // for toggling vlineto/hlineto
981 // --------------------------------------------------------------------
983 void CffSubsetterContext::popAll2Write( int nTypeOp
)
985 // pop in reverse order, then write
986 for( int i
= 0; i
< mnStackIdx
; ++i
) {
987 const ValType aVal
= mnValStack
[i
];
988 writeType1Val( aVal
);
991 writeTypeOp( nTypeOp
);
994 // --------------------------------------------------------------------
996 void CffSubsetterContext::writeCurveTo( int nStackPos
,
997 int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
)
999 // get the values from the stack
1000 const ValType nDX1
= nIX1
? mnValStack
[ nStackPos
+nIX1
] : 0;
1001 const ValType nDY1
= nIY1
? mnValStack
[ nStackPos
+nIY1
] : 0;
1002 const ValType nDX2
= nIX2
? mnValStack
[ nStackPos
+nIX2
] : 0;
1003 const ValType nDY2
= nIY2
? mnValStack
[ nStackPos
+nIY2
] : 0;
1004 const ValType nDX3
= nIX3
? mnValStack
[ nStackPos
+nIX3
] : 0;
1005 const ValType nDY3
= nIY3
? mnValStack
[ nStackPos
+nIY3
] : 0;
1007 // emit the curveto operator and operands
1008 // TODO: determine the most efficient curveto operator
1009 // TODO: depending on type1op or type2op target
1010 writeType1Val( nDX1
);
1011 writeType1Val( nDY1
);
1012 writeType1Val( nDX2
);
1013 writeType1Val( nDY2
);
1014 writeType1Val( nDX3
);
1015 writeType1Val( nDY3
);
1016 writeTypeOp( TYPE1OP::RCURVETO
);
1019 // --------------------------------------------------------------------
1021 void CffSubsetterContext::convertOneTypeOp( void)
1023 const int nType2Op
= *(mpReadPtr
++);
1025 int i
, nInt
; // prevent WAE for declarations inside switch cases
1026 // convert each T2op
1028 case TYPE2OP::T2ESC
:
1029 convertOneTypeEsc();
1031 case TYPE2OP::HSTEM
:
1032 case TYPE2OP::VSTEM
:
1033 addHints( nType2Op
== TYPE2OP::VSTEM
);
1034 #ifndef IGNORE_HINTS
1035 for( i
= 0; i
< mnHintSize
; i
+=2 ) {
1036 writeType1Val( mnHintStack
[i
]);
1037 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
1038 writeTypeOp( nType2Op
);
1040 #endif // IGNORE_HINTS
1042 case TYPE2OP::HSTEMHM
:
1043 case TYPE2OP::VSTEMHM
:
1044 addHints( nType2Op
== TYPE2OP::VSTEMHM
);
1046 case TYPE2OP::CNTRMASK
:
1047 // TODO: replace cntrmask with vstem3/hstem3
1050 mpReadPtr
+= (mnHintSize
+ 15) / 16;
1051 mbIgnoreHints
= true;
1056 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
1058 nMaskByte
= *(mpReadPtr
++);
1061 if( !(nMaskByte
& nMaskBit
))
1063 if( i
>= 8*(int)sizeof(mnCntrMask
))
1064 mbIgnoreHints
= true;
1067 mnCntrMask
|= (1U << i
);
1072 case TYPE2OP::HINTMASK
:
1075 mpReadPtr
+= (mnHintSize
+ 15) / 16;
1079 int nCntrBits
[2] = {0,0};
1082 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
1084 nMaskByte
= *(mpReadPtr
++);
1087 if( !(nMaskByte
& nMaskBit
))
1089 if( i
>= 8*(int)sizeof(nHintMask
))
1090 mbIgnoreHints
= true;
1093 nHintMask
|= (1U << i
);
1094 nCntrBits
[ i
< mnHorzHintSize
] += (mnCntrMask
>> i
) & 1;
1097 mbIgnoreHints
|= (nCntrBits
[0] && (nCntrBits
[0] != 3));
1098 mbIgnoreHints
|= (nCntrBits
[1] && (nCntrBits
[1] != 3));
1102 for( i
= 0; i
< mnHintSize
; i
+=2) {
1103 if( !(nHintMask
& (1U << i
)))
1105 writeType1Val( mnHintStack
[i
]);
1106 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
1107 const bool bHorz
= (i
< mnHorzHintSize
);
1108 if( !nCntrBits
[ bHorz
])
1109 writeTypeOp( bHorz
? TYPE1OP::HSTEM
: TYPE1OP::VSTEM
);
1110 else if( !--nCntrBits
[ bHorz
])
1111 writeTypeEsc( bHorz
? TYPE1OP::HSTEM3
: TYPE1OP::VSTEM3
);
1116 case TYPE2OP::CALLSUBR
:
1117 case TYPE2OP::CALLGSUBR
:
1120 const bool bGlobal
= (nType2Op
== TYPE2OP::CALLGSUBR
);
1121 callType2Subr( bGlobal
, nInt
);
1124 case TYPE2OP::RETURN
:
1125 // TODO: check that we are in a subroutine
1127 case TYPE2OP::VMOVETO
:
1128 case TYPE2OP::HMOVETO
:
1130 writeTypeOp( TYPE1OP::CLOSEPATH
);
1132 updateWidth( size() > 1);
1134 pop2MultiWrite( 1, nType2Op
);
1136 case TYPE2OP::VLINETO
:
1137 case TYPE2OP::HLINETO
:
1138 pop2MultiWrite( 1, nType2Op
,
1139 TYPE1OP::VLINETO
^ TYPE1OP::HLINETO
);
1141 case TYPE2OP::RMOVETO
:
1142 // TODO: convert rmoveto to vlineto/hlineto if possible
1144 writeTypeOp( TYPE1OP::CLOSEPATH
);
1146 updateWidth( size() > 2);
1148 pop2MultiWrite( 2, nType2Op
);
1150 case TYPE2OP::RLINETO
:
1151 // TODO: convert rlineto to vlineto/hlineto if possible
1152 pop2MultiWrite( 2, nType2Op
);
1154 case TYPE2OP::RCURVETO
:
1155 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
1156 pop2MultiWrite( 6, nType2Op
);
1158 case TYPE2OP::RCURVELINE
:
1160 while( (i
+= 6) <= mnStackIdx
)
1161 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
1163 while( (i
+= 2) <= mnStackIdx
) {
1164 writeType1Val( mnValStack
[i
-2]);
1165 writeType1Val( mnValStack
[i
-1]);
1166 writeTypeOp( TYPE2OP::RLINETO
);
1170 case TYPE2OP::RLINECURVE
:
1172 while( (i
+= 2) <= mnStackIdx
-6) {
1173 writeType1Val( mnValStack
[i
-2]);
1174 writeType1Val( mnValStack
[i
-1]);
1175 writeTypeOp( TYPE2OP::RLINETO
);
1178 while( (i
+= 6) <= mnStackIdx
)
1179 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
1182 case TYPE2OP::VHCURVETO
:
1183 case TYPE2OP::HVCURVETO
:
1185 bool bVert
= (nType2Op
== TYPE2OP::VHCURVETO
);
1188 if( mnStackIdx
& 1 )
1189 nInt
= static_cast<int>(mnValStack
[ --mnStackIdx
]);
1190 while( (i
+= 4) <= mnStackIdx
) {
1191 // TODO: use writeCurveTo()
1192 if( bVert
) writeType1Val( 0 );
1193 writeType1Val( mnValStack
[i
-4] );
1194 if( !bVert
) writeType1Val( 0);
1195 writeType1Val( mnValStack
[i
-3] );
1196 writeType1Val( mnValStack
[i
-2] );
1197 if( !bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
1198 writeType1Val( mnValStack
[i
-1] );
1199 if( bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
1201 writeTypeOp( TYPE2OP::RCURVETO
);
1206 case TYPE2OP::HHCURVETO
:
1207 i
= (mnStackIdx
& 1);
1208 while( (i
+= 4) <= mnStackIdx
) {
1210 writeCurveTo( i
, -4, 0, -3, -2, -1, 0);
1212 writeCurveTo( i
, -4, -5, -3, -2, -1, 0);
1216 case TYPE2OP::VVCURVETO
:
1217 i
= (mnStackIdx
& 1);
1218 while( (i
+= 4) <= mnStackIdx
) {
1220 writeCurveTo( i
, 0, -4, -3, -2, 0, -1);
1222 writeCurveTo( i
, -5, -4, -3, -2, 0, -1);
1226 case TYPE2OP::ENDCHAR
:
1228 writeTypeOp( TYPE1OP::CLOSEPATH
);
1230 updateWidth( size() >= 1);
1231 // mbNeedClose = true;
1232 writeTypeOp( TYPE1OP::ENDCHAR
);
1235 if( ((nType2Op
>= 32) && (nType2Op
<= 255)) || (nType2Op
== 28)) {
1239 popAll2Write( nType2Op
);
1240 assert( false); // TODO?
1246 // --------------------------------------------------------------------
1248 void CffSubsetterContext::convertOneTypeEsc( void)
1250 const int nType2Esc
= *(mpReadPtr
++);
1251 ValType
* pTop
= &mnValStack
[ mnStackIdx
-1];
1252 // convert each T2op
1253 switch( nType2Esc
) {
1255 assert( mnStackIdx
>= 2 );
1256 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) & static_cast<int>(pTop
[-1]));
1260 assert( mnStackIdx
>= 2 );
1261 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) | static_cast<int>(pTop
[-1]));
1265 assert( mnStackIdx
>= 1 );
1266 pTop
[0] = (pTop
[0] == 0);
1269 assert( mnStackIdx
>= 1 );
1274 assert( mnStackIdx
>= 1 );
1278 assert( mnStackIdx
>= 2 );
1279 pTop
[0] += pTop
[-1];
1283 assert( mnStackIdx
>= 2 );
1284 pTop
[0] -= pTop
[-1];
1288 assert( mnStackIdx
>= 2 );
1290 pTop
[0] *= pTop
[-1];
1294 assert( mnStackIdx
>= 2 );
1296 pTop
[0] /= pTop
[-1];
1300 assert( mnStackIdx
>= 2 );
1301 pTop
[0] = (pTop
[0] == pTop
[-1]);
1305 assert( mnStackIdx
>= 1 );
1308 case TYPE2OP::PUT
: {
1309 assert( mnStackIdx
>= 2 );
1310 const int nIdx
= static_cast<int>(pTop
[0]);
1311 assert( nIdx
>= 0 );
1312 assert( nIdx
< NMAXTRANS
);
1313 mnTransVals
[ nIdx
] = pTop
[-1];
1317 case TYPE2OP::GET
: {
1318 assert( mnStackIdx
>= 1 );
1319 const int nIdx
= static_cast<int>(pTop
[0]);
1320 assert( nIdx
>= 0 );
1321 assert( nIdx
< NMAXTRANS
);
1322 pTop
[0] = mnTransVals
[ nIdx
];
1325 case TYPE2OP::IFELSE
: {
1326 assert( mnStackIdx
>= 4 );
1327 if( pTop
[-1] > pTop
[0] )
1328 pTop
[-3] = pTop
[-2];
1332 case TYPE2OP::RANDOM
:
1333 pTop
[+1] = 1234; // TODO
1340 assert( mnStackIdx
>= 1 );
1344 case TYPE2OP::EXCH
: {
1345 assert( mnStackIdx
>= 2 );
1346 const ValType nVal
= pTop
[0];
1351 case TYPE2OP::INDEX
: {
1352 assert( mnStackIdx
>= 1 );
1353 const int nVal
= static_cast<int>(pTop
[0]);
1354 assert( nVal
>= 0 );
1355 assert( nVal
< mnStackIdx
-1 );
1356 pTop
[0] = pTop
[-1-nVal
];
1359 case TYPE2OP::ROLL
: {
1360 assert( mnStackIdx
>= 1 );
1361 const int nNum
= static_cast<int>(pTop
[0]);
1363 assert( nNum
< mnStackIdx
-2 );
1364 (void)nNum
; // TODO: implement
1365 const int nOfs
= static_cast<int>(pTop
[-1]);
1367 (void)nOfs
;// TODO: implement
1370 case TYPE2OP::HFLEX1
: {
1371 assert( mnStackIdx
== 9 );
1372 writeCurveTo( mnStackIdx
, -9, -8, -7, -6, -5, -6 );
1373 writeCurveTo( mnStackIdx
, -4, -6, -3, -2, -1, -8 );
1377 case TYPE2OP::HFLEX
: {
1378 assert( mnStackIdx
== 7 );
1379 writeCurveTo( mnStackIdx
, -7, 0, -6, -5, -4, -5 );
1380 writeCurveTo( mnStackIdx
, -3, -5, -2, 0, -1, 0 );
1384 case TYPE2OP::FLEX
: {
1385 assert( mnStackIdx
== 13 );
1386 writeCurveTo( mnStackIdx
, -13, -12, -11, -10, -9, -8 );
1387 writeCurveTo( mnStackIdx
, -7, -6, -5, -4, -3, -2 );
1388 const ValType nFlexDepth
= mnValStack
[ mnStackIdx
-1 ];
1389 (void)nFlexDepth
; // ignoring nFlexDepth
1393 case TYPE2OP::FLEX1
: {
1394 assert( mnStackIdx
== 11 );
1395 // write the first part of the flex1-hinted curve
1396 writeCurveTo( mnStackIdx
, -11, -10, -9, -8, -7, -6 );
1398 // determine if nD6 is horizontal or vertical
1399 const int i
= mnStackIdx
;
1400 ValType nDeltaX
= mnValStack
[i
-11] + mnValStack
[i
-9] + mnValStack
[i
-7] + mnValStack
[i
-5] + mnValStack
[i
-3];
1401 if( nDeltaX
< 0 ) nDeltaX
= -nDeltaX
;
1402 ValType nDeltaY
= mnValStack
[i
-10] + mnValStack
[i
-8] + mnValStack
[i
-6] + mnValStack
[i
-4] + mnValStack
[i
-2];
1403 if( nDeltaY
< 0 ) nDeltaY
= -nDeltaY
;
1404 const bool bVertD6
= (nDeltaY
> nDeltaX
);
1406 // write the second part of the flex1-hinted curve
1408 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, -1, 0);
1410 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, 0, -1);
1415 fprintf( stderr
,"unhandled type2esc %d\n", nType2Esc
);
1421 // --------------------------------------------------------------------
1423 void CffSubsetterContext::callType2Subr( bool bGlobal
, int nSubrNumber
)
1425 const U8
* const pOldReadPtr
= mpReadPtr
;
1426 const U8
* const pOldReadEnd
= mpReadEnd
;
1430 nSubrNumber
+= mnGlobalSubrBias
;
1431 nLen
= seekIndexData( mnGlobalSubrBase
, nSubrNumber
);
1433 nSubrNumber
+= mpCffLocal
->mnLocalSubrBias
;
1434 nLen
= seekIndexData( mpCffLocal
->mnLocalSubrBase
, nSubrNumber
);
1437 while( mpReadPtr
< mpReadEnd
)
1440 mpReadPtr
= pOldReadPtr
;
1441 mpReadEnd
= pOldReadEnd
;
1444 // --------------------------------------------------------------------
1446 static const int MAX_T1OPS_SIZE
= 81920; // TODO: use dynamic value
1448 int CffSubsetterContext::convert2Type1Ops( CffLocal
* pCffLocal
, const U8
* const pT2Ops
, int nT2Len
, U8
* const pT1Ops
)
1450 mpCffLocal
= pCffLocal
;
1452 // prepare the charstring conversion
1453 mpWritePtr
= pT1Ops
;
1454 #if 1 // TODO: update caller
1455 U8 aType1Ops
[ MAX_T1OPS_SIZE
];
1457 mpWritePtr
= aType1Ops
;
1458 *const_cast<U8
**>(&pT1Ops
) = mpWritePtr
;
1463 // prepend random seed for T1crypt
1464 *(mpWritePtr
++) = 0x48;
1465 *(mpWritePtr
++) = 0x44;
1466 *(mpWritePtr
++) = 0x55;
1467 *(mpWritePtr
++) = ' ';
1468 #if 1 // convert the Type2 charstring to Type1
1470 mpReadEnd
= pT2Ops
+ nT2Len
;
1471 // prepend "hsbw" or "sbw"
1472 // TODO: only emit hsbw when charwidth is known
1473 // TODO: remove charwidth from T2 stack
1474 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
1475 writeType1Val( 1000/*###getCharWidth()###*/);
1476 writeTypeOp( TYPE1OP::HSBW
);
1478 mbNeedClose
= false;
1479 mbIgnoreHints
= false;
1480 mnHintSize
=mnHorzHintSize
=mnStackIdx
=0; mnCharWidth
=-1;//#######
1482 while( mpReadPtr
< mpReadEnd
)
1485 // writeTypeOp( TYPE1OP::CLOSEPATH);
1487 // writeTypeOp( TYPE1OP::RETURN);
1489 mpWritePtr
= pT1Ops
+4;
1490 // create an "idiotproof" charstring
1492 writeType1Val( 800);
1493 writeTypeOp( TYPE1OP::HSBW
);
1495 writeTypeOp( TYPE1OP::HMOVETO
);
1496 writeType1Val( 650);
1497 writeType1Val( 100);
1498 writeTypeOp( TYPE1OP::RLINETO
);
1499 writeType1Val( -350);
1500 writeType1Val( 700);
1501 writeTypeOp( TYPE1OP::RLINETO
);
1503 writeType1Val( -300);
1504 writeType1Val( -800);
1505 writeTypeOp( TYPE1OP::RLINETO
);
1507 writeTypeOp( TYPE1OP::CLOSEPATH
);
1509 writeTypeOp( TYPE1OP::ENDCHAR
);
1511 #else // useful for manually encoding charstrings
1512 mpWritePtr
= pT1Ops
;
1513 mpWritePtr
+= sprintf( (char*)mpWritePtr
, "OOo_\x8b\x8c\x0c\x10\x0b");
1515 const int nType1Len
= mpWritePtr
- pT1Ops
;
1517 // encrypt the Type1 charstring
1518 int nRDCryptR
= 4330; // TODO: mnRDCryptSeed;
1519 for( U8
* p
= pT1Ops
; p
< mpWritePtr
; ++p
) {
1520 *p
^= (nRDCryptR
>> 8);
1521 nRDCryptR
= (*(U8
*)p
+ nRDCryptR
) * 52845 + 22719;
1527 // --------------------------------------------------------------------
1529 RealType
CffSubsetterContext::readRealVal()
1531 // TODO: more thorough number validity test
1532 bool bComma
= false;
1536 RealType fReal
= +1.0;
1538 const U8 c
= *(mpReadPtr
++); // read nibbles
1539 // parse high nibble
1540 const U8 nH
= c
>> 4U;
1542 nNumber
= nNumber
* 10 + nH
;
1544 } else if( nH
== 10) { // comma
1547 } else if( nH
== 11) { // +exp
1551 } else if( nH
== 12) { // -exp
1555 } else if( nH
== 13) { // reserved
1556 // TODO: ignore or error?
1557 } else if( nH
== 14) // minus
1559 else if( nH
== 15) // end
1562 const U8 nL
= c
& 0x0F;
1564 nNumber
= nNumber
* 10 + nL
;
1566 } else if( nL
== 10) { // comma
1569 } else if( nL
== 11) { // +exp
1573 } else if( nL
== 12) { // -exp
1577 } else if( nL
== 13) { // reserved
1578 // TODO: ignore or error?
1579 } else if( nL
== 14) // minus
1581 else if( nL
== 15) // end
1588 if( !nExpSign
) { fReal
*= nNumber
;}
1589 else if( nExpSign
> 0) { nExpVal
+= static_cast<int>(nNumber
);}
1590 else if( nExpSign
< 0) { nExpVal
-= static_cast<int>(nNumber
);}
1593 if( !nExpVal
) { /*nothing to apply*/}
1594 else if( nExpVal
> 0) { while( --nExpVal
>= 0) fReal
*= 10.0;}
1595 else if( nExpVal
< 0) { while( ++nExpVal
<= 0) fReal
/= 10.0;}
1599 // --------------------------------------------------------------------
1601 // prepare to access an element inside a CFF/CID index table
1602 int CffSubsetterContext::seekIndexData( int nIndexBase
, int nDataIndex
)
1604 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1607 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1608 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1609 if( nDataIndex
>= nDataCount
)
1611 const int nDataOfsSz
= mpReadPtr
[2];
1612 mpReadPtr
+= 3 + (nDataOfsSz
* nDataIndex
);
1614 switch( nDataOfsSz
) {
1615 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return -1;
1616 case 1: nOfs1
= mpReadPtr
[0]; break;
1617 case 2: nOfs1
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1618 case 3: nOfs1
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1619 case 4: nOfs1
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1621 mpReadPtr
+= nDataOfsSz
;
1624 switch( nDataOfsSz
) {
1625 case 1: nOfs2
= mpReadPtr
[0]; break;
1626 case 2: nOfs2
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1627 case 3: nOfs2
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1628 case 4: nOfs2
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1631 mpReadPtr
= mpBasePtr
+ (nIndexBase
+ 2) + nDataOfsSz
* (nDataCount
+ 1) + nOfs1
;
1632 mpReadEnd
= mpReadPtr
+ (nOfs2
- nOfs1
);
1633 assert( nOfs1
>= 0);
1634 assert( nOfs2
>= nOfs1
);
1635 assert( mpReadPtr
<= mpBaseEnd
);
1636 assert( mpReadEnd
<= mpBaseEnd
);
1637 return (nOfs2
- nOfs1
);
1640 // --------------------------------------------------------------------
1642 // skip over a CFF/CID index table
1643 void CffSubsetterContext::seekIndexEnd( int nIndexBase
)
1645 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1646 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1647 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1648 const int nDataOfsSz
= mpReadPtr
[2];
1649 mpReadPtr
+= 3 + nDataOfsSz
* nDataCount
;
1650 assert( mpReadPtr
<= mpBaseEnd
);
1652 switch( nDataOfsSz
) {
1653 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return;
1654 case 1: nEndOfs
= mpReadPtr
[0]; break;
1655 case 2: nEndOfs
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1656 case 3: nEndOfs
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2];break;
1657 case 4: nEndOfs
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1659 mpReadPtr
+= nDataOfsSz
;
1660 mpReadPtr
+= nEndOfs
- 1;
1661 mpReadEnd
= mpBaseEnd
;
1662 assert( nEndOfs
>= 0);
1663 assert( mpReadEnd
<= mpBaseEnd
);
1666 // ====================================================================
1668 // initialize FONTDICT specific values
1669 CffLocal::CffLocal( void)
1670 : mnPrivDictBase( 0)
1671 , mnPrivDictSize( 0)
1672 , mnLocalSubrOffs( 0)
1673 , mnLocalSubrBase( 0)
1674 , mnLocalSubrCount( 0)
1675 , mnLocalSubrBias( 0)
1676 , mnNominalWidth( 0)
1677 , mnDefaultWidth( 0)
1685 , mbForceBold( false)
1687 maStemSnapH
.clear();
1688 maStemSnapV
.clear();
1689 maBlueValues
.clear();
1690 maOtherBlues
.clear();
1691 maFamilyBlues
.clear();
1692 maFamilyOtherBlues
.clear();
1695 // --------------------------------------------------------------------
1697 CffGlobal::CffGlobal( void)
1699 , mnNameIdxCount( 0)
1700 , mnStringIdxBase( 0)
1701 , mnStringIdxCount( 0)
1704 , mnCharStrCount( 0)
1705 , mnEncodingBase( 0)
1707 , mnGlobalSubrBase( 0)
1708 , mnGlobalSubrCount( 0)
1709 , mnGlobalSubrBias( 0)
1710 , mnFDSelectBase( 0)
1711 , mnFontDictBase( 0)
1715 , mnFamilyNameSID( 0)
1718 // TODO; maFontMatrix.clear();
1721 // --------------------------------------------------------------------
1723 void CffSubsetterContext::initialCffRead( void)
1725 // get the CFFHeader
1726 mpReadPtr
= mpBasePtr
;
1727 const U8 nVerMajor
= *(mpReadPtr
++);
1728 const U8 nVerMinor
= *(mpReadPtr
++);
1729 const U8 nHeaderSize
= *(mpReadPtr
++);
1730 const U8 nOffsetSize
= *(mpReadPtr
++);
1731 // TODO: is the version number useful for anything else?
1732 assert( (nVerMajor
== 1) && (nVerMinor
== 0));
1733 (void)(nVerMajor
+ nVerMinor
+ nOffsetSize
); // avoid compiler warnings
1735 // prepare access to the NameIndex
1736 mnNameIdxBase
= nHeaderSize
;
1737 mpReadPtr
= mpBasePtr
+ nHeaderSize
;
1738 mnNameIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1739 seekIndexEnd( mnNameIdxBase
);
1741 // get the TopDict index
1742 const long nTopDictBase
= getReadOfs();
1743 const int nTopDictCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1744 if( nTopDictCount
) {
1745 for( int i
= 0; i
< nTopDictCount
; ++i
) {
1746 seekIndexData( nTopDictBase
, i
);
1747 while( mpReadPtr
< mpReadEnd
)
1749 assert( mpReadPtr
== mpReadEnd
);
1753 // prepare access to the String index
1754 mnStringIdxBase
= getReadOfs();
1755 mnStringIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1756 seekIndexEnd( mnStringIdxBase
);
1758 // prepare access to the GlobalSubr index
1759 mnGlobalSubrBase
= getReadOfs();
1760 mnGlobalSubrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1761 mnGlobalSubrBias
= (mnGlobalSubrCount
<1240)?107:(mnGlobalSubrCount
<33900)?1131:32768;
1762 // skip past the last GlobalSubr entry
1763 // seekIndexEnd( mnGlobalSubrBase);
1765 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1766 // seekEncodingsEnd( mnEncodingBase);
1767 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1768 // seekCharsetsEnd( mnCharStrBase);
1769 // get/skip FDSelect (CID only) data
1771 // prepare access to the CharStrings index (we got the base from TOPDICT)
1772 mpReadPtr
= mpBasePtr
+ mnCharStrBase
;
1773 mnCharStrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1774 // seekIndexEnd( mnCharStrBase);
1776 // read the FDArray index (CID only)
1778 // assert( mnFontDictBase == tellRel());
1779 mpReadPtr
= mpBasePtr
+ mnFontDictBase
;
1780 mnFDAryCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1781 assert( mnFDAryCount
< (int)(sizeof(maCffLocal
)/sizeof(*maCffLocal
)));
1783 // read FDArray details to get access to the PRIVDICTs
1784 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1785 mpCffLocal
= &maCffLocal
[i
];
1786 seekIndexData( mnFontDictBase
, i
);
1787 while( mpReadPtr
< mpReadEnd
)
1789 assert( mpReadPtr
== mpReadEnd
);
1793 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1794 mpCffLocal
= &maCffLocal
[i
];
1796 // get the PrivateDict index
1797 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1798 if( mpCffLocal
->mnPrivDictSize
!= 0) {
1799 assert( mpCffLocal
->mnPrivDictSize
> 0);
1800 // get the PrivDict data
1801 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnPrivDictBase
;
1802 mpReadEnd
= mpReadPtr
+ mpCffLocal
->mnPrivDictSize
;
1803 assert( mpReadEnd
<= mpBaseEnd
);
1804 // read PrivDict details
1805 while( mpReadPtr
< mpReadEnd
)
1809 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1810 if( mpCffLocal
->mnLocalSubrOffs
) {
1811 // read LocalSubrs summary
1812 mpCffLocal
->mnLocalSubrBase
= mpCffLocal
->mnPrivDictBase
+ mpCffLocal
->mnLocalSubrOffs
;
1813 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnLocalSubrBase
;
1814 const int nSubrCount
= (mpReadPtr
[0] << 8) + mpReadPtr
[1];
1815 mpCffLocal
->mnLocalSubrCount
= nSubrCount
;
1816 mpCffLocal
->mnLocalSubrBias
= (nSubrCount
<1240)?107:(nSubrCount
<33900)?1131:32768;
1817 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1821 // ignore the Notices info
1824 // --------------------------------------------------------------------
1826 // get a cstring from a StringID
1827 const char* CffSubsetterContext::getString( int nStringID
)
1829 // get a standard string if possible
1830 const static int nStdStrings
= sizeof(pStringIds
)/sizeof(*pStringIds
);
1831 if( (nStringID
>= 0) && (nStringID
< nStdStrings
))
1832 return pStringIds
[ nStringID
];
1834 // else get the string from the StringIndex table
1835 const U8
* pReadPtr
= mpReadPtr
;
1836 const U8
* pReadEnd
= mpReadEnd
;
1837 nStringID
-= nStdStrings
;
1838 int nLen
= seekIndexData( mnStringIdxBase
, nStringID
);
1839 // assert( nLen >= 0);
1840 // TODO: just return the undecorated name
1841 // TODO: get rid of static char buffer
1842 static char aNameBuf
[ 2560];
1844 sprintf( aNameBuf
, "name[%d].notfound!", nStringID
);
1846 const int nMaxLen
= sizeof(aNameBuf
) - 1;
1847 if( nLen
>= nMaxLen
)
1849 for( int i
= 0; i
< nLen
; ++i
)
1850 aNameBuf
[i
] = *(mpReadPtr
++);
1851 aNameBuf
[ nLen
] = '\0';
1853 mpReadPtr
= pReadPtr
;
1854 mpReadEnd
= pReadEnd
;
1858 // --------------------------------------------------------------------
1860 // access a CID's FDSelect table
1861 int CffSubsetterContext::getFDSelect( int nGlyphIndex
) const
1863 assert( nGlyphIndex
>= 0);
1864 assert( nGlyphIndex
< mnCharStrCount
);
1868 const U8
* pReadPtr
= mpBasePtr
+ mnFDSelectBase
;
1869 const U8 nFDSelFormat
= *(pReadPtr
++);
1870 switch( nFDSelFormat
) {
1871 case 0: { // FDSELECT format 0
1872 pReadPtr
+= nGlyphIndex
;
1873 const U8 nFDIdx
= *(pReadPtr
++);
1876 case 3: { // FDSELECT format 3
1877 const U16 nRangeCount
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1878 assert( nRangeCount
> 0);
1879 assert( nRangeCount
<= mnCharStrCount
);
1880 U16 nPrev
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1881 assert( nPrev
== 0);
1883 // TODO? binary search
1884 for( int i
= 0; i
< nRangeCount
; ++i
) {
1885 const U8 nFDIdx
= pReadPtr
[0];
1886 const U16 nNext
= (pReadPtr
[1]<<8) + pReadPtr
[2];
1887 assert( nPrev
< nNext
);
1888 if( nGlyphIndex
< nNext
)
1894 default: // invalid FDselect format
1895 fprintf( stderr
, "invalid CFF.FdselType=%d\n", nFDSelFormat
);
1903 // --------------------------------------------------------------------
1905 int CffSubsetterContext::getGlyphSID( int nGlyphIndex
) const
1907 if( nGlyphIndex
== 0)
1908 return 0; // ".notdef"
1909 assert( nGlyphIndex
>= 0);
1910 assert( nGlyphIndex
< mnCharStrCount
);
1911 if( (nGlyphIndex
< 0) || (nGlyphIndex
>= mnCharStrCount
))
1914 // get the SID/CID from the Charset table
1915 const U8
* pReadPtr
= mpBasePtr
+ mnCharsetBase
;
1916 const U8 nCSetFormat
= *(pReadPtr
++);
1917 int nGlyphsToSkip
= nGlyphIndex
- 1;
1918 switch( nCSetFormat
) {
1919 case 0: // charset format 0
1920 pReadPtr
+= 2 * nGlyphsToSkip
;
1923 case 1: // charset format 1
1924 while( nGlyphsToSkip
>= 0) {
1925 const int nLeft
= pReadPtr
[2];
1926 if( nGlyphsToSkip
<= nLeft
)
1928 nGlyphsToSkip
-= nLeft
+ 1;
1932 case 2: // charset format 2
1933 while( nGlyphsToSkip
>= 0) {
1934 const int nLeft
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1935 if( nGlyphsToSkip
<= nLeft
)
1937 nGlyphsToSkip
-= nLeft
+ 1;
1942 fprintf( stderr
, "ILLEGAL CFF-Charset format %d\n", nCSetFormat
);
1946 int nSID
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1947 nSID
+= nGlyphsToSkip
;
1948 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1952 // --------------------------------------------------------------------
1954 // NOTE: the result becomes invalid with the next call to this method
1955 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex
)
1957 // the first glyph is always the .notdef glyph
1958 const char* pGlyphName
= ".notdef";
1959 if( nGlyphIndex
== 0)
1962 // prepare a result buffer
1963 // TODO: get rid of static buffer
1964 static char aDefaultGlyphName
[64];
1965 pGlyphName
= aDefaultGlyphName
;
1967 // get the glyph specific name
1968 const int nSID
= getGlyphSID( nGlyphIndex
);
1969 if( nSID
< 0) // default glyph name
1970 sprintf( aDefaultGlyphName
, "gly%03d", nGlyphIndex
);
1971 else if( mbCIDFont
) // default glyph name in CIDs
1972 sprintf( aDefaultGlyphName
, "cid%03d", nSID
);
1973 else { // glyph name from string table
1974 const char* pSidName
= getString( nSID
);
1975 // check validity of glyph name
1977 const char* p
= pSidName
;
1978 while( (*p
>= '0') && (*p
<= 'z')) ++p
;
1979 if( (p
>= pSidName
+1) && (*p
== '\0'))
1980 pGlyphName
= pSidName
;
1982 // if needed invent a fallback name
1983 if( pGlyphName
!= pSidName
)
1984 sprintf( aDefaultGlyphName
, "bad%03d", nSID
);
1990 // --------------------------------------------------------------------
1995 explicit Type1Emitter( const char* pOutFileName
, bool bPfbSubset
= true);
1996 explicit Type1Emitter( FILE* pOutFile
, bool bPfbSubset
= true);
1997 /*virtual*/ ~Type1Emitter( void);
1998 void setSubsetName( const char* );
2000 void emitRawData( const char* pData
, int nLength
) const;
2001 void emitAllRaw( void);
2002 void emitAllHex( void);
2003 void emitAllCrypted( void);
2004 int tellPos( void) const;
2005 void updateLen( int nTellPos
, int nLength
);
2006 void emitValVector( const char* pLineHead
, const char* pLineTail
, const ValVector
&);
2009 bool mbCloseOutfile
;
2010 char maBuffer
[MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
2015 char maSubsetName
[256];
2020 // --------------------------------------------------------------------
2022 Type1Emitter::Type1Emitter( const char* pPfbFileName
, bool bPfbSubset
)
2024 , mbCloseOutfile( true)
2025 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
2027 , mbPfbSubset( bPfbSubset
)
2030 mpFileOut
= fopen( pPfbFileName
, "wb");
2031 maSubsetName
[0] = '\0';
2034 // --------------------------------------------------------------------
2036 Type1Emitter::Type1Emitter( FILE* pOutFile
, bool bPfbSubset
)
2037 : mpFileOut( pOutFile
)
2038 , mbCloseOutfile( false)
2039 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
2041 , mbPfbSubset( bPfbSubset
)
2044 maSubsetName
[0] = '\0';
2047 // --------------------------------------------------------------------
2049 Type1Emitter::~Type1Emitter( void)
2053 if( mbCloseOutfile
)
2058 // --------------------------------------------------------------------
2060 void Type1Emitter::setSubsetName( const char* pSubsetName
)
2062 maSubsetName
[0] = '\0';
2064 strncpy( maSubsetName
, pSubsetName
, sizeof(maSubsetName
));
2065 maSubsetName
[sizeof(maSubsetName
)-1] = '\0';
2068 // --------------------------------------------------------------------
2070 int Type1Emitter::tellPos( void) const
2072 int nTellPos
= ftell( mpFileOut
);
2076 // --------------------------------------------------------------------
2078 void Type1Emitter::updateLen( int nTellPos
, int nLength
)
2080 // update PFB segment header length
2082 cData
[0] = static_cast<U8
>(nLength
>> 0);
2083 cData
[1] = static_cast<U8
>(nLength
>> 8);
2084 cData
[2] = static_cast<U8
>(nLength
>> 16);
2085 cData
[3] = static_cast<U8
>(nLength
>> 24);
2086 const int nCurrPos
= ftell( mpFileOut
);
2087 fseek( mpFileOut
, nTellPos
, SEEK_SET
);
2088 fwrite( cData
, 1, sizeof(cData
), mpFileOut
);
2089 fseek( mpFileOut
, nCurrPos
, SEEK_SET
);
2092 // --------------------------------------------------------------------
2094 inline void Type1Emitter::emitRawData( const char* pData
, int nLength
) const
2096 fwrite( pData
, 1, nLength
, mpFileOut
);
2099 // --------------------------------------------------------------------
2101 inline void Type1Emitter::emitAllRaw( void)
2103 // writeout raw data
2104 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
2105 emitRawData( maBuffer
, mpPtr
- maBuffer
);
2106 // reset the raw buffer
2110 // --------------------------------------------------------------------
2112 inline void Type1Emitter::emitAllHex( void)
2114 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
2115 for( const char* p
= maBuffer
; p
< mpPtr
;) {
2116 // convert binary chunk to hex
2117 char aHexBuf
[0x4000];
2118 char* pOut
= aHexBuf
;
2119 while( (p
< mpPtr
) && (pOut
< aHexBuf
+sizeof(aHexBuf
)-4)) {
2120 // convert each byte to hex
2121 char cNibble
= (*p
>> 4) & 0x0F;
2122 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
2123 *(pOut
++) = cNibble
;
2124 cNibble
= *(p
++) & 0x0F;
2125 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
2126 *(pOut
++) = cNibble
;
2127 // limit the line length
2128 if( (++mnHexLineCol
& 0x3F) == 0)
2131 // writeout hex-converted chunk
2132 emitRawData( aHexBuf
, pOut
-aHexBuf
);
2134 // reset the raw buffer
2138 // --------------------------------------------------------------------
2140 void Type1Emitter::emitAllCrypted( void)
2143 for( char* p
= maBuffer
; p
< mpPtr
; ++p
) {
2144 *p
^= (mnEECryptR
>> 8);
2145 mnEECryptR
= (*(U8
*)p
+ mnEECryptR
) * 52845 + 22719;
2148 // emit the t1crypt result
2155 // --------------------------------------------------------------------
2157 void Type1Emitter::emitValVector( const char* pLineHead
, const char* pLineTail
,
2158 const ValVector
& rVector
)
2160 // ignore empty vectors
2161 if( rVector
.empty())
2164 // emit the line head
2165 mpPtr
+= sprintf( mpPtr
, pLineHead
);
2166 // emit the vector values
2167 ValVector::value_type aVal
= 0;
2168 for( ValVector::const_iterator it
= rVector
.begin();;) {
2170 if( ++it
== rVector
.end() )
2172 mpPtr
+= sprintf( mpPtr
, "%g ", aVal
);
2174 // emit the last value
2175 mpPtr
+= sprintf( mpPtr
, "%g", aVal
);
2176 // emit the line tail
2177 mpPtr
+= sprintf( mpPtr
, pLineTail
);
2180 // --------------------------------------------------------------------
2182 bool CffSubsetterContext::emitAsType1( Type1Emitter
& rEmitter
,
2183 const long* pReqGlyphIDs
, const U8
* pReqEncoding
,
2184 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rFSInfo
)
2186 // prepare some fontdirectory details
2187 static const int nUniqueIdBase
= 4100000; // using private-interchange UniqueIds
2188 static int nUniqueId
= nUniqueIdBase
;
2191 char* pFontName
= rEmitter
.maSubsetName
;
2193 if( mnFontNameSID
) {
2194 // get the fontname directly if available
2195 strncpy( pFontName
, getString( mnFontNameSID
), sizeof(rEmitter
.maSubsetName
));
2196 } else if( mnFullNameSID
) {
2197 // approximate fontname as fullname-whitespace
2198 const char* pI
= getString( mnFullNameSID
);
2199 char* pO
= pFontName
;
2200 const char* pLimit
= pFontName
+ sizeof(rEmitter
.maSubsetName
) - 1;
2201 while( pO
< pLimit
) {
2202 const char c
= *(pI
++);
2210 // fallback name of last resort
2211 strncpy( pFontName
, "DummyName", sizeof(rEmitter
.maSubsetName
));
2214 const char* pFullName
= pFontName
;
2215 const char* pFamilyName
= pFontName
;
2217 char*& pOut
= rEmitter
.mpPtr
; // convenience reference, TODO: cleanup
2219 // create a PFB+Type1 header
2220 if( rEmitter
.mbPfbSubset
) {
2221 static const char aPfbHeader
[] = "\x80\x01\x00\x00\x00\x00";
2222 rEmitter
.emitRawData( aPfbHeader
, sizeof(aPfbHeader
)-1);
2225 pOut
+= sprintf( pOut
, "%%!FontType1-1.0: %s 001.003\n", rEmitter
.maSubsetName
);
2227 #if 0 // improve PS Type1 caching?
2228 nOfs
+= sprintf( &aT1Str
[nOfs
],
2229 "FontDirectory/%s known{/%s findfont dup/UniqueID known{dup\n"
2230 "/UniqueID get %d eq exch/FontType get 1 eq and}{pop false}ifelse\n"
2231 "{save true}{false}ifelse}\n{false}ifelse\n",
2232 pFamilyName
, pFamilyName
, nUniqueId
);
2234 pOut
+= sprintf( pOut
,
2235 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
2237 "/PaintType 0 def\n");
2238 pOut
+= sprintf( pOut
, "/FontName /%s def\n", rEmitter
.maSubsetName
);
2239 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
2241 if( maFontMatrix
.size() == 6)
2242 rEmitter
.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix
);
2243 else // emit default FontMatrix if needed
2244 pOut
+= sprintf( pOut
, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
2246 if( maFontBBox
.size() == 4)
2247 rEmitter
.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox
);
2248 else // emit default FontBBox if needed
2249 pOut
+= sprintf( pOut
, "/FontBBox {0 0 999 999}readonly def\n");
2250 // emit FONTINFO into TOPDICT
2251 pOut
+= sprintf( pOut
,
2252 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
2253 " /FullName (%s) readonly def\n"
2254 " /FamilyName (%s) readonly def\n"
2255 "end readonly def\n",
2256 pFullName
, pFamilyName
);
2257 #if 0 // TODO: use an standard Type1 encoding if possible
2258 pOut
+= sprintf( pOut
,
2259 "/Encoding StandardEncoding def\n");
2261 pOut
+= sprintf( pOut
,
2262 "/Encoding 256 array\n"
2263 "0 1 255 {1 index exch /.notdef put} for\n");
2264 for( int i
= 1; (i
< nGlyphCount
) && (i
< 256); ++i
) {
2265 const char* pGlyphName
= getGlyphName( pReqGlyphIDs
[i
]);
2266 pOut
+= sprintf( pOut
, "dup %d /%s put\n", pReqEncoding
[i
], pGlyphName
);
2268 pOut
+= sprintf( pOut
, "readonly def\n");
2270 pOut
+= sprintf( pOut
,
2271 // TODO: more topdict entries
2273 "currentfile eexec\n");
2276 rEmitter
.emitAllRaw();
2277 if( rEmitter
.mbPfbSubset
) {
2278 // update PFB header segment
2279 const int nPfbHeaderLen
= rEmitter
.tellPos() - 6;
2280 rEmitter
.updateLen( 2, nPfbHeaderLen
);
2282 // prepare start of eexec segment
2283 rEmitter
.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
2285 const int nEExecSegTell
= rEmitter
.tellPos();
2287 // which always starts with a privdict
2288 // count the privdict entries
2289 int nPrivEntryCount
= 9;
2290 #if !defined(IGNORE_HINTS)
2291 // emit blue hints only if non-default values
2292 nPrivEntryCount
+= !mpCffLocal
->maOtherBlues
.empty();
2293 nPrivEntryCount
+= !mpCffLocal
->maFamilyBlues
.empty();
2294 nPrivEntryCount
+= !mpCffLocal
->maFamilyOtherBlues
.empty();
2295 nPrivEntryCount
+= (mpCffLocal
->mfBlueScale
!= 0.0);
2296 nPrivEntryCount
+= (mpCffLocal
->mfBlueShift
!= 0.0);
2297 nPrivEntryCount
+= (mpCffLocal
->mfBlueFuzz
!= 0.0);
2298 // emit stem hints only if non-default values
2299 nPrivEntryCount
+= (mpCffLocal
->mnStemStdHW
!= 0);
2300 nPrivEntryCount
+= (mpCffLocal
->mnStemStdVW
!= 0);
2301 nPrivEntryCount
+= !mpCffLocal
->maStemSnapH
.empty();
2302 nPrivEntryCount
+= !mpCffLocal
->maStemSnapV
.empty();
2303 // emit other hints only if non-default values
2304 nPrivEntryCount
+= (mpCffLocal
->mfExpFactor
!= 0.0);
2305 nPrivEntryCount
+= (mpCffLocal
->mnLangGroup
!= 0);
2306 nPrivEntryCount
+= (mpCffLocal
->mnLangGroup
== 1);
2307 nPrivEntryCount
+= (mpCffLocal
->mbForceBold
!= false);
2308 #endif // IGNORE_HINTS
2309 // emit the privdict header
2310 pOut
+= sprintf( pOut
,
2312 "dup\n/Private %d dict dup begin\n"
2313 "/RD{string currentfile exch readstring pop}executeonly def\n"
2314 "/ND{noaccess def}executeonly def\n"
2315 "/NP{noaccess put}executeonly def\n"
2316 "/MinFeature{16 16}ND\n"
2317 "/password 5839 def\n", // TODO: mnRDCryptSeed?
2320 #if defined(IGNORE_HINTS)
2321 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // BlueValues are mandatory
2323 // emit blue hint related privdict entries
2324 if( !mpCffLocal
->maBlueValues
.empty())
2325 rEmitter
.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal
->maBlueValues
);
2327 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // default to empty BlueValues
2328 rEmitter
.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal
->maOtherBlues
);
2329 rEmitter
.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal
->maFamilyBlues
);
2330 rEmitter
.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal
->maFamilyOtherBlues
);
2332 if( mpCffLocal
->mfBlueScale
)
2333 pOut
+= sprintf( pOut
, "/BlueScale %.6f def\n", mpCffLocal
->mfBlueScale
);
2334 if( mpCffLocal
->mfBlueShift
) // default BlueShift==7
2335 pOut
+= sprintf( pOut
, "/BlueShift %.1f def\n", mpCffLocal
->mfBlueShift
);
2336 if( mpCffLocal
->mfBlueFuzz
) // default BlueFuzz==1
2337 pOut
+= sprintf( pOut
, "/BlueFuzz %.1f def\n", mpCffLocal
->mfBlueFuzz
);
2339 // emit stem hint related privdict entries
2340 if( mpCffLocal
->mnStemStdHW
)
2341 pOut
+= sprintf( pOut
, "/StdHW [%d] def\n", mpCffLocal
->mnStemStdHW
);
2342 if( mpCffLocal
->mnStemStdVW
)
2343 pOut
+= sprintf( pOut
, "/StdVW [%d] def\n", mpCffLocal
->mnStemStdVW
);
2344 rEmitter
.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal
->maStemSnapH
);
2345 rEmitter
.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal
->maStemSnapV
);
2348 if( mpCffLocal
->mbForceBold
)
2349 pOut
+= sprintf( pOut
, "/ForceBold true def\n");
2350 if( mpCffLocal
->mnLangGroup
!= 0)
2351 pOut
+= sprintf( pOut
, "/LanguageGroup %d def\n", mpCffLocal
->mnLangGroup
);
2352 if( mpCffLocal
->mnLangGroup
== 1) // compatibility with ancient printers
2353 pOut
+= sprintf( pOut
, "/RndStemUp false def\n");
2354 if( mpCffLocal
->mfExpFactor
)
2355 pOut
+= sprintf( pOut
, "/ExpansionFactor %.2f def\n", mpCffLocal
->mfExpFactor
);
2356 #endif // IGNORE_HINTS
2358 // emit remaining privdict entries
2359 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
2360 // TODO?: more privdict entries?
2362 static const char aOtherSubrs
[] =
2364 "% Dummy code for faking flex hints\n"
2365 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2366 "{1183615869 systemdict /internaldict get exec\n"
2367 "dup /startlock known\n"
2368 "{/startlock get exec}\n"
2369 "{dup /strtlck known\n"
2370 "{/strtlck get exec}\n"
2371 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2373 memcpy( pOut
, aOtherSubrs
, sizeof(aOtherSubrs
)-1);
2374 pOut
+= sizeof(aOtherSubrs
)-1;
2376 // emit used GlobalSubr charstrings
2377 // these are the just the default subrs
2378 static const char aSubrs
[] =
2380 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2381 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2382 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2383 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2384 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2386 memcpy( pOut
, aSubrs
, sizeof(aSubrs
)-1);
2387 pOut
+= sizeof(aSubrs
)-1;
2389 // TODO: emit more GlobalSubr charstrings?
2390 // TODO: emit used LocalSubr charstrings?
2392 // emit the CharStrings for the requested glyphs
2393 pOut
+= sprintf( pOut
,
2394 "2 index /CharStrings %d dict dup begin\n", nGlyphCount
);
2395 rEmitter
.emitAllCrypted();
2396 for( int i
= 0; i
< nGlyphCount
; ++i
) {
2397 const int nGlyphId
= pReqGlyphIDs
[i
];
2398 assert( (nGlyphId
>= 0) && (nGlyphId
< mnCharStrCount
));
2399 // get privdict context matching to the glyph
2400 const int nFDSelect
= getFDSelect( nGlyphId
);
2401 mpCffLocal
= &maCffLocal
[ nFDSelect
];
2402 // convert the Type2op charstring to its Type1op counterpart
2403 const int nT2Len
= seekIndexData( mnCharStrBase
, nGlyphId
);
2404 assert( nT2Len
> 0);
2405 U8 aType1Ops
[ MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
2406 const int nT1Len
= convert2Type1Ops( mpCffLocal
, mpReadPtr
, nT2Len
, aType1Ops
);
2407 // get the glyph name
2408 const char* pGlyphName
= getGlyphName( nGlyphId
);
2409 // emit the encrypted Type1op charstring
2410 pOut
+= sprintf( pOut
, "/%s %d RD ", pGlyphName
, nT1Len
);
2411 memcpy( pOut
, aType1Ops
, nT1Len
);
2413 pOut
+= sprintf( pOut
, " ND\n");
2414 rEmitter
.emitAllCrypted();
2415 // provide individual glyphwidths if requested
2417 pGlyphWidths
[i
] = getCharWidth();
2419 pOut
+= sprintf( pOut
, "end end\nreadonly put\nput\n");
2420 pOut
+= sprintf( pOut
, "dup/FontName get exch definefont pop\n");
2421 pOut
+= sprintf( pOut
, "mark currentfile closefile\n");
2422 rEmitter
.emitAllCrypted();
2424 // mark stop of eexec encryption
2425 if( rEmitter
.mbPfbSubset
) {
2426 const int nEExecLen
= rEmitter
.tellPos() - nEExecSegTell
;
2427 rEmitter
.updateLen( nEExecSegTell
-4, nEExecLen
);
2430 // create PFB footer
2431 static const char aPfxFooter
[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2432 "0000000000000000000000000000000000000000000000000000000000000000\n"
2433 "0000000000000000000000000000000000000000000000000000000000000000\n"
2434 "0000000000000000000000000000000000000000000000000000000000000000\n"
2435 "0000000000000000000000000000000000000000000000000000000000000000\n"
2436 "0000000000000000000000000000000000000000000000000000000000000000\n"
2437 "0000000000000000000000000000000000000000000000000000000000000000\n"
2438 "0000000000000000000000000000000000000000000000000000000000000000\n"
2439 "0000000000000000000000000000000000000000000000000000000000000000\n"
2442 if( rEmitter
.mbPfbSubset
)
2443 rEmitter
.emitRawData( aPfxFooter
, sizeof(aPfxFooter
)-1);
2445 rEmitter
.emitRawData( aPfxFooter
+6, sizeof(aPfxFooter
)-9);
2447 // provide details to the subset requesters, TODO: move into own method?
2448 // note: Top and Bottom are flipped between Type1 and VCL
2449 rFSInfo
.m_aFontBBox
= Rectangle( Point( static_cast<long>(maFontBBox
[0]), static_cast<long>(maFontBBox
[1]) ),
2450 Point( static_cast<long>(maFontBBox
[2]), static_cast<long>(maFontBBox
[3]) ) );
2451 // PDF-Spec says the values below mean the ink bounds!
2452 // TODO: use better approximations for these ink bounds
2453 rFSInfo
.m_nAscent
= +rFSInfo
.m_aFontBBox
.Bottom(); // for capital letters
2454 rFSInfo
.m_nDescent
= -rFSInfo
.m_aFontBBox
.Top(); // for all letters
2455 rFSInfo
.m_nCapHeight
= rFSInfo
.m_nAscent
; // for top-flat capital letters
2457 rFSInfo
.m_nFontType
= rEmitter
.mbPfbSubset
? FontSubsetInfo::TYPE1_PFB
: FontSubsetInfo::TYPE1_PFA
;
2458 rFSInfo
.m_aPSName
= String( rEmitter
.maSubsetName
, RTL_TEXTENCODING_UTF8
);
2463 // ====================================================================
2465 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth
* pOutGlyphWidths
)
2467 CffSubsetterContext
aCff( mpInFontBytes
, mnInByteLength
);
2468 aCff
.initialCffRead();
2470 // emit Type1 subset from the CFF input
2471 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2472 const bool bPfbSubset
= (0 != (mnReqFontTypeMask
& FontSubsetInfo::TYPE1_PFB
));
2473 Type1Emitter
aType1Emitter( mpOutFile
, bPfbSubset
);
2474 aType1Emitter
.setSubsetName( mpReqFontName
);
2475 bool bRC
= aCff
.emitAsType1( aType1Emitter
,
2476 mpReqGlyphIds
, mpReqEncodedIds
,
2477 pOutGlyphWidths
, mnReqGlyphCount
, *this);
2481 // ====================================================================