/* * VF_TT.c * * Programmmed by Hirotsugu Kakugawa, Hiroshima University * E-Mail: h.kakugawa@computer.org * * Edition History (VF_Zeit.c) * 2 Nov 1993 * 3 Nov 1993 Added sl, rx, ry, ox, oy, fx, fy capabilities. * 4 Nov 1993 Added ro capability. * 29 Dec 1993 Added VF_GetOutline(), VF_FreeOutline(). * * Edition History (VF_TT.c) * 19 Jan 1994 Modified for TrueType font by I. Matsuda. * 20 Jan 1994 Added GetOutline2() by H.Kakugawa. * 4 Mar 1994 Bug fix (outline size) by T. Shimizu. * 3 Feb 1995 Bug fix for left slant conversion by H.Kakugawa. * 6 May 1995 Changed to call VF_Draw() to draw outline by H.Kakugawa. * 6 May 1995 Dynamic Opening/Closing font file feature by H.Kakugawa. * 23 May 1995 Added range checking of char code. * 12 Dec 1995 Patches for fonts of Windows95 by I. Matsuda. * */ /* This file is part of VFlib * * Copyright (C) 1993-1998 Hirotsugu KAKUGAWA. All rights reserved. * * This file is part of the VFlib Library. This library is free * software; you can redistribute it and/or modify it under the terms of * the GNU Library General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your * option) any later version. This library is distributed in the hope * that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Library General Public License for more details. * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Capabilities interpretable by TrueType font objects: "ff" (str) -- Font file path (THIS IS NECESSARY) "fr" (bool) -- Frame font if defined "th" (bool) -- Thicken the char if defined "ro" (num) -- Rotate the char 90*n degrees in clockwise direction "rx" (bool) -- Reflect about x-axis if defined "ry" (bool) -- Reflect about y-axis if defined "sl" (num) -- Slant the char n/100 Corrrection Factors: "ox" (num) -- Offset for x-axis for vector font data (will be subtracted) "oy" (num) -- Offset for y-axis for vector font data (will be subtracted) "fx" (num) -- Factor for x-axis for vector font data "fy" (num) -- Factor for x-axis for vector font data Each point p0=(x0,y0) of vector font data is transformed in the following order: 1. subtracting `offset' : (x1,y1)=(x0-x_offset, y0-y_offset) 2. magnification by `factor': (x2,y2)=(x1*x_factor, y2*y_factor) 3. computation of the slant 3. rotation in clockwise direction 4. reflection about x-axis 5. reflection about y-axis */ #include #include #include #include #include #include "config.h" #include "defs.h" #include "_VF.h" #include "VF.h" #include "VFcap.h" /* * UNPACKING Constants */ #define ONCURVE 0x01 #define XSHORT 0x02 #define YSHORT 0x04 #define REPEAT_FLAGS 0x08 /* repeat flag n times */ /* IF XSHORT */ #define SHORT_X_IS_POS 0x10 /* the short vector is positive */ /* ELSE */ #define NEXT_X_IS_ZERO 0x10 /* the relative x coordinate is zero */ /* ENDIF */ /* IF YSHORT */ #define SHORT_Y_IS_POS 0x20 /* the short vector is positive */ /* ELSE */ #define NEXT_Y_IS_ZERO 0x20 /* the relative y coordinate is zero */ /* ENDIF */ /* 0x40 & 0x80 RESERVED ** Set to Zero ** */ #define D_RANGE 32768 #define D_SIZE 8192 #define D_OFFSET ((D_RANGE - D_SIZE) / 2) typedef char *BUFFER; typedef double floatp; typedef struct { int x, y; } Point; typedef struct { int num_cts; int num_pts; unsigned short *end_points; unsigned char *flags; short *xlist; short *ylist; } TTFont; typedef struct { unsigned short CodeTable; unsigned short MaxJIS; unsigned short unitsPerEm; short xMin; short yMin; unsigned short maxPoints; unsigned short maxContours; unsigned long IndexBase; unsigned long GlyphBase; } TT_Header; struct s_font { FILE_Port Fd1; FILE_Port Fd2; TT_Header ReadHeader; char *FontFileName; /* ff */ int Frame; /* fr */ int Thicken; /* th */ int Rotate; /* ro */ int XReflect; /* rx */ int YReflect; /* ry */ int Slant; /* sl */ int Xoffset; /* xo */ int Yoffset; /* yo */ int Xfactor; /* xf */ int Yfactor; /* yf */ }; typedef struct s_font Font; Private int OpenFont(); Private int CloseFont(); Private int GetBitmap(); Private long *GetOutline(); Private long *GetOutline2(); Private int DrawOutline(); Private int FreeOutline(); Private int Link(); Private int Unlink(); Private int ReadCapa(); Private void Transformation(); int VF_Draw(); Private int TTOpenFont(); Private int TTCloseFont(); Private TTFont *TTread_font(); Private void TTfree_font(); Private int TTread_header(); Private long TTread_long(); Private int TTread_short(); Private int TTseek(); Private int jis2c(); Public FontObj* CreateFont_TT(ent) char *ent; { Font *font; FontObj *fobj; if ((font = (Font*) malloc(sizeof(Font))) == NULL) return NULL; /* ERR: malloc err */ font->Fd1 = NULL_PORT; font->Fd2 = NULL_PORT; if (ReadCapa(font, ent) < 0){ free(font); return NULL; } fobj = (FontObj*) malloc(sizeof(FontObj)); fobj->ClassID = VF_FONT_TT; fobj->Self = fobj; fobj->LinkCount = 0; fobj->OpenFont = OpenFont; fobj->CloseFont = CloseFont; fobj->GetBitmap = GetBitmap; fobj->GetOutline = GetOutline; fobj->GetOutline2 = GetOutline2; fobj->DrawOutline = DrawOutline; fobj->FreeOutline = FreeOutline; fobj->GetCharSet = NULL; fobj->GetEnc = NULL; fobj->Link = Link; fobj->Unlink = Unlink; fobj->Locals = (long) font; return fobj; } Private int OpenFont(obj) FontObj *obj; { return TTOpenFont((Font*) obj->Locals); } Private int CloseFont(obj) FontObj *obj; { return TTCloseFont((Font*) obj->Locals); } Private int GetBitmap(obj, jiscode, w, h, bw, bo, bm_buf) FontObj *obj; int jiscode; int w; int h; int bw; int bo; char *bm_buf; { int val; long *vfdata; if ((vfdata = GetOutline(obj, jiscode)) == NULL) return -1; val = DrawOutline(obj, vfdata, w, h, bw, bo, bm_buf); FreeOutline(obj, vfdata); return val; } Private long* GetOutline(obj, jiscode) FontObj *obj; int jiscode; { long *vfdata, *vfp; int vfsize; Font *fobj; TTFont *fontptr; int ct, pt, sp, ep, p1, p2, p3; float x1, y1, x2, y2, x3, y3, UPE; long token; #define ConvX(x) \ ((unsigned int)(OUTLINE_OFFSET+((float)((x)*OUTLINE_SIZE)/UPE))) #define ConvY(y) \ ((unsigned int)(OUTLINE_OFFSET+((float)((y)*OUTLINE_SIZE)/UPE))) if (jiscode == 0x2121){ if ((vfdata = (long*)malloc(3*sizeof(long))) == (long*)NULL) return NULL; vfdata[0] = (long) jiscode; vfdata[1] = (long) VF_SONY_COORDINATES; vfdata[2] = (long) 0; return (long*) vfdata; } fobj = (Font*) obj->Locals; UPE = fobj->ReadHeader.unitsPerEm; if((fontptr = TTread_font(fobj, jiscode)) == NULL) return NULL; vfsize = 0; ep = -1; for (ct = 0; ct < fontptr->num_cts; ct++) { token = 0; sp = ep + 1; ep = fontptr->end_points[ct]; for (pt = sp; pt <= ep; pt++) { p1 = pt; p2 = (p1 < ep)? (p1 + 1) : sp; if (fontptr->flags[p1] & fontptr->flags[p2] & ONCURVE) { /* line */ if (token != VFD_LINE) { token = VFD_LINE; vfsize ++; } vfsize += 1; } else { if (fontptr->flags[p2] & ONCURVE) continue; /* spline */ if (token != VFD_BEZ) { token = VFD_BEZ; vfsize ++; } vfsize += 3; } } } if ((vfdata = (long*)malloc((vfsize + 3)*sizeof(long))) == (long*)NULL) return NULL; vfdata[0] = (long) jiscode; vfdata[1] = (long) VF_SONY_COORDINATES; vfp = &vfdata[2]; ep = -1; for (ct = 0; ct < fontptr->num_cts; ct++) { token = (VFD_CHAR | VFD_CWCURV); sp = ep + 1; ep = fontptr->end_points[ct]; for (pt = sp; pt <= ep; pt++) { p1 = pt; p2 = (p1 < ep)? (p1 + 1) : sp; p3 = (p2 < ep)? (p2 + 1) : sp; if (fontptr->flags[p1] & fontptr->flags[p2] & ONCURVE) { /* line */ if (token != VFD_LINE) { if (token == (VFD_CHAR | VFD_CWCURV)) { *(vfp++) = token | VFD_LINE; } else { *(vfp++) = VFD_LINE; } token = VFD_LINE; } x1 = fontptr->xlist[p1]; y1 = fontptr->ylist[p1]; *(vfp++) = VFD_MAKE_XY(ConvX(x1), ConvY(y1)); } else { if (fontptr->flags[p2] & ONCURVE) continue; /* spline */ if (token != VFD_BEZ) { if (token == (VFD_CHAR | VFD_CWCURV)) { *(vfp++) = token | VFD_BEZ; } else { *(vfp++) = VFD_BEZ; } token = VFD_BEZ; } if (fontptr->flags[p1] & ONCURVE) { x1 = (float)fontptr->xlist[p1]; y1 = (float)fontptr->ylist[p1]; } else { x1 = (float)(fontptr->xlist[p1] + fontptr->xlist[p2]) / 2.0; y1 = (float)(fontptr->ylist[p1] + fontptr->ylist[p2]) / 2.0; } x2 = (float)fontptr->xlist[p2]; y2 = (float)fontptr->ylist[p2]; if (fontptr->flags[p3] & ONCURVE) { x3 = (float)fontptr->xlist[p3]; y3 = (float)fontptr->ylist[p3]; } else { x3 = (float)(fontptr->xlist[p2] + fontptr->xlist[p3]) / 2.0; y3 = (float)(fontptr->ylist[p2] + fontptr->ylist[p3]) / 2.0; } /* spline -> bezier */ *(vfp++) = VFD_MAKE_XY(ConvX(x1), ConvY(y1)); *(vfp++) = VFD_MAKE_XY(ConvX((x1 + 2.0*x2) / 3.0), ConvY((y1 + 2.0*y2) / 3.0)); *(vfp++) = VFD_MAKE_XY(ConvX((2.0*x2 + x3) / 3.0), ConvY((2.0*y2 + y3) / 3.0)); } } } *(vfp++) = (long)0; TTfree_font(fontptr); Transformation(&vfdata[2], fobj); return (long*) vfdata; } Private long* GetOutline2(obj, jiscode) FontObj *obj; int jiscode; { return NULL; /* NOT IMPLEMENTED */ } Private int DrawOutline(obj, vfdata, w, h, bw, bo, bm_buf) FontObj *obj; long *vfdata; int w; int h; int bw; int bo; char *bm_buf; { Font *font; unsigned char *buff, d; int rast, x, y, yy1, yy2, val, frame; int thin; font = (Font*) obj->Locals; rast = (w+7)/8; if ((buff = (unsigned char*) malloc(h*rast)) == NULL) return -1; /* ERR: malloc err */ bzero(buff, rast*h); switch (font->Thicken){ case 1: thin = 30; break; case 0: default: thin = 0; break; } switch (font->Frame){ case 1: frame = 1; break; case 0: default: frame = 0; break; } if ((val = VF_Draw(vfdata, w, h, rast, buff, thin, frame)) < 0){ free(buff); return -1; } yy1 = 0; yy2 = 0; for (y = 0; y < h; y++){ for (x = 0; x < rast; x++){ d = buff[yy2 + x]; bm_buf[yy1 + x] |= d >> bo; bm_buf[yy1 + x+1] |= d << (8-bo); } yy1 += bw; yy2 += rast; } free(buff); return 0; } Private int FreeOutline(obj, vfdata) FontObj *obj; long *vfdata; { free(vfdata); return 0; } Private int Link(obj) FontObj *obj; { obj->LinkCount = obj->LinkCount + 1; return obj->LinkCount; } Private int Unlink(obj) FontObj *obj; { obj->LinkCount = obj->LinkCount - 1; return obj->LinkCount; } Private int ReadCapa(font, ent) Font *font; char *ent; { char *p; font->Thicken = 0; font->Frame = 0; font->Slant = 0; font->Rotate = 0; font->XReflect = 0; font->YReflect = 0; font->Xoffset = 0; font->Yoffset = 0; font->Xfactor = 100; font->Yfactor = 100; VFC_GetEntry(ent); if (VFC_IsDefined(VFCE_THICKEN)) font->Thicken = 1; if (VFC_IsDefined(VFCE_FRAME)) font->Frame = 1; if ((font->Slant = VFC_GetNumber(VFCE_SLANT)) == -1) font->Slant = 0; if ((font->Rotate = VFC_GetNumber(VFCE_ROTATE)) == -1) font->Rotate = 0; if (VFC_IsDefined(VFCE_REF_X)) font->XReflect = 1; if (VFC_IsDefined(VFCE_REF_Y)) font->YReflect = 1; if ((font->Xoffset = VFC_GetNumber(VFCE_XOFFSET)) == -1) font->Xoffset = 0; if ((font->Yoffset = VFC_GetNumber(VFCE_YOFFSET)) == -1) font->Yoffset = 0; if ((font->Xfactor = VFC_GetNumber(VFCE_XFACTOR)) == -1) font->Xfactor = 100; if ((font->Yfactor = VFC_GetNumber(VFCE_YFACTOR)) == -1) font->Yfactor = 100; if ((p = VFC_GetString(VFCE_FONT_FILE)) == NULL) return -1; if ((font->FontFileName = malloc(strlen(p)+1)) == NULL) return -1; /* ERR: malloc err */ strcpy(font->FontFileName, p); return 0; } Private void Transformation(vfdata, fobj) long *vfdata; Font *fobj; { double t1, t2, t3, t4, t5, t6, sl; double tmp_x, tmp_y, xfact, yfact; int x, y, x2, y2, xoffset, yoffset; long *vfp; if (vfdata == NULL){ fprintf(stderr, "NULL OUTLINE DATA [in Transformation() / VF_TT.c]\n"); abort(); } /* Slant */ sl = fobj->Slant/100.0; if (sl < 0.0){ t1 = 1.0+sl; t2 = -sl; t3 =0.0; t4 = 0.0; t5 = 1.0; t6 = 0.0; } else { t1 = 1.0-sl; t2 = -sl; t3 = sl; t4 = 0.0; t5 = 1.0; t6 = 0.0; } xfact = (double)(fobj->Xfactor)/100.0; yfact = (double)(fobj->Yfactor)/100.0; xoffset = D_OFFSET + fobj->Xoffset; yoffset = D_OFFSET + fobj->Yoffset; for (vfp = vfdata; *vfp != (long)0; vfp++){ if ((*vfp & VFD_TOKEN) == (long)0){ tmp_x = xfact * (double)(VFD_GET_X(*vfp) - xoffset); tmp_y = yfact * (double)(VFD_GET_Y(*vfp) - yoffset); /* slant */ x = (int)(t1 * tmp_x + t2 * tmp_y + t3 * D_SIZE); y = (int)(t4 * tmp_x + t5 * tmp_y + t6 * D_SIZE); /* rotate */ switch (fobj->Rotate % 4){ default: case 0: x2 = x; y2 = y; break; case 1: x2 = D_SIZE-y; y2 = x; break; case 2: x2 = D_SIZE-x; y2 = D_SIZE-y; break; case 3: x2 = y; y2 = D_SIZE-x; break; } if (x2 < 0) x2 = 0; if (x2 >= D_SIZE) x2 = D_SIZE; if (y2 < 0) y2 = 0; if (y2 >= D_SIZE) y2 = D_SIZE; x2 += D_OFFSET; y2 += D_OFFSET; /* reflect x, y */ if (fobj->XReflect == 1) x2 = D_RANGE - x2; if (fobj->YReflect == 1) y2 = D_RANGE - y2; *vfp = VFD_MAKE_XY(x2, y2); } } } /*************************************************** * TrueType Font Access Routines * by I.Matsuda **************************************************/ Private int TTOpenFont(fobj) Font* fobj; { FILE_Port wfd1, wfd2; TT_Header header; char *the_name, *fn, *ext; if ((the_name = malloc(strlen(fobj->FontFileName)+1)) == NULL) return -1; /* ERR: malloc err */ if ((fn = malloc(strlen(fobj->FontFileName)+10)) == NULL){ free(the_name); return -1; /* ERR: malloc err */ } strcpy(the_name, fobj->FontFileName); strcpy(fn, fobj->FontFileName); ext = fn + strlen(fn); strcpy(ext, ".ttf"); if ((wfd1 = VFFM_Intern(fn, NULL, NULL)) == NULL_PORT){ strcpy(ext, ".ttc"); if ((wfd1 = VFFM_Intern(fn, NULL, NULL)) == NULL_PORT){ free(fn); free(the_name); return -1; } } strcpy(ext, ".tti"); if ((wfd2 = VFFM_Intern(fn, NULL, NULL)) == NULL_PORT){ free(fn); free(the_name); return -1; } free(fn); TTread_header(wfd2, &header); fobj->FontFileName = the_name; fobj->Fd1 = wfd1; fobj->Fd2 = wfd2; fobj->ReadHeader = header; return 0; } Private int TTCloseFont(fobj) Font *fobj; { if (fobj->FontFileName == NULL) return -1; free(fobj->FontFileName); fobj->FontFileName = NULL; VFFM_UnIntern(fobj->Fd1); fobj->Fd1 = NULL_PORT; VFFM_UnIntern(fobj->Fd2); fobj->Fd2 = NULL_PORT; return 0; } Private int TTread_header(fport, hptr) FILE_Port fport; TT_Header *hptr; { FILE *fp; fp = VFFM_FStream(fport); fseek(fp, 0, 0); hptr->CodeTable = TTread_short(fp); hptr->MaxJIS = TTread_short(fp); hptr->unitsPerEm = TTread_short(fp); hptr->xMin = TTread_short(fp); hptr->yMin = TTread_short(fp); hptr->maxPoints = TTread_short(fp); hptr->maxContours = TTread_short(fp); hptr->IndexBase = TTread_long(fp); hptr->GlyphBase = TTread_long(fp); return 0; } Private TTFont* TTread_font(fobj, code) Font *fobj; int code; { static TTFont ttfont; int code_offset; int i, j, UPE; short cp; FILE *fp; code_offset = jis2c(code); if ((code < 0x2122) || (0x7c7e < code)){ return NULL; } if ((code >> 8) - 0x21 >= fobj->ReadHeader.MaxJIS) return NULL; if (TTseek(fobj, code_offset) < 0) return NULL; fp = VFFM_FStream(fobj->Fd1); UPE = fobj->ReadHeader.unitsPerEm; ttfont.num_cts = TTread_short(fp); /* number of contours */ if (ttfont.num_cts > fobj->ReadHeader.maxContours) return NULL; /* error check */ fseek(fp, 8, 1); /* ignore 8 bytes */ if ((ttfont.end_points = (unsigned short *) malloc(sizeof(short) * ttfont.num_cts)) == NULL) return NULL; for (i = 0; i < ttfont.num_cts; i++) { ttfont.end_points[i] = TTread_short(fp); } ttfont.num_pts = ttfont.end_points[ttfont.num_cts - 1] + 1; if (ttfont.num_pts > fobj->ReadHeader.maxPoints) return NULL; /* error check */ i = TTread_short(fp); fseek(fp, i, 1); /* ignore instruction code */ if ((ttfont.flags = (unsigned char *) malloc(sizeof(char) * ttfont.num_pts)) == NULL) return NULL; if ((ttfont.xlist = (short *) malloc(sizeof(short) * ttfont.num_pts)) == NULL) return NULL; if ((ttfont.ylist = (short *) malloc(sizeof(short) * ttfont.num_pts)) == NULL) return NULL; /* read flags */ for (i = 0; i < ttfont.num_pts; i++) { ttfont.flags[i] = getc(fp); if (ttfont.flags[i] & REPEAT_FLAGS) { for (j = (unsigned char)getc(fp); j > 0; j--, i++) { ttfont.flags[i + 1] = ttfont.flags[i]; } } } /* read x_list */ cp = -fobj->ReadHeader.xMin; for (i = 0; i < ttfont.num_pts; i++) { if (ttfont.flags[i] & XSHORT) { if (ttfont.flags[i] & SHORT_X_IS_POS) { cp += (unsigned char)getc(fp); } else { cp -= (unsigned char)getc(fp); } } else { if (!(ttfont.flags[i] & NEXT_X_IS_ZERO)) { cp += TTread_short(fp); } } ttfont.xlist[i] = cp; } /* read y_list */ cp = -fobj->ReadHeader.yMin; for (i = 0; i < ttfont.num_pts; i++) { if (ttfont.flags[i] & YSHORT) { if (ttfont.flags[i] & SHORT_Y_IS_POS) { cp += (unsigned char)getc(fp); } else { cp -= (unsigned char)getc(fp); } } else { if (!(ttfont.flags[i] & NEXT_Y_IS_ZERO)) { cp += TTread_short(fp); } } ttfont.ylist[i] = UPE - cp; } #if 0 for (i = j = 0; i < ttfont.num_pts; i++) { printf("!%3d %s(%d, %d)\n", i, (ttfont.flags[i] & ONCURVE)? "*" : " ", ttfont.xlist[i], ttfont.ylist[i]); if (i == ttfont.end_points[j]) { j++; printf("--------\n"); } } #endif return (&ttfont); } Private void TTfree_font(ptr) TTFont *ptr; { free(ptr->end_points); free(ptr->flags); free(ptr->xlist); free(ptr->ylist); } Private long TTread_long(fp) FILE *fp; { long num; short c[2]; c[0] = TTread_short(fp); c[1] = TTread_short(fp); num = ((long)c[0] << 16) | (c[1] & 0xffff); return (num); } Private int TTread_short(fp) FILE *fp; { char c[2]; short num; c[0] = getc(fp); c[1] = getc(fp); num = (c[0] << 8) | (c[1] & 0xff); return (num); } Private int TTseek(fobj, code_offset) Font *fobj; int code_offset; { unsigned short gindex; unsigned long glyph_offset; FILE *fd1, *fd2; /* code_offset -> glyph index */ fd2 = VFFM_FStream(fobj->Fd2); fseek(fd2, fobj->ReadHeader.CodeTable + code_offset * 2L, 0); if((gindex = TTread_short(fd2)) == 0) return (-1); /* no glyph index */ /* glyph index -> offset */ fd1 = VFFM_FStream(fobj->Fd1); fseek(fd1, fobj->ReadHeader.IndexBase + gindex * 4L, 0); glyph_offset = TTread_long(fd1); /* seek to glyph data */ fseek(fd1, fobj->ReadHeader.GlyphBase + glyph_offset, 0); return (0); } Private int jis2c(code) int code; { int zscode; zscode = (((code >> 8) & 0xff) - 0x21) * 0x5e + (code & 0xff) - 0x21; return zscode; } /* EOF */