Back to index

lightning-sunbird  0.9+nobinonly
nsType1.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Golden Hills Computer Services code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Brian Stell <bstell@ix.netcom.com>.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Brian Stell <bstell@ix.netcom.com>
00024  *   Jungshik Shin <jshin@i18nl10n.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 //
00041 // This file has routines to build Postscript Type 1 fonts
00042 //
00043 // For general information on Postscript see:
00044 //   Adobe Solutions Network: Technical Notes - Fonts
00045 //   http://partners.adobe.com/asn/developer/technotes/fonts.html
00046 //
00047 // For information on Postscript Type 1 fonts see:
00048 //
00049 //   Adobe Type 1 Font Format
00050 //   http://partners.adobe.com/asn/developer/pdfs/tn/T1_SPEC.PDF
00051 //
00052 // This file uses the FreeType2 FT_Outline_Decompose facility to
00053 // access the outlines which are then converted to Postscript Type 1
00054 //
00055 // For general information on FreeType2 see:
00056 //
00057 //   The FreeType Project
00058 //   http://www.freetype.org/
00059 //
00060 //
00061 // For information on FreeType2's outline processing see:
00062 //   FT_Outline_Decompose
00063 //   http://freetype.sourceforge.net/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline_Decompose
00064 //
00065 //
00066 
00067 #include "nsType1.h"
00068 #include "gfx-config.h"
00069 #include <string.h>
00070 #include <unistd.h>
00071 
00072 #ifdef MOZ_ENABLE_FREETYPE2
00073 #include "nsIFreeType2.h"
00074 #include "nsServiceManagerUtils.h"
00075 #endif
00076 #include "nsPrintfCString.h"
00077 #include "nsAutoBuffer.h"
00078 
00079 #define HEXASCII_LINE_LEN 64
00080 
00081 static const PRUint16 kType1EncryptionC1 = 52845;
00082 static const PRUint16 kType1EncryptionC2  = 22719;
00083 static const PRUint16 kType1CharstringEncryptionKey = 4330;
00084 static const PRUint16 kType1EexecEncryptionKey = 55665;
00085 
00086 struct FT2PT1_info {
00087 #ifdef MOZ_ENABLE_FREETYPE2
00088   nsIFreeType2  *ft2;
00089 #endif
00090   FT_Face        face;
00091   int            elm_cnt;
00092   int            len;
00093   double         cur_x;
00094   double         cur_y;
00095   unsigned char *buf;
00096   int            wmode;
00097 };
00098 
00099 // In FT 2.2.0, 'const' was added to the prototypes of some callback functions.
00100 #if (FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2) 
00101 #define nsFT_CONST const
00102 #else 
00103 #define nsFT_CONST
00104 #endif
00105 
00106 static int cubicto(nsFT_CONST FT_Vector *aControlPt1,
00107                    nsFT_CONST FT_Vector *aControlPt2, 
00108                    nsFT_CONST FT_Vector *aEndPt, void *aClosure);
00109 static int Type1CharStringCommand(unsigned char **aBufPtrPtr, int aCmd);
00110 static int Type1EncodeCharStringInt(unsigned char **aBufPtrPtr, int aValue);
00111 
00112 static void encryptAndHexOut(FILE *aFile, PRUint32* aPos, PRUint16* aKey,
00113                              const char *aBuf, PRInt32 aLen = -1);
00114 static void charStringOut(FILE* aFile, PRUint32* aPos, PRUint16* aKey,
00115                           const char *aStr, PRUint32 aLen, 
00116                           PRUnichar aId);
00117 static void flattenName(nsCString& aString);
00118 
00119 /* thunk a short name for this function */
00120 static inline int
00121 csc(unsigned char **aBufPtrPtr, int aCmd)
00122 {
00123   return Type1CharStringCommand(aBufPtrPtr, aCmd);
00124 }
00125 
00126 /* thunk a short name for this function */
00127 static inline int
00128 ecsi(unsigned char **aBufPtrPtr, int aValue)
00129 {
00130   return Type1EncodeCharStringInt(aBufPtrPtr, aValue);
00131 }
00132 
00133 static int
00134 Type1CharStringCommand(unsigned char **aBufPtrPtr, int aCmd)
00135 {
00136   unsigned char *p = *aBufPtrPtr;
00137   if (p) {
00138     *p = aCmd;
00139     *aBufPtrPtr = p + 1;
00140   }
00141   return 1;
00142 }
00143 
00144 static int
00145 Type1EncodeCharStringInt(unsigned char **aBufPtrPtr, int aValue)
00146 {
00147   unsigned char *p = *aBufPtrPtr;
00148 
00149   if ((aValue >= -107) && (aValue <= 107)) { 
00150     if (p) {
00151       p[0] = aValue + 139;
00152       *aBufPtrPtr = p + 1;
00153     }
00154     return 1;
00155   }
00156   else if ((aValue >= 108) && (aValue <= 1131)) {
00157     if (p) {
00158       p[0] = ((aValue - 108)>>8) + 247; 
00159       p[1] = (aValue - 108) & 0xFF;
00160       *aBufPtrPtr = p + 2;
00161     }
00162     return 2;
00163   }
00164   else if ((aValue <= -108) && (aValue >= -1131)) {
00165     if (p) {
00166       p[0] = ((-aValue - 108)>>8) + 251;
00167       p[1] = (-aValue - 108) & 0xFF;
00168       *aBufPtrPtr = p + 2;
00169     }
00170     return 2;
00171   }
00172   else {
00173     unsigned int tmp = (unsigned int)aValue;
00174     if (p) {
00175       p[0] = 255;
00176       p[1] = (tmp>>24) & 0xFF;
00177       p[2] = (tmp>>16) & 0xFF;
00178       p[3] = (tmp>>8) & 0xFF;
00179       p[4] = tmp & 0xFF;
00180       *aBufPtrPtr = p + 5;
00181     }
00182     return 5;
00183   }
00184 }
00185 
00186 inline unsigned char
00187 Type1Encrypt(unsigned char aPlain, PRUint16 *aKeyPtr)
00188 {
00189   unsigned char cipher;
00190   cipher = (aPlain ^ (*aKeyPtr >> 8));
00191   *aKeyPtr = (cipher + *aKeyPtr) * kType1EncryptionC1 + kType1EncryptionC2;
00192   return cipher;
00193 }
00194 
00195 static void
00196 Type1EncryptString(unsigned char *aInBuf, unsigned char *aOutBuf, int aLen)
00197 {
00198   int i;
00199   PRUint16 key = kType1CharstringEncryptionKey;
00200 
00201   for (i=0; i<aLen; i++)
00202     aOutBuf[i] = Type1Encrypt(aInBuf[i], &key);
00203 }
00204 
00205 static PRBool
00206 sideWidthAndBearing(const FT_Vector *aEndPt, FT2PT1_info *aFti)
00207 {
00208   int aw = 0;
00209   int ah = 0;
00210   FT_UShort upm = aFti->face->units_per_EM;
00211   FT_GlyphSlot slot;
00212   FT_Glyph glyph;
00213   FT_BBox bbox;
00214 
00215   slot = aFti->face->glyph;
00216 
00217 #ifdef MOZ_ENABLE_XFT
00218   FT_Error error = FT_Get_Glyph(slot, &glyph);
00219   if (error) {
00220     NS_ERROR("sideWidthAndBearing failed to get glyph");
00221     return PR_FALSE;
00222   }
00223   FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_unscaled, &bbox);
00224 #else
00225   nsresult rv = aFti->ft2->GetGlyph(slot, &glyph);
00226   if (NS_FAILED(rv)) {
00227     NS_ERROR("sideWidthAndBearing failed to get glyph");
00228     return PR_FALSE;
00229   }
00230   aFti->ft2->GlyphGetCBox(glyph, ft_glyph_bbox_unscaled, &bbox);
00231 #endif
00232 
00233   if (aFti->wmode == 0)
00234     aw = toCS(upm, slot->metrics.horiAdvance);
00235   else
00236     aw = -toCS(upm, slot->metrics.vertAdvance);
00237 
00238   if (aEndPt->y == 0) {
00239     aFti->len += ecsi(&aFti->buf, (int)(aFti->cur_x = toCS(upm, bbox.xMin)));
00240     aFti->cur_y = 0;
00241     aFti->len += ecsi(&aFti->buf, aw);
00242     aFti->len += csc(&aFti->buf, T1_HSBW);
00243   }
00244   else {
00245     aFti->len += ecsi(&aFti->buf, (int)(aFti->cur_x = toCS(upm, bbox.xMin)));
00246     aFti->len += ecsi(&aFti->buf, (int)(aFti->cur_y = toCS(upm, bbox.yMin)));
00247     aFti->len += ecsi(&aFti->buf, aw);
00248     aFti->len += ecsi(&aFti->buf, ah);
00249     aFti->len += csc(&aFti->buf, T1_ESC_CMD);
00250     aFti->len += csc(&aFti->buf, T1_ESC_SBW);
00251   }
00252   return PR_TRUE;
00253 }
00254 
00255 static int
00256 moveto(nsFT_CONST FT_Vector *aEndPt, void *aClosure)
00257 {
00258   FT2PT1_info *fti = (FT2PT1_info *)aClosure;
00259   FT_UShort upm = fti->face->units_per_EM;
00260   PRBool rslt;
00261 
00262   if (fti->elm_cnt == 0) {
00263     rslt = sideWidthAndBearing(aEndPt, fti);
00264     if (rslt != PR_TRUE) {
00265       return 1;
00266     }
00267   }
00268   else {
00269     fti->len += csc(&fti->buf, T1_CLOSEPATH);
00270   }
00271 
00272   if (toCS(upm, aEndPt->x) == fti->cur_x) {
00273     fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y);
00274     fti->len += csc(&fti->buf, T1_VMOVETO);
00275   }
00276   else if (toCS(upm, aEndPt->y) == fti->cur_y) {
00277     fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->x) - (int)fti->cur_x);
00278     fti->len += csc(&fti->buf, T1_HMOVETO);
00279   }
00280   else {
00281     fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->x) - (int)fti->cur_x);
00282     fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y);
00283     fti->len += csc(&fti->buf, T1_RMOVETO);
00284   }
00285 
00286   fti->cur_x = toCS(upm, aEndPt->x);
00287   fti->cur_y = toCS(upm, aEndPt->y);
00288   fti->elm_cnt++;
00289   return 0;
00290 }
00291 
00292 static int
00293 lineto(nsFT_CONST FT_Vector *aEndPt, void *aClosure)
00294 {
00295   FT2PT1_info *fti = (FT2PT1_info *)aClosure;
00296   FT_UShort upm = fti->face->units_per_EM;
00297 
00298   if (toCS(upm, aEndPt->x) == fti->cur_x) {
00299     fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y);
00300     fti->len += csc(&fti->buf, T1_VLINETO);
00301   }
00302   else if (toCS(upm, aEndPt->y) == fti->cur_y) {
00303     fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->x) - (int)fti->cur_x);
00304     fti->len += csc(&fti->buf, T1_HLINETO);
00305   }
00306   else {
00307     fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->x) - (int)fti->cur_x);
00308     fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y);
00309     fti->len += csc(&fti->buf, T1_RLINETO);
00310   }
00311 
00312   fti->cur_x = toCS(upm, aEndPt->x);
00313   fti->cur_y = toCS(upm, aEndPt->y);
00314   fti->elm_cnt++;
00315   return 0;
00316 }
00317 
00318 static int
00319 conicto(nsFT_CONST FT_Vector *aControlPt, nsFT_CONST FT_Vector *aEndPt,
00320         void *aClosure)
00321 {
00322   FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure;
00323   FT_UShort upm = ftinfo->face->units_per_EM;
00324   double ctl_x, ctl_y;
00325   double cur_x, cur_y, x3, y3;
00326   FT_Vector aControlPt1, aControlPt2;
00327   int rslt;
00328 
00329   cur_x = ftinfo->cur_x;
00330   cur_y = ftinfo->cur_y;
00331   ctl_x = toCS(upm, aControlPt->x);
00332   ctl_y = toCS(upm, aControlPt->y);
00333   x3 = toCS(upm, aEndPt->x);
00334   y3 = toCS(upm, aEndPt->y);
00335 
00336   // So we can use the cubic curve code convert quadradic to cubic; 
00337 
00338   // the 1st control point is 2/3 the way from the start to the control point
00339   aControlPt1.x = fromCS(upm, (cur_x + (2 * (ctl_x - cur_x) + 1)/3));
00340   aControlPt1.y = fromCS(upm, (cur_y + (2 * (ctl_y - cur_y) + 1)/3));
00341 
00342   // the 2nd control point is 1/3 the way from the control point to the end
00343   aControlPt2.x = fromCS(upm, (ctl_x + (x3 - ctl_x + 1)/3));
00344   aControlPt2.y = fromCS(upm, (ctl_y + (y3 - ctl_y + 1)/3));
00345 
00346   // call the cubic code
00347   rslt = cubicto(&aControlPt1, &aControlPt2, aEndPt, aClosure);
00348   return rslt;
00349 }
00350 
00351 static int
00352 cubicto(nsFT_CONST FT_Vector *aControlPt1, nsFT_CONST FT_Vector *aControlPt2,
00353         nsFT_CONST FT_Vector *aEndPt, void *aClosure)
00354 {
00355   FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure;
00356   FT_UShort upm = ftinfo->face->units_per_EM;
00357   double cur_x, cur_y, x1, y1, x2, y2, x3, y3;
00358 
00359   cur_x = ftinfo->cur_x;
00360   cur_y = ftinfo->cur_y;
00361 
00362   x1 = toCS(upm, aControlPt1->x);
00363   y1 = toCS(upm, aControlPt1->y);
00364 
00365   x2 = toCS(upm, aControlPt2->x);
00366   y2 = toCS(upm, aControlPt2->y);
00367 
00368   x3 = toCS(upm, aEndPt->x);
00369   y3 = toCS(upm, aEndPt->y);
00370 
00371   /* horizontal to vertical curve */
00372   if (((int)(y1) == (int)(cur_y)) && ((int)(x3) == (int)(x2))) {
00373     ftinfo->len += ecsi(&ftinfo->buf, (int)(x1-cur_x));
00374     ftinfo->len += ecsi(&ftinfo->buf, (int)(x2-x1));
00375     ftinfo->len += ecsi(&ftinfo->buf, (int)(y2-y1));
00376     ftinfo->len += ecsi(&ftinfo->buf, (int)(y3-y2));
00377     ftinfo->len += csc(&ftinfo->buf, T1_HVCURVETO);
00378   }
00379   /* vertical to horizontal curve */
00380   else if (((int)(x1) == (int)(cur_x)) && ((int)(y3) == (int)(y2))) {
00381     ftinfo->len += ecsi(&ftinfo->buf, (int)(y1-cur_y));
00382     ftinfo->len += ecsi(&ftinfo->buf, (int)(x2-x1));
00383     ftinfo->len += ecsi(&ftinfo->buf, (int)(y2-y1));
00384     ftinfo->len += ecsi(&ftinfo->buf, (int)(x3-x2));
00385     ftinfo->len += csc(&ftinfo->buf, T1_VHCURVETO);
00386   }
00387   else {
00388     ftinfo->len += ecsi(&ftinfo->buf,  (int)(x1-cur_x));
00389     ftinfo->len += ecsi(&ftinfo->buf,  (int)(y1-cur_y));
00390     ftinfo->len += ecsi(&ftinfo->buf,  (int)(x2-x1));
00391     ftinfo->len += ecsi(&ftinfo->buf,  (int)(y2-y1));
00392     ftinfo->len += ecsi(&ftinfo->buf,  (int)(x3-x2));
00393     ftinfo->len += ecsi(&ftinfo->buf,  (int)(y3-y2));
00394     ftinfo->len += csc(&ftinfo->buf, T1_RRCURVETO);
00395   }
00396   ftinfo->cur_x = x3;
00397   ftinfo->cur_y = y3;
00398   ftinfo->elm_cnt++;
00399   return 0;
00400 }
00401 
00402 static FT_Outline_Funcs ft_outline_funcs = {
00403   moveto,
00404   lineto,
00405   conicto,
00406   cubicto,
00407   0,
00408   0
00409 };
00410 
00411 FT_Error
00412 #ifdef MOZ_ENABLE_XFT
00413 FT2GlyphToType1CharString(FT_Face aFace, PRUint32 aGlyphID,
00414                           int aWmode, int aLenIV, unsigned char *aBuf)
00415 #else
00416 FT2GlyphToType1CharString(nsIFreeType2 *aFt2, FT_Face aFace, PRUint32 aGlyphID,
00417                           int aWmode, int aLenIV, unsigned char *aBuf)
00418 #endif
00419 {
00420   int j;
00421   FT_Int32 flags = FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
00422   FT_GlyphSlot slot;
00423   unsigned char *start = aBuf;
00424   FT2PT1_info fti;
00425 
00426 #ifdef MOZ_ENABLE_XFT
00427   FT_Error error = FT_Load_Glyph(aFace, aGlyphID, flags);
00428   if (error) {
00429     NS_ERROR("failed to load aGlyphID");
00430     return error;
00431   }
00432 #else
00433   nsresult rv = aFt2->LoadGlyph(aFace, aGlyphID, flags);
00434   if (NS_FAILED(rv)) {
00435     NS_ERROR("failed to load aGlyphID");
00436     return 1;
00437   }
00438 #endif
00439   slot = aFace->glyph;
00440 
00441   if (slot->format != ft_glyph_format_outline) {
00442     NS_ERROR("aGlyphID is not an outline glyph");
00443     return 1;
00444   }
00445 
00446 #ifdef MOZ_ENABLE_FREETYPE2
00447   fti.ft2     = aFt2;
00448 #endif
00449   fti.face    = aFace;
00450   fti.buf     = aBuf;
00451   fti.elm_cnt = 0;
00452   fti.len     = 0;
00453   fti.wmode   = aWmode;
00454 
00455   /* add space for "random" bytes */
00456   for (j=0; j< aLenIV; j++) {
00457     fti.len += ecsi(&fti.buf, 0);
00458   }
00459 #ifdef MOZ_ENABLE_XFT
00460   if (FT_Outline_Decompose(&slot->outline, &ft_outline_funcs, &fti))  {
00461     NS_ERROR("error decomposing aGlyphID");
00462     return 1;
00463   }
00464 #else
00465   rv = aFt2->OutlineDecompose(&slot->outline, &ft_outline_funcs, &fti);
00466   if (NS_FAILED(rv)) {
00467     NS_ERROR("error decomposing aGlyphID");
00468     return 1;
00469   }
00470 #endif
00471 
00472   if (fti.elm_cnt) {
00473     fti.len += csc(&fti.buf, T1_CLOSEPATH);
00474     fti.len += csc(&fti.buf, T1_ENDCHAR);
00475   }
00476   else {
00477     FT_Vector end_pt;
00478     end_pt.x = 0;
00479     end_pt.y = 1; /* dummy value to cause sbw instead of hsbw */
00480     PRBool rslt = sideWidthAndBearing(&end_pt, &fti);
00481     if (rslt != PR_TRUE) {
00482       return 1;
00483     }
00484     fti.len += csc(&fti.buf, T1_ENDCHAR);
00485   }
00486   if (fti.buf) {
00487     Type1EncryptString(start, start, fti.len);
00488   }
00489 
00490   return fti.len;
00491 }
00492 
00493 static PRBool
00494 #ifdef MOZ_ENABLE_XFT
00495 outputType1SubFont(FT_Face aFace,
00496 #else
00497 outputType1SubFont(nsIFreeType2 *aFt2, FT_Face aFace,
00498 #endif
00499                  const nsAString &aCharIDs, const char *aFontName,
00500                  int aWmode, int aLenIV, FILE *aFile);
00501 
00502 nsresult
00503 FT2ToType1FontName(FT_Face aFace, int aWmode, nsCString& aFontName)
00504 {
00505   aFontName = aFace->family_name;
00506   aFontName.AppendLiteral(".");
00507   aFontName += aFace->style_name;
00508   aFontName += nsPrintfCString(".%ld.%d", aFace->face_index, aWmode ? 1 : 0);
00509   flattenName(aFontName);
00510   return NS_OK;
00511 }
00512 
00513 // output a subsetted truetype font converted to multiple type 1 fonts
00514 PRBool
00515 FT2SubsetToType1FontSet(FT_Face aFace, const nsString& aSubset,
00516                         int aWmode,  FILE *aFile)
00517 {
00518 #ifdef MOZ_ENABLE_FREETYPE2
00519   nsresult rv; 
00520   nsCOMPtr<nsIFreeType2> ft2 = do_GetService(NS_FREETYPE2_CONTRACTID, &rv);
00521   if (NS_FAILED(rv)) {
00522     NS_ERROR("Failed to get nsIFreeType2 service");
00523     return PR_FALSE;
00524   }
00525 #endif
00526 
00527   nsCAutoString fontNameBase;
00528   FT2ToType1FontName(aFace, aWmode, fontNameBase);
00529   PRUint32 i = 0;
00530   for (; i <= aSubset.Length() / 255 ; i++) {
00531     nsCAutoString fontName(fontNameBase);
00532     fontName.AppendLiteral(".Set");
00533     fontName.AppendInt(i);
00534 #ifdef MOZ_ENABLE_XFT
00535     outputType1SubFont(aFace,
00536 #else
00537     outputType1SubFont(ft2, aFace, 
00538 #endif
00539       Substring(aSubset, i * 255, PR_MIN(255, aSubset.Length() - i * 255)),
00540       fontName.get(), aWmode, 4, aFile);
00541   }
00542   return PR_TRUE;
00543 }
00544 
00545 // output a type 1 font (with 255 characters or fewer) 
00546 static PRBool
00547 #ifdef MOZ_ENABLE_XFT
00548 outputType1SubFont(FT_Face aFace,
00549 #else
00550 outputType1SubFont(nsIFreeType2 *aFt2, FT_Face aFace,
00551 #endif
00552                  const nsAString& aCharIDs, const char *aFontName,
00553                  int aWmode, int aLenIV, FILE *aFile)
00554 {
00555   FT_UShort upm = aFace->units_per_EM;
00556 
00557   fprintf(aFile, "%%%%BeginResource: font %s\n"
00558                  "%%!PS-AdobeFont-1.0-3.0 %s 1.0\n"
00559                  "%%%%Creator: Mozilla Freetype2 Printing code 2.0\n"
00560                  "%%%%Title: %s\n"
00561                  "%%%%Pages: 0\n"
00562                  "%%%%EndComments\n"
00563                  "8 dict begin\n", aFontName, aFontName, aFontName);
00564 
00565   fprintf(aFile, "/FontName /%s def\n"
00566                  "/FontType 1 def\n"
00567                  "/FontMatrix [ 0.001 0 0 0.001 0 0 ]readonly def\n"
00568                  "/PaintType 0 def\n", aFontName);
00569 
00570   fprintf(aFile, "/FontBBox [%d %d %d %d]readonly def\n", 
00571                  toCS(upm, aFace->bbox.xMin),
00572                  toCS(upm, aFace->bbox.yMin),
00573                  toCS(upm, aFace->bbox.xMax),
00574                  toCS(upm, aFace->bbox.yMax));
00575 
00576   nsString charIDstr(aCharIDs);
00577   PRUint32 len = aCharIDs.Length();
00578   
00579   if (len < 10) { 
00580     // Add a small set of characters to the subset of the user
00581     // defined font to produce to make sure the font ends up
00582     // being larger than 2000 bytes, a threshold under which
00583     // some printers will consider the font invalid.  (bug 253219)
00584     // XXX : need to check if this is true of type 1 fonts as well.
00585     // I suspect it's only the case of CID-keyed fonts (type 9) we used to
00586     // generate. 
00587     charIDstr.AppendLiteral("1234567890"); 
00588     len += 10;
00589   }
00590   
00591   const PRUnichar *charIDs = charIDstr.get();
00592 
00593   PRUint32 i;
00594 
00595   // construct an Encoding vector : the 0th element
00596   // is /.notdef
00597   fputs("/Encoding [\n/.notdef\n", aFile); 
00598   for (i = 0; i < len; ++i) {
00599       fprintf(aFile, "/uni%04X", charIDs[i]); 
00600       if (i % 8 == 7) fputc('\n', aFile);
00601   }
00602 
00603   for (i = len; i < 255; ++i) {
00604       fputs("/.notdef", aFile);
00605       if (i % 8 == 7) fputc('\n', aFile);
00606   }
00607   fputs("] def\n", aFile); 
00608 
00609   fprintf(aFile, "currentdict end\n"
00610                  "currentfile eexec\n");
00611 
00612   PRUint32 pos = 0;
00613   PRUint16 key = kType1EexecEncryptionKey;
00614 
00615   // add 'random' bytes (a sequence of zeros would suffice)
00616   for (i = 0; i < PRUint32(aLenIV); ++i)
00617     encryptAndHexOut(aFile, &pos, &key, "\0", 1);
00618 
00619   // We don't need any fancy stuff (hint, subroutines, etc) in 
00620   // 'Private' dictionary. (ref. Adobe Type 1 Spec. Chapters 2 and 5)
00621   encryptAndHexOut(aFile, &pos, &key,
00622                    "dup /Private 6 dict dup begin\n"
00623                    "/RD {string currentfile exch readstring pop} executeonly def\n"
00624                    "/ND {noaccess def} executeonly def\n"
00625                    "/NP {noaccess put} executeonly def\n"
00626                    "/BlueValues [] def\n"
00627                    "/MinFeature {16 16} def\n"
00628                    "/password 5839 def\n"); 
00629 
00630   // get the maximum charstring length without actually filling up the buffer
00631   PRInt32 charStringLen;
00632   PRInt32 maxCharStringLen =
00633 #ifdef MOZ_ENABLE_XFT
00634     FT2GlyphToType1CharString(aFace, 0, aWmode, aLenIV, nsnull);
00635 #else
00636     FT2GlyphToType1CharString(aFt2, aFace, 0, aWmode, aLenIV, nsnull);
00637 #endif
00638 
00639   PRUint32 glyphID;
00640 
00641   for (i = 0; i < len; i++) {
00642 #ifdef MOZ_ENABLE_XFT
00643     glyphID = FT_Get_Char_Index(aFace, charIDs[i]);
00644     charStringLen =
00645       FT2GlyphToType1CharString(aFace, glyphID, aWmode, aLenIV, nsnull);
00646 #else
00647     aFt2->GetCharIndex(aFace, charIDs[i], &glyphID);
00648     charStringLen =
00649       FT2GlyphToType1CharString(aFt2, aFace, glyphID, aWmode, aLenIV, nsnull);
00650 #endif
00651 
00652     if (charStringLen > maxCharStringLen)
00653       maxCharStringLen = charStringLen;
00654   }
00655 
00656   nsAutoBuffer<PRUint8, 1024> charString;
00657 
00658   if (!charString.EnsureElemCapacity(maxCharStringLen)) {
00659     NS_ERROR("Failed to alloc bytes for charstring");
00660     return PR_FALSE;
00661   }
00662 
00663   // output CharString 
00664   encryptAndHexOut(aFile, &pos, &key,
00665                    nsPrintfCString(60, "2 index /CharStrings %d dict dup begin\n",
00666                                    len + 1).get()); 
00667 
00668   // output the notdef glyph
00669 #ifdef MOZ_ENABLE_XFT
00670   charStringLen = FT2GlyphToType1CharString(aFace, 0, aWmode, aLenIV,
00671                                             charString.get());
00672 #else
00673   charStringLen = FT2GlyphToType1CharString(aFt2, aFace, 0, aWmode, aLenIV,
00674                                             charString.get());
00675 #endif
00676 
00677   // enclose charString with  "/.notdef RD .....  ND" 
00678   charStringOut(aFile, &pos, &key, NS_REINTERPRET_CAST(const char*, charString.get()),
00679                 charStringLen, 0); 
00680 
00681 
00682   // output the charstrings for each glyph in this sub font
00683   for (i = 0; i < len; i++) {
00684 #ifdef MOZ_ENABLE_XFT
00685     glyphID = FT_Get_Char_Index(aFace, charIDs[i]);
00686     charStringLen = FT2GlyphToType1CharString(aFace, glyphID, aWmode,
00687                                               aLenIV, charString.get());
00688 #else
00689     aFt2->GetCharIndex(aFace, charIDs[i], &glyphID);
00690     charStringLen = FT2GlyphToType1CharString(aFt2, aFace, glyphID, aWmode,
00691                                               aLenIV, charString.get());
00692 #endif
00693     charStringOut(aFile, &pos, &key, NS_REINTERPRET_CAST(const char*, charString.get()),
00694                   charStringLen, charIDs[i]);
00695   }
00696 
00697   // wrap up the encrypted part of the font definition
00698   encryptAndHexOut(aFile, &pos, &key,
00699                    "end\nend\n"
00700                    "readonly put\n"
00701                    "noaccess put\n"
00702                    "dup /FontName get exch definefont pop\n"
00703                    "mark currentfile closefile\n");
00704   if (pos) 
00705     fputc('\n', aFile);
00706 
00707   // output mandatory 512 0's
00708   const static char sixtyFourZeros[] =  
00709       "0000000000000000000000000000000000000000000000000000000000000000\n";
00710   for (i = 0; i < 8; i++) 
00711     fprintf(aFile, sixtyFourZeros);
00712 
00713   fprintf(aFile, "cleartomark\n%%%%EndResource\n"); 
00714 
00715   return PR_TRUE;
00716 }
00717   
00718 /* static */ 
00719 void flattenName(nsCString& aString)
00720 {
00721   nsCString::iterator start, end;
00722   aString.BeginWriting(start);
00723   aString.EndWriting(end);
00724   while(start != end) {
00725     if (*start == ' ')
00726       *start= '_';
00727     else if (*start == '(')
00728       *start = '_';
00729     else if (*start == ')')
00730       *start = '_';
00731     ++start;
00732   }
00733 }
00734 
00735 /* static */ 
00736 void encryptAndHexOut(FILE *aFile, PRUint32* aPos, PRUint16* aKey,
00737                       const char *aBuf, PRInt32 aLen) 
00738 {
00739   if (aLen == -1) 
00740       aLen = strlen(aBuf); 
00741 
00742   PRInt32 i;
00743   for (i = 0; i < aLen; i++) {
00744     PRUint8 cipher = Type1Encrypt((unsigned char) aBuf[i], aKey);  
00745     fprintf(aFile, "%02X", cipher); 
00746     *aPos += 2;
00747     if (*aPos >= HEXASCII_LINE_LEN) {
00748       fprintf(aFile, "\n");
00749       *aPos = 0;
00750     }
00751   }
00752 }
00753 
00754 /* static */ 
00755 void charStringOut(FILE* aFile,  PRUint32* aPos, PRUint16* aKey, 
00756                    const char *aStr, PRUint32 aLen, PRUnichar aId)
00757 {
00758     // use a local buffer instead of nsPrintfCString to avoid alloc.
00759     char buf[30];
00760     int oLen;
00761     if (aId == 0)
00762       oLen = PR_snprintf(buf, 30, "/.notdef %d RD ", aLen); 
00763     else 
00764       oLen = PR_snprintf(buf, 30, "/uni%04X %d RD ", aId, aLen); 
00765 
00766     if (oLen >= 30) {
00767       NS_WARNING("buffer size exceeded. charstring will be truncated");
00768       encryptAndHexOut(aFile, aPos, aKey, buf, 30); 
00769     }
00770     else 
00771       encryptAndHexOut(aFile, aPos, aKey, buf); 
00772 
00773     encryptAndHexOut(aFile, aPos, aKey, aStr, aLen);
00774 
00775     encryptAndHexOut(aFile, aPos, aKey, "ND\n");
00776 }