#include <stdio.h>
#include "hrf.h"
#include "hyraster.h"
#include "hy_cache.c"
#include "mask.h"

#define maxPoints           2048
#define maxHints            64
#define edgeSize            32
#define fontBufferSize     ((maxBitmapSize+itypeMask)/itypeSize*maxBitmapSize)

hyDeviceInfo hyDevice;

typedef long wtype;
typedef float real;
typedef struct { wtype x, y; } Point;

static union {
    struct {
        itype         imageBuffer[fontBufferSize];
        unsigned char edgeCnt[maxBitmapSize];
        signed char   edgeDir[maxBitmapSize][edgeSize];
        short         edge[maxBitmapSize][edgeSize];
        struct { short b, o; } oHintV[maxHints], oHintH[maxHints];
        struct { wtype b, o; } gHintV[maxHints], gHintH[maxHints];
        int     n;
        int     xMin, yMin, xMax, yMax;
        Point   c[maxPoints];
        char    a[maxPoints];
        } CS;
    struct {
        int status;
        int side;
        int ox, oy;
        int px, py;
        int sx, sy;
        int ex, ey;
        short edge[1][16];
        } GS;
    } hyRasterizerBuffer;

struct {
    int lineThickness;
    int isDrawOutline, fillMode;
    int patternType;
    int grayLevel;
    int depth;
    itype grayMask[itypeSize];
    itype *fillMask;
    struct {
        hyFontImage info;
        itype image[(maxThickness+itypeMask)/itypeSize*maxThickness];
        } olMask;
    } GS;

#define IMAGE_BUFFER  hyRasterizerBuffer.CS.imageBuffer
#define REDGE_CNT     hyRasterizerBuffer.CS.edgeCnt
#define EDGE_CNT      hyRasterizerBuffer.CS.edgeCnt
#define EDGE_DIR      hyRasterizerBuffer.CS.edgeDir
#define EDGE          hyRasterizerBuffer.CS.edge
#define OHINT_V       hyRasterizerBuffer.CS.oHintV
#define OHINT_H       hyRasterizerBuffer.CS.oHintH
#define GHINT_V       hyRasterizerBuffer.CS.gHintV
#define GHINT_H       hyRasterizerBuffer.CS.gHintH
#define GPOINT_CNT    hyRasterizerBuffer.CS.n
#define GPOINT_XMIN   hyRasterizerBuffer.CS.xMin
#define GPOINT_YMIN   hyRasterizerBuffer.CS.yMin
#define GPOINT_XMAX   hyRasterizerBuffer.CS.xMax
#define GPOINT_YMAX   hyRasterizerBuffer.CS.yMax
#define GPOINT_COORD  hyRasterizerBuffer.CS.c
#define GPOINT_ATTR   hyRasterizerBuffer.CS.a

#define GS_DEPTH                         GS.depth
#define GS_EDGE       hyRasterizerBuffer.GS.edge
#define ELL_OX        hyRasterizerBuffer.GS.ox
#define ELL_OY        hyRasterizerBuffer.GS.oy
#define ELL_PX        hyRasterizerBuffer.GS.px
#define ELL_PY        hyRasterizerBuffer.GS.py
#define ELL_SX        hyRasterizerBuffer.GS.sx
#define ELL_SY        hyRasterizerBuffer.GS.sy
#define ELL_EX        hyRasterizerBuffer.GS.ex
#define ELL_EY        hyRasterizerBuffer.GS.ey
#define ELL_STATUS    hyRasterizerBuffer.GS.status
#define ELL_SIDE      hyRasterizerBuffer.GS.side

#define bitMask(x)          (leftPixel >> (x))
#define leftMask(x)         (fullPixel >> (x))
#define rightMask(x)        (fullPixel << (itypeMask-(x)))

#define _X(x)               (x+devXDelta)
#define _Y(y)               (y+devYDelta)

#define setFontPixel(x,y)   fontImage[_Y(y)*bSize+(_X(x)>>itypeShift)] |=  bitMask(_X(x)&itypeMask)
#define clearFontPixel(x,y) fontImage[_Y(y)*bSize+(_X(x)>>itypeShift)] &= ~bitMask(_X(x)&itypeMask)
#define imgptn(p,v,n,ptn)   for(TEMP_VAL=n-1;TEMP_VAL>=0;TEMP_VAL--) (p)[TEMP_VAL]  = v & ptn
#define imgset(p,v,n)       for(TEMP_VAL=n-1;TEMP_VAL>=0;TEMP_VAL--) (p)[TEMP_VAL]  = v
#define imgor(p,v,n)        for(TEMP_VAL=n-1;TEMP_VAL>=0;TEMP_VAL--) (p)[TEMP_VAL] |= v
#define imgxor(p,v,n)       for(TEMP_VAL=n-1;TEMP_VAL>=0;TEMP_VAL--) (p)[TEMP_VAL] ^= v
void memcls(char*p,int n)  {for(;n;n--) *p++=0;}

#define lineFillPattern(image,x1,x2,pattern) \
            QUOTA1 = (x1) >> itypeShift; REMAINDER1 = (x1) & itypeMask; \
            QUOTA2 = (x2) >> itypeShift; REMAINDER2 = (x2) & itypeMask; \
            if( QUOTA1 == QUOTA2 ) { \
                *((image)+QUOTA1) &= ~(leftMask(REMAINDER1) & rightMask(REMAINDER2)); \
                *((image)+QUOTA1) |= ((leftMask(REMAINDER1) & rightMask(REMAINDER2)) & pattern); \
                } \
            else { \
                *((image)+QUOTA1) &= ~leftMask(REMAINDER1); \
                *((image)+QUOTA1) |=  leftMask(REMAINDER1) & pattern; \
                *((image)+QUOTA2) &= ~rightMask(REMAINDER2); \
                *((image)+QUOTA2) |=  rightMask(REMAINDER2) & pattern; \
                imgptn( (image)+QUOTA1+1, fullPixel, QUOTA2-QUOTA1-1, pattern ); \
                }
#define lineFill(image,x1,x2) \
            QUOTA1 = (x1) >> itypeShift; REMAINDER1 = (x1) & itypeMask; \
            QUOTA2 = (x2) >> itypeShift; REMAINDER2 = (x2) & itypeMask; \
            if( QUOTA1 == QUOTA2 ) { \
                *((image)+QUOTA1) |= leftMask(REMAINDER1) & rightMask(REMAINDER2); \
                } \
            else { \
                *((image)+QUOTA1) |= leftMask(REMAINDER1); \
                *((image)+QUOTA2) |= rightMask(REMAINDER2); \
                imgor( (image)+QUOTA1+1, fullPixel, QUOTA2-QUOTA1-1 ); \
                }
#define lineClear(image,x1,x2) \
            QUOTA1 = (x1) >> itypeShift; REMAINDER1 = (x1) & itypeMask; \
            QUOTA2 = (x2) >> itypeShift; REMAINDER2 = (x2) & itypeMask; \
            if( QUOTA1 == QUOTA2 ) { \
                *((image)+QUOTA1) &= ~(leftMask(REMAINDER1) & rightMask(REMAINDER2)); \
                } \
            else { \
                *((image)+QUOTA1) &= ~leftMask(REMAINDER1); \
                *((image)+QUOTA2) &= ~rightMask(REMAINDER2); \
                imgset( (image)+QUOTA1+1, 0, QUOTA2-QUOTA1-1 ); \
                }
#define lineXOR(image,x1,x2) \
            QUOTA1 = (x1) >> itypeShift; REMAINDER1 = (x1) & itypeMask; \
            QUOTA2 = (x2) >> itypeShift; REMAINDER2 = (x2) & itypeMask; \
            if( QUOTA1 == QUOTA2 ) { \
                REMAINDER2 = itypeMask - ((x2) & itypeMask); \
                *((image)+QUOTA1) ^= leftMask(REMAINDER1) & rightMask(REMAINDER2); \
                } \
            else { \
                *((image)+QUOTA1) ^= leftMask(REMAINDER1); \
                *((image)+QUOTA2) ^= rightMask(REMAINDER2); \
                imgxor( (image)+QUOTA1+1, fullPixel, QUOTA2-QUOTA1-1 ); \
                }

#define xGridUnit(x)       ((x)*hyAttribute.xSize_1)
#define yGridUnit(y)       ((y)*hyAttribute.ySize_1)
#define xGridUnit2(x)      ((x)*hyAttribute.xSize)
#define yGridUnit2(y)      ((y)*hyAttribute.ySize)
#define xPixelUnit(x)      ((x+hyAttribute.xHalf)/hyImageInfo.emXSize)
#define yPixelUnit(y)      ((y+hyAttribute.yHalf)/hyImageInfo.emYSize)
#define xPixelUnitS(x)     ((x<0)?((x-hyAttribute.xHalf)/hyImageInfo.emXSize):xPixelUnit(x))
#define yPixelUnitS(y)     ((y<0)?((y-hyAttribute.yHalf)/hyImageInfo.emYSize):yPixelUnit(y))

#define meanValue( x, y )  (((x)+(y)+1)>>1)
#define setEdge( x,y,d )   EDGE_DIR[y][EDGE_CNT[y]] = d; EDGE[y][EDGE_CNT[y]++] = x
#define ABS(x)             ((x)<0?-(x):(x))

static hrfFontType *curr_hrf;
static itype       *fontImage;
static int          physicalXPos;
static int          physicalYPos;
static int          devXPos;
static int          devYPos;
static int          devXDelta;
static int          devYDelta;
static int          devCurAbsolute;
static int          devOgnAbsolute;
static int          bSize;

static int QUOTA1, QUOTA2, REMAINDER1, REMAINDER2, TEMP_VAL;
static int CLEAROUTLINE;
static int OUTLINECOPY;
static int OUTLINEMOVE;
static int OGNDX, CPYDX;
static int OGNDY, CPYDY;
static int BAND_START, BAND_END, BAND_LEN, BAND_XLEN;
static int NUMOFMOVEMAP;
static int shadow, shadowdx, shadowdy, outline, bold;
static int reverse, pattern, underline, view_area;
static struct { char x, y; } MOVEMAP[128];
static union { unsigned char *b; signed   char *c; } CurP;

static void (*drawLINETO)(Point p);
static wtype  CX, CY;
static Point  MM;
static int    icx, icy;
static int    sx, sy;

static int globalVSTEM;
static int globalHSTEM;
static int localVSTEM;
static int localHSTEM;

uint8 *hrfReadOneGlyf( hrfFontType *hrf_font, uint16 index );
uint16 hrfReadWidth( hrfFontType *hrf_font, uint16 index );
hrfFontType *hrfReadCharIndex( uint16 code );

static void quickSort( int min, int max, short *desc_x, signed char *desc_d )
    {
    int i, j;
    int x;
    int itmp;

    if( min >= max ) return;

    i = min;
    j = max;
    x = desc_x[max];

    while( i < j ) {
        while( i<j && desc_x[i] <= x )
            i++;
        while( i<j && desc_x[j] >= x )
            j--;
        if( i<j ) {
            itmp = desc_d[i];
            desc_d[i] = desc_d[j];
            desc_d[j] = itmp;
            itmp = desc_x[i];
            desc_x[i] = desc_x[j];
            desc_x[j] = itmp;
            }
        }
    itmp = desc_d[i];
    desc_d[i] = desc_d[max];
    desc_d[max] = itmp;
    itmp = desc_x[i];
    desc_x[i] = desc_x[max];
    desc_x[max] = itmp;

    quickSort( min, i-1, desc_x, desc_d );
    quickSort( i+1, max, desc_x, desc_d );
    }

static unsigned char getByte( void )
    {
    return( *(CurP.b++) );
    }

static signed char hrfReadChar( void )
    {
    return( *(CurP.c++) );
    }

static short getWord( void )
    {
    signed short i = hrfReadChar();
    unsigned short m = getByte();
    return( (i<<8)|m );
    }

static short getNum( void )
    {
    short n = hrfReadChar();

    if( n >= 124 )
        return( ((n - 124) << 8) + 124 + getByte() );
    if( n > -124 )
        return( n );
    if( n > -128 )
        return( ((n + 124) << 8) - 124 - getByte() );
    return( getWord() );
    }

static void _drawMOVETO( wtype x, wtype y )
    {
    MM.x = CX = x;
    MM.y = CY = y;
    sx = icx = x;
    sy = icy = y;
    }

static void drawMOVETO( Point p )
    {
    MM.x = CX = p.x;
    MM.y = CY = p.y;
    sx = icx = xPixelUnit( p.x );
    sy = icy = yPixelUnit( p.y );
    }

static void drawLINETONormal( Point p )
    {
    int x2 = xPixelUnit( p.x );
    int y2 = yPixelUnit( p.y );
    int dx = x2 - icx;
    int dy = y2 - icy;
    int d1,d2;
    register i, d;

    if( !dx && !dy ) return;

    CX = p.x;
    CY = p.y;
    if (dx < 0) {
        dx = -dx;
        if (dy < 0) {
            dy = -dy;
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVLEFT;  cond=MVUP; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx--;
                    if (d >= 0) {
                        d -= d1;
                        icy--;
                        setEdge( sx, sy, -1 );
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    setFontPixel( icx, icy );
                    }
                }
            else {
                i=d1=dy; d2=dx;   /* always=MVUP;    cond=MVLEFT; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy--;
                    if (d >= 0) {
                        d -= d1;
                        icx--;
                        }
                    d += d2;
                    setEdge( sx, sy, -1 );
                    setFontPixel( icx, icy );
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        else {
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVLEFT;  cond=MVDOWN; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx--;
                    if (d >= 0) {
                        d -= d1;
                        icy++;
                        setEdge( icx, icy, 1 );
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    setFontPixel( icx, icy );
                    }
                }
            else {
                i=d1=dy; d2=dx;   /* always=MVDOWN;  cond=MVLEFT; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy++;
                    if (d >= 0) {
                        d -= d1;
                        icx--;
                        }
                    d += d2;
                    setEdge( icx, icy, 1 );
                    setFontPixel( icx, icy );
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        }
    else {
        if (dy < 0) {
            dy = -dy;
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVRIGHT; cond=MVUP; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx++;
                    if (d >= 0) {
                        d -= d1;
                        icy--;
                        setEdge( sx, sy, -1 );
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    setFontPixel( icx, icy );
                    }
                }
            else {
                i=d1=dy; d2=dx;   /* always=MVUP;    cond=MVRIGHT; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy--;
                    if (d >= 0) {
                        d -= d1;
                        icx++;
                        }
                    d += d2;
                    setEdge( sx, sy, -1 );
                    setFontPixel( icx, icy );
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        else {
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVRIGHT; cond=MVDOWN; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx++;
                    if (d >= 0) {
                        d -= d1;
                        icy++;
                        setEdge( icx, icy, 1 );
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    setFontPixel( icx, icy );
                    }
                }
            else {
                d1=dy; d2=dx;   /* always=MVDOWN;  cond=MVRIGHT; */
                i = d1;
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy++;
                    if (d >= 0) {
                        d -= d1;
                        icx++;
                        }
                    d += d2;
                    setEdge( icx, icy, 1 );
                    setFontPixel( icx, icy );
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        }
    }

static void setBand( int start, int end )
    {
    BAND_START = start;
    BAND_END = end;
    BAND_LEN = end - start;
    if( devCurAbsolute ) BAND_XLEN = devXMax;
    else BAND_XLEN = hyImageInfo.xSize - 1;
    }

#define isInBand(y) ((y)>=BAND_START && (y)<BAND_END) ? (y)-BAND_START : -1

static void setOutlineCopy( int onoff, int dx, int dy )
    {
    OUTLINECOPY = onoff;
    if( dx >= 0 ) {
        if( dy >= 0 ) {
            OGNDX = bold;  OGNDY = bold;    CPYDX = dx+bold; CPYDY = dy+bold;
            }
        else {
            OGNDX = bold;  OGNDY = bold-dy; CPYDX = dx+bold; CPYDY = bold;
            }
        }
    else {
        if( dy >= 0 ) {
            OGNDX = bold-dx;OGNDY = bold;   CPYDX = bold;  CPYDY = dy+bold;
            }
        else {
            OGNDX = bold-dx;OGNDY = bold-dy;CPYDX = bold;  CPYDY = bold;
            }
        }
    }

static int setOutlineMove( int onoff, int dx, int dy )
    {
    int i, sign;
    float ratio;

    OUTLINEMOVE = NUMOFMOVEMAP = 0;

    if( onoff ) {
        if( ABS( dx ) > ABS( dy ) ) {
            sign = ( dx < 0 ) ? -1 : 1;
            NUMOFMOVEMAP = ( sign * dx );
            if( NUMOFMOVEMAP > 128 ) NUMOFMOVEMAP = 128;
            if( !NUMOFMOVEMAP ) return( 0 );
            ratio = (float)dy / (float)dx;
            for( i=1; i<=NUMOFMOVEMAP; i++ ) {
                MOVEMAP[i-1].x = sign * i;
                MOVEMAP[i-1].y = (int)( (float)MOVEMAP[i-1].x * ratio );
                }
            }
        else {
            sign = ( dy < 0 ) ? -1 : 1;
            NUMOFMOVEMAP = ( sign * dy );
            if( NUMOFMOVEMAP > 128 ) NUMOFMOVEMAP = 128;
            if( !NUMOFMOVEMAP ) return( 0 );
            ratio = (float)dx / (float)dy;
            for( i=1; i<=NUMOFMOVEMAP; i++ ) {
                MOVEMAP[i-1].y = sign * i;
                MOVEMAP[i-1].x = (int)( (float)MOVEMAP[i-1].y * ratio );
                }
            }
        OUTLINEMOVE = 1;
        }
    return( 1 );
    }

static void _outlineMove( void )
    {
    int i, y;

    for( i=0; i<NUMOFMOVEMAP; i++ ) {
        if( (y=isInBand(icy+OGNDY+MOVEMAP[i].y))>=0 )
            setFontPixel( icx+OGNDX+MOVEMAP[i].x, y );
        }
    }

static void _outlineCopy( void )
    {
    int y;

    if( bold ) {
        int i;
        for( i=1; i<=bold; i++ ) {
            if( (y=isInBand(icy+OGNDY-i)) >= 0 ) setFontPixel( icx+OGNDX, y );
            if( (y=isInBand(icy+OGNDY+i)) >= 0 ) setFontPixel( icx+OGNDX, y );
            if( (y=isInBand(icy+OGNDY)) >= 0 ) {
                if( icx+OGNDX+i <= BAND_XLEN ) setFontPixel( icx+OGNDX+i, y );
                if( icx+OGNDX-i >= 0 ) setFontPixel( icx+OGNDX-i, y );
                }
            }
        }

    else if( OUTLINEMOVE ) _outlineMove();
    else if( (y=isInBand(icy+CPYDY)) >= 0 ) setFontPixel( icx+CPYDX, y );
    }

static void drawLINETOAttr( Point p )
    {
    int x2 = xPixelUnit( p.x );
    int y2 = yPixelUnit( p.y );
    int dx = x2 - icx;
    int dy = y2 - icy;
    int d1,d2,yy;
    register i, d;

    if( !dx && !dy ) return;

    CX = p.x;
    CY = p.y;
    if (dx < 0) {
        dx = -dx;
        if (dy < 0) {
            dy = -dy;
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVLEFT;  cond=MVUP; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx--;
                    if (d >= 0) {
                        d -= d1;
                        icy--;
                        if( (yy=isInBand(sy)) >= 0 ) {
                            setEdge( sx, yy, -1 );
                            }
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    if( (yy=isInBand(icy+OGNDY)) >= 0 ) {
                        if( CLEAROUTLINE ) clearFontPixel( icx, yy );
                        else setFontPixel( icx, yy );
                        }
                    if( OUTLINECOPY ) _outlineCopy();
                    }
                }
            else {
                i=d1=dy; d2=dx;   /* always=MVUP;    cond=MVLEFT; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy--;
                    if (d >= 0) {
                        d -= d1;
                        icx--;
                        }
                    d += d2;
                    if( (yy=isInBand(sy)) >= 0 ) {
                        setEdge( sx, yy, -1 );
                        }
                    if( (yy=isInBand(icy+OGNDY)) >= 0 ) {
                        if( CLEAROUTLINE ) clearFontPixel( icx, yy );
                        else setFontPixel( icx, yy );
                        }
                    if( OUTLINECOPY ) _outlineCopy();
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        else {
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVLEFT;  cond=MVDOWN; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx--;
                    if (d >= 0) {
                        d -= d1;
                        icy++;
                        if( (yy=isInBand(icy)) >= 0 ) {
                            setEdge( icx, yy, 1 );
                            }
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    if( (yy=isInBand(icy+OGNDY)) >= 0 ) {
                        if( CLEAROUTLINE ) clearFontPixel( icx, yy );
                        else setFontPixel( icx, yy );
                        }
                    if( OUTLINECOPY ) _outlineCopy();
                    }
                }
            else {
                i=d1=dy; d2=dx;   /* always=MVDOWN;  cond=MVLEFT; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy++;
                    if (d >= 0) {
                        d -= d1;
                        icx--;
                        }
                    d += d2;
                    if( (yy=isInBand(icy)) >= 0 ) {
                        setEdge( icx, yy, 1 );
                        }
                    if( (yy=isInBand(icy+OGNDY)) >= 0 ) {
                        if( CLEAROUTLINE ) clearFontPixel( icx, yy );
                        else setFontPixel( icx, yy );
                        }
                    if( OUTLINECOPY ) _outlineCopy();
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        }
    else {
        if (dy < 0) {
            dy = -dy;
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVRIGHT; cond=MVUP; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx++;
                    if (d >= 0) {
                        d -= d1;
                        icy--;
                        if( (yy=isInBand(sy)) >= 0 ) {
                            setEdge( sx, yy, -1 );
                            }
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    if( (yy=isInBand(icy+OGNDY)) >= 0 ) {
                        if( CLEAROUTLINE ) clearFontPixel( icx, yy );
                        else setFontPixel( icx, yy );
                        }
                    if( OUTLINECOPY ) _outlineCopy();
                    }
                }
            else {
                i=d1=dy; d2=dx;   /* always=MVUP;    cond=MVRIGHT; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy--;
                    if (d >= 0) {
                        d -= d1;
                        icx++;
                        }
                    d += d2;
                    if( (yy=isInBand(sy)) >= 0 ) {
                        setEdge( sx, yy, -1 );
                        }
                    if( (yy=isInBand(icy+OGNDY)) >= 0 ) {
                        if( CLEAROUTLINE ) clearFontPixel( icx, yy );
                        else setFontPixel( icx, yy );
                        }
                    if( OUTLINECOPY ) _outlineCopy();
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        else {
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVRIGHT; cond=MVDOWN; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx++;
                    if (d >= 0) {
                        d -= d1;
                        icy++;
                        if( (yy=isInBand(icy)) >= 0 ) {
                            setEdge( icx, yy, 1 );
                            }
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    if( (yy=isInBand(icy+OGNDY)) >= 0 ) {
                        if( CLEAROUTLINE ) clearFontPixel( icx, yy );
                        else setFontPixel( icx, yy );
                        }
                    if( OUTLINECOPY ) _outlineCopy();
                    }
                }
            else {
                d1=dy; d2=dx;   /* always=MVDOWN;  cond=MVRIGHT; */
                i = d1;
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy++;
                    if (d >= 0) {
                        d -= d1;
                        icx++;
                        }
                    d += d2;
                    if( (yy=isInBand(icy)) >= 0 ) {
                        setEdge( icx, yy, 1 );
                        }
                    if( (yy=isInBand(icy+OGNDY)) >= 0 ) {
                        if( CLEAROUTLINE ) clearFontPixel( icx, yy );
                        else setFontPixel( icx, yy );
                        }
                    if( OUTLINECOPY ) _outlineCopy();
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        }
    }

static void (*_setEdge)( int x, int y, int d );
static void (*_setFontPixel)( int x, int y );

static void set_edge( int x, int y, int d )
    {
    if( (y=isInBand(y)) < 0 ) return;
    setEdge( x, y, d );
    }

static void set_edge_null( int x, int y, int d ) {}

static void set_font_pixel_null( int x, int y ) {}

static void set_font_pixel( int x, int y )
    {
    int e, t;

    if( (y=isInBand(y)) < 0 ) return;

    for( e=0; e<EDGE_CNT[y]; e+=2 ) {
        if( (x >= EDGE[y][e]) && (x <= EDGE[y][e+1]) ) return;
        if( x == EDGE[y][e]-1 ) { EDGE[y][e] = x; return; }
        if( x == EDGE[y][e+1]+1 ) { EDGE[y][e+1] = x; return; }
        if( EDGE[y][e] >  x ) {
            for( t=EDGE_CNT[y]-1; t>=e; t-- ) {
                EDGE[y][t+1] = EDGE[y][t-1];
                EDGE[y][t+2] = EDGE[y][t];
                }
            break;
            }
        }
    EDGE[y][e]   = x;
    EDGE[y][e+1] = x;
    EDGE_CNT[y] += 2;
    }

static void _drawLINETODummy( wtype x, wtype y )
    {
    int dx = x - icx;
    int dy = y - icy;
    int d1,d2;
    register i, d;

    if( !dx && !dy ) return;

    if (dx < 0) {
        dx = -dx;
        if (dy < 0) {
            dy = -dy;
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVLEFT;  cond=MVUP; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx--;
                    if (d >= 0) {
                        d -= d1;
                        icy--;
                        _setEdge( sx, sy, -1 );
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    _setFontPixel( icx, icy );
                    }
                }
            else {
                i=d1=dy; d2=dx;   /* always=MVUP;    cond=MVLEFT; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy--;
                    if (d >= 0) {
                        d -= d1;
                        icx--;
                        }
                    d += d2;
                    _setEdge( sx, sy, -1 );
                    _setFontPixel( icx, icy );
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        else {
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVLEFT;  cond=MVDOWN; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx--;
                    if (d >= 0) {
                        d -= d1;
                        icy++;
                        _setEdge( icx, icy, 1 );
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    _setFontPixel( icx, icy );
                    }
                }
            else {
                i=d1=dy; d2=dx;   /* always=MVDOWN;  cond=MVLEFT; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy++;
                    if (d >= 0) {
                        d -= d1;
                        icx--;
                        }
                    d += d2;
                    _setEdge( icx, icy, 1 );
                    _setFontPixel( icx, icy );
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        }
    else {
        if (dy < 0) {
            dy = -dy;
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVRIGHT; cond=MVUP; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx++;
                    if (d >= 0) {
                        d -= d1;
                        icy--;
                        _setEdge( sx, sy, -1 );
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    _setFontPixel( icx, icy );
                    }
                }
            else {
                i=d1=dy; d2=dx;   /* always=MVUP;    cond=MVRIGHT; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy--;
                    if (d >= 0) {
                        d -= d1;
                        icx++;
                        }
                    d += d2;
                    _setEdge( sx, sy, -1 );
                    _setFontPixel( icx, icy );
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        else {
            if (dx >= dy) {
                i=d1=dx; d2=dy;   /* always=MVRIGHT; cond=MVDOWN; */
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icx++;
                    if (d >= 0) {
                        d -= d1;
                        icy++;
                        _setEdge( icx, icy, 1 );
                        sx = icx;
                        sy = icy;
                        }
                    d += d2;
                    _setFontPixel( icx, icy );
                    }
                }
            else {
                d1=dy; d2=dx;   /* always=MVDOWN;  cond=MVRIGHT; */
                i = d1;
                d2 <<= 1;
                d = d2 - d1;
                d1 <<= 1;
                for ( ; i>0 ; i--) {
                    icy++;
                    if (d >= 0) {
                        d -= d1;
                        icx++;
                        }
                    d += d2;
                    _setEdge( icx, icy, 1 );
                    _setFontPixel( icx, icy );
                    sx = icx;
                    sy = icy;
                    }
                }
            }
        }
    }

static void drawLINETODummy( Point p )
    {
    CX = p.x;
    CY = p.y;
    _drawLINETODummy( xPixelUnit(p.x), yPixelUnit(p.y) );
    }

static void CURVESEG( wtype x0, wtype y0,  wtype x1, wtype y1,
                      wtype x2, wtype y2,  wtype x3, wtype y3 )
    {
    wtype dx, dy;
    Point p1, p2, p3, p4, p5, mm;

    p1.x = meanValue( x0, x1 );
    p1.y = meanValue( y0, y1 );
    p5.x = meanValue( x2, x3 );
    p5.y = meanValue( y2, y3 );
    p3.x = meanValue( x1, x2 );
    p3.y = meanValue( y1, y2 );
    p2.x = meanValue( p1.x, p3.x );
    p2.y = meanValue( p1.y, p3.y );
    p4.x = meanValue( p5.x, p3.x );
    p4.y = meanValue( p5.y, p3.y );
    mm.x = meanValue( p2.x, p4.x );
    mm.y = meanValue( p2.y, p4.y );

    dx =  mm.x - p3.x;
    dy =  mm.y - p3.y;

    if( dx*dx+dy*dy < hyAttribute.threshold ) {
        mm.x = x3; mm.y = y3;
        drawLINETO( p1 );
        drawLINETO( p2 );
        drawLINETO( p4 );
        drawLINETO( p5 );
        drawLINETO( mm );
        return;
        }
    CURVESEG( x0,y0, p1.x,p1.y, p2.x,p2.y, mm.x,mm.y );
    CURVESEG( mm.x,mm.y, p4.x,p4.y, p5.x,p5.y, x3,y3 );
    }

static void drawCURVETO( Point p1, Point p2, Point p3 )
    {
    wtype px1 = meanValue( CX, p1.x );
    wtype py1 = meanValue( CY, p1.y );
    wtype px5 = meanValue( p2.x, p3.x );
    wtype py5 = meanValue( p2.y, p3.y );
    wtype px3 = meanValue( p1.x, p2.x );
    wtype py3 = meanValue( p1.y, p2.y );
    wtype px2 = meanValue( px1, px3 );
    wtype py2 = meanValue( py1, py3 );
    wtype px4 = meanValue( px5, px3 );
    wtype py4 = meanValue( py5, py3 );
    wtype mmx = meanValue( px2, px4 );
    wtype mmy = meanValue( py2, py4 );

    CURVESEG( CX,CY, px1,py1, px2,py2, mmx,mmy );
    CURVESEG( mmx,mmy, px4,py4, px5,py5, p3.x,p3.y );
    CX = p3.x; CY = p3.y;
    }

#define drawCLOSEPATH()    drawLINETO( MM )

static Point pp;

#define _sdX(x,y) (((x)*hyImageInfo.t.v[0][0]+(y)*hyImageInfo.t.v[0][1]+hyImageInfo.t.v[0][2])>>fixedShift)
#define _sdY(x,y) (((x)*hyImageInfo.t.v[1][0]+(y)*hyImageInfo.t.v[1][1]+hyImageInfo.t.v[1][2])>>fixedShift)

static Point gridFit( wtype x, wtype y )
    {
    int i;

    pp.x = xGridUnit(x);
    pp.y = yGridUnit(y);

    for( i=0; i<localVSTEM; i++ ) {
        if( x == OHINT_V[i].b ) {
            pp.x = GHINT_V[i].b;
            break;
            }
        if( x == OHINT_V[i].o ) {
            pp.x = GHINT_V[i].o;
            break;
            }
        }

    for( i=0; i<localHSTEM; i++ ) {
        if( y == OHINT_H[i].b ) {
            pp.y = GHINT_H[i].b;
            break;
            }
        if( y == OHINT_H[i].o ) {
            pp.y = GHINT_H[i].o;
            break;
            }
        }

    x = pp.x;
    y = pp.y;
    pp.x = _sdX( x, y );
    pp.y = _sdY( x, y );

    return( pp );
    }

static Point gridUnit( wtype x, wtype y )
    {
    pp.x = xGridUnit(x);
    pp.y = yGridUnit(y);

    x = pp.x;
    y = pp.y;
    pp.x = _sdX( x, y );
    pp.y = _sdY( x, y );

    return( pp );
    }

static Point gridUnit2( wtype x, wtype y )
    {
    pp.x = xGridUnit2(x);
    pp.y = yGridUnit2(y);

    x = pp.x;
    y = pp.y;
    pp.x = _sdX( x, y );
    pp.y = _sdY( x, y );

    return( pp );
    }

static void addVSTEM( int b, int o, int *index )
    {
    int   i = *index;
    wtype d, bb, oo;

    OHINT_V[i].b = b;
    OHINT_V[i].o = o;

    bb = xGridUnit( b );
    oo = xGridUnit( o );

    d = oo - bb;
    d = xPixelUnitS(d) * hyImageInfo.emXSize;
    GHINT_V[i].b = xPixelUnit(bb) * hyImageInfo.emXSize;
    GHINT_V[i].o = xPixelUnit(oo) * hyImageInfo.emXSize;
    if( ABS(bb-GHINT_V[i].b) <= ABS(oo-GHINT_V[i].o) ) GHINT_V[i].o = GHINT_V[i].b + d;
    else GHINT_V[i].b = GHINT_V[i].o - d;

    (*index)++;
    }

static void addHSTEM( int b, int o, int *index )
    {
    int   i = *index;
    wtype d, bb, oo;

    OHINT_H[i].b = b;
    OHINT_H[i].o = o;

    bb = yGridUnit( b );
    oo = yGridUnit( o );

    d = oo - bb;
    d = yPixelUnitS(d) * hyImageInfo.emYSize;
    GHINT_H[i].b = yPixelUnit(bb) * hyImageInfo.emYSize;
    GHINT_H[i].o = yPixelUnit(oo) * hyImageInfo.emYSize;
    if( ABS(bb-GHINT_H[i].b) <= ABS(oo-GHINT_H[i].o) ) GHINT_H[i].o = GHINT_H[i].b + d;
    else GHINT_H[i].b = GHINT_H[i].o - d;

    (*index)++;
    }

static void edgeSort( void )
    {
    int i;
    for( i=0; i<BAND_LEN; i++ ) quickSort( 0, EDGE_CNT[i]-1, EDGE[i], EDGE_DIR[i] );
    }

static void rastGlyph()
    {
    int i;
    for( i=0; i<GPOINT_CNT; i++ ) {
        switch( GPOINT_ATTR[i] ) {
            case PCRMoveTo:
                drawMOVETO( GPOINT_COORD[i] );
                break;
            case PCClosePath:
                drawCLOSEPATH();
                break;
            case PCRLineTo:
                drawLINETO( GPOINT_COORD[i] );
                break;
            case PCRRCurveTo:
                drawCURVETO( GPOINT_COORD[i], GPOINT_COORD[i+1], GPOINT_COORD[i+2] );
                i += 2;
                break;
            }
        }
    }

static void rastGlyph2( int n )
    {
    _setEdge = set_edge;
    _setFontPixel = set_font_pixel_null;
    drawMOVETO(      GPOINT_COORD[n+0] );
    drawLINETODummy( GPOINT_COORD[n+1] );
    drawLINETODummy( GPOINT_COORD[n+2] );
    drawLINETODummy( GPOINT_COORD[n+3] );
    drawLINETODummy( GPOINT_COORD[n+4] );
    edgeSort();
    _setEdge = set_edge_null;
    _setFontPixel = set_font_pixel;
    drawMOVETO(      GPOINT_COORD[n+0] );
    drawLINETODummy( GPOINT_COORD[n+1] );
    drawLINETODummy( GPOINT_COORD[n+2] );
    drawLINETODummy( GPOINT_COORD[n+3] );
    drawLINETODummy( GPOINT_COORD[n+4] );
    }

static void putPixelToImage( int dx, int dy )
    {
    int i, j, x1, x2, SUM;
    itype *WORK_IMAGE_PTR = fontImage + _Y(dy)*bSize;

    for( i=0; i<BAND_LEN; i++ ) {
        SUM = 0;
        for( j=0; j<EDGE_CNT[i]; j++ ) {
            if( SUM ) {
                if( !(SUM += EDGE_DIR[i][j]) ) {
                    x2 = _X( EDGE[i][j] + dx );
                    lineFill( WORK_IMAGE_PTR, x1, x2 );
                    }
                }
            else {
                SUM += EDGE_DIR[i][j];
                x1 = _X( EDGE[i][j] + dx );
                }
            }
        WORK_IMAGE_PTR += bSize;
        }
    }

static void clearPixelToImage( int dx, int dy, int dd )
    {
    int i, j, x1, x2, SUM;
    itype *WORK_IMAGE_PTR = fontImage + _Y(dy)*bSize;

    for( i=0; i<BAND_LEN; i++ ) {
        SUM = 0;
        for( j=0; j<EDGE_CNT[i]; j++ ) {
            if( SUM ) {
                if( !(SUM += EDGE_DIR[i][j]) ) {
                    x2 = _X( EDGE[i][j] + dx - dd );
                    if( x2 >= x1 ) {
                        lineClear( WORK_IMAGE_PTR, x1, x2 );
                        }
                    }
                }
            else {
                SUM += EDGE_DIR[i][j];
                x1 = _X( EDGE[i][j] + dx + dd );
                }
            }
        WORK_IMAGE_PTR += bSize;
        }
    }

static void patternPixelToImage( int dx, int dy )
    {
    int i, j;
    int m = (physicalYPos+dy) & itypeMask;
    int l = (physicalXPos+dx) & itypeMask;
    int r = itypeSize - l;
    itype mask;
    itype *WORK_IMAGE_PTR = fontImage + _Y(dy)*bSize;

    for( i=0; i<BAND_LEN; i++,m++ ) {
        for( j=0; j<EDGE_CNT[i]; j+=2 ) {
            mask = (hyAttribute.patternMask[m&itypeMask] << l)
                 | (hyAttribute.patternMask[m&itypeMask] >> r);
            lineFillPattern( WORK_IMAGE_PTR, _X(EDGE[i][j]+dx), _X(EDGE[i][j+1]+dx), mask );
            }
        WORK_IMAGE_PTR += bSize;
        }
    }

static void xorPixelToImage( int dx, int dy )
    {
    int i, j;
    itype *WORK_IMAGE_PTR = fontImage + _Y(dy)*bSize;

    for( i=0; i<BAND_LEN; i++ ) {
        for( j=0; j<EDGE_CNT[i]; j+=2 ) {
            lineXOR( WORK_IMAGE_PTR, _X(EDGE[i][j]+dx), _X(EDGE[i][j+1]+dx) );
            }
        WORK_IMAGE_PTR += bSize;
        }
    }

static void clsPixelToImage( int dx, int dy )
    {
    int i, j;
    itype *WORK_IMAGE_PTR = fontImage + _Y(dy)*bSize;

    for( i=0; i<BAND_LEN; i++ ) {
        for( j=0; j<EDGE_CNT[i]; j+=2 ) {
            lineClear( WORK_IMAGE_PTR, _X(EDGE[i][j]+dx), _X(EDGE[i][j+1]+dx) );
            }
        WORK_IMAGE_PTR += bSize;
        }
    }

static void makeShadowImage()
    {
    setOutlineCopy( 1, shadowdx, shadowdy );
    if( !devCurAbsolute ) imgset( fontImage, 0, BAND_LEN*hyImageInfo.bSize );

    if( pattern < 0 ) {
        memcls( (char*)EDGE_CNT, BAND_LEN );
        rastGlyph2( GPOINT_CNT+10 );
        patternPixelToImage( bold, bold );
        }

    memcls( (char*)EDGE_CNT, BAND_LEN );

    switch( ( shadow + 3 ) / 4 ) {
        case 1:
            setOutlineCopy( 1, (int)shadowdx, (int)shadowdy );
            rastGlyph();
            edgeSort();
            putPixelToImage( CPYDX, CPYDY );
            clearPixelToImage( OGNDX, OGNDY, 1 );
            memcls( (char*)EDGE_CNT, BAND_LEN );
            CLEAROUTLINE = 1;
            setOutlineCopy( 0, (int)shadowdx, (int)shadowdy );
            rastGlyph();
            CLEAROUTLINE = 0;
            break;
        case 2:
            rastGlyph();
            edgeSort();
            clearPixelToImage( OGNDX, OGNDY, 1 );
            putPixelToImage( OGNDX, OGNDY );
            break;
        case 3:
            setOutlineMove( 1, CPYDX-OGNDX, CPYDY-OGNDY );
            rastGlyph();
            edgeSort();
            clearPixelToImage( OGNDX, OGNDY, 1 );
            memcls( (char*)EDGE_CNT, BAND_LEN );
            setOutlineCopy( 0, (int)shadowdx, (int)shadowdy );
            setOutlineMove( 0, 0, 0 );
            rastGlyph();
            break;
        case 4:  case 5:
            setOutlineMove( 1, CPYDX-OGNDX, CPYDY-OGNDY );
            rastGlyph();
            edgeSort();
            clearPixelToImage( OGNDX, OGNDY, 0 );
            setOutlineMove( 0, 0, 0 );
            break;
        }
    }

static void makeBandNormal( int start, int end )
    {
    setBand( start, end );

    if( shadow ) {
        makeShadowImage();
        }
    else {
        if( bold ) setOutlineCopy( 1, 0, 0 );
        if( !devCurAbsolute ) imgset( fontImage, 0, BAND_LEN*hyImageInfo.bSize );

        if( pattern < 0 ) {
            memcls( (char*)EDGE_CNT, BAND_LEN );
            rastGlyph2( GPOINT_CNT+10 );
            patternPixelToImage( bold, bold );
            }

        memcls( (char*)EDGE_CNT, BAND_LEN );
        rastGlyph();
        if( !outline ) {
            edgeSort();
            putPixelToImage( bold, bold );
            }
        }

    if( reverse ) {
        memcls( (char*)EDGE_CNT, BAND_LEN );
        rastGlyph2( GPOINT_CNT );
        xorPixelToImage( bold, bold );
        }

    if( view_area ) {
        memcls( (char*)EDGE_CNT, BAND_LEN );
        rastGlyph2( GPOINT_CNT+5 );
        clsPixelToImage( bold, bold );
        }

    if( pattern > 0 ) {
        int x, y;
        int m = physicalYPos & itypeMask;
        int l = physicalXPos & itypeMask;
        int r = itypeSize - l;
        itype *p = fontImage;
        for( y=0; y<BAND_LEN; y++,m++ ) {
            for( x=0; x<bSize; x++ ) {
                *p++ &= (hyAttribute.patternMask[m&itypeMask] << l)
                      | (hyAttribute.patternMask[m&itypeMask] >> r);
                }
            }
        }
    }

static void _PutOlFontImage( int xPos, int yPos, hyFontImage *font )
    {
    int b, y, yStart;
    int xEnd = xPos + font->xSize - 1;
    int yEnd = yPos + font->ySize - 1;
    int shift = xPos & itypeMask;
    unsigned char *image;
    unsigned char *pointer;

    if( xPos > devXMax ) return;
    if( yPos > devYMax ) return;
    if( xEnd < devXMin ) return;
    if( yEnd < devYMin ) return;

    yStart = yPos < devYMin ? devYMin : yPos;
    if( yEnd > devYMax ) yEnd = devYMax;

    if( xPos < devXMin || xEnd > devXMax ) {
        int c;
        int sb = (devXMin >> itypeShift);
        int eb = (devXMax >> itypeShift);
        if( xPos < devXMin ) sb++;
        if( xEnd > devXMax ) eb--;
        for( y=yStart; y<=yEnd; y++ ) {
            image   = font->image + (y-yPos)*font->bSize;
            pointer = devAddress  +  y*devBSize;
            c = xPos >> itypeShift;
            for( b=0; b<font->bSize; b++,c++,image++ ) {
                if( (c >= sb) && (c <= eb) )
                    pointer[c]   |= *image >> shift;
                if( (c+1 >= sb) && (c+1 <= eb) )
                    pointer[c+1] |= *image << (8-shift);
                }
            }
        if( xPos < devXMin ) {
            itype sm = leftMask(devXMin & itypeMask);
            sb--;
            for( y=yStart; y<=yEnd; y++ ) {
                image   = font->image + (y-yPos)*font->bSize;
                pointer = devAddress  +  y*devBSize;
                c = (xPos >> itypeShift);
                for( b=0; b<font->bSize; b++,c++,image++ ) {
                    if( c+1==sb ) {
                        pointer[c+1] ^= (*image << (8-shift)) & sm;
                        break;
                        }
                    }
                }
            for( y=yStart; y<=yEnd; y++ ) {
                image   = font->image + (y-yPos)*font->bSize;
                pointer = devAddress  +  y*devBSize;
                c = (xPos >> itypeShift);
                for( b=0; b<font->bSize; b++,c++,image++ ) {
                    if( c==sb ) {
                        pointer[c]   ^= (*image >> shift) & sm;
                        break;
                        }
                    }
                }
            }
        if( xEnd > devXMax ) {
            itype em = rightMask(devXMax & itypeMask);
            image = font->image + (yStart-yPos)*font->bSize;
            eb++;
            for( y=yStart; y<=yEnd; y++ ) {
                image   = font->image + (y-yPos)*font->bSize;
                pointer = devAddress  +  y*devBSize;
                c = xPos >> itypeShift;
                for( b=0; b<font->bSize; b++,c++,image++ ) {
                    if( c+1 == eb )
                        pointer[c+1] ^= (*image << (8-shift)) & em;
                    }
                }
            for( y=yStart; y<=yEnd; y++ ) {
                image   = font->image + (y-yPos)*font->bSize;
                pointer = devAddress  +  y*devBSize;
                c = xPos >> itypeShift;
                for( b=0; b<font->bSize; b++,c++,image++ ) {
                    if( c == eb )
                        pointer[c]   ^= (*image >> shift) & em;
                    }
                }
            }
        }
    else {
        image = font->image + (yStart-yPos)*font->bSize;
        for( y=yStart; y<=yEnd; y++ ) {
            pointer = devAddress + y*devBSize + (xPos >> itypeShift);
            for( b=0; b<font->bSize; b++ ) {
                *pointer++ |= *image   >> shift;
                *pointer   |= *image++ << (8-shift);
                }
            }
        }
    }

static void makeBandAttr()
    {
    drawLINETO = drawLINETOAttr;

    if( !hyImageInfo.tooLarge ) {
        makeBandNormal( 0, hyImageInfo.ySize );
        if( !devCurAbsolute ) _PutOlFontImage( devXPos+hyImageInfo.xDelta, devYPos+hyImageInfo.yDelta, &hyImageInfo );
        }
    else {
        int psy_xpos = devXPos + hyImageInfo.xDelta;
        int psy_ypos = devYPos + hyImageInfo.yDelta;
        int i, height = hyImageInfo.ySize;
        int bandsize, step, bandgap = 0;
        int bandgaplen = 0;

        step = maxBitmapSize;
        if( hyImageInfo.bSize*step > fontBufferSize ) step = fontBufferSize / hyImageInfo.bSize;

        hyImageInfo.totalBand--;
        hyImageInfo.totalBand += (height + step - 1) / step;
        if( shadow || bold ) {
            hyImageInfo.totalBand++;
            if( shadow ) setOutlineCopy( 1, (int)shadowdx, (int)shadowdy );
            bandgap = ( ( CPYDY > OGNDY ) ? CPYDY : OGNDY ) + bold;
            bandgaplen = bandgap * hyImageInfo.bSize;
            step -= ( bandgap * 2 );
            bandsize = bandgap;
            makeBandNormal( 0, bandsize );
            hyImageInfo.ySize = bandsize;
            if( devCurAbsolute ) devYDelta += bandsize;
            else _PutOlFontImage( psy_xpos, psy_ypos, &hyImageInfo );
            psy_ypos     += bandsize;
            hyImageInfo.bandCount++;
            }
        if( step < bandgap * 2 || step < 1 ) {
            return;
            }

        for( i=0; height>0; i++, height-=step ) {
            bandsize = ( ( height < step ) ? height : step );
            makeBandNormal( i*step, i*step+bandsize+bandgap );
            hyImageInfo.ySize = bandsize;
            hyImageInfo.image += bandgaplen;
            if( devCurAbsolute ) devYDelta += bandsize;
            else _PutOlFontImage( psy_xpos, psy_ypos, &hyImageInfo );
            hyImageInfo.image -= bandgaplen;
            psy_ypos     += bandsize;
            physicalYPos += bandsize;
            hyImageInfo.bandCount++;
            }
        }
    }

static void gridFitOneGlyph( unsigned char *data )
    {
    unsigned char OpCode;
    wtype cx, mx, x;
    wtype cy, my, y;
    #define addPoint(xx,yy,aa) \
        if( GPOINT_XMIN > xx ) GPOINT_XMIN = xx; \
        if( GPOINT_XMAX < xx ) GPOINT_XMAX = xx; \
        if( GPOINT_YMIN > yy ) GPOINT_YMIN = yy; \
        if( GPOINT_YMAX < yy ) GPOINT_YMAX = yy; \
        GPOINT_COORD[GPOINT_CNT].x = xx; \
        GPOINT_COORD[GPOINT_CNT].y = yy; \
        GPOINT_ATTR[GPOINT_CNT++] = aa

    cx = cy = mx = my = 0;
    CurP.b = data;
    localVSTEM = globalVSTEM =
    localHSTEM = globalHSTEM = 0;

    while( 1 ) {
        OpCode = getByte();
        if( OpCode == PCEndChar ) break;
        switch( OpCode ) {
            case PCClear:
                cx = cy = mx = my = 0;
                localVSTEM = globalVSTEM =
                localHSTEM = globalHSTEM = 0;
                break;
            case PCRMoveTo:
                mx = cx += getNum();
                my = cy += getNum();
                gridFit(cx,cy);
                addPoint( pp.x, pp.y, PCRMoveTo );
                break;
            case PCClosePath:
                localVSTEM = globalVSTEM;
                localHSTEM = globalHSTEM;
                cx = mx; cy = my;
                gridFit(cx,cy);
                addPoint( pp.x, pp.y, PCClosePath );
                break;
            case PCRLineTo:
                cx += getNum();
                cy += getNum();
                gridFit(cx,cy);
                addPoint( pp.x, pp.y, PCRLineTo );
                break;
            case PCRRCurveTo:
                cx += getNum();
                cy += getNum();
                gridFit(cx,cy);
                addPoint( pp.x, pp.y, PCRRCurveTo );
                cx += getNum();
                cy += getNum();
                gridFit(cx,cy);
                addPoint( pp.x, pp.y, PCRRCurveTo );
                cx += getNum();
                cy += getNum();
                gridFit(cx,cy);
                addPoint( pp.x, pp.y, PCRLineTo );
                break;
            case _lsVhint:
                x = getWord();
                y = getWord();
                addVSTEM( x, y, &localVSTEM );
                break;
            case _lsHhint:
                x = getWord();
                y = getWord();
                addHSTEM( x, y, &localHSTEM );
                break;
            case _gsVhint:
                x = getWord();
                y = getWord();
                addVSTEM( x, y, &globalVSTEM );
                localVSTEM++;
                break;
            case _gsHhint:
                x = getWord();
                y = getWord();
                addHSTEM( x, y, &globalHSTEM );
                localHSTEM++;
                break;
            }
        }
    #undef addPoint
    }

static void gridFitGlyph( int from, int to )
    {
    int i;
    wtype x0, y0;

    hyImageInfo.t = hyAttribute.t[hyImageInfo.index[0]];

    GPOINT_CNT = 0;
    GPOINT_XMIN = x0 = xGridUnit( hyImageInfo.emXSize );
    GPOINT_YMIN = y0 = yGridUnit( hyImageInfo.emYSize );
    GPOINT_XMAX = 0;
    GPOINT_YMAX = 0;

    for( i=from; i<=to; i++ ) {
        hyImageInfo.data = hrfReadOneGlyf( curr_hrf, hyImageInfo.index[i] );
        if( hyImageInfo.data ) {
            gridFitOneGlyph( hyImageInfo.data );
            }
        }

    if( reverse ) {
        int xmin = 0;
        int ymin = 0;
        int xmax = hyImageInfo.width;
        int ymax = hyImageInfo.emYSize;
        if(      reverse == down_reverse  ) ymin = ymax / 2;
        else if( reverse == up_reverse    ) ymax = ymax / 2;
        if(      reverse == right_reverse ) xmin = xmax / 2;
        else if( reverse == left_reverse  ) xmax = xmax / 2;
        i = GPOINT_CNT;
        gridUnit( xmin, ymin );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        gridUnit( xmin, ymax );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        gridUnit( xmax, ymax );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        gridUnit( xmax, ymin );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        GPOINT_COORD[i] = GPOINT_COORD[GPOINT_CNT];
        }

    if( view_area ) {
        int xmin = 0;
        int ymin = 0;
        int xmax = hyImageInfo.width;
        int ymax = hyImageInfo.emYSize;
        if( view_area == up_char_view ) ymin = ymax / 2;
        else                            ymax = ymax / 2;
        i = GPOINT_CNT+5;
        gridUnit( xmin, ymin );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        gridUnit( xmin, ymax );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        gridUnit( xmax, ymax );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        gridUnit( xmax, ymin );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        GPOINT_COORD[i] = GPOINT_COORD[GPOINT_CNT+5];
        }

    if( pattern < 0 ) {
        int xmin = 0;
        int ymin = 0;
        int xmax = hyImageInfo.width;
        int ymax = hyImageInfo.emYSize;
        i = GPOINT_CNT+10;
        gridUnit( xmin, ymin );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        gridUnit( xmin, ymax );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        gridUnit( xmax, ymax );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        gridUnit( xmax, ymin );
        GPOINT_COORD[i].x = pp.x; GPOINT_COORD[i].y = pp.y;
        if( GPOINT_XMIN > GPOINT_COORD[i].x ) GPOINT_XMIN = GPOINT_COORD[i].x;
        if( GPOINT_XMAX < GPOINT_COORD[i].x ) GPOINT_XMAX = GPOINT_COORD[i].x;
        if( GPOINT_YMIN > GPOINT_COORD[i].y ) GPOINT_YMIN = GPOINT_COORD[i].y;
        if( GPOINT_YMAX < GPOINT_COORD[i].y ) GPOINT_YMAX = GPOINT_COORD[i].y; i++;
        GPOINT_COORD[i] = GPOINT_COORD[GPOINT_CNT+10];
        }

    if( GPOINT_XMIN == x0 && GPOINT_YMIN == y0 ) return;

    GPOINT_XMIN = xPixelUnitS(GPOINT_XMIN) * hyImageInfo.emXSize;
    GPOINT_YMIN = yPixelUnitS(GPOINT_YMIN) * hyImageInfo.emYSize;
    gridUnit2( 0, -hyImageInfo.emYSize*_BASELINE_RATIO/100 );
    hyImageInfo.xDelta = pp.x + GPOINT_XMIN;
    hyImageInfo.yDelta = pp.y + GPOINT_YMIN;
    hyImageInfo.xDelta = xPixelUnitS(hyImageInfo.xDelta) - bold + (shadowdx<0?shadowdx:0);
    hyImageInfo.yDelta = yPixelUnitS(hyImageInfo.yDelta) - bold + (shadowdy<0?shadowdy:0);
    hyImageInfo.xSize  = xPixelUnitS(GPOINT_XMAX)-xPixelUnitS(GPOINT_XMIN)+1 + ABS(shadowdx) + bold*2;
    hyImageInfo.ySize  = yPixelUnitS(GPOINT_YMAX)-yPixelUnitS(GPOINT_YMIN)+1 + ABS(shadowdy) + bold*2;
    hyImageInfo.bSize  = alignSize( hyImageInfo.xSize );

    for( i=GPOINT_CNT+14; i>=0; i-- ) {
        GPOINT_COORD[i].x -= GPOINT_XMIN;
        GPOINT_COORD[i].y -= GPOINT_YMIN;
        }

    if( !devCurAbsolute ||
        (devXPos + hyImageInfo.xDelta < devXMin) ||
        (devYPos + hyImageInfo.yDelta < devYMin) ||
        (devXPos + hyImageInfo.xDelta + hyImageInfo.ySize - 1 > devXMax) ||
        (devYPos + hyImageInfo.yDelta + hyImageInfo.ySize - 1 > devYMax) ) {
        devCurAbsolute = 0;
        hyImageInfo.image = fontImage = IMAGE_BUFFER;
        bSize = hyImageInfo.bSize;
        devXDelta = 0;
        devYDelta = 0;
        if( hyImageInfo.bSize*hyImageInfo.ySize > fontBufferSize ||
            hyImageInfo.ySize > maxBitmapSize ) {
            hyImageInfo.tooLarge = 1;
            }
        else {
            hyImageInfo.tooLarge = 0;
            }
        }
    else {
        hyImageInfo.image = fontImage = devAddress;
        bSize = devBSize;
        devXDelta = devXPos + hyImageInfo.xDelta;
        devYDelta = devYPos + hyImageInfo.yDelta;
        if( hyImageInfo.ySize > maxBitmapSize ) hyImageInfo.tooLarge = 1;
        else hyImageInfo.tooLarge = 0;
        }

    physicalXPos = devXPos + hyImageInfo.xDelta;
    physicalYPos = devYPos + hyImageInfo.yDelta;
    }

static void makeBitmapNormal( int from, int to )
    {
    gridFitGlyph( from, to );
    if( hyImageInfo.tooLarge ) makeBandAttr();
    else {
        drawLINETO = drawLINETONormal;
        makeBandNormal( 0, hyImageInfo.ySize );
        }
    }

static void makeBitmapAttr( int from, int to )
    {
    gridFitGlyph( from, to );
    makeBandAttr();
    }

/****** Global Function Define ******/

void setDeviceConfig( unsigned long address,
                      int bSize,
                      int xMin, int yMin, int xMax, int yMax )
    {
    devAddress = (itype *)address;
    devBSize   = bSize;
    devXMin    = xMin;
    devYMin    = yMin;
    devXMax    = xMax;
    devYMax    = yMax;
    devXSize   = devXMax - devXMin;
    devYSize   = devYMax - devYMin;

    hySetLineThickness( 1 );
    hySetFillMode( 1, 0 );
    hySetPatternType( 0 );
    hySetGrayLevel( 30 );
    GS_DEPTH = ((unsigned long)(&hyRasterizerBuffer+1) - (unsigned long)GS_EDGE)
               / sizeof(GS_EDGE);
    }

hyFontImage *hyPrepareFontImage( int xPos, int yPos, unsigned int code )
    {
    hyImageInfo.image  = 0;
    hyImageInfo.mask   = 0;
    hyImageInfo.xSize  = 0;
    hyImageInfo.ySize  = 0;
    hyImageInfo.bSize  = 0;
    hyImageInfo.xInc   = 0;
    hyImageInfo.yInc   = 0;
    hyImageInfo.status = validStatus;

    curr_hrf = hrfReadCharIndex( code );
    if( !curr_hrf ) return( 0 );

    hyImageInfo.emXSize = SWAPW(curr_hrf->hy_font->header.emXSize);
    hyImageInfo.emYSize = SWAPW(curr_hrf->hy_font->header.emYSize);
    hyImageInfo.width   = hrfReadWidth( curr_hrf, hyImageInfo.index[1] );
    hyImageInfo.height  = hyImageInfo.emYSize;
    hyImageInfo.mask    = hyAttribute.mask[hyImageInfo.index[0]];
    hyImageInfo.t       = hyAttribute.t[hyImageInfo.index[0]];

    gridUnit2( hyImageInfo.width, 0 );
    hyImageInfo.xInc = xPixelUnitS( pp.x );
    hyImageInfo.yInc = yPixelUnitS( pp.y );

    if( hyAttribute.orientation == orientation_0 ) {
        xPos = devXMin + xPos;
        yPos = devYMin + yPos;
        }
    else if( hyAttribute.orientation == orientation_90 ) {
        TEMP_VAL = xPos;
        xPos = devXMin + yPos;
        yPos = devYMin + devYSize - TEMP_VAL;
        }
    else if( hyAttribute.orientation == orientation_180 ) {
        xPos = devXMin + devXSize - xPos;
        yPos = devYMin + devYSize - yPos;
        }
    else if( hyAttribute.orientation == orientation_270 ) {
        TEMP_VAL = xPos;
        xPos = devXMin + devXSize - yPos;
        yPos = devYMin + TEMP_VAL;
        }

    switch( hyAttribute.orientation ) {
        case orientation_0:
            if( xPos + hyImageInfo.xInc  > devXMax ) { hyImageInfo.status |= lineOver; yPos += hyAttribute.ySize; }
            if( yPos + hyAttribute.ySize > devYMax )   hyImageInfo.status |= pageOver;
            break;
        case orientation_90:
            if( yPos + hyImageInfo.yInc  < devYMin ) { hyImageInfo.status |= lineOver; xPos += hyAttribute.ySize; }
            if( xPos + hyAttribute.ySize > devXMax )   hyImageInfo.status |= pageOver;
            break;
        case orientation_180:
            if( xPos + hyImageInfo.xInc  < devXMin ) { hyImageInfo.status |= lineOver; yPos -= hyAttribute.ySize; }
            if( yPos - hyAttribute.ySize < devYMin )   hyImageInfo.status |= pageOver;
            break;
        case orientation_270:
            if( yPos + hyImageInfo.yInc  > devYMax ) { hyImageInfo.status |= lineOver; xPos -= hyAttribute.ySize; }
            if( xPos - hyAttribute.ySize < devXMin )   hyImageInfo.status |= pageOver;
            break;
        }

    if( hyAttribute.orientation == orientation_0 ) {
        }
    else if( hyAttribute.orientation == orientation_90 ) {
        TEMP_VAL = hyImageInfo.xInc;
        hyImageInfo.xInc = -hyImageInfo.yInc;
        hyImageInfo.yInc = TEMP_VAL;
        }
    else if( hyAttribute.orientation == orientation_180 ) {
        hyImageInfo.xInc = -hyImageInfo.xInc;
        hyImageInfo.yInc = -hyImageInfo.yInc;
        }
    else if( hyAttribute.orientation == orientation_270 ) {
        TEMP_VAL = hyImageInfo.xInc;
        hyImageInfo.xInc = hyImageInfo.yInc;
        hyImageInfo.yInc = -TEMP_VAL;
        }

    return( &hyImageInfo );
    }

hyFontImage *hyMakeFontImage( int xPos, int yPos,
                              int compelNormal,
                              int absolute )
    {
    int hyDrawUnderline( int x0, int y0, int x1, int y1 );
    int i, cacheOn = hyCache.enabled & curr_hrf->cacheOn;

    if( hyAttribute.orientation == orientation_0 ) {
        xPos = devXMin + xPos;
        yPos = devYMin + yPos;
        }
    else if( hyAttribute.orientation == orientation_90 ) {
        TEMP_VAL = xPos;
        xPos = devXMin + yPos;
        yPos = devYMin + devYSize - TEMP_VAL;
        }
    else if( hyAttribute.orientation == orientation_180 ) {
        xPos = devXMin + devXSize - xPos;
        yPos = devYMin + devYSize - yPos;
        }
    else if( hyAttribute.orientation == orientation_270 ) {
        TEMP_VAL = xPos;
        xPos = devXMin + devXSize - yPos;
        yPos = devYMin + TEMP_VAL;
        }

    if( hyImageInfo.nIndex < 3 ) {
        return( &hyImageInfo );
        }

    bold = 0;
    shadowdx = 0;
    shadowdy = 0;

    if( compelNormal ) {
        shadow    = 0;
        outline   = 0;
        pattern   = 0;
        underline = 0;
        view_area = 0;
        cacheOn = hyCache.enabled;
        if( hyAttribute.xSize < hyCache.lowestSize  ) cacheOn = 0;
        if( hyAttribute.xSize > hyCache.highestSize ) cacheOn = 0;
        if( hyAttribute.ySize < hyCache.lowestSize  ) cacheOn = 0;
        if( hyAttribute.ySize > hyCache.highestSize ) cacheOn = 0;
        }
    else {
        shadow    = hyAttribute.shadow;
        outline   = hyAttribute.outline;
        reverse   = hyAttribute.reverse;
        pattern   = hyAttribute.pattern;
        underline = hyAttribute.underline;
        view_area = hyAttribute.view_area;
        if( outline ) {
            hyImageInfo.mask &= ~hyAttrBoldMask;
            bold = 0;
            }
        if( hyImageInfo.mask & hyAttrBoldMask ) {
            bold = (hyAttribute.xSize + hyAttribute.ySize) / 320 + 1;
            }
        if( shadow ) {
            hyImageInfo.mask &= ~hyAttrShadowMask;
            shadowdx = hyImageInfo.emXSize / 100;
            shadowdy = hyImageInfo.emYSize / 100;
            if( ((shadow + 3) / 4) == 4 ) {
                shadowdx = shadowdy = 1;
                }
            switch( shadow % 4 ) {
                case 1: shadowdy *= (-1); break;
                case 2: shadowdx *= (-1); shadowdy *= (-1); break;
                case 3: shadowdx *= (-1); break;
                }
            gridUnit( shadowdx, shadowdy );
            shadowdx = xPixelUnitS(pp.x) + 1;
            shadowdy = yPixelUnitS(pp.y) + 1;
            bold = 0;
            }
        }

    if( underline ) {
        int y = hyImageInfo.emYSize*(100-hyAttribute.underlinePos-_BASELINE_RATIO)/100;
        int x0, y0, x1, y1;
        gridUnit2( 0, y );
        x0 = xPixelUnitS( pp.x );
        y0 = yPixelUnitS( pp.y );
        gridUnit2( hyImageInfo.width, y );
        x1 = xPixelUnitS( pp.x );
        y1 = yPixelUnitS( pp.y );
        hyDrawUnderline( xPos+x0, yPos+y0, xPos+x1, yPos+y1 );
        }

    if( !(hyAttribute.rotate % 90) ) hyImageInfo.mask &= ~hyAttrRotateMask;

    devXPos = xPos;
    devYPos = yPos;
    devOgnAbsolute =
    devCurAbsolute = absolute;

    setOutlineCopy( 0, 0, 0 );
    hyImageInfo.totalBand = 1;
    hyImageInfo.bandCount = 0;

    if( bold || shadow || reverse || pattern || view_area ) {
        if( reverse || pattern || view_area ) devOgnAbsolute = devCurAbsolute = 0;
        makeBitmapAttr( 2, hyImageInfo.nIndex-1 );
        }
    else {
#ifdef _MAKE_WHOLE_IMAGE
        if( cacheOn ) {
            devCurAbsolute = 0;
            if( !hyCacheHit( curr_hrf, hyImageInfo.index[1], &hyImageInfo ) ) {
                makeBitmapNormal( 2, hyImageInfo.nIndex-1 );
                if( hyImageInfo.tooLarge ) goto END;
                hyCacheAdd( curr_hrf, hyImageInfo.index[1], &hyImageInfo );
                }
            _PutOlFontImage( devXPos+hyImageInfo.xDelta, devYPos+hyImageInfo.yDelta, &hyImageInfo );
            }
        else {
            makeBitmapNormal( 2, hyImageInfo.nIndex-1 );
            if( hyImageInfo.tooLarge ) goto END;
            if( !devCurAbsolute ) _PutOlFontImage( devXPos+hyImageInfo.xDelta, devYPos+hyImageInfo.yDelta, &hyImageInfo );
            }
#else
        hyImageInfo.totalBand = hyImageInfo.nIndex - 2;
        for( i=2; i<hyImageInfo.nIndex; i++,hyImageInfo.bandCount++ ) {
            if( cacheOn ) {
                devCurAbsolute = 0;
                if( !hyCacheHit( curr_hrf, hyImageInfo.index[i], &hyImageInfo ) ) {
                    makeBitmapNormal( i, i );
                    if( hyImageInfo.tooLarge ) continue;
                    hyCacheAdd( curr_hrf, hyImageInfo.index[i], &hyImageInfo );
                    }
                _PutOlFontImage( devXPos+hyImageInfo.xDelta, devYPos+hyImageInfo.yDelta, &hyImageInfo );
                }
            else {
                makeBitmapNormal( i, i );
                if( hyImageInfo.tooLarge ) continue;
                if( !devCurAbsolute ) _PutOlFontImage( devXPos+hyImageInfo.xDelta, devYPos+hyImageInfo.yDelta, &hyImageInfo );
                }
            }
#endif
        }

#ifdef _MAKE_WHOLE_IMAGE
    END:
#endif

    return( &hyImageInfo );
    }

hyFontImage *hyGetFontImage( int xPos, int yPos,
                             unsigned int code,
                             int compelNormal,
                             int absolute )
    {
    if( !hyPrepareFontImage(xPos,yPos,code) ) return( 0 );
    return hyMakeFontImage( xPos, yPos, compelNormal, absolute );
    }

itype *hyGetFontImageBuffer( void )
    {
    return IMAGE_BUFFER;
    }

void *hyGetRasterizerBuffer( int *size )
    {
    if( size ) *size = sizeof(hyRasterizerBuffer);
    return (void *)&hyRasterizerBuffer;
    }

static void _hySetFillMask( itype *d, unsigned char *s )
    {
    int i, j;
    itype m = 0;
    for( i=0; i<itypeSize; i++ ) {
        for( j=0; j<itypeBytes; j++ ) m = (m<<8) | s[i%8];
        d[i] = m;
        }
    }

#undef EDGE
#undef EDGE_CNT
#define EDGE(y,x)       GS_EDGE[y][x+1]
#define EDGE_CNT(y)     GS_EDGE[y][0]

static void _quickSort( int min, int max, short *desc_x )
    {
    int i, j;
    int x;
    int itmp;

    if( min >= max ) return;

    i = min;
    j = max;
    x = desc_x[max];

    while( i < j ) {
        while( i<j && desc_x[i] <= x )
            i++;
        while( i<j && desc_x[j] >= x )
            j--;
        if( i<j ) {
            itmp = desc_x[i];
            desc_x[i] = desc_x[j];
            desc_x[j] = itmp;
            }
        }
    itmp = desc_x[i];
    desc_x[i] = desc_x[max];
    desc_x[max] = itmp;

    _quickSort( min, i-1, desc_x );
    _quickSort( i+1, max, desc_x );
    }

static void _edgeSort( void )
    {
    int i;
    for( i=0; i<BAND_LEN; i++ ) _quickSort( 0, EDGE_CNT(i)-1, &EDGE(i,0) );
    }

static void _set_edge( int x, int y, int d )
    {
    if( (y=isInBand(y)) < 0 ) return;
    EDGE(y,EDGE_CNT(y)++) = x;
    }

#define _set_edge_null       set_edge_null

#define _set_font_pixel_null set_font_pixel_null

static void _set_font_pixel( int x, int y )
    {
    int e, t;

    if( (y=isInBand(y)) < 0 ) return;
    for( e=0; e<EDGE_CNT(y); e+=2 ) {
        if( (x >= EDGE(y,e)) && (x <= EDGE(y,e+1)) ) return;
        if( x == EDGE(y,e)-1 )   { EDGE(y,e)   = x; return; }
        if( x == EDGE(y,e+1)+1 ) { EDGE(y,e+1) = x; return; }
        if( EDGE(y,e) >  x ) {
            for( t=EDGE_CNT(y)-1; t>=e; t-- ) {
                EDGE(y,t+1) = EDGE(y,t-1);
                EDGE(y,t+2) = EDGE(y,t);
                }
            break;
            }
        }
    EDGE(y,e)   = x;
    EDGE(y,e+1) = x;
    EDGE_CNT(y) += 2;
    }

static void _set_font_pixel_outline( int x, int y )
    {
    if( (y=isInBand(y)) < 0 ) return;
    if( x < devXMin ) return;
    if( x > devXMax ) return;
    if( y < devYMin ) return;
    if( y > devYMax ) return;
    if( GS.lineThickness == 1 ) {
        setFontPixel( x, y );
        }
    else {
        _PutOlFontImage( x+GS.olMask.info.xDelta, y+GS.olMask.info.yDelta, &GS.olMask.info );
        }
    }

static void _set_font_pixel_underline( int x, int y )
    {
    if( (y=isInBand(y)) < 0 ) return;
    if( x < devXMin ) return;
    if( x > devXMax ) return;
    if( y < devYMin ) return;
    if( y > devYMax ) return;
    if( underline == 1 ) {
        setFontPixel( x, y );
        }
    else {
        hyFontImage f;
        f.xSize  = underline+1;
        f.ySize  = underline+1;
        f.bSize  = alignSize(underline);
        f.image = fat_mask+(underline-1)*8;
        f.xDelta = -underline/2;
        f.yDelta = -underline/2;
        _PutOlFontImage( x+f.xDelta, y+f.yDelta, &f );
        }
    }

static int SIDE( int x, int y )
    {
    int side = ELL_PX*y - ELL_PY*x;
    if( side > 0 ) return  1;
    if( side < 0 ) return -1;
    return 0;
    }

static int _valid_ellipse_point( int x, int y )
    {
    int side;
    if( ELL_STATUS < 0 ) return( 1 );

    x -= ELL_OX;
    y -= ELL_OY;

    side = SIDE( x, y );
    if( ELL_STATUS == 2 ) {
        if( side ) {
            if( ELL_SIDE ) {
                if( ELL_SIDE != side ) {
                    ELL_PX = ELL_EX;
                    ELL_PY = ELL_EY;
                    ELL_SIDE = SIDE( x, y );
                    ELL_STATUS--;
                    return( 1 );
                    }
                }
            else {
                ELL_SIDE = side;
                }
            }
        else {
            int p = ELL_PX*x + ELL_PY*y;
            if( p > 0 ) {
                ELL_PX = ELL_EX;
                ELL_PY = ELL_EY;
                ELL_SIDE = SIDE( x, y );
                ELL_STATUS--;
                return( 1 );
                }
            }
        return( 0 );
        }

    if( ELL_STATUS == 1 ) {
        if( side ) {
            if( ELL_SIDE ) {
                int p = ELL_PX*x + ELL_PY*y;
                if( p > 0 ) {
                    if( ELL_SIDE != side  ) {
                        ELL_STATUS--;
                        }
                    }
                }
            ELL_SIDE = side;
            }
        else {
            int p = ELL_PX*x + ELL_PY*y;
            if( p > 0 ) {
                ELL_STATUS--;
                }
            }
        return( 1 );
        }

    return( 0 );
    }

static int valid_ellipse_point( int x, int y )
    {
    int r = _valid_ellipse_point( x, y );
    return r;
    }

static void _set_edge_ellipse( int x, int y, int d )
    {
    if( valid_ellipse_point(x,y) ) {
        _set_edge( x, y, d );
        }
    }

static void _set_font_pixel_ellipse( int x, int y )
    {
    if( valid_ellipse_point(x,y) )
        _set_font_pixel( x, y );
    }

static void _set_font_pixel_null_ellipse( int x, int y )
    {
    valid_ellipse_point(x,y);
    }

static void _set_font_pixel_outline_ellipse( int x, int y )
    {
    if( valid_ellipse_point(x,y) )
        _set_font_pixel_outline( x, y );
    }

static void _set_font_pixel_outline_ellipse1( int x, int y )
    {
    if( valid_ellipse_point(x,y) )
        _set_font_pixel_outline( x, y );
    }

static void _putPixelToImage( int dy )
    {
    int i, j, x1, x2, y = _Y(dy);
    itype *WORK_IMAGE_PTR = fontImage + y*bSize;

    for( i=0; i<BAND_LEN; i++,y++,WORK_IMAGE_PTR+=bSize ) {
        if( y < devYMin ) continue;
        if( y > devYMax ) break;
        for( j=0; j<EDGE_CNT(i); j+=2 ) {
            x1 = _X( EDGE(i,j) );
            x2 = _X( EDGE(i,j+1) );
            if( x1 > devXMax ) break;
            if( x2 < devXMin ) continue;
            if( x1 < devXMin ) x1 = devXMin;
            if( x2 > devXMax ) x2 = devXMax;
            lineFillPattern( WORK_IMAGE_PTR, x1, x2, GS.fillMask[y&itypeMask] );
            }
        }
    }

static void _clearPixelToImage( int dy )
    {
    int i, j, x1, x2, y = _Y(dy);
    itype *WORK_IMAGE_PTR = fontImage + y*bSize;

    for( i=0; i<BAND_LEN; i++,y++,WORK_IMAGE_PTR+=bSize ) {
        if( y < devYMin ) continue;
        if( y > devYMax ) break;
        for( j=0; j<EDGE_CNT(i); j+=2 ) {
            x1 = _X( EDGE(i,j) );
            x2 = _X( EDGE(i,j+1) );
            if( x1 > devXMax ) break;
            if( x2 < devXMin ) continue;
            if( x1 < devXMin ) x1 = devXMin;
            if( x2 > devXMax ) x2 = devXMax;
            lineClear( WORK_IMAGE_PTR, x1, x2 );
            }
        }
    }

static void (*ell_point)( wtype x, wtype y );

static void ell_line( wtype x, wtype y )
    {
    _drawLINETODummy( x, y );
    }

static void ell_move( wtype x, wtype y )
    {
    if( valid_ellipse_point(x,y) ) {
        _drawMOVETO( x, y );
        ell_point = ell_line;
        }
    }

static void ell( int type, int x, int y, int a, int b, int start, int end )
    {
    int  t, q, sx, sy;
    int  Limit, zz, vv ,*px, *py;
    long ll, ss, di, d, dt;

    ell_point = ell_move;

    ELL_STATUS = 2;
    if( type == circle ) ELL_STATUS = -1;
    else end += 89;
    ELL_PX = ELL_SX;
    ELL_PY = ELL_SY;
    ELL_SIDE = 0;

    for( t=start; t<end && ELL_STATUS; t+=90 ) {
        q = (t % 360) / 90;
        Limit = 0;
        zz = 0;
        if( q & 1 ) {
            px = &zz; py = &vv;
            vv = b;
            ll = a*a;
            ss = b*b;
            di = ss - 2*ll*b + ll;
            if( q >> 1 ) { sx = +1; sy = +1; }  /* 3 -> 4 */
            else         { sx = -1; sy = -1; }  /* 1 -> 2 */
            }
        else {
            px = &vv; py = &zz;
            vv = a;
            ll = b*b;
            ss = a*a;
            di = ss - 2*ll*a + ll;
            if( q >> 1 ) { sx = -1; sy = +1; }  /* 2 -> 3 */
            else         { sx = +1; sy = -1; }  /* 0 -> 1 */
            }
        for(;ELL_STATUS;) {
            ell_point( x+sx*(*px), y+sy*(*py) );
            if( vv <= Limit ) break;
            if( di < 0 ) {
                d = 2*di + 2*vv*ll - ll;
                if( d <= 0 ) {
                    zz = zz + 1;
                    di = di + 2*zz*ss + ss;
                    }
                if( d > 0 ) {
                    zz = zz + 1;
                    vv = vv - 1;
                    di = di + 2*zz*ss - 2*vv*ll + ll + ss;
                    }
                }
            if( di > 0 ) {
                dt = 2*di - 2*zz*ss - ss;
                if( dt <= 0 ) {
                    zz = zz + 1;
                    vv = vv - 1;
                    di = di + 2*zz*ss - 2*vv*ll + ll + ss;
                    }
                if( dt > 0 ) {
                    vv = vv -1;
                    di = di - 2*vv*ll + ll;
                    }
                }
            if( di == 0 ) {
                zz = zz + 1;
                vv = vv - 1;
                di = di + 2*zz*ss - 2*vv*ll + ll + ss;
                }
            }
        }
    }

static void _set_font_pixel_mask( int x, int y )
    {
    if( (y=isInBand(y)) < 0 ) return;
    setFontPixel(x,y);
    }

int hyDrawUnderline( int x0, int y0, int x1, int y1 )
    {
    fontImage = devAddress;
    bSize     = devBSize;
    devXDelta = 0;
    devYDelta = 0;

    setBand( 0, 0x7fffU );

    _setEdge      = _set_edge_null;
    _setFontPixel = _set_font_pixel_underline;
    _setFontPixel(    x0, y0 );
    _drawMOVETO(      x0, y0 );
    _drawLINETODummy( x1, y1 );
    return( 1 );
    }

int hySetLineThickness( int lineThickness )
    {
    if( lineThickness > maxThickness-1 ) lineThickness = maxThickness-1;
    if( GS.lineThickness != lineThickness ) {
        GS.lineThickness = lineThickness;
        GS.olMask.info.xSize  = lineThickness+1;
        GS.olMask.info.ySize  = lineThickness+1;
        GS.olMask.info.bSize  = alignSize(lineThickness);
        GS.olMask.info.image  = GS.olMask.image;
        GS.olMask.info.xDelta = -lineThickness/2;
        GS.olMask.info.yDelta = -lineThickness/2;
        if( lineThickness > 8 ) {
            fontImage = GS.olMask.info.image;
            bSize     = GS.olMask.info.bSize;
            devXDelta = 0;
            devYDelta = 0;
            setBand( 0, GS.olMask.info.ySize );
            imgset( fontImage, 0, BAND_LEN*GS.olMask.info.bSize );
            memcls( (char*)REDGE_CNT, BAND_LEN );
            _setEdge      = set_edge;
            _setFontPixel = _set_font_pixel_mask;
            ell( circle, lineThickness/2, lineThickness/2,
                         lineThickness/2, lineThickness/2, 0, 360 );
            edgeSort();
            putPixelToImage( 0, 0 );
            }
        else {
            GS.olMask.info.image = fat_mask+(lineThickness-1)*8;
            }
        }
    return( 1 );
    }

int hySetFillMode( int isDrawOutline, int fillMode )
    {
    GS.isDrawOutline = isDrawOutline;
    GS.fillMode      = fillMode;
    if(      GS.fillMode == patternFill ) GS.fillMask = hyAttribute.patternMask;
    else if( GS.fillMode == grayFill )    GS.fillMask = GS.grayMask;
    return( 1 );
    }

int hySetPatternType( int n )
    {
    GS.patternType = n;
    _hySetFillMask( hyAttribute.patternMask, pattern_mask+n*8 );
    return( 1 );
    }

int hySetGrayLevel( int level )
    {
    GS.grayLevel = level = level / 10;
    _hySetFillMask( GS.grayMask, gray_mask+level*8 );
    return( 1 );
    }

int hyDrawLine( int x0, int y0, int x1, int y1 )
    {
    if( hyAttribute.pageOrientation == orientation_0 ) {
        x0 = devXMin + x0;
        y0 = devYMin + y0;
        x1 = devXMin + x1;
        y1 = devYMin + y1;
        }
    else if( hyAttribute.pageOrientation == orientation_90 ) {
        TEMP_VAL = x0;
        x0 = devXMin + y0;
        y0 = devYMin + devYSize - TEMP_VAL;
        TEMP_VAL = x1;
        x1 = devXMin + y1;
        y1 = devYMin + devYSize - TEMP_VAL;
        }
    else if( hyAttribute.pageOrientation == orientation_180 ) {
        x0 = devXMin + devXSize - x0;
        y0 = devYMin + devYSize - y0;
        x1 = devXMin + devXSize - x1;
        y1 = devYMin + devYSize - y1;
        }
    else if( hyAttribute.pageOrientation == orientation_270 ) {
        TEMP_VAL = x0;
        x0 = devXMin + devXSize - y0;
        y0 = devYMin + TEMP_VAL;
        TEMP_VAL = x1;
        x1 = devXMin + devXSize - y1;
        y1 = devYMin + TEMP_VAL;
        }

    fontImage = devAddress;
    bSize     = devBSize;
    devXDelta = 0;
    devYDelta = 0;

    setBand( 0, 0x7fffU );

    _setEdge      = _set_edge_null;
    _setFontPixel = _set_font_pixel_outline;
    _setFontPixel(    x0, y0 );
    _drawMOVETO(      x0, y0 );
    _drawLINETODummy( x1, y1 );
    return( 1 );
    }

int hyDrawRectangle( int x0, int y0, int x1, int y1 )
    {
    if( x0 == x1 || y0 == y1 ) return hyDrawLine( x0, y0, x1, y1 );

    if( hyAttribute.pageOrientation == orientation_0 ) {
        x0 = devXMin + x0;
        y0 = devYMin + y0;
        x1 = devXMin + x1;
        y1 = devYMin + y1;
        }
    else if( hyAttribute.pageOrientation == orientation_90 ) {
        TEMP_VAL = x0;
        x0 = devXMin + y0;
        y0 = devYMin + devYSize - TEMP_VAL;
        TEMP_VAL = x1;
        x1 = devXMin + y1;
        y1 = devYMin + devYSize - TEMP_VAL;
        }
    else if( hyAttribute.pageOrientation == orientation_180 ) {
        x0 = devXMin + devXSize - x0;
        y0 = devYMin + devYSize - y0;
        x1 = devXMin + devXSize - x1;
        y1 = devYMin + devYSize - y1;
        }
    else if( hyAttribute.pageOrientation == orientation_270 ) {
        TEMP_VAL = x0;
        x0 = devXMin + devXSize - y0;
        y0 = devYMin + TEMP_VAL;
        TEMP_VAL = x1;
        x1 = devXMin + devXSize - y1;
        y1 = devYMin + TEMP_VAL;
        }

    fontImage = devAddress;
    bSize     = devBSize;
    devXDelta = 0;

    if( GS.fillMode ) {
        int i, s;
        int size, height, yy;
        if( y1 > y0 ) { height = y1 - y0 + 1; yy = y0; }
        else          { height = y0 - y1 + 1; yy = y1; }
        for( s=0; height>0; s++,height-=GS_DEPTH ) {
            devYDelta = GS_DEPTH*s;
            size = ( height < GS_DEPTH ) ? height : GS_DEPTH;
            setBand( yy+devYDelta, y0+devYDelta+size );
            for( i=0; i<BAND_LEN; i++ ) EDGE_CNT(i) = 0;
            _setEdge = _set_edge;
            _setFontPixel = _set_font_pixel_null;
            _drawMOVETO(      x0, y0 );
            _drawLINETODummy( x0, y1 );
            _drawLINETODummy( x1, y1 );
            _drawLINETODummy( x1, y0 );
            _drawLINETODummy( x0, y0 );
            _edgeSort();
            _setEdge = _set_edge_null;
            _setFontPixel = _set_font_pixel;
            _drawMOVETO(      x0, y0 );
            _drawLINETODummy( x0, y1 );
            _drawLINETODummy( x1, y1 );
            _drawLINETODummy( x1, y0 );
            _drawLINETODummy( x0, y0 );
            if( GS.fillMode == clearFill )
                _clearPixelToImage( y0 );
            else
                _putPixelToImage( y0 );
            }
        }

    if( GS.isDrawOutline ) {
        devYDelta = 0;
        setBand( 0, 0x7fffU );
        _setEdge      = _set_edge_null;
        _setFontPixel = _set_font_pixel_outline;
        _drawMOVETO(      x0, y0 );
        _drawLINETODummy( x0, y1 );
        _drawLINETODummy( x1, y1 );
        _drawLINETODummy( x1, y0 );
        _drawLINETODummy( x0, y0 );
        }
    return( 1 );
    }

int hyDrawEllipse( int type, int x, int y, int a, int b, int start, int end )
    {
    void getSinCos( int t, long *s, long *c );
    long s, c;

    if( hyAttribute.pageOrientation == orientation_0 ) {
        x = devXMin + x;
        y = devYMin + y;
        }
    else if( hyAttribute.pageOrientation == orientation_90 ) {
        TEMP_VAL = x;
        x = devXMin + y;
        y = devYMin + devYSize - TEMP_VAL;
        TEMP_VAL = a; a = b; b = TEMP_VAL;
        }
    else if( hyAttribute.pageOrientation == orientation_180 ) {
        x = devXMin + devXSize - x;
        y = devYMin + devYSize - y;
        }
    else if( hyAttribute.pageOrientation == orientation_270 ) {
        TEMP_VAL = x;
        x = devXMin + devXSize - y;
        y = devYMin + TEMP_VAL;
        TEMP_VAL = a; a = b; b = TEMP_VAL;
        }

    start += hyAttribute.pageOrientation;
    end   += hyAttribute.pageOrientation;

    fontImage = devAddress;
    bSize     = devBSize;
    devXDelta = 0;

    while( start > end ) end += 360;
    if( start == end || type == circle ) { start = 0; end = 360; }
    if( start == 0 && end == 360 ) type = circle;
    ELL_OX = x;
    ELL_OY = y;
    getSinCos( start, &c, &s );
    ELL_SX =  a * (s / (real)(1<<fixedShift));
    ELL_SY = -a * (c / (real)(1<<fixedShift));
    getSinCos( end, &c, &s );
    ELL_EX =  a * (s / (real)(1<<fixedShift));
    ELL_EY = -a * (c / (real)(1<<fixedShift));

    if( GS.fillMode && type != arc ) {
        int i, s;
        int x0 = x - a, x1 = x + a;
        int y0 = y - b, y1 = y + b;
        int size, height = y1 - y0 + 1;
        for( s=0; height>0; s++,height-=GS_DEPTH ) {
            devYDelta = GS_DEPTH*s;
            size = ( height < GS_DEPTH ) ? height : GS_DEPTH;
            setBand( y0+GS_DEPTH*s, y0+GS_DEPTH*s+size );
            for( i=0; i<BAND_LEN; i++ ) EDGE_CNT(i) = 0;
            _setEdge = _set_edge_ellipse;
            _setFontPixel = _set_font_pixel_null_ellipse;
            ell( type, x, y, a, b, start, end );
            if( type == fan ) {
                _setEdge = _set_edge;
                _drawLINETODummy( MM.x, MM.y );
                }
            else if( type == chord ) {
                _setEdge = _set_edge;
                _drawLINETODummy( x, y );
                _drawLINETODummy( MM.x, MM.y );
                }
            _edgeSort();
            _setEdge = _set_edge_null;
            _setFontPixel = _set_font_pixel_ellipse;
            ell( type, x, y, a, b, start, end );
            if( type == fan ) {
                _setFontPixel = _set_font_pixel;
                _drawLINETODummy( MM.x, MM.y );
                }
            else if( type == chord ) {
                _setFontPixel = _set_font_pixel;
                _drawLINETODummy( x, y );
                _drawLINETODummy( MM.x, MM.y );
                }
            if( GS.fillMode == clearFill )
                _clearPixelToImage( y0 );
            else
                _putPixelToImage( y0 );
            }
        }

    if( GS.isDrawOutline || type == arc ) {
        devYDelta = 0;
        setBand( 0, 0x7fffU );
        _setEdge      = _set_edge_null;
        _setFontPixel = _set_font_pixel_outline_ellipse;
        ell( type, x, y, a, b, start, end );
        if( type == fan ) {
            _setFontPixel = _set_font_pixel_outline;
            _drawLINETODummy( MM.x, MM.y );
            }
        else if( type == chord ) {
            _setFontPixel = _set_font_pixel_outline;
            _drawLINETODummy( x, y );
            _drawLINETODummy( MM.x, MM.y );
            }
        }

    return( 1 );
    }
