/* * VFlib.c - Vector font library Version 2 * * Programmmed by Hirotsugu Kakugawa, Hiroshima University * E-Mail: h.kakugawa@computer.org * * Edition History * 13 Mar 1993 Version 1 * 31 Oct 1993 Version 2 support of SONY Vector Fonts * 3 Nov 1993 Support of Zeit "Syotai Club" Fonts * 5 Nov 1993 Support of Compound Fonts * 28 Dec 1993 Added VF_GetOutline(), VF_DrawOutline(), VF_FreeOutline(). * 19 Jan 1994 Support of TrueType fonts. (by I. Matsuda) * 20 Jan 1994 Added VF_GetOutline2(). * 8 Mar 1994 Fixed small bugs and removed dead code * 11 Mar 1994 Added draw routine. * 25 May 1994 Changed default behavior when ptr to vfontcap file is null. * 10 May 1995 Added VF_ReserveBitmap(). * 13 Jun 1995 Added VF_libVFlib, VF_libVFlibd for VFlibd compatibility. * 17 Nov 1995 Added NULL font class. * 21 Dec 1995 Added X window BDF font class. * 19 Feb 1996 Changed return value of VF_CloseAllFonts from void to * integer. (WL) * 1 Apr 1996 Added HBF font class. (WL) * 20 Mar 1998 Added TrueType suport using FreeType library. */ /* 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. */ #include #include #include #include #include #include #include "config.h" #include "with.h" #include "defs.h" #include "_VF.h" #include "VF.h" #include "VFcap.h" /* global variable for controlling max # of open fonts */ Public int VF_MaxOpenFontFiles = MAX_OPEN_FONT_FILES; /* dummy variable for libVFlibd.a compatibility */ Public int VF_InitialRetryInterval = 0; Public int VF_MaxRetry = 0; /* for Stub Checking */ Const int VF_libVFlib = 1; Const int VF_libVFlibd = 0; static int VFlibInited = 0; Public FontTable FTable[MAX_FONTS]; /* needed in VFenc.c */ Public FontObj *CreateFont_Sony(); Public FontObj *CreateFont_Zeit(); Public FontObj *CreateFont_Jg(); Public FontObj *CreateFont_TT(); Public FontObj *CreateFont_Comp(); Public FontObj *CreateFont_BitOp(); Public FontObj *CreateFont_Bdf(); Public FontObj *CreateFont_Hbf(); Public FontObj *CreateFont_FreeType(); Public FontObj *CreateFont_FreeTypeGBK(); Public FontObj *CreateFont_FontWave(); Public FontObj *CreateFont_Null(); Public FontObj *CreateFont_Comp2(); static FontClassTable FCTable[] = { #ifdef WITH_SONY_FSLIB {"sony", VF_FONT_SONY, CreateFont_Sony}, #endif #ifdef WITH_FREETYPE {"freetype", VF_FONT_FREETYPE, CreateFont_FreeType}, {"freetype-gbk", VF_FONT_FREETYPE_GBK, CreateFont_FreeTypeGBK}, #endif {"zeit", VF_FONT_ZEIT, CreateFont_Zeit}, {"jg", VF_FONT_JG, CreateFont_Jg}, {"truetype", VF_FONT_TT, CreateFont_TT}, {"compound", VF_FONT_COMPOUND, CreateFont_Comp}, {"bitop", VF_FONT_BITOP, CreateFont_BitOp}, {"bdf", VF_FONT_BDF, CreateFont_Bdf}, {"hbf", VF_FONT_HBF, CreateFont_Hbf}, {"null", VF_FONT_NULLFONT, CreateFont_Null}, {"fontwave", VF_FONT_FONTWAVE, CreateFont_FontWave}, {"compound2", VF_FONT_COMPOUND2, CreateFont_Comp2}, {NULL, VF_FONT_NULL, NULL}, }; /* HOW TO ADD A NEW FONT CLASS: * 1. Add an entry in structure FCTable[] above. This is the only * modification you must do in this file. * 2. Add a definition of font class identity in _VF.h. * 3. Write a font driver (VF_XXX.c). * 4. Modify Makefile to link the new font driver. * 5. Add an entry for the new font class in vfontcap file. * That's it. It's easy, isn't it? */ Private FontObj *VF_CreateFontObj(); /* * VF_Init * --- Initialize VFlib. * * ARGUMENTS: * vfcap : A path name for vfontcap file. If it is null pointer, default * file is used. * RETURN VALUE (integer): * 0 : if succeeded. * -1 : if failed to initialize. (maybe, vfontcap is not found, or lack of * memory) */ int VF_Init(vfcap) char *vfcap; { int i; if (VFlibInited == 1){ return -1; /* ERR: re-initialization */ } /* if (vfcap == NULL) vfcap = DEFAULT_VFCAP; */ if (VFC_Init(vfcap) < 0) return -1; /* ERR: vfcap init err */ for (i = 0; i < MAX_FONTS; i++){ FTable[i].Fobj = (FontObj*) NULL; FTable[i].Fname = (char*) NULL; }; if (! VFFM_Init()) return -1; VFlibInited = 1; return 0; } /* * VF_Deinit * --- Finish using VFlib. * * ARGUMENTS: * none * RETURN VALUE (integer): * 0 : always succeeds. */ int VF_Deinit() { VF_CloseAllFonts(); VFC_Deinit(); if (! VFFM_Deinit()) return -1; VFlibInited = 0; return 0; } /* * VF_OpenFont * --- Open a new font entry. * * ARGUMENTS: * fontname : font entry name. * RETURN VALUE (integer): * -1 : if failed to open the font entry. * (non-negative integer) : font ID. This font ID is used to get bitmaps. * */ int VF_OpenFont(fontname) char *fontname; { int fid; char *ent; if (VFlibInited == 0) VF_Init(NULL); if ((ent = VF_Fontname2Entry(fontname)) == NULL){ return -1; /* ERR: ill font name */ } for (fid = 0; fid < MAX_FONTS; fid++){ if ((FTable[fid].Fobj != (FontObj*) NULL) && (strcmp(FTable[fid].Fentry, ent) == 0)){ VF_LinkFont(FTable[fid].Fobj); return fid; } } for (fid = 0; fid < MAX_FONTS; fid++){ if (FTable[fid].Fobj == (FontObj*) NULL){ if ((FTable[fid].Fentry = malloc(strlen(ent)+1)) == NULL){ return -1; /* ERR: malloc error */ } strcpy(FTable[fid].Fentry, ent); if ((FTable[fid].Fobj = VF_CreateFontObj(FTable[fid].Fentry)) == NULL){ free(FTable[fid].Fentry); return -1; /* ERR: no such entry (maybe) */ } if ((FTable[fid].Fname = malloc(strlen(fontname)+1)) == NULL){ free(FTable[fid].Fentry); return -1; /* ERR: malloc error */ } strcpy(FTable[fid].Fname, fontname); if ((FTable[fid].Fobj->OpenFont)(FTable[fid].Fobj) < 0){ free(FTable[fid].Fentry); free(FTable[fid].Fname); return -1; /* ERR: font not found (maybe) */ } VF_LinkFont(FTable[fid].Fobj); return fid; } } return -1; /* ERR: font table full */ } /* * VF_CloseFont * --- Close a font (specified by font ID) * * ARGUMENTS: * fid : A font ID to close. * RETURN VALUE (integer): * 0 : (always succeeds) */ int VF_CloseFont(fid) int fid; { if (FTable[fid].Fobj == (FontObj*) NULL) return 0; if (VF_UnlinkFont(FTable[fid].Fobj) == 0){ free(FTable[fid].Fentry); FTable[fid].Fentry = NULL; free(FTable[fid].Fname); FTable[fid].Fname = NULL; (*FTable[fid].Fobj->CloseFont)(FTable[fid].Fobj); FTable[fid].Fobj = (FontObj*) NULL; } return 0; } /* * VF_CloseAllFonts * --- Close all opened fonts. * * ARGUMENTS: * none * RETURN VALUE (integer): * 0 : (always succeeds) */ int VF_CloseAllFonts() { int fid; for (fid = 0; fid < MAX_FONTS; fid++){ if (FTable[fid].Fobj != (FontObj*) NULL) VF_CloseFont(fid); } return 0; } /* * VF_GetBitmap * --- Get a bitmap image for a character. * * ARGUMENTS: * jiscode : character code of wanted glyph. * fid : font ID. * w : width of bitmap. * h : height of bitmap. * bw : bytes per line of bitmap. * bo : bit offset of the generated bitmap image from left side. * bm_buf : a memory area to hold the generated bitmap. * RETURN VALUE (integer): * 0 : if successful * -1 : if error */ int VF_GetBitmap(jiscode, fid, w, h, bw, bo, bm_buf) int jiscode; int fid; int w; int h; int bw; int bo; char *bm_buf; { if (FTable[fid].Fobj == (FontObj*) NULL) return -1; /* ERR: ill fid */ if (FTable[fid].Fobj->GetBitmap == NULL) return -1; return (FTable[fid].Fobj->GetBitmap)(FTable[fid].Fobj, jiscode, w, h, bw, bo, bm_buf); } /* * VF_ReserveBitmap * --- Reserve a bitmap image for a character. * Stub function for libVFlibd.a. * * ARGUMENTS: * code : character code of wanted glyph. * fid : font ID. * w : width of bitmap. * h : height of bitmap. * bw : bytes per line of bitmap. * bo : bit offset of the generated bitmap image from left side. * bm_buf : a memory area that bitmap to be generated. * bm_buf : a memory area to hold the generated bitmap. * RETURN VALUE (integer): * 0 : if successful * -1 : if error */ int VF_ReserveBitmap(code, fid, w, h, bw, bo, bm_buf) int code; int fid; int w; int h; int bw; int bo; unsigned char *bm_buf; { /* Always returns 0 */ return 0; } Private FontObj* VF_CreateFontObj(ent) char *ent; { FontObj *obj; char *f_type; int i; if (VFC_GetEntry(ent) < 0) return NULL; if ((f_type = VFC_GetString(VFCE_FONT_TYPE)) == NULL) return NULL; /**printf("Entry:%s Font Type:%s\n", ent, f_type);**/ for (i = 0; FCTable[i].ClassName != NULL; i++) if (strcmp(FCTable[i].ClassName, f_type) == 0){ if ((obj = (FCTable[i].ObjCreater)(ent)) == NULL) return NULL; return obj; } return NULL; /* ERR: no interned font */ } /* * VF_GetOutline() * --- Get outline data of a character. * * ARGUMENTS: * jiscode : character code of wanted glyph. * fid : font ID * RETURN VALUE (pointer to long): * NULL : if failed to get outline. * otherwise, pointer to outline data. Use VF_DrawOutline() to generate * bitmap image from this outline data, and VF_FreeOutline() to * release memory allocated for outline data. */ long* VF_GetOutline(jiscode, fid) int jiscode; int fid; { if (FTable[fid].Fobj == (FontObj*) NULL) return NULL; if (FTable[fid].Fobj->GetOutline == NULL) return NULL; return (FTable[fid].Fobj->GetOutline)(FTable[fid].Fobj, jiscode); } /* * VF_GetOutline2() * --- Get outline data of a character in font dependent coordinates. * * ARGUMENTS: * jiscode : character code of wanted glyph. * fid : font ID * RETURN VALUE (pointer to long): * NULL : if failed to get outline. * otherwise, pointer to outline data. Use VF_DrawOutline() to generate * bitmap image from this outline data, and VF_FreeOutline() to * release memory allocated for outline data. */ long* VF_GetOutline2(jiscode, fid) int jiscode; int fid; { if (FTable[fid].Fobj == (FontObj*) NULL) return NULL; if (FTable[fid].Fobj->GetOutline2 == NULL) return NULL; return (FTable[fid].Fobj->GetOutline2)(FTable[fid].Fobj, jiscode); } /* * VF_DrawOutline() * --- Get bitmap image from outline data. * ARGUMENTS: * vfdata : outline data. * fid : font ID. * w : width of bitmap. * h : height of bitmap. * bw : bytes per line of bitmap. * bo : bit offset of the generated bitmap image from left side. * bm_buf : a memory area to hold the generated bitmap. * RETURN VALUE (integer): * 0 : if successful * -1 : if error */ int VF_DrawOutline(vfdata, fid, w, h, bw, bo, bm_buf) long *vfdata; int fid; int w; int h; int bw; int bo; char *bm_buf; { if (FTable[fid].Fobj == (FontObj*) NULL) return -1; if (FTable[fid].Fobj->DrawOutline == NULL) return -1; return (FTable[fid].Fobj->DrawOutline)(FTable[fid].Fobj, vfdata, w, h, bw, bo, bm_buf); } /* * VF_FreeOutline() * --- Release outline data allocated by VF_GetOutline(). * * ARGUMENTS: * vfdata : outline data allocated by VF_GetOutline(). * fid : font ID. * RETURN VALUE (integer): * 0 : if successful * -1 : if error */ int VF_FreeOutline(vfdata, fid) long *vfdata; int fid; { if (FTable[fid].Fobj == (FontObj*) NULL) return -1; if (FTable[fid].Fobj->FreeOutline == NULL) return -1; return (FTable[fid].Fobj->FreeOutline)(FTable[fid].Fobj, vfdata); } /* * VF_LinkFont() * --- (INTERNAL USE) Increment link count of font. */ int VF_LinkFont(obj) FontObj *obj; { return (obj->Link)(obj); } /* * VF_UnlinkFont() * --- (INTERNAL USE) Decrement link count of font. */ int VF_UnlinkFont(obj) FontObj *obj; { return (obj->Unlink)(obj); } /* * Draw routines for outline data * Snarfed from VF_TT.c by I. Matsuda. */ Private unsigned char* Vbuffer; Private int Vwidth; Private int Vheight; Private int Vmax_width; Private int Vmax_height; Private int Vrast; Private int Vthin; Private int Vframe; Private long ReadXY(); Private void DrawArc(), DrawBezier(); Private void fill_edges(), trace_outline(); /* * VF_Draw() * --- (INTERNAL USE) */ int VF_Draw(vfdata, w, h, bw, bm_buf, thin, frame) long *vfdata; int w, h, bw, thin, frame; unsigned char *bm_buf; { int x[4], y[4]; int func, func1; long *vfp, token; Private void (*DrawFuncTbl[])() = {fill_edges, trace_outline}; Vbuffer = bm_buf; Vwidth = w; Vheight = h; Vrast = bw; Vthin = thin; Vframe = frame; Vmax_width = OUTLINE_SIZE; Vmax_height = OUTLINE_SIZE; switch (Vframe){ case 1: func1 = 1; break; case 0: default: func1 = 0; break; } for (func = func1; func <= 1; func++){ vfp = &vfdata[2]; token = *vfp++; while (token != 0) { switch (token & (VFD_LINE | VFD_ARC | VFD_BEZ)) { case VFD_LINE: token = ReadXY(x, y, &vfp, token); DrawFuncTbl[func](x[0], y[0], x[1], y[1]); break; case VFD_ARC: token = ReadXY(x, y, &vfp, token); DrawArc(x, y, DrawFuncTbl[func]); break; case VFD_BEZ: token = ReadXY(x, y, &vfp, token); DrawBezier(x, y, DrawFuncTbl[func]); break; default: return (-1); } } } return 0; } Private long ReadXY(x, y, vfpp, token) int *x; int *y; long **vfpp; long token; { static int xbeg, ybeg; #define TOP_OF_SEGMENT(x) \ (((x) & VFD_CWCURV) == VFD_CWCURV || ((x) & VFD_CCWCURV) == VFD_CCWCURV) if (TOP_OF_SEGMENT(token)) { xbeg = VFD_GET_X(**vfpp) - OUTLINE_OFFSET; ybeg = VFD_GET_Y(**vfpp) - OUTLINE_OFFSET; token &= (long)~((VFD_CWCURV | VFD_CCWCURV) & ~VFD_TOKEN); } switch (token & (VFD_LINE | VFD_ARC | VFD_BEZ)) { case VFD_BEZ: *x++ = VFD_GET_X(**vfpp) - OUTLINE_OFFSET; *y++ = VFD_GET_Y(**vfpp) - OUTLINE_OFFSET; (*vfpp)++; case VFD_ARC: *x++ = VFD_GET_X(**vfpp) - OUTLINE_OFFSET; *y++ = VFD_GET_Y(**vfpp) - OUTLINE_OFFSET; (*vfpp)++; case VFD_LINE: *x++ = VFD_GET_X(**vfpp) - OUTLINE_OFFSET; *y++ = VFD_GET_Y(**vfpp) - OUTLINE_OFFSET; (*vfpp)++; } if ((**vfpp == 0) || ((**vfpp) & VFD_TOKEN)) { token = *(*vfpp)++; if ((token == 0) || TOP_OF_SEGMENT(token)) { *x = xbeg; *y = ybeg; return (token); } } *x = VFD_GET_X(**vfpp) - OUTLINE_OFFSET; *y = VFD_GET_Y(**vfpp) - OUTLINE_OFFSET; return (token); } Private void DrawArc(x, y, DrawFunc) int *x; int *y; void (*DrawFunc)(); { double dx1, dy1, dx3, dy3, cx, cy, z, r, ang, dang, ang_step; int i; #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define ARC_DIV 8 dx1 = x[0] - x[1]; dy1 = y[0] - y[1]; dx3 = x[2] - x[1]; dy3 = y[2] - y[1]; z = dx1 * dy3 - dx3 * dy1; if (z == 0) { if((dx1 == dx3) && (dy1 == dy3)) { cx = dx1 / 2.0; cy = dy1 / 2.0; r = sqrt(cx*cx + cy*cy); cx += x[1]; cy += y[1]; ang = 0.0; dang = 2.0 * M_PI; } else { DrawFunc(x[0], y[0], x[2], y[2]); return; } } else { cx = ((dx1*dx1 + dy1*dy1)*dy3 - (dx3*dx3 + dy3*dy3)*dy1) / z / 2.0; cy = - ((dx1*dx1 + dy1*dy1)*dx3 - (dx3*dx3 + dy3*dy3)*dx1) / z / 2.0; r = sqrt(cx*cx + cy*cy); ang = atan2(dy1 - cy, dx1 - cx); dang = atan2(dy3 - cy, dx3 - cx); if (z < 0) { if (dang < ang) dang += 2.0 * M_PI; } else { if (dang > ang) dang -= 2.0 * M_PI; } dang -= ang; if(dang == 0.0) { ang = 0.0; dang = 2.0 * M_PI; } cx += x[1]; cy += y[1]; } ang_step = dang / (double)ARC_DIV; dx1 = x[0]; dy1 = y[0]; ang += ang_step; for (i = 1; i < ARC_DIV; i++) { dx3 = cx + r * cos(ang); dy3 = cy + r * sin(ang); DrawFunc((int)dx1, (int)dy1, (int)dx3, (int)dy3); dx1 = dx3; dy1 = dy3; ang += ang_step; } dx3 = x[2]; dy3 = y[2]; DrawFunc((int)dx1, (int)dy1, (int)dx3, (int)dy3); } Private void DrawBezier(x, y, DrawFunc) int *x; int *y; void (*DrawFunc)(); { int i, xs, ys, xe, ye; #define BEZ_DIV 8 static double b[4][BEZ_DIV], t = -1; if (t < 0) { for (i = 0; i < BEZ_DIV; i++) { /* basis of bezier function */ t = (double)(i + 1) / BEZ_DIV; b[0][i] = (1.0 - t) * (1.0 - t) * (1.0 - t); b[1][i] = 3.0 * t * (1.0 - t) * (1.0 - t); b[2][i] = 3.0 * t * t * (1.0 - t); b[3][i] = t * t * t; } } xs = x[0]; ys = y[0]; for (i = 0; i < BEZ_DIV; i++) { xe = b[0][i]*x[0] + b[1][i]*x[1] + b[2][i]*x[2] + b[3][i]*x[3]; ye = b[0][i]*y[0] + b[1][i]*y[1] + b[2][i]*y[2] + b[3][i]*y[3]; DrawFunc((int)xs, (int)ys, (int)xe, (int)ye); xs = xe; ys = ye; } } Private void trace_outline(x1, y1, x2, y2) int x1, y1, x2, y2; { int dx, dy, dx2, dy2, e, i, tmp; unsigned char* address; unsigned char* buffer = Vbuffer; int width = Vwidth; int height = Vheight; int max_width = Vmax_width; int max_height = Vmax_height; int thin = Vthin; int y_factor = Vrast; long offset_x, minus_offset_x, plus_offset_x; long offset_y, minus_offset_y, plus_offset_y; unsigned char mask; offset_x = (long)thin*(max_width+1)/100L/2L; minus_offset_x = -(max_width+1)/2L - offset_x; plus_offset_x = -(max_width+1)/2L + offset_x; offset_y = (long)thin*(max_height+1)/100L/2L; minus_offset_y = -(max_height+1)/2L - offset_y; plus_offset_y = -(max_height+1)/2L + offset_y; /**printf("T.O. (%5d,%5d)-(%5d,%5d)\n", x1,y1,x2,y2);**/ dx = x2 - x1; dy = y2 - y1; if (dy < 0) { x1 = (int)(((long)x1 * width + minus_offset_x) / (max_width + 1)); x2 = (int)(((long)x2 * width + minus_offset_x) / (max_width + 1)); } else if (dy == 0) { x1 = (int)(((long)x1 * width - (max_width + 1) / 2) / (max_width + 1)); x2 = (int)(((long)x2 * width - (max_width + 1) / 2) / (max_width + 1)); } else { x1 = (int)(((long)x1 * width + plus_offset_x) / (max_width + 1)); x2 = (int)(((long)x2 * width + plus_offset_x) / (max_width + 1)); } if (dx > 0) { y1 = (int)( ((long)y1 * height + minus_offset_y) / (max_height + 1) ); y2 = (int)( ((long)y2 * height + minus_offset_y) / (max_height + 1) ); } else if (dx == 0) { y1 = (int)( ((long)y1 * height - (max_height + 1) / 2) / (max_height + 1) ); y2 = (int)( ((long)y2 * height - (max_height + 1) / 2) / (max_height + 1) ); } else { y1 = (int)(((long)y1 * height + plus_offset_y) / (max_height + 1)); y2 = (int)(((long)y2 * height + plus_offset_y) / (max_height + 1)); } if (x1 < 0) x1 = 0; else if (x1 >= max_width ) x1 = max_width - 1; if (x2 < 0) x2 = 0; else if (x2 >= max_width ) x2 = max_width - 1; if (y1 < 0) y1 = 0; else if (y1 >= max_height) y1 = max_height - 1; if (y2 < 0) y2 = 0; else if (y2 >= max_height) y2 = max_height - 1; dy = y2 - y1; if (dy < 0) { tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; dy = -dy; } dx = x2 - x1; if (dx < 0) dx = -dx; if (dx == 0 && dy == 0) return; address = &buffer[y1 * y_factor + x1 / 8]; mask = 0x80 >> (x1 & 7); dx2 = 2 * dx; dy2 = 2 * dy; if (dx < dy) { e = dx2 - dy; if (x1 < x2) { for (i = 0; i <= dy; i++) { *address |= mask; while (e >= 0) { if ((mask >>= 1) == 0) { address++; mask = 0x80; } e -= dy2; } address += y_factor; e += dx2; } } else { for (i = 0; i <= dy; i++) { *address |= mask; while (e >= 0) { if ((mask <<= 1) == 0) { address--; mask = 0x1; } e -= dy2; } address += y_factor; e += dx2; } } } else { e = dy2 - dx; if (x1 < x2) { for (i = 0; i <= dx; i++) { *address |= mask; while (e >= 0) { address += y_factor; e -= dx2; } if ((mask >>= 1) == 0) { address++; mask = 0x80; } e += dy2; } } else { for (i = 0; i <= dx; i++) { *address |= mask; while (e >= 0) { address += y_factor; e -= dx2; } if ((mask <<= 1) == 0) { address--; mask = 0x1; } e += dy2; } } } } Private void fill_edges(x1, y1, x2, y2) int x1, y1, x2, y2; { Private unsigned char mask_pattern[8] = { 0xff, 0x7f, 0x3f, 0x1f, 0xf, 0x7, 0x3, 0x1 }; int dx, dy, dx2, dy2, sx, e, i, j, tmp; int width = Vwidth; int height = Vheight; int max_width = Vmax_width; int max_height = Vmax_height; int y_factor = Vrast; unsigned char *buffer = Vbuffer; unsigned char *address; int bit, right_bytes; /**printf("F.E. (%5d,%5d)-(%5d,%5d)\n", x1,y1,x2,y2);**/ x1 = (int)( ((long)x1*width -(max_width+1)/2) / (max_width+1) ); y1 = (int)( ((long)y1*height-(max_height+1)/2) / (max_height+1) ); x2 = (int)( ((long)x2*width -(max_width+1)/2) / (max_width+1) ); y2 = (int)( ((long)y2*height-(max_height+1)/2) / (max_height+1) ); dy = y2 - y1; if (dy == 0) return; if (dy < 0) { tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; dy = -dy; } dx = x2 - x1; sx = dx > 0 ? 1 : -1; if (dx < 0) dx = -dx; address = &buffer[y1 * y_factor + x1 / 8]; right_bytes = (width - 1) / 8 - x1 / 8; bit = x1 & 7; dx2 = 2 * dx; dy2 = 2 * dy; e = dx2 - dy; for (i = 0; i < dy; i++) { /* Change right bits in this byte. */ *address ^= mask_pattern[bit]; /* Change all the bits in right bytes. */ for (j = 1; j <= right_bytes; j++) { address[j] = ~address[j]; } while (e >= 0) { bit += sx; if (bit & 0x8) { address += sx; right_bytes -= sx; bit &= 0x7; } e -= dy2; } address += y_factor; e += dx2; } } /*EOF*/