/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * ex: set tabstop=8 softtabstop=2 shiftwidth=2 expandtab: * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Golden Hills Computer Services code. * * The Initial Developer of the Original Code is * Brian Stell . * * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Brian Stell . * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ // // This file has routines to build Postscript Type 1 fonts // // For general information on Postscript see: // Adobe Solutions Network: Technical Notes - Fonts // http://partners.adobe.com/asn/developer/technotes/fonts.html // // For information on Postscript Type 1 fonts see: // // Adobe Type 1 Font Format // http://partners.adobe.com/asn/developer/pdfs/tn/T1_SPEC.PDF // // This file uses the FreeType2 FT_Outline_Decompose facility to // access the outlines which are then converted to Postscript Type 1 // // For general information on FreeType2 see: // // The FreeType Project // http://www.freetype.org/ // // // For information on FreeType2's outline processing see: // FT_Outline_Decompose // http://freetype.sourceforge.net/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline_Decompose // // #include "nsType1.h" static const PRUint16 type1_encryption_c1 = TYPE1_ENCRYPTION_C1; static const PRUint16 type1_encryption_c2 = TYPE1_ENCRYPTION_C2; typedef struct { nsIFreeType2 *ft2; FT_Face face; int elm_cnt; int len; double cur_x; double cur_y; unsigned char *buf; int wmode; } FT2PT1_info; static int cubicto(FT_Vector *aControlPt1, FT_Vector *aControlPt2, FT_Vector *aEndPt, void *aClosure); static int Type1CharStringCommand(unsigned char **aBufPtrPtr, int aCmd); static int Type1EncodeCharStringInt(unsigned char **aBufPtrPtr, int aValue); /* thunk a short name for this function */ static inline int csc(unsigned char **aBufPtrPtr, int aCmd) { return Type1CharStringCommand(aBufPtrPtr, aCmd); } /* thunk a short name for this function */ static inline int ecsi(unsigned char **aBufPtrPtr, int aValue) { return Type1EncodeCharStringInt(aBufPtrPtr, aValue); } static int Type1CharStringCommand(unsigned char **aBufPtrPtr, int aCmd) { unsigned char *p = *aBufPtrPtr; if (p) { *p = aCmd; *aBufPtrPtr = p + 1; } return 1; } static int Type1EncodeCharStringInt(unsigned char **aBufPtrPtr, int aValue) { unsigned char *p = *aBufPtrPtr; if ((aValue >= -107) && (aValue <= 107)) { if (p) { p[0] = aValue + 139; *aBufPtrPtr = p + 1; } return 1; } else if ((aValue >= 108) && (aValue <= 1131)) { if (p) { p[0] = ((aValue - 108)>>8) + 247; p[1] = (aValue - 108) & 0xFF; *aBufPtrPtr = p + 2; } return 2; } else if ((aValue <= -108) && (aValue >= -1131)) { if (p) { p[0] = ((-aValue - 108)>>8) + 251; p[1] = (-aValue - 108) & 0xFF; *aBufPtrPtr = p + 2; } return 2; } else { unsigned int tmp = (unsigned int)aValue; if (p) { p[0] = 255; p[1] = (tmp>>24) & 0xFF; p[2] = (tmp>>16) & 0xFF; p[3] = (tmp>>8) & 0xFF; p[4] = tmp & 0xFF; *aBufPtrPtr = p + 5; } return 5; } } inline unsigned char Type1Encrypt(unsigned char aPlain, PRUint16 *aKeyPtr) { unsigned char cipher; cipher = (aPlain ^ (*aKeyPtr >> 8)); *aKeyPtr = (cipher + *aKeyPtr) * type1_encryption_c1 + type1_encryption_c2; return cipher; } static void Type1EncryptString(unsigned char *aInBuf, unsigned char *aOutBuf, int aLen) { int i; PRUint16 key = TYPE1_ENCRYPTION_KEY; for (i=0; iface->units_per_EM; FT_GlyphSlot slot; FT_Glyph glyph; FT_BBox bbox; nsresult rv; slot = aFti->face->glyph; rv = aFti->ft2->GetGlyph(slot, &glyph); if (NS_FAILED(rv)) { NS_ERROR("sideWidthAndBearing failed to get glyph"); return PR_FALSE; } aFti->ft2->GlyphGetCBox(glyph, ft_glyph_bbox_unscaled, &bbox); if (aFti->wmode == 0) aw = toCS(upm, slot->metrics.horiAdvance); else aw = -toCS(upm, slot->metrics.vertAdvance); if (aEndPt->y == 0) { aFti->len += ecsi(&aFti->buf, (int)(aFti->cur_x = toCS(upm, bbox.xMin))); aFti->cur_y = 0; aFti->len += ecsi(&aFti->buf, aw); aFti->len += csc(&aFti->buf, T1_HSBW); } else { aFti->len += ecsi(&aFti->buf, (int)(aFti->cur_x = toCS(upm, bbox.xMin))); aFti->len += ecsi(&aFti->buf, (int)(aFti->cur_y = toCS(upm, bbox.yMin))); aFti->len += ecsi(&aFti->buf, aw); aFti->len += ecsi(&aFti->buf, ah); aFti->len += csc(&aFti->buf, T1_ESC_CMD); aFti->len += csc(&aFti->buf, T1_ESC_SBW); } return PR_TRUE; } static int moveto(FT_Vector *aEndPt, void *aClosure) { FT2PT1_info *fti = (FT2PT1_info *)aClosure; FT_UShort upm = fti->face->units_per_EM; PRBool rslt; if (fti->elm_cnt == 0) { rslt = sideWidthAndBearing(aEndPt, fti); if (rslt != PR_TRUE) { return 1; } } else { fti->len += csc(&fti->buf, T1_CLOSEPATH); } if (toCS(upm, aEndPt->x) == fti->cur_x) { fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y); fti->len += csc(&fti->buf, T1_VMOVETO); } else if (toCS(upm, aEndPt->y) == fti->cur_y) { fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->x) - (int)fti->cur_x); fti->len += csc(&fti->buf, T1_HMOVETO); } else { fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->x) - (int)fti->cur_x); fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y); fti->len += csc(&fti->buf, T1_RMOVETO); } fti->cur_x = toCS(upm, aEndPt->x); fti->cur_y = toCS(upm, aEndPt->y); fti->elm_cnt++; return 0; } static int lineto(FT_Vector *aEndPt, void *aClosure) { FT2PT1_info *fti = (FT2PT1_info *)aClosure; FT_UShort upm = fti->face->units_per_EM; if (toCS(upm, aEndPt->x) == fti->cur_x) { fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y); fti->len += csc(&fti->buf, T1_VLINETO); } else if (toCS(upm, aEndPt->y) == fti->cur_y) { fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->x) - (int)fti->cur_x); fti->len += csc(&fti->buf, T1_HLINETO); } else { fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->x) - (int)fti->cur_x); fti->len += ecsi(&fti->buf, toCS(upm, aEndPt->y) - (int)fti->cur_y); fti->len += csc(&fti->buf, T1_RLINETO); } fti->cur_x = toCS(upm, aEndPt->x); fti->cur_y = toCS(upm, aEndPt->y); fti->elm_cnt++; return 0; } static int conicto(FT_Vector *aControlPt, FT_Vector *aEndPt, void *aClosure) { FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure; FT_UShort upm = ftinfo->face->units_per_EM; double ctl_x, ctl_y; double cur_x, cur_y, x3, y3; FT_Vector aControlPt1, aControlPt2; int rslt; cur_x = ftinfo->cur_x; cur_y = ftinfo->cur_y; ctl_x = toCS(upm, aControlPt->x); ctl_y = toCS(upm, aControlPt->y); x3 = toCS(upm, aEndPt->x); y3 = toCS(upm, aEndPt->y); // So we can use the cubic curve code convert quadradic to cubic; // the 1st control point is 2/3 the way from the start to the control point aControlPt1.x = fromCS(upm, (cur_x + (2 * (ctl_x - cur_x) + 1)/3)); aControlPt1.y = fromCS(upm, (cur_y + (2 * (ctl_y - cur_y) + 1)/3)); // the 2nd control point is 1/3 the way from the control point to the end aControlPt2.x = fromCS(upm, (ctl_x + (x3 - ctl_x + 1)/3)); aControlPt2.y = fromCS(upm, (ctl_y + (y3 - ctl_y + 1)/3)); // call the cubic code rslt = cubicto(&aControlPt1, &aControlPt2, aEndPt, aClosure); return rslt; } static int cubicto(FT_Vector *aControlPt1, FT_Vector *aControlPt2, FT_Vector *aEndPt, void *aClosure) { FT2PT1_info *ftinfo = (FT2PT1_info *)aClosure; FT_UShort upm = ftinfo->face->units_per_EM; double cur_x, cur_y, x1, y1, x2, y2, x3, y3; cur_x = ftinfo->cur_x; cur_y = ftinfo->cur_y; x1 = toCS(upm, aControlPt1->x); y1 = toCS(upm, aControlPt1->y); x2 = toCS(upm, aControlPt2->x); y2 = toCS(upm, aControlPt2->y); x3 = toCS(upm, aEndPt->x); y3 = toCS(upm, aEndPt->y); /* horizontal to vertical curve */ if (((int)(y1) == (int)(cur_y)) && ((int)(x3) == (int)(x2))) { ftinfo->len += ecsi(&ftinfo->buf, (int)(x1-cur_x)); ftinfo->len += ecsi(&ftinfo->buf, (int)(x2-x1)); ftinfo->len += ecsi(&ftinfo->buf, (int)(y2-y1)); ftinfo->len += ecsi(&ftinfo->buf, (int)(y3-y2)); ftinfo->len += csc(&ftinfo->buf, T1_HVCURVETO); } /* vertical to horizontal curve */ else if (((int)(x1) == (int)(cur_x)) && ((int)(y3) == (int)(y2))) { ftinfo->len += ecsi(&ftinfo->buf, (int)(y1-cur_y)); ftinfo->len += ecsi(&ftinfo->buf, (int)(x2-x1)); ftinfo->len += ecsi(&ftinfo->buf, (int)(y2-y1)); ftinfo->len += ecsi(&ftinfo->buf, (int)(x3-x2)); ftinfo->len += csc(&ftinfo->buf, T1_VHCURVETO); } else { ftinfo->len += ecsi(&ftinfo->buf, (int)(x1-cur_x)); ftinfo->len += ecsi(&ftinfo->buf, (int)(y1-cur_y)); ftinfo->len += ecsi(&ftinfo->buf, (int)(x2-x1)); ftinfo->len += ecsi(&ftinfo->buf, (int)(y2-y1)); ftinfo->len += ecsi(&ftinfo->buf, (int)(x3-x2)); ftinfo->len += ecsi(&ftinfo->buf, (int)(y3-y2)); ftinfo->len += csc(&ftinfo->buf, T1_RRCURVETO); } ftinfo->cur_x = x3; ftinfo->cur_y = y3; ftinfo->elm_cnt++; return 0; } static FT_Outline_Funcs ft_outline_funcs = { moveto, lineto, conicto, cubicto, 0, 0 }; FT_Error FT2GlyphToType1CharString(nsIFreeType2 *aFt2, FT_Face aFace, PRUint32 aGlyphID, int aWmode, int aLenIV, unsigned char *aBuf) { int j; FT_Int32 flags = FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING; FT_GlyphSlot slot; unsigned char *start = aBuf; FT2PT1_info fti; nsresult rv; rv = aFt2->LoadGlyph(aFace, aGlyphID, flags); if (NS_FAILED(rv)) { NS_ERROR("failed to load aGlyphID"); return 1; } slot = aFace->glyph; if (slot->format != ft_glyph_format_outline) { NS_ERROR("aGlyphID is not an outline glyph"); return 1; } fti.ft2 = aFt2; fti.face = aFace; fti.buf = aBuf; fti.elm_cnt = 0; fti.len = 0; fti.wmode = aWmode; /* add space for "random" bytes */ for (j=0; j< aLenIV; j++) { fti.len += ecsi(&fti.buf, 0); } rv = aFt2->OutlineDecompose(&slot->outline, &ft_outline_funcs, &fti); if (NS_FAILED(rv)) { NS_ERROR("error decomposing aGlyphID"); return 1; } if (fti.elm_cnt) { fti.len += csc(&fti.buf, T1_CLOSEPATH); fti.len += csc(&fti.buf, T1_ENDCHAR); } else { FT_Vector end_pt; end_pt.x = 0; end_pt.y = 1; /* dummy value to cause sbw instead of hsbw */ PRBool rslt = sideWidthAndBearing(&end_pt, &fti); if (rslt != PR_TRUE) { return 1; } fti.len += csc(&fti.buf, T1_ENDCHAR); } if (fti.buf) { Type1EncryptString(start, start, fti.len); } return fti.len; }