1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 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. 14 * 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). 20 * 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. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include <cstdio> 32 #include <cstring> 33 #include <assert.h> 34 35 #include <fontsubset.hxx> 36 37 #include <vcl/strhelper.hxx> 38 39 //#define IGNORE_HINTS 40 41 typedef unsigned char U8; 42 typedef unsigned short U16; 43 typedef long long S64; 44 45 typedef sal_Int32 GlyphWidth; 46 47 typedef float RealType; 48 typedef RealType ValType; 49 #include <vector> 50 typedef std::vector<ValType> ValVector; 51 52 // ==================================================================== 53 54 static const char* pStringIds[] = { 55 /*0*/ ".notdef", "space", "exclam", "quotedbl", 56 "numbersign", "dollar", "percent", "ampersand", 57 "quoteright", "parenleft", "parenright", "asterisk", 58 "plus", "comma", "hyphen", "period", 59 /*16*/ "slash", "zero", "one", "two", 60 "three", "four", "five", "six", 61 "seven", "eight", "nine", "colon", 62 "semicolon", "less", "equal", "greater", 63 /*32*/ "question", "at", "A", "B", 64 "C", "D", "E", "F", 65 "G", "H", "I", "J", 66 "K", "L", "M", "N", 67 /*48*/ "O", "P", "Q", "R", 68 "S", "T", "U", "V", 69 "W", "X", "Y", "Z", 70 "bracketleft", "backslash", "bracketright", "asciicircum", 71 /*64*/ "underscore", "quoteleft", "a", "b", 72 "c", "d", "e", "f", 73 "g", "h", "i", "j", 74 "k", "l", "m", "n", 75 /*80*/ "o", "p", "q", "r", 76 "s", "t", "u", "v", 77 "w", "x", "y", "z", 78 "braceleft", "bar", "braceright", "asciitilde", 79 /*96*/ "exclamdown", "cent", "sterlin", "fraction", 80 "yen", "florin", "section", "currency", 81 "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", 82 "guilsinglright", "fi", "fl", "endash", 83 /*112*/ "dagger", "daggerdbl", "periodcentered", "paragraph", 84 "bullet", "quotesinglbase", "quotedblbase", "quotedblright", 85 "guillemotright", "ellipsis", "perthousand", "questiondown", 86 "grave", "acute", "circumflex", "tilde", 87 /*128*/ "macron", "breve", "dotaccent", "dieresis", 88 "ring", "cedilla", "hungarumlaut", "ogonek", 89 "caron", "endash", "AE", "ordfeminine", 90 "Lslash", "Oslash", "OE", "ordmasculine", 91 /*144*/ "ae", "dotlessi", "lslash", "oslash", 92 "oe", "germandbls", "onesuperior", "logicalnot", 93 "mu", "trademark", "Eth", "onehalf", 94 "plusminus", "Thorn", "onequarter", "divide", 95 /*160*/ "brokenbar", "degree", "thorn", "threequarters", 96 "twosuperior", "registered", "minus", "eth", 97 "multiply", "threesuperior", "copyright", "Aacute", 98 "Acircumflex", "Adieresis", "Agrave", "Aring", 99 /*176*/ "Atilde", "Ccedilla", "Eacute", "Ecircumflex", 100 "Edieresis", "Egrave", "Iacute", "Icircumflex", 101 "Idieresis", "Igrave", "Ntilde", "Oacute", 102 "Ocircumflex", "Odieresis", "Ograve", "Otilde", 103 /*192*/ "Scaron", "Uacute", "Ucircumflex", "Udieresis", 104 "Ugrave", "Yacute", "Ydieresis", "Zcaron", 105 "aacute", "acircumflex", "adieresis", "agrave", 106 "aring", "atilde", "ccedilla", "eacute", 107 /*208*/ "ecircumflex", "edieresis", "egrave", "iacute", 108 "icircumflex", "idieresis", "igrave", "ntilde", 109 "oacute", "ocircumflex", "odieresis", "ograve", 110 "otilde", "scaron", "uacute", "ucircumflex", 111 /*224*/ "udieresis", "ugrave", "yacute", "ydieresis", 112 "zcaron", "exclamsmall", "Hungarumlautsmall","dollaroldstyle", 113 "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", 114 "parenrightsuperior","twodotenleader", "onedotenleader", "zerooldstyle", 115 /*240*/ "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", 116 "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", 117 "nineoldstile", "commasuperior", "threequartersemdash","periodsuperior", 118 "questionsmall", "asuperior", "bsuperior", "centsuperior", 119 /*256*/ "dsuperior", "esuperior", "isuperior", "lsuperior", 120 "msuperior", "nsuperior", "osuperior", "rsuperior", 121 "ssuperior", "tsuperior", "ff", "ffi", 122 "ffl", "parenleftinferior","parenrightinferior","Circumflexsmall", 123 /*272*/ "hyphensuperior","Gravesmall", "Asmall", "Bsmall", 124 "Csmall", "Dsmall", "Esmall", "Fsmall", 125 "Gsmall", "Hsmall", "Ismall", "Jsmall", 126 "Ksmall", "Lsmall", "Msmall", "Nsmall", 127 /*288*/ "Osmall", "Psmall", "Qsmall", "Rsmall", 128 "Ssmall", "Tsmall", "Usmall", "Vsmall", 129 "Wsmall", "Xsmall", "Ysmall", "Zsmall", 130 "colonmonetary", "onefitted", "rupia", "Tildesmall", 131 /*304*/ "exclamdownsmall","centoldstyle", "Lslashsmall", "Scaronsmall", 132 "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", 133 "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", 134 "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", 135 /*320*/ "oneeight", "threeeights", "fiveeights", "seveneights", 136 "onethird", "twothirds", "zerosuperior", "foursuperior", 137 "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", 138 "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", 139 /*336*/ "threeinferior","fourinferior", "fiveinferior", "sixinferior", 140 "seveninferior", "eightinferior", "nineinferior", "centinferior", 141 "dollarinferior", "periodinferior", "commainferior", "Agravesmall", 142 "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", 143 /*352*/ "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", 144 "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", 145 "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", 146 "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", 147 /*368*/ "Otildesmall", "Odieressissmall", "OEsmall", "Oslashsmall", 148 "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", 149 "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", 150 "001.001", "001.002", "001.003", "Black", 151 /*384*/ "Bold", "Book", "Light", "Medium", 152 "Regular", "Roman", "Semibold" 153 }; 154 155 // -------------------------------------------------------------------- 156 157 #if 0 // TODO: use them 158 static const char* pStdEncNames[] = { 159 "ISOAdobe", "Expert", "ExpertSubSet" 160 }; 161 #endif 162 163 // -------------------------------------------------------------------- 164 165 // TOP DICT keywords (also covers PRIV DICT keywords) 166 static const char* pDictOps[] = { 167 "sVersion", "sNotice", "sFullName", "sFamilyName", 168 "sWeight", "aFontBBox", "dBlueValues", "dOtherBlues", 169 "dFamilyBlues", "dFamilyOtherBlues", "nStdHW", "nStdVW", 170 "xESC", "nUniqueID", "aXUID", "nCharset", 171 "nEncoding", "nCharStrings", "PPrivate", "nSubrs", 172 "nDefaultWidthX", "nNominalWidthX", NULL, NULL, 173 NULL, NULL, NULL, NULL, 174 "shortint", "longint", "BCD", NULL 175 }; 176 177 // -------------------------------------------------------------------- 178 179 // TOP DICT escapes (also covers PRIV DICT escapes) 180 static const char* pDictEscs[] = { 181 "sCopyright", "bIsFixedPitch", "nItalicAngle", "nUnderlinePosition", 182 "nUnderlineThickness", "nPaintType", "tCharstringType", "aFontMatrix", 183 "nStrokeWidth", "nBlueScale", "nBlueShift", "nBlueFuzz", 184 "dStemSnapH", "dStemSnapV", "bForceBold", NULL, 185 NULL, "nLanguageGroup", "nExpansionFactor", "nInitialRandomSeed", 186 "nSyntheticBase", "sPostScript", "sBaseFontName", "dBaseFontBlend", 187 NULL, NULL, NULL, NULL, 188 NULL, NULL, "rROS", "nCIDFontVersion", 189 "nCIDFontRevision", "nCIDFontType", "nCIDCount", "nUIDBase", 190 "nFDArray", "nFDSelect", "sFontName" 191 }; 192 193 // -------------------------------------------------------------------- 194 195 static const char* pType1Ops[] = { 196 NULL, "2hstem", NULL, "2vstem", 197 "1vmoveto", "Arlineto", "1hlineto", "1vlineto", 198 "Crrcurveto", "0closepath", "Lcallsubr", "0return", 199 "xT1ESC", "2hsbw", "0endchar", NULL, 200 NULL, NULL, NULL, NULL, 201 NULL, "2rmoveto", "1hmoveto", NULL, 202 NULL, NULL, NULL, NULL, 203 NULL, NULL, "4vhcurveto", "4hvcurveto" 204 }; 205 206 // -------------------------------------------------------------------- 207 208 static const char* pT1EscOps[] = { 209 "0dotsection", "6vstem3", "6hstem3", NULL, 210 NULL, NULL, "5seac", "4sbw", 211 NULL, "1abs", "2add", "2sub", 212 "2div", NULL, NULL, NULL, 213 "Gcallothersubr", "1pop", NULL, NULL, 214 NULL, NULL, NULL, NULL, 215 NULL, NULL, NULL, NULL, 216 NULL, NULL, NULL, NULL, 217 NULL, "2setcurrentpoint" 218 }; 219 220 // -------------------------------------------------------------------- 221 222 struct TYPE1OP 223 { 224 enum OPS 225 { 226 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5, 227 HLINETO=6, VLINETO=7, RCURVETO=8, CLOSEPATH=9, 228 CALLSUBR=10, RETURN=11, T1ESC=12, HSBW=13, 229 ENDCHAR=14, RMOVETO=21, HMOVETO=22, VHCURVETO=30, 230 HVCURVETO=31 231 }; 232 233 enum ESCS 234 { 235 DOTSECTION=0, VSTEM3=1, HSTEM3=2, SEAC=6, 236 SBW=7, ABS=9, ADD=10, SUB=11, 237 DIV=12, CALLOTHERSUBR=16, POP=17, SETCURRENTPOINT=33 238 }; 239 }; 240 241 // -------------------------------------------------------------------- 242 243 static const char* pType2Ops[] = { 244 NULL, "hhstem", NULL, "vvstem", 245 "mvmoveto", "Arlineto", "Ehlineto", "Evlineto", 246 "Crrcurveto", NULL, "Lcallsubr", "Xreturn", 247 "xT2ESC", NULL, "eendchar", NULL, 248 NULL, NULL, "Hhstemhm", "Khintmask", 249 "Kcntrmask", "Mrmoveto", "mhmoveto", "Vvstemhm", 250 ".rcurveline", ".rlinecurve", ".vvcurveto", ".hhcurveto", 251 ".shortint", "Gcallgsubr", ".vhcurveto", ".hvcurveto" 252 }; 253 254 // -------------------------------------------------------------------- 255 256 static const char* pT2EscOps[] = { 257 NULL, NULL, NULL, "2and", 258 "2or", "1not", NULL, NULL, 259 NULL, "1abs", "2add", "2sub", 260 "2div", NULL, "1neg", "2eq", 261 NULL, NULL, "1drop", NULL, 262 "1put", "1get", "4ifelse", "0random", 263 "2mul", NULL, "1sqrt", "1dup", 264 "2exch", "Iindex", "Rroll", NULL, 265 NULL, NULL, "7hflex", "Fflex", 266 "9hflex1", "fflex1" 267 }; 268 269 // -------------------------------------------------------------------- 270 271 struct TYPE2OP 272 { 273 enum OPS 274 { 275 HSTEM=1, VSTEM=3, VMOVETO=4, RLINETO=5, 276 HLINETO=6, VLINETO=7, RCURVETO=8, CALLSUBR=10, 277 RETURN=11, T2ESC=12, ENDCHAR=14, HSTEMHM=18, 278 HINTMASK=19, CNTRMASK=20, RMOVETO=21, HMOVETO=22, 279 VSTEMHM=23, RCURVELINE=24, RLINECURVE=25, VVCURVETO=26, 280 HHCURVETO=27, SHORTINT=28, CALLGSUBR=29, VHCURVETO=30, 281 HVCURVETO=31 282 }; 283 284 enum ESCS 285 { 286 AND=3, OR=4, NOT=5, ABS=9, 287 ADD=10, SUB=11, DIV=12, NEG=14, 288 EQ=15, DROP=18, PUT=20, GET=21, 289 IFELSE=22, RANDOM=23, MUL=24, SQRT=26, 290 DUP=27, EXCH=28, INDEX=29, ROLL=30, 291 HFLEX=34, FLEX=35, HFLEX1=36, FLEX1=37 292 }; 293 }; 294 295 // ==================================================================== 296 297 struct CffGlobal 298 { 299 explicit CffGlobal(); 300 301 int mnNameIdxBase; 302 int mnNameIdxCount; 303 int mnStringIdxBase; 304 int mnStringIdxCount; 305 bool mbCIDFont; 306 int mnCharStrBase; 307 int mnCharStrCount; 308 int mnEncodingBase; 309 int mnCharsetBase; 310 int mnGlobalSubrBase; 311 int mnGlobalSubrCount; 312 int mnGlobalSubrBias; 313 int mnFDSelectBase; 314 int mnFontDictBase; 315 int mnFDAryCount; 316 317 ValVector maFontBBox; 318 ValVector maFontMatrix; 319 320 int mnFontNameSID; 321 int mnFullNameSID; 322 int mnFamilyNameSID; 323 }; 324 325 // ==================================================================== 326 327 struct CffLocal 328 { 329 explicit CffLocal(); 330 331 int mnPrivDictBase; 332 int mnPrivDictSize; 333 int mnLocalSubrOffs; 334 int mnLocalSubrBase; 335 int mnLocalSubrCount; 336 int mnLocalSubrBias; 337 338 ValType maNominalWidth; 339 ValType maDefaultWidth; 340 341 // ATM hinting related values 342 ValType maStemStdHW; 343 ValType maStemStdVW; 344 ValVector maStemSnapH; 345 ValVector maStemSnapV; 346 ValVector maBlueValues; 347 ValVector maOtherBlues; 348 ValVector maFamilyBlues; 349 ValVector maFamilyOtherBlues; 350 RealType mfBlueScale; 351 RealType mfBlueShift; 352 RealType mfBlueFuzz; 353 RealType mfExpFactor; 354 int mnLangGroup; 355 bool mbForceBold; 356 }; 357 358 // ==================================================================== 359 360 class SubsetterContext 361 { 362 public: 363 virtual ~SubsetterContext( void); 364 virtual bool emitAsType1( class Type1Emitter&, 365 const long* pGlyphIDs, const U8* pEncoding, 366 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& ) = 0; 367 }; 368 369 // -------------------------------------------------------------------- 370 371 SubsetterContext::~SubsetterContext( void) 372 {} 373 374 // ==================================================================== 375 376 class CffSubsetterContext 377 : public SubsetterContext 378 , private CffGlobal 379 { 380 public: 381 static const int NMAXSTACK = 48; // see CFF.appendixB 382 static const int NMAXHINTS = 2*96; // see CFF.appendixB 383 static const int NMAXTRANS = 32; // see CFF.appendixB 384 public: 385 explicit CffSubsetterContext( const U8* pBasePtr, int nBaseLen); 386 virtual ~CffSubsetterContext( void); 387 388 void initialCffRead( void); 389 bool emitAsType1( class Type1Emitter&, 390 const long* pGlyphIDs, const U8* pEncoding, 391 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& ); 392 393 // used by charstring converter 394 void setCharStringType( int); 395 void fakeLocalSubrCount( int nLocalSubrs ) { maCffLocal[0].mnLocalSubrCount=nLocalSubrs;} 396 protected: 397 int convert2Type1Ops( CffLocal*, const U8* pType2Ops, int nType2Len, U8* pType1Ops); 398 private: 399 void convertOneTypeOp( void); 400 void convertOneTypeEsc( void); 401 void callType2Subr( bool bGlobal, int nSubrNumber); 402 long getReadOfs( void) const { return (long)(mpReadPtr - mpBasePtr);} 403 404 const U8* mpBasePtr; 405 const U8* mpBaseEnd; 406 407 const U8* mpReadPtr; 408 const U8* mpReadEnd; 409 410 U8* mpWritePtr; 411 bool mbSawError; 412 bool mbNeedClose; 413 bool mbIgnoreHints; 414 long mnCntrMask; 415 416 private: 417 int seekIndexData( int nIndexBase, int nDataIndex); 418 void seekIndexEnd( int nIndexBase); 419 420 private: 421 const char** mpCharStringOps; 422 const char** mpCharStringEscs; 423 424 CffLocal maCffLocal[16]; 425 CffLocal* mpCffLocal; 426 427 void readDictOp( void); 428 RealType readRealVal( void); 429 const char* getString( int nStringID); 430 int getFDSelect( int nGlyphIndex) const; 431 int getGlyphSID( int nGlyphIndex) const; 432 const char* getGlyphName( int nGlyphIndex); 433 434 void read2push( void); 435 void pop2write( void); 436 void writeType1Val( ValType); 437 void writeTypeOp( int nTypeOp); 438 void writeTypeEsc( int nTypeOp); 439 void writeCurveTo( int nStackPos, int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3); 440 void pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor=0); 441 void popAll2Write( int nTypeOp); 442 443 public: // TODO: is public really needed? 444 // accessing the value stack 445 // TODO: add more checks 446 void push( ValType nVal) { mnValStack[ mnStackIdx++] = nVal;} 447 ValType popVal( void) { return ((mnStackIdx>0) ? mnValStack[ --mnStackIdx] : 0);} 448 ValType peekVal( void) const { return ((mnStackIdx>0) ? mnValStack[ mnStackIdx-1] : 0);} 449 ValType getVal( int nIndex) const { return mnValStack[ nIndex];} 450 int popInt( void); 451 int peekInt( void) const; 452 int getInt( int nIndex) const; 453 int size( void) const { return mnStackIdx;} 454 bool empty( void) const { return !mnStackIdx;} 455 void clear( void) { mnStackIdx = 0;} 456 457 // accessing the charstring hints 458 void addHints( bool bVerticalHints); 459 int getHorzHintCount( void) const { return (mnHorzHintSize/2);} 460 int getVertHintCount( void) const { return (mnHintSize-mnHorzHintSize)/2;} 461 void getHintPair( int nIndex, ValType* nMin, ValType* nEnd) const; 462 463 // accessing other charstring specifics 464 bool hasCharWidth( void) const { return (maCharWidth > 0);} 465 ValType getCharWidth( void) const { return maCharWidth;} 466 void setNominalWidth( ValType aWidth) { mpCffLocal->maNominalWidth = aWidth;} 467 void setDefaultWidth( ValType aWidth) { mpCffLocal->maDefaultWidth = aWidth;} 468 void updateWidth( bool bUseFirstVal); 469 470 private: 471 // typeop exceution context 472 int mnStackIdx; 473 ValType mnValStack[ NMAXSTACK+4]; 474 ValType mnTransVals[ NMAXTRANS]; 475 476 int mnHintSize; 477 int mnHorzHintSize; 478 ValType mnHintStack[ NMAXHINTS]; 479 480 ValType maCharWidth; 481 }; 482 483 // -------------------------------------------------------------------- 484 485 CffSubsetterContext::CffSubsetterContext( const U8* pBasePtr, int nBaseLen) 486 : mpBasePtr( pBasePtr) 487 , mpBaseEnd( pBasePtr+nBaseLen) 488 , mnStackIdx(0) 489 , mnHintSize(0) 490 , mnHorzHintSize(0) 491 , maCharWidth(-1) 492 { 493 // setCharStringType( 1); 494 // TODO: new CffLocal[ mnFDAryCount]; 495 mpCffLocal = &maCffLocal[0]; 496 } 497 498 // -------------------------------------------------------------------- 499 500 CffSubsetterContext::~CffSubsetterContext( void) 501 { 502 // TODO: delete[] maCffLocal; 503 } 504 505 // -------------------------------------------------------------------- 506 507 inline int CffSubsetterContext::popInt( void) 508 { 509 const ValType aVal = popVal(); 510 const int nInt = static_cast<int>(aVal); 511 assert( nInt == aVal); 512 return nInt; 513 } 514 515 // -------------------------------------------------------------------- 516 517 inline int CffSubsetterContext::peekInt( void) const 518 { 519 const ValType aVal = peekVal(); 520 const int nInt = static_cast<int>(aVal); 521 assert( nInt == aVal); 522 return nInt; 523 } 524 525 // -------------------------------------------------------------------- 526 527 inline int CffSubsetterContext::getInt( int nIndex) const 528 { 529 const ValType aVal = getVal( nIndex); 530 const int nInt = static_cast<int>(aVal); 531 assert( nInt == aVal); 532 return nInt; 533 } 534 535 // -------------------------------------------------------------------- 536 537 inline void CffSubsetterContext::updateWidth( bool bUseFirstVal) 538 { 539 #if 1 // TODO: is this still needed? 540 // the first value is not a hint but the charwidth 541 if( hasCharWidth()) 542 return; 543 #endif 544 if( bUseFirstVal) { 545 maCharWidth = mpCffLocal->maNominalWidth + mnValStack[0]; 546 // remove bottom stack entry 547 --mnStackIdx; 548 for( int i = 0; i < mnStackIdx; ++i) 549 mnValStack[ i] = mnValStack[ i+1]; 550 } else { 551 maCharWidth = mpCffLocal->maDefaultWidth; 552 } 553 } 554 555 // -------------------------------------------------------------------- 556 557 void CffSubsetterContext::addHints( bool bVerticalHints) 558 { 559 // the first charstring value may a charwidth instead of a charwidth 560 updateWidth( (mnStackIdx & 1) != 0); 561 // return early (e.g. no implicit hints for hintmask) 562 if( !mnStackIdx) 563 return; 564 565 // copy the remaining values to the hint arrays 566 // assert( (mnStackIdx & 1) == 0); // depends on called subrs 567 if( mnStackIdx & 1) --mnStackIdx;//####### 568 // TODO: if( !bSubr) assert( mnStackIdx >= 2); 569 570 assert( (mnHintSize + mnStackIdx) <= 2*NMAXHINTS); 571 572 #ifdef IGNORE_HINTS 573 mnHintSize += mnStackIdx; 574 #else 575 ValType nHintOfs = 0; 576 for( int i = 0; i < mnStackIdx; ++i) { 577 nHintOfs += mnValStack[ i ]; 578 mnHintStack[ mnHintSize++] = nHintOfs; 579 } 580 #endif // IGNORE_HINTS 581 if( !bVerticalHints) 582 mnHorzHintSize = mnHintSize; 583 584 // clear all values from the stack 585 mnStackIdx = 0; 586 } 587 588 // -------------------------------------------------------------------- 589 590 void CffSubsetterContext::getHintPair( int nIndex, ValType* pMin, ValType* pEnd) const 591 { 592 nIndex *= 2; 593 assert( nIndex < mnHintSize); 594 assert( nIndex >= 0); 595 const ValType* pHint = &mnHintStack[ nIndex ]; 596 *pMin = pHint[0]; 597 *pEnd = pHint[1]; 598 } 599 600 // -------------------------------------------------------------------- 601 602 void CffSubsetterContext::setCharStringType( int nVal) 603 { 604 switch( nVal) { 605 case 1: mpCharStringOps=pType1Ops; mpCharStringEscs=pT1EscOps; break; 606 case 2: mpCharStringOps=pType2Ops; mpCharStringEscs=pT2EscOps; break; 607 default: fprintf( stderr, "Unknown CharstringType=%d\n",nVal); break; 608 } 609 } 610 611 // -------------------------------------------------------------------- 612 613 void CffSubsetterContext::readDictOp( void) 614 { 615 ValType nVal = 0; 616 int nInt = 0; 617 const U8 c = *mpReadPtr; 618 if( c <= 21 ) { 619 int nOpId = *(mpReadPtr++); 620 const char* pCmdName; 621 if( nOpId != 12) 622 pCmdName = pDictOps[ nOpId]; 623 else { 624 const U8 nExtId = *(mpReadPtr++); 625 pCmdName = pDictEscs[ nExtId]; 626 nOpId = 900 + nExtId; 627 } 628 629 //TODO: if( nStackIdx > 0) 630 switch( *pCmdName) { 631 default: fprintf( stderr, "unsupported DictOp.type=\'%c\'\n", *pCmdName); break; 632 case 'b': // bool 633 nInt = popInt(); 634 switch( nOpId) { 635 case 915: mpCffLocal->mbForceBold = nInt; break; // "ForceBold" 636 default: break; // TODO: handle more boolean dictops? 637 } 638 break; 639 case 'n': // dict-op number 640 nVal = popVal(); 641 nInt = static_cast<int>(nVal); 642 switch( nOpId) { 643 case 10: mpCffLocal->maStemStdHW = nVal; break; // "StdHW" 644 case 11: mpCffLocal->maStemStdVW = nVal; break; // "StdVW" 645 case 15: mnCharsetBase = nInt; break; // "charset" 646 case 16: mnEncodingBase = nInt; break; // "nEncoding" 647 case 17: mnCharStrBase = nInt; break; // "nCharStrings" 648 case 19: mpCffLocal->mnLocalSubrOffs = nInt; break;// "nSubrs" 649 case 20: setDefaultWidth( nVal ); break; // "defaultWidthX" 650 case 21: setNominalWidth( nVal ); break; // "nominalWidthX" 651 case 909: mpCffLocal->mfBlueScale = nVal; break; // "BlueScale" 652 case 910: mpCffLocal->mfBlueShift = nVal; break; // "BlueShift" 653 case 911: mpCffLocal->mfBlueFuzz = nVal; break; // "BlueFuzz" 654 case 912: mpCffLocal->mfExpFactor = nVal; break; // "ExpansionFactor" 655 case 917: mpCffLocal->mnLangGroup = nInt; break; // "LanguageGroup" 656 case 936: mnFontDictBase = nInt; break; // "nFDArray" 657 case 937: mnFDSelectBase = nInt; break; // "nFDSelect" 658 default: break; // TODO: handle more numeric dictops? 659 } 660 break; 661 case 'a': { // array 662 switch( nOpId) { 663 case 5: maFontBBox.clear(); break; // "FontBBox" 664 case 907: maFontMatrix.clear(); break; // "FontMatrix" 665 default: break; // TODO: reset other arrays? 666 } 667 for( int i = 0; i < size(); ++i ) { 668 nVal = getVal(i); 669 switch( nOpId) { 670 case 5: maFontBBox.push_back( nVal); break; // "FontBBox" 671 case 907: maFontMatrix.push_back( nVal); break; // "FontMatrix" 672 default: break; // TODO: handle more array dictops? 673 } 674 } 675 clear(); 676 } break; 677 case 'd': { // delta array 678 nVal = 0; 679 for( int i = 0; i < size(); ++i ) { 680 nVal += getVal(i); 681 switch( nOpId) { 682 case 6: mpCffLocal->maBlueValues.push_back( nVal); break; // "BlueValues" 683 case 7: mpCffLocal->maOtherBlues.push_back( nVal); break; // "OtherBlues" 684 case 8: mpCffLocal->maFamilyBlues.push_back( nVal); break; // "FamilyBlues" 685 case 9: mpCffLocal->maFamilyOtherBlues.push_back( nVal); break;// "FamilyOtherBlues" 686 case 912: mpCffLocal->maStemSnapH.push_back( nVal); break; // "StemSnapH" 687 case 913: mpCffLocal->maStemSnapV.push_back( nVal); break; // "StemSnapV" 688 default: break; // TODO: handle more delta-array dictops? 689 } 690 } 691 clear(); 692 } break; 693 case 's': // stringid (SID) 694 nInt = popInt(); 695 switch( nOpId ) { 696 case 2: mnFullNameSID = nInt; break; // "FullName" 697 case 3: mnFamilyNameSID = nInt; break; // "FamilyName" 698 case 938: mnFontNameSID = nInt; break; // "FontName" 699 default: break; // TODO: handle more string dictops? 700 } 701 break; 702 case 'P': // private dict 703 mpCffLocal->mnPrivDictBase = popInt(); 704 mpCffLocal->mnPrivDictSize = popInt(); 705 break; 706 case 'r': { // ROS operands 707 int nSid1 = popInt(); 708 int nSid2 = popInt(); 709 (void)nSid1; // TODO: use 710 (void)nSid2; // TODO: use 711 nVal = popVal(); 712 mbCIDFont = true; 713 } break; 714 case 't': // CharstringType 715 nInt = popInt(); 716 setCharStringType( nInt ); 717 break; 718 } 719 720 return; 721 } 722 723 if( (c >= 32) || (c == 28) ) { 724 // --mpReadPtr; 725 read2push(); 726 } else if( c == 29 ) { // longint 727 ++mpReadPtr; // skip 29 728 int nS32 = mpReadPtr[0] << 24; 729 nS32 += mpReadPtr[1] << 16; 730 nS32 += mpReadPtr[2] << 8; 731 nS32 += mpReadPtr[3] << 0; 732 if( (sizeof(nS32) != 4) && (nS32 & (1<<31))) 733 nS32 |= (~0U) << 31; // assuming 2s complement 734 mpReadPtr += 4; 735 nVal = static_cast<ValType>(nS32); 736 push( nVal ); 737 } else if( c == 30) { // real number 738 ++mpReadPtr; // skip 30 739 const RealType fReal = readRealVal(); 740 // push value onto stack 741 nVal = fReal; 742 push( nVal); 743 } 744 } 745 746 // -------------------------------------------------------------------- 747 748 void CffSubsetterContext::read2push() 749 { 750 ValType aVal = 0; 751 752 const U8*& p = mpReadPtr; 753 const U8 c = *p; 754 if( c == 28 ) { 755 short nS16 = (p[1] << 8) + p[2]; 756 if( (sizeof(nS16) != 2) && (nS16 & (1<<15))) 757 nS16 |= (~0U) << 15; // assuming 2s complement 758 aVal = nS16; 759 p += 3; 760 } else if( c <= 246 ) { // -107..+107 761 aVal = static_cast<ValType>(p[0] - 139); 762 p += 1; 763 } else if( c <= 250 ) { // +108..+1131 764 aVal = static_cast<ValType>(((p[0] << 8) + p[1]) - 63124); 765 p += 2; 766 } else if( c <= 254 ) { // -108..-1131 767 aVal = static_cast<ValType>(64148 - ((p[0] << 8) + p[1])); 768 p += 2; 769 } else /*if( c == 255)*/ { // Fixed16.16 770 int nS32 = (p[1] << 24) + (p[2] << 16) + (p[3] << 8) + p[4]; 771 if( (sizeof(nS32) != 2) && (nS32 & (1<<31))) 772 nS32 |= (~0U) << 31; // assuming 2s complement 773 aVal = static_cast<ValType>(nS32 * (1.0 / 0x10000)); 774 p += 5; 775 } 776 777 push( aVal); 778 } 779 780 // -------------------------------------------------------------------- 781 782 void CffSubsetterContext::writeType1Val( ValType aVal) 783 { 784 U8* pOut = mpWritePtr; 785 786 int nInt = static_cast<int>(aVal); 787 static const int nOutCharstrType = 1; 788 if( (nInt != aVal) && (nOutCharstrType == 2)) { 789 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!! 790 *(pOut++) = 255; // Fixed 16.16 791 *(pOut++) = static_cast<U8>(nInt >> 8); 792 *(pOut++) = static_cast<U8>(nInt); 793 nInt = static_cast<int>(aVal * 0x10000) & 0xFFFF; 794 *(pOut++) = static_cast<U8>(nInt >> 8); 795 *(pOut++) = static_cast<U8>(nInt); 796 } else if( (nInt >= -107) && (nInt <= +107)) { 797 *(pOut++) = static_cast<U8>(nInt + 139); // -107..+107 798 } else if( (nInt >= -1131) && (nInt <= +1131)) { 799 if( nInt >= 0) 800 nInt += 63124; // +108..+1131 801 else 802 nInt = 64148 - nInt; // -108..-1131 803 *(pOut++) = static_cast<U8>(nInt >> 8); 804 *(pOut++) = static_cast<U8>(nInt); 805 } else if( nOutCharstrType == 1) { 806 // numtype==255 means int32 for Type1, but 16.16 for Type2 charstrings!!! 807 *(pOut++) = 255; 808 *(pOut++) = static_cast<U8>(nInt >> 24); 809 *(pOut++) = static_cast<U8>(nInt >> 16); 810 *(pOut++) = static_cast<U8>(nInt >> 8); 811 *(pOut++) = static_cast<U8>(nInt); 812 } 813 814 mpWritePtr = pOut; 815 } 816 817 // -------------------------------------------------------------------- 818 819 inline void CffSubsetterContext::pop2write( void) 820 { 821 const ValType aVal = popVal(); 822 writeType1Val( aVal); 823 } 824 825 // -------------------------------------------------------------------- 826 827 inline void CffSubsetterContext::writeTypeOp( int nTypeOp) 828 { 829 *(mpWritePtr++) = static_cast<U8>(nTypeOp); 830 } 831 832 // -------------------------------------------------------------------- 833 834 inline void CffSubsetterContext::writeTypeEsc( int nTypeEsc) 835 { 836 *(mpWritePtr++) = TYPE1OP::T1ESC; 837 *(mpWritePtr++) = static_cast<U8>(nTypeEsc); 838 } 839 840 // -------------------------------------------------------------------- 841 842 void CffSubsetterContext::pop2MultiWrite( int nArgsPerTypo, int nTypeOp, int nTypeXor) 843 { 844 for( int i = 0; i < mnStackIdx;) { 845 for( int j = 0; j < nArgsPerTypo; ++j) { 846 const ValType aVal = mnValStack[i+j]; 847 writeType1Val( aVal); 848 } 849 i += nArgsPerTypo; 850 writeTypeOp( nTypeOp); 851 nTypeOp ^= nTypeXor; // for toggling vlineto/hlineto 852 } 853 clear(); 854 } 855 856 // -------------------------------------------------------------------- 857 858 void CffSubsetterContext::popAll2Write( int nTypeOp) 859 { 860 // pop in reverse order, then write 861 for( int i = 0; i < mnStackIdx; ++i) { 862 const ValType aVal = mnValStack[i]; 863 writeType1Val( aVal); 864 } 865 clear(); 866 writeTypeOp( nTypeOp); 867 } 868 869 // -------------------------------------------------------------------- 870 871 void CffSubsetterContext::writeCurveTo( int nStackPos, 872 int nIX1, int nIY1, int nIX2, int nIY2, int nIX3, int nIY3) 873 { 874 // get the values from the stack 875 const ValType nDX1 = nIX1 ? mnValStack[ nStackPos+nIX1 ] : 0; 876 const ValType nDY1 = nIY1 ? mnValStack[ nStackPos+nIY1 ] : 0; 877 const ValType nDX2 = nIX2 ? mnValStack[ nStackPos+nIX2 ] : 0; 878 const ValType nDY2 = nIY2 ? mnValStack[ nStackPos+nIY2 ] : 0; 879 const ValType nDX3 = nIX3 ? mnValStack[ nStackPos+nIX3 ] : 0; 880 const ValType nDY3 = nIY3 ? mnValStack[ nStackPos+nIY3 ] : 0; 881 882 // emit the curveto operator and operands 883 // TODO: determine the most efficient curveto operator 884 // TODO: depending on type1op or type2op target 885 writeType1Val( nDX1 ); 886 writeType1Val( nDY1 ); 887 writeType1Val( nDX2 ); 888 writeType1Val( nDY2 ); 889 writeType1Val( nDX3 ); 890 writeType1Val( nDY3 ); 891 writeTypeOp( TYPE1OP::RCURVETO ); 892 } 893 894 // -------------------------------------------------------------------- 895 896 void CffSubsetterContext::convertOneTypeOp( void) 897 { 898 const int nType2Op = *(mpReadPtr++); 899 900 int i, nInt; // prevent WAE for declarations inside switch cases 901 // convert each T2op 902 switch( nType2Op) { 903 case TYPE2OP::T2ESC: 904 convertOneTypeEsc(); 905 break; 906 case TYPE2OP::HSTEM: 907 case TYPE2OP::VSTEM: 908 addHints( nType2Op == TYPE2OP::VSTEM ); 909 #ifndef IGNORE_HINTS 910 for( i = 0; i < mnHintSize; i+=2 ) { 911 writeType1Val( mnHintStack[i]); 912 writeType1Val( mnHintStack[i+1] - mnHintStack[i]); 913 writeTypeOp( nType2Op ); 914 } 915 #endif // IGNORE_HINTS 916 break; 917 case TYPE2OP::HSTEMHM: 918 case TYPE2OP::VSTEMHM: 919 addHints( nType2Op == TYPE2OP::VSTEMHM); 920 break; 921 case TYPE2OP::CNTRMASK: 922 // TODO: replace cntrmask with vstem3/hstem3 923 addHints( true); 924 #ifdef IGNORE_HINTS 925 mpReadPtr += (mnHintSize + 15) / 16; 926 mbIgnoreHints = true; 927 #else 928 { 929 U8 nMaskBit = 0; 930 U8 nMaskByte = 0; 931 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) { 932 if( !nMaskBit) { 933 nMaskByte = *(mpReadPtr++); 934 nMaskBit = 0x80; 935 } 936 if( !(nMaskByte & nMaskBit)) 937 continue; 938 if( i >= 8*(int)sizeof(mnCntrMask)) 939 mbIgnoreHints = true; 940 if( mbIgnoreHints) 941 continue; 942 mnCntrMask |= (1U << i); 943 } 944 } 945 #endif 946 break; 947 case TYPE2OP::HINTMASK: 948 addHints( true); 949 #ifdef IGNORE_HINTS 950 mpReadPtr += (mnHintSize + 15) / 16; 951 #else 952 { 953 long nHintMask = 0; 954 int nCntrBits[2] = {0,0}; 955 U8 nMaskBit = 0; 956 U8 nMaskByte = 0; 957 for( i = 0; i < mnHintSize; i+=2, nMaskBit>>=1) { 958 if( !nMaskBit) { 959 nMaskByte = *(mpReadPtr++); 960 nMaskBit = 0x80; 961 } 962 if( !(nMaskByte & nMaskBit)) 963 continue; 964 if( i >= 8*(int)sizeof(nHintMask)) 965 mbIgnoreHints = true; 966 if( mbIgnoreHints) 967 continue; 968 nHintMask |= (1U << i); 969 nCntrBits[ i < mnHorzHintSize] += (mnCntrMask >> i) & 1; 970 } 971 972 mbIgnoreHints |= (nCntrBits[0] && (nCntrBits[0] != 3)); 973 mbIgnoreHints |= (nCntrBits[1] && (nCntrBits[1] != 3)); 974 if( mbIgnoreHints) 975 break; 976 977 for( i = 0; i < mnHintSize; i+=2) { 978 if( !(nHintMask & (1U << i))) 979 continue; 980 writeType1Val( mnHintStack[i]); 981 writeType1Val( mnHintStack[i+1] - mnHintStack[i]); 982 const bool bHorz = (i < mnHorzHintSize); 983 if( !nCntrBits[ bHorz]) 984 writeTypeOp( bHorz ? TYPE1OP::HSTEM : TYPE1OP::VSTEM); 985 else if( !--nCntrBits[ bHorz]) 986 writeTypeEsc( bHorz ? TYPE1OP::HSTEM3 : TYPE1OP::VSTEM3); 987 } 988 } 989 #endif 990 break; 991 case TYPE2OP::CALLSUBR: 992 case TYPE2OP::CALLGSUBR: 993 { 994 nInt = popInt(); 995 const bool bGlobal = (nType2Op == TYPE2OP::CALLGSUBR); 996 callType2Subr( bGlobal, nInt); 997 } 998 break; 999 case TYPE2OP::RETURN: 1000 // TODO: check that we are in a subroutine 1001 return; 1002 case TYPE2OP::VMOVETO: 1003 case TYPE2OP::HMOVETO: 1004 if( mbNeedClose) 1005 writeTypeOp( TYPE1OP::CLOSEPATH); 1006 else 1007 updateWidth( size() > 1); 1008 mbNeedClose = true; 1009 pop2MultiWrite( 1, nType2Op); 1010 break; 1011 case TYPE2OP::VLINETO: 1012 case TYPE2OP::HLINETO: 1013 pop2MultiWrite( 1, nType2Op, 1014 TYPE1OP::VLINETO ^ TYPE1OP::HLINETO); 1015 break; 1016 case TYPE2OP::RMOVETO: 1017 // TODO: convert rmoveto to vlineto/hlineto if possible 1018 if( mbNeedClose) 1019 writeTypeOp( TYPE1OP::CLOSEPATH); 1020 else 1021 updateWidth( size() > 2); 1022 mbNeedClose = true; 1023 pop2MultiWrite( 2, nType2Op); 1024 break; 1025 case TYPE2OP::RLINETO: 1026 // TODO: convert rlineto to vlineto/hlineto if possible 1027 pop2MultiWrite( 2, nType2Op); 1028 break; 1029 case TYPE2OP::RCURVETO: 1030 // TODO: convert rcurveto to vh/hv/hh/vv-curveto if possible 1031 pop2MultiWrite( 6, nType2Op); 1032 break; 1033 case TYPE2OP::RCURVELINE: 1034 i = 0; 1035 while( (i += 6) <= mnStackIdx) 1036 writeCurveTo( i, -6, -5, -4, -3, -2, -1 ); 1037 i -= 6; 1038 while( (i += 2) <= mnStackIdx) { 1039 writeType1Val( mnValStack[i-2]); 1040 writeType1Val( mnValStack[i-1]); 1041 writeTypeOp( TYPE2OP::RLINETO); 1042 } 1043 clear(); 1044 break; 1045 case TYPE2OP::RLINECURVE: 1046 i = 0; 1047 while( (i += 2) <= mnStackIdx-6) { 1048 writeType1Val( mnValStack[i-2]); 1049 writeType1Val( mnValStack[i-1]); 1050 writeTypeOp( TYPE2OP::RLINETO); 1051 } 1052 i -= 2; 1053 while( (i += 6) <= mnStackIdx) 1054 writeCurveTo( i, -6, -5, -4, -3, -2, -1 ); 1055 clear(); 1056 break; 1057 case TYPE2OP::VHCURVETO: 1058 case TYPE2OP::HVCURVETO: 1059 { 1060 bool bVert = (nType2Op == TYPE2OP::VHCURVETO); 1061 i = 0; 1062 nInt = 0; 1063 if( mnStackIdx & 1 ) 1064 nInt = static_cast<int>(mnValStack[ --mnStackIdx ]); 1065 while( (i += 4) <= mnStackIdx) { 1066 // TODO: use writeCurveTo() 1067 if( bVert ) writeType1Val( 0 ); 1068 writeType1Val( mnValStack[i-4] ); 1069 if( !bVert ) writeType1Val( 0); 1070 writeType1Val( mnValStack[i-3] ); 1071 writeType1Val( mnValStack[i-2] ); 1072 if( !bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) ); 1073 writeType1Val( mnValStack[i-1] ); 1074 if( bVert ) writeType1Val( static_cast<ValType>((i==mnStackIdx) ? nInt : 0) ); 1075 bVert = !bVert; 1076 writeTypeOp( TYPE2OP::RCURVETO); 1077 } 1078 } 1079 clear(); 1080 break; 1081 case TYPE2OP::HHCURVETO: 1082 i = (mnStackIdx & 1); 1083 while( (i += 4) <= mnStackIdx) { 1084 if( i != 5) 1085 writeCurveTo( i, -4, 0, -3, -2, -1, 0); 1086 else 1087 writeCurveTo( i, -4, -5, -3, -2, -1, 0); 1088 } 1089 clear(); 1090 break; 1091 case TYPE2OP::VVCURVETO: 1092 i = (mnStackIdx & 1); 1093 while( (i += 4) <= mnStackIdx) { 1094 if( i != 5) 1095 writeCurveTo( i, 0, -4, -3, -2, 0, -1); 1096 else 1097 writeCurveTo( i, -5, -4, -3, -2, 0, -1); 1098 } 1099 clear(); 1100 break; 1101 case TYPE2OP::ENDCHAR: 1102 if( mbNeedClose) 1103 writeTypeOp( TYPE1OP::CLOSEPATH); 1104 else 1105 updateWidth( size() >= 1); 1106 // mbNeedClose = true; 1107 writeTypeOp( TYPE1OP::ENDCHAR); 1108 break; 1109 default: 1110 if( ((nType2Op >= 32) && (nType2Op <= 255)) || (nType2Op == 28)) { 1111 --mpReadPtr; 1112 read2push(); 1113 } else { 1114 popAll2Write( nType2Op); 1115 assert( false); // TODO? 1116 } 1117 break; 1118 } 1119 } 1120 1121 // -------------------------------------------------------------------- 1122 1123 void CffSubsetterContext::convertOneTypeEsc( void) 1124 { 1125 const int nType2Esc = *(mpReadPtr++); 1126 ValType* pTop = &mnValStack[ mnStackIdx-1]; 1127 // convert each T2op 1128 switch( nType2Esc) { 1129 case TYPE2OP::AND: 1130 assert( mnStackIdx >= 2 ); 1131 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) & static_cast<int>(pTop[-1])); 1132 --mnStackIdx; 1133 break; 1134 case TYPE2OP::OR: 1135 assert( mnStackIdx >= 2 ); 1136 pTop[0] = static_cast<ValType>(static_cast<int>(pTop[0]) | static_cast<int>(pTop[-1])); 1137 --mnStackIdx; 1138 break; 1139 case TYPE2OP::NOT: 1140 assert( mnStackIdx >= 1 ); 1141 pTop[0] = (pTop[0] == 0); 1142 break; 1143 case TYPE2OP::ABS: 1144 assert( mnStackIdx >= 1 ); 1145 if( pTop[0] >= 0) 1146 break; 1147 // fall through 1148 case TYPE2OP::NEG: 1149 assert( mnStackIdx >= 1 ); 1150 pTop[0] = -pTop[0]; 1151 break; 1152 case TYPE2OP::ADD: 1153 assert( mnStackIdx >= 2 ); 1154 pTop[0] += pTop[-1]; 1155 --mnStackIdx; 1156 break; 1157 case TYPE2OP::SUB: 1158 assert( mnStackIdx >= 2 ); 1159 pTop[0] -= pTop[-1]; 1160 --mnStackIdx; 1161 break; 1162 case TYPE2OP::MUL: 1163 assert( mnStackIdx >= 2 ); 1164 if( pTop[-1]) 1165 pTop[0] *= pTop[-1]; 1166 --mnStackIdx; 1167 break; 1168 case TYPE2OP::DIV: 1169 assert( mnStackIdx >= 2 ); 1170 if( pTop[-1]) 1171 pTop[0] /= pTop[-1]; 1172 --mnStackIdx; 1173 break; 1174 case TYPE2OP::EQ: 1175 assert( mnStackIdx >= 2 ); 1176 pTop[0] = (pTop[0] == pTop[-1]); 1177 --mnStackIdx; 1178 break; 1179 case TYPE2OP::DROP: 1180 assert( mnStackIdx >= 1 ); 1181 --mnStackIdx; 1182 break; 1183 case TYPE2OP::PUT: { 1184 assert( mnStackIdx >= 2 ); 1185 const int nIdx = static_cast<int>(pTop[0]); 1186 assert( nIdx >= 0 ); 1187 assert( nIdx < NMAXTRANS ); 1188 mnTransVals[ nIdx] = pTop[-1]; 1189 mnStackIdx -= 2; 1190 break; 1191 } 1192 case TYPE2OP::GET: { 1193 assert( mnStackIdx >= 1 ); 1194 const int nIdx = static_cast<int>(pTop[0]); 1195 assert( nIdx >= 0 ); 1196 assert( nIdx < NMAXTRANS ); 1197 pTop[0] = mnTransVals[ nIdx ]; 1198 break; 1199 } 1200 case TYPE2OP::IFELSE: { 1201 assert( mnStackIdx >= 4 ); 1202 if( pTop[-1] > pTop[0] ) 1203 pTop[-3] = pTop[-2]; 1204 mnStackIdx -= 3; 1205 break; 1206 } 1207 case TYPE2OP::RANDOM: 1208 pTop[+1] = 1234; // TODO 1209 ++mnStackIdx; 1210 break; 1211 case TYPE2OP::SQRT: 1212 // TODO: implement 1213 break; 1214 case TYPE2OP::DUP: 1215 assert( mnStackIdx >= 1 ); 1216 pTop[+1] = pTop[0]; 1217 ++mnStackIdx; 1218 break; 1219 case TYPE2OP::EXCH: { 1220 assert( mnStackIdx >= 2 ); 1221 const ValType nVal = pTop[0]; 1222 pTop[0] = pTop[-1]; 1223 pTop[-1] = nVal; 1224 break; 1225 } 1226 case TYPE2OP::INDEX: { 1227 assert( mnStackIdx >= 1 ); 1228 const int nVal = static_cast<int>(pTop[0]); 1229 assert( nVal >= 0 ); 1230 assert( nVal < mnStackIdx-1 ); 1231 pTop[0] = pTop[-1-nVal]; 1232 break; 1233 } 1234 case TYPE2OP::ROLL: { 1235 assert( mnStackIdx >= 1 ); 1236 const int nNum = static_cast<int>(pTop[0]); 1237 assert( nNum >= 0); 1238 assert( nNum < mnStackIdx-2 ); 1239 (void)nNum; // TODO: implement 1240 const int nOfs = static_cast<int>(pTop[-1]); 1241 mnStackIdx -= 2; 1242 (void)nOfs;// TODO: implement 1243 break; 1244 } 1245 case TYPE2OP::HFLEX1: { 1246 assert( mnStackIdx == 9); 1247 #if 0 // emulate hflex1 as straight line 1248 const ValType* pX = &mnValStack[ mnStackIdx]; 1249 const ValType fDX = pX[-9] + pX[-7] + pX[-5] + pX[-4] + pX[-3] + pX[-1]; 1250 writeType1Val( fDX); 1251 writeTypeOp( TYPE1OP::HLINETO); 1252 #else // emulate hflex1 as two curves 1253 writeCurveTo( mnStackIdx, -9, -8, -7, -6, -5, 0); 1254 writeCurveTo( mnStackIdx, -4, 0, -3, -2, -1, 0); 1255 // TODO: emulate hflex1 using othersubr call 1256 #endif 1257 mnStackIdx -= 9; 1258 } 1259 break; 1260 case TYPE2OP::HFLEX: { 1261 assert( mnStackIdx == 7); 1262 ValType* pX = &mnValStack[ mnStackIdx]; 1263 #if 0 // emulate hflex as straight line 1264 const ValType fDX = pX[-7] + pX[-6] + pX[-4] + pX[-3] + pX[-2] + pX[-1]; 1265 writeType1Val( fDX); 1266 writeTypeOp( TYPE1OP::HLINETO); 1267 #else // emulate hflex as two curves 1268 pX[+1] = -pX[-5]; // temp: +dy5==-dy2 1269 writeCurveTo( mnStackIdx, -7, 0, -6, -5, -4, 0); 1270 writeCurveTo( mnStackIdx, -3, 0, -2, +1, -1, 0); 1271 // TODO: emulate hflex using othersubr call 1272 #endif 1273 mnStackIdx -= 7; 1274 } 1275 break; 1276 case TYPE2OP::FLEX: { 1277 assert( mnStackIdx == 13 ); 1278 writeCurveTo( mnStackIdx, -13, -12, -11, -10, -9, -8 ); 1279 writeCurveTo( mnStackIdx, -7, -6, -5, -4, -3, -2 ); 1280 const ValType nFlexDepth = mnValStack[ mnStackIdx-1 ]; 1281 (void)nFlexDepth; // ignoring nFlexDepth 1282 mnStackIdx -= 13; 1283 } 1284 break; 1285 case TYPE2OP::FLEX1: { 1286 assert( mnStackIdx == 11 ); 1287 // write the first part of the flex1-hinted curve 1288 writeCurveTo( mnStackIdx, -11, -10, -9, -8, -7, -6 ); 1289 1290 // determine if nD6 is horizontal or vertical 1291 const int i = mnStackIdx; 1292 ValType nDeltaX = mnValStack[i-11] + mnValStack[i-9] + mnValStack[i-7] + mnValStack[i-5] + mnValStack[i-3]; 1293 if( nDeltaX < 0 ) nDeltaX = -nDeltaX; 1294 ValType nDeltaY = mnValStack[i-10] + mnValStack[i-8] + mnValStack[i-6] + mnValStack[i-4] + mnValStack[i-2]; 1295 if( nDeltaY < 0 ) nDeltaY = -nDeltaY; 1296 const bool bVertD6 = (nDeltaY > nDeltaX); 1297 1298 // write the second part of the flex1-hinted curve 1299 if( !bVertD6 ) 1300 writeCurveTo( mnStackIdx, -5, -4, -3, -2, -1, 0); 1301 else 1302 writeCurveTo( mnStackIdx, -5, -4, -3, -2, 0, -1); 1303 mnStackIdx -= 11; 1304 } 1305 break; 1306 default: 1307 fprintf( stderr,"unhandled type2esc %d\n", nType2Esc); 1308 assert( false); 1309 break; 1310 } 1311 } 1312 1313 // -------------------------------------------------------------------- 1314 1315 void CffSubsetterContext::callType2Subr( bool bGlobal, int nSubrNumber) 1316 { 1317 const U8* const pOldReadPtr = mpReadPtr; 1318 const U8* const pOldReadEnd = mpReadEnd; 1319 1320 int nLen = 0; 1321 if( bGlobal ) { 1322 nSubrNumber += mnGlobalSubrBias; 1323 nLen = seekIndexData( mnGlobalSubrBase, nSubrNumber); 1324 } else { 1325 nSubrNumber += mpCffLocal->mnLocalSubrBias; 1326 nLen = seekIndexData( mpCffLocal->mnLocalSubrBase, nSubrNumber); 1327 } 1328 1329 while( mpReadPtr < mpReadEnd) 1330 convertOneTypeOp(); 1331 1332 mpReadPtr = pOldReadPtr; 1333 mpReadEnd = pOldReadEnd; 1334 } 1335 1336 // -------------------------------------------------------------------- 1337 1338 static const int MAX_T1OPS_SIZE = 81920; // TODO: use dynamic value 1339 1340 int CffSubsetterContext::convert2Type1Ops( CffLocal* pCffLocal, const U8* const pT2Ops, int nT2Len, U8* const pT1Ops) 1341 { 1342 mpCffLocal = pCffLocal; 1343 1344 // prepare the charstring conversion 1345 mpWritePtr = pT1Ops; 1346 #if 1 // TODO: update caller 1347 U8 aType1Ops[ MAX_T1OPS_SIZE]; 1348 if( !pT1Ops) 1349 mpWritePtr = aType1Ops; 1350 *const_cast<U8**>(&pT1Ops) = mpWritePtr; 1351 #else 1352 assert( pT1Ops); 1353 #endif 1354 1355 // prepend random seed for T1crypt 1356 *(mpWritePtr++) = 0x48; 1357 *(mpWritePtr++) = 0x44; 1358 *(mpWritePtr++) = 0x55; 1359 *(mpWritePtr++) = ' '; 1360 #if 1 // convert the Type2 charstring to Type1 1361 mpReadPtr = pT2Ops; 1362 mpReadEnd = pT2Ops + nT2Len; 1363 // prepend "hsbw" or "sbw" 1364 // TODO: only emit hsbw when charwidth is known 1365 // TODO: remove charwidth from T2 stack 1366 writeType1Val( 0); // TODO: aSubsetterContext.getLeftSideBearing(); 1367 writeType1Val( 1000/*###getCharWidth()###*/); 1368 writeTypeOp( TYPE1OP::HSBW); 1369 mbSawError = false; 1370 mbNeedClose = false; 1371 mbIgnoreHints = false; 1372 mnHintSize=mnHorzHintSize=mnStackIdx=0; maCharWidth=-1;//####### 1373 mnCntrMask = 0; 1374 while( mpReadPtr < mpReadEnd) 1375 convertOneTypeOp(); 1376 // if( bActivePath) 1377 // writeTypeOp( TYPE1OP::CLOSEPATH); 1378 // if( bSubRoutine) 1379 // writeTypeOp( TYPE1OP::RETURN); 1380 if( mbSawError) { 1381 mpWritePtr = pT1Ops+4; 1382 // create an "idiotproof" charstring 1383 writeType1Val( 0); 1384 writeType1Val( 800); 1385 writeTypeOp( TYPE1OP::HSBW); 1386 writeType1Val( 50); 1387 writeTypeOp( TYPE1OP::HMOVETO); 1388 writeType1Val( 650); 1389 writeType1Val( 100); 1390 writeTypeOp( TYPE1OP::RLINETO); 1391 writeType1Val( -350); 1392 writeType1Val( 700); 1393 writeTypeOp( TYPE1OP::RLINETO); 1394 #if 0 1395 writeType1Val( -300); 1396 writeType1Val( -800); 1397 writeTypeOp( TYPE1OP::RLINETO); 1398 #else 1399 writeTypeOp( TYPE1OP::CLOSEPATH); 1400 #endif 1401 writeTypeOp( TYPE1OP::ENDCHAR); 1402 } 1403 #else // useful for manually encoding charstrings 1404 mpWritePtr = pT1Ops; 1405 mpWritePtr += sprintf( (char*)mpWritePtr, "OOo_\x8b\x8c\x0c\x10\x0b"); 1406 #endif 1407 const int nType1Len = mpWritePtr - pT1Ops; 1408 1409 // encrypt the Type1 charstring 1410 int nRDCryptR = 4330; // TODO: mnRDCryptSeed; 1411 for( U8* p = pT1Ops; p < mpWritePtr; ++p) { 1412 *p ^= (nRDCryptR >> 8); 1413 nRDCryptR = (*(U8*)p + nRDCryptR) * 52845 + 22719; 1414 } 1415 1416 return nType1Len; 1417 } 1418 1419 // -------------------------------------------------------------------- 1420 1421 RealType CffSubsetterContext::readRealVal() 1422 { 1423 // TODO: more thorough number validity test 1424 bool bComma = false; 1425 int nExpVal = 0; 1426 int nExpSign = 0; 1427 S64 nNumber = 0; 1428 RealType fReal = +1.0; 1429 for(;;){ 1430 const U8 c = *(mpReadPtr++); // read nibbles 1431 // parse high nibble 1432 const U8 nH = c >> 4U; 1433 if( nH <= 9) { 1434 nNumber = nNumber * 10 + nH; 1435 --nExpVal; 1436 } else if( nH == 10) { // comma 1437 nExpVal = 0; 1438 bComma = true; 1439 } else if( nH == 11) { // +exp 1440 fReal *= nNumber; 1441 nExpSign = +1; 1442 nNumber = 0; 1443 } else if( nH == 12) { // -exp 1444 fReal *= nNumber; 1445 nExpSign = -1; 1446 nNumber = 0; 1447 } else if( nH == 13) { // reserved 1448 // TODO: ignore or error? 1449 } else if( nH == 14) // minus 1450 fReal = -fReal; 1451 else if( nH == 15) // end 1452 break; 1453 // parse low nibble 1454 const U8 nL = c & 0x0F; 1455 if( nL <= 9) { 1456 nNumber = nNumber * 10 + nL; 1457 --nExpVal; 1458 } else if( nL == 10) { // comma 1459 nExpVal = 0; 1460 bComma = true; 1461 } else if( nL == 11) { // +exp 1462 fReal *= nNumber; 1463 nNumber = 0; 1464 nExpSign = +1; 1465 } else if( nL == 12) { // -exp 1466 fReal *= nNumber; 1467 nNumber = 0; 1468 nExpSign = -1; 1469 } else if( nL == 13) { // reserved 1470 // TODO: ignore or error? 1471 } else if( nL == 14) // minus 1472 fReal = -fReal; 1473 else if( nL == 15) // end 1474 break; 1475 } 1476 1477 // merge exponents 1478 if( !bComma) 1479 nExpVal = 0; 1480 if( !nExpSign) { fReal *= nNumber;} 1481 else if( nExpSign > 0) { nExpVal += static_cast<int>(nNumber);} 1482 else if( nExpSign < 0) { nExpVal -= static_cast<int>(nNumber);} 1483 1484 // apply exponents 1485 if( !nExpVal) { /*nothing to apply*/} 1486 else if( nExpVal > 0) { while( --nExpVal >= 0) fReal *= 10.0;} 1487 else if( nExpVal < 0) { while( ++nExpVal <= 0) fReal /= 10.0;} 1488 return fReal; 1489 } 1490 1491 // -------------------------------------------------------------------- 1492 1493 // prepare to access an element inside a CFF/CID index table 1494 int CffSubsetterContext::seekIndexData( int nIndexBase, int nDataIndex) 1495 { 1496 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd)); 1497 if( nDataIndex < 0) 1498 return -1; 1499 mpReadPtr = mpBasePtr + nIndexBase; 1500 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1]; 1501 if( nDataIndex >= nDataCount) 1502 return -1; 1503 const int nDataOfsSz = mpReadPtr[2]; 1504 mpReadPtr += 3 + (nDataOfsSz * nDataIndex); 1505 int nOfs1 = 0; 1506 switch( nDataOfsSz) { 1507 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return -1; 1508 case 1: nOfs1 = mpReadPtr[0]; break; 1509 case 2: nOfs1 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break; 1510 case 3: nOfs1 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break; 1511 case 4: nOfs1 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break; 1512 } 1513 mpReadPtr += nDataOfsSz; 1514 1515 int nOfs2 = 0; 1516 switch( nDataOfsSz) { 1517 case 1: nOfs2 = mpReadPtr[0]; break; 1518 case 2: nOfs2 = (mpReadPtr[0]<<8) + mpReadPtr[1]; break; 1519 case 3: nOfs2 = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2]; break; 1520 case 4: nOfs2 = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break; 1521 } 1522 1523 mpReadPtr = mpBasePtr + (nIndexBase + 2) + nDataOfsSz * (nDataCount + 1) + nOfs1; 1524 mpReadEnd = mpReadPtr + (nOfs2 - nOfs1); 1525 assert( nOfs1 >= 0); 1526 assert( nOfs2 >= nOfs1); 1527 assert( mpReadPtr <= mpBaseEnd); 1528 assert( mpReadEnd <= mpBaseEnd); 1529 return (nOfs2 - nOfs1); 1530 } 1531 1532 // -------------------------------------------------------------------- 1533 1534 // skip over a CFF/CID index table 1535 void CffSubsetterContext::seekIndexEnd( int nIndexBase) 1536 { 1537 assert( (nIndexBase > 0) && (mpBasePtr + nIndexBase + 3 <= mpBaseEnd)); 1538 mpReadPtr = mpBasePtr + nIndexBase; 1539 const int nDataCount = (mpReadPtr[0]<<8) + mpReadPtr[1]; 1540 const int nDataOfsSz = mpReadPtr[2]; 1541 mpReadPtr += 3 + nDataOfsSz * nDataCount; 1542 assert( mpReadPtr <= mpBaseEnd); 1543 int nEndOfs = 0; 1544 switch( nDataOfsSz) { 1545 default: fprintf( stderr, "\tINVALID nDataOfsSz=%d\n\n", nDataOfsSz); return; 1546 case 1: nEndOfs = mpReadPtr[0]; break; 1547 case 2: nEndOfs = (mpReadPtr[0]<<8) + mpReadPtr[1]; break; 1548 case 3: nEndOfs = (mpReadPtr[0]<<16) + (mpReadPtr[1]<<8) + mpReadPtr[2];break; 1549 case 4: nEndOfs = (mpReadPtr[0]<<24) + (mpReadPtr[1]<<16) + (mpReadPtr[2]<<8) + mpReadPtr[3]; break; 1550 } 1551 mpReadPtr += nDataOfsSz; 1552 mpReadPtr += nEndOfs - 1; 1553 mpReadEnd = mpBaseEnd; 1554 assert( nEndOfs >= 0); 1555 assert( mpReadEnd <= mpBaseEnd); 1556 } 1557 1558 // ==================================================================== 1559 1560 // initialize FONTDICT specific values 1561 CffLocal::CffLocal( void) 1562 : mnPrivDictBase( 0) 1563 , mnPrivDictSize( 0) 1564 , mnLocalSubrOffs( 0) 1565 , mnLocalSubrBase( 0) 1566 , mnLocalSubrCount( 0) 1567 , mnLocalSubrBias( 0) 1568 , maNominalWidth( 0) 1569 , maDefaultWidth( 0) 1570 , maStemStdHW( 0) 1571 , maStemStdVW( 0) 1572 , mfBlueScale( 0.0) 1573 , mfBlueShift( 0.0) 1574 , mfBlueFuzz( 0.0) 1575 , mfExpFactor( 0.0) 1576 , mnLangGroup( 0) 1577 , mbForceBold( false) 1578 { 1579 maStemSnapH.clear(); 1580 maStemSnapV.clear(); 1581 maBlueValues.clear(); 1582 maOtherBlues.clear(); 1583 maFamilyBlues.clear(); 1584 maFamilyOtherBlues.clear(); 1585 } 1586 1587 // -------------------------------------------------------------------- 1588 1589 CffGlobal::CffGlobal( void) 1590 : mnNameIdxBase( 0) 1591 , mnNameIdxCount( 0) 1592 , mnStringIdxBase( 0) 1593 , mnStringIdxCount( 0) 1594 , mbCIDFont( false) 1595 , mnCharStrBase( 0) 1596 , mnCharStrCount( 0) 1597 , mnEncodingBase( 0) 1598 , mnCharsetBase( 0) 1599 , mnGlobalSubrBase( 0) 1600 , mnGlobalSubrCount( 0) 1601 , mnGlobalSubrBias( 0) 1602 , mnFDSelectBase( 0) 1603 , mnFontDictBase( 0) 1604 , mnFDAryCount( 1) 1605 , mnFontNameSID( 0) 1606 , mnFullNameSID( 0) 1607 , mnFamilyNameSID( 0) 1608 { 1609 maFontBBox.clear(); 1610 // TODO; maFontMatrix.clear(); 1611 } 1612 1613 // -------------------------------------------------------------------- 1614 1615 void CffSubsetterContext::initialCffRead( void) 1616 { 1617 // get the CFFHeader 1618 mpReadPtr = mpBasePtr; 1619 const U8 nVerMajor = *(mpReadPtr++); 1620 const U8 nVerMinor = *(mpReadPtr++); 1621 const U8 nHeaderSize = *(mpReadPtr++); 1622 const U8 nOffsetSize = *(mpReadPtr++); 1623 // TODO: is the version number useful for anything else? 1624 assert( (nVerMajor == 1) && (nVerMinor == 0)); 1625 (void)(nVerMajor + nVerMinor + nOffsetSize); // avoid compiler warnings 1626 1627 // prepare access to the NameIndex 1628 mnNameIdxBase = nHeaderSize; 1629 mpReadPtr = mpBasePtr + nHeaderSize; 1630 mnNameIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1]; 1631 seekIndexEnd( mnNameIdxBase); 1632 1633 // get the TopDict index 1634 const long nTopDictBase = getReadOfs(); 1635 const int nTopDictCount = (mpReadPtr[0]<<8) + mpReadPtr[1]; 1636 if( nTopDictCount) { 1637 for( int i = 0; i < nTopDictCount; ++i) { 1638 seekIndexData( nTopDictBase, i); 1639 while( mpReadPtr < mpReadEnd) 1640 readDictOp(); 1641 assert( mpReadPtr == mpReadEnd); 1642 } 1643 } 1644 1645 // prepare access to the String index 1646 mnStringIdxBase = getReadOfs(); 1647 mnStringIdxCount = (mpReadPtr[0]<<8) + mpReadPtr[1]; 1648 seekIndexEnd( mnStringIdxBase); 1649 1650 // prepare access to the GlobalSubr index 1651 mnGlobalSubrBase = getReadOfs(); 1652 mnGlobalSubrCount = (mpReadPtr[0]<<8) + mpReadPtr[1]; 1653 mnGlobalSubrBias = (mnGlobalSubrCount<1240)?107:(mnGlobalSubrCount<33900)?1131:32768; 1654 // skip past the last GlobalSubr entry 1655 // seekIndexEnd( mnGlobalSubrBase); 1656 1657 // get/skip the Encodings (we got mnEncodingBase from TOPDICT) 1658 // seekEncodingsEnd( mnEncodingBase); 1659 // get/skip the Charsets (we got mnCharsetBase from TOPDICT) 1660 // seekCharsetsEnd( mnCharStrBase); 1661 // get/skip FDSelect (CID only) data 1662 1663 // prepare access to the CharStrings index (we got the base from TOPDICT) 1664 mpReadPtr = mpBasePtr + mnCharStrBase; 1665 mnCharStrCount = (mpReadPtr[0]<<8) + mpReadPtr[1]; 1666 // seekIndexEnd( mnCharStrBase); 1667 1668 // read the FDArray index (CID only) 1669 if( mbCIDFont) { 1670 // assert( mnFontDictBase == tellRel()); 1671 mpReadPtr = mpBasePtr + mnFontDictBase; 1672 mnFDAryCount = (mpReadPtr[0]<<8) + mpReadPtr[1]; 1673 assert( mnFDAryCount < (int)(sizeof(maCffLocal)/sizeof(*maCffLocal))); 1674 1675 // read FDArray details to get access to the PRIVDICTs 1676 for( int i = 0; i < mnFDAryCount; ++i) { 1677 mpCffLocal = &maCffLocal[i]; 1678 seekIndexData( mnFontDictBase, i); 1679 while( mpReadPtr < mpReadEnd) 1680 readDictOp(); 1681 assert( mpReadPtr == mpReadEnd); 1682 } 1683 } 1684 1685 for( int i = 0; i < mnFDAryCount; ++i) { 1686 mpCffLocal = &maCffLocal[i]; 1687 1688 // get the PrivateDict index 1689 // (we got mnPrivDictSize and mnPrivDictBase from TOPDICT or FDArray) 1690 if( mpCffLocal->mnPrivDictSize != 0) { 1691 assert( mpCffLocal->mnPrivDictSize > 0); 1692 // get the PrivDict data 1693 mpReadPtr = mpBasePtr + mpCffLocal->mnPrivDictBase; 1694 mpReadEnd = mpReadPtr + mpCffLocal->mnPrivDictSize; 1695 assert( mpReadEnd <= mpBaseEnd); 1696 // read PrivDict details 1697 while( mpReadPtr < mpReadEnd) 1698 readDictOp(); 1699 } 1700 1701 // prepare access to the LocalSubrs (we got mnLocalSubrOffs from PRIVDICT) 1702 if( mpCffLocal->mnLocalSubrOffs) { 1703 // read LocalSubrs summary 1704 mpCffLocal->mnLocalSubrBase = mpCffLocal->mnPrivDictBase + mpCffLocal->mnLocalSubrOffs; 1705 mpReadPtr = mpBasePtr + mpCffLocal->mnLocalSubrBase; 1706 const int nSubrCount = (mpReadPtr[0] << 8) + mpReadPtr[1]; 1707 mpCffLocal->mnLocalSubrCount = nSubrCount; 1708 mpCffLocal->mnLocalSubrBias = (nSubrCount<1240)?107:(nSubrCount<33900)?1131:32768; 1709 // seekIndexEnd( mpCffLocal->mnLocalSubrBase); 1710 } 1711 } 1712 1713 // ignore the Notices info 1714 } 1715 1716 // -------------------------------------------------------------------- 1717 1718 // get a cstring from a StringID 1719 const char* CffSubsetterContext::getString( int nStringID) 1720 { 1721 // get a standard string if possible 1722 const static int nStdStrings = sizeof(pStringIds)/sizeof(*pStringIds); 1723 if( (nStringID >= 0) && (nStringID < nStdStrings)) 1724 return pStringIds[ nStringID]; 1725 1726 // else get the string from the StringIndex table 1727 const U8* pReadPtr = mpReadPtr; 1728 const U8* pReadEnd = mpReadEnd; 1729 nStringID -= nStdStrings; 1730 int nLen = seekIndexData( mnStringIdxBase, nStringID); 1731 // assert( nLen >= 0); 1732 // TODO: just return the undecorated name 1733 // TODO: get rid of static char buffer 1734 static char aNameBuf[ 2560]; 1735 if( nLen < 0) { 1736 sprintf( aNameBuf, "name[%d].notfound!", nStringID); 1737 } else { 1738 const int nMaxLen = sizeof(aNameBuf) - 1; 1739 if( nLen >= nMaxLen) 1740 nLen = nMaxLen; 1741 for( int i = 0; i < nLen; ++i) 1742 aNameBuf[i] = *(mpReadPtr++); 1743 aNameBuf[ nLen] = '\0'; 1744 } 1745 mpReadPtr = pReadPtr; 1746 mpReadEnd = pReadEnd; 1747 return aNameBuf; 1748 } 1749 1750 // -------------------------------------------------------------------- 1751 1752 // access a CID's FDSelect table 1753 int CffSubsetterContext::getFDSelect( int nGlyphIndex) const 1754 { 1755 assert( nGlyphIndex >= 0); 1756 assert( nGlyphIndex < mnCharStrCount); 1757 if( !mbCIDFont) 1758 return 0; 1759 1760 const U8* pReadPtr = mpBasePtr + mnFDSelectBase; 1761 const U8 nFDSelFormat = *(pReadPtr++); 1762 switch( nFDSelFormat) { 1763 case 0: { // FDSELECT format 0 1764 pReadPtr += nGlyphIndex; 1765 const U8 nFDIdx = *(pReadPtr++); 1766 return nFDIdx; 1767 } //break; 1768 case 3: { // FDSELECT format 3 1769 const U16 nRangeCount = (pReadPtr[0]<<8) + pReadPtr[1]; 1770 assert( nRangeCount > 0); 1771 assert( nRangeCount <= mnCharStrCount); 1772 U16 nPrev = (pReadPtr[2]<<8) + pReadPtr[3]; 1773 assert( nPrev == 0); 1774 pReadPtr += 4; 1775 // TODO? binary search 1776 for( int i = 0; i < nRangeCount; ++i) { 1777 const U8 nFDIdx = pReadPtr[0]; 1778 const U16 nNext = (pReadPtr[1]<<8) + pReadPtr[2]; 1779 assert( nPrev < nNext); 1780 if( nGlyphIndex < nNext) 1781 return nFDIdx; 1782 pReadPtr += 3; 1783 nPrev = nNext; 1784 } 1785 } break; 1786 default: // invalid FDselect format 1787 fprintf( stderr, "invalid CFF.FdselType=%d\n", nFDSelFormat); 1788 break; 1789 } 1790 1791 assert( false); 1792 return -1; 1793 } 1794 1795 // -------------------------------------------------------------------- 1796 1797 int CffSubsetterContext::getGlyphSID( int nGlyphIndex) const 1798 { 1799 if( nGlyphIndex == 0) 1800 return 0; // ".notdef" 1801 assert( nGlyphIndex >= 0); 1802 assert( nGlyphIndex < mnCharStrCount); 1803 if( (nGlyphIndex < 0) || (nGlyphIndex >= mnCharStrCount)) 1804 return -1; 1805 1806 // get the SID/CID from the Charset table 1807 const U8* pReadPtr = mpBasePtr + mnCharsetBase; 1808 const U8 nCSetFormat = *(pReadPtr++); 1809 int nGlyphsToSkip = nGlyphIndex - 1; 1810 switch( nCSetFormat) { 1811 case 0: // charset format 0 1812 pReadPtr += 2 * nGlyphsToSkip; 1813 nGlyphsToSkip = 0; 1814 break; 1815 case 1: // charset format 1 1816 while( nGlyphsToSkip >= 0) { 1817 const int nLeft = pReadPtr[2]; 1818 if( nGlyphsToSkip <= nLeft) 1819 break; 1820 nGlyphsToSkip -= nLeft + 1; 1821 pReadPtr += 3; 1822 } 1823 break; 1824 case 2: // charset format 2 1825 while( nGlyphsToSkip >= 0) { 1826 const int nLeft = (pReadPtr[2]<<8) + pReadPtr[3]; 1827 if( nGlyphsToSkip <= nLeft) 1828 break; 1829 nGlyphsToSkip -= nLeft + 1; 1830 pReadPtr += 4; 1831 } 1832 break; 1833 default: 1834 fprintf( stderr, "ILLEGAL CFF-Charset format %d\n", nCSetFormat); 1835 return -2; 1836 } 1837 1838 int nSID = (pReadPtr[0]<<8) + pReadPtr[1]; 1839 nSID += nGlyphsToSkip; 1840 // NOTE: for CID-fonts the resulting SID is interpreted as CID 1841 return nSID; 1842 } 1843 1844 // -------------------------------------------------------------------- 1845 1846 // NOTE: the result becomes invalid with the next call to this method 1847 const char* CffSubsetterContext::getGlyphName( int nGlyphIndex) 1848 { 1849 // the first glyph is always the .notdef glyph 1850 const char* pGlyphName = ".notdef"; 1851 if( nGlyphIndex == 0) 1852 return pGlyphName; 1853 1854 // prepare a result buffer 1855 // TODO: get rid of static buffer 1856 static char aDefaultGlyphName[64]; 1857 pGlyphName = aDefaultGlyphName; 1858 1859 // get the glyph specific name 1860 const int nSID = getGlyphSID( nGlyphIndex); 1861 if( nSID < 0) // default glyph name 1862 sprintf( aDefaultGlyphName, "gly%03d", nGlyphIndex); 1863 else if( mbCIDFont) // default glyph name in CIDs 1864 sprintf( aDefaultGlyphName, "cid%03d", nSID); 1865 else { // glyph name from string table 1866 const char* pSidName = getString( nSID); 1867 // check validity of glyph name 1868 if( pSidName) { 1869 const char* p = pSidName; 1870 while( (*p >= '0') && (*p <= 'z')) ++p; 1871 if( (p >= pSidName+1) && (*p == '\0')) 1872 pGlyphName = pSidName; 1873 } 1874 // if needed invent a fallback name 1875 if( pGlyphName != pSidName) 1876 sprintf( aDefaultGlyphName, "bad%03d", nSID); 1877 } 1878 1879 return pGlyphName; 1880 } 1881 1882 // -------------------------------------------------------------------- 1883 1884 class Type1Emitter 1885 { 1886 public: 1887 explicit Type1Emitter( const char* pOutFileName, bool bPfbSubset = true); 1888 explicit Type1Emitter( FILE* pOutFile, bool bPfbSubset = true); 1889 /*virtual*/ ~Type1Emitter( void); 1890 void setSubsetName( const char* ); 1891 1892 void emitRawData( const char* pData, int nLength) const; 1893 void emitAllRaw( void); 1894 void emitAllHex( void); 1895 void emitAllCrypted( void); 1896 int tellPos( void) const; 1897 void updateLen( int nTellPos, int nLength); 1898 void emitValVector( const char* pLineHead, const char* pLineTail, const ValVector&); 1899 private: 1900 FILE* mpFileOut; 1901 bool mbCloseOutfile; 1902 char maBuffer[MAX_T1OPS_SIZE]; // TODO: dynamic allocation 1903 int mnEECryptR; 1904 public: 1905 char* mpPtr; 1906 1907 char maSubsetName[256]; 1908 bool mbPfbSubset; 1909 int mnHexLineCol; 1910 }; 1911 1912 // -------------------------------------------------------------------- 1913 1914 Type1Emitter::Type1Emitter( const char* pPfbFileName, bool bPfbSubset) 1915 : mpFileOut( NULL) 1916 , mbCloseOutfile( true) 1917 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed 1918 , mpPtr( maBuffer) 1919 , mbPfbSubset( bPfbSubset) 1920 , mnHexLineCol( 0) 1921 { 1922 mpFileOut = fopen( pPfbFileName, "wb"); 1923 maSubsetName[0] = '\0'; 1924 } 1925 1926 // -------------------------------------------------------------------- 1927 1928 Type1Emitter::Type1Emitter( FILE* pOutFile, bool bPfbSubset) 1929 : mpFileOut( pOutFile) 1930 , mbCloseOutfile( false) 1931 , mnEECryptR( 55665) // default eexec seed, TODO: mnEECryptSeed 1932 , mpPtr( maBuffer) 1933 , mbPfbSubset( bPfbSubset) 1934 , mnHexLineCol( 0) 1935 { 1936 maSubsetName[0] = '\0'; 1937 } 1938 1939 // -------------------------------------------------------------------- 1940 1941 Type1Emitter::~Type1Emitter( void) 1942 { 1943 if( !mpFileOut) 1944 return; 1945 if( mbCloseOutfile ) 1946 fclose( mpFileOut); 1947 mpFileOut = NULL; 1948 } 1949 1950 // -------------------------------------------------------------------- 1951 1952 void Type1Emitter::setSubsetName( const char* pSubsetName) 1953 { 1954 maSubsetName[0] = '\0'; 1955 if( pSubsetName) 1956 strncpy( maSubsetName, pSubsetName, sizeof(maSubsetName)); 1957 maSubsetName[sizeof(maSubsetName)-1] = '\0'; 1958 } 1959 1960 // -------------------------------------------------------------------- 1961 1962 int Type1Emitter::tellPos( void) const 1963 { 1964 int nTellPos = ftell( mpFileOut); 1965 return nTellPos; 1966 } 1967 1968 // -------------------------------------------------------------------- 1969 1970 void Type1Emitter::updateLen( int nTellPos, int nLength) 1971 { 1972 // update PFB segment header length 1973 U8 cData[4]; 1974 cData[0] = static_cast<U8>(nLength >> 0); 1975 cData[1] = static_cast<U8>(nLength >> 8); 1976 cData[2] = static_cast<U8>(nLength >> 16); 1977 cData[3] = static_cast<U8>(nLength >> 24); 1978 const int nCurrPos = ftell( mpFileOut); 1979 fseek( mpFileOut, nTellPos, SEEK_SET); 1980 fwrite( cData, 1, sizeof(cData), mpFileOut); 1981 fseek( mpFileOut, nCurrPos, SEEK_SET); 1982 } 1983 1984 // -------------------------------------------------------------------- 1985 1986 inline void Type1Emitter::emitRawData( const char* pData, int nLength) const 1987 { 1988 fwrite( pData, 1, nLength, mpFileOut); 1989 } 1990 1991 // -------------------------------------------------------------------- 1992 1993 inline void Type1Emitter::emitAllRaw( void) 1994 { 1995 // writeout raw data 1996 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer)); 1997 emitRawData( maBuffer, mpPtr - maBuffer); 1998 // reset the raw buffer 1999 mpPtr = maBuffer; 2000 } 2001 2002 // -------------------------------------------------------------------- 2003 2004 inline void Type1Emitter::emitAllHex( void) 2005 { 2006 assert( (mpPtr - maBuffer) < (int)sizeof(maBuffer)); 2007 for( const char* p = maBuffer; p < mpPtr;) { 2008 // convert binary chunk to hex 2009 char aHexBuf[0x4000]; 2010 char* pOut = aHexBuf; 2011 while( (p < mpPtr) && (pOut < aHexBuf+sizeof(aHexBuf)-4)) { 2012 // convert each byte to hex 2013 char cNibble = (*p >> 4) & 0x0F; 2014 cNibble += (cNibble < 10) ? '0' : 'A'-10; 2015 *(pOut++) = cNibble; 2016 cNibble = *(p++) & 0x0F; 2017 cNibble += (cNibble < 10) ? '0' : 'A'-10; 2018 *(pOut++) = cNibble; 2019 // limit the line length 2020 if( (++mnHexLineCol & 0x3F) == 0) 2021 *(pOut++) = '\n'; 2022 } 2023 // writeout hex-converted chunk 2024 emitRawData( aHexBuf, pOut-aHexBuf); 2025 } 2026 // reset the raw buffer 2027 mpPtr = maBuffer; 2028 } 2029 2030 // -------------------------------------------------------------------- 2031 2032 void Type1Emitter::emitAllCrypted( void) 2033 { 2034 // apply t1crypt 2035 for( char* p = maBuffer; p < mpPtr; ++p) { 2036 *p ^= (mnEECryptR >> 8); 2037 mnEECryptR = (*(U8*)p + mnEECryptR) * 52845 + 22719; 2038 } 2039 2040 // emit the t1crypt result 2041 if( mbPfbSubset) 2042 emitAllRaw(); 2043 else 2044 emitAllHex(); 2045 } 2046 2047 // -------------------------------------------------------------------- 2048 2049 // #i110387# quick-and-dirty double->ascii conversion 2050 // needed because sprintf/ecvt/etc. alone are too localized (LC_NUMERIC) 2051 // also strip off trailing zeros in fraction while we are at it 2052 inline int dbl2str( char* pOut, double fVal, int nPrecision=6) 2053 { 2054 const int nLen = psp::getValueOfDouble( pOut, fVal, nPrecision); 2055 return nLen; 2056 } 2057 2058 // -------------------------------------------------------------------- 2059 2060 void Type1Emitter::emitValVector( const char* pLineHead, const char* pLineTail, 2061 const ValVector& rVector) 2062 { 2063 // ignore empty vectors 2064 if( rVector.empty()) 2065 return; 2066 2067 // emit the line head 2068 mpPtr += sprintf( mpPtr, pLineHead); 2069 // emit the vector values 2070 ValVector::value_type aVal = 0; 2071 for( ValVector::const_iterator it = rVector.begin();;) { 2072 aVal = *it; 2073 if( ++it == rVector.end() ) 2074 break; 2075 mpPtr += dbl2str( mpPtr, aVal); 2076 *(mpPtr++) = ' '; 2077 } 2078 // emit the last value 2079 mpPtr += dbl2str( mpPtr, aVal); 2080 // emit the line tail 2081 mpPtr += sprintf( mpPtr, pLineTail); 2082 } 2083 2084 // -------------------------------------------------------------------- 2085 2086 bool CffSubsetterContext::emitAsType1( Type1Emitter& rEmitter, 2087 const long* pReqGlyphIDs, const U8* pReqEncoding, 2088 GlyphWidth* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rFSInfo) 2089 { 2090 // prepare some fontdirectory details 2091 static const int nUniqueIdBase = 4100000; // using private-interchange UniqueIds 2092 static int nUniqueId = nUniqueIdBase; 2093 ++nUniqueId; 2094 2095 char* pFontName = rEmitter.maSubsetName; 2096 if( !*pFontName ) { 2097 if( mnFontNameSID) { 2098 // get the fontname directly if available 2099 strncpy( pFontName, getString( mnFontNameSID), sizeof(rEmitter.maSubsetName)); 2100 } else if( mnFullNameSID) { 2101 // approximate fontname as fullname-whitespace 2102 const char* pI = getString( mnFullNameSID); 2103 char* pO = pFontName; 2104 const char* pLimit = pFontName + sizeof(rEmitter.maSubsetName) - 1; 2105 while( pO < pLimit) { 2106 const char c = *(pI++); 2107 if( c != ' ') 2108 *(pO++) = c; 2109 if( !c) 2110 break; 2111 } 2112 *pO = '\0'; 2113 } else { 2114 // fallback name of last resort 2115 strncpy( pFontName, "DummyName", sizeof(rEmitter.maSubsetName)); 2116 } 2117 } 2118 const char* pFullName = pFontName; 2119 const char* pFamilyName = pFontName; 2120 2121 char*& pOut = rEmitter.mpPtr; // convenience reference, TODO: cleanup 2122 2123 // create a PFB+Type1 header 2124 if( rEmitter.mbPfbSubset ) { 2125 static const char aPfbHeader[] = "\x80\x01\x00\x00\x00\x00"; 2126 rEmitter.emitRawData( aPfbHeader, sizeof(aPfbHeader)-1); 2127 } 2128 2129 pOut += sprintf( pOut, "%%!FontType1-1.0: %s 001.003\n", rEmitter.maSubsetName); 2130 // emit TOPDICT 2131 #if 0 // improve PS Type1 caching? 2132 nOfs += sprintf( &aT1Str[nOfs], 2133 "FontDirectory/%s known{/%s findfont dup/UniqueID known{dup\n" 2134 "/UniqueID get %d eq exch/FontType get 1 eq and}{pop false}ifelse\n" 2135 "{save true}{false}ifelse}\n{false}ifelse\n", 2136 pFamilyName, pFamilyName, nUniqueId); 2137 #endif 2138 pOut += sprintf( pOut, 2139 "11 dict begin\n" // TODO: dynamic entry count for TOPDICT 2140 "/FontType 1 def\n" 2141 "/PaintType 0 def\n"); 2142 pOut += sprintf( pOut, "/FontName /%s def\n", rEmitter.maSubsetName); 2143 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId); 2144 // emit FontMatrix 2145 if( maFontMatrix.size() == 6) 2146 rEmitter.emitValVector( "/FontMatrix [", "]readonly def\n", maFontMatrix); 2147 else // emit default FontMatrix if needed 2148 pOut += sprintf( pOut, "/FontMatrix [0.001 0 0 0.001 0 0]readonly def\n"); 2149 // emit FontBBox 2150 if( maFontBBox.size() == 4) 2151 rEmitter.emitValVector( "/FontBBox {", "}readonly def\n", maFontBBox); 2152 else // emit default FontBBox if needed 2153 pOut += sprintf( pOut, "/FontBBox {0 0 999 999}readonly def\n"); 2154 // emit FONTINFO into TOPDICT 2155 pOut += sprintf( pOut, 2156 "/FontInfo 2 dict dup begin\n" // TODO: check fontinfo entry count 2157 " /FullName (%s) readonly def\n" 2158 " /FamilyName (%s) readonly def\n" 2159 "end readonly def\n", 2160 pFullName, pFamilyName); 2161 #if 0 // TODO: use an standard Type1 encoding if possible 2162 pOut += sprintf( pOut, 2163 "/Encoding StandardEncoding def\n"); 2164 #else 2165 pOut += sprintf( pOut, 2166 "/Encoding 256 array\n" 2167 "0 1 255 {1 index exch /.notdef put} for\n"); 2168 for( int i = 1; (i < nGlyphCount) && (i < 256); ++i) { 2169 const char* pGlyphName = getGlyphName( pReqGlyphIDs[i]); 2170 pOut += sprintf( pOut, "dup %d /%s put\n", pReqEncoding[i], pGlyphName); 2171 } 2172 pOut += sprintf( pOut, "readonly def\n"); 2173 #endif 2174 pOut += sprintf( pOut, 2175 // TODO: more topdict entries 2176 "currentdict end\n" 2177 "currentfile eexec\n"); 2178 2179 // emit PFB header 2180 rEmitter.emitAllRaw(); 2181 if( rEmitter.mbPfbSubset) { 2182 // update PFB header segment 2183 const int nPfbHeaderLen = rEmitter.tellPos() - 6; 2184 rEmitter.updateLen( 2, nPfbHeaderLen); 2185 2186 // prepare start of eexec segment 2187 rEmitter.emitRawData( "\x80\x02\x00\x00\x00\x00", 6); // segment start 2188 } 2189 const int nEExecSegTell = rEmitter.tellPos(); 2190 2191 // which always starts with a privdict 2192 // count the privdict entries 2193 int nPrivEntryCount = 9; 2194 #if !defined(IGNORE_HINTS) 2195 // emit blue hints only if non-default values 2196 nPrivEntryCount += !mpCffLocal->maOtherBlues.empty(); 2197 nPrivEntryCount += !mpCffLocal->maFamilyBlues.empty(); 2198 nPrivEntryCount += !mpCffLocal->maFamilyOtherBlues.empty(); 2199 nPrivEntryCount += (mpCffLocal->mfBlueScale != 0.0); 2200 nPrivEntryCount += (mpCffLocal->mfBlueShift != 0.0); 2201 nPrivEntryCount += (mpCffLocal->mfBlueFuzz != 0.0); 2202 // emit stem hints only if non-default values 2203 nPrivEntryCount += (mpCffLocal->maStemStdHW != 0); 2204 nPrivEntryCount += (mpCffLocal->maStemStdVW != 0); 2205 nPrivEntryCount += !mpCffLocal->maStemSnapH.empty(); 2206 nPrivEntryCount += !mpCffLocal->maStemSnapV.empty(); 2207 // emit other hints only if non-default values 2208 nPrivEntryCount += (mpCffLocal->mfExpFactor != 0.0); 2209 nPrivEntryCount += (mpCffLocal->mnLangGroup != 0); 2210 nPrivEntryCount += (mpCffLocal->mnLangGroup == 1); 2211 nPrivEntryCount += (mpCffLocal->mbForceBold != false); 2212 #endif // IGNORE_HINTS 2213 // emit the privdict header 2214 pOut += sprintf( pOut, 2215 "\110\104\125 " 2216 "dup\n/Private %d dict dup begin\n" 2217 "/RD{string currentfile exch readstring pop}executeonly def\n" 2218 "/ND{noaccess def}executeonly def\n" 2219 "/NP{noaccess put}executeonly def\n" 2220 "/MinFeature{16 16}ND\n" 2221 "/password 5839 def\n", // TODO: mnRDCryptSeed? 2222 nPrivEntryCount); 2223 2224 #if defined(IGNORE_HINTS) 2225 pOut += sprintf( pOut, "/BlueValues []ND\n"); // BlueValues are mandatory 2226 #else 2227 // emit blue hint related privdict entries 2228 if( !mpCffLocal->maBlueValues.empty()) 2229 rEmitter.emitValVector( "/BlueValues [", "]ND\n", mpCffLocal->maBlueValues); 2230 else 2231 pOut += sprintf( pOut, "/BlueValues []ND\n"); // default to empty BlueValues 2232 rEmitter.emitValVector( "/OtherBlues [", "]ND\n", mpCffLocal->maOtherBlues); 2233 rEmitter.emitValVector( "/FamilyBlues [", "]ND\n", mpCffLocal->maFamilyBlues); 2234 rEmitter.emitValVector( "/FamilyOtherBlues [", "]ND\n", mpCffLocal->maFamilyOtherBlues); 2235 2236 if( mpCffLocal->mfBlueScale) { 2237 pOut += sprintf( pOut, "/BlueScale "); 2238 pOut += dbl2str( pOut, mpCffLocal->mfBlueScale, 6); 2239 pOut += sprintf( pOut, " def\n"); 2240 } 2241 if( mpCffLocal->mfBlueShift) { // default BlueShift==7 2242 pOut += sprintf( pOut, "/BlueShift "); 2243 pOut += dbl2str( pOut, mpCffLocal->mfBlueShift); 2244 pOut += sprintf( pOut, " def\n"); 2245 } 2246 if( mpCffLocal->mfBlueFuzz) { // default BlueFuzz==1 2247 pOut += sprintf( pOut, "/BlueFuzz "); 2248 pOut += dbl2str( pOut, mpCffLocal->mfBlueFuzz); 2249 pOut += sprintf( pOut, " def\n"); 2250 } 2251 2252 // emit stem hint related privdict entries 2253 if( mpCffLocal->maStemStdHW) { 2254 pOut += sprintf( pOut, "/StdHW ["); 2255 pOut += dbl2str( pOut, mpCffLocal->maStemStdHW); 2256 pOut += sprintf( pOut, "] def\n"); 2257 } 2258 if( mpCffLocal->maStemStdVW) { 2259 pOut += sprintf( pOut, "/StdVW ["); 2260 pOut += dbl2str( pOut, mpCffLocal->maStemStdVW); 2261 pOut += sprintf( pOut, "] def\n"); 2262 } 2263 rEmitter.emitValVector( "/StemSnapH [", "]ND\n", mpCffLocal->maStemSnapH); 2264 rEmitter.emitValVector( "/StemSnapV [", "]ND\n", mpCffLocal->maStemSnapV); 2265 2266 // emit other hints 2267 if( mpCffLocal->mbForceBold) 2268 pOut += sprintf( pOut, "/ForceBold true def\n"); 2269 if( mpCffLocal->mnLangGroup != 0) 2270 pOut += sprintf( pOut, "/LanguageGroup %d def\n", mpCffLocal->mnLangGroup); 2271 if( mpCffLocal->mnLangGroup == 1) // compatibility with ancient printers 2272 pOut += sprintf( pOut, "/RndStemUp false def\n"); 2273 if( mpCffLocal->mfExpFactor) { 2274 pOut += sprintf( pOut, "/ExpansionFactor "); 2275 pOut += dbl2str( pOut, mpCffLocal->mfExpFactor); 2276 pOut += sprintf( pOut, " def\n"); 2277 } 2278 #endif // IGNORE_HINTS 2279 2280 // emit remaining privdict entries 2281 pOut += sprintf( pOut, "/UniqueID %d def\n", nUniqueId); 2282 // TODO?: more privdict entries? 2283 2284 static const char aOtherSubrs[] = 2285 "/OtherSubrs\n" 2286 "% Dummy code for faking flex hints\n" 2287 "[ {} {} {} {systemdict /internaldict known not {pop 3}\n" 2288 "{1183615869 systemdict /internaldict get exec\n" 2289 "dup /startlock known\n" 2290 "{/startlock get exec}\n" 2291 "{dup /strtlck known\n" 2292 "{/strtlck get exec}\n" 2293 "{pop 3}\nifelse}\nifelse}\nifelse\n} executeonly\n" 2294 "] ND\n"; 2295 memcpy( pOut, aOtherSubrs, sizeof(aOtherSubrs)-1); 2296 pOut += sizeof(aOtherSubrs)-1; 2297 2298 // emit used GlobalSubr charstrings 2299 // these are the just the default subrs 2300 // TODO: do we need them as the flex hints are resolved differently? 2301 static const char aSubrs[] = 2302 "/Subrs 5 array\n" 2303 "dup 0 15 RD \x5F\x3D\x6B\xAC\x3C\xBD\x74\x3D\x3E\x17\xA0\x86\x58\x08\x85 NP\n" 2304 "dup 1 9 RD \x5F\x3D\x6B\xD8\xA6\xB5\x68\xB6\xA2 NP\n" 2305 "dup 2 9 RD \x5F\x3D\x6B\xAC\x39\x46\xB9\x43\xF9 NP\n" 2306 "dup 3 5 RD \x5F\x3D\x6B\xAC\xB9 NP\n" 2307 "dup 4 12 RD \x5F\x3D\x6B\xAC\x3E\x5D\x48\x54\x62\x76\x39\x03 NP\n" 2308 "ND\n"; 2309 memcpy( pOut, aSubrs, sizeof(aSubrs)-1); 2310 pOut += sizeof(aSubrs)-1; 2311 2312 // TODO: emit more GlobalSubr charstrings? 2313 // TODO: emit used LocalSubr charstrings? 2314 2315 // emit the CharStrings for the requested glyphs 2316 pOut += sprintf( pOut, 2317 "2 index /CharStrings %d dict dup begin\n", nGlyphCount); 2318 rEmitter.emitAllCrypted(); 2319 for( int i = 0; i < nGlyphCount; ++i) { 2320 const int nGlyphId = pReqGlyphIDs[i]; 2321 assert( (nGlyphId >= 0) && (nGlyphId < mnCharStrCount)); 2322 // get privdict context matching to the glyph 2323 const int nFDSelect = getFDSelect( nGlyphId); 2324 mpCffLocal = &maCffLocal[ nFDSelect]; 2325 // convert the Type2op charstring to its Type1op counterpart 2326 const int nT2Len = seekIndexData( mnCharStrBase, nGlyphId); 2327 assert( nT2Len > 0); 2328 U8 aType1Ops[ MAX_T1OPS_SIZE]; // TODO: dynamic allocation 2329 const int nT1Len = convert2Type1Ops( mpCffLocal, mpReadPtr, nT2Len, aType1Ops); 2330 // get the glyph name 2331 const char* pGlyphName = getGlyphName( nGlyphId); 2332 // emit the encrypted Type1op charstring 2333 pOut += sprintf( pOut, "/%s %d RD ", pGlyphName, nT1Len); 2334 memcpy( pOut, aType1Ops, nT1Len); 2335 pOut += nT1Len; 2336 pOut += sprintf( pOut, " ND\n"); 2337 rEmitter.emitAllCrypted(); 2338 // provide individual glyphwidths if requested 2339 if( pGlyphWidths ) { 2340 ValType aCharWidth = getCharWidth(); 2341 if( maFontMatrix.size() >= 4) 2342 aCharWidth *= 1000.0F * maFontMatrix[0]; 2343 pGlyphWidths[i] = static_cast<GlyphWidth>(aCharWidth); 2344 } 2345 } 2346 pOut += sprintf( pOut, "end end\nreadonly put\nput\n"); 2347 pOut += sprintf( pOut, "dup/FontName get exch definefont pop\n"); 2348 pOut += sprintf( pOut, "mark currentfile closefile\n"); 2349 rEmitter.emitAllCrypted(); 2350 2351 // mark stop of eexec encryption 2352 if( rEmitter.mbPfbSubset) { 2353 const int nEExecLen = rEmitter.tellPos() - nEExecSegTell; 2354 rEmitter.updateLen( nEExecSegTell-4, nEExecLen); 2355 } 2356 2357 // create PFB footer 2358 static const char aPfxFooter[] = "\x80\x01\x14\x02\x00\x00\n" // TODO: check segment len 2359 "0000000000000000000000000000000000000000000000000000000000000000\n" 2360 "0000000000000000000000000000000000000000000000000000000000000000\n" 2361 "0000000000000000000000000000000000000000000000000000000000000000\n" 2362 "0000000000000000000000000000000000000000000000000000000000000000\n" 2363 "0000000000000000000000000000000000000000000000000000000000000000\n" 2364 "0000000000000000000000000000000000000000000000000000000000000000\n" 2365 "0000000000000000000000000000000000000000000000000000000000000000\n" 2366 "0000000000000000000000000000000000000000000000000000000000000000\n" 2367 "cleartomark\n" 2368 "\x80\x03"; 2369 if( rEmitter.mbPfbSubset) 2370 rEmitter.emitRawData( aPfxFooter, sizeof(aPfxFooter)-1); 2371 else 2372 rEmitter.emitRawData( aPfxFooter+6, sizeof(aPfxFooter)-9); 2373 2374 // provide details to the subset requesters, TODO: move into own method? 2375 // note: Top and Bottom are flipped between Type1 and VCL 2376 // note: the rest of VCL expects the details below to be scaled like for an emUnits==1000 font 2377 ValType fXFactor = 1.0; 2378 ValType fYFactor = 1.0; 2379 if( maFontMatrix.size() >= 4) { 2380 fXFactor = 1000.0F * maFontMatrix[0]; 2381 fYFactor = 1000.0F * maFontMatrix[3]; 2382 } 2383 rFSInfo.m_aFontBBox = Rectangle( Point( static_cast<long>(maFontBBox[0] * fXFactor), 2384 static_cast<long>(maFontBBox[1] * fYFactor) ), 2385 Point( static_cast<long>(maFontBBox[2] * fXFactor), 2386 static_cast<long>(maFontBBox[3] * fYFactor) ) ); 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 2392 2393 rFSInfo.m_nFontType = rEmitter.mbPfbSubset ? FontSubsetInfo::TYPE1_PFB : FontSubsetInfo::TYPE1_PFA; 2394 rFSInfo.m_aPSName = String( rEmitter.maSubsetName, RTL_TEXTENCODING_UTF8 ); 2395 2396 return true; 2397 } 2398 2399 // ==================================================================== 2400 2401 bool FontSubsetInfo::CreateFontSubsetFromCff( GlyphWidth* pOutGlyphWidths ) 2402 { 2403 CffSubsetterContext aCff( mpInFontBytes, mnInByteLength); 2404 aCff.initialCffRead(); 2405 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); 2414 return bRC; 2415 } 2416 2417 // ==================================================================== 2418 2419