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
;
46 typedef std::vector
<int> IntVector
;
48 // ====================================================================
50 static const char* pStringIds
[] = {
51 /*0*/ ".notdef", "space", "exclam", "quotedbl",
52 "numbersign", "dollar", "percent", "ampersand",
53 "quoteright", "parenleft", "parenright", "asterisk",
54 "plus", "comma", "hyphen", "period",
55 /*16*/ "slash", "zero", "one", "two",
56 "three", "four", "five", "six",
57 "seven", "eight", "nine", "colon",
58 "semicolon", "less", "equal", "greater",
59 /*32*/ "question", "at", "A", "B",
63 /*48*/ "O", "P", "Q", "R",
66 "bracketleft", "backslash", "bracketright", "asciicircum",
67 /*64*/ "underscore", "quoteleft", "a", "b",
71 /*80*/ "o", "p", "q", "r",
74 "braceleft", "bar", "braceright", "asciitilde",
75 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
76 "yen", "florin", "section", "currency",
77 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
78 "guilsinglright", "fi", "fl", "endash",
79 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
80 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
81 "guillemotright", "ellipsis", "perthousand", "questiondown",
82 "grave", "acute", "circumflex", "tilde",
83 /*128*/ "macron", "breve", "dotaccent", "dieresis",
84 "ring", "cedilla", "hungarumlaut", "ogonek",
85 "caron", "endash", "AE", "ordfeminine",
86 "Lslash", "Oslash", "OE", "ordmasculine",
87 /*144*/ "ae", "dotlessi", "lslash", "oslash",
88 "oe", "germandbls", "onesuperior", "logicalnot",
89 "mu", "trademark", "Eth", "onehalf",
90 "plusminus", "Thorn", "onequarter", "divide",
91 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
92 "twosuperior", "registered", "minus", "eth",
93 "multiply", "threesuperior", "copyright", "Aacute",
94 "Acircumflex", "Adieresis", "Agrave", "Aring",
95 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
96 "Edieresis", "Egrave", "Iacute", "Icircumflex",
97 "Idieresis", "Igrave", "Ntilde", "Oacute",
98 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
99 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
100 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
101 "aacute", "acircumflex", "adieresis", "agrave",
102 "aring", "atilde", "ccedilla", "eacute",
103 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
104 "icircumflex", "idieresis", "igrave", "ntilde",
105 "oacute", "ocircumflex", "odieresis", "ograve",
106 "otilde", "scaron", "uacute", "ucircumflex",
107 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
108 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
109 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
110 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
111 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
112 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
113 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
114 "questionsmall", "asuperior", "bsuperior", "centsuperior",
115 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
116 "msuperior", "nsuperior", "osuperior", "rsuperior",
117 "ssuperior", "tsuperior", "ff", "ffi",
118 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
119 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
120 "Csmall", "Dsmall", "Esmall", "Fsmall",
121 "Gsmall", "Hsmall", "Ismall", "Jsmall",
122 "Ksmall", "Lsmall", "Msmall", "Nsmall",
123 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
124 "Ssmall", "Tsmall", "Usmall", "Vsmall",
125 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
126 "colonmonetary", "onefitted", "rupia", "Tildesmall",
127 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
128 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
129 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
130 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
131 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
132 "onethird", "twothirds", "zerosuperior", "foursuperior",
133 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
134 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
135 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
136 "seveninferior", "eightinferior", "nineinferior", "centinferior",
137 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
138 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
139 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
140 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
141 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
142 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
143 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
144 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
145 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
146 "001.001", "001.002", "001.003", "Black",
147 /*384*/ "Bold", "Book", "Light", "Medium",
148 "Regular", "Roman", "Semibold"
151 // --------------------------------------------------------------------
153 #if 0 // TODO: use them
154 static const char* pStdEncNames
[] = {
155 "ISOAdobe", "Expert", "ExpertSubSet"
159 // --------------------------------------------------------------------
161 // TOP DICT keywords (also covers PRIV DICT keywords)
162 static const char* pDictOps
[] = {
163 "sVersion", "sNotice", "sFullName", "sFamilyName",
164 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
165 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
166 "xESC", "nUniqueID", "aXUID", "nCharset",
167 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
168 "nDefaultWidthX", "nNominalWidthX", NULL
, NULL
,
169 NULL
, NULL
, NULL
, NULL
,
170 "shortint", "longint", "BCD", NULL
173 // --------------------------------------------------------------------
175 // TOP DICT escapes (also covers PRIV DICT escapes)
176 static const char* pDictEscs
[] = {
177 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
178 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
179 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
180 "dStemSnapH", "dStemSnapV", "bForceBold", NULL
,
181 NULL
, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
182 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
183 NULL
, NULL
, NULL
, NULL
,
184 NULL
, NULL
, "rROS", "nCIDFontVersion",
185 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
186 "nFDArray", "nFDSelect", "sFontName"
189 // --------------------------------------------------------------------
191 static const char* pType1Ops
[] = {
192 NULL
, "2hstem", NULL
, "2vstem",
193 "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
194 "Crrcurveto", "0closepath", "Lcallsubr", "0return",
195 "xT1ESC", "2hsbw", "0endchar", NULL
,
196 NULL
, NULL
, NULL
, NULL
,
197 NULL
, "2rmoveto", "1hmoveto", NULL
,
198 NULL
, NULL
, NULL
, NULL
,
199 NULL
, NULL
, "4vhcurveto", "4hvcurveto"
202 // --------------------------------------------------------------------
204 static const char* pT1EscOps
[] = {
205 "0dotsection", "6vstem3", "6hstem3", NULL
,
206 NULL
, NULL
, "5seac", "4sbw",
207 NULL
, "1abs", "2add", "2sub",
208 "2div", NULL
, NULL
, NULL
,
209 "Gcallothersubr", "1pop", NULL
, NULL
,
210 NULL
, NULL
, NULL
, NULL
,
211 NULL
, NULL
, NULL
, NULL
,
212 NULL
, NULL
, NULL
, NULL
,
213 NULL
, "2setcurrentpoint"
216 // --------------------------------------------------------------------
222 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
223 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CLOSEPATH
=9,
224 CALLSUBR
=10, RETURN
=11, T1ESC
=12, HSBW
=13,
225 ENDCHAR
=14, RMOVETO
=21, HMOVETO
=22, VHCURVETO
=30,
231 DOTSECTION
=0, VSTEM3
=1, HSTEM3
=2, SEAC
=6,
232 SBW
=7, ABS
=9, ADD
=10, SUB
=11,
233 DIV
=12, CALLOTHERSUBR
=16, POP
=17, SETCURRENTPOINT
=33
237 // --------------------------------------------------------------------
239 static const char* pType2Ops
[] = {
240 NULL
, "hhstem", NULL
, "vvstem",
241 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
242 "Crrcurveto", NULL
, "Lcallsubr", "Xreturn",
243 "xT2ESC", NULL
, "eendchar", NULL
,
244 NULL
, NULL
, "Hhstemhm", "Khintmask",
245 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
246 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
247 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
250 // --------------------------------------------------------------------
252 static const char* pT2EscOps
[] = {
253 NULL
, NULL
, NULL
, "2and",
254 "2or", "1not", NULL
, NULL
,
255 NULL
, "1abs", "2add", "2sub",
256 "2div", NULL
, "1neg", "2eq",
257 NULL
, NULL
, "1drop", NULL
,
258 "1put", "1get", "4ifelse", "0random",
259 "2mul", NULL
, "1sqrt", "1dup",
260 "2exch", "Iindex", "Rroll", NULL
,
261 NULL
, NULL
, "7hflex", "Fflex",
265 // --------------------------------------------------------------------
271 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
272 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CALLSUBR
=10,
273 RETURN
=11, T2ESC
=12, ENDCHAR
=14, HSTEMHM
=18,
274 HINTMASK
=19, CNTRMASK
=20, RMOVETO
=21, HMOVETO
=22,
275 VSTEMHM
=23, RCURVELINE
=24, RLINECURVE
=25, VVCURVETO
=26,
276 HHCURVETO
=27, SHORTINT
=28, CALLGSUBR
=29, VHCURVETO
=30,
282 AND
=3, OR
=4, NOT
=5, ABS
=9,
283 ADD
=10, SUB
=11, DIV
=12, NEG
=14,
284 EQ
=15, DROP
=18, PUT
=20, GET
=21,
285 IFELSE
=22, RANDOM
=23, MUL
=24, SQRT
=26,
286 DUP
=27, EXCH
=28, INDEX
=29, ROLL
=30,
287 HFLEX
=34, FLEX
=35, HFLEX1
=36, FLEX1
=37
291 // ====================================================================
295 explicit CffGlobal();
300 int mnStringIdxCount
;
306 int mnGlobalSubrBase
;
307 int mnGlobalSubrCount
;
308 int mnGlobalSubrBias
;
313 IntVector maFontBBox
;
314 //FloatVector maFontMatrix;
321 // ====================================================================
331 int mnLocalSubrCount
;
336 // ATM hinting related values
339 IntVector maStemSnapH
;
340 IntVector maStemSnapV
;
341 IntVector maBlueValues
;
342 IntVector maOtherBlues
;
343 IntVector maFamilyBlues
;
344 IntVector maFamilyOtherBlues
;
353 // ====================================================================
355 class SubsetterContext
358 virtual ~SubsetterContext( void);
359 virtual bool emitAsType1( class Type1Emitter
&,
360 const long* pGlyphIDs
, const U8
* pEncoding
,
361 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& ) = 0;
364 // --------------------------------------------------------------------
366 SubsetterContext::~SubsetterContext( void)
369 // ====================================================================
371 class CffSubsetterContext
372 : public SubsetterContext
376 static const int NMAXSTACK
= 48; // see CFF.appendixB
377 static const int NMAXHINTS
= 2*96; // see CFF.appendixB
378 static const int NMAXTRANS
= 32; // see CFF.appendixB
380 explicit CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
);
381 virtual ~CffSubsetterContext( void);
383 void initialCffRead( void);
384 bool emitAsType1( class Type1Emitter
&,
385 const long* pGlyphIDs
, const U8
* pEncoding
,
386 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& );
388 // used by charstring converter
389 void setCharStringType( int);
390 void fakeLocalSubrCount( int nLocalSubrs
) { maCffLocal
[0].mnLocalSubrCount
=nLocalSubrs
;}
391 void readCharString( const U8
* pTypeOps
, int nTypeLen
);
393 int convert2Type1Ops( CffLocal
*, const U8
* pType2Ops
, int nType2Len
, U8
* pType1Ops
);
395 void readTypeOp( CffSubsetterContext
&);
396 void convertOneTypeOp( void);
397 void convertOneTypeEsc( void);
398 void callType2Subr( bool bGlobal
, int nSubrNumber
);
399 long getReadOfs( void) const { return (long)(mpReadPtr
- mpBasePtr
);}
414 int seekIndexData( int nIndexBase
, int nDataIndex
);
415 void seekIndexEnd( int nIndexBase
);
418 const char** mpCharStringOps
;
419 const char** mpCharStringEscs
;
421 CffLocal maCffLocal
[16];
422 CffLocal
* mpCffLocal
;
424 void readDictOp( void);
425 double readRealVal( void);
426 const char* getString( int nStringID
);
427 int getFDSelect( int nGlyphIndex
) const;
428 int getGlyphSID( int nGlyphIndex
) const;
429 const char* getGlyphName( int nGlyphIndex
);
431 void readTypeOp( void);
432 void read2push( void);
433 void pop2write( void);
434 void writeType1Val( int/*TODO: double*/ nVal
);
435 void writeTypeOp( int nTypeOp
);
436 void writeTypeEsc( int nTypeOp
);
437 void writeCurveTo( int nStackPos
, int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
);
438 void pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
=0);
439 void popAll2Write( int nTypeOp
);
441 public: // TODO: is public really needed?
442 // accessing the value stack
443 // TODO: add more checks
444 void push( int nVal
) { mnValStack
[ mnStackIdx
++] = nVal
;}
445 int pop( void) { return ((mnStackIdx
>0) ? mnValStack
[ --mnStackIdx
] : 0);}
446 int peek( void) { return ((mnStackIdx
>0) ? mnValStack
[ mnStackIdx
-1] : 0);}
447 int get( int nIndex
) { return mnValStack
[ nIndex
];}
448 int size( void) const { return mnStackIdx
;}
449 bool empty( void) const { return !mnStackIdx
;}
450 void clear( void) { mnStackIdx
= 0;}
452 // accessing the charstring hints
453 void addHints( bool bVerticalHints
);
454 int getHorzHintCount( void) const { return (mnHorzHintSize
/2);}
455 int getVertHintCount( void) const { return (mnHintSize
-mnHorzHintSize
)/2;}
456 void getHintPair( int nIndex
, int* nMin
, int* nEnd
) const;
458 // accessing other charstring specifics
459 bool hasCharWidth( void) const { return (mnCharWidth
!= -1);}
460 int getCharWidth( void) const { return mnCharWidth
;}
461 void setNominalWidth( int nWidth
) { mpCffLocal
->mnNominalWidth
= nWidth
;}
462 void setDefaultWidth( int nWidth
) { mpCffLocal
->mnDefaultWidth
= nWidth
;}
463 void updateWidth( bool bUseFirstVal
);
466 // typeop exceution context
468 int mnValStack
[ NMAXSTACK
];
469 int mnTransVals
[ NMAXTRANS
];
473 int mnHintStack
[ NMAXHINTS
];
478 // --------------------------------------------------------------------
480 CffSubsetterContext::CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
)
481 : mpBasePtr( pBasePtr
)
482 , mpBaseEnd( pBasePtr
+nBaseLen
)
488 // setCharStringType( 1);
489 // TODO: new CffLocal[ mnFDAryCount];
490 mpCffLocal
= &maCffLocal
[0];
493 // --------------------------------------------------------------------
495 CffSubsetterContext::~CffSubsetterContext( void)
497 // TODO: delete[] maCffLocal;
500 // --------------------------------------------------------------------
502 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal
)
504 #if 1 // TODO: is this still needed?
505 // the first value is not a hint but the charwidth
510 mnCharWidth
= mpCffLocal
->mnNominalWidth
+ mnValStack
[0];
511 // remove bottom stack entry
513 for( int i
= 0; i
< mnStackIdx
; ++i
)
514 mnValStack
[ i
] = mnValStack
[ i
+1];
516 mnCharWidth
= mpCffLocal
->mnDefaultWidth
;
520 // --------------------------------------------------------------------
522 void CffSubsetterContext::addHints( bool bVerticalHints
)
524 // the first charstring value may a charwidth instead of a charwidth
525 updateWidth( (mnStackIdx
& 1) != 0);
526 // return early (e.g. no implicit hints for hintmask)
530 // copy the remaining values to the hint arrays
531 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
532 if( mnStackIdx
& 1) --mnStackIdx
;//#######
533 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
535 assert( (mnHintSize
+ mnStackIdx
) <= 2*NMAXHINTS
);
538 mnHorzHintSize
+= mnStackIdx
;
541 for( int i
= 0; i
< mnStackIdx
; ++i
) {
542 nHintOfs
+= mnValStack
[ i
];
543 mnHintStack
[ mnHintSize
++] = nHintOfs
;
546 mnHorzHintSize
= mnHintSize
;
547 #endif // IGNORE_HINTS
549 // clear all values from the stack
553 // --------------------------------------------------------------------
555 void CffSubsetterContext::getHintPair( int nIndex
, int* pMin
, int* pEnd
) const
558 assert( nIndex
< mnHintSize
);
559 assert( nIndex
>= 0);
560 const int* pHint
= &mnHintStack
[ nIndex
];
565 // --------------------------------------------------------------------
567 void CffSubsetterContext::setCharStringType( int nVal
)
570 case 1: mpCharStringOps
=pType1Ops
; mpCharStringEscs
=pT1EscOps
; break;
571 case 2: mpCharStringOps
=pType2Ops
; mpCharStringEscs
=pT2EscOps
; break;
572 default: fprintf( stderr
, "Unknown CharstringType=%d\n",nVal
); break;
576 // --------------------------------------------------------------------
578 void CffSubsetterContext::readCharString( const U8
* pTypeOps
, int nTypeLen
)
585 assert( nTypeLen
>= 0);
586 // assert( nEnd <= getLength());
587 mpReadPtr
= pTypeOps
;
588 mpReadEnd
= mpReadPtr
+ nTypeLen
;
589 // reset the execution context
590 while( mpReadPtr
< mpReadEnd
)
592 //### assert( tellRel() == nEnd);
595 // --------------------------------------------------------------------
597 void CffSubsetterContext::readDictOp( void)
600 const U8 c
= *mpReadPtr
;
602 int nOpId
= *(mpReadPtr
++);
603 const char* pCmdName
;
605 pCmdName
= pDictOps
[ nOpId
];
607 const U8 nExtId
= *(mpReadPtr
++);
608 pCmdName
= pDictEscs
[ nExtId
];
609 nOpId
= 900 + nExtId
;
612 //TODO: if( nStackIdx > 0)
614 default: fprintf( stderr
, "unsupported DictOp.type=\'%c\'\n", *pCmdName
); break;
618 case 915: mpCffLocal
->mbForceBold
= nVal
; break; // "ForceBold"
619 default: break; // TODO: handle more boolean dictops?
622 case 'n': // dict-op number
625 case 10: mpCffLocal
->mnStemStdHW
= nVal
; break; // "StdHW"
626 case 11: mpCffLocal
->mnStemStdVW
= nVal
; break; // "StdVW"
627 case 15: mnCharsetBase
= nVal
; break; // "charset"
628 case 16: mnEncodingBase
= nVal
; break; // "nEncoding"
629 case 17: mnCharStrBase
= nVal
; break; // "nCharStrings"
630 case 19: mpCffLocal
->mnLocalSubrOffs
= nVal
; break;// "nSubrs"
631 case 20: setDefaultWidth( nVal
); break; // "defaultWidthX"
632 case 21: setNominalWidth( nVal
); break; // "nominalWidthX"
633 case 909: mpCffLocal
->mfBlueScale
= nVal
; break; // "BlueScale"
634 case 910: mpCffLocal
->mfBlueShift
= nVal
; break; // "BlueShift"
635 case 911: mpCffLocal
->mfBlueFuzz
= nVal
; break; // "BlueFuzz"
636 case 912: mpCffLocal
->mfExpFactor
= nVal
; break; // "ExpansionFactor"
637 case 917: mpCffLocal
->mnLangGroup
= nVal
; break; // "LanguageGroup"
638 case 936: mnFontDictBase
= nVal
; break; // "nFDArray"
639 case 937: mnFDSelectBase
= nVal
; break; // "nFDSelect"
640 default: break; // TODO: handle more numeric dictops?
644 for( int i
= 0; i
< size(); ++i
) {
647 case 5: maFontBBox
.push_back( nVal
); break; // "FontBBox"
649 case 907: maFontMatrix
.push_back( nVal
); break; // "FontMatrix"
651 default: break; // TODO: handle more array dictops?
656 case 'd': { // delta array
658 for( int i
= 0; i
< size(); ++i
) {
661 case 6: mpCffLocal
->maBlueValues
.push_back( nVal
); break; // "BlueValues"
662 case 7: mpCffLocal
->maOtherBlues
.push_back( nVal
); break; // "OtherBlues"
663 case 8: mpCffLocal
->maFamilyBlues
.push_back( nVal
); break; // "FamilyBlues"
664 case 9: mpCffLocal
->maFamilyOtherBlues
.push_back( nVal
); break;// "FamilyOtherBlues"
665 case 912: mpCffLocal
->maStemSnapH
.push_back( nVal
); break; // "StemSnapH"
666 case 913: mpCffLocal
->maStemSnapV
.push_back( nVal
); break; // "StemSnapV"
667 default: break; // TODO: handle more delta-array dictops?
672 case 's': // stringid (SID)
675 case 2: mnFullNameSID
= nVal
; break; // "FullName"
676 case 3: mnFamilyNameSID
= nVal
; break; // "FamilyName"
677 case 938: mnFontNameSID
= nVal
; break; // "FontName"
678 default: break; // TODO: handle more string dictops?
681 case 'P': // private dict
682 mpCffLocal
->mnPrivDictBase
= pop();
683 mpCffLocal
->mnPrivDictSize
= pop();
685 case 'r': { // ROS operands
688 (void)nSid1
; // TODO: use
689 (void)nSid2
; // TODO: use
693 case 't': // CharstringType
695 setCharStringType( nVal
);
702 if( (c
>= 32) || (c
== 28)) {
705 } else if( c
== 29) { // longint
706 ++mpReadPtr
; // skip 29
707 int nS32
= mpReadPtr
[0] << 24;
708 nS32
+= mpReadPtr
[1] << 16;
709 nS32
+= mpReadPtr
[2] << 8;
710 nS32
+= mpReadPtr
[3] << 0;
711 if( (sizeof(nS32
) != 4) && (nS32
& (1<<31)))
712 nS32
|= (~0U) << 31; // assuming 2s complement
716 } else if( c
== 30) { // real number
717 ++mpReadPtr
; // skip 30
718 const double fReal
= readRealVal();
719 // push value onto stack
720 nVal
= static_cast<int>(fReal
+0.5); //TODO!!! allow float on operand stack!
725 // --------------------------------------------------------------------
727 void CffSubsetterContext::readTypeOp( void)
730 const U8 c
= *mpReadPtr
;
731 if( (c
<= 31) && (c
!= 28) ) {
732 const int nOpId
= *(mpReadPtr
++);
733 const char* pCmdName
;
735 pCmdName
= mpCharStringOps
[ nOpId
];
737 const int nExtId
= *(mpReadPtr
++);
738 pCmdName
= mpCharStringEscs
[ nExtId
];
743 // handle typeop parameters
744 int nMinStack
= -1, nMaxStack
= -1;
746 default: fprintf( stderr
, "unsupported TypeOp.type=\'%c\'\n", *pCmdName
); break;
747 case '.': nMinStack
= 0; nMaxStack
= 999; break;
748 case '0': nMinStack
= nMaxStack
= 0; break;
749 case '1': nMinStack
= nMaxStack
= 1; break;
750 case '2': nMinStack
= nMaxStack
= 2; break;
751 case '4': nMinStack
= nMaxStack
= 4; break;
752 case '5': nMinStack
= nMaxStack
= 5; break; // not used for Type2 ops
753 case '6': nMinStack
= nMaxStack
= 6; break;
754 case '7': nMinStack
= nMaxStack
= 7; break;
755 case '9': nMinStack
= nMaxStack
= 9; break;
756 case 'f': nMinStack
= nMaxStack
= 11; break;
757 case 'F': nMinStack
= nMaxStack
= 13; break;
758 case 'A': nMinStack
= 2; nMaxStack
= 999; break;
759 case 'C': nMinStack
= 6; nMaxStack
= 999; break;
760 case 'E': nMinStack
= 1; nMaxStack
= 999; break;
761 case 'G': nMinStack
= 1; nMaxStack
= 999; // global subr
765 case 'L': // local subr
766 nMinStack
= 1; nMaxStack
= 999;
770 case 'I': // operands for "index"
772 nMinStack
= nValStack
[ nStackIdx
-1];
773 if( nMinStack
< 0) nMinStack
= 0;
776 fprintf( stderr
, "TODO: Iindex op\n");
779 case 'R': // operands for "rol"
781 nMinStack
= nValStack
[ nStackIdx
-2];
783 fprintf( stderr
, "TODO: Rrol op\n");
785 case 'X': // operands for "return"
787 nMaxStack
= /*### (!bInSubrs)? 0 :###*/999;
789 case 'H': // "hstemhm"
792 nMinStack
= nMaxStack
= 0;
794 case 'V': // "vstemhm"
797 nMinStack
= nMaxStack
= 0;
799 case 'K': // "hintmask" or "cntrmask"
800 addHints( true); // implicit vstemhm
801 nMinStack
= nMaxStack
= 0;
804 updateWidth( (size() >= 1) && (size() != 4));
805 nMinStack
= nMaxStack
= 0;
807 fprintf( stderr
,"Deprecated SEAC-like endchar is not supported for CFF subsetting!\n"); // TODO: handle deprecated op
809 case 'm': // hmoveto or vmoveto
810 updateWidth( size() > 1);
812 nMaxStack
= nMinStack
;
815 updateWidth( size() > 2);
817 nMaxStack
= nMinStack
;
825 if( (c
>= 32) || (c
== 28)) {
831 // --------------------------------------------------------------------
833 void CffSubsetterContext::read2push( void)
837 const U8
*& p
= mpReadPtr
;
840 short nS16
= (p
[1] << 8) + p
[2];
841 if( (sizeof(nS16
) != 2) && (nS16
& (1<<15)))
842 nS16
|= (~0U) << 15; // assuming 2s complement
845 } else if( c
<= 246) { // -107..+107
848 } else if( c
<= 250) { // +108..+1131
849 nVal
= ((p
[0] << 8) + p
[1]) - 63124;
851 } else if( c
<= 254) { // -108..-1131
852 nVal
= 64148 - ((p
[0] << 8) + p
[1]);
854 } else /*if( c == 255)*/ { // Fixed16.16
855 nVal
= (p
[1] << 8) + p
[2];
856 // TODO: read non-integer part
863 // --------------------------------------------------------------------
865 void CffSubsetterContext::writeType1Val( int/*TODO: double*/ nVal
)
867 U8
* pOut
= mpWritePtr
;
868 if( (nVal
>= -107) && (nVal
<= +107)) {
869 *(pOut
++) = static_cast<U8
>(nVal
+ 139); // -107..+107
870 } else if( (nVal
>= -1131) && (nVal
<= +1131)) {
872 nVal
+= 63124; // +108..+1131
874 nVal
= 64148 - nVal
; // -108..-1131
875 *(pOut
++) = static_cast<U8
>(nVal
>> 8);
876 *(pOut
++) = static_cast<U8
>(nVal
);
878 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
880 *(pOut
++) = static_cast<U8
>(nVal
>> 24);
881 *(pOut
++) = static_cast<U8
>(nVal
>> 16);
882 *(pOut
++) = static_cast<U8
>(nVal
>> 8);
883 *(pOut
++) = static_cast<U8
>(nVal
);
889 // --------------------------------------------------------------------
891 inline void CffSubsetterContext::pop2write( void)
894 writeType1Val( nVal
);
897 // --------------------------------------------------------------------
899 inline void CffSubsetterContext::writeTypeOp( int nTypeOp
)
901 *(mpWritePtr
++) = static_cast<U8
>(nTypeOp
);
904 // --------------------------------------------------------------------
906 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc
)
908 *(mpWritePtr
++) = TYPE1OP::T1ESC
;
909 *(mpWritePtr
++) = static_cast<U8
>(nTypeEsc
);
912 // --------------------------------------------------------------------
914 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
)
916 for( int i
= 0; i
< mnStackIdx
;) {
917 for( int j
= 0; j
< nArgsPerTypo
; ++j
) {
918 int nVal
= mnValStack
[i
+j
];
919 writeType1Val( nVal
);
922 writeTypeOp( nTypeOp
);
923 nTypeOp
^= nTypeXor
; // for toggling vlineto/hlineto
928 // --------------------------------------------------------------------
930 void CffSubsetterContext::popAll2Write( int nTypeOp
)
932 // pop in reverse order, then write
933 for( int i
= 0; i
< mnStackIdx
; ++i
) {
934 int nVal
= mnValStack
[i
];
935 writeType1Val( nVal
);
938 writeTypeOp( nTypeOp
);
941 // --------------------------------------------------------------------
943 void CffSubsetterContext::writeCurveTo( int nStackPos
,
944 int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
)
946 // get the values from the stack
947 const int nDX1
= nIX1
? mnValStack
[ nStackPos
+nIX1
] : 0;
948 const int nDY1
= nIY1
? mnValStack
[ nStackPos
+nIY1
] : 0;
949 const int nDX2
= nIX2
? mnValStack
[ nStackPos
+nIX2
] : 0;
950 const int nDY2
= nIY2
? mnValStack
[ nStackPos
+nIY2
] : 0;
951 const int nDX3
= nIX3
? mnValStack
[ nStackPos
+nIX3
] : 0;
952 const int nDY3
= nIY3
? mnValStack
[ nStackPos
+nIY3
] : 0;
954 // emit the curveto operator and operands
955 // TODO: determine the most efficient curveto operator
956 // TODO: depending on type1op or type2op target
957 writeType1Val( nDX1
);
958 writeType1Val( nDY1
);
959 writeType1Val( nDX2
);
960 writeType1Val( nDY2
);
961 writeType1Val( nDX3
);
962 writeType1Val( nDY3
);
963 writeTypeOp( TYPE1OP::RCURVETO
);
966 // --------------------------------------------------------------------
968 void CffSubsetterContext::convertOneTypeOp( void)
970 const int nType2Op
= *(mpReadPtr
++);
972 int i
, nVal
; // prevent WAE for declarations inside switch cases
980 addHints( nType2Op
== TYPE2OP::VSTEM
);
982 for( i
= 0; i
< mnHintSize
; i
+=2) {
983 writeType1Val( mnHintStack
[i
]);
984 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
985 writeTypeOp( nType2Op
);
987 #endif // IGNORE_HINTS
989 case TYPE2OP::HSTEMHM
:
990 case TYPE2OP::VSTEMHM
:
991 addHints( nType2Op
== TYPE2OP::VSTEMHM
);
993 case TYPE2OP::CNTRMASK
:
994 // TODO: replace cntrmask with vstem3/hstem3
997 mpReadPtr
+= (mnHintSize
+ 15) / 16;
998 mbIgnoreHints
= true;
1003 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
1005 nMaskByte
= *(mpReadPtr
++);
1008 if( !(nMaskByte
& nMaskBit
))
1010 if( i
>= 8*(int)sizeof(mnCntrMask
))
1011 mbIgnoreHints
= true;
1014 mnCntrMask
|= (1U << i
);
1019 case TYPE2OP::HINTMASK
:
1022 mpReadPtr
+= (mnHintSize
+ 15) / 16;
1026 int nCntrBits
[2] = {0,0};
1029 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
1031 nMaskByte
= *(mpReadPtr
++);
1034 if( !(nMaskByte
& nMaskBit
))
1036 if( i
>= 8*(int)sizeof(nHintMask
))
1037 mbIgnoreHints
= true;
1040 nHintMask
|= (1U << i
);
1041 nCntrBits
[ i
< mnHorzHintSize
] += (mnCntrMask
>> i
) & 1;
1044 mbIgnoreHints
|= (nCntrBits
[0] && (nCntrBits
[0] != 3));
1045 mbIgnoreHints
|= (nCntrBits
[1] && (nCntrBits
[1] != 3));
1049 for( i
= 0; i
< mnHintSize
; i
+=2) {
1050 if( !(nHintMask
& (1U << i
)))
1052 writeType1Val( mnHintStack
[i
]);
1053 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
1054 const bool bHorz
= (i
< mnHorzHintSize
);
1055 if( !nCntrBits
[ bHorz
])
1056 writeTypeOp( bHorz
? TYPE1OP::HSTEM
: TYPE1OP::VSTEM
);
1057 else if( !--nCntrBits
[ bHorz
])
1058 writeTypeEsc( bHorz
? TYPE1OP::HSTEM3
: TYPE1OP::VSTEM3
);
1063 case TYPE2OP::CALLSUBR
:
1064 case TYPE2OP::CALLGSUBR
:
1067 const bool bGlobal
= (nType2Op
== TYPE2OP::CALLGSUBR
);
1068 callType2Subr( bGlobal
, nVal
);
1071 case TYPE2OP::RETURN
:
1072 // TODO: check that we are in a subroutine
1074 case TYPE2OP::VMOVETO
:
1075 case TYPE2OP::HMOVETO
:
1077 writeTypeOp( TYPE1OP::CLOSEPATH
);
1079 updateWidth( size() > 1);
1081 pop2MultiWrite( 1, nType2Op
);
1083 case TYPE2OP::VLINETO
:
1084 case TYPE2OP::HLINETO
:
1085 pop2MultiWrite( 1, nType2Op
,
1086 TYPE1OP::VLINETO
^ TYPE1OP::HLINETO
);
1088 case TYPE2OP::RMOVETO
:
1089 // TODO: convert rmoveto to vlineto/hlineto if possible
1091 writeTypeOp( TYPE1OP::CLOSEPATH
);
1093 updateWidth( size() > 2);
1095 pop2MultiWrite( 2, nType2Op
);
1097 case TYPE2OP::RLINETO
:
1098 // TODO: convert rlineto to vlineto/hlineto if possible
1099 pop2MultiWrite( 2, nType2Op
);
1101 case TYPE2OP::RCURVETO
:
1102 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
1103 pop2MultiWrite( 6, nType2Op
);
1105 case TYPE2OP::RCURVELINE
:
1107 while( (i
+= 6) <= mnStackIdx
)
1108 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
1110 while( (i
+= 2) <= mnStackIdx
) {
1111 writeType1Val( mnValStack
[i
-2]);
1112 writeType1Val( mnValStack
[i
-1]);
1113 writeTypeOp( TYPE2OP::RLINETO
);
1117 case TYPE2OP::RLINECURVE
:
1119 while( (i
+= 2) <= mnStackIdx
-6) {
1120 writeType1Val( mnValStack
[i
-2]);
1121 writeType1Val( mnValStack
[i
-1]);
1122 writeTypeOp( TYPE2OP::RLINETO
);
1125 while( (i
+= 6) <= mnStackIdx
)
1126 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
1129 case TYPE2OP::VHCURVETO
:
1130 case TYPE2OP::HVCURVETO
:
1132 bool bVert
= (nType2Op
== TYPE2OP::VHCURVETO
);
1136 nVal
= mnValStack
[ --mnStackIdx
];
1137 while( (i
+= 4) <= mnStackIdx
) {
1138 // TODO: use writeCurveTo()
1139 if( bVert
) writeType1Val( 0);
1140 writeType1Val( mnValStack
[i
-4]);
1141 if( !bVert
) writeType1Val( 0);
1142 writeType1Val( mnValStack
[i
-3]);
1143 writeType1Val( mnValStack
[i
-2]);
1144 if( !bVert
) writeType1Val( (i
==mnStackIdx
) ? nVal
: 0);
1145 writeType1Val( mnValStack
[i
-1]);
1146 if( bVert
) writeType1Val( (i
==mnStackIdx
) ? nVal
: 0 );
1148 writeTypeOp( TYPE2OP::RCURVETO
);
1153 case TYPE2OP::HHCURVETO
:
1154 i
= (mnStackIdx
& 1);
1155 while( (i
+= 4) <= mnStackIdx
) {
1157 writeCurveTo( i
, -4, 0, -3, -2, -1, 0);
1159 writeCurveTo( i
, -4, -5, -3, -2, -1, 0);
1163 case TYPE2OP::VVCURVETO
:
1164 i
= (mnStackIdx
& 1);
1165 while( (i
+= 4) <= mnStackIdx
) {
1167 writeCurveTo( i
, 0, -4, -3, -2, 0, -1);
1169 writeCurveTo( i
, -5, -4, -3, -2, 0, -1);
1173 case TYPE2OP::ENDCHAR
:
1175 writeTypeOp( TYPE1OP::CLOSEPATH
);
1177 updateWidth( size() >= 1);
1178 // mbNeedClose = true;
1179 writeTypeOp( TYPE1OP::ENDCHAR
);
1182 if( ((nType2Op
>= 32) && (nType2Op
<= 255)) || (nType2Op
== 28)) {
1186 popAll2Write( nType2Op
);
1187 assert( false); // TODO?
1193 // --------------------------------------------------------------------
1195 void CffSubsetterContext::convertOneTypeEsc( void)
1197 const int nType2Esc
= *(mpReadPtr
++);
1198 int* pTop
= &mnValStack
[ mnStackIdx
-1];
1199 // convert each T2op
1200 switch( nType2Esc
) {
1202 assert( mnStackIdx
>= 2);
1203 pTop
[0] &= pTop
[-1];
1207 assert( mnStackIdx
>= 2);
1208 pTop
[0] |= pTop
[-1];
1212 assert( mnStackIdx
>= 1);
1216 assert( mnStackIdx
>= 1);
1221 assert( mnStackIdx
>= 1);
1225 assert( mnStackIdx
>= 2);
1226 pTop
[0] += pTop
[-1];
1230 assert( mnStackIdx
>= 2);
1231 pTop
[0] -= pTop
[-1];
1235 assert( mnStackIdx
>= 2);
1237 pTop
[0] *= pTop
[-1];
1241 assert( mnStackIdx
>= 2);
1243 pTop
[0] /= pTop
[-1];
1247 assert( mnStackIdx
>= 2);
1248 pTop
[0] = (pTop
[0] == pTop
[-1]);
1252 assert( mnStackIdx
>= 1);
1255 case TYPE2OP::PUT
: {
1256 assert( mnStackIdx
>= 2);
1257 const int nIdx
= pTop
[0];
1259 assert( nIdx
< NMAXTRANS
);
1260 mnTransVals
[ nIdx
] = pTop
[-1];
1264 case TYPE2OP::GET
: {
1265 assert( mnStackIdx
>= 1);
1266 const int nIdx
= pTop
[0];
1268 assert( nIdx
< NMAXTRANS
);
1269 pTop
[0] = mnTransVals
[ nIdx
];
1272 case TYPE2OP::IFELSE
: {
1273 assert( mnStackIdx
>= 4);
1274 if( pTop
[-1] > pTop
[0])
1275 pTop
[-3] = pTop
[-2];
1279 case TYPE2OP::RANDOM
:
1280 pTop
[+1] = 1234; // TODO
1287 assert( mnStackIdx
>= 1);
1291 case TYPE2OP::EXCH
: {
1292 assert( mnStackIdx
>= 2);
1293 const int nVal
= pTop
[0];
1298 case TYPE2OP::INDEX
: {
1299 assert( mnStackIdx
>= 1);
1300 const int nVal
= pTop
[0];
1302 assert( nVal
< mnStackIdx
-1);
1303 pTop
[0] = pTop
[-1-nVal
];
1306 case TYPE2OP::ROLL
: {
1307 assert( mnStackIdx
>= 1);
1308 const int nNum
= pTop
[0];
1310 assert( nNum
< mnStackIdx
-2);
1311 (void)nNum
; // TODO: implement
1312 const int nOfs
= pTop
[-1];
1314 (void)nOfs
;// TODO: implement
1317 case TYPE2OP::HFLEX1
: {
1318 assert( mnStackIdx
== 9);
1319 writeCurveTo( mnStackIdx
, -9, -8, -7, -6, -5, -6);
1320 writeCurveTo( mnStackIdx
, -4, -6, -3, -2, -1, -8);
1324 case TYPE2OP::HFLEX
: {
1325 assert( mnStackIdx
== 7);
1326 writeCurveTo( mnStackIdx
, -7, 0, -6, -5, -4, -5);
1327 writeCurveTo( mnStackIdx
, -3, -5, -2, 0, -1, 0);
1331 case TYPE2OP::FLEX
: {
1332 assert( mnStackIdx
== 13);
1333 writeCurveTo( mnStackIdx
, -13, -12, -11, -10, -9, -8);
1334 writeCurveTo( mnStackIdx
, -7, -6, -5, -4, -3, -2);
1335 const int nFlexDepth
= mnValStack
[ mnStackIdx
-1];
1336 (void)nFlexDepth
; // ignoring nFlexDepth
1340 case TYPE2OP::FLEX1
: {
1341 assert( mnStackIdx
== 11);
1342 // write the first part of the flex1-hinted curve
1343 writeCurveTo( mnStackIdx
, -11, -10, -9, -8, -7, -6);
1345 // determine if nD6 is horizontal or vertical
1346 const int i
= mnStackIdx
;
1347 int nDeltaX
= mnValStack
[i
-11] + mnValStack
[i
-9] + mnValStack
[i
-7] + mnValStack
[i
-5] + mnValStack
[i
-3];
1348 if( nDeltaX
< 0 ) nDeltaX
= -nDeltaX
;
1349 int nDeltaY
= mnValStack
[i
-10] + mnValStack
[i
-8] + mnValStack
[i
-6] + mnValStack
[i
-4] + mnValStack
[i
-2];
1350 if( nDeltaY
< 0 ) nDeltaY
= -nDeltaY
;
1351 const bool bVertD6
= (nDeltaY
> nDeltaX
);
1353 // write the second part of the flex1-hinted curve
1355 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, -1, 0);
1357 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, 0, -1);
1362 fprintf( stderr
,"unhandled type2esc %d\n", nType2Esc
);
1368 // --------------------------------------------------------------------
1370 void CffSubsetterContext::callType2Subr( bool bGlobal
, int nSubrNumber
)
1372 const U8
* const pOldReadPtr
= mpReadPtr
;
1373 const U8
* const pOldReadEnd
= mpReadEnd
;
1377 nSubrNumber
+= mnGlobalSubrBias
;
1378 nLen
= seekIndexData( mnGlobalSubrBase
, nSubrNumber
);
1380 nSubrNumber
+= mpCffLocal
->mnLocalSubrBias
;
1381 nLen
= seekIndexData( mpCffLocal
->mnLocalSubrBase
, nSubrNumber
);
1384 while( mpReadPtr
< mpReadEnd
)
1387 mpReadPtr
= pOldReadPtr
;
1388 mpReadEnd
= pOldReadEnd
;
1391 // --------------------------------------------------------------------
1393 static const int MAX_T1OPS_SIZE
= 81920; // TODO: use dynamic value
1395 int CffSubsetterContext::convert2Type1Ops( CffLocal
* pCffLocal
, const U8
* const pT2Ops
, int nT2Len
, U8
* const pT1Ops
)
1397 mpCffLocal
= pCffLocal
;
1399 // prepare the charstring conversion
1400 mpWritePtr
= pT1Ops
;
1401 #if 1 // TODO: update caller
1402 U8 aType1Ops
[ MAX_T1OPS_SIZE
];
1404 mpWritePtr
= aType1Ops
;
1405 *const_cast<U8
**>(&pT1Ops
) = mpWritePtr
;
1410 // prepend random seed for T1crypt
1411 *(mpWritePtr
++) = 0x48;
1412 *(mpWritePtr
++) = 0x44;
1413 *(mpWritePtr
++) = 0x55;
1414 *(mpWritePtr
++) = ' ';
1415 #if 1 // convert the Type2 charstring to Type1
1417 mpReadEnd
= pT2Ops
+ nT2Len
;
1418 // prepend "hsbw" or "sbw"
1419 // TODO: only emit hsbw when charwidth is known
1420 // TODO: remove charwidth from T2 stack
1421 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
1422 writeType1Val( 1000/*###getCharWidth()###*/);
1423 writeTypeOp( TYPE1OP::HSBW
);
1425 mbNeedClose
= false;
1426 mbIgnoreHints
= false;
1427 mnHintSize
=mnHorzHintSize
=mnStackIdx
=0; mnCharWidth
=-1;//#######
1429 while( mpReadPtr
< mpReadEnd
)
1432 // writeTypeOp( TYPE1OP::CLOSEPATH);
1434 // writeTypeOp( TYPE1OP::RETURN);
1436 mpWritePtr
= pT1Ops
+4;
1437 // create an "idiotproof" charstring
1439 writeType1Val( 800);
1440 writeTypeOp( TYPE1OP::HSBW
);
1442 writeTypeOp( TYPE1OP::HMOVETO
);
1443 writeType1Val( 650);
1444 writeType1Val( 100);
1445 writeTypeOp( TYPE1OP::RLINETO
);
1446 writeType1Val( -350);
1447 writeType1Val( 700);
1448 writeTypeOp( TYPE1OP::RLINETO
);
1450 writeType1Val( -300);
1451 writeType1Val( -800);
1452 writeTypeOp( TYPE1OP::RLINETO
);
1454 writeTypeOp( TYPE1OP::CLOSEPATH
);
1456 writeTypeOp( TYPE1OP::ENDCHAR
);
1458 #else // useful for manually encoding charstrings
1459 mpWritePtr
= pT1Ops
;
1460 mpWritePtr
+= sprintf( (char*)mpWritePtr
, "OOo_\x8b\x8c\x0c\x10\x0b");
1462 const int nType1Len
= mpWritePtr
- pT1Ops
;
1464 // encrypt the Type1 charstring
1465 int nRDCryptR
= 4330; // TODO: mnRDCryptSeed;
1466 for( U8
* p
= pT1Ops
; p
< mpWritePtr
; ++p
) {
1467 *p
^= (nRDCryptR
>> 8);
1468 nRDCryptR
= (*(U8
*)p
+ nRDCryptR
) * 52845 + 22719;
1474 // --------------------------------------------------------------------
1476 double CffSubsetterContext::readRealVal()
1478 // TODO: more thorough number validity test
1479 bool bComma
= false;
1483 double fReal
= +1.0;
1485 const U8 c
= *(mpReadPtr
++); // read nibbles
1486 // parse high nibble
1487 const U8 nH
= c
>> 4U;
1489 nNumber
= nNumber
* 10 + nH
;
1491 } else if( nH
== 10) { // comma
1494 } else if( nH
== 11) { // +exp
1498 } else if( nH
== 12) { // -exp
1502 } else if( nH
== 13) { // reserved
1503 // TODO: ignore or error?
1504 } else if( nH
== 14) // minus
1506 else if( nH
== 15) // end
1509 const U8 nL
= c
& 0x0F;
1511 nNumber
= nNumber
* 10 + nL
;
1513 } else if( nL
== 10) { // comma
1516 } else if( nL
== 11) { // +exp
1520 } else if( nL
== 12) { // -exp
1524 } else if( nL
== 13) { // reserved
1525 // TODO: ignore or error?
1526 } else if( nL
== 14) // minus
1528 else if( nL
== 15) // end
1535 if( !nExpSign
) { fReal
*= nNumber
;}
1536 else if( nExpSign
> 0) { nExpVal
+= static_cast<int>(nNumber
);}
1537 else if( nExpSign
< 0) { nExpVal
-= static_cast<int>(nNumber
);}
1540 if( !nExpVal
) { /*nothing to apply*/}
1541 else if( nExpVal
> 0) { while( --nExpVal
>= 0) fReal
*= 10.0;}
1542 else if( nExpVal
< 0) { while( ++nExpVal
<= 0) fReal
/= 10.0;}
1546 // --------------------------------------------------------------------
1548 // prepare to access an element inside a CFF/CID index table
1549 int CffSubsetterContext::seekIndexData( int nIndexBase
, int nDataIndex
)
1553 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1554 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1555 if( nDataIndex
>= nDataCount
)
1557 const int nDataOfsSz
= mpReadPtr
[2];
1558 mpReadPtr
+= 3 + (nDataOfsSz
* nDataIndex
);
1560 switch( nDataOfsSz
) {
1561 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return -1;
1562 case 1: nOfs1
= mpReadPtr
[0]; break;
1563 case 2: nOfs1
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1564 case 3: nOfs1
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1565 case 4: nOfs1
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1567 mpReadPtr
+= nDataOfsSz
;
1570 switch( nDataOfsSz
) {
1571 case 1: nOfs2
= mpReadPtr
[0]; break;
1572 case 2: nOfs2
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1573 case 3: nOfs2
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1574 case 4: nOfs2
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1577 mpReadPtr
= mpBasePtr
+ (nIndexBase
+ 2) + nDataOfsSz
* (nDataCount
+ 1) + nOfs1
;
1578 mpReadEnd
= mpReadPtr
+ (nOfs2
- nOfs1
);
1579 assert( nOfs1
>= 0);
1580 assert( nOfs2
>= nOfs1
);
1581 assert( mpReadEnd
<= mpBaseEnd
);
1582 return (nOfs2
- nOfs1
);
1585 // --------------------------------------------------------------------
1587 // skip over a CFF/CID index table
1588 void CffSubsetterContext::seekIndexEnd( int nIndexBase
)
1590 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1591 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1592 const int nDataOfsSz
= mpReadPtr
[2];
1593 mpReadPtr
+= 3 + nDataOfsSz
* nDataCount
;
1595 switch( nDataOfsSz
) {
1596 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return;
1597 case 1: nEndOfs
= mpReadPtr
[0]; break;
1598 case 2: nEndOfs
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1599 case 3: nEndOfs
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2];break;
1600 case 4: nEndOfs
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1602 mpReadPtr
+= nDataOfsSz
;
1603 mpReadPtr
+= nEndOfs
- 1;
1604 mpReadEnd
= mpBaseEnd
;
1607 // ====================================================================
1609 // initialize FONTDICT specific values
1610 CffLocal::CffLocal( void)
1611 : mnPrivDictBase( 0)
1612 , mnPrivDictSize( 0)
1613 , mnLocalSubrOffs( 0)
1614 , mnLocalSubrBase( 0)
1615 , mnLocalSubrCount( 0)
1616 , mnLocalSubrBias( 0)
1617 , mnNominalWidth( 0)
1618 , mnDefaultWidth( 0)
1626 , mbForceBold( false)
1628 maStemSnapH
.clear();
1629 maStemSnapV
.clear();
1630 maBlueValues
.clear();
1631 maOtherBlues
.clear();
1632 maFamilyBlues
.clear();
1633 maFamilyOtherBlues
.clear();
1636 // --------------------------------------------------------------------
1638 CffGlobal::CffGlobal( void)
1640 , mnNameIdxCount( 0)
1641 , mnStringIdxBase( 0)
1642 , mnStringIdxCount( 0)
1645 , mnCharStrCount( 0)
1646 , mnEncodingBase( 0)
1648 , mnGlobalSubrBase( 0)
1649 , mnGlobalSubrCount( 0)
1650 , mnGlobalSubrBias( 0)
1651 , mnFDSelectBase( 0)
1652 , mnFontDictBase( 0)
1656 , mnFamilyNameSID( 0)
1659 // TODO; maFontMatrix.clear();
1662 // --------------------------------------------------------------------
1664 void CffSubsetterContext::initialCffRead( void)
1666 // get the CFFHeader
1667 mpReadPtr
= mpBasePtr
;
1668 const U8 nVerMajor
= *(mpReadPtr
++);
1669 const U8 nVerMinor
= *(mpReadPtr
++);
1670 const U8 nHeaderSize
= *(mpReadPtr
++);
1671 const U8 nOffsetSize
= *(mpReadPtr
++);
1672 // TODO: is the version number useful for anything else?
1673 assert( (nVerMajor
== 1) && (nVerMinor
== 0));
1674 (void)(nVerMajor
+ nVerMinor
+ nOffsetSize
); // avoid compiler warnings
1676 // prepare access to the NameIndex
1677 mnNameIdxBase
= nHeaderSize
;
1678 mpReadPtr
= mpBasePtr
+ nHeaderSize
;
1679 mnNameIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1680 seekIndexEnd( mnNameIdxBase
);
1682 // get the TopDict index
1683 const long nTopDictBase
= getReadOfs();
1684 const int nTopDictCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1685 if( nTopDictCount
) {
1686 for( int i
= 0; i
< nTopDictCount
; ++i
) {
1687 seekIndexData( nTopDictBase
, i
);
1688 while( mpReadPtr
< mpReadEnd
)
1690 assert( mpReadPtr
== mpReadEnd
);
1694 // prepare access to the String index
1695 mnStringIdxBase
= getReadOfs();
1696 mnStringIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1697 seekIndexEnd( mnStringIdxBase
);
1699 // prepare access to the GlobalSubr index
1700 mnGlobalSubrBase
= getReadOfs();
1701 mnGlobalSubrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1702 mnGlobalSubrBias
= (mnGlobalSubrCount
<1240)?107:(mnGlobalSubrCount
<33900)?1131:32768;
1703 // skip past the last GlobalSubr entry
1704 // seekIndexEnd( mnGlobalSubrBase);
1706 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1707 // seekEncodingsEnd( mnEncodingBase);
1708 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1709 // seekCharsetsEnd( mnCharStrBase);
1710 // get/skip FDSelect (CID only) data
1712 // prepare access to the CharStrings index (we got the base from TOPDICT)
1713 mpReadPtr
= mpBasePtr
+ mnCharStrBase
;
1714 mnCharStrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1715 // seekIndexEnd( mnCharStrBase);
1717 // read the FDArray index (CID only)
1719 // assert( mnFontDictBase == tellRel());
1720 mpReadPtr
= mpBasePtr
+ mnFontDictBase
;
1721 mnFDAryCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1722 assert( mnFDAryCount
< (int)(sizeof(maCffLocal
)/sizeof(*maCffLocal
)));
1724 // read FDArray details to get access to the PRIVDICTs
1725 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1726 mpCffLocal
= &maCffLocal
[i
];
1727 seekIndexData( mnFontDictBase
, i
);
1728 while( mpReadPtr
< mpReadEnd
)
1730 assert( mpReadPtr
== mpReadEnd
);
1734 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1735 mpCffLocal
= &maCffLocal
[i
];
1737 // get the PrivateDict index
1738 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1739 if( mpCffLocal
->mnPrivDictSize
!= 0) {
1740 assert( mpCffLocal
->mnPrivDictSize
> 0);
1741 // get the PrivDict data
1742 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnPrivDictBase
;
1743 mpReadEnd
= mpReadPtr
+ mpCffLocal
->mnPrivDictSize
;
1744 assert( mpReadEnd
<= mpBaseEnd
);
1745 // read PrivDict details
1746 while( mpReadPtr
< mpReadEnd
)
1750 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1751 if( mpCffLocal
->mnLocalSubrOffs
) {
1752 // read LocalSubrs summary
1753 mpCffLocal
->mnLocalSubrBase
= mpCffLocal
->mnPrivDictBase
+ mpCffLocal
->mnLocalSubrOffs
;
1754 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnLocalSubrBase
;
1755 const int nSubrCount
= (mpReadPtr
[0] << 8) + mpReadPtr
[1];
1756 mpCffLocal
->mnLocalSubrCount
= nSubrCount
;
1757 mpCffLocal
->mnLocalSubrBias
= (nSubrCount
<1240)?107:(nSubrCount
<33900)?1131:32768;
1758 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1762 // ignore the Notices info
1765 // --------------------------------------------------------------------
1767 // get a cstring from a StringID
1768 const char* CffSubsetterContext::getString( int nStringID
)
1770 // get a standard string if possible
1771 const static int nStdStrings
= sizeof(pStringIds
)/sizeof(*pStringIds
);
1772 if( (nStringID
>= 0) && (nStringID
< nStdStrings
))
1773 return pStringIds
[ nStringID
];
1775 // else get the string from the StringIndex table
1776 const U8
* pReadPtr
= mpReadPtr
;
1777 const U8
* pReadEnd
= mpReadEnd
;
1778 nStringID
-= nStdStrings
;
1779 int nLen
= seekIndexData( mnStringIdxBase
, nStringID
);
1780 // assert( nLen >= 0);
1781 // TODO: just return the undecorated name
1782 // TODO: get rid of static char buffer
1783 static char aNameBuf
[ 2560];
1785 sprintf( aNameBuf
, "name[%d].notfound!", nStringID
);
1787 const int nMaxLen
= sizeof(aNameBuf
) - 1;
1788 if( nLen
>= nMaxLen
)
1790 for( int i
= 0; i
< nLen
; ++i
)
1791 aNameBuf
[i
] = *(mpReadPtr
++);
1792 aNameBuf
[ nLen
] = '\0';
1794 mpReadPtr
= pReadPtr
;
1795 mpReadEnd
= pReadEnd
;
1799 // --------------------------------------------------------------------
1801 // access a CID's FDSelect table
1802 int CffSubsetterContext::getFDSelect( int nGlyphIndex
) const
1804 assert( nGlyphIndex
>= 0);
1805 assert( nGlyphIndex
< mnCharStrCount
);
1809 const U8
* pReadPtr
= mpBasePtr
+ mnFDSelectBase
;
1810 const U8 nFDSelFormat
= *(pReadPtr
++);
1811 switch( nFDSelFormat
) {
1812 case 0: { // FDSELECT format 0
1813 pReadPtr
+= nGlyphIndex
;
1814 const U8 nFDIdx
= *(pReadPtr
++);
1817 case 3: { // FDSELECT format 3
1818 const U16 nRangeCount
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1819 assert( nRangeCount
> 0);
1820 assert( nRangeCount
<= mnCharStrCount
);
1821 U16 nPrev
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1822 assert( nPrev
== 0);
1824 // TODO? binary search
1825 for( int i
= 0; i
< nRangeCount
; ++i
) {
1826 const U8 nFDIdx
= pReadPtr
[0];
1827 const U16 nNext
= (pReadPtr
[1]<<8) + pReadPtr
[2];
1828 assert( nPrev
< nNext
);
1829 if( nGlyphIndex
< nNext
)
1835 default: // invalid FDselect format
1836 fprintf( stderr
, "invalid CFF.FdselType=%d\n", nFDSelFormat
);
1844 // --------------------------------------------------------------------
1846 int CffSubsetterContext::getGlyphSID( int nGlyphIndex
) const
1848 if( nGlyphIndex
== 0)
1849 return 0; // ".notdef"
1850 assert( nGlyphIndex
>= 0);
1851 assert( nGlyphIndex
< mnCharStrCount
);
1852 if( (nGlyphIndex
< 0) || (nGlyphIndex
>= mnCharStrCount
))
1855 // get the SID/CID from the Charset table
1856 const U8
* pReadPtr
= mpBasePtr
+ mnCharsetBase
;
1857 const U8 nCSetFormat
= *(pReadPtr
++);
1858 int nGlyphsToSkip
= nGlyphIndex
- 1;
1859 switch( nCSetFormat
) {
1860 case 0: // charset format 0
1861 pReadPtr
+= 2 * nGlyphsToSkip
;
1864 case 1: // charset format 1
1865 while( nGlyphsToSkip
>= 0) {
1866 const int nLeft
= pReadPtr
[2];
1867 if( nGlyphsToSkip
<= nLeft
)
1869 nGlyphsToSkip
-= nLeft
+ 1;
1873 case 2: // charset format 2
1874 while( nGlyphsToSkip
>= 0) {
1875 const int nLeft
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1876 if( nGlyphsToSkip
<= nLeft
)
1878 nGlyphsToSkip
-= nLeft
+ 1;
1883 fprintf( stderr
, "ILLEGAL CFF-Charset format %d\n", nCSetFormat
);
1887 int nSID
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1888 nSID
+= nGlyphsToSkip
;
1889 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1893 // --------------------------------------------------------------------
1895 // NOTE: the result becomes invalid with the next call to this method
1896 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex
)
1898 // the first glyph is always the .notdef glyph
1899 const char* pGlyphName
= ".notdef";
1900 if( nGlyphIndex
== 0)
1903 // prepare a result buffer
1904 // TODO: get rid of static buffer
1905 static char aDefaultGlyphName
[64];
1906 pGlyphName
= aDefaultGlyphName
;
1908 // get the glyph specific name
1909 const int nSID
= getGlyphSID( nGlyphIndex
);
1910 if( nSID
< 0) // default glyph name
1911 sprintf( aDefaultGlyphName
, "gly%03d", nGlyphIndex
);
1912 else if( mbCIDFont
) // default glyph name in CIDs
1913 sprintf( aDefaultGlyphName
, "cid%03d", nSID
);
1914 else { // glyph name from string table
1915 const char* pSidName
= getString( nSID
);
1916 // check validity of glyph name
1918 const char* p
= pSidName
;
1919 while( (*p
>= '0') && (*p
<= 'z')) ++p
;
1920 if( (p
>= pSidName
+1) && (*p
== '\0'))
1921 pGlyphName
= pSidName
;
1923 // if needed invent a fallback name
1924 if( pGlyphName
!= pSidName
)
1925 sprintf( aDefaultGlyphName
, "bad%03d", nSID
);
1931 // --------------------------------------------------------------------
1936 explicit Type1Emitter( const char* pOutFileName
, bool bPfbSubset
= true);
1937 explicit Type1Emitter( FILE* pOutFile
, bool bPfbSubset
= true);
1938 /*virtual*/ ~Type1Emitter( void);
1939 void setSubsetName( const char* );
1941 void emitRawData( const char* pData
, int nLength
) const;
1942 void emitAllRaw( void);
1943 void emitAllHex( void);
1944 void emitAllCrypted( void);
1945 int tellPos( void) const;
1946 void updateLen( int nTellPos
, int nLength
);
1947 void emitIntVector( const char* pLineHead
, const char* pLineTail
, const IntVector
&);
1950 bool mbCloseOutfile
;
1951 char maBuffer
[MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
1956 char maSubsetName
[256];
1961 // --------------------------------------------------------------------
1963 Type1Emitter::Type1Emitter( const char* pPfbFileName
, bool bPfbSubset
)
1965 , mbCloseOutfile( true)
1966 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1968 , mbPfbSubset( bPfbSubset
)
1971 mpFileOut
= fopen( pPfbFileName
, "wb");
1972 maSubsetName
[0] = '\0';
1975 // --------------------------------------------------------------------
1977 Type1Emitter::Type1Emitter( FILE* pOutFile
, bool bPfbSubset
)
1978 : mpFileOut( pOutFile
)
1979 , mbCloseOutfile( false)
1980 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1982 , mbPfbSubset( bPfbSubset
)
1985 maSubsetName
[0] = '\0';
1988 // --------------------------------------------------------------------
1990 Type1Emitter::~Type1Emitter( void)
1994 if( mbCloseOutfile
)
1999 // --------------------------------------------------------------------
2001 void Type1Emitter::setSubsetName( const char* pSubsetName
)
2003 maSubsetName
[0] = '\0';
2005 strncpy( maSubsetName
, pSubsetName
, sizeof(maSubsetName
));
2006 maSubsetName
[sizeof(maSubsetName
)-1] = '\0';
2009 // --------------------------------------------------------------------
2011 int Type1Emitter::tellPos( void) const
2013 int nTellPos
= ftell( mpFileOut
);
2017 // --------------------------------------------------------------------
2019 void Type1Emitter::updateLen( int nTellPos
, int nLength
)
2021 // update PFB segment header length
2023 cData
[0] = static_cast<U8
>(nLength
>> 0);
2024 cData
[1] = static_cast<U8
>(nLength
>> 8);
2025 cData
[2] = static_cast<U8
>(nLength
>> 16);
2026 cData
[3] = static_cast<U8
>(nLength
>> 24);
2027 const int nCurrPos
= ftell( mpFileOut
);
2028 fseek( mpFileOut
, nTellPos
, SEEK_SET
);
2029 fwrite( cData
, 1, sizeof(cData
), mpFileOut
);
2030 fseek( mpFileOut
, nCurrPos
, SEEK_SET
);
2033 // --------------------------------------------------------------------
2035 inline void Type1Emitter::emitRawData( const char* pData
, int nLength
) const
2037 fwrite( pData
, 1, nLength
, mpFileOut
);
2040 // --------------------------------------------------------------------
2042 inline void Type1Emitter::emitAllRaw( void)
2044 // writeout raw data
2045 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
2046 emitRawData( maBuffer
, mpPtr
- maBuffer
);
2047 // reset the raw buffer
2051 // --------------------------------------------------------------------
2053 inline void Type1Emitter::emitAllHex( void)
2055 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
2056 for( const char* p
= maBuffer
; p
< mpPtr
;) {
2057 // convert binary chunk to hex
2058 char aHexBuf
[0x4000];
2059 char* pOut
= aHexBuf
;
2060 while( (p
< mpPtr
) && (pOut
< aHexBuf
+sizeof(aHexBuf
)-4)) {
2061 // convert each byte to hex
2062 char cNibble
= (*p
>> 4) & 0x0F;
2063 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
2064 *(pOut
++) = cNibble
;
2065 cNibble
= *(p
++) & 0x0F;
2066 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
2067 *(pOut
++) = cNibble
;
2068 // limit the line length
2069 if( (++mnHexLineCol
& 0x3F) == 0)
2072 // writeout hex-converted chunk
2073 emitRawData( aHexBuf
, pOut
-aHexBuf
);
2075 // reset the raw buffer
2079 // --------------------------------------------------------------------
2081 void Type1Emitter::emitAllCrypted( void)
2084 for( char* p
= maBuffer
; p
< mpPtr
; ++p
) {
2085 *p
^= (mnEECryptR
>> 8);
2086 mnEECryptR
= (*(U8
*)p
+ mnEECryptR
) * 52845 + 22719;
2089 // emit the t1crypt result
2096 // --------------------------------------------------------------------
2098 void Type1Emitter::emitIntVector( const char* pLineHead
, const char* pLineTail
,
2099 const IntVector
& rVector
)
2101 // ignore empty vectors
2102 if( rVector
.empty())
2105 // emit the line head
2106 mpPtr
+= sprintf( mpPtr
, pLineHead
);
2107 // emit the vector values
2108 IntVector::value_type nVal
= 0;
2109 for( IntVector::const_iterator it
= rVector
.begin();;) {
2111 if( ++it
== rVector
.end() )
2113 mpPtr
+= sprintf( mpPtr
, "%d ", nVal
);
2115 // emit the last value
2116 mpPtr
+= sprintf( mpPtr
, "%d", nVal
);
2117 // emit the line tail
2118 mpPtr
+= sprintf( mpPtr
, pLineTail
);
2121 // --------------------------------------------------------------------
2123 bool CffSubsetterContext::emitAsType1( Type1Emitter
& rEmitter
,
2124 const long* pReqGlyphIDs
, const U8
* pReqEncoding
,
2125 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rFSInfo
)
2127 // prepare some fontdirectory details
2128 static const int nUniqueIdBase
= 4100000; // using private-interchange UniqueIds
2129 static int nUniqueId
= nUniqueIdBase
;
2132 char* pFontName
= rEmitter
.maSubsetName
;
2134 if( mnFontNameSID
) {
2135 // get the fontname directly if available
2136 strncpy( pFontName
, getString( mnFontNameSID
), sizeof(rEmitter
.maSubsetName
));
2137 } else if( mnFullNameSID
) {
2138 // approximate fontname as fullname-whitespace
2139 const char* pI
= getString( mnFullNameSID
);
2140 char* pO
= pFontName
;
2141 const char* pLimit
= pFontName
+ sizeof(rEmitter
.maSubsetName
) - 1;
2142 while( pO
< pLimit
) {
2143 const char c
= *(pI
++);
2151 // fallback name of last resort
2152 strncpy( pFontName
, "DummyName", sizeof(rEmitter
.maSubsetName
));
2155 const char* pFullName
= pFontName
;
2156 const char* pFamilyName
= pFontName
;
2158 char*& pOut
= rEmitter
.mpPtr
; // convenience reference, TODO: cleanup
2160 // create a PFB+Type1 header
2161 if( rEmitter
.mbPfbSubset
) {
2162 static const char aPfbHeader
[] = "\x80\x01\x00\x00\x00\x00";
2163 rEmitter
.emitRawData( aPfbHeader
, sizeof(aPfbHeader
)-1);
2166 pOut
+= sprintf( pOut
, "%%!FontType1-1.0: %s 001.003\n", rEmitter
.maSubsetName
);
2168 #if 0 // improve PS Type1 caching?
2169 nOfs
+= sprintf( &aT1Str
[nOfs
],
2170 "FontDirectory/%s known{/%s findfont dup/UniqueID known{dup\n"
2171 "/UniqueID get %d eq exch/FontType get 1 eq and}{pop false}ifelse\n"
2172 "{save true}{false}ifelse}\n{false}ifelse\n",
2173 pFamilyName
, pFamilyName
, nUniqueId
);
2175 pOut
+= sprintf( pOut
,
2176 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
2178 "/PaintType 0 def\n");
2179 pOut
+= sprintf( pOut
, "/FontName /%s def\n", rEmitter
.maSubsetName
);
2180 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
2181 pOut
+= sprintf( pOut
, "/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def\n");
2182 if( maFontBBox
.size() == 4)
2183 pOut
+= sprintf( pOut
, "/FontBBox [%d %d %d %d ]readonly def\n",
2184 maFontBBox
[0], maFontBBox
[1], maFontBBox
[2], maFontBBox
[3]);
2186 pOut
+= sprintf( pOut
, "/FontBBox [0 0 999 999]readonly def\n");
2187 // emit FONTINFO into TOPDICT
2188 pOut
+= sprintf( pOut
,
2189 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
2190 " /FullName (%s) readonly def\n"
2191 " /FamilyName (%s) readonly def\n"
2192 "end readonly def\n",
2193 pFullName
, pFamilyName
);
2194 #if 0 // TODO: use an standard Type1 encoding if possible
2195 pOut
+= sprintf( pOut
,
2196 "/Encoding StandardEncoding def\n");
2198 pOut
+= sprintf( pOut
,
2199 "/Encoding 256 array\n"
2200 "0 1 255 {1 index exch /.notdef put} for\n");
2201 for( int i
= 1; (i
< nGlyphCount
) && (i
< 256); ++i
) {
2202 const char* pGlyphName
= getGlyphName( pReqGlyphIDs
[i
]);
2203 pOut
+= sprintf( pOut
, "dup %d /%s put\n", pReqEncoding
[i
], pGlyphName
);
2205 pOut
+= sprintf( pOut
, "readonly def\n");
2207 pOut
+= sprintf( pOut
,
2208 // TODO: more topdict entries
2210 "currentfile eexec\n");
2213 rEmitter
.emitAllRaw();
2214 if( rEmitter
.mbPfbSubset
) {
2215 // update PFB header segment
2216 const int nPfbHeaderLen
= rEmitter
.tellPos() - 6;
2217 rEmitter
.updateLen( 2, nPfbHeaderLen
);
2219 // prepare start of eexec segment
2220 rEmitter
.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
2222 const int nEExecSegTell
= rEmitter
.tellPos();
2224 // which always starts with a privdict
2225 // count the privdict entries
2226 int nPrivEntryCount
= 9;
2227 #if !defined(IGNORE_HINTS)
2228 // emit blue hints only if non-default values
2229 nPrivEntryCount
+= !mpCffLocal
->maOtherBlues
.empty();
2230 nPrivEntryCount
+= !mpCffLocal
->maFamilyBlues
.empty();
2231 nPrivEntryCount
+= !mpCffLocal
->maFamilyOtherBlues
.empty();
2232 nPrivEntryCount
+= (mpCffLocal
->mfBlueScale
!= 0.0);
2233 nPrivEntryCount
+= (mpCffLocal
->mfBlueShift
!= 0.0);
2234 nPrivEntryCount
+= (mpCffLocal
->mfBlueFuzz
!= 0.0);
2235 // emit stem hints only if non-default values
2236 nPrivEntryCount
+= (mpCffLocal
->mnStemStdHW
!= 0);
2237 nPrivEntryCount
+= (mpCffLocal
->mnStemStdVW
!= 0);
2238 nPrivEntryCount
+= !mpCffLocal
->maStemSnapH
.empty();
2239 nPrivEntryCount
+= !mpCffLocal
->maStemSnapV
.empty();
2240 // emit other hints only if non-default values
2241 nPrivEntryCount
+= (mpCffLocal
->mfExpFactor
!= 0.0);
2242 nPrivEntryCount
+= (mpCffLocal
->mnLangGroup
!= 0);
2243 nPrivEntryCount
+= (mpCffLocal
->mnLangGroup
== 1);
2244 nPrivEntryCount
+= (mpCffLocal
->mbForceBold
!= false);
2245 #endif // IGNORE_HINTS
2246 // emit the privdict header
2247 pOut
+= sprintf( pOut
,
2249 "dup\n/Private %d dict dup begin\n"
2250 "/RD{string currentfile exch readstring pop}executeonly def\n"
2251 "/ND{noaccess def}executeonly def\n"
2252 "/NP{noaccess put}executeonly def\n"
2253 "/MinFeature{16 16}ND\n"
2254 "/password 5839 def\n", // TODO: mnRDCryptSeed?
2257 #if defined(IGNORE_HINTS)
2258 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // BlueValues are mandatory
2260 // emit blue hint related privdict entries
2261 if( !mpCffLocal
->maBlueValues
.empty())
2262 rEmitter
.emitIntVector( "/BlueValues [", "]ND\n", mpCffLocal
->maBlueValues
);
2264 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // default to empty BlueValues
2265 rEmitter
.emitIntVector( "/OtherBlues [", "]ND\n", mpCffLocal
->maOtherBlues
);
2266 rEmitter
.emitIntVector( "/FamilyBlues [", "]ND\n", mpCffLocal
->maFamilyBlues
);
2267 rEmitter
.emitIntVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal
->maFamilyOtherBlues
);
2269 if( mpCffLocal
->mfBlueScale
)
2270 pOut
+= sprintf( pOut
, "/BlueScale %.6f def\n", mpCffLocal
->mfBlueScale
);
2271 if( mpCffLocal
->mfBlueShift
) // default BlueShift==7
2272 pOut
+= sprintf( pOut
, "/BlueShift %.1f def\n", mpCffLocal
->mfBlueShift
);
2273 if( mpCffLocal
->mfBlueFuzz
) // default BlueFuzz==1
2274 pOut
+= sprintf( pOut
, "/BlueFuzz %.1f def\n", mpCffLocal
->mfBlueFuzz
);
2276 // emit stem hint related privdict entries
2277 if( mpCffLocal
->mnStemStdHW
)
2278 pOut
+= sprintf( pOut
, "/StdHW [%d] def\n", mpCffLocal
->mnStemStdHW
);
2279 if( mpCffLocal
->mnStemStdVW
)
2280 pOut
+= sprintf( pOut
, "/StdVW [%d] def\n", mpCffLocal
->mnStemStdVW
);
2281 rEmitter
.emitIntVector( "/StemSnapH [", "]ND\n", mpCffLocal
->maStemSnapH
);
2282 rEmitter
.emitIntVector( "/StemSnapV [", "]ND\n", mpCffLocal
->maStemSnapV
);
2285 if( mpCffLocal
->mbForceBold
)
2286 pOut
+= sprintf( pOut
, "/ForceBold true def\n");
2287 if( mpCffLocal
->mnLangGroup
!= 0)
2288 pOut
+= sprintf( pOut
, "/LanguageGroup %d def\n", mpCffLocal
->mnLangGroup
);
2289 if( mpCffLocal
->mnLangGroup
== 1) // compatibility with ancient printers
2290 pOut
+= sprintf( pOut
, "/RndStemUp false def\n");
2291 if( mpCffLocal
->mfExpFactor
)
2292 pOut
+= sprintf( pOut
, "/ExpansionFactor %.2f def\n", mpCffLocal
->mfExpFactor
);
2293 #endif // IGNORE_HINTS
2295 // emit remaining privdict entries
2296 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
2297 // TODO?: more privdict entries?
2299 static const char aOtherSubrs
[] =
2301 "% Dummy code for faking flex hints\n"
2302 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2303 "{1183615869 systemdict /internaldict get exec\n"
2304 "dup /startlock known\n"
2305 "{/startlock get exec}\n"
2306 "{dup /strtlck known\n"
2307 "{/strtlck get exec}\n"
2308 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2310 memcpy( pOut
, aOtherSubrs
, sizeof(aOtherSubrs
)-1);
2311 pOut
+= sizeof(aOtherSubrs
)-1;
2313 // emit used GlobalSubr charstrings
2314 // these are the just the default subrs
2315 static const char aSubrs
[] =
2317 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2318 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2319 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2320 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2321 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2323 memcpy( pOut
, aSubrs
, sizeof(aSubrs
)-1);
2324 pOut
+= sizeof(aSubrs
)-1;
2326 // TODO: emit more GlobalSubr charstrings?
2327 // TODO: emit used LocalSubr charstrings?
2329 // emit the CharStrings for the requested glyphs
2330 pOut
+= sprintf( pOut
,
2331 "2 index /CharStrings %d dict dup begin\n", nGlyphCount
);
2332 rEmitter
.emitAllCrypted();
2333 for( int i
= 0; i
< nGlyphCount
; ++i
) {
2334 const int nGlyphId
= pReqGlyphIDs
[i
];
2335 assert( (nGlyphId
>= 0) && (nGlyphId
< mnCharStrCount
));
2336 // get privdict context matching to the glyph
2337 const int nFDSelect
= getFDSelect( nGlyphId
);
2338 mpCffLocal
= &maCffLocal
[ nFDSelect
];
2339 // convert the Type2op charstring to its Type1op counterpart
2340 const int nT2Len
= seekIndexData( mnCharStrBase
, nGlyphId
);
2341 assert( nT2Len
> 0);
2342 U8 aType1Ops
[ MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
2343 const int nT1Len
= convert2Type1Ops( mpCffLocal
, mpReadPtr
, nT2Len
, aType1Ops
);
2344 // get the glyph name
2345 const char* pGlyphName
= getGlyphName( nGlyphId
);
2346 // emit the encrypted Type1op charstring
2347 pOut
+= sprintf( pOut
, "/%s %d RD ", pGlyphName
, nT1Len
);
2348 memcpy( pOut
, aType1Ops
, nT1Len
);
2350 pOut
+= sprintf( pOut
, " ND\n");
2351 rEmitter
.emitAllCrypted();
2352 // provide individual glyphwidths if requested
2354 pGlyphWidths
[i
] = getCharWidth();
2356 pOut
+= sprintf( pOut
, "end end\nreadonly put\nput\n");
2357 pOut
+= sprintf( pOut
, "dup/FontName get exch definefont pop\n");
2358 pOut
+= sprintf( pOut
, "mark currentfile closefile\n");
2359 rEmitter
.emitAllCrypted();
2361 // mark stop of eexec encryption
2362 if( rEmitter
.mbPfbSubset
) {
2363 const int nEExecLen
= rEmitter
.tellPos() - nEExecSegTell
;
2364 rEmitter
.updateLen( nEExecSegTell
-4, nEExecLen
);
2367 // create PFB footer
2368 static const char aPfxFooter
[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2369 "0000000000000000000000000000000000000000000000000000000000000000\n"
2370 "0000000000000000000000000000000000000000000000000000000000000000\n"
2371 "0000000000000000000000000000000000000000000000000000000000000000\n"
2372 "0000000000000000000000000000000000000000000000000000000000000000\n"
2373 "0000000000000000000000000000000000000000000000000000000000000000\n"
2374 "0000000000000000000000000000000000000000000000000000000000000000\n"
2375 "0000000000000000000000000000000000000000000000000000000000000000\n"
2376 "0000000000000000000000000000000000000000000000000000000000000000\n"
2379 if( rEmitter
.mbPfbSubset
)
2380 rEmitter
.emitRawData( aPfxFooter
, sizeof(aPfxFooter
)-1);
2382 rEmitter
.emitRawData( aPfxFooter
+6, sizeof(aPfxFooter
)-9);
2384 // provide details to the subset requesters, TODO: move into own method?
2385 // note: Top and Bottom are flipped between Type1 and VCL
2386 rFSInfo
.m_aFontBBox
= Rectangle( Point( maFontBBox
[0], maFontBBox
[1] ), Point( maFontBBox
[2], maFontBBox
[3] ) );
2387 // PDF-Spec says the values below mean the ink bounds!
2388 // TODO: use better approximations for these ink bounds
2389 rFSInfo
.m_nAscent
= +rFSInfo
.m_aFontBBox
.Bottom(); // for capital letters
2390 rFSInfo
.m_nDescent
= -rFSInfo
.m_aFontBBox
.Top(); // for all letters
2391 rFSInfo
.m_nCapHeight
= rFSInfo
.m_nAscent
; // for top-flat capital letters
2393 rFSInfo
.m_nFontType
= rEmitter
.mbPfbSubset
? FontSubsetInfo::TYPE1_PFB
: FontSubsetInfo::TYPE1_PFA
;
2394 rFSInfo
.m_aPSName
= String( rEmitter
.maSubsetName
, RTL_TEXTENCODING_UTF8
);
2399 // ====================================================================
2401 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth
* pOutGlyphWidths
)
2403 CffSubsetterContext
aCff( mpInFontBytes
, mnInByteLength
);
2404 aCff
.initialCffRead();
2406 // emit Type1 subset from the CFF input
2407 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2408 const bool bPfbSubset
= (0 != (mnReqFontTypeMask
& FontSubsetInfo::TYPE1_PFB
));
2409 Type1Emitter
aType1Emitter( mpOutFile
, bPfbSubset
);
2410 aType1Emitter
.setSubsetName( mpReqFontName
);
2411 bool bRC
= aCff
.emitAsType1( aType1Emitter
,
2412 mpReqGlyphIds
, mpReqEncodedIds
,
2413 pOutGlyphWidths
, mnReqGlyphCount
, *this);
2417 // ====================================================================