/* Copyright (c) 2003-2004 Roland Mainz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include #include #include "os.h" #define USE_PSOUT_PRIVATE 1 #include "psout.h" #include #include FT_FREETYPE_H #include FT_TRUETYPE_TABLES_H #include FT_BBOX_H #include FT_GLYPH_H #include FT_CONFIG_CONFIG_H #include FT_CONFIG_OPTIONS_H #include FT_ERRORS_H #include FT_SYSTEM_H #include FT_IMAGE_H #include FT_TYPES_H #include FT_OUTLINE_H #include FT_MODULE_H #include FT_RENDER_H #include FT_TYPE1_TABLES_H #include FT_TRUETYPE_IDS_H #include FT_TRUETYPE_TAGS_H #include FT_CACHE_H #include FT_CACHE_IMAGE_H #include FT_CACHE_SMALL_BITMAPS_H #include FT_MULTIPLE_MASTERS_H #include FT_SFNT_NAMES_H #include #include #include #include #include #include #include #define NOT_IN_FTFUNCS #include struct ft2info { FontPtr pFont; FTFontPtr tf; FT_Face ttface; struct { char *full_name; char *copyright; char *family; char *subfamily; char *version; } nameid; TT_Postscript *ttpostscript; TT_Header *ttheader; }; /* Local prototypes */ static FT_Error PSType3_createOutlineGlyphs(FILE *out, struct ft2info *ti, unsigned long unicode, const char *psglyphname); static int PSType3_generateOutlineFont(FILE *out, const char *psfontname, struct ft2info *ti, long block_offset); extern FT_Library ftypeLibrary; /* defined in xc/lib/font/FreeType/ftfuncs.c */ #define USE_FT_PS_NAMES 1 static FT_Error PSType3_createOutlineGlyphs( FILE *out, struct ft2info *ti, unsigned long x11fontindex, const char *psglyphname ) { unsigned long ftindex; FT_BBox bbox; FT_Error error; FT_Outline outline; /* Remap X11 font index to FreeType font index */ ftindex = FTRemap(ti->ttface, &ti->tf->mapping, x11fontindex); error = FT_Load_Glyph(ti->ttface, ftindex, (FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING)); if( error ) { fprintf(stderr, "PSType3_createOutlineGlyphs: FT_Load_Glyph() failure, error=%d\n", (int)error); return error; } outline = ti->ttface->glyph->outline; FT_Outline_Get_CBox(&outline, &bbox); fprintf(out, "/%s {\n", psglyphname); fprintf(out, "%ld 0 %ld %ld %ld %ld setcachedevice\n", (signed long)ti->ttface->glyph->metrics.horiAdvance, (long)bbox.xMin, (long)bbox.yMin, (long)bbox.xMax, (long)bbox.yMax); if( outline.n_contours > 0 ) { long i, j, k, k1, cs, ce, nguide, contour_start, contour_end, last_point; Bool first; FT_Vector *vec; contour_start = ce = 0; vec = outline.points; last_point = outline.n_points; i = j = k = 0; first = TRUE; while( i <= outline.contours[outline.n_contours - 1] ) { contour_end = outline.contours[j]; if( first ) { fprintf(out, "%ld %ld moveto\n", vec[i].x, vec[i].y); contour_start = i; first = FALSE; } else if( outline.tags[i] & FT_CURVE_TAG_ON ) { fprintf(out, "%ld %ld lineto\n", vec[i].x, vec[i].y); } else { Bool finished = FALSE; cs = i-1; nguide = 0; while( !finished ) { if( i == contour_end+1 ) { ce = contour_start; finished = TRUE; } else if( outline.tags[i] & FT_CURVE_TAG_ON ) { ce = i; finished = TRUE; } else { i++; nguide++; } } switch( nguide ) { case 0: fprintf(out, "%ld %ld lineto\n", vec[ce].x, vec[ce].y); break; case 1: fprintf(out, "%ld %ld %ld %ld %ld %ld curveto\n", (vec[cs].x+2*vec[cs+1].x)/3, (vec[cs].y+2*vec[cs+1].y)/3, (2*vec[cs+1].x+vec[ce].x)/3, (2*vec[cs+1].y+vec[ce].y)/3, vec[ce].x, vec[ce].y); break; case 2: fprintf(out, "%ld %ld %ld %ld %ld %ld curveto\n", (-vec[cs].x+4*vec[cs+1].x)/3, (-vec[cs].y+4*vec[cs+1].y)/3, (4*vec[cs+2].x-vec[ce].x)/3, (4*vec[cs+2].y-vec[ce].y)/3, vec[ce].x, vec[ce].y); break; case 3: fprintf(out, "%ld %ld %ld %ld %ld %ld curveto\n", (vec[cs].x+2*vec[cs+1].x)/3, (vec[cs].y+2*vec[cs+1].y)/3, (5*vec[cs+1].x+vec[cs+2].x)/6, (5*vec[cs+1].y+vec[cs+2].y)/6, (vec[cs+1].x+vec[cs+2].x)/2, (vec[cs+1].y+vec[cs+2].y)/2); fprintf(out, "%ld %ld %ld %ld %ld %ld curveto\n", (vec[cs+1].x+5*vec[cs+2].x)/6, (vec[cs+1].y+5*vec[cs+2].y)/6, (5*vec[cs+2].x+vec[cs+3].x)/6, (5*vec[cs+2].y+vec[cs+3].y)/6, (vec[cs+3].x+vec[cs+2].x)/2, (vec[cs+3].y+vec[cs+2].y)/2); fprintf(out, "%ld %ld %ld %ld %ld %ld curveto\n", (vec[cs+2].x+5*vec[cs+3].x)/6, (vec[cs+2].y+5*vec[cs+3].y)/6, (2*vec[cs+3].x+vec[ce].x)/3, (2*vec[cs+3].y+vec[ce].y)/3, vec[ce].x, vec[ce].y); break; default: /* anything |nguide > 3| */ k1 = cs + nguide; fprintf(out, "%ld %ld %ld %ld %ld %ld curveto\n", (vec[cs].x+2*vec[cs+1].x)/3, (vec[cs].y+2*vec[cs+1].y)/3, (5*vec[cs+1].x+vec[cs+2].x)/6, (5*vec[cs+1].y+vec[cs+2].y)/6, (vec[cs+1].x+vec[cs+2].x)/2, (vec[cs+1].y+vec[cs+2].y)/2); for( k = cs+2 ; k <= k1-1 ; k++ ) { fprintf(out, "%ld %ld %ld %ld %ld %ld curveto\n", (vec[k-1].x+5*vec[k].x)/6, (vec[k-1].y+5*vec[k].y)/6, (5*vec[k].x+vec[k+1].x)/6, (5*vec[k].y+vec[k+1].y)/6, (vec[k].x+vec[k+1].x)/2, (vec[k].y+vec[k+1].y)/2); } fprintf(out, "%ld %ld %ld %ld %ld %ld curveto\n", (vec[k1-1].x+5*vec[k1].x)/6, (vec[k1-1].y+5*vec[k1].y)/6, (2*vec[k1].x+vec[ce].x)/3, (2*vec[k1].y+vec[ce].y)/3, vec[ce].x, vec[ce].y); break; } } if( i >= contour_end ) { fprintf(out, "closepath\n"); first = TRUE; i = contour_end + 1; j++; } else { i++; } } } fprintf(out, "fill } bind def\n"); return 0; } static int PSType3_generateOutlineFont(FILE *out, const char *psfontname, struct ft2info *ti, long block_offset) { long i; double scaler; const int numchars = 256; #ifdef USE_FT_PS_NAMES int linewidth = 0; #endif /* USE_FT_PS_NAMES */ fprintf(out, "%%%%BeginFont: %s\n", psfontname); fprintf(out, "22 dict begin\n"); fprintf(out, "/FontType 3 def\n"); fprintf(out, "/StrokeWidth 0 def\n"); fprintf(out, "/PaintType 0 def\n"); fprintf(out, "/FontName (%s) def\n", psfontname); fprintf(out, "/FontInfo 9 dict dup begin\n"); fprintf(out, " /FullName (%s) def\n", ti->nameid.full_name?ti->nameid.full_name:psfontname); fprintf(out, " /Notice (%s) def\n", ti->nameid.copyright?ti->nameid.copyright:"nothing here"); fprintf(out, " /FamilyName (%s) def\n", ti->nameid.family?ti->nameid.family:psfontname); fprintf(out, " /Weight (%s) def\n", ti->nameid.subfamily?ti->nameid.subfamily:"Regular"); fprintf(out, " /version (%s) def\n", ti->nameid.version?ti->nameid.version:"0.1"); if( ti->ttpostscript ) { fprintf(out, " /italicAngle %.9g def\n", (double)ti->ttpostscript->italicAngle); fprintf(out, " /underlineThickness %d def\n", (int)ti->ttpostscript->underlineThickness); fprintf(out, " /underlinePosition %d def\n", (int)ti->ttpostscript->underlinePosition); fprintf(out, " /isFixedPitch %s def\n", ((ti->ttpostscript->isFixedPitch)?("true"):("false"))); } else { fprintf(out, " /italicAngle %.9g def\n", 0.0); fprintf(out, " /underlineThickness %d def\n", 100); fprintf(out, " /underlinePosition %d def\n", 0); fprintf(out, " /isFixedPitch false def\n"); } fprintf(out, "end def\n"); scaler = (1000.0 / (double)ti->ttface->units_per_EM) / 1000.0; fprintf(out, "/FontMatrix [%.9g 0 0 %.9g 0 0] def\n", scaler, scaler); if( ti->ttheader ) { fprintf(out, "/FontBBox [%d %d %d %d] def\n", (int)ti->ttheader->xMin, (int)ti->ttheader->yMin, (int)ti->ttheader->xMax, (int)ti->ttheader->yMax); } else { fprintf(out, "/FontBBox [%ld %ld %ld %ld] def\n", ti->ttface->bbox.xMin, ti->ttface->bbox.yMin, ti->ttface->bbox.xMax, ti->ttface->bbox.yMax); } fprintf(out, "/Encoding [\n"); for( i = 0 ; i < 256 ; i++ ) { #ifdef USE_FT_PS_NAMES char namebuf[256]; PsOut_Get_FreeType_Glyph_Name(namebuf, ti->pFont, i+block_offset); linewidth += strlen(namebuf) + 2; fprintf(out, "/%s%s", namebuf, (linewidth > 70)?(linewidth = 0, "\n"):(" ")); #else fprintf(out, "/ch%02x%s", i, (((i % 10) == 9)?("\n"):(" "))); #endif /* USE_FT_PS_NAMES */ } fprintf(out, "] def\n"); fprintf(out, "/CharProcs %d dict def CharProcs begin\n", (int)(numchars + 1)); fprintf(out, "/.notdef {\n" "1000 0 0 0 0 0 setcachedevice\n" "fill } bind def\n"); for( i = 0 ; i < numchars ; i++ ) { char buf[32]; #ifdef USE_FT_PS_NAMES char namebuf[256]; PsOut_Get_FreeType_Glyph_Name(namebuf, ti->pFont, i+block_offset); sprintf(buf, "%s ", namebuf); #else sprintf(buf, "ch%02lx ", i); #endif /* USE_FT_PS_NAMES */ PSType3_createOutlineGlyphs(out, ti, i+block_offset, buf); } fprintf(out, "end\n" "/BuildGlyph {\n" " exch /CharProcs get exch\n" " 2 copy known not {pop /.notdef} if get exec } bind def\n" "/BuildChar { 1 index /Encoding get exch get\n" " 1 index /Encoding get exec } bind def\n"); fprintf(out, "currentdict end /%s exch definefont pop\n", psfontname); fprintf(out, "%%EndFont\n"); return 0; } static char *FT_Get_TT_NAME_ID(FT_Face ttface, int index) { FT_SfntName name; char *s; if( index >= FT_Get_Sfnt_Name_Count(ttface) ) return NULL; FT_Get_Sfnt_Name(ttface, index, &name); s = (char *)malloc(name.string_len+2); if( !s ) return NULL; memcpy(s, (char *)name.string, name.string_len); s[name.string_len] = '\0'; return s; } int PsOut_DownloadFreeType3(PsOutPtr self, const char *psfontname, FontPtr pFont, long block_offset) { struct ft2info cft2info = { 0 }; struct ft2info *ti = &cft2info; S_Flush(self); ti->tf = (FTFontPtr)pFont->fontPrivate; ti->ttface = ti->tf->instance->face->face; ti->pFont = pFont; #ifdef DEBUG_gisburn fprintf(stderr, "# Downloading FT2 font filename='%s', ttface=%lx\n", ti->tf->instance->face->filename, (long)ti->ttface); #endif /* DEBUG_gisburn */ ti->nameid.full_name = FT_Get_TT_NAME_ID(ti->ttface, TT_NAME_ID_FULL_NAME); ti->nameid.copyright = FT_Get_TT_NAME_ID(ti->ttface, TT_NAME_ID_COPYRIGHT); ti->nameid.family = FT_Get_TT_NAME_ID(ti->ttface, TT_NAME_ID_FONT_FAMILY); ti->nameid.subfamily = FT_Get_TT_NAME_ID(ti->ttface, TT_NAME_ID_FONT_SUBFAMILY); ti->nameid.version = FT_Get_TT_NAME_ID(ti->ttface, TT_NAME_ID_VERSION_STRING); ti->ttheader = (TT_Header *)FT_Get_Sfnt_Table(ti->ttface, ft_sfnt_head); ti->ttpostscript = (TT_Postscript *)FT_Get_Sfnt_Table(ti->ttface, ft_sfnt_post); PSType3_generateOutlineFont(self->Fp, psfontname, ti, block_offset); free(ti->nameid.full_name); free(ti->nameid.copyright); free(ti->nameid.family); free(ti->nameid.subfamily); free(ti->nameid.version); S_Flush(self); return 0; }