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