1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
24 #include "fontsubset.hxx"
26 #include <vcl/strhelper.hxx>
28 //#define IGNORE_HINTS
30 typedef unsigned char U8
;
31 typedef unsigned short U16
;
32 typedef long long S64
;
34 typedef sal_Int32 GlyphWidth
;
36 typedef float RealType
;
37 typedef RealType ValType
;
39 typedef std::vector
<ValType
> ValVector
;
41 static const char* pStringIds
[] = {
42 /*0*/ ".notdef", "space", "exclam", "quotedbl",
43 "numbersign", "dollar", "percent", "ampersand",
44 "quoteright", "parenleft", "parenright", "asterisk",
45 "plus", "comma", "hyphen", "period",
46 /*16*/ "slash", "zero", "one", "two",
47 "three", "four", "five", "six",
48 "seven", "eight", "nine", "colon",
49 "semicolon", "less", "equal", "greater",
50 /*32*/ "question", "at", "A", "B",
54 /*48*/ "O", "P", "Q", "R",
57 "bracketleft", "backslash", "bracketright", "asciicircum",
58 /*64*/ "underscore", "quoteleft", "a", "b",
62 /*80*/ "o", "p", "q", "r",
65 "braceleft", "bar", "braceright", "asciitilde",
66 /*96*/ "exclamdown", "cent", "sterlin", "fraction",
67 "yen", "florin", "section", "currency",
68 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
69 "guilsinglright", "fi", "fl", "endash",
70 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph",
71 "bullet", "quotesinglbase", "quotedblbase", "quotedblright",
72 "guillemotright", "ellipsis", "perthousand", "questiondown",
73 "grave", "acute", "circumflex", "tilde",
74 /*128*/ "macron", "breve", "dotaccent", "dieresis",
75 "ring", "cedilla", "hungarumlaut", "ogonek",
76 "caron", "emdash", "AE", "ordfeminine",
77 "Lslash", "Oslash", "OE", "ordmasculine",
78 /*144*/ "ae", "dotlessi", "lslash", "oslash",
79 "oe", "germandbls", "onesuperior", "logicalnot",
80 "mu", "trademark", "Eth", "onehalf",
81 "plusminus", "Thorn", "onequarter", "divide",
82 /*160*/ "brokenbar", "degree", "thorn", "threequarters",
83 "twosuperior", "registered", "minus", "eth",
84 "multiply", "threesuperior", "copyright", "Aacute",
85 "Acircumflex", "Adieresis", "Agrave", "Aring",
86 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex",
87 "Edieresis", "Egrave", "Iacute", "Icircumflex",
88 "Idieresis", "Igrave", "Ntilde", "Oacute",
89 "Ocircumflex", "Odieresis", "Ograve", "Otilde",
90 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis",
91 "Ugrave", "Yacute", "Ydieresis", "Zcaron",
92 "aacute", "acircumflex", "adieresis", "agrave",
93 "aring", "atilde", "ccedilla", "eacute",
94 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute",
95 "icircumflex", "idieresis", "igrave", "ntilde",
96 "oacute", "ocircumflex", "odieresis", "ograve",
97 "otilde", "scaron", "uacute", "ucircumflex",
98 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis",
99 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle",
100 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior",
101 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle",
102 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle",
103 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle",
104 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior",
105 "questionsmall", "asuperior", "bsuperior", "centsuperior",
106 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior",
107 "msuperior", "nsuperior", "osuperior", "rsuperior",
108 "ssuperior", "tsuperior", "ff", "ffi",
109 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall",
110 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall",
111 "Csmall", "Dsmall", "Esmall", "Fsmall",
112 "Gsmall", "Hsmall", "Ismall", "Jsmall",
113 "Ksmall", "Lsmall", "Msmall", "Nsmall",
114 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall",
115 "Ssmall", "Tsmall", "Usmall", "Vsmall",
116 "Wsmall", "Xsmall", "Ysmall", "Zsmall",
117 "colonmonetary", "onefitted", "rupia", "Tildesmall",
118 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall",
119 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall",
120 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior",
121 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall",
122 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights",
123 "onethird", "twothirds", "zerosuperior", "foursuperior",
124 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior",
125 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior",
126 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior",
127 "seveninferior", "eightinferior", "nineinferior", "centinferior",
128 "dollarinferior", "periodinferior", "commainferior", "Agravesmall",
129 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall",
130 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall",
131 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall",
132 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall",
133 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall",
134 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall",
135 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall",
136 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000",
137 "001.001", "001.002", "001.003", "Black",
138 /*384*/ "Bold", "Book", "Light", "Medium",
139 "Regular", "Roman", "Semibold"
142 // TOP DICT keywords (also covers PRIV DICT keywords)
143 static const char* pDictOps
[] = {
144 "sVersion", "sNotice", "sFullName", "sFamilyName",
145 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues",
146 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW",
147 "xESC", "nUniqueID", "aXUID", "nCharset",
148 "nEncoding", "nCharStrings", "PPrivate", "nSubrs",
149 "nDefaultWidthX", "nNominalWidthX", NULL
, NULL
,
150 NULL
, NULL
, NULL
, NULL
,
151 "shortint", "longint", "BCD", NULL
154 // TOP DICT escapes (also covers PRIV DICT escapes)
155 static const char* pDictEscs
[] = {
156 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition",
157 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix",
158 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz",
159 "dStemSnapH", "dStemSnapV", "bForceBold", NULL
,
160 NULL
, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed",
161 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend",
162 NULL
, NULL
, NULL
, NULL
,
163 NULL
, NULL
, "rROS", "nCIDFontVersion",
164 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase",
165 "nFDArray", "nFDSelect", "sFontName"
168 static const char* pType1Ops
[] = {
169 NULL
, "2hstem", NULL
, "2vstem",
170 "1vmoveto", "Arlineto", "1hlineto", "1vlineto",
171 "Crrcurveto", "0closepath", "Lcallsubr", "0return",
172 "xT1ESC", "2hsbw", "0endchar", NULL
,
173 NULL
, NULL
, NULL
, NULL
,
174 NULL
, "2rmoveto", "1hmoveto", NULL
,
175 NULL
, NULL
, NULL
, NULL
,
176 NULL
, NULL
, "4vhcurveto", "4hvcurveto"
179 static const char* pT1EscOps
[] = {
180 "0dotsection", "6vstem3", "6hstem3", NULL
,
181 NULL
, NULL
, "5seac", "4sbw",
182 NULL
, "1abs", "2add", "2sub",
183 "2div", NULL
, NULL
, NULL
,
184 "Gcallothersubr", "1pop", NULL
, NULL
,
185 NULL
, NULL
, NULL
, NULL
,
186 NULL
, NULL
, NULL
, NULL
,
187 NULL
, NULL
, NULL
, NULL
,
188 NULL
, "2setcurrentpoint"
195 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
196 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CLOSEPATH
=9,
197 CALLSUBR
=10, RETURN
=11, T1ESC
=12, HSBW
=13,
198 ENDCHAR
=14, RMOVETO
=21, HMOVETO
=22, VHCURVETO
=30,
204 DOTSECTION
=0, VSTEM3
=1, HSTEM3
=2, SEAC
=6,
205 SBW
=7, ABS
=9, ADD
=10, SUB
=11,
206 DIV
=12, CALLOTHERSUBR
=16, POP
=17, SETCURRENTPOINT
=33
210 static const char* pType2Ops
[] = {
211 NULL
, "hhstem", NULL
, "vvstem",
212 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto",
213 "Crrcurveto", NULL
, "Lcallsubr", "Xreturn",
214 "xT2ESC", NULL
, "eendchar", NULL
,
215 NULL
, NULL
, "Hhstemhm", "Khintmask",
216 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm",
217 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto",
218 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto"
221 static const char* pT2EscOps
[] = {
222 NULL
, NULL
, NULL
, "2and",
223 "2or", "1not", NULL
, NULL
,
224 NULL
, "1abs", "2add", "2sub",
225 "2div", NULL
, "1neg", "2eq",
226 NULL
, NULL
, "1drop", NULL
,
227 "1put", "1get", "4ifelse", "0random",
228 "2mul", NULL
, "1sqrt", "1dup",
229 "2exch", "Iindex", "Rroll", NULL
,
230 NULL
, NULL
, "7hflex", "Fflex",
238 HSTEM
=1, VSTEM
=3, VMOVETO
=4, RLINETO
=5,
239 HLINETO
=6, VLINETO
=7, RCURVETO
=8, CALLSUBR
=10,
240 RETURN
=11, T2ESC
=12, ENDCHAR
=14, HSTEMHM
=18,
241 HINTMASK
=19, CNTRMASK
=20, RMOVETO
=21, HMOVETO
=22,
242 VSTEMHM
=23, RCURVELINE
=24, RLINECURVE
=25, VVCURVETO
=26,
243 HHCURVETO
=27, SHORTINT
=28, CALLGSUBR
=29, VHCURVETO
=30,
249 AND
=3, OR
=4, NOT
=5, ABS
=9,
250 ADD
=10, SUB
=11, DIV
=12, NEG
=14,
251 EQ
=15, DROP
=18, PUT
=20, GET
=21,
252 IFELSE
=22, RANDOM
=23, MUL
=24, SQRT
=26,
253 DUP
=27, EXCH
=28, INDEX
=29, ROLL
=30,
254 HFLEX
=34, FLEX
=35, HFLEX1
=36, FLEX1
=37
260 explicit CffGlobal();
265 int mnStringIdxCount
;
271 int mnGlobalSubrBase
;
272 int mnGlobalSubrCount
;
273 int mnGlobalSubrBias
;
278 ValVector maFontBBox
;
279 ValVector maFontMatrix
;
294 int mnLocalSubrCount
;
297 ValType maNominalWidth
;
298 ValType maDefaultWidth
;
300 // ATM hinting related values
303 ValVector maStemSnapH
;
304 ValVector maStemSnapV
;
305 ValVector maBlueValues
;
306 ValVector maOtherBlues
;
307 ValVector maFamilyBlues
;
308 ValVector maFamilyOtherBlues
;
309 RealType mfBlueScale
;
310 RealType mfBlueShift
;
312 RealType mfExpFactor
;
317 class CffSubsetterContext
321 static const int NMAXSTACK
= 48; // see CFF.appendixB
322 static const int NMAXHINTS
= 2*96; // see CFF.appendixB
323 static const int NMAXTRANS
= 32; // see CFF.appendixB
325 explicit CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
);
326 ~CffSubsetterContext();
328 bool initialCffRead();
329 bool emitAsType1( class Type1Emitter
&,
330 const sal_GlyphId
* pGlyphIds
, const U8
* pEncoding
,
331 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& );
333 // used by charstring converter
334 void setCharStringType( int);
336 int convert2Type1Ops( CffLocal
*, const U8
* pType2Ops
, int nType2Len
, U8
* pType1Ops
);
338 void convertOneTypeOp();
339 void convertOneTypeEsc();
340 void callType2Subr( bool bGlobal
, int nSubrNumber
);
341 sal_Int32
getReadOfs() const { return (sal_Int32
)(mpReadPtr
- mpBasePtr
);}
353 sal_Int32 mnCntrMask
;
356 int seekIndexData( int nIndexBase
, int nDataIndex
);
357 void seekIndexEnd( int nIndexBase
);
360 const char** mpCharStringOps
;
361 const char** mpCharStringEscs
;
363 CffLocal maCffLocal
[256];
364 CffLocal
* mpCffLocal
;
367 RealType
readRealVal();
368 const char* getString( int nStringID
);
369 int getFDSelect( int nGlyphIndex
) const;
370 int getGlyphSID( int nGlyphIndex
) const;
371 const char* getGlyphName( int nGlyphIndex
);
374 void writeType1Val( ValType
);
375 void writeTypeOp( int nTypeOp
);
376 void writeTypeEsc( int nTypeOp
);
377 void writeCurveTo( int nStackPos
, int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
);
378 void pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
=0);
379 void popAll2Write( int nTypeOp
);
381 public: // TODO: is public really needed?
382 // accessing the value stack
383 // TODO: add more checks
384 void push( ValType nVal
) { mnValStack
[ mnStackIdx
++] = nVal
;}
385 ValType
popVal() { return ((mnStackIdx
>0) ? mnValStack
[ --mnStackIdx
] : 0);}
386 ValType
getVal( int nIndex
) const { return mnValStack
[ nIndex
];}
388 int size() const { return mnStackIdx
;}
389 void clear() { mnStackIdx
= 0;}
391 // accessing the charstring hints
392 void addHints( bool bVerticalHints
);
394 // accessing other charstring specifics
395 bool hasCharWidth() const { return (maCharWidth
> 0);}
396 ValType
getCharWidth() const { return maCharWidth
;}
397 void setNominalWidth( ValType aWidth
) { mpCffLocal
->maNominalWidth
= aWidth
;}
398 void setDefaultWidth( ValType aWidth
) { mpCffLocal
->maDefaultWidth
= aWidth
;}
399 void updateWidth( bool bUseFirstVal
);
402 // typeop exceution context
404 ValType mnValStack
[ NMAXSTACK
+4];
405 ValType mnTransVals
[ NMAXTRANS
];
409 ValType mnHintStack
[ NMAXHINTS
];
414 CffSubsetterContext::CffSubsetterContext( const U8
* pBasePtr
, int nBaseLen
)
415 : mpBasePtr( pBasePtr
)
416 , mpBaseEnd( pBasePtr
+nBaseLen
)
422 , mbIgnoreHints(false)
424 , mpCharStringOps(NULL
)
425 , mpCharStringEscs(NULL
)
431 // setCharStringType( 1);
432 // TODO: new CffLocal[ mnFDAryCount];
433 mpCffLocal
= &maCffLocal
[0];
436 CffSubsetterContext::~CffSubsetterContext()
438 // TODO: delete[] maCffLocal;
441 inline int CffSubsetterContext::popInt()
443 const ValType aVal
= popVal();
444 const int nInt
= static_cast<int>(aVal
);
445 assert( nInt
== aVal
);
449 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal
)
451 #if 1 // TODO: is this still needed?
452 // the first value is not a hint but the charwidth
457 maCharWidth
= mpCffLocal
->maNominalWidth
+ mnValStack
[0];
458 // remove bottom stack entry
460 for( int i
= 0; i
< mnStackIdx
; ++i
)
461 mnValStack
[ i
] = mnValStack
[ i
+1];
463 maCharWidth
= mpCffLocal
->maDefaultWidth
;
467 void CffSubsetterContext::addHints( bool bVerticalHints
)
469 // the first charstring value may a charwidth instead of a charwidth
470 updateWidth( (mnStackIdx
& 1) != 0);
471 // return early (e.g. no implicit hints for hintmask)
475 // copy the remaining values to the hint arrays
476 // assert( (mnStackIdx & 1) == 0); // depends on called subrs
477 if( mnStackIdx
& 1) --mnStackIdx
;//#######
478 // TODO: if( !bSubr) assert( mnStackIdx >= 2);
480 assert( (mnHintSize
+ mnStackIdx
) <= 2*NMAXHINTS
);
483 mnHintSize
+= mnStackIdx
;
485 ValType nHintOfs
= 0;
486 for( int i
= 0; i
< mnStackIdx
; ++i
) {
487 nHintOfs
+= mnValStack
[ i
];
488 mnHintStack
[ mnHintSize
++] = nHintOfs
;
490 #endif // IGNORE_HINTS
492 mnHorzHintSize
= mnHintSize
;
494 // clear all values from the stack
498 void CffSubsetterContext::setCharStringType( int nVal
)
501 case 1: mpCharStringOps
=pType1Ops
; mpCharStringEscs
=pT1EscOps
; break;
502 case 2: mpCharStringOps
=pType2Ops
; mpCharStringEscs
=pT2EscOps
; break;
503 default: fprintf( stderr
, "Unknown CharstringType=%d\n",nVal
); break;
507 void CffSubsetterContext::readDictOp()
510 const U8 c
= *mpReadPtr
;
512 int nOpId
= *(mpReadPtr
++);
513 const char* pCmdName
= 0;
515 pCmdName
= pDictOps
[nOpId
];
517 const U8 nExtId
= *(mpReadPtr
++);
519 pCmdName
= pDictEscs
[nExtId
];
520 nOpId
= 900 + nExtId
;
523 if (!pCmdName
) // skip reserved operators
526 //TODO: if( nStackIdx > 0)
529 default: fprintf( stderr
, "unsupported DictOp.type=\'%c\'\n", *pCmdName
); break;
533 case 915: mpCffLocal
->mbForceBold
= nInt
; break; // "ForceBold"
534 default: break; // TODO: handle more boolean dictops?
537 case 'n': // dict-op number
539 nInt
= static_cast<int>(nVal
);
541 case 10: mpCffLocal
->maStemStdHW
= nVal
; break; // "StdHW"
542 case 11: mpCffLocal
->maStemStdVW
= nVal
; break; // "StdVW"
543 case 15: mnCharsetBase
= nInt
; break; // "charset"
544 case 16: mnEncodingBase
= nInt
; break; // "nEncoding"
545 case 17: mnCharStrBase
= nInt
; break; // "nCharStrings"
546 case 19: mpCffLocal
->mnLocalSubrOffs
= nInt
; break;// "nSubrs"
547 case 20: setDefaultWidth( nVal
); break; // "defaultWidthX"
548 case 21: setNominalWidth( nVal
); break; // "nominalWidthX"
549 case 909: mpCffLocal
->mfBlueScale
= nVal
; break; // "BlueScale"
550 case 910: mpCffLocal
->mfBlueShift
= nVal
; break; // "BlueShift"
551 case 911: mpCffLocal
->mfBlueFuzz
= nVal
; break; // "BlueFuzz"
552 case 912: mpCffLocal
->mfExpFactor
= nVal
; break; // "ExpansionFactor"
553 case 917: mpCffLocal
->mnLangGroup
= nInt
; break; // "LanguageGroup"
554 case 936: mnFontDictBase
= nInt
; break; // "nFDArray"
555 case 937: mnFDSelectBase
= nInt
; break; // "nFDSelect"
556 default: break; // TODO: handle more numeric dictops?
561 case 5: maFontBBox
.clear(); break; // "FontBBox"
562 case 907: maFontMatrix
.clear(); break; // "FontMatrix"
563 default: break; // TODO: reset other arrays?
565 for( int i
= 0; i
< size(); ++i
) {
568 case 5: maFontBBox
.push_back( nVal
); break; // "FontBBox"
569 case 907: maFontMatrix
.push_back( nVal
); break; // "FontMatrix"
570 default: break; // TODO: handle more array dictops?
575 case 'd': { // delta array
577 for( int i
= 0; i
< size(); ++i
) {
580 case 6: mpCffLocal
->maBlueValues
.push_back( nVal
); break; // "BlueValues"
581 case 7: mpCffLocal
->maOtherBlues
.push_back( nVal
); break; // "OtherBlues"
582 case 8: mpCffLocal
->maFamilyBlues
.push_back( nVal
); break; // "FamilyBlues"
583 case 9: mpCffLocal
->maFamilyOtherBlues
.push_back( nVal
); break;// "FamilyOtherBlues"
584 case 912: mpCffLocal
->maStemSnapH
.push_back( nVal
); break; // "StemSnapH"
585 case 913: mpCffLocal
->maStemSnapV
.push_back( nVal
); break; // "StemSnapV"
586 default: break; // TODO: handle more delta-array dictops?
591 case 's': // stringid (SID)
594 case 2: mnFullNameSID
= nInt
; break; // "FullName"
595 case 3: mnFamilyNameSID
= nInt
; break; // "FamilyName"
596 case 938: mnFontNameSID
= nInt
; break; // "FontName"
597 default: break; // TODO: handle more string dictops?
600 case 'P': // private dict
601 mpCffLocal
->mnPrivDictBase
= popInt();
602 mpCffLocal
->mnPrivDictSize
= popInt();
604 case 'r': { // ROS operands
605 int nSid1
= popInt();
606 int nSid2
= popInt();
607 (void)nSid1
; // TODO: use
608 (void)nSid2
; // TODO: use
612 case 't': // CharstringType
614 setCharStringType( nInt
);
621 if( (c
>= 32) || (c
== 28) ) {
624 } else if( c
== 29 ) { // longint
625 ++mpReadPtr
; // skip 29
626 int nS32
= mpReadPtr
[0] << 24;
627 nS32
+= mpReadPtr
[1] << 16;
628 nS32
+= mpReadPtr
[2] << 8;
629 nS32
+= mpReadPtr
[3] << 0;
630 if( (sizeof(nS32
) != 4) && (nS32
& (1U<<31)))
631 nS32
|= (~0U) << 31; // assuming 2s complement
633 nVal
= static_cast<ValType
>(nS32
);
635 } else if( c
== 30) { // real number
636 ++mpReadPtr
; // skip 30
637 const RealType fReal
= readRealVal();
638 // push value onto stack
644 void CffSubsetterContext::read2push()
648 const U8
*& p
= mpReadPtr
;
651 short nS16
= (p
[1] << 8) + p
[2];
652 if( (sizeof(nS16
) != 2) && (nS16
& (1<<15)))
653 nS16
|= (~0U) << 15; // assuming 2s complement
656 } else if( c
<= 246 ) { // -107..+107
657 aVal
= static_cast<ValType
>(p
[0] - 139);
659 } else if( c
<= 250 ) { // +108..+1131
660 aVal
= static_cast<ValType
>(((p
[0] << 8) + p
[1]) - 63124);
662 } else if( c
<= 254 ) { // -108..-1131
663 aVal
= static_cast<ValType
>(64148 - ((p
[0] << 8) + p
[1]));
665 } else /*if( c == 255)*/ { // Fixed16.16
666 int nS32
= (p
[1] << 24) + (p
[2] << 16) + (p
[3] << 8) + p
[4];
667 if( (sizeof(nS32
) != 2) && (nS32
& (1U<<31)))
668 nS32
|= (~0U) << 31; // assuming 2s complement
669 aVal
= static_cast<ValType
>(nS32
* (1.0 / 0x10000));
676 void CffSubsetterContext::writeType1Val( ValType aVal
)
678 U8
* pOut
= mpWritePtr
;
680 int nInt
= static_cast<int>(aVal
);
681 if( (nInt
>= -107) && (nInt
<= +107)) {
682 *(pOut
++) = static_cast<U8
>(nInt
+ 139); // -107..+107
683 } else if( (nInt
>= -1131) && (nInt
<= +1131)) {
685 nInt
+= 63124; // +108..+1131
687 nInt
= 64148 - nInt
; // -108..-1131
688 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
689 *(pOut
++) = static_cast<U8
>(nInt
);
691 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!!
693 *(pOut
++) = static_cast<U8
>(nInt
>> 24);
694 *(pOut
++) = static_cast<U8
>(nInt
>> 16);
695 *(pOut
++) = static_cast<U8
>(nInt
>> 8);
696 *(pOut
++) = static_cast<U8
>(nInt
);
702 inline void CffSubsetterContext::writeTypeOp( int nTypeOp
)
704 *(mpWritePtr
++) = static_cast<U8
>(nTypeOp
);
707 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc
)
709 *(mpWritePtr
++) = TYPE1OP::T1ESC
;
710 *(mpWritePtr
++) = static_cast<U8
>(nTypeEsc
);
713 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo
, int nTypeOp
, int nTypeXor
)
715 for( int i
= 0; i
< mnStackIdx
;) {
716 for( int j
= 0; j
< nArgsPerTypo
; ++j
) {
717 const ValType aVal
= mnValStack
[i
+j
];
718 writeType1Val( aVal
);
721 writeTypeOp( nTypeOp
);
722 nTypeOp
^= nTypeXor
; // for toggling vlineto/hlineto
727 void CffSubsetterContext::popAll2Write( int nTypeOp
)
729 // pop in reverse order, then write
730 for( int i
= 0; i
< mnStackIdx
; ++i
) {
731 const ValType aVal
= mnValStack
[i
];
732 writeType1Val( aVal
);
735 writeTypeOp( nTypeOp
);
738 void CffSubsetterContext::writeCurveTo( int nStackPos
,
739 int nIX1
, int nIY1
, int nIX2
, int nIY2
, int nIX3
, int nIY3
)
741 // get the values from the stack
742 const ValType nDX1
= nIX1
? mnValStack
[ nStackPos
+nIX1
] : 0;
743 const ValType nDY1
= nIY1
? mnValStack
[ nStackPos
+nIY1
] : 0;
744 const ValType nDX2
= nIX2
? mnValStack
[ nStackPos
+nIX2
] : 0;
745 const ValType nDY2
= nIY2
? mnValStack
[ nStackPos
+nIY2
] : 0;
746 const ValType nDX3
= nIX3
? mnValStack
[ nStackPos
+nIX3
] : 0;
747 const ValType nDY3
= nIY3
? mnValStack
[ nStackPos
+nIY3
] : 0;
749 // emit the curveto operator and operands
750 // TODO: determine the most efficient curveto operator
751 // TODO: depending on type1op or type2op target
752 writeType1Val( nDX1
);
753 writeType1Val( nDY1
);
754 writeType1Val( nDX2
);
755 writeType1Val( nDY2
);
756 writeType1Val( nDX3
);
757 writeType1Val( nDY3
);
758 writeTypeOp( TYPE1OP::RCURVETO
);
761 void CffSubsetterContext::convertOneTypeOp()
763 const int nType2Op
= *(mpReadPtr
++);
765 int i
, nInt
; // prevent WAE for declarations inside switch cases
773 addHints( nType2Op
== TYPE2OP::VSTEM
);
775 for( i
= 0; i
< mnHintSize
; i
+=2 ) {
776 writeType1Val( mnHintStack
[i
]);
777 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
778 writeTypeOp( nType2Op
);
780 #endif // IGNORE_HINTS
782 case TYPE2OP::HSTEMHM
:
783 case TYPE2OP::VSTEMHM
:
784 addHints( nType2Op
== TYPE2OP::VSTEMHM
);
786 case TYPE2OP::CNTRMASK
:
787 // TODO: replace cntrmask with vstem3/hstem3
790 mpReadPtr
+= (mnHintSize
+ 15) / 16;
791 mbIgnoreHints
= true;
796 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
798 nMaskByte
= *(mpReadPtr
++);
801 if( !(nMaskByte
& nMaskBit
))
803 if( i
>= 8*(int)sizeof(mnCntrMask
))
804 mbIgnoreHints
= true;
807 mnCntrMask
|= (1U << i
);
812 case TYPE2OP::HINTMASK
:
815 mpReadPtr
+= (mnHintSize
+ 15) / 16;
818 sal_Int32 nHintMask
= 0;
819 int nCntrBits
[2] = {0,0};
822 for( i
= 0; i
< mnHintSize
; i
+=2, nMaskBit
>>=1) {
824 nMaskByte
= *(mpReadPtr
++);
827 if( !(nMaskByte
& nMaskBit
))
829 if( i
>= 8*(int)sizeof(nHintMask
))
830 mbIgnoreHints
= true;
833 nHintMask
|= (1U << i
);
834 nCntrBits
[ i
< mnHorzHintSize
] += (mnCntrMask
>> i
) & 1;
837 mbIgnoreHints
|= (nCntrBits
[0] && (nCntrBits
[0] != 3));
838 mbIgnoreHints
|= (nCntrBits
[1] && (nCntrBits
[1] != 3));
842 for( i
= 0; i
< mnHintSize
; i
+=2) {
843 if( !(nHintMask
& (1U << i
)))
845 writeType1Val( mnHintStack
[i
]);
846 writeType1Val( mnHintStack
[i
+1] - mnHintStack
[i
]);
847 const bool bHorz
= (i
< mnHorzHintSize
);
848 if( !nCntrBits
[ bHorz
])
849 writeTypeOp( bHorz
? TYPE1OP::HSTEM
: TYPE1OP::VSTEM
);
850 else if( !--nCntrBits
[ bHorz
])
851 writeTypeEsc( bHorz
? TYPE1OP::HSTEM3
: TYPE1OP::VSTEM3
);
856 case TYPE2OP::CALLSUBR
:
857 case TYPE2OP::CALLGSUBR
:
860 const bool bGlobal
= (nType2Op
== TYPE2OP::CALLGSUBR
);
861 callType2Subr( bGlobal
, nInt
);
864 case TYPE2OP::RETURN
:
865 // TODO: check that we are in a subroutine
867 case TYPE2OP::VMOVETO
:
868 case TYPE2OP::HMOVETO
:
870 writeTypeOp( TYPE1OP::CLOSEPATH
);
872 updateWidth( size() > 1);
874 pop2MultiWrite( 1, nType2Op
);
876 case TYPE2OP::VLINETO
:
877 case TYPE2OP::HLINETO
:
878 pop2MultiWrite( 1, nType2Op
,
879 TYPE1OP::VLINETO
^ TYPE1OP::HLINETO
);
881 case TYPE2OP::RMOVETO
:
882 // TODO: convert rmoveto to vlineto/hlineto if possible
884 writeTypeOp( TYPE1OP::CLOSEPATH
);
886 updateWidth( size() > 2);
888 pop2MultiWrite( 2, nType2Op
);
890 case TYPE2OP::RLINETO
:
891 // TODO: convert rlineto to vlineto/hlineto if possible
892 pop2MultiWrite( 2, nType2Op
);
894 case TYPE2OP::RCURVETO
:
895 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible
896 pop2MultiWrite( 6, nType2Op
);
898 case TYPE2OP::RCURVELINE
:
900 while( (i
+= 6) <= mnStackIdx
)
901 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
903 while( (i
+= 2) <= mnStackIdx
) {
904 writeType1Val( mnValStack
[i
-2]);
905 writeType1Val( mnValStack
[i
-1]);
906 writeTypeOp( TYPE2OP::RLINETO
);
910 case TYPE2OP::RLINECURVE
:
912 while( (i
+= 2) <= mnStackIdx
-6) {
913 writeType1Val( mnValStack
[i
-2]);
914 writeType1Val( mnValStack
[i
-1]);
915 writeTypeOp( TYPE2OP::RLINETO
);
918 while( (i
+= 6) <= mnStackIdx
)
919 writeCurveTo( i
, -6, -5, -4, -3, -2, -1 );
922 case TYPE2OP::VHCURVETO
:
923 case TYPE2OP::HVCURVETO
:
925 bool bVert
= (nType2Op
== TYPE2OP::VHCURVETO
);
929 nInt
= static_cast<int>(mnValStack
[ --mnStackIdx
]);
930 while( (i
+= 4) <= mnStackIdx
) {
931 // TODO: use writeCurveTo()
932 if( bVert
) writeType1Val( 0 );
933 writeType1Val( mnValStack
[i
-4] );
934 if( !bVert
) writeType1Val( 0);
935 writeType1Val( mnValStack
[i
-3] );
936 writeType1Val( mnValStack
[i
-2] );
937 if( !bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
938 writeType1Val( mnValStack
[i
-1] );
939 if( bVert
) writeType1Val( static_cast<ValType
>((i
==mnStackIdx
) ? nInt
: 0) );
941 writeTypeOp( TYPE2OP::RCURVETO
);
946 case TYPE2OP::HHCURVETO
:
947 i
= (mnStackIdx
& 1);
948 while( (i
+= 4) <= mnStackIdx
) {
950 writeCurveTo( i
, -4, 0, -3, -2, -1, 0);
952 writeCurveTo( i
, -4, -5, -3, -2, -1, 0);
956 case TYPE2OP::VVCURVETO
:
957 i
= (mnStackIdx
& 1);
958 while( (i
+= 4) <= mnStackIdx
) {
960 writeCurveTo( i
, 0, -4, -3, -2, 0, -1);
962 writeCurveTo( i
, -5, -4, -3, -2, 0, -1);
966 case TYPE2OP::ENDCHAR
:
968 writeTypeOp( TYPE1OP::CLOSEPATH
);
970 updateWidth( size() >= 1);
971 // mbNeedClose = true;
972 writeTypeOp( TYPE1OP::ENDCHAR
);
975 if( ((nType2Op
>= 32) && (nType2Op
<= 255)) || (nType2Op
== 28)) {
979 popAll2Write( nType2Op
);
980 assert(false && "TODO?");
986 void CffSubsetterContext::convertOneTypeEsc()
988 const int nType2Esc
= *(mpReadPtr
++);
989 ValType
* pTop
= &mnValStack
[ mnStackIdx
-1];
993 assert( mnStackIdx
>= 2 );
994 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) & static_cast<int>(pTop
[-1]));
998 assert( mnStackIdx
>= 2 );
999 pTop
[0] = static_cast<ValType
>(static_cast<int>(pTop
[0]) | static_cast<int>(pTop
[-1]));
1003 assert( mnStackIdx
>= 1 );
1004 pTop
[0] = ValType(pTop
[0] == 0);
1007 assert( mnStackIdx
>= 1 );
1012 assert( mnStackIdx
>= 1 );
1016 assert( mnStackIdx
>= 2 );
1017 pTop
[0] += pTop
[-1];
1021 assert( mnStackIdx
>= 2 );
1022 pTop
[0] -= pTop
[-1];
1026 assert( mnStackIdx
>= 2 );
1028 pTop
[0] *= pTop
[-1];
1032 assert( mnStackIdx
>= 2 );
1034 pTop
[0] /= pTop
[-1];
1038 assert( mnStackIdx
>= 2 );
1039 pTop
[0] = ValType(pTop
[0] == pTop
[-1]);
1043 assert( mnStackIdx
>= 1 );
1046 case TYPE2OP::PUT
: {
1047 assert( mnStackIdx
>= 2 );
1048 const int nIdx
= static_cast<int>(pTop
[0]);
1049 assert( nIdx
>= 0 );
1050 assert( nIdx
< NMAXTRANS
);
1051 mnTransVals
[ nIdx
] = pTop
[-1];
1055 case TYPE2OP::GET
: {
1056 assert( mnStackIdx
>= 1 );
1057 const int nIdx
= static_cast<int>(pTop
[0]);
1058 assert( nIdx
>= 0 );
1059 assert( nIdx
< NMAXTRANS
);
1060 pTop
[0] = mnTransVals
[ nIdx
];
1063 case TYPE2OP::IFELSE
: {
1064 assert( mnStackIdx
>= 4 );
1065 if( pTop
[-1] > pTop
[0] )
1066 pTop
[-3] = pTop
[-2];
1070 case TYPE2OP::RANDOM
:
1071 pTop
[+1] = 1234; // TODO
1078 assert( mnStackIdx
>= 1 );
1082 case TYPE2OP::EXCH
: {
1083 assert( mnStackIdx
>= 2 );
1084 const ValType nVal
= pTop
[0];
1089 case TYPE2OP::INDEX
: {
1090 assert( mnStackIdx
>= 1 );
1091 const int nVal
= static_cast<int>(pTop
[0]);
1092 assert( nVal
>= 0 );
1093 assert( nVal
< mnStackIdx
-1 );
1094 pTop
[0] = pTop
[-1-nVal
];
1097 case TYPE2OP::ROLL
: {
1098 assert( mnStackIdx
>= 1 );
1099 const int nNum
= static_cast<int>(pTop
[0]);
1101 assert( nNum
< mnStackIdx
-2 );
1102 (void)nNum
; // TODO: implement
1103 const int nOfs
= static_cast<int>(pTop
[-1]);
1105 (void)nOfs
;// TODO: implement
1108 case TYPE2OP::HFLEX1
: {
1109 assert( mnStackIdx
== 9);
1111 writeCurveTo( mnStackIdx
, -9, -8, -7, -6, -5, 0);
1112 writeCurveTo( mnStackIdx
, -4, 0, -3, -2, -1, 0);
1113 // TODO: emulate hflex1 using othersubr call
1118 case TYPE2OP::HFLEX
: {
1119 assert( mnStackIdx
== 7);
1120 ValType
* pX
= &mnValStack
[ mnStackIdx
];
1122 pX
[+1] = -pX
[-5]; // temp: +dy5==-dy2
1123 writeCurveTo( mnStackIdx
, -7, 0, -6, -5, -4, 0);
1124 writeCurveTo( mnStackIdx
, -3, 0, -2, +1, -1, 0);
1125 // TODO: emulate hflex using othersubr call
1130 case TYPE2OP::FLEX
: {
1131 assert( mnStackIdx
== 13 );
1132 writeCurveTo( mnStackIdx
, -13, -12, -11, -10, -9, -8 );
1133 writeCurveTo( mnStackIdx
, -7, -6, -5, -4, -3, -2 );
1134 const ValType nFlexDepth
= mnValStack
[ mnStackIdx
-1 ];
1135 (void)nFlexDepth
; // ignoring nFlexDepth
1139 case TYPE2OP::FLEX1
: {
1140 assert( mnStackIdx
== 11 );
1141 // write the first part of the flex1-hinted curve
1142 writeCurveTo( mnStackIdx
, -11, -10, -9, -8, -7, -6 );
1144 // determine if nD6 is horizontal or vertical
1145 const int i
= mnStackIdx
;
1146 ValType nDeltaX
= mnValStack
[i
-11] + mnValStack
[i
-9] + mnValStack
[i
-7] + mnValStack
[i
-5] + mnValStack
[i
-3];
1147 if( nDeltaX
< 0 ) nDeltaX
= -nDeltaX
;
1148 ValType nDeltaY
= mnValStack
[i
-10] + mnValStack
[i
-8] + mnValStack
[i
-6] + mnValStack
[i
-4] + mnValStack
[i
-2];
1149 if( nDeltaY
< 0 ) nDeltaY
= -nDeltaY
;
1150 const bool bVertD6
= (nDeltaY
> nDeltaX
);
1152 // write the second part of the flex1-hinted curve
1154 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, -1, 0);
1156 writeCurveTo( mnStackIdx
, -5, -4, -3, -2, 0, -1);
1161 fprintf( stderr
,"unhandled type2esc %d\n", nType2Esc
);
1167 void CffSubsetterContext::callType2Subr( bool bGlobal
, int nSubrNumber
)
1169 const U8
* const pOldReadPtr
= mpReadPtr
;
1170 const U8
* const pOldReadEnd
= mpReadEnd
;
1173 nSubrNumber
+= mnGlobalSubrBias
;
1174 seekIndexData( mnGlobalSubrBase
, nSubrNumber
);
1176 nSubrNumber
+= mpCffLocal
->mnLocalSubrBias
;
1177 seekIndexData( mpCffLocal
->mnLocalSubrBase
, nSubrNumber
);
1180 while( mpReadPtr
< mpReadEnd
)
1183 mpReadPtr
= pOldReadPtr
;
1184 mpReadEnd
= pOldReadEnd
;
1187 static const int MAX_T1OPS_SIZE
= 81920; // TODO: use dynamic value
1189 int CffSubsetterContext::convert2Type1Ops( CffLocal
* pCffLocal
, const U8
* const pT2Ops
, int nT2Len
, U8
* const pT1Ops
)
1191 mpCffLocal
= pCffLocal
;
1193 // prepare the charstring conversion
1194 mpWritePtr
= pT1Ops
;
1195 #if 1 // TODO: update caller
1196 U8 aType1Ops
[ MAX_T1OPS_SIZE
];
1198 mpWritePtr
= aType1Ops
;
1199 *const_cast<U8
**>(&pT1Ops
) = mpWritePtr
;
1204 // prepend random seed for T1crypt
1205 *(mpWritePtr
++) = 0x48;
1206 *(mpWritePtr
++) = 0x44;
1207 *(mpWritePtr
++) = 0x55;
1208 *(mpWritePtr
++) = ' ';
1209 #if 1 // convert the Type2 charstring to Type1
1211 mpReadEnd
= pT2Ops
+ nT2Len
;
1212 // prepend "hsbw" or "sbw"
1213 // TODO: only emit hsbw when charwidth is known
1214 // TODO: remove charwidth from T2 stack
1215 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing();
1216 writeType1Val( 1000/*###getCharWidth()###*/);
1217 writeTypeOp( TYPE1OP::HSBW
);
1219 mbNeedClose
= false;
1220 mbIgnoreHints
= false;
1221 mnHintSize
=mnHorzHintSize
=mnStackIdx
=0; maCharWidth
=-1;//#######
1223 while( mpReadPtr
< mpReadEnd
)
1226 // writeTypeOp( TYPE1OP::CLOSEPATH);
1228 // writeTypeOp( TYPE1OP::RETURN);
1230 mpWritePtr
= pT1Ops
+4;
1231 // create an "idiotproof" charstring
1233 writeType1Val( 800);
1234 writeTypeOp( TYPE1OP::HSBW
);
1236 writeTypeOp( TYPE1OP::HMOVETO
);
1237 writeType1Val( 650);
1238 writeType1Val( 100);
1239 writeTypeOp( TYPE1OP::RLINETO
);
1240 writeType1Val( -350);
1241 writeType1Val( 700);
1242 writeTypeOp( TYPE1OP::RLINETO
);
1243 writeTypeOp( TYPE1OP::CLOSEPATH
);
1244 writeTypeOp( TYPE1OP::ENDCHAR
);
1246 #else // useful for manually encoding charstrings
1247 mpWritePtr
= pT1Ops
;
1248 mpWritePtr
+= sprintf( (char*)mpWritePtr
, "OOo_\x8b\x8c\x0c\x10\x0b");
1250 const int nType1Len
= mpWritePtr
- pT1Ops
;
1252 // encrypt the Type1 charstring
1253 int nRDCryptR
= 4330; // TODO: mnRDCryptSeed;
1254 for( U8
* p
= pT1Ops
; p
< mpWritePtr
; ++p
) {
1255 *p
^= (nRDCryptR
>> 8);
1256 nRDCryptR
= (*p
+ nRDCryptR
) * 52845 + 22719;
1262 RealType
CffSubsetterContext::readRealVal()
1264 // TODO: more thorough number validity test
1265 bool bComma
= false;
1269 RealType fReal
= +1.0;
1271 const U8 c
= *(mpReadPtr
++); // read nibbles
1272 // parse high nibble
1273 const U8 nH
= c
>> 4U;
1275 nNumber
= nNumber
* 10 + nH
;
1277 } else if( nH
== 10) { // comma
1280 } else if( nH
== 11) { // +exp
1284 } else if( nH
== 12) { // -exp
1288 } else if( nH
== 13) { // reserved
1289 // TODO: ignore or error?
1290 } else if( nH
== 14) // minus
1292 else if( nH
== 15) // end
1295 const U8 nL
= c
& 0x0F;
1297 nNumber
= nNumber
* 10 + nL
;
1299 } else if( nL
== 10) { // comma
1302 } else if( nL
== 11) { // +exp
1306 } else if( nL
== 12) { // -exp
1310 } else if( nL
== 13) { // reserved
1311 // TODO: ignore or error?
1312 } else if( nL
== 14) // minus
1314 else if( nL
== 15) // end
1321 if( !nExpSign
) { fReal
*= nNumber
;}
1322 else if( nExpSign
> 0) { nExpVal
+= static_cast<int>(nNumber
);}
1323 else if( nExpSign
< 0) { nExpVal
-= static_cast<int>(nNumber
);}
1326 if( !nExpVal
) { /*nothing to apply*/}
1327 else if( nExpVal
> 0) { while( --nExpVal
>= 0) fReal
*= 10.0;}
1328 else if( nExpVal
< 0) { while( ++nExpVal
<= 0) fReal
/= 10.0;}
1332 // prepare to access an element inside a CFF/CID index table
1333 int CffSubsetterContext::seekIndexData( int nIndexBase
, int nDataIndex
)
1335 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1338 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1339 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1340 if( nDataIndex
>= nDataCount
)
1342 const int nDataOfsSz
= mpReadPtr
[2];
1343 mpReadPtr
+= 3 + (nDataOfsSz
* nDataIndex
);
1345 switch( nDataOfsSz
) {
1346 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return -1;
1347 case 1: nOfs1
= mpReadPtr
[0]; break;
1348 case 2: nOfs1
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1349 case 3: nOfs1
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1350 case 4: nOfs1
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1352 mpReadPtr
+= nDataOfsSz
;
1355 switch( nDataOfsSz
) {
1356 case 1: nOfs2
= mpReadPtr
[0]; break;
1357 case 2: nOfs2
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1358 case 3: nOfs2
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2]; break;
1359 case 4: nOfs2
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1362 mpReadPtr
= mpBasePtr
+ (nIndexBase
+ 2) + nDataOfsSz
* (nDataCount
+ 1) + nOfs1
;
1363 mpReadEnd
= mpReadPtr
+ (nOfs2
- nOfs1
);
1364 assert( nOfs1
>= 0);
1365 assert( nOfs2
>= nOfs1
);
1366 assert( mpReadPtr
<= mpBaseEnd
);
1367 assert( mpReadEnd
<= mpBaseEnd
);
1368 return (nOfs2
- nOfs1
);
1371 // skip over a CFF/CID index table
1372 void CffSubsetterContext::seekIndexEnd( int nIndexBase
)
1374 assert( (nIndexBase
> 0) && (mpBasePtr
+ nIndexBase
+ 3 <= mpBaseEnd
));
1375 mpReadPtr
= mpBasePtr
+ nIndexBase
;
1376 const int nDataCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1377 const int nDataOfsSz
= mpReadPtr
[2];
1378 mpReadPtr
+= 3 + nDataOfsSz
* nDataCount
;
1379 assert( mpReadPtr
<= mpBaseEnd
);
1381 switch( nDataOfsSz
) {
1382 default: fprintf( stderr
, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz
); return;
1383 case 1: nEndOfs
= mpReadPtr
[0]; break;
1384 case 2: nEndOfs
= (mpReadPtr
[0]<<8) + mpReadPtr
[1]; break;
1385 case 3: nEndOfs
= (mpReadPtr
[0]<<16) + (mpReadPtr
[1]<<8) + mpReadPtr
[2];break;
1386 case 4: nEndOfs
= (mpReadPtr
[0]<<24) + (mpReadPtr
[1]<<16) + (mpReadPtr
[2]<<8) + mpReadPtr
[3]; break;
1388 mpReadPtr
+= nDataOfsSz
;
1389 mpReadPtr
+= nEndOfs
- 1;
1390 mpReadEnd
= mpBaseEnd
;
1391 assert( nEndOfs
>= 0);
1392 assert( mpReadEnd
<= mpBaseEnd
);
1395 // initialize FONTDICT specific values
1396 CffLocal::CffLocal()
1397 : mnPrivDictBase( 0)
1398 , mnPrivDictSize( 0)
1399 , mnLocalSubrOffs( 0)
1400 , mnLocalSubrBase( 0)
1401 , mnLocalSubrCount( 0)
1402 , mnLocalSubrBias( 0)
1403 , maNominalWidth( 0)
1404 , maDefaultWidth( 0)
1412 , mbForceBold( false)
1414 maStemSnapH
.clear();
1415 maStemSnapV
.clear();
1416 maBlueValues
.clear();
1417 maOtherBlues
.clear();
1418 maFamilyBlues
.clear();
1419 maFamilyOtherBlues
.clear();
1422 CffGlobal::CffGlobal()
1424 , mnNameIdxCount( 0)
1425 , mnStringIdxBase( 0)
1426 , mnStringIdxCount( 0)
1429 , mnCharStrCount( 0)
1430 , mnEncodingBase( 0)
1432 , mnGlobalSubrBase( 0)
1433 , mnGlobalSubrCount( 0)
1434 , mnGlobalSubrBias( 0)
1435 , mnFDSelectBase( 0)
1436 , mnFontDictBase( 0)
1440 , mnFamilyNameSID( 0)
1443 // TODO; maFontMatrix.clear();
1446 bool CffSubsetterContext::initialCffRead()
1448 // get the CFFHeader
1449 mpReadPtr
= mpBasePtr
;
1450 const U8 nVerMajor
= *(mpReadPtr
++);
1451 const U8 nVerMinor
= *(mpReadPtr
++);
1452 const U8 nHeaderSize
= *(mpReadPtr
++);
1453 const U8 nOffsetSize
= *(mpReadPtr
++);
1454 // TODO: is the version number useful for anything else?
1455 assert( (nVerMajor
== 1) && (nVerMinor
== 0));
1456 (void)(nVerMajor
+ nVerMinor
+ nOffsetSize
); // avoid compiler warnings
1458 // prepare access to the NameIndex
1459 mnNameIdxBase
= nHeaderSize
;
1460 mpReadPtr
= mpBasePtr
+ nHeaderSize
;
1461 mnNameIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1462 seekIndexEnd( mnNameIdxBase
);
1464 // get the TopDict index
1465 const sal_Int32 nTopDictBase
= getReadOfs();
1466 const int nTopDictCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1467 if( nTopDictCount
) {
1468 for( int i
= 0; i
< nTopDictCount
; ++i
) {
1469 seekIndexData( nTopDictBase
, i
);
1470 while( mpReadPtr
< mpReadEnd
)
1472 assert( mpReadPtr
== mpReadEnd
);
1476 // prepare access to the String index
1477 mnStringIdxBase
= getReadOfs();
1478 mnStringIdxCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1479 seekIndexEnd( mnStringIdxBase
);
1481 // prepare access to the GlobalSubr index
1482 mnGlobalSubrBase
= getReadOfs();
1483 mnGlobalSubrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1484 mnGlobalSubrBias
= (mnGlobalSubrCount
<1240)?107:(mnGlobalSubrCount
<33900)?1131:32768;
1485 // skip past the last GlobalSubr entry
1486 // seekIndexEnd( mnGlobalSubrBase);
1488 // get/skip the Encodings (we got mnEncodingBase from TOPDICT)
1489 // seekEncodingsEnd( mnEncodingBase);
1490 // get/skip the Charsets (we got mnCharsetBase from TOPDICT)
1491 // seekCharsetsEnd( mnCharStrBase);
1492 // get/skip FDSelect (CID only) data
1494 // prepare access to the CharStrings index (we got the base from TOPDICT)
1495 mpReadPtr
= mpBasePtr
+ mnCharStrBase
;
1496 mnCharStrCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1497 // seekIndexEnd( mnCharStrBase);
1499 // read the FDArray index (CID only)
1501 // assert( mnFontDictBase == tellRel());
1502 mpReadPtr
= mpBasePtr
+ mnFontDictBase
;
1503 mnFDAryCount
= (mpReadPtr
[0]<<8) + mpReadPtr
[1];
1504 if (static_cast<size_t>(mnFDAryCount
) >= SAL_N_ELEMENTS(maCffLocal
))
1506 SAL_INFO("vcl.fonts", "CffSubsetterContext: too many CFF in font");
1510 // read FDArray details to get access to the PRIVDICTs
1511 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1512 mpCffLocal
= &maCffLocal
[i
];
1513 seekIndexData( mnFontDictBase
, i
);
1514 while( mpReadPtr
< mpReadEnd
)
1516 assert( mpReadPtr
== mpReadEnd
);
1520 for( int i
= 0; i
< mnFDAryCount
; ++i
) {
1521 mpCffLocal
= &maCffLocal
[i
];
1523 // get the PrivateDict index
1524 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray)
1525 if( mpCffLocal
->mnPrivDictSize
!= 0) {
1526 assert( mpCffLocal
->mnPrivDictSize
> 0);
1527 // get the PrivDict data
1528 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnPrivDictBase
;
1529 mpReadEnd
= mpReadPtr
+ mpCffLocal
->mnPrivDictSize
;
1530 assert( mpReadEnd
<= mpBaseEnd
);
1531 // read PrivDict details
1532 while( mpReadPtr
< mpReadEnd
)
1536 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT)
1537 if( mpCffLocal
->mnLocalSubrOffs
) {
1538 // read LocalSubrs summary
1539 mpCffLocal
->mnLocalSubrBase
= mpCffLocal
->mnPrivDictBase
+ mpCffLocal
->mnLocalSubrOffs
;
1540 mpReadPtr
= mpBasePtr
+ mpCffLocal
->mnLocalSubrBase
;
1541 const int nSubrCount
= (mpReadPtr
[0] << 8) + mpReadPtr
[1];
1542 mpCffLocal
->mnLocalSubrCount
= nSubrCount
;
1543 mpCffLocal
->mnLocalSubrBias
= (nSubrCount
<1240)?107:(nSubrCount
<33900)?1131:32768;
1544 // seekIndexEnd( mpCffLocal->mnLocalSubrBase);
1548 // ignore the Notices info
1553 // get a cstring from a StringID
1554 const char* CffSubsetterContext::getString( int nStringID
)
1556 // get a standard string if possible
1557 const static int nStdStrings
= sizeof(pStringIds
)/sizeof(*pStringIds
);
1558 if( (nStringID
>= 0) && (nStringID
< nStdStrings
))
1559 return pStringIds
[ nStringID
];
1561 // else get the string from the StringIndex table
1562 const U8
* pReadPtr
= mpReadPtr
;
1563 const U8
* pReadEnd
= mpReadEnd
;
1564 nStringID
-= nStdStrings
;
1565 int nLen
= seekIndexData( mnStringIdxBase
, nStringID
);
1566 // assert( nLen >= 0);
1567 // TODO: just return the undecorated name
1568 // TODO: get rid of static char buffer
1569 static char aNameBuf
[ 2560];
1571 sprintf( aNameBuf
, "name[%d].notfound!", nStringID
);
1573 const int nMaxLen
= sizeof(aNameBuf
) - 1;
1574 if( nLen
>= nMaxLen
)
1576 for( int i
= 0; i
< nLen
; ++i
)
1577 aNameBuf
[i
] = *(mpReadPtr
++);
1578 aNameBuf
[ nLen
] = '\0';
1580 mpReadPtr
= pReadPtr
;
1581 mpReadEnd
= pReadEnd
;
1585 // access a CID's FDSelect table
1586 int CffSubsetterContext::getFDSelect( int nGlyphIndex
) const
1588 assert( nGlyphIndex
>= 0);
1589 assert( nGlyphIndex
< mnCharStrCount
);
1593 const U8
* pReadPtr
= mpBasePtr
+ mnFDSelectBase
;
1594 const U8 nFDSelFormat
= *(pReadPtr
++);
1595 switch( nFDSelFormat
) {
1596 case 0: { // FDSELECT format 0
1597 pReadPtr
+= nGlyphIndex
;
1598 const U8 nFDIdx
= *(pReadPtr
++);
1601 case 3: { // FDSELECT format 3
1602 const U16 nRangeCount
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1603 assert( nRangeCount
> 0);
1604 assert( nRangeCount
<= mnCharStrCount
);
1605 U16 nPrev
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1606 assert( nPrev
== 0);
1609 // TODO? binary search
1610 for( int i
= 0; i
< nRangeCount
; ++i
) {
1611 const U8 nFDIdx
= pReadPtr
[0];
1612 const U16 nNext
= (pReadPtr
[1]<<8) + pReadPtr
[2];
1613 assert( nPrev
< nNext
);
1614 if( nGlyphIndex
< nNext
)
1620 default: // invalid FDselect format
1621 fprintf( stderr
, "invalid CFF.FdselType=%d\n", nFDSelFormat
);
1629 int CffSubsetterContext::getGlyphSID( int nGlyphIndex
) const
1631 if( nGlyphIndex
== 0)
1632 return 0; // ".notdef"
1633 assert( nGlyphIndex
>= 0);
1634 assert( nGlyphIndex
< mnCharStrCount
);
1635 if( (nGlyphIndex
< 0) || (nGlyphIndex
>= mnCharStrCount
))
1638 // get the SID/CID from the Charset table
1639 const U8
* pReadPtr
= mpBasePtr
+ mnCharsetBase
;
1640 const U8 nCSetFormat
= *(pReadPtr
++);
1641 int nGlyphsToSkip
= nGlyphIndex
- 1;
1642 switch( nCSetFormat
) {
1643 case 0: // charset format 0
1644 pReadPtr
+= 2 * nGlyphsToSkip
;
1647 case 1: // charset format 1
1648 while( nGlyphsToSkip
>= 0) {
1649 const int nLeft
= pReadPtr
[2];
1650 if( nGlyphsToSkip
<= nLeft
)
1652 nGlyphsToSkip
-= nLeft
+ 1;
1656 case 2: // charset format 2
1657 while( nGlyphsToSkip
>= 0) {
1658 const int nLeft
= (pReadPtr
[2]<<8) + pReadPtr
[3];
1659 if( nGlyphsToSkip
<= nLeft
)
1661 nGlyphsToSkip
-= nLeft
+ 1;
1666 fprintf( stderr
, "ILLEGAL CFF-Charset format %d\n", nCSetFormat
);
1670 int nSID
= (pReadPtr
[0]<<8) + pReadPtr
[1];
1671 nSID
+= nGlyphsToSkip
;
1672 // NOTE: for CID-fonts the resulting SID is interpreted as CID
1676 // NOTE: the result becomes invalid with the next call to this method
1677 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex
)
1679 // the first glyph is always the .notdef glyph
1680 const char* pGlyphName
= ".notdef";
1681 if( nGlyphIndex
== 0)
1684 // prepare a result buffer
1685 // TODO: get rid of static buffer
1686 static char aDefaultGlyphName
[64];
1687 pGlyphName
= aDefaultGlyphName
;
1689 // get the glyph specific name
1690 const int nSID
= getGlyphSID( nGlyphIndex
);
1691 if( nSID
< 0) // default glyph name
1692 sprintf( aDefaultGlyphName
, "gly%03d", nGlyphIndex
);
1693 else if( mbCIDFont
) // default glyph name in CIDs
1694 sprintf( aDefaultGlyphName
, "cid%03d", nSID
);
1695 else { // glyph name from string table
1696 const char* pSidName
= getString( nSID
);
1697 // check validity of glyph name
1699 const char* p
= pSidName
;
1700 while( (*p
>= '0') && (*p
<= 'z')) ++p
;
1701 if( (p
>= pSidName
+1) && (*p
== '\0'))
1702 pGlyphName
= pSidName
;
1704 // if needed invent a fallback name
1705 if( pGlyphName
!= pSidName
)
1706 sprintf( aDefaultGlyphName
, "bad%03d", nSID
);
1715 explicit Type1Emitter( FILE* pOutFile
, bool bPfbSubset
= true);
1717 void setSubsetName( const char* );
1719 size_t emitRawData( const char* pData
, size_t nLength
) const;
1722 void emitAllCrypted();
1723 int tellPos() const;
1724 size_t updateLen( int nTellPos
, size_t nLength
);
1725 void emitValVector( const char* pLineHead
, const char* pLineTail
, const ValVector
&);
1728 bool mbCloseOutfile
;
1729 char maBuffer
[MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
1734 char maSubsetName
[256];
1739 Type1Emitter::Type1Emitter( FILE* pOutFile
, bool bPfbSubset
)
1740 : mpFileOut( pOutFile
)
1741 , mbCloseOutfile( false)
1742 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed
1744 , mbPfbSubset( bPfbSubset
)
1747 maSubsetName
[0] = '\0';
1750 Type1Emitter::~Type1Emitter()
1754 if( mbCloseOutfile
)
1759 void Type1Emitter::setSubsetName( const char* pSubsetName
)
1761 maSubsetName
[0] = '\0';
1763 strncpy( maSubsetName
, pSubsetName
, sizeof(maSubsetName
));
1764 maSubsetName
[sizeof(maSubsetName
)-1] = '\0';
1767 int Type1Emitter::tellPos() const
1769 int nTellPos
= ftell( mpFileOut
);
1773 size_t Type1Emitter::updateLen( int nTellPos
, size_t nLength
)
1775 // update PFB segment header length
1777 cData
[0] = static_cast<U8
>(nLength
>> 0);
1778 cData
[1] = static_cast<U8
>(nLength
>> 8);
1779 cData
[2] = static_cast<U8
>(nLength
>> 16);
1780 cData
[3] = static_cast<U8
>(nLength
>> 24);
1781 const long nCurrPos
= ftell(mpFileOut
);
1784 if (fseek( mpFileOut
, nTellPos
, SEEK_SET
) != 0)
1786 size_t nWrote
= fwrite(cData
, 1, sizeof(cData
), mpFileOut
);
1788 (void)fseek(mpFileOut
, nCurrPos
, SEEK_SET
);
1792 inline size_t Type1Emitter::emitRawData(const char* pData
, size_t nLength
) const
1794 return fwrite( pData
, 1, nLength
, mpFileOut
);
1797 inline void Type1Emitter::emitAllRaw()
1799 // writeout raw data
1800 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
1801 emitRawData( maBuffer
, mpPtr
- maBuffer
);
1802 // reset the raw buffer
1806 inline void Type1Emitter::emitAllHex()
1808 assert( (mpPtr
- maBuffer
) < (int)sizeof(maBuffer
));
1809 for( const char* p
= maBuffer
; p
< mpPtr
;) {
1810 // convert binary chunk to hex
1811 char aHexBuf
[0x4000];
1812 char* pOut
= aHexBuf
;
1813 while( (p
< mpPtr
) && (pOut
< aHexBuf
+sizeof(aHexBuf
)-4)) {
1814 // convert each byte to hex
1815 char cNibble
= (*p
>> 4) & 0x0F;
1816 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1817 *(pOut
++) = cNibble
;
1818 cNibble
= *(p
++) & 0x0F;
1819 cNibble
+= (cNibble
< 10) ? '0' : 'A'-10;
1820 *(pOut
++) = cNibble
;
1821 // limit the line length
1822 if( (++mnHexLineCol
& 0x3F) == 0)
1825 // writeout hex-converted chunk
1826 emitRawData( aHexBuf
, pOut
-aHexBuf
);
1828 // reset the raw buffer
1832 void Type1Emitter::emitAllCrypted()
1835 for( char* p
= maBuffer
; p
< mpPtr
; ++p
) {
1836 *p
^= (mnEECryptR
>> 8);
1837 mnEECryptR
= (*reinterpret_cast<U8
*>(p
) + mnEECryptR
) * 52845 + 22719;
1840 // emit the t1crypt result
1847 // #i110387# quick-and-dirty double->ascii conversion
1848 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC)
1849 // also strip off trailing zeros in fraction while we are at it
1850 inline int dbl2str( char* pOut
, double fVal
, int nPrecision
=6)
1852 const int nLen
= psp::getValueOfDouble( pOut
, fVal
, nPrecision
);
1856 void Type1Emitter::emitValVector( const char* pLineHead
, const char* pLineTail
,
1857 const ValVector
& rVector
)
1859 // ignore empty vectors
1860 if( rVector
.empty())
1863 // emit the line head
1864 mpPtr
+= sprintf( mpPtr
, "%s", pLineHead
);
1865 // emit the vector values
1866 ValVector::value_type aVal
= 0;
1867 for( ValVector::const_iterator it
= rVector
.begin();;) {
1869 if( ++it
== rVector
.end() )
1871 mpPtr
+= dbl2str( mpPtr
, aVal
);
1874 // emit the last value
1875 mpPtr
+= dbl2str( mpPtr
, aVal
);
1876 // emit the line tail
1877 mpPtr
+= sprintf( mpPtr
, "%s", pLineTail
);
1880 bool CffSubsetterContext::emitAsType1( Type1Emitter
& rEmitter
,
1881 const sal_GlyphId
* pReqGlyphIds
, const U8
* pReqEncoding
,
1882 GlyphWidth
* pGlyphWidths
, int nGlyphCount
, FontSubsetInfo
& rFSInfo
)
1884 // prepare some fontdirectory details
1885 static const int nUniqueIdBase
= 4100000; // using private-interchange UniqueIds
1886 static int nUniqueId
= nUniqueIdBase
;
1889 char* pFontName
= rEmitter
.maSubsetName
;
1891 if( mnFontNameSID
) {
1892 // get the fontname directly if available
1893 strncpy( pFontName
, getString( mnFontNameSID
), sizeof(rEmitter
.maSubsetName
) - 1);
1894 pFontName
[sizeof(rEmitter
.maSubsetName
) - 1] = 0;
1895 } else if( mnFullNameSID
) {
1896 // approximate fontname as fullname-whitespace
1897 const char* pI
= getString( mnFullNameSID
);
1898 char* pO
= pFontName
;
1899 const char* pLimit
= pFontName
+ sizeof(rEmitter
.maSubsetName
) - 1;
1900 while( pO
< pLimit
) {
1901 const char c
= *(pI
++);
1909 // fallback name of last resort
1910 strncpy( pFontName
, "DummyName", sizeof(rEmitter
.maSubsetName
));
1913 const char* pFullName
= pFontName
;
1914 const char* pFamilyName
= pFontName
;
1916 char*& pOut
= rEmitter
.mpPtr
; // convenience reference, TODO: cleanup
1918 // create a PFB+Type1 header
1919 if( rEmitter
.mbPfbSubset
) {
1920 static const char aPfbHeader
[] = "\x80\x01\x00\x00\x00\x00";
1921 rEmitter
.emitRawData( aPfbHeader
, sizeof(aPfbHeader
)-1);
1924 pOut
+= sprintf( pOut
, "%%!FontType1-1.0: %s 001.003\n", rEmitter
.maSubsetName
);
1926 pOut
+= sprintf( pOut
,
1927 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT
1929 "/PaintType 0 def\n");
1930 pOut
+= sprintf( pOut
, "/FontName /%s def\n", rEmitter
.maSubsetName
);
1931 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
1933 if( maFontMatrix
.size() == 6)
1934 rEmitter
.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix
);
1935 else // emit default FontMatrix if needed
1936 pOut
+= sprintf( pOut
, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n");
1938 if( maFontBBox
.size() == 4)
1939 rEmitter
.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox
);
1940 else // emit default FontBBox if needed
1941 pOut
+= sprintf( pOut
, "/FontBBox {0 0 999 999}readonly def\n");
1942 // emit FONTINFO into TOPDICT
1943 pOut
+= sprintf( pOut
,
1944 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count
1945 " /FullName (%s) readonly def\n"
1946 " /FamilyName (%s) readonly def\n"
1947 "end readonly def\n",
1948 pFullName
, pFamilyName
);
1950 pOut
+= sprintf( pOut
,
1951 "/Encoding 256 array\n"
1952 "0 1 255 {1 index exch /.notdef put} for\n");
1953 for( int i
= 1; (i
< nGlyphCount
) && (i
< 256); ++i
) {
1954 const char* pGlyphName
= getGlyphName( pReqGlyphIds
[i
]);
1955 pOut
+= sprintf( pOut
, "dup %d /%s put\n", pReqEncoding
[i
], pGlyphName
);
1957 pOut
+= sprintf( pOut
, "readonly def\n");
1958 pOut
+= sprintf( pOut
,
1959 // TODO: more topdict entries
1961 "currentfile eexec\n");
1964 rEmitter
.emitAllRaw();
1965 if( rEmitter
.mbPfbSubset
) {
1966 // update PFB header segment
1967 const int nPfbHeaderLen
= rEmitter
.tellPos() - 6;
1968 rEmitter
.updateLen( 2, nPfbHeaderLen
);
1970 // prepare start of eexec segment
1971 rEmitter
.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start
1973 const int nEExecSegTell
= rEmitter
.tellPos();
1975 // which always starts with a privdict
1976 // count the privdict entries
1977 int nPrivEntryCount
= 9;
1978 #if !defined(IGNORE_HINTS)
1979 // emit blue hints only if non-default values
1980 nPrivEntryCount
+= int(!mpCffLocal
->maOtherBlues
.empty());
1981 nPrivEntryCount
+= int(!mpCffLocal
->maFamilyBlues
.empty());
1982 nPrivEntryCount
+= int(!mpCffLocal
->maFamilyOtherBlues
.empty());
1983 nPrivEntryCount
+= int(mpCffLocal
->mfBlueScale
!= 0.0);
1984 nPrivEntryCount
+= int(mpCffLocal
->mfBlueShift
!= 0.0);
1985 nPrivEntryCount
+= int(mpCffLocal
->mfBlueFuzz
!= 0.0);
1986 // emit stem hints only if non-default values
1987 nPrivEntryCount
+= int(mpCffLocal
->maStemStdHW
!= 0);
1988 nPrivEntryCount
+= int(mpCffLocal
->maStemStdVW
!= 0);
1989 nPrivEntryCount
+= int(!mpCffLocal
->maStemSnapH
.empty());
1990 nPrivEntryCount
+= int(!mpCffLocal
->maStemSnapV
.empty());
1991 // emit other hints only if non-default values
1992 nPrivEntryCount
+= int(mpCffLocal
->mfExpFactor
!= 0.0);
1993 nPrivEntryCount
+= int(mpCffLocal
->mnLangGroup
!= 0);
1994 nPrivEntryCount
+= int(mpCffLocal
->mnLangGroup
== 1);
1995 nPrivEntryCount
+= int(mpCffLocal
->mbForceBold
);
1996 #endif // IGNORE_HINTS
1997 // emit the privdict header
1998 pOut
+= sprintf( pOut
,
2000 "dup\n/Private %d dict dup begin\n"
2001 "/RD{string currentfile exch readstring pop}executeonly def\n"
2002 "/ND{noaccess def}executeonly def\n"
2003 "/NP{noaccess put}executeonly def\n"
2004 "/MinFeature{16 16}ND\n"
2005 "/password 5839 def\n", // TODO: mnRDCryptSeed?
2008 #if defined(IGNORE_HINTS)
2009 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // BlueValues are mandatory
2011 // emit blue hint related privdict entries
2012 if( !mpCffLocal
->maBlueValues
.empty())
2013 rEmitter
.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal
->maBlueValues
);
2015 pOut
+= sprintf( pOut
, "/BlueValues []ND\n"); // default to empty BlueValues
2016 rEmitter
.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal
->maOtherBlues
);
2017 rEmitter
.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal
->maFamilyBlues
);
2018 rEmitter
.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal
->maFamilyOtherBlues
);
2020 if( mpCffLocal
->mfBlueScale
) {
2021 pOut
+= sprintf( pOut
, "/BlueScale ");
2022 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueScale
, 6);
2023 pOut
+= sprintf( pOut
, " def\n");
2025 if( mpCffLocal
->mfBlueShift
) { // default BlueShift==7
2026 pOut
+= sprintf( pOut
, "/BlueShift ");
2027 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueShift
);
2028 pOut
+= sprintf( pOut
, " def\n");
2030 if( mpCffLocal
->mfBlueFuzz
) { // default BlueFuzz==1
2031 pOut
+= sprintf( pOut
, "/BlueFuzz ");
2032 pOut
+= dbl2str( pOut
, mpCffLocal
->mfBlueFuzz
);
2033 pOut
+= sprintf( pOut
, " def\n");
2036 // emit stem hint related privdict entries
2037 if( mpCffLocal
->maStemStdHW
) {
2038 pOut
+= sprintf( pOut
, "/StdHW [");
2039 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdHW
);
2040 pOut
+= sprintf( pOut
, "] def\n");
2042 if( mpCffLocal
->maStemStdVW
) {
2043 pOut
+= sprintf( pOut
, "/StdVW [");
2044 pOut
+= dbl2str( pOut
, mpCffLocal
->maStemStdVW
);
2045 pOut
+= sprintf( pOut
, "] def\n");
2047 rEmitter
.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal
->maStemSnapH
);
2048 rEmitter
.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal
->maStemSnapV
);
2051 if( mpCffLocal
->mbForceBold
)
2052 pOut
+= sprintf( pOut
, "/ForceBold true def\n");
2053 if( mpCffLocal
->mnLangGroup
!= 0)
2054 pOut
+= sprintf( pOut
, "/LanguageGroup %d def\n", mpCffLocal
->mnLangGroup
);
2055 if( mpCffLocal
->mnLangGroup
== 1) // compatibility with ancient printers
2056 pOut
+= sprintf( pOut
, "/RndStemUp false def\n");
2057 if( mpCffLocal
->mfExpFactor
) {
2058 pOut
+= sprintf( pOut
, "/ExpansionFactor ");
2059 pOut
+= dbl2str( pOut
, mpCffLocal
->mfExpFactor
);
2060 pOut
+= sprintf( pOut
, " def\n");
2062 #endif // IGNORE_HINTS
2064 // emit remaining privdict entries
2065 pOut
+= sprintf( pOut
, "/UniqueID %d def\n", nUniqueId
);
2066 // TODO?: more privdict entries?
2068 static const char aOtherSubrs
[] =
2070 "% Dummy code for faking flex hints\n"
2071 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n"
2072 "{1183615869 systemdict /internaldict get exec\n"
2073 "dup /startlock known\n"
2074 "{/startlock get exec}\n"
2075 "{dup /strtlck known\n"
2076 "{/strtlck get exec}\n"
2077 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n"
2079 memcpy( pOut
, aOtherSubrs
, sizeof(aOtherSubrs
)-1);
2080 pOut
+= sizeof(aOtherSubrs
)-1;
2082 // emit used GlobalSubr charstrings
2083 // these are the just the default subrs
2084 // TODO: do we need them as the flex hints are resolved differently?
2085 static const char aSubrs
[] =
2087 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n"
2088 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n"
2089 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n"
2090 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n"
2091 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n"
2093 memcpy( pOut
, aSubrs
, sizeof(aSubrs
)-1);
2094 pOut
+= sizeof(aSubrs
)-1;
2096 // TODO: emit more GlobalSubr charstrings?
2097 // TODO: emit used LocalSubr charstrings?
2099 // emit the CharStrings for the requested glyphs
2100 pOut
+= sprintf( pOut
,
2101 "2 index /CharStrings %d dict dup begin\n", nGlyphCount
);
2102 rEmitter
.emitAllCrypted();
2103 for( int i
= 0; i
< nGlyphCount
; ++i
) {
2104 const int nCffGlyphId
= pReqGlyphIds
[i
];
2105 assert( (nCffGlyphId
>= 0) && (nCffGlyphId
< mnCharStrCount
));
2106 // get privdict context matching to the glyph
2107 const int nFDSelect
= getFDSelect( nCffGlyphId
);
2110 mpCffLocal
= &maCffLocal
[ nFDSelect
];
2111 // convert the Type2op charstring to its Type1op counterpart
2112 const int nT2Len
= seekIndexData( mnCharStrBase
, nCffGlyphId
);
2113 assert( nT2Len
> 0);
2114 U8 aType1Ops
[ MAX_T1OPS_SIZE
]; // TODO: dynamic allocation
2115 const int nT1Len
= convert2Type1Ops( mpCffLocal
, mpReadPtr
, nT2Len
, aType1Ops
);
2116 // get the glyph name
2117 const char* pGlyphName
= getGlyphName( nCffGlyphId
);
2118 // emit the encrypted Type1op charstring
2119 pOut
+= sprintf( pOut
, "/%s %d RD ", pGlyphName
, nT1Len
);
2120 memcpy( pOut
, aType1Ops
, nT1Len
);
2122 pOut
+= sprintf( pOut
, " ND\n");
2123 rEmitter
.emitAllCrypted();
2124 // provide individual glyphwidths if requested
2125 if( pGlyphWidths
) {
2126 ValType aCharWidth
= getCharWidth();
2127 if( maFontMatrix
.size() >= 4)
2128 aCharWidth
*= 1000.0F
* maFontMatrix
[0];
2129 pGlyphWidths
[i
] = static_cast<GlyphWidth
>(aCharWidth
);
2132 pOut
+= sprintf( pOut
, "end end\nreadonly put\nput\n");
2133 pOut
+= sprintf( pOut
, "dup/FontName get exch definefont pop\n");
2134 pOut
+= sprintf( pOut
, "mark currentfile closefile\n");
2135 rEmitter
.emitAllCrypted();
2137 // mark stop of eexec encryption
2138 if( rEmitter
.mbPfbSubset
) {
2139 const int nEExecLen
= rEmitter
.tellPos() - nEExecSegTell
;
2140 rEmitter
.updateLen( nEExecSegTell
-4, nEExecLen
);
2143 // create PFB footer
2144 static const char aPfxFooter
[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len
2145 "0000000000000000000000000000000000000000000000000000000000000000\n"
2146 "0000000000000000000000000000000000000000000000000000000000000000\n"
2147 "0000000000000000000000000000000000000000000000000000000000000000\n"
2148 "0000000000000000000000000000000000000000000000000000000000000000\n"
2149 "0000000000000000000000000000000000000000000000000000000000000000\n"
2150 "0000000000000000000000000000000000000000000000000000000000000000\n"
2151 "0000000000000000000000000000000000000000000000000000000000000000\n"
2152 "0000000000000000000000000000000000000000000000000000000000000000\n"
2155 if( rEmitter
.mbPfbSubset
)
2156 rEmitter
.emitRawData( aPfxFooter
, sizeof(aPfxFooter
)-1);
2158 rEmitter
.emitRawData( aPfxFooter
+6, sizeof(aPfxFooter
)-9);
2160 // provide details to the subset requesters, TODO: move into own method?
2161 // note: Top and Bottom are flipped between Type1 and VCL
2162 // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font
2163 ValType fXFactor
= 1.0;
2164 ValType fYFactor
= 1.0;
2165 if( maFontMatrix
.size() >= 4) {
2166 fXFactor
= 1000.0F
* maFontMatrix
[0];
2167 fYFactor
= 1000.0F
* maFontMatrix
[3];
2169 rFSInfo
.m_aFontBBox
= Rectangle( Point( static_cast<sal_Int32
>(maFontBBox
[0] * fXFactor
),
2170 static_cast<sal_Int32
>(maFontBBox
[1] * fYFactor
) ),
2171 Point( static_cast<sal_Int32
>(maFontBBox
[2] * fXFactor
),
2172 static_cast<sal_Int32
>(maFontBBox
[3] * fYFactor
) ) );
2173 // PDF-Spec says the values below mean the ink bounds!
2174 // TODO: use better approximations for these ink bounds
2175 rFSInfo
.m_nAscent
= +rFSInfo
.m_aFontBBox
.Bottom(); // for capital letters
2176 rFSInfo
.m_nDescent
= -rFSInfo
.m_aFontBBox
.Top(); // for all letters
2177 rFSInfo
.m_nCapHeight
= rFSInfo
.m_nAscent
; // for top-flat capital letters
2179 rFSInfo
.m_nFontType
= rEmitter
.mbPfbSubset
? FontSubsetInfo::TYPE1_PFB
: FontSubsetInfo::TYPE1_PFA
;
2180 rFSInfo
.m_aPSName
= OUString( rEmitter
.maSubsetName
, strlen(rEmitter
.maSubsetName
), RTL_TEXTENCODING_UTF8
);
2185 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth
* pOutGlyphWidths
)
2187 CffSubsetterContext
aCff( mpInFontBytes
, mnInByteLength
);
2188 bool bRC
= aCff
.initialCffRead();
2192 // emit Type1 subset from the CFF input
2193 // TODO: also support CFF->CFF subsetting (when PDF-export and PS-printing need it)
2194 const bool bPfbSubset
= (0 != (mnReqFontTypeMask
& FontSubsetInfo::TYPE1_PFB
));
2195 Type1Emitter
aType1Emitter( mpOutFile
, bPfbSubset
);
2196 aType1Emitter
.setSubsetName( mpReqFontName
);
2197 bRC
= aCff
.emitAsType1( aType1Emitter
,
2198 mpReqGlyphIds
, mpReqEncodedIds
,
2199 pOutGlyphWidths
, mnReqGlyphCount
, *this);
2203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */