/*
 * 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  <stdio.h>
#include  <stdlib.h>
#include  <string.h>
#include  <ctype.h>
#include  <math.h> 
#include  <sys/types.h>

#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_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},
#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*/
