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