OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openrisc/trunk/rtos/ecos-2.0/packages/services/gfx/mw/v2_0/src/engine
    from Rev 27 to Rev 174
    Reverse comparison

Rev 27 → Rev 174

/devkbd.c
0,0 → 1,51
/*
* Copyright (c) 1999 Greg Haerr <greg@censoft.com>
*
* Device-independent keyboard routines
*/
#include "device.h"
 
/*
* Open the keyboard.
*/
int
GdOpenKeyboard(void)
{
int fd;
 
if ((fd = kbddev.Open(&kbddev)) == -1)
return -1;
 
/* possible -2 return means no kbd*/
return fd;
}
 
/*
* Close the keyboard.
*/
void
GdCloseKeyboard(void)
{
kbddev.Close();
}
 
/*
* Return the possible modifiers for the keyboard.
*/
void
GdGetModifierInfo(MWKEYMOD *modifiers, MWKEYMOD *curmodifiers)
{
kbddev.GetModifierInfo(modifiers, curmodifiers);
}
 
/*
* This reads one keystroke from the keyboard, and the current state of
* the mode keys (ALT, SHIFT, CTRL). Returns -1 on error, 0 if no data
* is ready, 1 if keypress, 2 if keyrelease.
* This is a non-blocking call. Returns -2 if ESC pressed.
*/
int
GdReadKeyboard(MWKEY *buf, MWKEYMOD *modifiers, MWSCANCODE *scancode)
{
return kbddev.Read(buf, modifiers, scancode);
}
/devpal4.c
0,0 → 1,29
/*
* Copyright (c) 1999 Greg Haerr <greg@censoft.com>
*
* 4bpp (16 color) standard palette definition
*/
#include "device.h"
 
/*
* Standard palette for 16 color systems.
*/
MWPALENTRY mwstdpal4[16] = {
/* 16 EGA colors, arranged in VGA standard palette order*/
RGBDEF( 0 , 0 , 0 ), /* black*/
RGBDEF( 0 , 0 , 128 ), /* blue*/
RGBDEF( 0 , 128, 0 ), /* green*/
RGBDEF( 0 , 128, 128 ), /* cyan*/
RGBDEF( 128, 0 , 0 ), /* red*/
RGBDEF( 128, 0 , 128 ), /* magenta*/
RGBDEF( 128, 64 , 0 ), /* adjusted brown*/
RGBDEF( 192, 192, 192 ), /* ltgray*/
RGBDEF( 128, 128, 128 ), /* gray*/
RGBDEF( 0 , 0 , 255 ), /* ltblue*/
RGBDEF( 0 , 255, 0 ), /* ltgreen*/
RGBDEF( 0 , 255, 255 ), /* ltcyan*/
RGBDEF( 255, 0 , 0 ), /* ltred*/
RGBDEF( 255, 0 , 255 ), /* ltmagenta*/
RGBDEF( 255, 255, 0 ), /* yellow*/
RGBDEF( 255, 255, 255 ), /* white*/
};
/devfont.caching.c
0,0 → 1,2921
/*
* Copyright (c) 2000 Greg Haerr <greg@censoft.com>
* T1lib Adobe type1 routines contributed by Vidar Hokstad
* Freetype TrueType routines contributed by Martin Jolicoeur
* Han Zi Ku routines contributed by Tanghao and Jauming
*
* Device-independent font and text drawing routines
*
* These routines do the necessary range checking, clipping, and cursor
* overwriting checks, and then call the lower level device dependent
* routines to actually do the drawing. The lower level routines are
* only called when it is known that all the pixels to be drawn are
* within the device area and are visible.
*/
/*#define NDEBUG*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <string.h>
 
#include "device.h"
#if (UNIX | DOS_DJGPP)
#define strcmpi strcasecmp
#endif
 
#if HAVE_T1LIB_SUPPORT
#include <t1lib.h>
#define T1LIB_USE_AA_HIGH
 
typedef struct {
PMWFONTPROCS fontprocs; /* common hdr*/
MWCOORD fontsize;
int fontrotation;
int fontattr;
 
int fontid; /* t1lib stuff*/
} MWT1LIBFONT, *PMWT1LIBFONT;
 
static int t1lib_init(PSD psd);
static PMWT1LIBFONT t1lib_createfont(const char *name, MWCOORD height,int attr);
static void t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags);
static MWBOOL t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);
static void t1lib_gettextsize(PMWFONT pfont, const void *text, int cc,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
static void t1lib_destroyfont(PMWFONT pfont);
 
/* handling routines for MWT1LIBFONT*/
static MWFONTPROCS t1lib_procs = {
MWTF_ASCII, /* routines expect ascii*/
t1lib_getfontinfo,
t1lib_gettextsize,
NULL, /* gettextbits*/
t1lib_destroyfont,
t1lib_drawtext,
NULL, /* setfontsize*/
NULL, /* setfontrotation*/
NULL, /* setfontattr*/
};
#endif
 
#ifdef T1LIB_USE_AA_HIGH
typedef unsigned long OUTPIXELVAL;
#else
typedef MWPIXELVAL OUTPIXELVAL;
#endif
 
#if HAVE_FREETYPE_SUPPORT
#include <freetype/freetype.h>
#include <freetype/ftxkern.h>
#include <freetype/ftnameid.h>
#include <freetype/ftxcmap.h>
#include <freetype/ftxwidth.h>
#include <math.h>
 
/************/
 
typedef struct xTT_Glyph_Cache_ {
 
TT_Error error;
TT_Glyph glyph;
TT_UShort index;
TT_UShort flags;
 
struct xTT_Glyph_Cache_ * l;
struct xTT_Glyph_Cache_ * r;
 
} xTT_Glyph_Cache;
 
typedef struct xTT_Instance_Object_ {
 
TT_Face face;
TT_Instance instance;
 
xTT_Glyph_Cache * head;
 
} xTT_Instance_Object;
 
typedef struct xTT_Instance_ {
 
xTT_Instance_Object * instance;
 
} xTT_Instance;
 
typedef struct xTT_Outline_Object_ {
 
TT_Outline outline;
TT_BBox bbox;
 
} xTT_Outline_Object;
 
typedef struct xTT_Outline_ {
 
xTT_Outline_Object * outline;
 
} xTT_Outline;
 
typedef struct xTT_Glyph_Object_ {
 
TT_Glyph * glyph;
 
xTT_Outline_Object outline;
 
} xTT_Glyph_Object;
 
typedef struct xTT_Glyph_ {
 
xTT_Glyph_Object * glyph;
 
} xTT_Glyph;
 
TT_Error
xTT_Glyph_Cache_Find ( xTT_Instance instance,
xTT_Glyph glyph,
TT_UShort glyphIndex,
TT_UShort loadFlags )
{
xTT_Glyph_Cache * node;
xTT_Glyph_Cache ** inode = &instance.instance->head;
 
int miss = 0;
 
while ( 1 )
{
if (*inode == 0)
{
miss = 1;
 
node = *inode = calloc(1,sizeof(**inode));
 
if (node == 0)
return TT_Err_Out_Of_Memory;
 
node->error = TT_New_Glyph(instance.instance->face,&(node->glyph));
 
if (node->error == 0)
node->error = TT_Load_Glyph(instance.instance->instance,
node->glyph,
(node->index = glyphIndex),
(node->flags = loadFlags));
 
if (node->error != 0)
TT_Done_Glyph(node->glyph);
}
else
{
node = *inode;
}
 
if (glyphIndex < node->index)
inode = &node->l;
else if (glyphIndex > node->index)
inode = &node->r;
else if (loadFlags < node->flags)
inode = &node->l;
else if (loadFlags > node->flags)
inode = &node->r;
else
{
static int count [] = { 0, 0 };
++count[miss];
printf("\r(%s | hit %d | miss %d)",__TIME__,count[0],count[1]);
glyph.glyph->glyph = &node->glyph;
return node->error;
}
}
}
 
void
xTT_Glyph_Cache_Free ( xTT_Glyph_Cache ** pnode )
{
xTT_Glyph_Cache * node;
 
if (pnode == 0)
return;
 
node = *pnode;
 
if (node == 0)
return;
 
if (node->l)
xTT_Glyph_Cache_Free(&node->l);
 
if (node->r)
xTT_Glyph_Cache_Free(&node->r);
 
TT_Done_Glyph(node->glyph);
free(node);
 
*pnode = 0;
}
 
TT_Error
xTT_New_Instance ( TT_Face face,
xTT_Instance * instance )
{
instance->instance = calloc(1,sizeof(*instance->instance));
if (instance->instance == 0)
return TT_Err_Out_Of_Memory;
 
instance->instance->face = face;
instance->instance->head = 0;
 
return TT_New_Instance(face,&instance->instance->instance);
}
 
TT_Error
xTT_Done_Instance ( xTT_Instance instance )
{
TT_Error error;
 
xTT_Glyph_Cache_Free(&instance.instance->head);
error = TT_Done_Instance(instance.instance->instance);
 
free(instance.instance);
 
return error;
}
 
TT_Error
xTT_Get_Instance_Metrics ( xTT_Instance instance,
TT_Instance_Metrics * imetrics )
{
return TT_Get_Instance_Metrics(instance.instance->instance,imetrics);
}
 
TT_Error
xTT_Set_Instance_CharSize ( xTT_Instance instance,
TT_F26Dot6 charsize )
{
xTT_Glyph_Cache_Free(&instance.instance->head);
return TT_Set_Instance_CharSize(instance.instance->instance,charsize);
}
 
TT_Error
xTT_Set_Instance_PixelSizes ( xTT_Instance instance,
TT_UShort pixelWidth,
TT_UShort pixelHeight,
TT_F26Dot6 pointSize )
{
xTT_Glyph_Cache_Free(&instance.instance->head);
return TT_Set_Instance_PixelSizes(instance.instance->instance,
pixelWidth,
pixelHeight,
pointSize);
}
 
TT_Error
xTT_Set_Instance_Transform_Flags ( xTT_Instance instance,
TT_Bool rotated,
TT_Bool stretched )
{
xTT_Glyph_Cache_Free(&instance.instance->head);
return TT_Set_Instance_Resolutions(instance.instance->instance,
rotated,
stretched);
}
 
TT_Error
xTT_Set_Instance_Resolutions ( xTT_Instance instance,
TT_UShort xResolution,
TT_UShort yResolution )
{
xTT_Glyph_Cache_Free(&instance.instance->head);
return TT_Set_Instance_Resolutions(instance.instance->instance,
xResolution,
yResolution);
}
 
TT_Error
xTT_New_Glyph ( TT_Face face,
xTT_Glyph * glyph )
{
glyph->glyph = calloc(1,sizeof(*glyph->glyph));
if (glyph->glyph == 0)
return TT_Err_Out_Of_Memory;
return 0;
}
 
TT_Error
xTT_Done_Glyph ( xTT_Glyph glyph )
{
free(glyph.glyph);
return 0;
}
 
TT_Error
xTT_Load_Glyph ( xTT_Instance instance,
xTT_Glyph glyph,
TT_UShort glyphIndex,
TT_UShort loadFlags )
{
TT_Error error;
error = xTT_Glyph_Cache_Find(instance,glyph,glyphIndex,loadFlags);
TT_Get_Glyph_Outline(*glyph.glyph->glyph,
&glyph.glyph->outline.outline);
TT_Get_Outline_BBox(&glyph.glyph->outline.outline,
&glyph.glyph->outline.bbox);
return error;
}
 
TT_Error
xTT_Get_Glyph_Metrics ( xTT_Glyph glyph,
TT_Glyph_Metrics * metrics )
{
return TT_Get_Glyph_Metrics(*glyph.glyph->glyph,metrics);
}
 
TT_Error
xTT_Get_Glyph_Outline ( xTT_Glyph glyph,
xTT_Outline * outline )
{
outline->outline = &glyph.glyph->outline;
return 0;
}
 
TT_Error
xTT_Get_Outline_BBox ( xTT_Outline * outline,
TT_BBox * bbox )
{
*bbox = outline->outline->bbox;
return 0;
}
 
void
xTT_Transform_Outline ( xTT_Outline * outline,
TT_Matrix * matrix )
{
TT_Transform_Outline(&outline->outline->outline,matrix);
TT_Get_Outline_BBox(&outline->outline->outline,
&outline->outline->bbox);
}
 
TT_Error
xTT_Get_Glyph_Bitmap ( xTT_Glyph glyph,
TT_Raster_Map * bitmap,
TT_F26Dot6 xOffset,
TT_F26Dot6 yOffset )
{
return TT_Get_Glyph_Bitmap(*glyph.glyph->glyph,
bitmap,
xOffset,
yOffset);
}
 
TT_Error
xTT_Get_Glyph_Pixmap ( xTT_Glyph glyph,
TT_Raster_Map * pixmap,
TT_F26Dot6 xOffset,
TT_F26Dot6 yOffset )
{
return TT_Get_Glyph_Pixmap(*glyph.glyph->glyph,
pixmap,
xOffset,
yOffset);
}
 
#ifndef xTT_ALIAS
#define xTT_ALIAS 1
#endif
 
#if xTT_ALIAS
 
#define TT_Instance xTT_Instance
#define TT_Outline xTT_Outline
#define TT_Glyph xTT_Glyph
 
#define TT_New_Instance xTT_New_Instance
#define TT_Done_Instance xTT_Done_Instance
 
#define TT_Get_Instance_Metrics xTT_Get_Instance_Metrics
#define TT_Set_Instance_CharSize xTT_Set_Instance_CharSize
#define TT_Set_Instance_PixelSizes xTT_Set_Instance_PixelSizes
#define TT_Set_Instance_Transform_Flags xTT_Set_Instance_Transform_Flags
#define TT_Set_Instance_Resolutions xTT_Set_Instance_Resolutions
 
#define TT_New_Glyph xTT_New_Glyph
#define TT_Done_Glyph xTT_Done_Glyph
 
#define TT_Load_Glyph xTT_Load_Glyph
#define TT_Get_Glyph_Metrics xTT_Get_Glyph_Metrics
#define TT_Get_Glyph_Outline xTT_Get_Glyph_Outline
#define TT_Get_Glyph_Bitmap xTT_Get_Glyph_Bitmap
#define TT_Get_Glyph_Pixmap xTT_Get_Glyph_Pixmap
 
#define TT_Get_Outline_BBox xTT_Get_Outline_BBox
#define TT_Transform_Outline xTT_Transform_Outline
 
#endif
 
/************/
 
#ifndef FREETYPE_FONT_DIR
#define FREETYPE_FONT_DIR "/usr/local/microwin/fonts"
#endif
 
#if TT_FREETYPE_MAJOR != 1 | TT_FREETYPE_MINOR < 3
#error "You must link with freetype lib version 1.3.x +, and not freetype 2. \
Download it at http://www.freetype.org or http://microwindows.org"
#endif
 
#ifndef MWFREETYPEFONT_CACHE
#define MWFREETYPEFONT_CACHE 1
#endif
 
#if MWFREETYPEFONT_CACHE
 
#ifndef MWFREETYPEFONT_CACHEBITMAP
#define MWFREETYPEFONT_CACHEBITMAP 1
#endif
 
typedef struct mwfreetypefontcache {
unsigned curchar;
void * buffer;
#if MWFREETYPEFONT_CACHEBITMAP
MWPIXELVAL fg;
MWPIXELVAL bg;
MWBOOL usebg;
void * bitmap;
#endif
struct mwfreetypefontcache * l;
struct mwfreetypefontcache * r;
} MWFREETYPEFONTCACHE;
 
#endif
 
typedef struct {
 
PMWFONTPROCS fontprocs; /* common hdr*/
MWCOORD fontsize;
int fontrotation;
int fontattr;
 
TT_Face face; /* freetype stuff*/
TT_Instance instance;
TT_CharMap char_map;
TT_Kerning directory;
TT_Matrix matrix;
TT_Glyph glyph;
MWBOOL can_kern;
short last_glyph_code;
short last_pen_pos;
 
#if MWFREETYPEFONT_CACHE
MWFREETYPEFONTCACHE * glyph_cache;
#endif
 
} MWFREETYPEFONT, *PMWFREETYPEFONT;
 
static int freetype_init(PSD psd);
static PMWFREETYPEFONT freetype_createfont(const char *name, MWCOORD height,
int attr);
static MWBOOL freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);
static void freetype_gettextsize(PMWFONT pfont, const void *text,
int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
static void freetype_destroyfont(PMWFONT pfont);
static void freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags);
static void freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize);
static void freetype_setfontrotation(PMWFONT pfont, int tenthdegrees);
/* handling routines for MWFREETYPEFONT*/
static MWFONTPROCS freetype_procs = {
MWTF_UC16, /* routines expect unicode 16*/
freetype_getfontinfo,
freetype_gettextsize,
NULL, /* gettextbits*/
freetype_destroyfont,
freetype_drawtext,
freetype_setfontsize,
freetype_setfontrotation,
NULL, /* setfontattr*/
};
 
static TT_Engine engine; /* THE ONLY freetype engine */
#endif /* HAVE_FREETYPE_SUPPORT*/
 
#if HAVE_HZK_SUPPORT
/*
* 12x12 and 16x16 ascii and chinese fonts
* Big5 and GB2312 encodings supported
*/
#define MAX_PATH 256
typedef struct {
int width;
int height;
int size;
unsigned long use_count;
char * pFont;
char file[MAX_PATH + 1];
} HZKFONT;
 
static int use_big5=1;
static HZKFONT CFont[2]; /* font cache*/
static HZKFONT AFont[2]; /* font cache*/
 
/*jmt: moved inside MWHZKFONT*/
static int afont_width = 8;
static int cfont_width = 16;
static int font_height = 16;
static char *afont_address;
static char *cfont_address;
 
typedef struct {
PMWFONTPROCS fontprocs; /* common hdr*/
MWCOORD fontsize;
int fontrotation;
int fontattr;
 
HZKFONT CFont; /* hzkfont stuff */
HZKFONT AFont;
int afont_width;
int cfont_width;
int font_height;
char *afont_address;
char *cfont_address;
} MWHZKFONT, *PMWHZKFONT;
 
static int hzk_init(PSD psd);
static PMWHZKFONT hzk_createfont(const char *name, MWCOORD height,int fontattr);
static MWBOOL hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);
static void hzk_gettextsize(PMWFONT pfont, const void *text,
int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
/*static void hzk_gettextbits(PMWFONT pfont, int ch, IMAGEBITS *retmap,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);*/
static void hzk_destroyfont(PMWFONT pfont);
static void hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags);
static void hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize);
/*static void hzk_setfontrotation(PMWFONT pfont, int tenthdegrees);*/
/* handling routines for MWHZKFONT*/
static MWFONTPROCS hzk_procs = {
MWTF_ASCII, /* routines expect ASCII*/
hzk_getfontinfo,
hzk_gettextsize,
NULL, /* hzk_gettextbits*/
hzk_destroyfont,
hzk_drawtext,
hzk_setfontsize,
NULL, /* setfontrotation*/
NULL, /* setfontattr*/
};
 
static int
UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii);
#endif /* HAVE_HZK_SUPPORT*/
 
static PMWFONT gr_pfont; /* current font*/
 
/* temp extern decls*/
extern MWPIXELVAL gr_foreground;
extern MWPIXELVAL gr_background;
extern MWBOOL gr_usebg;
 
static int utf8_to_utf16(const unsigned char *utf8, int cc,
unsigned short *unicode16);
 
#if FONTMAPPER
/* entry point for font selection*/
int select_font(const PMWLOGFONT plogfont, char *physname);
#endif
 
/*
* Set the font for future calls.
*/
PMWFONT
GdSetFont(PMWFONT pfont)
{
PMWFONT oldfont = gr_pfont;
gr_pfont = pfont;
return oldfont;
}
 
/*
* Select a font, based on various parameters.
* If plogfont is specified, name and height parms are ignored
* and instead used from MWLOGFONT.
*
* If height is 0, return builtin font from passed name.
* Otherwise find builtin font best match based on height.
*/
PMWFONT
GdCreateFont(PSD psd, const char *name, MWCOORD height,
const PMWLOGFONT plogfont)
{
int i;
int fontht;
int fontno;
int fontclass;
int fontattr = 0;
PMWFONT pfont;
PMWCOREFONT pf = psd->builtin_fonts;
MWFONTINFO fontinfo;
MWSCREENINFO scrinfo;
char fontname[128];
 
GdGetScreenInfo(psd, &scrinfo);
 
/* if plogfont not specified, use name and height*/
if (!plogfont) {
if (!name)
name = MWFONT_SYSTEM_VAR;
strcpy(fontname, name);
fontclass = MWLF_CLASS_ANY;
} else {
#if FONTMAPPER
/* otherwise, use MWLOGFONT name and height*/
fontclass = select_font(plogfont, fontname);
#else
if (!name)
name = MWFONT_SYSTEM_VAR;
strcpy(fontname, name);
fontclass = MWLF_CLASS_ANY;
#endif
height = plogfont->lfHeight;
if (plogfont->lfUnderline)
fontattr = MWTF_UNDERLINE;
}
height = abs(height);
if (!fontclass)
goto first;
/* use builtin screen fonts, FONT_xxx, if height is 0 */
if (height == 0 || fontclass == MWLF_CLASS_ANY ||
fontclass == MWLF_CLASS_BUILTIN) {
for(i = 0; i < scrinfo.fonts; ++i) {
if(!strcmpi(pf[i].name, fontname)) {
pf[i].fontsize = pf[i].cfont->height;
pf[i].fontattr = fontattr;
return (PMWFONT)&pf[i];
}
}
/* return first builtin font*/
if (height == 0 || fontclass == MWLF_CLASS_BUILTIN)
goto first;
}
 
#if HAVE_HZK_SUPPORT
/* Make sure the library is initialized */
if (hzk_init(psd)) {
pfont = (PMWFONT)hzk_createfont(name, height, fontattr);
if(pfont)
return pfont;
printf("hzk_createfont: %s not found\n", name);
}
#endif
 
#if HAVE_FREETYPE_SUPPORT
if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_FREETYPE) {
if (freetype_init(psd)) {
/* auto antialias for height > 14 for kaffe*/
if (plogfont && plogfont->lfHeight > 14 &&
plogfont->lfQuality)
fontattr |= MWTF_ANTIALIAS;
 
pfont = (PMWFONT)freetype_createfont(fontname, height,
fontattr);
if(pfont) {
/* temp kaffe kluge*/
pfont->fontattr |= FS_FREETYPE;
return pfont;
}
DPRINTF("freetype_createfont: %s,%d not found\n",
fontname, height);
}
}
#endif
 
#if HAVE_T1LIB_SUPPORT
if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_T1LIB) {
if (t1lib_init(psd)) {
pfont = (PMWFONT)t1lib_createfont(fontname, height,
fontattr);
if(pfont)
return pfont;
DPRINTF("t1lib_createfont: %s,%d not found\n",
fontname, height);
}
}
#endif
 
/* find builtin font closest in height*/
if(height != 0) {
fontno = 0;
height = abs(height);
fontht = MAX_MWCOORD;
for(i = 0; i < scrinfo.fonts; ++i) {
pfont = (PMWFONT)&pf[i];
GdGetFontInfo(pfont, &fontinfo);
if(fontht > abs(height-fontinfo.height)) {
fontno = i;
fontht = abs(height-fontinfo.height);
}
}
pf[fontno].fontsize = pf[fontno].cfont->height;
pf[fontno].fontattr = fontattr;
return (PMWFONT)&pf[fontno];
}
 
first:
/* Return first builtin font*/
pf->fontsize = pf->cfont->height;
pf->fontattr = fontattr;
return (PMWFONT)&pf[0];
}
 
/* Set the font size for the passed font*/
MWCOORD
GdSetFontSize(PMWFONT pfont, MWCOORD fontsize)
{
MWCOORD oldfontsize = pfont->fontsize;
 
pfont->fontsize = fontsize;
 
if (pfont->fontprocs->SetFontSize)
pfont->fontprocs->SetFontSize(pfont, fontsize);
 
return oldfontsize;
}
 
/* Set the font rotation angle in tenths of degrees for the passed font*/
int
GdSetFontRotation(PMWFONT pfont, int tenthdegrees)
{
MWCOORD oldrotation = pfont->fontrotation;
 
pfont->fontrotation = tenthdegrees;
 
if (pfont->fontprocs->SetFontRotation)
pfont->fontprocs->SetFontRotation(pfont, tenthdegrees);
return oldrotation;
}
 
/*
* Set/reset font attributes (MWTF_KERNING, MWTF_ANTIALIAS)
* for the passed font.
*/
int
GdSetFontAttr(PMWFONT pfont, int setflags, int clrflags)
{
MWCOORD oldattr = pfont->fontattr;
 
pfont->fontattr &= ~clrflags;
pfont->fontattr |= setflags;
 
if (pfont->fontprocs->SetFontAttr)
pfont->fontprocs->SetFontAttr(pfont, setflags, clrflags);
return oldattr;
}
 
/* Unload and deallocate font*/
void
GdDestroyFont(PMWFONT pfont)
{
if (pfont->fontprocs->DestroyFont)
pfont->fontprocs->DestroyFont(pfont);
}
 
/* Return information about a specified font*/
MWBOOL
GdGetFontInfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
{
if(!pfont || !pfont->fontprocs->GetFontInfo)
return FALSE;
 
return pfont->fontprocs->GetFontInfo(pfont, pfontinfo);
}
 
/*
* Convert from one encoding to another
* Input cc and returned cc is character count, not bytes
* Return < 0 on error or can't translate
*/
int
GdConvertEncoding(const void *istr, int iflags, int cc, void *ostr, int oflags)
{
const unsigned char *istr8;
const unsigned short *istr16;
const unsigned long *istr32;
unsigned char *ostr8;
unsigned short *ostr16;
unsigned long *ostr32;
unsigned int ch;
int icc;
unsigned short buf16[512];
 
iflags &= MWTF_PACKMASK;
oflags &= MWTF_PACKMASK;
 
/* allow -1 for len with ascii*/
if(cc == -1 && (iflags == MWTF_ASCII))
cc = strlen((char *)istr);
 
/* first check for utf8 input encoding*/
if(iflags == MWTF_UTF8) {
/* we've only got uc16 now so convert to uc16...*/
cc = utf8_to_utf16((unsigned char *)istr, cc,
oflags==MWTF_UC16?(unsigned short*) ostr: buf16);
 
if(oflags == MWTF_UC16 || cc < 0)
return cc;
 
/* will decode again to requested format (probably ascii)*/
iflags = MWTF_UC16;
istr = buf16;
}
 
#if HAVE_HZK_SUPPORT
if(iflags == MWTF_UC16 && oflags == MWTF_ASCII) {
/* only support uc16 convert to ascii now...*/
cc = UC16_to_GB( istr, cc, ostr);
return cc;
}
#endif
 
icc = cc;
istr8 = istr;
istr16 = istr;
istr32 = istr;
ostr8 = ostr;
ostr16 = ostr;
ostr32 = ostr;
 
/* Convert between formats. Note that there's no error
* checking here yet.
*/
while(--icc >= 0) {
switch(iflags) {
default:
ch = *istr8++;
break;
case MWTF_UC16:
ch = *istr16++;
break;
case MWTF_UC32:
ch = *istr32++;
}
switch(oflags) {
default:
*ostr8++ = (unsigned char)ch;
break;
case MWTF_UC16:
*ostr16++ = (unsigned short)ch;
break;
case MWTF_UC32:
*ostr32++ = ch;
}
}
return cc;
}
 
/* Get the width and height of passed text string in the passed font*/
void
GdGetTextSize(PMWFONT pfont, const void *str, int cc, MWCOORD *pwidth,
MWCOORD *pheight, MWCOORD *pbase, int flags)
{
const void * text;
unsigned long buf[256];
int defencoding = pfont->fontprocs->encoding;
 
/* convert encoding if required*/
if((flags & MWTF_PACKMASK) != defencoding) {
cc = GdConvertEncoding(str, flags, cc, buf, defencoding);
flags &= ~MWTF_PACKMASK;
flags |= defencoding;
text = buf;
} else text = str;
 
if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII)
cc = strlen((char *)str);
 
if(cc <= 0 || !pfont->fontprocs->GetTextSize) {
*pwidth = *pheight = *pbase = 0;
return;
}
 
/* calc height and width of string*/
pfont->fontprocs->GetTextSize(pfont, text, cc, pwidth, pheight, pbase);
}
 
/* Draw a text string at a specifed coordinates in the foreground color
* (and possibly the background color), applying clipping if necessary.
* The background color is only drawn if the gr_usebg flag is set.
* Use the current font.
*/
void
GdText(PSD psd, MWCOORD x, MWCOORD y, const void *str, int cc, int flags)
{
const void * text;
unsigned long buf[256];
int defencoding = gr_pfont->fontprocs->encoding;
 
/* convert encoding if required*/
if((flags & MWTF_PACKMASK) != defencoding) {
cc = GdConvertEncoding(str, flags, cc, buf, defencoding);
flags &= ~MWTF_PACKMASK;
flags |= defencoding;
text = buf;
} else text = str;
 
if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII)
cc = strlen((char *)str);
 
if(cc <= 0 || !gr_pfont->fontprocs->DrawText)
return;
 
/* draw text string*/
gr_pfont->fontprocs->DrawText(gr_pfont, psd, x, y, text, cc, flags);
}
 
/*
* Draw ascii text using COREFONT type font.
*/
void
corefont_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags)
{
const unsigned char *str = text;
MWCOORD width; /* width of text area */
MWCOORD height; /* height of text area */
MWCOORD base; /* baseline of text*/
MWCOORD startx, starty;
/* bitmap for characters */
MWIMAGEBITS bitmap[MAX_CHAR_HEIGHT*MAX_CHAR_WIDTH/MWIMAGE_BITSPERIMAGE];
 
pfont->fontprocs->GetTextSize(pfont, str, cc, &width, &height, &base);
if(flags & MWTF_BASELINE)
y -= base;
else if(flags & MWTF_BOTTOM)
y -= (height - 1);
startx = x;
starty = y + base;
 
switch (GdClipArea(psd, x, y, x + width - 1, y + height - 1)) {
case CLIP_VISIBLE:
/*
* For size considerations, there's no low-level text
* draw, so we've got to draw all text
* with per-point clipping for the time being
if (gr_usebg)
psd->FillRect(psd, x, y, x + width - 1, y + height - 1,
gr_background);
psd->DrawText(psd, x, y, str, cc, gr_foreground, pfont);
GdFixCursor(psd);
return;
*/
break;
 
case CLIP_INVISIBLE:
return;
}
 
/* Get the bitmap for each character individually, and then display
* them using clipping for each one.
*/
while (--cc >= 0 && x < psd->xvirtres) {
unsigned int ch = *str++;
#if HAVE_BIG5_SUPPORT
/* chinese big5 decoding*/
if (ch >= 0xA1 && ch <= 0xF9 && cc >= 1 &&
((*str >= 0x40 && *str <= 0x7E) ||
(*str >= 0xA1 && *str <= 0xFE)) ) {
ch = (ch << 8) | *str++;
--cc;
}
#endif
#if HAVE_GB2312_SUPPORT
/* chinese gb2312 decoding*/
if (ch >= 0xA1 && ch < 0xF8 && cc >= 1 &&
*str >= 0xA1 && *str < 0xFF) {
ch = (ch << 8) | *str++;
--cc;
}
#endif
pfont->fontprocs->GetTextBits(pfont, ch, bitmap, &width,
&height, &base);
 
/* note: change to bitmap*/
GdBitmap(psd, x, y, width, height, bitmap);
x += width;
}
 
if (pfont->fontattr & MWTF_UNDERLINE)
GdLine(psd, startx, starty, x, starty, FALSE);
 
GdFixCursor(psd);
}
 
#if HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT
/*
* Produce blend table from src and dst based on passed alpha table
* Used because we don't quite yet have GdArea with alphablending,
* so we pre-blend fg/bg colors for fade effect.
*/
static void
alphablend(PSD psd, OUTPIXELVAL *out, MWPIXELVAL src, MWPIXELVAL dst,
unsigned char *alpha, int count)
{
unsigned int a, d;
unsigned char r, g, b;
MWCOLORVAL palsrc, paldst;
extern MWPALENTRY gr_palette[256];
 
while (--count >= 0) {
a = *alpha++;
 
#define BITS(pixel,shift,mask) (((pixel)>>shift)&(mask))
if(a == 0)
*out++ = dst;
else if(a == 255)
*out++ = src;
else
switch(psd->pixtype) {
case MWPF_TRUECOLOR0888:
case MWPF_TRUECOLOR888:
d = BITS(dst, 16, 0xff);
r = (unsigned char)(((BITS(src, 16, 0xff) - d)*a)>>8) + d;
d = BITS(dst, 8, 0xff);
g = (unsigned char)(((BITS(src, 8, 0xff) - d)*a)>>8) + d;
d = BITS(dst, 0, 0xff);
b = (unsigned char)(((BITS(src, 0, 0xff) - d)*a)>>8) + d;
*out++ = (r << 16) | (g << 8) | b;
break;
 
case MWPF_TRUECOLOR565:
d = BITS(dst, 11, 0x1f);
r = (unsigned char)(((BITS(src, 11, 0x1f) - d)*a)>>8) + d;
d = BITS(dst, 5, 0x3f);
g = (unsigned char)(((BITS(src, 5, 0x3f) - d)*a)>>8) + d;
d = BITS(dst, 0, 0x1f);
b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d;
*out++ = (r << 11) | (g << 5) | b;
break;
 
case MWPF_TRUECOLOR555:
d = BITS(dst, 10, 0x1f);
r = (unsigned char)(((BITS(src, 10, 0x1f) - d)*a)>>8) + d;
d = BITS(dst, 5, 0x1f);
g = (unsigned char)(((BITS(src, 5, 0x1f) - d)*a)>>8) + d;
d = BITS(dst, 0, 0x1f);
b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d;
*out++ = (r << 10) | (g << 5) | b;
break;
 
case MWPF_TRUECOLOR332:
d = BITS(dst, 5, 0x07);
r = (unsigned char)(((BITS(src, 5, 0x07) - d)*a)>>8) + d;
d = BITS(dst, 2, 0x07);
g = (unsigned char)(((BITS(src, 2, 0x07) - d)*a)>>8) + d;
d = BITS(dst, 0, 0x03);
b = (unsigned char)(((BITS(src, 0, 0x03) - d)*a)>>8) + d;
*out++ = (r << 5) | (g << 2) | b;
break;
 
case MWPF_PALETTE:
/* reverse lookup palette entry for blend ;-)*/
palsrc = GETPALENTRY(gr_palette, src);
paldst = GETPALENTRY(gr_palette, dst);
d = REDVALUE(paldst);
r = (unsigned char)(((REDVALUE(palsrc) - d)*a)>>8) + d;
d = GREENVALUE(paldst);
g = (unsigned char)(((GREENVALUE(palsrc) - d)*a)>>8) + d;
d = BLUEVALUE(paldst);
b = (unsigned char)(((BLUEVALUE(palsrc) - d)*a)>>8) + d;
*out++ = GdFindNearestColor(gr_palette, (int)psd->ncolors,
MWRGB(r, g, b));
break;
}
}
}
#endif /*HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT*/
 
#if HAVE_T1LIB_SUPPORT
/* contributed by Vidar Hokstad*/
 
static int
t1lib_init(PSD psd)
{
static int inited = 0;
 
if (inited)
return 1;
 
T1_SetBitmapPad(8);
if (!T1_InitLib(0))
return 0;
#ifdef T1LIB_USE_AA_HIGH
T1_AASetLevel(T1_AA_HIGH);
#else
T1_AASetLevel(T1_AA_LOW);
#endif
#if 0
/* kluge: this is required if 16bpp drawarea driver is used*/
if(psd->bpp == 16)
T1_AASetBitsPerPixel(16);
else
#endif
T1_AASetBitsPerPixel(sizeof(MWPIXELVAL)*8);
 
inited = 1;
return 1;
}
 
static PMWT1LIBFONT
t1lib_createfont(const char *name, MWCOORD height, int attr)
{
PMWT1LIBFONT pf;
int id;
char * p;
char buf[256];
 
/* match name against t1 font id's from t1 font database*/
for(id=0; id<T1_Get_no_fonts(); ++id) {
strncpy(buf, T1_GetFontFileName(id), sizeof(buf));
 
/* remove extension*/
for(p=buf; *p; ++p) {
if(*p == '.') {
*p = 0;
break;
}
}
 
if(!strcmpi(name, buf)) {
/* allocate font structure*/
pf = (PMWT1LIBFONT)calloc(sizeof(MWT1LIBFONT), 1);
if (!pf)
return NULL;
pf->fontprocs = &t1lib_procs;
GdSetFontSize((PMWFONT)pf, height);
GdSetFontRotation((PMWFONT)pf, 0);
GdSetFontAttr((PMWFONT)pf, attr, 0);
pf->fontid = id;
return pf;
}
}
return NULL;
}
 
/*
* Draw ascii text string using T1LIB type font
*/
static void
t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags)
{
PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont;
const unsigned char *str = text;
MWCOORD width; /* width of text area */
MWCOORD height; /* height of text area */
MWCOORD underliney;
GLYPH * g; /* T1lib glyph structure. Memory handling by T1lib */
#ifdef T1LIB_USE_AA_HIGH
OUTPIXELVAL gvals[17];
 
/* Blending array for antialiasing. The steeper the values increase
* near the end, the sharper the characters look, but also more jagged
*/
static unsigned char blend[17] = {
0x00, 0x00, 0x04, 0x0c, 0x10, 0x14, 0x18, 0x20,
0x30, 0x38, 0x40, 0x50, 0x70, 0x80, 0xa0, 0xc0, 0xff
};
#else
OUTPIXELVAL gvals[5];
static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff };
#endif
 
/* Check if we should throw out some fonts */
 
if (pf->fontattr&MWTF_ANTIALIAS) {
#ifdef T1LIB_USE_AA_HIGH
alphablend(psd, gvals, gr_foreground, gr_background, blend, 17);
T1_AAHSetGrayValues(gvals);
#else
alphablend(psd, gvals, gr_foreground, gr_background, blend, 5);
T1_AASetGrayValues(gvals[0],gvals[1],gvals[2],gvals[3],gvals[4]);
#endif
g = T1_AASetString(pf->fontid,(char *)str,cc,0,
(pf->fontattr&MWTF_KERNING)? T1_KERNING: 0,
pf->fontsize * 1.0, 0);
 
if (g && g->bits) {
/*MWPIXELVAL save = gr_background;*/
width = g->metrics.rightSideBearing - g->metrics.leftSideBearing;
height = g->metrics.ascent - g->metrics.descent;
 
if(flags & MWTF_BASELINE)
y -= g->metrics.ascent;
else if(flags & MWTF_BOTTOM)
y -= (height - 1);
underliney = y + g->metrics.ascent;
 
/* FIXME: Looks damn ugly if usebg is false.
* Will be handled when using alphablending in GdArea...
*/
/* clipping handled in GdArea*/
/*FIXME kluge for transparency*/
/*gr_background = gr_foreground + 1;*/
/*gr_usebg = 0;*/
GdArea(psd,x,y, width, height, g->bits, MWPF_PIXELVAL);
/*gr_background = save;*/
 
if (pf->fontattr & MWTF_UNDERLINE)
GdLine(psd, x, underliney, x+width, underliney, FALSE);
 
}
} else {
/* Do non-aa drawing */
g = T1_SetString(pf->fontid,(char *)str,cc,0,
(pf->fontattr&MWTF_KERNING)? T1_KERNING: 0,
pf->fontsize * 1.0, 0);
 
if (g && g->bits) {
unsigned char * b;
int xoff;
int maxy;
int xmod;
/* I'm sure this sorry excuse for a bitmap rendering routine can
* be optimized quite a bit ;)
*/
width = g->metrics.rightSideBearing - g->metrics.leftSideBearing;
height = g->metrics.ascent - g->metrics.descent;
 
if(flags & MWTF_BASELINE)
y -= g->metrics.ascent;
else if(flags & MWTF_BOTTOM)
y -= (height - 1);
underliney = y + g->metrics.ascent;
b = g->bits;
maxy = y + height;
/* if ((x + width) > psd->xvirtres) {
xmod = (x + width - psd->xvirtres + 7) >> 3;
width = width + x + width - psd->xvirtres;
} else xmod = 0;
*/
xmod = 0;
while (y < maxy) {
unsigned char data;
xoff = 0;
while (xoff < width ) {
if (!(xoff % 8)) {
data = *b;
b++;
}
if (GdClipPoint(psd, x+xoff,y)) {
if (gr_usebg) {
psd->DrawPixel(psd,x+xoff,y,
data & (1 << (xoff % 8)) ?
gr_foreground : gr_background);
} else if (data & (1 << (xoff % 8))) {
psd->DrawPixel(psd,x+xoff,y, gr_foreground);
}
}
xoff++;
}
b += xmod;
y++;
}
if (pf->fontattr & MWTF_UNDERLINE)
GdLine(psd, x, underliney, x+xoff, underliney, FALSE);
}
}
 
if (g && g->bits) {
/* Save some memory */
free(g->bits);
g->bits = 0; /* Make sure T1lib doesnt try to free it again */
}
 
GdFixCursor(psd);
}
 
static MWBOOL
t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
{
int i;
MWCOORD width, height, baseline;
 
/* FIXME, guess all sizes*/
GdGetTextSize(pfont, "A", 1, &width, &height, &baseline, MWTF_ASCII);
pfontinfo->height = height;
pfontinfo->maxwidth = width;
pfontinfo->baseline = 0;
pfontinfo->firstchar = 32;
pfontinfo->lastchar = 255;
pfontinfo->fixed = TRUE;
for(i=0; i<256; ++i)
pfontinfo->widths[i] = width;
return TRUE;
}
 
/* Get the width and height of passed text string in the current font*/
static void
t1lib_gettextsize(PMWFONT pfont, const void *text, int cc,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
{
PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont;
const unsigned char * str = text;
GLYPH * g;
 
g = T1_SetString(pf->fontid, (char *)str, cc, 0,
(pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, pf->fontsize * 1.0, 0);
*pwidth = g->metrics.rightSideBearing - g->metrics.leftSideBearing;
*pheight = g->metrics.ascent - g->metrics.descent;
if(g && g->bits) {
free(g->bits);
g->bits = 0;
}
#if 0
BBox b;
 
/* FIXME. Something is *VERY* wrong here */
b = T1_GetStringBBox(pf->fontid, str, cc, 0, (pf->fontattr&MWTF_KERNING)?T1_KERNING:0);
 
DPRINTF("b.urx = %d, b.llx = %d\n",b.urx, b.llx);
DPRINTF("b.ury = %d, b.lly = %d\n",b.ury, b.lly);
*pwidth = (b.urx - b.llx);
*pheight = (b.lly - b.ury);
#endif
}
 
static void
t1lib_destroyfont(PMWFONT pfont)
{
PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont;
 
T1_DeleteAllSizes(pf->fontid);
free(pf);
}
 
#endif /* HAVE_T1LIB_SUPPORT*/
 
#if HAVE_FREETYPE_SUPPORT
static OUTPIXELVAL gray_palette[5];
 
static int
freetype_init(PSD psd)
{
static int inited = 0;
 
if (inited)
return 1;
/* Init freetype library */
if (TT_Init_FreeType (&engine) != TT_Err_Ok) {
return 0;
}
 
/* Init kerning extension */
if (TT_Init_Kerning_Extension (engine) != TT_Err_Ok)
return 0;
 
inited = 1;
return 1;
}
 
static PMWFREETYPEFONT
freetype_createfont(const char *name, MWCOORD height, int attr)
{
PMWFREETYPEFONT pf;
unsigned short i, n;
unsigned short platform, encoding;
TT_Face_Properties properties;
char * p;
char fontname[128];
 
/* check for pathname prefix*/
if (strchr(name, '/') != NULL)
strcpy(fontname, name);
else {
strcpy(fontname, FREETYPE_FONT_DIR);
strcat(fontname, "/");
strcat(fontname, name);
}
 
/* check for extension*/
if ((p = strrchr(fontname, '.')) == NULL ||
strcmp(p, ".ttf") != 0) {
strcat(fontname, ".ttf");
}
 
/* allocate font structure*/
pf = (PMWFREETYPEFONT)calloc(sizeof(MWFREETYPEFONT), 1);
if (!pf)
return NULL;
pf->fontprocs = &freetype_procs;
 
/* Load face */
if (TT_Open_Face (engine, fontname, &pf->face) != TT_Err_Ok)
goto out;
 
/* Load first kerning table */
pf->can_kern = TRUE;
if (TT_Load_Kerning_Table (pf->face, 0) != TT_Err_Ok)
pf->can_kern = FALSE;
else {
if (TT_Get_Kerning_Directory (pf->face, &pf->directory)
!= TT_Err_Ok)
pf->can_kern = FALSE;
else {
/* Support only version 0 kerning table ... */
if ((pf->directory.version != 0) ||
(pf->directory.nTables <= 0) ||
(pf->directory.tables->loaded != 1) ||
(pf->directory.tables->version != 0) ||
(pf->directory.tables->t.kern0.nPairs <= 0))
pf->can_kern = FALSE;
}
}
 
/* get face properties and allocate preload arrays */
TT_Get_Face_Properties (pf->face, &properties);
 
#if 0
/*
* Use header information for ascent and descent
* to compute scaled ascent/descent for current font height.
*/
h = properties.os2->sTypoAscender - properties.os2->sTypoDescender
+ properties.os2->sTypoLineGap;
ascent = properties.os2->sTypoAscender
+ properties.os2->sTypoLineGap/2;
pf->ascent = (ascent * height + h/2) / h;
pf->descent = height - pf->ascent;
#endif
/* Create a glyph container */
if (TT_New_Glyph (pf->face, &pf->glyph) != TT_Err_Ok)
goto out;
 
/* create instance */
if (TT_New_Instance (pf->face, &pf->instance) != TT_Err_Ok)
goto out;
 
/* Set the instance resolution */
if (TT_Set_Instance_Resolutions (pf->instance, 96, 96) != TT_Err_Ok)
goto out;
 
/* Look for a Unicode charmap: Windows flavor of Apple flavor only */
n = properties.num_CharMaps;
 
for (i = 0; i < n; i++) {
TT_Get_CharMap_ID (pf->face, i, &platform, &encoding);
if (((platform == TT_PLATFORM_MICROSOFT) &&
(encoding == TT_MS_ID_UNICODE_CS)) ||
((platform == TT_PLATFORM_APPLE_UNICODE) &&
(encoding == TT_APPLE_ID_DEFAULT)))
{
TT_Get_CharMap (pf->face, i, &pf->char_map);
i = n + 1;
}
}
if (i == n) {
DPRINTF("freetype_createfont: no unicode map table\n");
goto out;
}
GdSetFontSize((PMWFONT)pf, height);
GdSetFontRotation((PMWFONT)pf, 0);
GdSetFontAttr((PMWFONT)pf, attr, 0);
 
return pf;
 
out:
free(pf);
return NULL;
}
 
static int
compute_kernval(PMWFREETYPEFONT pf, short current_glyph_code)
{
int i = 0;
int kernval;
int nPairs = pf->directory.tables->t.kern0.nPairs;
TT_Kern_0_Pair *pair = pf->directory.tables->t.kern0.pairs;
 
if (pf->last_glyph_code != -1) {
while ((pair->left != pf->last_glyph_code)
&& (pair->right != current_glyph_code))
{
pair++;
i++;
if (i == nPairs)
break;
}
 
if (i == nPairs)
kernval = 0;
else
/* We round the value (hence the +32) */
kernval = (pair->value + 32) & -64;
} else
kernval = 0;
 
return kernval;
}
 
static TT_UShort
Get_Glyph_Width(PMWFREETYPEFONT pf, TT_UShort glyph_index)
{
TT_Glyph_Metrics metrics;
 
if (TT_Load_Glyph ( pf->instance, pf->glyph,
TT_Char_Index (pf->char_map,glyph_index),
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
{
/* Try to load default glyph: index 0 */
if (TT_Load_Glyph ( pf->instance, pf->glyph, 0,
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
return 0;
}
 
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
return((metrics.advance & 0xFFFFFFC0) >> 6);
}
 
static MWFREETYPEFONTCACHE *
find_cache_glyph ( PMWFREETYPEFONT pf, unsigned curchar )
{
MWFREETYPEFONTCACHE ** inode = &pf->glyph_cache;
 
while (1)
{
if (*inode == 0)
{
*inode = calloc(sizeof(MWFREETYPEFONTCACHE),1);
(*inode)->curchar = curchar;
}
 
if (curchar < (*inode)->curchar)
inode = &(*inode)->l;
else if (curchar > (*inode)->curchar)
inode = &(*inode)->r;
else
return *inode;
}
}
 
static void
free_cache_glyph ( MWFREETYPEFONTCACHE * node )
{
if (node->l != 0)
free_cache_glyph(node->l);
 
if (node->r != 0)
free_cache_glyph(node->r);
 
free(node);
}
 
/* Render a single glyph*/
static void
drawchar(PMWFREETYPEFONT pf, PSD psd, unsigned curchar, int x_offset,
int y_offset)
{
TT_F26Dot6 xmin, ymin, xmax, ymax, x, y, z;
unsigned char *src, *srcptr;
MWPIXELVAL *dst, *dstptr;
MWPIXELVAL *bitmap;
int size, width, height;
TT_Outline outline;
TT_BBox bbox;
TT_Raster_Map Raster;
TT_Error error;
/*MWPIXELVAL save;*/
MWFREETYPEFONTCACHE * cache;
 
/* we begin by grid-fitting the bounding box */
TT_Get_Glyph_Outline (pf->glyph, &outline);
TT_Get_Outline_BBox (&outline, &bbox);
 
xmin = (bbox.xMin & -64) >> 6;
ymin = (bbox.yMin & -64) >> 6;
xmax = ((bbox.xMax + 63) & -64) >> 6;
ymax = ((bbox.yMax + 63) & -64) >> 6;
width = xmax - xmin;
height = ymax - ymin;
size = width * height;
 
/* now re-allocate the raster bitmap */
Raster.rows = height;
Raster.width = width;
 
if (pf->fontattr&MWTF_ANTIALIAS)
Raster.cols = (Raster.width + 3) & -4; /* pad to 32-bits */
else
Raster.cols = (Raster.width + 7) & -8; /* pad to 64-bits ??? */
 
cache = find_cache_glyph(pf,curchar);
/* SDR: if cache is 0 here, something really really bad happened */
 
Raster.flow = TT_Flow_Up;
Raster.size = Raster.rows * Raster.cols;
Raster.bitmap = cache->buffer;
 
if (Raster.bitmap == 0)
{
Raster.bitmap = malloc (Raster.size);
 
memset (Raster.bitmap, 0, Raster.size);
 
/* now render the glyph in the small pixmap */
 
/* IMPORTANT NOTE: the offset parameters passed to the function */
/* TT_Get_Glyph_Bitmap() must be integer pixel values, i.e., */
/* multiples of 64. HINTING WILL BE RUINED IF THIS ISN'T THE CASE! */
/* This is why we _did_ grid-fit the bounding box, especially xmin */
/* and ymin. */
 
if (!(pf->fontattr&MWTF_ANTIALIAS))
error = TT_Get_Glyph_Bitmap (pf->glyph, &Raster,
-xmin * 64, -ymin * 64);
else
error = TT_Get_Glyph_Pixmap (pf->glyph, &Raster,
-xmin * 64, -ymin * 64);
 
if (error) {
free (Raster.bitmap);
return;
}
 
cache->buffer = Raster.bitmap;
}
 
#if MWFREETYPEFONT_CACHEBITMAP
if ((memcmp(&gr_foreground,&cache->fg,sizeof(gr_foreground)) != 0) ||
(memcmp(&gr_background,&cache->bg,sizeof(gr_background)) != 0) ||
(gr_usebg != cache->usebg))
{
if (cache->bitmap)
{
free(cache->bitmap);
cache->bitmap = 0;
}
}
 
bitmap = cache->bitmap;
#else
bitmap = 0;
#endif
 
if (bitmap == 0)
{
bitmap = malloc (size * sizeof (MWPIXELVAL));
memset (bitmap, 0, size * sizeof (MWPIXELVAL));
 
src = (char *) Raster.bitmap;
dst = bitmap + (size - width);
 
for (y = ymin; y < ymax; y++)
{
srcptr = src;
dstptr = dst;
 
for (x = xmin; x < xmax; x++)
{
if (pf->fontattr&MWTF_ANTIALIAS)
*dstptr++ = gray_palette[(int) *srcptr];
else
{
for ( z=0;
z <= ((xmax-x-1) < 7 ? (xmax-x-1) : 7);
z++ )
*dstptr++ = ((*srcptr << z) & 0x80) ? gr_foreground : gr_background;
x += 7;
}
 
srcptr++;
}
 
src += Raster.cols;
dst -= width;
}
#if MWFREETYPEFONT_CACHEBITMAP
cache->fg = gr_foreground;
cache->bg = gr_background;
cache->usebg = gr_usebg;
cache->bitmap = bitmap;
#endif
}
 
/* Now draw the bitmap ... */
GdArea(psd, x_offset + xmin, y_offset - (ymin + height), width, height,
bitmap, MWPF_PIXELVAL);
 
#if !MWFREETYPEFONT_CACHEBITMAP
free(bitmap);
#endif
}
 
/*
* Draw unicode 16 text string using FREETYPE type font
*/
static void
freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay,
const void *text, int cc, int flags)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
const unsigned short * str = text;
TT_F26Dot6 x = ax, y = ay;
TT_Pos vec_x, vec_y;
int i;
TT_F26Dot6 startx, starty;
TT_Outline outline;
TT_UShort curchar;
TT_Glyph_Metrics metrics;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
TT_F26Dot6 ascent, descent;
static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff };
static unsigned char virtual_palette[5] = { 0, 1, 2, 3, 4 };
 
pf->last_glyph_code = -1; /* reset kerning*/
pf->last_pen_pos = -32767;
 
/*
* Compute instance ascent & descent values
* in fractional units (1/64th pixel)
*/
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
ascent = ((properties.horizontal->Ascender * imetrics.y_scale)/0x10000);
descent = ((properties.horizontal->Descender*imetrics.y_scale)/0x10000);
 
/*
* Offset the starting point if necessary,
* FreeType always aligns at baseline
*/
if (flags&MWTF_BOTTOM) {
vec_x = 0;
vec_y = descent;
TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
x -= vec_x / 64;
y += vec_y / 64;
} else if (flags&MWTF_TOP) {
vec_x = 0;
vec_y = ascent;
TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
x -= vec_x / 64;
y += vec_y / 64;
}
 
/* Set the "graylevels" */
if (pf->fontattr&MWTF_ANTIALIAS) {
TT_Set_Raster_Gray_Palette (engine, virtual_palette);
 
alphablend(psd, gray_palette, gr_foreground, gr_background,
blend, 5);
}
 
startx = x;
starty = y;
for (i = 0; i < cc; i++) {
curchar = TT_Char_Index (pf->char_map, str[i]);
 
if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
TTLOAD_DEFAULT) != TT_Err_Ok)
continue;
 
if (pf->fontrotation) {
TT_Get_Glyph_Outline (pf->glyph, &outline);
TT_Transform_Outline (&outline, &pf->matrix);
}
 
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
 
if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) {
if (pf->fontrotation) {
vec_x = compute_kernval(pf, curchar);
vec_y = 0;
TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
 
x += vec_x / 64;
y -= vec_y / 64;
} else
x += compute_kernval(pf, curchar) / 64;
}
drawchar(pf, psd, curchar, x, y);
 
if (pf->fontrotation) {
vec_x = metrics.advance;
vec_y = 0;
TT_Transform_Vector (&vec_x, &vec_y, &pf->matrix);
 
x += vec_x / 64;
y -= vec_y / 64;
} else {
x += metrics.advance / 64;
 
/* Kerning point syndrome avoidance */
if (pf->last_pen_pos > x)
x = pf->last_pen_pos;
pf->last_pen_pos = x;
}
 
pf->last_glyph_code = curchar;
}
 
if (pf->fontattr & MWTF_UNDERLINE)
GdLine(psd, startx, starty, x, y, FALSE);
}
 
/*
* Return information about a specified font.
*/
static MWBOOL
freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
{
int i;
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
TT_UShort last_glyph_index;
 
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
 
/* Fill up the fields */
pfontinfo->height = (((properties.horizontal->Ascender * \
imetrics.y_scale)/ 0x10000) >> 6) -
(((properties.horizontal->Descender * \
imetrics.y_scale)/ 0x10000) >> 6);
pfontinfo->maxwidth = ((properties.horizontal->xMax_Extent * \
imetrics.x_scale)/ 0x10000) >> 6;
pfontinfo->baseline = ((properties.horizontal->Ascender * \
imetrics.y_scale)/ 0x10000) >> 6;
pfontinfo->firstchar = TT_CharMap_First(pf->char_map, NULL);
pfontinfo->lastchar = TT_CharMap_Last(pf->char_map, NULL);
pfontinfo->fixed = properties.postscript->isFixedPitch;
last_glyph_index = properties.num_Glyphs > 255 ? 255: properties.num_Glyphs-1;
 
/* Doesn't work ... don't know why ....*/
#if 0
if (TT_Get_Face_Widths( pf->face, 0,
last_glyph_index, widths, NULL ) != TT_Err_Ok) {
return TRUE;
}
 
for(i=0; i<=last_glyph_index; i++)
DPRINTF("widths[%d]: %d\n", i, widths[i]);
#endif
 
/* Get glyphs widths */
for(i=0; i<=last_glyph_index; i++)
pfontinfo->widths[i] = Get_Glyph_Width(pf, i);
 
#if 0
DPRINTF("x_ppem: %d\ny_ppem: %d\nx_scale: %d\ny_scale: %d\n\
x_resolution: %d\ny_resolution: %d\n",
imetrics.x_ppem, imetrics.y_ppem, imetrics.x_scale, \
imetrics.y_scale, imetrics.x_resolution, imetrics.y_resolution);
 
DPRINTF("Ascender: %d\nDescender: %d\nxMax_Extent: %d\n\
Mac Style Say Italic?: %d\nMac Style Say Bold?: %d\n\
sTypoAscender: %d\nsTypoDescender: %d\nusWinAscent: %d\n\
usWinDescent: %d\nusFirstCharIndex: %d\nusLastCharIndex: %d\n\
OS2 Say Italic?: %d\nOS2 Say Bold?: %d\nOS2 Say monospaced?: %d\n\
Postscript Say monospaced?: %d\n",\
properties.horizontal->Ascender,
properties.horizontal->Descender,
properties.horizontal->xMax_Extent,
(properties.header->Mac_Style & 0x2)?1:0,
(properties.header->Mac_Style & 0x1)?1:0,
properties.os2->sTypoAscender,
properties.os2->sTypoDescender,
properties.os2->usWinAscent,
properties.os2->usWinDescent,
properties.os2->usFirstCharIndex,
properties.os2->usLastCharIndex,
(properties.os2->fsSelection & 0x1)?1:0,
(properties.os2->fsSelection & 0x20)?1:0,
properties.postscript->isFixedPitch,
(properties.os2->panose[3] == 9)?1:0);
#endif
return TRUE;
}
 
static void
freetype_gettextsize(PMWFONT pfont, const void *text, int cc,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
const unsigned short * str = text;
TT_F26Dot6 x = 0;
int i;
TT_UShort curchar;
TT_Glyph_Metrics metrics;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
 
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
pf->last_glyph_code = -1; /* reset kerning*/
pf->last_pen_pos = -32767;
for (i = 0; i < cc; i++) {
curchar = TT_Char_Index (pf->char_map, str[i]);
 
if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
continue;
 
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
 
if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) {
x += compute_kernval(pf, curchar) / 64;
}
x += metrics.advance / 64;
 
/* Kerning point syndrome avoidance */
if (pf->last_pen_pos > x)
x = pf->last_pen_pos;
pf->last_pen_pos = x;
 
pf->last_glyph_code = curchar;
}
 
*pwidth = x;
*pheight = (((properties.horizontal->Ascender *
imetrics.y_scale)/ 0x10000) >> 6) -
(((properties.horizontal->Descender *
imetrics.y_scale)/ 0x10000) >> 6);
/* FIXME: is it what's required ?? */
*pbase = (((-properties.horizontal->Descender) *
imetrics.y_scale)/ 0x10000) >> 6;
}
 
static void
freetype_destroyfont(PMWFONT pfont)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
 
TT_Close_Face(pf->face);
 
/*----------*/
 
if (pf->glyph_cache != 0)
free_cache_glyph(pf->glyph_cache);
 
/*----------*/
 
free(pf);
}
 
static void
freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
pf->fontsize = fontsize;
/* We want real pixel sizes ... not points ...*/
TT_Set_Instance_PixelSizes( pf->instance, pf->fontsize,
pf->fontsize, pf->fontsize * 64 );
#if 0
/* set charsize (convert to points for freetype)*/
TT_Set_Instance_CharSize (pf->instance,
((pf->fontsize * 72 + 96/2) / 96) * 64);
#endif
}
 
static void
freetype_setfontrotation(PMWFONT pfont, int tenthdegrees)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
float angle;
pf->fontrotation = tenthdegrees;
 
/* Build the rotation matrix with the given angle */
TT_Set_Instance_Transform_Flags (pf->instance, TRUE, FALSE);
 
angle = pf->fontrotation * M_PI / 1800;
pf->matrix.yy = (TT_Fixed) (cos (angle) * (1 << 16));
pf->matrix.yx = (TT_Fixed) (sin (angle) * (1 << 16));
pf->matrix.xx = pf->matrix.yy;
pf->matrix.xy = -pf->matrix.yx;
}
 
#endif /* HAVE_FREETYPE_SUPPORT*/
 
/* UTF-8 to UTF-16 conversion. Surrogates are handeled properly, e.g.
* a single 4-byte UTF-8 character is encoded into a surrogate pair.
* On the other hand, if the UTF-8 string contains surrogate values, this
* is considered an error and returned as such.
*
* The destination array must be able to hold as many Unicode-16 characters
* as there are ASCII characters in the UTF-8 string. This in case all UTF-8
* characters are ASCII characters. No more will be needed.
*
* Copyright (c) 2000 Morten Rolland, Screen Media
*/
static int
utf8_to_utf16(const unsigned char *utf8, int cc, unsigned short *unicode16)
{
int count = 0;
unsigned char c0, c1;
unsigned long scalar;
 
while(--cc >= 0) {
c0 = *utf8++;
/*DPRINTF("Trying: %02x\n",c0);*/
 
if ( c0 < 0x80 ) {
/* Plain ASCII character, simple translation :-) */
*unicode16++ = c0;
count++;
continue;
}
 
if ( (c0 & 0xc0) == 0x80 )
/* Illegal; starts with 10xxxxxx */
return -1;
 
/* c0 must be 11xxxxxx if we get here => at least 2 bytes */
scalar = c0;
if(--cc < 0)
return -1;
c1 = *utf8++;
/*DPRINTF("c1=%02x\n",c1);*/
if ( (c1 & 0xc0) != 0x80 )
/* Bad byte */
return -1;
scalar <<= 6;
scalar |= (c1 & 0x3f);
 
if ( !(c0 & 0x20) ) {
/* Two bytes UTF-8 */
if ( scalar < 0x80 )
return -1; /* Overlong encoding */
*unicode16++ = scalar & 0x7ff;
count++;
continue;
}
 
/* c0 must be 111xxxxx if we get here => at least 3 bytes */
if(--cc < 0)
return -1;
c1 = *utf8++;
/*DPRINTF("c1=%02x\n",c1);*/
if ( (c1 & 0xc0) != 0x80 )
/* Bad byte */
return -1;
scalar <<= 6;
scalar |= (c1 & 0x3f);
 
if ( !(c0 & 0x10) ) {
/*DPRINTF("####\n");*/
/* Three bytes UTF-8 */
if ( scalar < 0x800 )
return -1; /* Overlong encoding */
if ( scalar >= 0xd800 && scalar < 0xe000 )
return -1; /* UTF-16 high/low halfs */
*unicode16++ = scalar & 0xffff;
count++;
continue;
}
 
/* c0 must be 1111xxxx if we get here => at least 4 bytes */
c1 = *utf8++;
if(--cc < 0)
return -1;
/*DPRINTF("c1=%02x\n",c1);*/
if ( (c1 & 0xc0) != 0x80 )
/* Bad byte */
return -1;
scalar <<= 6;
scalar |= (c1 & 0x3f);
 
if ( !(c0 & 0x08) ) {
/* Four bytes UTF-8, needs encoding as surrogates */
if ( scalar < 0x10000 )
return -1; /* Overlong encoding */
scalar -= 0x10000;
*unicode16++ = ((scalar >> 10) & 0x3ff) + 0xd800;
*unicode16++ = (scalar & 0x3ff) + 0xdc00;
count += 2;
continue;
}
 
return -1; /* No support for more than four byte UTF-8 */
}
return count;
}
 
#if HAVE_HZK_SUPPORT
 
/* UniCode-16 (MWTF_UC16) to GB(MWTF_ASCII) Chinese Characters conversion.
* a single 2-byte UC16 character is encoded into a surrogate pair.
* return -1 ,if error;
* The destination array must be able to hold as many
* as there are Unicode-16 characters.
*
* Copyright (c) 2000 Tang Hao (TownHall)(tang_hao@263.net).
*/
static int
UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii)
{
FILE* fp;
char buffer[256];
unsigned char *uc16p;
int i=0,j=0, k;
unsigned char *filebuffer;
unsigned short *uc16pp,*table;
unsigned short uc16px;
int length=31504;
 
if (use_big5)
length=54840;
 
uc16p=(unsigned char *) uc16;
uc16pp=(unsigned short *) uc16;
 
strcpy(buffer,HZK_FONT_DIR);
if (use_big5)
strcat(buffer,"/BG2UBG.KU");
else
strcat(buffer,"/UGB2GB.KU");
if(!(fp = fopen(buffer, "rb")))
{
fprintf (stderr, "Error.\nThe %s file can not be found!\n",buffer);
return -1;
}
 
filebuffer= (unsigned char *)malloc ( length);
 
if(fread(filebuffer, sizeof(char),length, fp) < length) {
fprintf (stderr, "Error in reading ugb2gb.ku file!\n");
fclose(fp);
return -1;
}
fclose(fp);
 
if (use_big5)
{
table=(unsigned short *)filebuffer;
while(1)
{
if(j>=cc)
{
ascii[i]=0;
break;
}
uc16px=*uc16pp;
if((uc16px)<=0x00ff)
{
ascii[i]=(char)(*uc16pp);
i++;
}
else
{
ascii[i]=0xa1; ascii[i+1]=0x40;
for (k=0; k<13710; k++)
{
if (*(table+(k*2+1))==(uc16px))
{
ascii[i]=(char)((*(table+(k*2)) & 0xff00) >> 8);
ascii[i+1]=(char)(*(table+(k*2)) & 0x00ff);
break;
}
}
i+=2;
}
uc16pp++; j++;
}
}
else
{
while(1)
{
if(j>=cc)
{
ascii[i]=0;
break;
}
if((*((uc16p)+j)==0)&&(*((uc16p)+j+1)==0))
{
ascii[i]=0;
break;
}
else
{
if(*((uc16p)+j+1)==0)
{
ascii[i]=*((uc16p)+j);
i++;
j+=2;
}
else
{
 
{
int p1=0,p2=length-4,p;
unsigned int c1,c2,c,d;
c1=((unsigned int )filebuffer[p1])*0x100+(filebuffer[p1+1]);
c2=((unsigned int )filebuffer[p2])*0x100+(filebuffer[p2+1]);
d=((unsigned int )*((uc16p)+j))*0x100+*((uc16p)+j+1);
if(c1==d)
{
ascii[i]=filebuffer[p1+2];
ascii[i+1]=filebuffer[p1+3];
goto findit;
}
if(c2==d)
{
ascii[i]=filebuffer[p2+2];
ascii[i+1]=filebuffer[p2+3];
goto findit;
}
while(1)
{
p=(((p2-p1)/2+p1)>>2)<<2;
c=((unsigned int )filebuffer[p])*0x100+(filebuffer[p+1]);
if(d==c) /*find it*/
{
ascii[i]=filebuffer[p+2];
ascii[i+1]=filebuffer[p+3];
break;
}
else if(p2<=p1+4) /*can't find.*/
{
ascii[i]='.';/*((uc16p)+j);*/
ascii[i+1]='.';/*((uc16p)+j+1);*/
break;
}
else if(d<c)
{
p2=p;
c2=c;
}
else
{
p1=p;
c1=c;
}
}
}
findit:
i+=2;
j+=2;
}
}
}
}
free(filebuffer);
 
return i;
}
 
/************************** functions definition ******************************/
 
static int hzk_id( PMWHZKFONT pf )
{
switch(pf->font_height)
{
case 12:
return 0;
case 16: default:
return 1;
}
}
 
/* This function get Chinese font info from etc file.*/
static MWBOOL GetCFontInfo( PMWHZKFONT pf )
{
int charset;
 
if (use_big5)
charset=(13094+408);
else
charset=8178;
 
CFont[hzk_id(pf)].width = pf->cfont_width;
pf->CFont.width = pf->cfont_width;
 
CFont[hzk_id(pf)].height = pf->font_height;
pf->CFont.height = pf->font_height;
 
CFont[hzk_id(pf)].size = ((pf->CFont.width + 7) / 8) *
pf->CFont.height * charset;
pf->CFont.size = ((pf->CFont.width + 7) / 8) * pf->CFont.height * charset;
 
if(pf->CFont.size < charset * 8)
return FALSE;
 
strcpy(CFont[hzk_id(pf)].file,HZK_FONT_DIR);
strcpy(pf->CFont.file,HZK_FONT_DIR);
 
if(pf->font_height==16)
{
strcat(CFont[hzk_id(pf)].file,"/hzk16");
strcat(pf->CFont.file,"/hzk16");
}
else
{
strcat(CFont[hzk_id(pf)].file,"/hzk12");
strcat(pf->CFont.file,"/hzk12");
}
 
if (use_big5)
{
CFont[hzk_id(pf)].file[strlen(pf->CFont.file)-3]+=use_big5;
pf->CFont.file[strlen(pf->CFont.file)-3]+=use_big5;
}
 
return TRUE;
}
 
/* This function get ASCII font info from etc file.*/
static MWBOOL GetAFontInfo( PMWHZKFONT pf )
{
AFont[hzk_id(pf)].width = pf->afont_width;
pf->AFont.width = pf->afont_width;
 
AFont[hzk_id(pf)].height = pf->font_height;
pf->AFont.height = pf->font_height;
 
AFont[hzk_id(pf)].size = ((pf->AFont.width + 7) / 8) *
pf->AFont.height * 255;
pf->AFont.size = ((pf->AFont.width + 7) / 8) * pf->AFont.height * 255;
if(pf->AFont.size < 255 * 8)
return FALSE;
 
strcpy(AFont[hzk_id(pf)].file,HZK_FONT_DIR);
strcpy(pf->AFont.file,HZK_FONT_DIR);
if(pf->font_height==16)
{
strcat(AFont[hzk_id(pf)].file,"/asc16");
strcat(pf->AFont.file,"/asc16");
}
else
{
strcat(AFont[hzk_id(pf)].file,"/asc12");
strcat(pf->AFont.file,"/asc12");
}
return TRUE;
}
 
/* This function load system font into memory.*/
static MWBOOL LoadFont( PMWHZKFONT pf )
{
FILE* fp;
 
if(!GetCFontInfo(pf))
{
fprintf (stderr, "Get Chinese HZK font info failure!\n");
return FALSE;
}
if(CFont[hzk_id(pf)].pFont == NULL)/*check font cache*/
{
 
/* Allocate system memory for Chinese font.*/
if( !(CFont[hzk_id(pf)].pFont = (char *)malloc(pf->CFont.size)) )
{
fprintf (stderr, "Allocate memory for Chinese HZK font failure.\n");
return FALSE;
}
/* Open font file and read information to the system memory.*/
fprintf (stderr, "Loading Chinese HZK font from file(%s)..." ,pf->CFont.file);
if(!(fp = fopen(CFont[hzk_id(pf)].file, "rb")))
{
fprintf (stderr, "Error.\nThe Chinese HZK font file can not be found!\n");
return FALSE;
}
if(fread(CFont[hzk_id(pf)].pFont, sizeof(char), pf->CFont.size, fp) < pf->CFont.size)
{
fprintf (stderr, "Error in reading Chinese HZK font file!\n");
fclose(fp);
return FALSE;
}
 
fclose(fp);
 
CFont[hzk_id(pf)].use_count=0;
 
fprintf (stderr, "done.\n" );
 
}
cfont_address = CFont[hzk_id(pf)].pFont;
pf->cfont_address = CFont[hzk_id(pf)].pFont;
pf->CFont.pFont = CFont[hzk_id(pf)].pFont;
 
CFont[hzk_id(pf)].use_count++;
 
if(!GetAFontInfo(pf))
{
fprintf (stderr, "Get ASCII HZK font info failure!\n");
return FALSE;
}
if(AFont[hzk_id(pf)].pFont == NULL)/*check font cache*/
{
/* Allocate system memory for ASCII font.*/
if( !(AFont[hzk_id(pf)].pFont = (char *)malloc(pf->AFont.size)) )
{
fprintf (stderr, "Allocate memory for ASCII HZK font failure.\n");
free(CFont[hzk_id(pf)].pFont);
CFont[hzk_id(pf)].pFont = NULL;
return FALSE;
}
/* Load ASCII font information to the near memory.*/
fprintf (stderr, "Loading ASCII HZK font..." );
if(!(fp = fopen(AFont[hzk_id(pf)].file, "rb")))
{
fprintf (stderr, "Error.\nThe ASCII HZK font file can not be found!\n");
return FALSE;
}
if(fread(AFont[hzk_id(pf)].pFont, sizeof(char), pf->AFont.size, fp) < pf->AFont.size)
{
fprintf (stderr, "Error in reading ASCII HZK font file!\n");
fclose(fp);
return FALSE;
}
fclose(fp);
AFont[hzk_id(pf)].use_count=0;
 
fprintf (stderr, "done.\n" );
 
}
afont_address = AFont[hzk_id(pf)].pFont;
pf->afont_address = AFont[hzk_id(pf)].pFont;
pf->AFont.pFont = AFont[hzk_id(pf)].pFont;
 
AFont[hzk_id(pf)].use_count++;
 
return TRUE;
}
 
/* This function unload system font from memory.*/
static void UnloadFont( PMWHZKFONT pf )
{
CFont[hzk_id(pf)].use_count--;
AFont[hzk_id(pf)].use_count--;
 
if (!CFont[hzk_id(pf)].use_count)
{
free(pf->CFont.pFont);
free(pf->AFont.pFont);
 
CFont[hzk_id(pf)].pFont = NULL;
AFont[hzk_id(pf)].pFont = NULL;
}
}
 
static int
hzk_init(PSD psd)
{
/* FIXME: *.KU file should be opened and
* read in here...*/
return 1;
}
 
static PMWHZKFONT
hzk_createfont(const char *name, MWCOORD height, int attr)
{
PMWHZKFONT pf;
 
if(strcmp(name,"HZKFONT")!=0 && strcmp(name,"HZXFONT")!=0)
return FALSE;
 
printf("hzk_createfont(%s,%d)\n",name,height);
 
use_big5=name[2]-'K';
 
/* allocate font structure*/
pf = (PMWHZKFONT)calloc(sizeof(MWHZKFONT), 1);
if (!pf)
return NULL;
pf->fontprocs = &hzk_procs;
 
pf->fontsize=height;
/*GdSetFontSize((PMWFONT)pf, height);*/
GdSetFontRotation((PMWFONT)pf, 0);
GdSetFontAttr((PMWFONT)pf, attr, 0);
 
if(height==12)
{
afont_width = 6;
cfont_width = 12;
font_height = 12;
 
pf->afont_width = 6;
pf->cfont_width = 12;
pf->font_height = 12;
}
else
{
afont_width = 8;
cfont_width = 16;
font_height = 16;
 
pf->afont_width = 8;
pf->cfont_width = 16;
pf->font_height = 16;
}
 
/* Load the font library to the system memory.*/
if(!LoadFont(pf))
return FALSE;
 
return pf;
}
 
int IsBig5(int i)
{
if ((i>=0xa140 && i<=0xa3bf) || /* a140-a3bf(!a3e0) */
(i>=0xa440 && i<=0xc67e) || /* a440-c67e */
(i>=0xc6a1 && i<=0xc8d3) || /* c6a1-c8d3(!c8fe) */
(i>=0xc940 && i<=0xf9fe)) /* c940-f9fe */
return 1;
else
return 0;
}
 
/*
* following several function is used in hzk_drawtext
*/
 
static int getnextchar(char* s, unsigned char* cc)
{
if( s[0] == '\0') return 0;
 
cc[0] = (unsigned char)(*s);
cc[1] = (unsigned char)(*(s + 1));
 
if (use_big5)
{
if( IsBig5( (int) ( (cc[0] << 8) + cc[1]) ) )
return 1;
}
else
{
if( ((unsigned char)cc[0] > 0xa0) &&
((unsigned char)cc[1] > 0xa0) )
return 1;
}
 
cc[1] = '\0';
 
return 1;
}
 
static void
expandcchar(PMWHZKFONT pf, int bg, int fg, unsigned char* c, MWPIXELVAL* bitmap)
{
int i=0;
int c1, c2, seq;
int x,y;
unsigned char *font;
int b = 0; /* keep gcc happy with b = 0 - MW */
 
int pixelsize;
pixelsize=sizeof(MWPIXELVAL);
 
c1 = c[0];
c2 = c[1];
if (use_big5)
{
seq=0;
/*ladd=loby-(if(loby<127)?64:98)*/
c2-=(c2<127?64:98);
 
/*hadd=(hiby-164)*157*/
if (c1>=0xa4)/*standard font*/
{
seq=(((c1-164)*157)+c2);
if (seq>=5809) seq-=408;
}
 
/*hadd=(hiby-161)*157*/
if (c1<=0xa3)/*special font*/
seq=(((c1-161)*157)+c2)+13094;
}
else
seq=((c1 - 161)*94 + c2 - 161);
 
font = pf->cfont_address + ((seq) *
(pf->font_height * ((pf->cfont_width + 7) / 8)));
 
for (y = 0; y < pf->font_height; y++)
for (x = 0; x < pf->cfont_width; x++)
{
if (x % 8 == 0)
b = *font++;
 
if (b & (128 >> (x % 8))) /* pixel */
bitmap[i++]=fg;
else
bitmap[i++]=bg;
}
}
 
static void expandchar(PMWHZKFONT pf, int bg, int fg, int c, MWPIXELVAL* bitmap)
{
int i=0;
int x,y;
unsigned char *font;
int pixelsize;
int b = 0; /* keep gcc happy with b = 0 - MW */
 
pixelsize=sizeof(MWPIXELVAL);
 
font = pf->afont_address + c * (pf->font_height *
((pf->afont_width + 7) / 8));
 
for (y = 0; y < pf->font_height; y++)
for (x = 0; x < pf->afont_width; x++)
{
if (x % 8 == 0)
b = *font++;
if (b & (128 >> (x % 8))) /* pixel */
bitmap[i++]=fg;
else
bitmap[i++]=bg;
}
}
 
/*
* Draw ASCII text string using HZK type font
*/
static void
hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay,
const void *text, int cc, int flags)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
 
unsigned char c[2];
MWPIXELVAL *bitmap;
unsigned char s1[3];
char *s,*sbegin;
 
s=(char *)text;
 
if(cc==1)
{
s1[0]=*((unsigned char*)text);
s1[1]=0x0;
s1[2]=0x0;
s=s1;
}
 
sbegin=s;
bitmap = (MWPIXELVAL *)ALLOCA(pf->cfont_width * pf->font_height *
sizeof(MWPIXELVAL));
 
while( getnextchar(s, c) )
{
if( c[1] != '\0')
{
expandcchar(pf, gr_background,gr_foreground,
c, bitmap);
/* Now draw the bitmap ... */
if (flags&MWTF_TOP)
GdArea(psd,ax, ay, pf->cfont_width,
pf->font_height, bitmap, MWPF_PIXELVAL);
else
GdArea(psd,ax, ay-pf->font_height+2,
pf->cfont_width, pf->font_height,
bitmap, MWPF_PIXELVAL);
 
s += 2;
ax += pf->cfont_width;
}
else
{
expandchar(pf, gr_background,gr_foreground,
c[0], bitmap);
/* Now draw the bitmap ... */
 
if (flags&MWTF_TOP)
GdArea(psd,ax, ay, pf->afont_width,
pf->font_height, bitmap, MWPF_PIXELVAL);
else
GdArea(psd,ax, ay-pf->font_height+2,
pf->afont_width, pf->font_height,
bitmap, MWPF_PIXELVAL);
 
s += 1;
ax += pf->afont_width;
}
if(s>=sbegin+cc)break;
}
 
FREEA(bitmap);
}
 
/*
* Return information about a specified font.
*/
static MWBOOL
hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
 
int i;
 
pfontinfo->height = pf->font_height;
pfontinfo->maxwidth = pf->cfont_width;
pfontinfo->baseline = pf->font_height-2;
pfontinfo->firstchar = 0;
pfontinfo->lastchar = 0;
pfontinfo->fixed = TRUE;
for(i=0; i<=256; i++)
pfontinfo->widths[i] = pf->afont_width;
 
return TRUE;
}
 
static void
hzk_gettextsize(PMWFONT pfont, const void *text, int cc,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
 
unsigned char c[2];
char *s,*sbegin;
unsigned char s1[3];
 
int ax=0;
 
 
 
s=(char *)text;
if(cc==0)
{
*pwidth = 0;
*pheight = pf->font_height;
*pbase = pf->font_height-2;
 
}
if(cc==1)
{
s1[0]=*((unsigned char*)text);
s1[1]=0x0;
s1[2]=0x0;
s=s1;
}
sbegin=s;
while( getnextchar(s, c) )
{
if( c[1] != '\0')
{
s += 2;
ax += pf->cfont_width;
}
else
{
s += 1;
ax += pf->afont_width;
}
if(s>=sbegin+cc)break;
/* fprintf(stderr,"s=%x,sbegin=%x,cc=%x\n",s,sbegin,cc);*/
 
}
/* fprintf(stderr,"ax=%d,\n",ax);*/
 
*pwidth = ax;
*pheight = pf->font_height;
*pbase = pf->font_height-2;
}
 
static void
hzk_destroyfont(PMWFONT pfont)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
 
UnloadFont(pf);
free(pf);
}
 
static void
hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
 
/*jmt: hzk_setfontsize not supported*/
/*jmt: & pf->fontsize can't be changed*/
/*jmt: because of hzk_id() :p*/
pf->fontsize=pf->font_height;
}
#endif /* HAVE_HZK_SUPPORT*/
 
/* FIXME: this routine should work for all font renderers...*/
int
GdGetTextSizeEx(PMWFONT pfont, const void *str, int cc,int nMaxExtent,
int* lpnFit, int* alpDx,MWCOORD *pwidth,MWCOORD *pheight,
MWCOORD *pbase, int flags)
{
#ifdef HAVE_FREETYPE_SUPPORT
unsigned short buf[256];
unsigned short* text;
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
int defencoding = pf->fontprocs->encoding;
int x = 0;
int i;
TT_UShort curchar;
TT_Glyph_Metrics metrics;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
 
if ((cc<0)||(!str))
{
*pwidth = *pheight = *pbase = 0;
return 0;
}
/* convert encoding if required*/
if((flags & MWTF_PACKMASK) != defencoding)
{
cc = GdConvertEncoding(str, flags, cc, buf, defencoding);
flags &= ~MWTF_PACKMASK;
flags |= defencoding;
text=buf;
} else text =(unsigned short*)str;
if(cc <= 0)
{
*pwidth = *pheight = *pbase = 0;
return 0;
}
 
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
pf->last_glyph_code = -1; /* reset kerning*/
pf->last_pen_pos = -32767;
if (lpnFit)
*lpnFit=-1;
for (i = 0; i < cc; i++)
{
curchar = TT_Char_Index (pf->char_map,text[i]);
if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
{
printf("Unable to load glyph with index=%d\n",curchar);
return 0;
}
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
if ((pf->fontattr&MWTF_KERNING) && pf->can_kern)
{
x += compute_kernval(pf, curchar) / 64;
}
x += metrics.advance / 64;
if((lpnFit)&&(alpDx))
{
if (x<=nMaxExtent)
alpDx[i]=x;
else
if (*lpnFit==-1)
(*lpnFit)=i;
}
/* Kerning point syndrome avoidance */
if (pf->last_pen_pos > x)
x = pf->last_pen_pos;
pf->last_pen_pos = x;
pf->last_glyph_code = curchar;
}
if ((lpnFit)&&(*lpnFit==-1))
*lpnFit=cc;
*pwidth = x;
*pheight = (((properties.horizontal->Ascender *
imetrics.y_scale)/ 0x10000) >> 6) -
(((properties.horizontal->Descender *
imetrics.y_scale)/ 0x10000) >> 6);
/*FIXME: is it what's required ??*/
if (pbase)
*pbase = (((-properties.horizontal->Descender) *
imetrics.y_scale)/ 0x10000) >> 6;
return 1;
#else /* HAVE_FREETYPE_SUPPORT*/
*pwidth = *pheight = *pbase = 0;
return 0;
#endif
}
/devopen.c
0,0 → 1,529
/*
* Copyright (c) 1999, 2000, 2001 Greg Haerr <greg@censoft.com>
* Portions Copyright (c) 1991 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Device-independent mid level screen device init routines
*
* These routines implement the smallest Microwindows engine level
* interface to the screen driver. By setting the NOFONTSORCLIPPING
* config option, only these routines will be included, which can
* be used to generate a low-level interface to the screen drivers
* without dragging in any other GdXXX routines.
*/
#include <stdio.h>
#include <stdlib.h>
#include "device.h"
#include "swap.h"
 
#if MSDOS | ELKS
#define NOSTDPAL8
#endif
 
/*
* The following define can change depending on the window manager
* usage of colors and layout of the 8bpp palette devpal8.c.
* Color entries below this value won't be overwritten by user
* programs or bitmap display conversion tables.
*/
#define FIRSTUSERPALENTRY 24 /* first writable pal entry over 16 color*/
 
MWPIXELVAL gr_foreground; /* current foreground color */
MWPIXELVAL gr_background; /* current background color */
MWBOOL gr_usebg; /* TRUE if background drawn in pixmaps */
int gr_mode = MWMODE_COPY; /* drawing mode */
/*static*/ MWPALENTRY gr_palette[256]; /* current palette*/
/*static*/ int gr_firstuserpalentry;/* first user-changable palette entry*/
/*static*/ int gr_nextpalentry; /* next available palette entry*/
static int gr_pixtype; /* screen pixel format*/
static long gr_ncolors; /* screen # colors*/
 
/*
* Open low level graphics driver
*/
PSD
GdOpenScreen(void)
{
PSD psd;
MWPALENTRY * stdpal;
MWSCREENINFO sinfo;
 
psd = scrdev.Open(&scrdev);
if (!psd)
return NULL;
GdGetScreenInfo(psd, &sinfo);
gr_pixtype = sinfo.pixtype;
gr_ncolors = sinfo.ncolors;
 
/* assume no user changable palette entries*/
gr_firstuserpalentry = (int)psd->ncolors;
 
/* set palette according to system colors and devpalX.c*/
switch((int)psd->ncolors) {
 
#if !defined(NOSTDPAL1) /* don't require stdpal1 if not needed */
case 2: /* 1bpp*/
{
extern MWPALENTRY mwstdpal1[2];
stdpal = mwstdpal1;
}
break;
#endif
 
#if !defined(NOSTDPAL2) /* don't require stdpal2 if not needed */
case 4: /* 2bpp*/
{
extern MWPALENTRY mwstdpal2[4];
stdpal = mwstdpal2;
}
break;
#endif
 
#if !defined(NOSTDPAL4)
/* don't require stdpal4 if not needed */
case 8: /* 3bpp - not fully supported*/
case 16: /* 4bpp*/
{
extern MWPALENTRY mwstdpal4[16];
stdpal = mwstdpal4;
}
break;
#endif
 
#if !defined(NOSTDPAL8) /* don't require large stdpal8 if not needed */
case 256: /* 8bpp*/
{
extern MWPALENTRY mwstdpal8[256];
#if xxxALPHABLEND
/* don't change uniform palette if alpha blending*/
gr_firstuserpalentry = 256;
#else
/* start after last system-reserved color*/
gr_firstuserpalentry = FIRSTUSERPALENTRY;
#endif
stdpal = mwstdpal8;
}
break;
#endif /* !defined(NOSTDPAL8)*/
 
default: /* truecolor*/
/* no palette*/
gr_firstuserpalentry = 0;
stdpal = NULL;
}
 
/* reset next user palette entry, write hardware palette*/
GdResetPalette();
GdSetPalette(psd, 0, (int)psd->ncolors, stdpal);
#if xxxALPHABLEND
/* one-time create alpha lookup table for 8bpp systems (takes ~1 sec)*/
if(psd->ncolors == 256)
init_alpha_lookup();
#endif
 
#if !NOFONTSORCLIPPING
/* init local vars*/
GdSetMode(MWMODE_COPY);
GdSetForeground(GdFindColor(MWRGB(255, 255, 255))); /* WHITE*/
GdSetBackground(GdFindColor(MWRGB(0, 0, 0))); /* BLACK*/
GdSetUseBackground(TRUE);
GdSetFont(GdCreateFont(psd, MWFONT_SYSTEM_VAR, 0, NULL));
#if DYNAMICREGIONS
GdSetClipRegion(psd,
GdAllocRectRegion(0, 0, psd->xvirtres, psd->yvirtres));
#else
GdSetClipRects(psd, 0, NULL);
#endif /* DYNAMICREGIONS*/
#endif /* NOFONTSORCLIPPING*/
 
/* fill black (actually fill to first palette entry or truecolor 0*/
psd->FillRect(psd, 0, 0, psd->xvirtres-1, psd->yvirtres-1, 0);
return psd;
}
 
/*
* Close low level graphics driver
*/
void
GdCloseScreen(PSD psd)
{
psd->Close(psd);
}
 
/* Set dynamic screen portrait mode, return new mode*/
int
GdSetPortraitMode(PSD psd, int portraitmode)
{
/* set portrait mode if supported*/
if (psd->SetPortrait)
psd->SetPortrait(psd, portraitmode);
return psd->portrait;
}
 
/*
* Return about the screen.
*/
void
GdGetScreenInfo(PSD psd, PMWSCREENINFO psi)
{
psd->GetScreenInfo(psd, psi);
GdGetButtonInfo(&psi->buttons);
GdGetModifierInfo(&psi->modifiers, NULL);
GdGetCursorPos(&psi->xpos, &psi->ypos);
}
 
/* reset palette to empty except for system colors*/
void
GdResetPalette(void)
{
/* note: when palette entries are changed, all
* windows may need to be redrawn
*/
gr_nextpalentry = gr_firstuserpalentry;
}
 
/* set the system palette section to the passed palette entries*/
void
GdSetPalette(PSD psd, int first, int count, MWPALENTRY *palette)
{
int i;
 
/* no palette management needed if running truecolor*/
if(psd->pixtype != MWPF_PALETTE)
return;
 
/* bounds check against # of device color entries*/
if(first + count > (int)psd->ncolors)
count = (int)psd->ncolors - first;
if(count >= 0 && first < (int)psd->ncolors) {
psd->SetPalette(psd, first, count, palette);
 
/* copy palette for GdFind*Color*/
for(i=0; i<count; ++i)
gr_palette[i+first] = palette[i];
}
}
 
/* get system palette entries, return count*/
int
GdGetPalette(PSD psd, int first, int count, MWPALENTRY *palette)
{
int i;
 
/* no palette if running truecolor*/
if(psd->pixtype != MWPF_PALETTE)
return 0;
 
/* bounds check against # of device color entries*/
if(first + count > (int)psd->ncolors)
if( (count = (int)psd->ncolors - first) <= 0)
return 0;
 
for(i=0; i<count; ++i)
*palette++ = gr_palette[i+first];
 
return count;
}
 
/*
* Convert a palette-independent value to a hardware color
*/
MWPIXELVAL
GdFindColor(MWCOLORVAL c)
{
/*
* Handle truecolor displays. Note that the MWF_PALINDEX
* bit is ignored when running truecolor drivers.
*/
switch(gr_pixtype) {
case MWPF_TRUECOLOR0888:
case MWPF_TRUECOLOR888:
/* create 24 bit 8/8/8 pixel (0x00RRGGBB) from RGB colorval*/
/*RGB2PIXEL888(REDVALUE(c), GREENVALUE(c), BLUEVALUE(c))*/
return COLOR2PIXEL888(c);
 
case MWPF_TRUECOLOR565:
/* create 16 bit 5/6/5 format pixel from RGB colorval*/
/*RGB2PIXEL565(REDVALUE(c), GREENVALUE(c), BLUEVALUE(c))*/
return COLOR2PIXEL565(c);
 
case MWPF_TRUECOLOR555:
/* create 16 bit 5/5/5 format pixel from RGB colorval*/
/*RGB2PIXEL555(REDVALUE(c), GREENVALUE(c), BLUEVALUE(c))*/
return COLOR2PIXEL555(c);
 
case MWPF_TRUECOLOR332:
/* create 8 bit 3/3/2 format pixel from RGB colorval*/
/*RGB2PIXEL332(REDVALUE(c), GREENVALUE(c), BLUEVALUE(c))*/
return COLOR2PIXEL332(c);
}
 
/* case MWPF_PALETTE: must be running 1, 2, 4 or 8 bit palette*/
 
/*
* Check if color is a palette index. Note that the index
* isn't error checked against the system palette, for speed.
*/
if(c & MWF_PALINDEX)
return (c & 0xff);
 
/* search palette for closest match*/
return GdFindNearestColor(gr_palette, (int)gr_ncolors, c);
}
 
/*
* Search a palette to find the nearest color requested.
* Uses a weighted squares comparison.
*/
MWPIXELVAL
GdFindNearestColor(MWPALENTRY *pal, int size, MWCOLORVAL cr)
{
MWPALENTRY * rgb;
int r, g, b;
int R, G, B;
long diff = 0x7fffffffL;
long sq;
int best = 0;
 
r = REDVALUE(cr);
g = GREENVALUE(cr);
b = BLUEVALUE(cr);
for(rgb=pal; diff && rgb < &pal[size]; ++rgb) {
R = rgb->r - r;
G = rgb->g - g;
B = rgb->b - b;
#if 1
/* speedy linear distance method*/
sq = abs(R) + abs(G) + abs(B);
#else
/* slower distance-cubed with luminance adjustment*/
/* gray is .30R + .59G + .11B*/
/* = (R*77 + G*151 + B*28)/256*/
sq = (long)R*R*30*30 + (long)G*G*59*59 + (long)B*B*11*11;
#endif
 
if(sq < diff) {
best = rgb - pal;
if((diff = sq) == 0)
return best;
}
}
return best;
}
 
#if !VXWORKS
#include <unistd.h>
#include <fcntl.h>
/*
* Create .bmp file from framebuffer data
*
* 1, 4, 8, 16, 24 and 32 bpp supported
*/
#define BI_RGB 0L
#define BI_RLE8 1L
#define BI_RLE4 2L
#define BI_BITFIELDS 3L
 
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
 
#pragma pack(1)
/* windows style bmp*/
typedef struct {
/* BITMAPFILEHEADER*/
BYTE bfType[2];
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
/* BITMAPINFOHEADER*/
DWORD BiSize;
LONG BiWidth;
LONG BiHeight;
WORD BiPlanes;
WORD BiBitCount;
DWORD BiCompression;
DWORD BiSizeImage;
LONG BiXpelsPerMeter;
LONG BiYpelsPerMeter;
DWORD BiClrUsed;
DWORD BiClrImportant;
} BMPHEAD;
#pragma pack()
 
/* r/g/b masks for non-palette bitmaps*/
#define RMASK332 0xe0
#define GMASK332 0x1c
#define BMASK332 0x03
#define RMASK555 0x7c00
#define GMASK555 0x03e0
#define BMASK555 0x001f
#define RMASK565 0xf800
#define GMASK565 0x07e0
#define BMASK565 0x001f
#define RMASK888 0xff0000
#define GMASK888 0x00ff00
#define BMASK888 0x0000ff
 
#if defined(HAVE_FILEIO)
static void
putsw(unsigned long dw, FILE *ofp)
{
/* little-endian storage of shortword*/
putc((unsigned char)dw, ofp);
dw >>= 8;
putc((unsigned char)dw, ofp);
}
 
static void
putdw(unsigned long dw, FILE *ofp)
{
/* little-endian storage of longword*/
putc((unsigned char)dw, ofp);
dw >>= 8;
putc((unsigned char)dw, ofp);
dw >>= 8;
putc((unsigned char)dw, ofp);
dw >>= 8;
putc((unsigned char)dw, ofp);
}
#endif /* HAVE_FILEIO*/
 
/* create .bmp file from framebuffer data*/
int
GdCaptureScreen(char *path)
{
#if defined(HAVE_FILEIO)
int ifd, i, j;
FILE * ofp;
int cx, cy, extra, bpp, bytespp, ncolors, sizecolortable;
unsigned long rmask, gmask, bmask;
unsigned char *cptr;
unsigned short *sptr;
unsigned long *lptr;
BMPHEAD bmp;
unsigned char buf[2048*4];
 
ofp = fopen(path, "wb");
if (!ofp)
return 1;
ifd = open("/dev/fb0", 0);
 
cx = scrdev.xvirtres;
cy = scrdev.yvirtres;
bpp = scrdev.bpp;
bytespp = (bpp+7)/8;
 
/* dword right padded*/
extra = (cx*bytespp) & 3;
if (extra)
extra = 4 - extra;
ncolors = (bpp <= 8)? (1<<bpp): 0;
/* color table is either palette or 3 longword r/g/b masks*/
sizecolortable = ncolors? ncolors*4: 3*4;
if (bpp == 24)
sizecolortable = 0; /* special case 24bpp has no table*/
 
/* fill out bmp header*/
memset(&bmp, 0, sizeof(bmp));
bmp.bfType[0] = 'B';
bmp.bfType[1] = 'M';
bmp.bfSize = dwswap(sizeof(bmp) + sizecolortable + (long)(cx+extra)*cy*bytespp);
bmp.bfOffBits = dwswap(sizeof(bmp) + sizecolortable);
bmp.BiSize = dwswap(40);
bmp.BiWidth = dwswap(cx);
bmp.BiHeight = dwswap(cy);
bmp.BiPlanes = wswap(1);
bmp.BiBitCount = wswap(bpp);
bmp.BiCompression = dwswap((bpp==16 || bpp==32)? BI_BITFIELDS: BI_RGB);
bmp.BiSizeImage = dwswap((long)(cx+extra)*cy*bytespp);
bmp.BiClrUsed = dwswap((bpp <= 8)? ncolors: 0);
/*bmp.BiClrImportant = 0;*/
 
/* write header*/
fwrite(&bmp, sizeof(bmp), 1, ofp);
 
/* write colortable*/
if (sizecolortable) {
if(bpp <= 8) {
/* write palette*/
for(i=0; i<ncolors; i++) {
putc(gr_palette[i].b, ofp);
putc(gr_palette[i].g, ofp);
putc(gr_palette[i].r, ofp);
putc(0, ofp);
}
} else {
/* write 3 r/g/b masks*/
switch (gr_pixtype) {
case MWPF_TRUECOLOR0888:
default:
rmask = RMASK888;
gmask = GMASK888;
bmask = BMASK888;
break;
case MWPF_TRUECOLOR565:
rmask = RMASK565;
gmask = GMASK565;
bmask = BMASK565;
break;
case MWPF_TRUECOLOR555:
rmask = RMASK555;
gmask = GMASK555;
bmask = BMASK555;
break;
case MWPF_TRUECOLOR332:
rmask = RMASK332;
gmask = GMASK332;
bmask = BMASK332;
break;
}
putdw(rmask, ofp);
putdw(gmask, ofp);
putdw(bmask, ofp);
}
}
 
/* write image data, upside down ;)*/
for(i=cy-1; i>=0; --i) {
long base = sizeof(bmp) + sizecolortable + (long)i*cx*bytespp;
fseek(ofp, base, SEEK_SET);
read(ifd, buf, cx*bytespp);
switch (bpp) {
case 32:
lptr = (unsigned long *)buf;
for(j=0; j<cx; ++j)
putdw(*lptr++, ofp);
break;
case 24:
cptr = (unsigned char *)buf;
for(j=0; j<cx; ++j) {
putc(*cptr++, ofp);
putc(*cptr++, ofp);
putc(*cptr++, ofp);
}
break;
case 16:
sptr = (unsigned short *)buf;
for(j=0; j<cx; ++j)
putsw(*sptr++, ofp);
break;
default:
cptr = (unsigned char *)buf;
for(j=0; j<cx; ++j)
putc(*cptr++, ofp);
break;
}
for(j=0; j<extra; ++j)
putc(0, ofp); /* DWORD pad each line*/
}
 
fclose(ofp);
close(ifd);
#endif /* HAVE_FILEIO*/
return 0;
}
#endif /* !VXWORKS*/
/devpal8.c
0,0 → 1,302
/*
* Copyright (c) 1999 Greg Haerr <greg@censoft.com>
*
* 8bpp (256 color) standard palette definition
*/
#include "device.h"
 
/*
* Special palette for supporting 48 Windows colors and a 216 color
* uniform color distribution.
* Note: the first 20 colors are used internally as system colors.
*/
MWPALENTRY mwstdpal8[256] = {
/* 16 EGA colors, arranged for direct predefined palette indexing*/
RGBDEF( 0 , 0 , 0 ), /* black*/
RGBDEF( 0 , 0 , 128 ), /* blue*/
RGBDEF( 0 , 128, 0 ), /* green*/
RGBDEF( 0 , 128, 128 ), /* cyan*/ /* COLOR_BACKGROUND*/
RGBDEF( 128, 0 , 0 ), /* red*/ /* COLOR_ACTIVECAPTION A*/
RGBDEF( 128, 0 , 128 ), /* magenta*/ /* COLOR_ACTIVECAPTION B*/
RGBDEF( 128, 64 , 0 ), /* adjusted brown*/
RGBDEF( 192, 192, 192 ), /* ltgray*/
RGBDEF( 128, 128, 128 ), /* gray*/
RGBDEF( 0 , 0 , 255 ), /* ltblue*/
RGBDEF( 0 , 255, 0 ), /* ltgreen*/
RGBDEF( 0 , 255, 255 ), /* ltcyan*/
RGBDEF( 255, 0 , 0 ), /* ltred*/
RGBDEF( 255, 0 , 255 ), /* ltmagenta*/
RGBDEF( 255, 255, 0 ), /* yellow*/
RGBDEF( 255, 255, 255 ), /* white*/
 
/* 32 basic windows colors (first 8 are most important)*/
RGBDEF( 32 , 32 , 32 ), /* DKGRAY_BRUSH*/
RGBDEF( 128, 128, 0 ), /* non-adjusted brown*/
RGBDEF( 223, 223, 223 ), /* COLOR_3DLIGHT B*/
RGBDEF( 160, 160, 160 ), /* COLOR_3DLIGHT C*/
 
RGBDEF( 234, 230, 221 ), /* COLOR_BTNHIGHLIGHT A*/
RGBDEF( 213, 204, 187 ), /* COLOR_BTNFACE A*/
RGBDEF( 162, 141, 104 ), /* COLOR_BTNSHADOW A*/
RGBDEF( 0 , 64 , 128 ), /* COLOR_INACTIVECAPTION C*/
/*RGBDEF( 0 , 0 , 64 ),*/
/*RGBDEF( 0 , 64 , 0 ),*/
/*RGBDEF( 0 , 64 , 64 ),*/
/*RGBDEF( 0 , 128, 64 ),*/
RGBDEF( 0 , 128, 255 ),
RGBDEF( 0 , 255, 128 ),
RGBDEF( 64 , 0 , 0 ),
RGBDEF( 64 , 0 , 64 ),
RGBDEF( 64 , 0 , 128 ),
RGBDEF( 64 , 128, 128 ),
RGBDEF( 128, 0 , 64 ),
RGBDEF( 128, 0 , 255 ),
RGBDEF( 128, 64 , 64 ),
RGBDEF( 128, 128, 64 ),
RGBDEF( 128, 128, 192 ),
RGBDEF( 128, 128, 255 ),
RGBDEF( 128, 255, 0 ),
RGBDEF( 128, 255, 255 ),
RGBDEF( 164, 200, 240 ),
RGBDEF( 192, 220, 192 ),
RGBDEF( 255, 0 , 128 ),
RGBDEF( 255, 128, 0 ),
RGBDEF( 255, 128, 192 ),
RGBDEF( 255, 128, 255 ),
RGBDEF( 255, 128, 128 ),
RGBDEF( 255, 255, 128 ),
RGBDEF( 255, 251, 240 ),
RGBDEF( 255, 255, 232 ),
 
/* 216 colors spread uniformly across rgb spectrum*/
/* 8 colors removed that are duplicated above*/
/*RGBDEF( 0x00, 0x00, 0x00 ),*/
RGBDEF( 0x00, 0x00, 0x33 ),
RGBDEF( 0x00, 0x00, 0x66 ),
RGBDEF( 0x00, 0x00, 0x99 ),
RGBDEF( 0x00, 0x00, 0xcc ),
/*RGBDEF( 0x00, 0x00, 0xff ),*/
RGBDEF( 0x33, 0x00, 0x00 ),
RGBDEF( 0x33, 0x00, 0x33 ),
RGBDEF( 0x33, 0x00, 0x66 ),
RGBDEF( 0x33, 0x00, 0x99 ),
RGBDEF( 0x33, 0x00, 0xcc ),
RGBDEF( 0x33, 0x00, 0xff ),
RGBDEF( 0x66, 0x00, 0x00 ),
RGBDEF( 0x66, 0x00, 0x33 ),
RGBDEF( 0x66, 0x00, 0x66 ),
RGBDEF( 0x66, 0x00, 0x99 ),
RGBDEF( 0x66, 0x00, 0xcc ),
RGBDEF( 0x66, 0x00, 0xff ),
RGBDEF( 0x99, 0x00, 0x00 ),
RGBDEF( 0x99, 0x00, 0x33 ),
RGBDEF( 0x99, 0x00, 0x66 ),
RGBDEF( 0x99, 0x00, 0x99 ),
RGBDEF( 0x99, 0x00, 0xcc ),
RGBDEF( 0x99, 0x00, 0xff ),
RGBDEF( 0xcc, 0x00, 0x00 ),
RGBDEF( 0xcc, 0x00, 0x33 ),
RGBDEF( 0xcc, 0x00, 0x66 ),
RGBDEF( 0xcc, 0x00, 0x99 ),
RGBDEF( 0xcc, 0x00, 0xcc ),
RGBDEF( 0xcc, 0x00, 0xff ),
/*RGBDEF( 0xff, 0x00, 0x00 ),*/
RGBDEF( 0xff, 0x00, 0x33 ),
RGBDEF( 0xff, 0x00, 0x66 ),
RGBDEF( 0xff, 0x00, 0x99 ),
RGBDEF( 0xff, 0x00, 0xcc ),
/*RGBDEF( 0xff, 0x00, 0xff ),*/
RGBDEF( 0x00, 0x33, 0x00 ),
RGBDEF( 0x00, 0x33, 0x33 ),
RGBDEF( 0x00, 0x33, 0x66 ),
RGBDEF( 0x00, 0x33, 0x99 ),
RGBDEF( 0x00, 0x33, 0xcc ),
RGBDEF( 0x00, 0x33, 0xff ),
RGBDEF( 0x33, 0x33, 0x00 ),
RGBDEF( 0x33, 0x33, 0x33 ),
RGBDEF( 0x33, 0x33, 0x66 ),
RGBDEF( 0x33, 0x33, 0x99 ),
RGBDEF( 0x33, 0x33, 0xcc ),
RGBDEF( 0x33, 0x33, 0xff ),
RGBDEF( 0x66, 0x33, 0x00 ),
RGBDEF( 0x66, 0x33, 0x33 ),
RGBDEF( 0x66, 0x33, 0x66 ),
RGBDEF( 0x66, 0x33, 0x99 ),
RGBDEF( 0x66, 0x33, 0xcc ),
RGBDEF( 0x66, 0x33, 0xff ),
RGBDEF( 0x99, 0x33, 0x00 ),
RGBDEF( 0x99, 0x33, 0x33 ),
RGBDEF( 0x99, 0x33, 0x66 ),
RGBDEF( 0x99, 0x33, 0x99 ),
RGBDEF( 0x99, 0x33, 0xcc ),
RGBDEF( 0x99, 0x33, 0xff ),
RGBDEF( 0xcc, 0x33, 0x00 ),
RGBDEF( 0xcc, 0x33, 0x33 ),
RGBDEF( 0xcc, 0x33, 0x66 ),
RGBDEF( 0xcc, 0x33, 0x99 ),
RGBDEF( 0xcc, 0x33, 0xcc ),
RGBDEF( 0xcc, 0x33, 0xff ),
RGBDEF( 0xff, 0x33, 0x00 ),
RGBDEF( 0xff, 0x33, 0x33 ),
RGBDEF( 0xff, 0x33, 0x66 ),
RGBDEF( 0xff, 0x33, 0x99 ),
RGBDEF( 0xff, 0x33, 0xcc ),
RGBDEF( 0xff, 0x33, 0xff ),
RGBDEF( 0x00, 0x66, 0x00 ),
RGBDEF( 0x00, 0x66, 0x33 ),
RGBDEF( 0x00, 0x66, 0x66 ),
RGBDEF( 0x00, 0x66, 0x99 ),
RGBDEF( 0x00, 0x66, 0xcc ),
RGBDEF( 0x00, 0x66, 0xff ),
RGBDEF( 0x33, 0x66, 0x00 ),
RGBDEF( 0x33, 0x66, 0x33 ),
RGBDEF( 0x33, 0x66, 0x66 ),
RGBDEF( 0x33, 0x66, 0x99 ),
RGBDEF( 0x33, 0x66, 0xcc ),
RGBDEF( 0x33, 0x66, 0xff ),
RGBDEF( 0x66, 0x66, 0x00 ),
RGBDEF( 0x66, 0x66, 0x33 ),
RGBDEF( 0x66, 0x66, 0x66 ),
RGBDEF( 0x66, 0x66, 0x99 ),
RGBDEF( 0x66, 0x66, 0xcc ),
RGBDEF( 0x66, 0x66, 0xff ),
RGBDEF( 0x99, 0x66, 0x00 ),
RGBDEF( 0x99, 0x66, 0x33 ),
RGBDEF( 0x99, 0x66, 0x66 ),
RGBDEF( 0x99, 0x66, 0x99 ),
RGBDEF( 0x99, 0x66, 0xcc ),
RGBDEF( 0x99, 0x66, 0xff ),
RGBDEF( 0xcc, 0x66, 0x00 ),
RGBDEF( 0xcc, 0x66, 0x33 ),
RGBDEF( 0xcc, 0x66, 0x66 ),
RGBDEF( 0xcc, 0x66, 0x99 ),
RGBDEF( 0xcc, 0x66, 0xcc ),
RGBDEF( 0xcc, 0x66, 0xff ),
RGBDEF( 0xff, 0x66, 0x00 ),
RGBDEF( 0xff, 0x66, 0x33 ),
RGBDEF( 0xff, 0x66, 0x66 ),
RGBDEF( 0xff, 0x66, 0x99 ),
RGBDEF( 0xff, 0x66, 0xcc ),
RGBDEF( 0xff, 0x66, 0xff ),
RGBDEF( 0x00, 0x99, 0x00 ),
RGBDEF( 0x00, 0x99, 0x33 ),
RGBDEF( 0x00, 0x99, 0x66 ),
RGBDEF( 0x00, 0x99, 0x99 ),
RGBDEF( 0x00, 0x99, 0xcc ),
RGBDEF( 0x00, 0x99, 0xff ),
RGBDEF( 0x33, 0x99, 0x00 ),
RGBDEF( 0x33, 0x99, 0x33 ),
RGBDEF( 0x33, 0x99, 0x66 ),
RGBDEF( 0x33, 0x99, 0x99 ),
RGBDEF( 0x33, 0x99, 0xcc ),
RGBDEF( 0x33, 0x99, 0xff ),
RGBDEF( 0x66, 0x99, 0x00 ),
RGBDEF( 0x66, 0x99, 0x33 ),
RGBDEF( 0x66, 0x99, 0x66 ),
RGBDEF( 0x66, 0x99, 0x99 ),
RGBDEF( 0x66, 0x99, 0xcc ),
RGBDEF( 0x66, 0x99, 0xff ),
RGBDEF( 0x99, 0x99, 0x00 ),
RGBDEF( 0x99, 0x99, 0x33 ),
RGBDEF( 0x99, 0x99, 0x66 ),
RGBDEF( 0x99, 0x99, 0x99 ),
RGBDEF( 0x99, 0x99, 0xcc ),
RGBDEF( 0x99, 0x99, 0xff ),
RGBDEF( 0xcc, 0x99, 0x00 ),
RGBDEF( 0xcc, 0x99, 0x33 ),
RGBDEF( 0xcc, 0x99, 0x66 ),
RGBDEF( 0xcc, 0x99, 0x99 ),
RGBDEF( 0xcc, 0x99, 0xcc ),
RGBDEF( 0xcc, 0x99, 0xff ),
RGBDEF( 0xff, 0x99, 0x00 ),
RGBDEF( 0xff, 0x99, 0x33 ),
RGBDEF( 0xff, 0x99, 0x66 ),
RGBDEF( 0xff, 0x99, 0x99 ),
RGBDEF( 0xff, 0x99, 0xcc ),
RGBDEF( 0xff, 0x99, 0xff ),
RGBDEF( 0x00, 0xcc, 0x00 ),
RGBDEF( 0x00, 0xcc, 0x33 ),
RGBDEF( 0x00, 0xcc, 0x66 ),
RGBDEF( 0x00, 0xcc, 0x99 ),
RGBDEF( 0x00, 0xcc, 0xcc ),
RGBDEF( 0x00, 0xcc, 0xff ),
RGBDEF( 0x33, 0xcc, 0x00 ),
RGBDEF( 0x33, 0xcc, 0x33 ),
RGBDEF( 0x33, 0xcc, 0x66 ),
RGBDEF( 0x33, 0xcc, 0x99 ),
RGBDEF( 0x33, 0xcc, 0xcc ),
RGBDEF( 0x33, 0xcc, 0xff ),
RGBDEF( 0x66, 0xcc, 0x00 ),
RGBDEF( 0x66, 0xcc, 0x33 ),
RGBDEF( 0x66, 0xcc, 0x66 ),
RGBDEF( 0x66, 0xcc, 0x99 ),
RGBDEF( 0x66, 0xcc, 0xcc ),
RGBDEF( 0x66, 0xcc, 0xff ),
RGBDEF( 0x99, 0xcc, 0x00 ),
RGBDEF( 0x99, 0xcc, 0x33 ),
RGBDEF( 0x99, 0xcc, 0x66 ),
RGBDEF( 0x99, 0xcc, 0x99 ),
RGBDEF( 0x99, 0xcc, 0xcc ),
RGBDEF( 0x99, 0xcc, 0xff ),
RGBDEF( 0xcc, 0xcc, 0x00 ),
RGBDEF( 0xcc, 0xcc, 0x33 ),
RGBDEF( 0xcc, 0xcc, 0x66 ),
RGBDEF( 0xcc, 0xcc, 0x99 ),
RGBDEF( 0xcc, 0xcc, 0xcc ),
RGBDEF( 0xcc, 0xcc, 0xff ),
RGBDEF( 0xff, 0xcc, 0x00 ),
RGBDEF( 0xff, 0xcc, 0x33 ),
RGBDEF( 0xff, 0xcc, 0x66 ),
RGBDEF( 0xff, 0xcc, 0x99 ),
RGBDEF( 0xff, 0xcc, 0xcc ),
RGBDEF( 0xff, 0xcc, 0xff ),
/*RGBDEF( 0x00, 0xff, 0x00 ),*/
RGBDEF( 0x00, 0xff, 0x33 ),
RGBDEF( 0x00, 0xff, 0x66 ),
RGBDEF( 0x00, 0xff, 0x99 ),
RGBDEF( 0x00, 0xff, 0xcc ),
/*RGBDEF( 0x00, 0xff, 0xff ),*/
RGBDEF( 0x33, 0xff, 0x00 ),
RGBDEF( 0x33, 0xff, 0x33 ),
RGBDEF( 0x33, 0xff, 0x66 ),
RGBDEF( 0x33, 0xff, 0x99 ),
RGBDEF( 0x33, 0xff, 0xcc ),
RGBDEF( 0x33, 0xff, 0xff ),
RGBDEF( 0x66, 0xff, 0x00 ),
RGBDEF( 0x66, 0xff, 0x33 ),
RGBDEF( 0x66, 0xff, 0x66 ),
RGBDEF( 0x66, 0xff, 0x99 ),
RGBDEF( 0x66, 0xff, 0xcc ),
RGBDEF( 0x66, 0xff, 0xff ),
RGBDEF( 0x99, 0xff, 0x00 ),
RGBDEF( 0x99, 0xff, 0x33 ),
RGBDEF( 0x99, 0xff, 0x66 ),
RGBDEF( 0x99, 0xff, 0x99 ),
RGBDEF( 0x99, 0xff, 0xcc ),
RGBDEF( 0x99, 0xff, 0xff ),
RGBDEF( 0xcc, 0xff, 0x00 ),
RGBDEF( 0xcc, 0xff, 0x33 ),
RGBDEF( 0xcc, 0xff, 0x66 ),
RGBDEF( 0xcc, 0xff, 0x99 ),
RGBDEF( 0xcc, 0xff, 0xcc ),
RGBDEF( 0xcc, 0xff, 0xff ),
/*RGBDEF( 0xff, 0xff, 0x00 ),*/
RGBDEF( 0xff, 0xff, 0x33 ),
RGBDEF( 0xff, 0xff, 0x66 ),
RGBDEF( 0xff, 0xff, 0x99 ),
RGBDEF( 0xff, 0xff, 0xcc ),
/*RGBDEF( 0xff, 0xff, 0xff )*/
};
 
#if TEST
main()
{
int c;
 
DPRINTF("%d\n", ((int)&stdpalette[1]) - (int)&stdpalette[0]);
 
c = FindNearestColor(stdpalette, 224, 224, 224);
DPRINTF("%d = %02x %02x %02x\n", c, stdpalette[c].r, stdpalette[c].g,
stdpalette[c].b);
}
#endif
/devarc.c
0,0 → 1,589
/*
* Copyright (c) 2000-2001 Greg Haerr <greg@censoft.com>
*
* Device-independent arc, pie and ellipse routines.
* GdArc is integer only and requires start/end points.
* GdArcAngle requires floating point and uses angles.
* GdArcAngle uses qsin() and qcos() instead of sin() / cos()
* so no math lib needed.
*
* Portions Copyright (c) 1991 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Arc line clipping and integer qsin/qcos routines used by permission:
* Copyright (C) 1997-1998 by Eero Tamminen
* Bugfixed by Greg Haerr
*/
 
#include <stdio.h>
#include "device.h"
 
#if HAVEFLOAT /* =1 compiles in GdArcAngle*/
#define HIGHPRECISION 0 /* =1 for high precision angles, uses mathlib*/
 
#if !HIGHPRECISION
typedef float FLOAT;
/*
* qsin/qcos - calculate sin() and cos() approximations from a lookup table
*
* This uses a cosine lookup table of 0-90 degrees at one degree steps
* with the difference between successive values used for interpolation.
* The achieved accuracy should be about +/-0.0001. If you want more
* accuracy, use doubles and smaller steps. If you want more speed, use
* fixed point arithmetics.
*/
static float cosine[91][2] = {
{ 1.000000, -1.523048e-04 },
{ 0.999848, -4.568681e-04 },
{ 0.999391, -7.612923e-04 },
{ 0.998630, -1.065484e-03 },
{ 0.997564, -1.369352e-03 },
{ 0.996195, -1.672803e-03 },
{ 0.994522, -1.975744e-03 },
{ 0.992546, -2.278083e-03 },
{ 0.990268, -2.579728e-03 },
{ 0.987688, -2.880588e-03 },
{ 0.984808, -3.180570e-03 },
{ 0.981627, -3.479583e-03 },
{ 0.978148, -3.777536e-03 },
{ 0.974370, -4.074339e-03 },
{ 0.970296, -4.369900e-03 },
{ 0.965926, -4.664130e-03 },
{ 0.961262, -4.956940e-03 },
{ 0.956305, -5.248240e-03 },
{ 0.951057, -5.537941e-03 },
{ 0.945519, -5.825955e-03 },
{ 0.939693, -6.112194e-03 },
{ 0.933580, -6.396572e-03 },
{ 0.927184, -6.679001e-03 },
{ 0.920505, -6.959396e-03 },
{ 0.913545, -7.237671e-03 },
{ 0.906308, -7.513741e-03 },
{ 0.898794, -7.787522e-03 },
{ 0.891007, -8.058931e-03 },
{ 0.882948, -8.327886e-03 },
{ 0.874620, -8.594303e-03 },
{ 0.866025, -8.858103e-03 },
{ 0.857167, -9.119205e-03 },
{ 0.848048, -9.377528e-03 },
{ 0.838671, -9.632995e-03 },
{ 0.829038, -9.885528e-03 },
{ 0.819152, -1.013505e-02 },
{ 0.809017, -1.038148e-02 },
{ 0.798636, -1.062476e-02 },
{ 0.788011, -1.086479e-02 },
{ 0.777146, -1.110152e-02 },
{ 0.766044, -1.133486e-02 },
{ 0.754710, -1.156475e-02 },
{ 0.743145, -1.179112e-02 },
{ 0.731354, -1.201390e-02 },
{ 0.719340, -1.223302e-02 },
{ 0.707107, -1.244841e-02 },
{ 0.694658, -1.266001e-02 },
{ 0.681998, -1.286775e-02 },
{ 0.669131, -1.307158e-02 },
{ 0.656059, -1.327142e-02 },
{ 0.642788, -1.346722e-02 },
{ 0.629320, -1.365892e-02 },
{ 0.615661, -1.384645e-02 },
{ 0.601815, -1.402977e-02 },
{ 0.587785, -1.420882e-02 },
{ 0.573576, -1.438353e-02 },
{ 0.559193, -1.455387e-02 },
{ 0.544639, -1.471977e-02 },
{ 0.529919, -1.488119e-02 },
{ 0.515038, -1.503807e-02 },
{ 0.500000, -1.519038e-02 },
{ 0.484810, -1.533806e-02 },
{ 0.469472, -1.548106e-02 },
{ 0.453990, -1.561935e-02 },
{ 0.438371, -1.575289e-02 },
{ 0.422618, -1.588162e-02 },
{ 0.406737, -1.600551e-02 },
{ 0.390731, -1.612454e-02 },
{ 0.374607, -1.623864e-02 },
{ 0.358368, -1.634781e-02 },
{ 0.342020, -1.645199e-02 },
{ 0.325568, -1.655116e-02 },
{ 0.309017, -1.664529e-02 },
{ 0.292372, -1.673435e-02 },
{ 0.275637, -1.681831e-02 },
{ 0.258819, -1.689715e-02 },
{ 0.241922, -1.697084e-02 },
{ 0.224951, -1.703936e-02 },
{ 0.207912, -1.710270e-02 },
{ 0.190809, -1.716082e-02 },
{ 0.173648, -1.721371e-02 },
{ 0.156434, -1.726136e-02 },
{ 0.139173, -1.730376e-02 },
{ 0.121869, -1.734088e-02 },
{ 0.104528, -1.737272e-02 },
{ 0.087156, -1.739927e-02 },
{ 0.069756, -1.742052e-02 },
{ 0.052336, -1.743646e-02 },
{ 0.034899, -1.744709e-02 },
{ 0.017452, -1.745241e-02 },
{ 0.000000, -1.745241e-02 }
};
 
static float
qcos(FLOAT angle)
{
short a, b, c;
 
a = angle;
if (a < 0) {
angle = a - angle;
a = -a;
} else {
angle = angle - a;
}
b = a / 90;
c = a - b * 90;
 
/* interpolate according to angle */
switch(b&3) {
case 3:
c = 90 - c;
return cosine[c][0] - cosine[c-1][1] * angle;
case 2:
return -(cosine[c][0] + cosine[c][1] * angle);
case 1:
c = 90 - c;
return cosine[c-1][1] * angle - cosine[c][0];
default:
return cosine[c][0] + cosine[c][1] * angle;
}
}
 
static float
qsin(FLOAT angle)
{
short a, b, c;
 
/* change to cosine by subtracting 90 */
a = (int)angle - 90;
if (a < 0) {
angle = (a + 90) - angle;
a = -a;
} else {
angle = angle - (a + 90);
}
b = a / 90;
c = a - b * 90;
 
/* interpolate according to angle */
switch(b&3) {
case 3:
c = 90 - c;
return cosine[c][0] - cosine[c-1][1] * angle;
case 2:
return -(cosine[c][0] + cosine[c][1] * angle);
case 1:
c = 90 - c;
return cosine[c-1][1] * angle - cosine[c][0];
default:
return cosine[c][0] + cosine[c][1] * angle;
}
}
#else /* HIGHPRECISION*/
 
#include <math.h>
#define qcos QCOS
#define qsin QSIN
typedef double FLOAT;
 
FLOAT QCOS(FLOAT a)
{
return cos(a * M_PI / 180.);
}
 
FLOAT QSIN(FLOAT a)
{
return sin(a * M_PI / 180.);
}
#endif /* HIGHPRECISION*/
#endif /* HAVEFLOAT*/
 
/*
* Draw an arc or pie, angles are specified in 64th's of a degree.
* This function requires floating point, use GdArc for integer only.
*/
void
GdArcAngle(PSD psd, MWCOORD x0, MWCOORD y0, MWCOORD rx, MWCOORD ry,
MWCOORD angle1, MWCOORD angle2, int type)
{
#if HAVEFLOAT
MWCOORD ax, ay, bx, by;
FLOAT a, b;
 
/* calculate pie edge offsets from center to the ellipse rim */
ax = qcos(angle1/64.) * rx;
bx = qcos(angle2/64.) * rx;
 
a = -qsin(angle1/64.);
b = -qsin(angle2/64.);
ay = a * ry;
by = b * ry;
 
/* call integer routine*/
GdArc(psd, x0, y0, rx, ry, ax, ay, bx, by, type);
#endif /* HAVEFLOAT*/
}
 
/* argument holder for pie, arc and ellipse functions*/
typedef struct {
PSD psd;
MWCOORD x0, y0;
MWCOORD rx, ry;
MWCOORD ax, ay;
MWCOORD bx, by;
int adir, bdir;
int type;
} SLICE;
 
extern void drawpoint(PSD psd, MWCOORD x, MWCOORD y);
extern void drawrow(PSD psd, MWCOORD x1, MWCOORD x2, MWCOORD y);
 
/*
* Clip a line segment for arc or pie drawing.
* Returns 0 if line is clipped or on acceptable side, 1 if it's vertically
* on other side, otherwise 3.
*/
static int
clip_line(SLICE *slice, MWCOORD xe, MWCOORD ye, int dir, MWCOORD y, MWCOORD *x0,
MWCOORD *x1)
{
#if 0
/*
* kluge: handle 180 degree case
*/
if (y >= 0 && ye == 0) {
/*printf("cl %d,%d %d,%d %d,%d %d,%d %d,%d\n", xe, ye, y, dir,
slice->ax, slice->ay, slice->bx, slice->by, slice->adir, slice->bdir);*/
/* bottom 180*/
if (slice->adir < 0) {
if (slice->ay || slice->by)
return 1;
if (slice->ax == -slice->bx)
return 0;
}
return 3;
}
#endif
/* hline on the same vertical side with the given edge? */
if ((y >= 0 && ye >= 0) || (y < 0 && ye < 0)) {
MWCOORD x;
 
if (ye == 0) x = xe; else
x = (MWCOORD)(long)xe * y / ye;
 
if (x >= *x0 && x <= *x1) {
if (dir > 0)
*x0 = x;
else
*x1 = x;
return 0;
} else {
if (dir > 0) {
if (x <= *x0)
return 0;
} else {
if (x >= *x1)
return 0;
}
}
return 3;
}
return 1;
}
 
/* relative offsets, direction from left to right. */
static void
draw_line(SLICE *slice, MWCOORD x0, MWCOORD y, MWCOORD x1)
{
int dbl = (slice->adir > 0 && slice->bdir < 0);
int discard, ret;
MWCOORD x2 = x0, x3 = x1;
 
if (y == 0) {
if (slice->type != MWPIE)
return;
/* edges on different sides */
if ((slice->ay <= 0 && slice->by >= 0) ||
(slice->ay >= 0 && slice->by <= 0)) {
if (slice->adir < 0) {
if (x1 > 0)
x1 = 0;
}
if (slice->bdir > 0) {
if (x0 < 0)
x0 = 0;
}
} else {
if (!dbl) {
/* FIXME leaving in draws dot in center*/
drawpoint(slice->psd, slice->x0, slice->y0);
return;
}
}
drawrow(slice->psd, slice->x0 + x0, slice->x0 + x1, slice->y0);
return;
}
 
/* clip left edge / line */
ret = clip_line(slice, slice->ax, slice->ay, slice->adir, y, &x0, &x1);
 
if (dbl) {
if (!ret) {
/* edges separate line to two parts */
drawrow(slice->psd, slice->x0 + x0, slice->x0 + x1,
slice->y0 + y);
x0 = x2;
x1 = x3;
}
} else {
if (ret > 1) {
return;
}
}
 
discard = ret;
ret = clip_line(slice, slice->bx, slice->by, slice->bdir, y, &x0, &x1);
 
discard += ret;
if (discard > 2 && !(dbl && ret == 0 && discard == 3)) {
return;
}
if (discard == 2) {
/* line on other side than slice */
if (slice->adir < 0 || slice->bdir > 0) {
return;
}
}
drawrow(slice->psd, slice->x0 + x0, slice->x0 + x1, slice->y0 + y);
}
 
/* draw one line segment or set of points, called from drawarc routine*/
static void
drawarcsegment(SLICE *slice, MWCOORD xp, MWCOORD yp)
{
switch (slice->type) {
case MWELLIPSEFILL:
/* draw ellipse fill segment*/
drawrow(slice->psd, slice->x0-xp, slice->x0+xp, slice->y0-yp);
drawrow(slice->psd, slice->x0-xp, slice->x0+xp, slice->y0+yp);
return;
 
case MWELLIPSE:
/* set four points symmetrically situated around a point*/
drawpoint(slice->psd, slice->x0 + xp, slice->y0 + yp);
drawpoint(slice->psd, slice->x0 - xp, slice->y0 + yp);
drawpoint(slice->psd, slice->x0 + xp, slice->y0 - yp);
drawpoint(slice->psd, slice->x0 - xp, slice->y0 - yp);
return;
 
case MWPIE:
/* draw top and bottom halfs of pie*/
draw_line(slice, -xp, -yp, +xp);
draw_line(slice, -xp, +yp, +xp);
return;
 
default: /* MWARC, MWARCOUTLINE*/
/* set four points symmetrically around a point and clip*/
draw_line(slice, +xp, +yp, +xp);
draw_line(slice, -xp, +yp, -xp);
draw_line(slice, +xp, -yp, +xp);
draw_line(slice, -xp, -yp, -xp);
return;
}
}
 
/* General routine to plot points on an arc. Used by arc, pie and ellipse*/
static void
drawarc(SLICE *slice)
{
MWCOORD xp, yp; /* current point (based on center) */
MWCOORD rx, ry;
long Asquared; /* square of x semi axis */
long TwoAsquared;
long Bsquared; /* square of y semi axis */
long TwoBsquared;
long d;
long dx, dy;
 
rx = slice->rx;
ry = slice->ry;
 
xp = 0;
yp = ry;
Asquared = rx * rx;
TwoAsquared = 2 * Asquared;
Bsquared = ry * ry;
TwoBsquared = 2 * Bsquared;
d = Bsquared - Asquared * ry + (Asquared >> 2);
dx = 0;
dy = TwoAsquared * ry;
 
while (dx < dy) {
drawarcsegment(slice, xp, yp);
if (d > 0) {
yp--;
dy -= TwoAsquared;
d -= dy;
}
xp++;
dx += TwoBsquared;
d += (Bsquared + dx);
}
 
d += ((3L * (Asquared - Bsquared) / 2L - (dx + dy)) >> 1);
 
while (yp >= 0) {
drawarcsegment(slice, xp, yp);
if (d < 0) {
xp++;
dx += TwoBsquared;
d += dx;
}
yp--;
dy -= TwoAsquared;
d += (Asquared - dy);
}
 
}
 
/*
* Draw an arc or pie using start/end points.
* Integer only routine. To specify start/end angles,
* use GdArcAngle, which requires floating point.
*/
void
GdArc(PSD psd, MWCOORD x0, MWCOORD y0, MWCOORD rx, MWCOORD ry,
MWCOORD ax, MWCOORD ay, MWCOORD bx, MWCOORD by, int type)
{
MWCOORD adir, bdir;
SLICE slice;
 
if (rx <= 0 || ry <= 0)
return;
 
/*
* Calculate right/left side clipping, based on quadrant.
* dir is positive when right side is filled and negative when
* left side is to be filled.
*
* >= 0 is bottom half
*/
if (ay >= 0)
adir = 1;
else
adir = -1;
 
if (by >= 0)
bdir = -1;
else
bdir = 1;
 
/*
* The clip_line routine has problems around the 0 and
* 180 degree axes.
* This <fix> is required to make the clip_line algorithm
* work. Getting these routines to work for all angles is
* a bitch. And they're still buggy. Doing this causes
* half circles to be outlined with a slightly bent line
* on the x axis. FIXME
*/
if (ay == 0) ++ay;
if (by == 0) ++by;
 
/* swap rightmost edge first */
if (bx > ax) {
MWCOORD swap;
 
swap = ax;
ax = bx;
bx = swap;
 
swap = ay;
ay = by;
by = swap;
 
swap = adir;
adir = bdir;
bdir = swap;
}
 
/* check for entire area clipped, draw with per-point clipping*/
if (GdClipArea(psd, x0-rx, y0-ry, x0+rx, y0+ry) == CLIP_INVISIBLE)
return;
 
slice.psd = psd;
slice.x0 = x0;
slice.y0 = y0;
slice.rx = rx;
slice.ry = ry;
slice.ax = ax;
slice.ay = ay;
slice.bx = bx;
slice.by = by;
slice.adir = adir;
slice.bdir = bdir;
slice.type = type;
 
drawarc(&slice);
 
if (type & MWOUTLINE) {
/* draw two lines from rx,ry to arc endpoints*/
GdLine(psd, x0, y0, x0+ax, y0+ay, TRUE);
GdLine(psd, x0, y0, x0+bx, y0+by, TRUE);
}
 
GdFixCursor(psd);
}
 
/*
* Draw an ellipse using the current clipping region and foreground color.
* This draws in the outline of the ellipse, or fills it.
* Integer only routine.
*/
void
GdEllipse(PSD psd, MWCOORD x, MWCOORD y, MWCOORD rx, MWCOORD ry, MWBOOL fill)
{
SLICE slice;
 
if (rx < 0 || ry < 0)
return;
 
/* Check if the ellipse bounding box is either totally visible
* or totally invisible. Draw with per-point clipping.
*/
switch (GdClipArea(psd, x - rx, y - ry, x + rx, y + ry)) {
case CLIP_VISIBLE:
/*
* For size considerations, there's no low-level ellipse
* draw, so we've got to draw all ellipses
* with per-point clipping for the time being
psd->DrawEllipse(psd, x, y, rx, ry, fill, gr_foreground);
GdFixCursor(psd);
return;
*/
break;
 
case CLIP_INVISIBLE:
return;
}
 
slice.psd = psd;
slice.x0 = x;
slice.y0 = y;
slice.rx = rx;
slice.ry = ry;
slice.type = fill? MWELLIPSEFILL: MWELLIPSE;
/* other elements unused*/
 
drawarc(&slice);
 
GdFixCursor(psd);
}
/devfont.c
0,0 → 1,2689
/*
* Copyright (c) 2000 Greg Haerr <greg@censoft.com>
* T1lib Adobe type1 routines contributed by Vidar Hokstad
* Freetype TrueType routines contributed by Martin Jolicoeur
* Han Zi Ku routines contributed by Tanghao and Jauming
*
* Device-independent font and text drawing routines
*
* These routines do the necessary range checking, clipping, and cursor
* overwriting checks, and then call the lower level device dependent
* routines to actually do the drawing. The lower level routines are
* only called when it is known that all the pixels to be drawn are
* within the device area and are visible.
*/
/*#define NDEBUG*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <string.h>
 
#include "device.h"
#if (UNIX | DOS_DJGPP)
#define strcmpi strcasecmp
#endif
 
#if HAVE_T1LIB_SUPPORT
#include <t1lib.h>
#define T1LIB_USE_AA_HIGH
 
typedef struct {
PMWFONTPROCS fontprocs; /* common hdr*/
MWCOORD fontsize;
int fontrotation;
int fontattr;
 
int fontid; /* t1lib stuff*/
} MWT1LIBFONT, *PMWT1LIBFONT;
 
static int t1lib_init(PSD psd);
static PMWT1LIBFONT t1lib_createfont(const char *name, MWCOORD height,int attr);
static void t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags);
static MWBOOL t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);
static void t1lib_gettextsize(PMWFONT pfont, const void *text, int cc,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
static void t1lib_destroyfont(PMWFONT pfont);
 
/* handling routines for MWT1LIBFONT*/
static MWFONTPROCS t1lib_procs = {
MWTF_ASCII, /* routines expect ascii*/
t1lib_getfontinfo,
t1lib_gettextsize,
NULL, /* gettextbits*/
t1lib_destroyfont,
t1lib_drawtext,
NULL, /* setfontsize*/
NULL, /* setfontrotation*/
NULL, /* setfontattr*/
};
#endif
 
#ifdef T1LIB_USE_AA_HIGH
typedef unsigned long OUTPIXELVAL;
#else
typedef MWPIXELVAL OUTPIXELVAL;
#endif
 
#if HAVE_FREETYPE_SUPPORT
#include <freetype/freetype.h>
#include <freetype/ftxkern.h>
#include <freetype/ftnameid.h>
#include <freetype/ftxcmap.h>
#include <freetype/ftxwidth.h>
#include <math.h>
 
#ifndef FREETYPE_FONT_DIR
#define FREETYPE_FONT_DIR "/usr/local/microwin/fonts"
#endif
 
#if TT_FREETYPE_MAJOR != 1 | TT_FREETYPE_MINOR < 3
#error "You must link with freetype lib version 1.3.x +, and not freetype 2. \
Download it at http://www.freetype.org or http://microwindows.org"
#endif
 
typedef struct {
PMWFONTPROCS fontprocs; /* common hdr*/
MWCOORD fontsize;
int fontrotation;
int fontattr;
 
TT_Face face; /* freetype stuff*/
TT_Instance instance;
TT_CharMap char_map;
TT_Kerning directory;
TT_Matrix matrix;
TT_Glyph glyph;
MWBOOL can_kern;
short last_glyph_code;
short last_pen_pos;
} MWFREETYPEFONT, *PMWFREETYPEFONT;
 
static int freetype_init(PSD psd);
static PMWFREETYPEFONT freetype_createfont(const char *name, MWCOORD height,
int attr);
static MWBOOL freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);
static void freetype_gettextsize(PMWFONT pfont, const void *text,
int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
static void freetype_destroyfont(PMWFONT pfont);
static void freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags);
static void freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize);
static void freetype_setfontrotation(PMWFONT pfont, int tenthdegrees);
/* handling routines for MWFREETYPEFONT*/
static MWFONTPROCS freetype_procs = {
MWTF_UC16, /* routines expect unicode 16*/
freetype_getfontinfo,
freetype_gettextsize,
NULL, /* gettextbits*/
freetype_destroyfont,
freetype_drawtext,
freetype_setfontsize,
freetype_setfontrotation,
NULL, /* setfontattr*/
};
 
static TT_Engine engine; /* THE ONLY freetype engine */
#endif /* HAVE_FREETYPE_SUPPORT*/
 
#if HAVE_HZK_SUPPORT
/*
* 12x12 and 16x16 ascii and chinese fonts
* Big5 and GB2312 encodings supported
*/
#define MAX_PATH 256
typedef struct {
int width;
int height;
int size;
unsigned long use_count;
char * pFont;
char file[MAX_PATH + 1];
} HZKFONT;
 
static int use_big5=1;
static HZKFONT CFont[2]; /* font cache*/
static HZKFONT AFont[2]; /* font cache*/
 
/* jmt: moved inside MWHZKFONT*/
static int afont_width = 8;
static int cfont_width = 16;
static int font_height = 16;
static char *afont_address;
static char *cfont_address;
 
typedef struct {
PMWFONTPROCS fontprocs; /* common hdr*/
MWCOORD fontsize;
int fontrotation;
int fontattr;
 
HZKFONT CFont; /* hzkfont stuff */
HZKFONT AFont;
int afont_width;
int cfont_width;
int font_height;
char *afont_address;
char *cfont_address;
} MWHZKFONT, *PMWHZKFONT;
 
static int hzk_init(PSD psd);
static PMWHZKFONT hzk_createfont(const char *name, MWCOORD height,int fontattr);
static MWBOOL hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo);
static void hzk_gettextsize(PMWFONT pfont, const void *text,
int cc, MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
#if 0
static void hzk_gettextbits(PMWFONT pfont, int ch, IMAGEBITS *retmap,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase);
static void hzk_setfontrotation(PMWFONT pfont, int tenthdegrees);
#endif
static void hzk_destroyfont(PMWFONT pfont);
static void hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags);
static void hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize);
/* handling routines for MWHZKFONT*/
static MWFONTPROCS hzk_procs = {
MWTF_ASCII, /* routines expect ASCII*/
hzk_getfontinfo,
hzk_gettextsize,
NULL, /* hzk_gettextbits*/
hzk_destroyfont,
hzk_drawtext,
hzk_setfontsize,
NULL, /* setfontrotation*/
NULL, /* setfontattr*/
};
 
static int
UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii);
#endif /* HAVE_HZK_SUPPORT*/
 
static PMWFONT gr_pfont; /* current font*/
 
/* temp extern decls*/
extern MWPIXELVAL gr_foreground;
extern MWPIXELVAL gr_background;
extern MWBOOL gr_usebg;
 
static int utf8_to_utf16(const unsigned char *utf8, int cc,
unsigned short *unicode16);
 
#if FONTMAPPER
/* entry point for font selection*/
int select_font(const PMWLOGFONT plogfont, char *physname);
#endif
 
/*
* Set the font for future calls.
*/
PMWFONT
GdSetFont(PMWFONT pfont)
{
PMWFONT oldfont = gr_pfont;
 
gr_pfont = pfont;
return oldfont;
}
 
/*
* Select a font, based on various parameters.
* If plogfont is specified, name and height parms are ignored
* and instead used from MWLOGFONT.
*
* If height is 0, return builtin font from passed name.
* Otherwise find builtin font best match based on height.
*/
PMWFONT
GdCreateFont(PSD psd, const char *name, MWCOORD height,
const PMWLOGFONT plogfont)
{
int i;
int fontht;
int fontno;
int fontclass;
int fontattr = 0;
PMWFONT pfont;
PMWCOREFONT pf = psd->builtin_fonts;
MWFONTINFO fontinfo;
MWSCREENINFO scrinfo;
char fontname[128];
 
GdGetScreenInfo(psd, &scrinfo);
 
/* if plogfont not specified, use name and height*/
if (!plogfont) {
if (!name)
name = MWFONT_SYSTEM_VAR;
strcpy(fontname, name);
fontclass = MWLF_CLASS_ANY;
} else {
#if FONTMAPPER
/* otherwise, use MWLOGFONT name and height*/
fontclass = select_font(plogfont, fontname);
#else
if (!name)
name = MWFONT_SYSTEM_VAR;
strcpy(fontname, name);
fontclass = MWLF_CLASS_ANY;
#endif
height = plogfont->lfHeight;
if (plogfont->lfUnderline)
fontattr = MWTF_UNDERLINE;
}
height = abs(height);
if (!fontclass)
goto first;
/* use builtin screen fonts, FONT_xxx, if height is 0 */
if (height == 0 || fontclass == MWLF_CLASS_ANY ||
fontclass == MWLF_CLASS_BUILTIN) {
for(i = 0; i < scrinfo.fonts; ++i) {
if(!strcmpi(pf[i].name, fontname)) {
pf[i].fontsize = pf[i].cfont->height;
pf[i].fontattr = fontattr;
return (PMWFONT)&pf[i];
}
}
/* return first builtin font*/
if (height == 0 || fontclass == MWLF_CLASS_BUILTIN)
goto first;
}
 
#if HAVE_HZK_SUPPORT
/* Make sure the library is initialized */
if (hzk_init(psd)) {
pfont = (PMWFONT)hzk_createfont(name, height, fontattr);
if(pfont)
return pfont;
fprintf(stderr, "hzk_createfont: %s not found\n", name);
}
#endif
 
#if HAVE_FREETYPE_SUPPORT
if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_FREETYPE) {
if (freetype_init(psd)) {
/* auto antialias for height > 14 for kaffe*/
if (plogfont && plogfont->lfHeight > 14 &&
plogfont->lfQuality)
fontattr |= MWTF_ANTIALIAS;
 
pfont = (PMWFONT)freetype_createfont(fontname, height,
fontattr);
if(pfont) {
/* temp kaffe kluge*/
pfont->fontattr |= FS_FREETYPE;
return pfont;
}
DPRINTF("freetype_createfont: %s,%d not found\n",
fontname, height);
}
}
#endif
 
#if HAVE_T1LIB_SUPPORT
if (fontclass == MWLF_CLASS_ANY || fontclass == MWLF_CLASS_T1LIB) {
if (t1lib_init(psd)) {
pfont = (PMWFONT)t1lib_createfont(fontname, height,
fontattr);
if(pfont)
return pfont;
DPRINTF("t1lib_createfont: %s,%d not found\n",
fontname, height);
}
}
#endif
 
/* find builtin font closest in height*/
if(height != 0) {
fontno = 0;
height = abs(height);
fontht = MAX_MWCOORD;
for(i = 0; i < scrinfo.fonts; ++i) {
pfont = (PMWFONT)&pf[i];
GdGetFontInfo(pfont, &fontinfo);
if(fontht > abs(height-fontinfo.height)) {
fontno = i;
fontht = abs(height-fontinfo.height);
}
}
pf[fontno].fontsize = pf[fontno].cfont->height;
pf[fontno].fontattr = fontattr;
return (PMWFONT)&pf[fontno];
}
 
first:
/* Return first builtin font*/
pf->fontsize = pf->cfont->height;
pf->fontattr = fontattr;
return (PMWFONT)&pf[0];
}
 
/* Set the font size for the passed font*/
MWCOORD
GdSetFontSize(PMWFONT pfont, MWCOORD fontsize)
{
MWCOORD oldfontsize = pfont->fontsize;
 
pfont->fontsize = fontsize;
 
if (pfont->fontprocs->SetFontSize)
pfont->fontprocs->SetFontSize(pfont, fontsize);
 
return oldfontsize;
}
 
/* Set the font rotation angle in tenths of degrees for the passed font*/
int
GdSetFontRotation(PMWFONT pfont, int tenthdegrees)
{
MWCOORD oldrotation = pfont->fontrotation;
 
pfont->fontrotation = tenthdegrees;
 
if (pfont->fontprocs->SetFontRotation)
pfont->fontprocs->SetFontRotation(pfont, tenthdegrees);
return oldrotation;
}
 
/*
* Set/reset font attributes (MWTF_KERNING, MWTF_ANTIALIAS)
* for the passed font.
*/
int
GdSetFontAttr(PMWFONT pfont, int setflags, int clrflags)
{
MWCOORD oldattr = pfont->fontattr;
 
pfont->fontattr &= ~clrflags;
pfont->fontattr |= setflags;
 
if (pfont->fontprocs->SetFontAttr)
pfont->fontprocs->SetFontAttr(pfont, setflags, clrflags);
return oldattr;
}
 
/* Unload and deallocate font*/
void
GdDestroyFont(PMWFONT pfont)
{
if (pfont->fontprocs->DestroyFont)
pfont->fontprocs->DestroyFont(pfont);
}
 
/* Return information about a specified font*/
MWBOOL
GdGetFontInfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
{
if(!pfont || !pfont->fontprocs->GetFontInfo)
return FALSE;
 
return pfont->fontprocs->GetFontInfo(pfont, pfontinfo);
}
 
/*
* Convert from one encoding to another
* Input cc and returned cc is character count, not bytes
* Return < 0 on error or can't translate
*/
int
GdConvertEncoding(const void *istr, int iflags, int cc, void *ostr, int oflags)
{
const unsigned char *istr8;
const unsigned short *istr16;
const unsigned long *istr32;
unsigned char *ostr8;
unsigned short *ostr16;
unsigned long *ostr32;
unsigned int ch;
int icc;
unsigned short buf16[512];
 
iflags &= MWTF_PACKMASK;
oflags &= MWTF_PACKMASK;
 
/* allow -1 for len with ascii*/
if(cc == -1 && (iflags == MWTF_ASCII))
cc = strlen((char *)istr);
 
/* first check for utf8 input encoding*/
if(iflags == MWTF_UTF8) {
/* we've only got uc16 now so convert to uc16...*/
cc = utf8_to_utf16((unsigned char *)istr, cc,
oflags==MWTF_UC16?(unsigned short*) ostr: buf16);
 
if(oflags == MWTF_UC16 || cc < 0)
return cc;
 
/* will decode again to requested format (probably ascii)*/
iflags = MWTF_UC16;
istr = buf16;
}
 
#if HAVE_HZK_SUPPORT
if(iflags == MWTF_UC16 && oflags == MWTF_ASCII) {
/* only support uc16 convert to ascii now...*/
cc = UC16_to_GB( istr, cc, ostr);
return cc;
}
#endif
 
icc = cc;
istr8 = istr;
istr16 = istr;
istr32 = istr;
ostr8 = ostr;
ostr16 = ostr;
ostr32 = ostr;
 
/* Convert between formats. Note that there's no error
* checking here yet.
*/
while(--icc >= 0) {
switch(iflags) {
default:
ch = *istr8++;
break;
case MWTF_UC16:
ch = *istr16++;
break;
case MWTF_UC32:
ch = *istr32++;
}
switch(oflags) {
default:
*ostr8++ = (unsigned char)ch;
break;
case MWTF_UC16:
*ostr16++ = (unsigned short)ch;
break;
case MWTF_UC32:
*ostr32++ = ch;
}
}
return cc;
}
 
/* Get the width and height of passed text string in the passed font*/
void
GdGetTextSize(PMWFONT pfont, const void *str, int cc, MWCOORD *pwidth,
MWCOORD *pheight, MWCOORD *pbase, int flags)
{
const void * text;
unsigned long buf[256];
int defencoding = pfont->fontprocs->encoding;
 
/* convert encoding if required*/
if((flags & MWTF_PACKMASK) != defencoding) {
cc = GdConvertEncoding(str, flags, cc, buf, defencoding);
flags &= ~MWTF_PACKMASK;
flags |= defencoding;
text = buf;
} else text = str;
 
if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII)
cc = strlen((char *)str);
 
if(cc <= 0 || !pfont->fontprocs->GetTextSize) {
*pwidth = *pheight = *pbase = 0;
return;
}
 
/* calc height and width of string*/
pfont->fontprocs->GetTextSize(pfont, text, cc, pwidth, pheight, pbase);
}
 
/* Draw a text string at a specifed coordinates in the foreground color
* (and possibly the background color), applying clipping if necessary.
* The background color is only drawn if the gr_usebg flag is set.
* Use the current font.
*/
void
GdText(PSD psd, MWCOORD x, MWCOORD y, const void *str, int cc, int flags)
{
const void * text;
unsigned long buf[256];
int defencoding = gr_pfont->fontprocs->encoding;
 
/* convert encoding if required*/
if((flags & MWTF_PACKMASK) != defencoding) {
cc = GdConvertEncoding(str, flags, cc, buf, defencoding);
flags &= ~MWTF_PACKMASK;
flags |= defencoding;
text = buf;
} else text = str;
 
if(cc == -1 && (flags & MWTF_PACKMASK) == MWTF_ASCII)
cc = strlen((char *)str);
 
if(cc <= 0 || !gr_pfont->fontprocs->DrawText)
return;
 
/* draw text string*/
gr_pfont->fontprocs->DrawText(gr_pfont, psd, x, y, text, cc, flags);
}
 
/*
* Draw ascii text using COREFONT type font.
*/
void
corefont_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags)
{
const unsigned char *str = text;
MWCOORD width; /* width of text area */
MWCOORD height; /* height of text area */
MWCOORD base; /* baseline of text*/
MWCOORD startx, starty;
/* bitmap for characters */
MWIMAGEBITS bitmap[MAX_CHAR_HEIGHT*MAX_CHAR_WIDTH/MWIMAGE_BITSPERIMAGE];
 
pfont->fontprocs->GetTextSize(pfont, str, cc, &width, &height, &base);
if(flags & MWTF_BASELINE)
y -= base;
else if(flags & MWTF_BOTTOM)
y -= (height - 1);
startx = x;
starty = y + base;
 
switch (GdClipArea(psd, x, y, x + width - 1, y + height - 1)) {
case CLIP_VISIBLE:
/*
* For size considerations, there's no low-level text
* draw, so we've got to draw all text
* with per-point clipping for the time being
if (gr_usebg)
psd->FillRect(psd, x, y, x + width - 1, y + height - 1,
gr_background);
psd->DrawText(psd, x, y, str, cc, gr_foreground, pfont);
GdFixCursor(psd);
return;
*/
break;
 
case CLIP_INVISIBLE:
return;
}
 
/* Get the bitmap for each character individually, and then display
* them using clipping for each one.
*/
while (--cc >= 0 && x < psd->xvirtres) {
unsigned int ch = *str++;
#if HAVE_BIG5_SUPPORT
/* chinese big5 decoding*/
if (ch >= 0xA1 && ch <= 0xF9 && cc >= 1 &&
((*str >= 0x40 && *str <= 0x7E) ||
(*str >= 0xA1 && *str <= 0xFE)) ) {
ch = (ch << 8) | *str++;
--cc;
}
#endif
#if HAVE_GB2312_SUPPORT
/* chinese gb2312 decoding*/
if (ch >= 0xA1 && ch < 0xF8 && cc >= 1 &&
*str >= 0xA1 && *str < 0xFF) {
ch = (ch << 8) | *str++;
--cc;
}
#endif
#if HAVE_KSC5601_SUPPORT
/* Korean KSC5601 decoding */
if (ch >= 0xA1 && ch <= 0xFE && cc >= 1 &&
(*str >= 0xA1 && *str <= 0xFE)) {
ch = (ch << 8) | *str++;
--cc;
}
#endif
pfont->fontprocs->GetTextBits(pfont, ch, bitmap, &width,
&height, &base);
 
/* note: change to bitmap*/
GdBitmap(psd, x, y, width, height, bitmap);
x += width;
}
 
if (pfont->fontattr & MWTF_UNDERLINE)
GdLine(psd, startx, starty, x, starty, FALSE);
 
GdFixCursor(psd);
}
 
#if HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT
/*
* Produce blend table from src and dst based on passed alpha table
* Used because we don't quite yet have GdArea with alphablending,
* so we pre-blend fg/bg colors for fade effect.
*/
static void
alphablend(PSD psd, OUTPIXELVAL *out, MWPIXELVAL src, MWPIXELVAL dst,
unsigned char *alpha, int count)
{
unsigned int a, d;
unsigned char r, g, b;
MWCOLORVAL palsrc, paldst;
extern MWPALENTRY gr_palette[256];
 
while (--count >= 0) {
a = *alpha++;
 
#define BITS(pixel,shift,mask) (((pixel)>>shift)&(mask))
if(a == 0)
*out++ = dst;
else if(a == 255)
*out++ = src;
else
switch(psd->pixtype) {
case MWPF_TRUECOLOR0888:
case MWPF_TRUECOLOR888:
d = BITS(dst, 16, 0xff);
r = (unsigned char)(((BITS(src, 16, 0xff) - d)*a)>>8) + d;
d = BITS(dst, 8, 0xff);
g = (unsigned char)(((BITS(src, 8, 0xff) - d)*a)>>8) + d;
d = BITS(dst, 0, 0xff);
b = (unsigned char)(((BITS(src, 0, 0xff) - d)*a)>>8) + d;
*out++ = (r << 16) | (g << 8) | b;
break;
 
case MWPF_TRUECOLOR565:
d = BITS(dst, 11, 0x1f);
r = (unsigned char)(((BITS(src, 11, 0x1f) - d)*a)>>8) + d;
d = BITS(dst, 5, 0x3f);
g = (unsigned char)(((BITS(src, 5, 0x3f) - d)*a)>>8) + d;
d = BITS(dst, 0, 0x1f);
b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d;
*out++ = (r << 11) | (g << 5) | b;
break;
 
case MWPF_TRUECOLOR555:
d = BITS(dst, 10, 0x1f);
r = (unsigned char)(((BITS(src, 10, 0x1f) - d)*a)>>8) + d;
d = BITS(dst, 5, 0x1f);
g = (unsigned char)(((BITS(src, 5, 0x1f) - d)*a)>>8) + d;
d = BITS(dst, 0, 0x1f);
b = (unsigned char)(((BITS(src, 0, 0x1f) - d)*a)>>8) + d;
*out++ = (r << 10) | (g << 5) | b;
break;
 
case MWPF_TRUECOLOR332:
d = BITS(dst, 5, 0x07);
r = (unsigned char)(((BITS(src, 5, 0x07) - d)*a)>>8) + d;
d = BITS(dst, 2, 0x07);
g = (unsigned char)(((BITS(src, 2, 0x07) - d)*a)>>8) + d;
d = BITS(dst, 0, 0x03);
b = (unsigned char)(((BITS(src, 0, 0x03) - d)*a)>>8) + d;
*out++ = (r << 5) | (g << 2) | b;
break;
 
case MWPF_PALETTE:
/* reverse lookup palette entry for blend ;-)*/
palsrc = GETPALENTRY(gr_palette, src);
paldst = GETPALENTRY(gr_palette, dst);
d = REDVALUE(paldst);
r = (unsigned char)(((REDVALUE(palsrc) - d)*a)>>8) + d;
d = GREENVALUE(paldst);
g = (unsigned char)(((GREENVALUE(palsrc) - d)*a)>>8) + d;
d = BLUEVALUE(paldst);
b = (unsigned char)(((BLUEVALUE(palsrc) - d)*a)>>8) + d;
*out++ = GdFindNearestColor(gr_palette, (int)psd->ncolors,
MWRGB(r, g, b));
break;
}
}
}
#endif /*HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT*/
 
#if HAVE_T1LIB_SUPPORT
/* contributed by Vidar Hokstad*/
 
static int
t1lib_init(PSD psd)
{
char **encoding;
static int inited = 0;
 
if (inited)
return 1;
 
T1_SetBitmapPad(8);
if (!T1_InitLib(0))
return 0;
 
/* set default Latin1 encoding*/
encoding = T1_LoadEncoding("IsoLatin1.enc");
T1_SetDefaultEncoding(encoding);
 
#ifdef T1LIB_USE_AA_HIGH
T1_AASetLevel(T1_AA_HIGH);
#else
T1_AASetLevel(T1_AA_LOW);
#endif
#if 0
/* kluge: this is required if 16bpp drawarea driver is used*/
if(psd->bpp == 16)
T1_AASetBitsPerPixel(16);
else
#endif
T1_AASetBitsPerPixel(sizeof(MWPIXELVAL)*8);
 
inited = 1;
return 1;
}
 
static PMWT1LIBFONT
t1lib_createfont(const char *name, MWCOORD height, int attr)
{
PMWT1LIBFONT pf;
int id;
char * p;
char buf[256];
 
/* match name against t1 font id's from t1 font database*/
for(id=0; id<T1_Get_no_fonts(); ++id) {
strncpy(buf, T1_GetFontFileName(id), sizeof(buf));
 
/* remove extension*/
for(p=buf; *p; ++p) {
if(*p == '.') {
*p = 0;
break;
}
}
 
if(!strcmpi(name, buf)) {
/* allocate font structure*/
pf = (PMWT1LIBFONT)calloc(sizeof(MWT1LIBFONT), 1);
if (!pf)
return NULL;
pf->fontprocs = &t1lib_procs;
GdSetFontSize((PMWFONT)pf, height);
GdSetFontRotation((PMWFONT)pf, 0);
GdSetFontAttr((PMWFONT)pf, attr, 0);
pf->fontid = id;
return pf;
}
}
return NULL;
}
 
/*
* Draw ascii text string using T1LIB type font
*/
static void
t1lib_drawtext(PMWFONT pfont, PSD psd, MWCOORD x, MWCOORD y,
const void *text, int cc, int flags)
{
PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont;
const unsigned char *str = text;
MWCOORD width; /* width of text area */
MWCOORD height; /* height of text area */
MWCOORD underliney;
GLYPH * g; /* T1lib glyph structure. Memory handling by T1lib */
#ifdef T1LIB_USE_AA_HIGH
OUTPIXELVAL gvals[17];
 
/* Blending array for antialiasing. The steeper the values increase
* near the end, the sharper the characters look, but also more jagged
*/
static unsigned char blend[17] = {
0x00, 0x00, 0x04, 0x0c, 0x10, 0x14, 0x18, 0x20,
0x30, 0x38, 0x40, 0x50, 0x70, 0x80, 0xa0, 0xc0, 0xff
};
#else
OUTPIXELVAL gvals[5];
static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff };
#endif
 
/* Check if we should throw out some fonts */
 
if (pf->fontattr&MWTF_ANTIALIAS) {
#ifdef T1LIB_USE_AA_HIGH
alphablend(psd, gvals, gr_foreground, gr_background, blend, 17);
T1_AAHSetGrayValues(gvals);
#else
alphablend(psd, gvals, gr_foreground, gr_background, blend, 5);
T1_AASetGrayValues(gvals[0],gvals[1],gvals[2],gvals[3],gvals[4]);
#endif
g = T1_AASetString(pf->fontid,(char *)str,cc,0,
(pf->fontattr&MWTF_KERNING)? T1_KERNING: 0,
pf->fontsize * 1.0, 0);
 
if (g && g->bits) {
/*MWPIXELVAL save = gr_background;*/
width = g->metrics.rightSideBearing - g->metrics.leftSideBearing;
height = g->metrics.ascent - g->metrics.descent;
 
if(flags & MWTF_BASELINE)
y -= g->metrics.ascent;
else if(flags & MWTF_BOTTOM)
y -= (height - 1);
underliney = y + g->metrics.ascent;
 
/* FIXME: Looks damn ugly if usebg is false.
* Will be handled when using alphablending in GdArea...
*/
/* clipping handled in GdArea*/
/*FIXME kluge for transparency*/
/*gr_background = gr_foreground + 1;*/
/*gr_usebg = 0;*/
GdArea(psd,x,y, width, height, g->bits, MWPF_PIXELVAL);
/*gr_background = save;*/
 
if (pf->fontattr & MWTF_UNDERLINE)
GdLine(psd, x, underliney, x+width, underliney, FALSE);
 
}
} else {
/* Do non-aa drawing */
g = T1_SetString(pf->fontid,(char *)str,cc,0,
(pf->fontattr&MWTF_KERNING)? T1_KERNING: 0,
pf->fontsize * 1.0, 0);
 
if (g && g->bits) {
unsigned char * b;
int xoff;
int maxy;
int xmod;
/* I'm sure this sorry excuse for a bitmap rendering routine can
* be optimized quite a bit ;)
*/
width = g->metrics.rightSideBearing - g->metrics.leftSideBearing;
height = g->metrics.ascent - g->metrics.descent;
 
if(flags & MWTF_BASELINE)
y -= g->metrics.ascent;
else if(flags & MWTF_BOTTOM)
y -= (height - 1);
underliney = y + g->metrics.ascent;
b = g->bits;
maxy = y + height;
/* if ((x + width) > psd->xvirtres) {
xmod = (x + width - psd->xvirtres + 7) >> 3;
width = width + x + width - psd->xvirtres;
} else xmod = 0;
*/
xmod = 0;
while (y < maxy) {
unsigned char data;
xoff = 0;
while (xoff < width ) {
if (!(xoff % 8)) {
data = *b;
b++;
}
if (GdClipPoint(psd, x+xoff,y)) {
if (gr_usebg) {
psd->DrawPixel(psd,x+xoff,y,
data & (1 << (xoff % 8)) ?
gr_foreground : gr_background);
} else if (data & (1 << (xoff % 8))) {
psd->DrawPixel(psd,x+xoff,y, gr_foreground);
}
}
xoff++;
}
b += xmod;
y++;
}
if (pf->fontattr & MWTF_UNDERLINE)
GdLine(psd, x, underliney, x+xoff, underliney, FALSE);
}
}
 
if (g && g->bits) {
/* Save some memory */
free(g->bits);
g->bits = 0; /* Make sure T1lib doesnt try to free it again */
}
 
GdFixCursor(psd);
}
 
static MWBOOL
t1lib_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
{
int i;
MWCOORD width, height, baseline;
 
/* FIXME, guess all sizes*/
GdGetTextSize(pfont, "A", 1, &width, &height, &baseline, MWTF_ASCII);
pfontinfo->height = height;
pfontinfo->maxwidth = width;
pfontinfo->baseline = 0;
pfontinfo->firstchar = 32;
pfontinfo->lastchar = 255;
pfontinfo->fixed = TRUE;
for(i=0; i<256; ++i)
pfontinfo->widths[i] = width;
return TRUE;
}
 
/* Get the width and height of passed text string in the current font*/
static void
t1lib_gettextsize(PMWFONT pfont, const void *text, int cc,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
{
PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont;
const unsigned char * str = text;
GLYPH * g;
 
g = T1_SetString(pf->fontid, (char *)str, cc, 0,
(pf->fontattr&MWTF_KERNING)? T1_KERNING: 0, pf->fontsize * 1.0, 0);
*pwidth = g->metrics.rightSideBearing - g->metrics.leftSideBearing;
*pheight = g->metrics.ascent - g->metrics.descent;
if(g && g->bits) {
free(g->bits);
g->bits = 0;
}
#if 0
BBox b;
 
/* FIXME. Something is *VERY* wrong here */
b = T1_GetStringBBox(pf->fontid, str, cc, 0, (pf->fontattr&MWTF_KERNING)?T1_KERNING:0);
 
DPRINTF("b.urx = %d, b.llx = %d\n",b.urx, b.llx);
DPRINTF("b.ury = %d, b.lly = %d\n",b.ury, b.lly);
*pwidth = (b.urx - b.llx);
*pheight = (b.lly - b.ury);
#endif
}
 
static void
t1lib_destroyfont(PMWFONT pfont)
{
PMWT1LIBFONT pf = (PMWT1LIBFONT)pfont;
 
T1_DeleteAllSizes(pf->fontid);
free(pf);
}
 
#endif /* HAVE_T1LIB_SUPPORT*/
 
#if HAVE_FREETYPE_SUPPORT
static OUTPIXELVAL gray_palette[5];
 
static int
freetype_init(PSD psd)
{
static int inited = 0;
 
if (inited)
return 1;
/* Init freetype library */
if (TT_Init_FreeType (&engine) != TT_Err_Ok) {
return 0;
}
 
/* Init kerning extension */
if (TT_Init_Kerning_Extension (engine) != TT_Err_Ok)
return 0;
 
inited = 1;
return 1;
}
 
static PMWFREETYPEFONT
freetype_createfont(const char *name, MWCOORD height, int attr)
{
PMWFREETYPEFONT pf;
unsigned short i, n;
unsigned short platform, encoding;
TT_Face_Properties properties;
char * p;
char fontname[128];
 
/* check for pathname prefix*/
if (strchr(name, '/') != NULL)
strcpy(fontname, name);
else {
strcpy(fontname, FREETYPE_FONT_DIR);
strcat(fontname, "/");
strcat(fontname, name);
}
 
/* check for extension*/
if ((p = strrchr(fontname, '.')) == NULL ||
strcmp(p, ".ttf") != 0) {
strcat(fontname, ".ttf");
}
 
/* allocate font structure*/
pf = (PMWFREETYPEFONT)calloc(sizeof(MWFREETYPEFONT), 1);
if (!pf)
return NULL;
pf->fontprocs = &freetype_procs;
 
/* Load face */
if (TT_Open_Face (engine, fontname, &pf->face) != TT_Err_Ok)
goto out;
 
/* Load first kerning table */
pf->can_kern = TRUE;
if (TT_Load_Kerning_Table (pf->face, 0) != TT_Err_Ok)
pf->can_kern = FALSE;
else {
if (TT_Get_Kerning_Directory (pf->face, &pf->directory)
!= TT_Err_Ok)
pf->can_kern = FALSE;
else {
/* Support only version 0 kerning table ... */
if ((pf->directory.version != 0) ||
(pf->directory.nTables <= 0) ||
(pf->directory.tables->loaded != 1) ||
(pf->directory.tables->version != 0) ||
(pf->directory.tables->t.kern0.nPairs <= 0))
pf->can_kern = FALSE;
}
}
 
/* get face properties and allocate preload arrays */
TT_Get_Face_Properties (pf->face, &properties);
 
#if 0
/*
* Use header information for ascent and descent
* to compute scaled ascent/descent for current font height.
*/
h = properties.os2->sTypoAscender - properties.os2->sTypoDescender
+ properties.os2->sTypoLineGap;
ascent = properties.os2->sTypoAscender
+ properties.os2->sTypoLineGap/2;
pf->ascent = (ascent * height + h/2) / h;
pf->descent = height - pf->ascent;
#endif
/* Create a glyph container */
if (TT_New_Glyph (pf->face, &pf->glyph) != TT_Err_Ok)
goto out;
 
/* create instance */
if (TT_New_Instance (pf->face, &pf->instance) != TT_Err_Ok)
goto out;
 
/* Set the instance resolution */
if (TT_Set_Instance_Resolutions (pf->instance, 96, 96) != TT_Err_Ok)
goto out;
 
/* Look for a Unicode charmap: Windows flavor of Apple flavor only */
n = properties.num_CharMaps;
 
for (i = 0; i < n; i++) {
TT_Get_CharMap_ID (pf->face, i, &platform, &encoding);
if (((platform == TT_PLATFORM_MICROSOFT) &&
(encoding == TT_MS_ID_UNICODE_CS)) ||
((platform == TT_PLATFORM_APPLE_UNICODE) &&
(encoding == TT_APPLE_ID_DEFAULT)))
{
TT_Get_CharMap (pf->face, i, &pf->char_map);
i = n + 1;
}
}
if (i == n) {
DPRINTF("freetype_createfont: no unicode map table\n");
goto out;
}
GdSetFontSize((PMWFONT)pf, height);
GdSetFontRotation((PMWFONT)pf, 0);
GdSetFontAttr((PMWFONT)pf, attr, 0);
 
return pf;
 
out:
free(pf);
return NULL;
}
 
static int
compute_kernval(PMWFREETYPEFONT pf, short current_glyph_code)
{
int i = 0;
int kernval;
int nPairs = pf->directory.tables->t.kern0.nPairs;
TT_Kern_0_Pair *pair = pf->directory.tables->t.kern0.pairs;
 
if (pf->last_glyph_code != -1) {
while ((pair->left != pf->last_glyph_code)
&& (pair->right != current_glyph_code))
{
pair++;
i++;
if (i == nPairs)
break;
}
 
if (i == nPairs)
kernval = 0;
else
/* We round the value (hence the +32) */
kernval = (pair->value + 32) & -64;
} else
kernval = 0;
 
return kernval;
}
 
static TT_UShort
Get_Glyph_Width(PMWFREETYPEFONT pf, TT_UShort glyph_index)
{
TT_Glyph_Metrics metrics;
if (TT_Load_Glyph ( pf->instance, pf->glyph,
TT_Char_Index (pf->char_map,glyph_index),
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
{
/* Try to load default glyph: index 0 */
if (TT_Load_Glyph ( pf->instance, pf->glyph, 0,
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
return 0;
}
 
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
return((metrics.advance & 0xFFFFFFC0) >> 6);
}
 
/* Render a single glyph*/
static void
drawchar(PMWFREETYPEFONT pf, PSD psd, TT_Glyph glyph, int x_offset,
int y_offset)
{
TT_F26Dot6 xmin, ymin, xmax, ymax, x, y, z;
unsigned char *src, *srcptr;
MWPIXELVAL *dst, *dstptr;
MWPIXELVAL *bitmap;
int size, width, height;
TT_Outline outline;
TT_BBox bbox;
TT_Raster_Map Raster;
TT_Error error;
/*MWPIXELVAL save;*/
 
/* we begin by grid-fitting the bounding box */
TT_Get_Glyph_Outline (pf->glyph, &outline);
TT_Get_Outline_BBox (&outline, &bbox);
 
xmin = (bbox.xMin & -64) >> 6;
ymin = (bbox.yMin & -64) >> 6;
xmax = ((bbox.xMax + 63) & -64) >> 6;
ymax = ((bbox.yMax + 63) & -64) >> 6;
width = xmax - xmin;
height = ymax - ymin;
size = width * height;
 
/* now re-allocate the raster bitmap */
Raster.rows = height;
Raster.width = width;
 
if (pf->fontattr&MWTF_ANTIALIAS)
Raster.cols = (Raster.width + 3) & -4; /* pad to 32-bits */
else
Raster.cols = (Raster.width + 7) & -8; /* pad to 64-bits ??? */
 
Raster.flow = TT_Flow_Up;
Raster.size = Raster.rows * Raster.cols;
Raster.bitmap = malloc (Raster.size);
 
memset (Raster.bitmap, 0, Raster.size);
 
/* now render the glyph in the small pixmap */
 
/* IMPORTANT NOTE: the offset parameters passed to the function */
/* TT_Get_Glyph_Bitmap() must be integer pixel values, i.e., */
/* multiples of 64. HINTING WILL BE RUINED IF THIS ISN'T THE CASE! */
/* This is why we _did_ grid-fit the bounding box, especially xmin */
/* and ymin. */
 
if (!(pf->fontattr&MWTF_ANTIALIAS))
error = TT_Get_Glyph_Bitmap (pf->glyph, &Raster,
-xmin * 64, -ymin * 64);
else
error = TT_Get_Glyph_Pixmap (pf->glyph, &Raster,
-xmin * 64, -ymin * 64);
 
if (error) {
free (Raster.bitmap);
return;
}
 
bitmap = malloc (size * sizeof (MWPIXELVAL));
memset (bitmap, 0, size * sizeof (MWPIXELVAL));
 
src = (char *) Raster.bitmap;
dst = bitmap + (size - width);
 
for (y = ymin; y < ymax; y++) {
srcptr = src;
dstptr = dst;
 
for (x = xmin; x < xmax; x++) {
if (pf->fontattr&MWTF_ANTIALIAS)
*dstptr++ = gray_palette[(int) *srcptr];
else {
for(z=0;
z <= ((xmax-x-1) < 7 ? (xmax-x-1) : 7);
z++) {
*dstptr++ = ((*srcptr << z) & 0x80)?
gr_foreground: gr_background;
}
x += 7;
}
 
srcptr++;
}
 
src += Raster.cols;
dst -= width;
}
 
/* FIXME - must clear background upstairs if not gr_usebg*/
/* FIXME: GdArea problem if fg == bg*/
/*save = gr_background;*/
/*gr_background = gr_foreground + 1;*/
 
/* Now draw the bitmap ... */
GdArea(psd, x_offset + xmin, y_offset - (ymin + height), width, height,
bitmap, MWPF_PIXELVAL);
 
/*gr_background = save;*/
 
free (bitmap);
free (Raster.bitmap);
}
 
/*
* Draw unicode 16 text string using FREETYPE type font
*/
static void
freetype_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay,
const void *text, int cc, int flags)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
const unsigned short * str = text;
TT_F26Dot6 x = ax, y = ay;
TT_Pos vec_x, vec_y;
int i;
TT_F26Dot6 startx, starty;
TT_Outline outline;
TT_UShort curchar;
TT_Glyph_Metrics metrics;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
TT_F26Dot6 ascent, descent;
static unsigned char blend[5] = { 0x00, 0x44, 0x88, 0xcc, 0xff };
static unsigned char virtual_palette[5] = { 0, 1, 2, 3, 4 };
 
pf->last_glyph_code = -1; /* reset kerning*/
pf->last_pen_pos = -32767;
 
/*
* Compute instance ascent & descent values
* in fractional units (1/64th pixel)
*/
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
ascent = ((properties.horizontal->Ascender * imetrics.y_scale)/0x10000);
descent = ((properties.horizontal->Descender*imetrics.y_scale)/0x10000);
 
/*
* Offset the starting point if necessary,
* FreeType always aligns at baseline
*/
if (flags&MWTF_BOTTOM) {
vec_x = 0;
vec_y = descent;
TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
x -= vec_x / 64;
y += vec_y / 64;
} else if (flags&MWTF_TOP) {
vec_x = 0;
vec_y = ascent;
TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
x -= vec_x / 64;
y += vec_y / 64;
}
 
/* Set the "graylevels" */
if (pf->fontattr&MWTF_ANTIALIAS) {
TT_Set_Raster_Gray_Palette (engine, virtual_palette);
 
alphablend(psd, gray_palette, gr_foreground, gr_background,
blend, 5);
}
 
startx = x;
starty = y;
for (i = 0; i < cc; i++) {
curchar = TT_Char_Index (pf->char_map, str[i]);
 
if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
TTLOAD_DEFAULT) != TT_Err_Ok)
continue;
 
if (pf->fontrotation) {
TT_Get_Glyph_Outline (pf->glyph, &outline);
TT_Transform_Outline (&outline, &pf->matrix);
}
 
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
 
if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) {
if (pf->fontrotation) {
vec_x = compute_kernval(pf, curchar);
vec_y = 0;
TT_Transform_Vector(&vec_x, &vec_y,&pf->matrix);
 
x += vec_x / 64;
y -= vec_y / 64;
} else
x += compute_kernval(pf, curchar) / 64;
}
drawchar(pf, psd, pf->glyph, x, y);
 
if (pf->fontrotation) {
vec_x = metrics.advance;
vec_y = 0;
TT_Transform_Vector (&vec_x, &vec_y, &pf->matrix);
 
x += vec_x / 64;
y -= vec_y / 64;
} else {
x += metrics.advance / 64;
 
/* Kerning point syndrome avoidance */
if (pf->last_pen_pos > x)
x = pf->last_pen_pos;
pf->last_pen_pos = x;
}
 
pf->last_glyph_code = curchar;
}
 
if (pf->fontattr & MWTF_UNDERLINE)
GdLine(psd, startx, starty, x, y, FALSE);
}
 
/*
* Return information about a specified font.
*/
static MWBOOL
freetype_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
{
int i;
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
TT_UShort last_glyph_index;
 
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
 
/* Fill up the fields */
pfontinfo->height = (((properties.horizontal->Ascender * \
imetrics.y_scale)/ 0x10000) >> 6) -
(((properties.horizontal->Descender * \
imetrics.y_scale)/ 0x10000) >> 6);
pfontinfo->maxwidth = ((properties.horizontal->xMax_Extent * \
imetrics.x_scale)/ 0x10000) >> 6;
pfontinfo->baseline = ((properties.horizontal->Ascender * \
imetrics.y_scale)/ 0x10000) >> 6;
pfontinfo->firstchar = TT_CharMap_First(pf->char_map, NULL);
pfontinfo->lastchar = TT_CharMap_Last(pf->char_map, NULL);
pfontinfo->fixed = properties.postscript->isFixedPitch;
last_glyph_index = properties.num_Glyphs > 255 ? 255: properties.num_Glyphs-1;
 
/* Doesn't work ... don't know why ....*/
#if 0
if (TT_Get_Face_Widths( pf->face, 0,
last_glyph_index, widths, NULL ) != TT_Err_Ok) {
return TRUE;
}
 
for(i=0; i<=last_glyph_index; i++)
DPRINTF("widths[%d]: %d\n", i, widths[i]);
#endif
 
/* Get glyphs widths */
for(i=0; i<=last_glyph_index; i++)
pfontinfo->widths[i] = Get_Glyph_Width(pf, i);
 
#if 0
DPRINTF("x_ppem: %d\ny_ppem: %d\nx_scale: %d\ny_scale: %d\n\
x_resolution: %d\ny_resolution: %d\n",
imetrics.x_ppem, imetrics.y_ppem, imetrics.x_scale, \
imetrics.y_scale, imetrics.x_resolution, imetrics.y_resolution);
 
DPRINTF("Ascender: %d\nDescender: %d\nxMax_Extent: %d\n\
Mac Style Say Italic?: %d\nMac Style Say Bold?: %d\n\
sTypoAscender: %d\nsTypoDescender: %d\nusWinAscent: %d\n\
usWinDescent: %d\nusFirstCharIndex: %d\nusLastCharIndex: %d\n\
OS2 Say Italic?: %d\nOS2 Say Bold?: %d\nOS2 Say monospaced?: %d\n\
Postscript Say monospaced?: %d\n",\
properties.horizontal->Ascender,
properties.horizontal->Descender,
properties.horizontal->xMax_Extent,
(properties.header->Mac_Style & 0x2)?1:0,
(properties.header->Mac_Style & 0x1)?1:0,
properties.os2->sTypoAscender,
properties.os2->sTypoDescender,
properties.os2->usWinAscent,
properties.os2->usWinDescent,
properties.os2->usFirstCharIndex,
properties.os2->usLastCharIndex,
(properties.os2->fsSelection & 0x1)?1:0,
(properties.os2->fsSelection & 0x20)?1:0,
properties.postscript->isFixedPitch,
(properties.os2->panose[3] == 9)?1:0);
#endif
return TRUE;
}
 
static void
freetype_gettextsize(PMWFONT pfont, const void *text, int cc,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
const unsigned short * str = text;
TT_F26Dot6 x = 0;
int i;
TT_UShort curchar;
TT_Glyph_Metrics metrics;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
 
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
pf->last_glyph_code = -1; /* reset kerning*/
pf->last_pen_pos = -32767;
for (i = 0; i < cc; i++) {
curchar = TT_Char_Index (pf->char_map, str[i]);
 
if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
continue;
 
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
 
if ((pf->fontattr&MWTF_KERNING) && pf->can_kern) {
x += compute_kernval(pf, curchar) / 64;
}
x += metrics.advance / 64;
 
/* Kerning point syndrome avoidance */
if (pf->last_pen_pos > x)
x = pf->last_pen_pos;
pf->last_pen_pos = x;
 
pf->last_glyph_code = curchar;
}
 
*pwidth = x;
*pheight = (((properties.horizontal->Ascender *
imetrics.y_scale)/ 0x10000) >> 6) -
(((properties.horizontal->Descender *
imetrics.y_scale)/ 0x10000) >> 6);
/* FIXME: is it what's required ?? */
*pbase = (((-properties.horizontal->Descender) *
imetrics.y_scale)/ 0x10000) >> 6;
}
 
static void
freetype_destroyfont(PMWFONT pfont)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
 
TT_Close_Face(pf->face);
free(pf);
}
 
static void
freetype_setfontsize(PMWFONT pfont, MWCOORD fontsize)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
pf->fontsize = fontsize;
/* We want real pixel sizes ... not points ...*/
TT_Set_Instance_PixelSizes( pf->instance, pf->fontsize,
pf->fontsize, pf->fontsize * 64 );
#if 0
/* set charsize (convert to points for freetype)*/
TT_Set_Instance_CharSize (pf->instance,
((pf->fontsize * 72 + 96/2) / 96) * 64);
#endif
}
 
static void
freetype_setfontrotation(PMWFONT pfont, int tenthdegrees)
{
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
float angle;
pf->fontrotation = tenthdegrees;
 
/* Build the rotation matrix with the given angle */
TT_Set_Instance_Transform_Flags (pf->instance, TRUE, FALSE);
 
angle = pf->fontrotation * M_PI / 1800;
pf->matrix.yy = (TT_Fixed) (cos (angle) * (1 << 16));
pf->matrix.yx = (TT_Fixed) (sin (angle) * (1 << 16));
pf->matrix.xx = pf->matrix.yy;
pf->matrix.xy = -pf->matrix.yx;
}
 
#endif /* HAVE_FREETYPE_SUPPORT*/
 
/* UTF-8 to UTF-16 conversion. Surrogates are handeled properly, e.g.
* a single 4-byte UTF-8 character is encoded into a surrogate pair.
* On the other hand, if the UTF-8 string contains surrogate values, this
* is considered an error and returned as such.
*
* The destination array must be able to hold as many Unicode-16 characters
* as there are ASCII characters in the UTF-8 string. This in case all UTF-8
* characters are ASCII characters. No more will be needed.
*
* Copyright (c) 2000 Morten Rolland, Screen Media
*/
static int
utf8_to_utf16(const unsigned char *utf8, int cc, unsigned short *unicode16)
{
int count = 0;
unsigned char c0, c1;
unsigned long scalar;
 
while(--cc >= 0) {
c0 = *utf8++;
/*DPRINTF("Trying: %02x\n",c0);*/
 
if ( c0 < 0x80 ) {
/* Plain ASCII character, simple translation :-) */
*unicode16++ = c0;
count++;
continue;
}
 
if ( (c0 & 0xc0) == 0x80 )
/* Illegal; starts with 10xxxxxx */
return -1;
 
/* c0 must be 11xxxxxx if we get here => at least 2 bytes */
scalar = c0;
if(--cc < 0)
return -1;
c1 = *utf8++;
/*DPRINTF("c1=%02x\n",c1);*/
if ( (c1 & 0xc0) != 0x80 )
/* Bad byte */
return -1;
scalar <<= 6;
scalar |= (c1 & 0x3f);
 
if ( !(c0 & 0x20) ) {
/* Two bytes UTF-8 */
if ( scalar < 0x80 )
return -1; /* Overlong encoding */
*unicode16++ = scalar & 0x7ff;
count++;
continue;
}
 
/* c0 must be 111xxxxx if we get here => at least 3 bytes */
if(--cc < 0)
return -1;
c1 = *utf8++;
/*DPRINTF("c1=%02x\n",c1);*/
if ( (c1 & 0xc0) != 0x80 )
/* Bad byte */
return -1;
scalar <<= 6;
scalar |= (c1 & 0x3f);
 
if ( !(c0 & 0x10) ) {
/*DPRINTF("####\n");*/
/* Three bytes UTF-8 */
if ( scalar < 0x800 )
return -1; /* Overlong encoding */
if ( scalar >= 0xd800 && scalar < 0xe000 )
return -1; /* UTF-16 high/low halfs */
*unicode16++ = scalar & 0xffff;
count++;
continue;
}
 
/* c0 must be 1111xxxx if we get here => at least 4 bytes */
c1 = *utf8++;
if(--cc < 0)
return -1;
/*DPRINTF("c1=%02x\n",c1);*/
if ( (c1 & 0xc0) != 0x80 )
/* Bad byte */
return -1;
scalar <<= 6;
scalar |= (c1 & 0x3f);
 
if ( !(c0 & 0x08) ) {
/* Four bytes UTF-8, needs encoding as surrogates */
if ( scalar < 0x10000 )
return -1; /* Overlong encoding */
scalar -= 0x10000;
*unicode16++ = ((scalar >> 10) & 0x3ff) + 0xd800;
*unicode16++ = (scalar & 0x3ff) + 0xdc00;
count += 2;
continue;
}
 
return -1; /* No support for more than four byte UTF-8 */
}
return count;
}
 
#if HAVE_HZK_SUPPORT
 
/* UniCode-16 (MWTF_UC16) to GB(MWTF_ASCII) Chinese Characters conversion.
* a single 2-byte UC16 character is encoded into a surrogate pair.
* return -1 ,if error;
* The destination array must be able to hold as many
* as there are Unicode-16 characters.
*
* Copyright (c) 2000 Tang Hao (TownHall)(tang_hao@263.net).
*/
static int
UC16_to_GB(const unsigned char *uc16, int cc, unsigned char *ascii)
{
FILE* fp;
char buffer[256];
unsigned char *uc16p;
int i=0,j=0, k;
unsigned char *filebuffer;
unsigned short *uc16pp,*table;
unsigned short uc16px;
int length=31504;
 
if (use_big5)
length=54840;
 
uc16p=(unsigned char *) uc16;
uc16pp=(unsigned short *) uc16;
 
strcpy(buffer,HZK_FONT_DIR);
if (use_big5)
strcat(buffer,"/BG2UBG.KU");
else
strcat(buffer,"/UGB2GB.KU");
if(!(fp = fopen(buffer, "rb")))
{
fprintf (stderr, "Error.\nThe %s file can not be found!\n",buffer);
return -1;
}
 
filebuffer= (unsigned char *)malloc ( length);
 
if(fread(filebuffer, sizeof(char),length, fp) < length) {
fprintf (stderr, "Error in reading ugb2gb.ku file!\n");
fclose(fp);
return -1;
}
fclose(fp);
 
if (use_big5)
{
table=(unsigned short *)filebuffer;
while(1)
{
if(j>=cc)
{
ascii[i]=0;
break;
}
uc16px=*uc16pp;
if((uc16px)<=0x00ff)
{
ascii[i]=(char)(*uc16pp);
i++;
}
else
{
ascii[i]=0xa1; ascii[i+1]=0x40;
for (k=0; k<13710; k++)
{
if (*(table+(k*2+1))==(uc16px))
{
ascii[i]=(char)((*(table+(k*2)) & 0xff00) >> 8);
ascii[i+1]=(char)(*(table+(k*2)) & 0x00ff);
break;
}
}
i+=2;
}
uc16pp++; j++;
}
}
else
{
while(1)
{
if(j>=cc)
{
ascii[i]=0;
break;
}
if((*((uc16p)+j)==0)&&(*((uc16p)+j+1)==0))
{
ascii[i]=0;
break;
}
else
{
if(*((uc16p)+j+1)==0)
{
ascii[i]=*((uc16p)+j);
i++;
j+=2;
}
else
{
 
{
int p1=0,p2=length-4,p;
unsigned int c1,c2,c,d;
c1=((unsigned int )filebuffer[p1])*0x100+(filebuffer[p1+1]);
c2=((unsigned int )filebuffer[p2])*0x100+(filebuffer[p2+1]);
d=((unsigned int )*((uc16p)+j))*0x100+*((uc16p)+j+1);
if(c1==d)
{
ascii[i]=filebuffer[p1+2];
ascii[i+1]=filebuffer[p1+3];
goto findit;
}
if(c2==d)
{
ascii[i]=filebuffer[p2+2];
ascii[i+1]=filebuffer[p2+3];
goto findit;
}
while(1)
{
p=(((p2-p1)/2+p1)>>2)<<2;
c=((unsigned int )filebuffer[p])*0x100+(filebuffer[p+1]);
if(d==c) /* find it*/
{
ascii[i]=filebuffer[p+2];
ascii[i+1]=filebuffer[p+3];
break;
}
else if(p2<=p1+4) /* can't find.*/
{
ascii[i]='.'; /* ((uc16p)+j);*/
ascii[i+1]='.'; /* ((uc16p)+j+1);*/
break;
}
else if(d<c)
{
p2=p;
c2=c;
}
else
{
p1=p;
c1=c;
}
}
}
findit:
i+=2;
j+=2;
}
}
}
}
free(filebuffer);
 
return i;
}
 
/************************** functions definition ******************************/
 
static int hzk_id( PMWHZKFONT pf )
{
switch(pf->font_height)
{
case 12:
return 0;
case 16: default:
return 1;
}
}
 
/* This function get Chinese font info from etc file.*/
static MWBOOL GetCFontInfo( PMWHZKFONT pf )
{
int charset;
 
if (use_big5)
charset=(13094+408);
else
charset=8178;
 
CFont[hzk_id(pf)].width = pf->cfont_width;
pf->CFont.width = pf->cfont_width;
 
CFont[hzk_id(pf)].height = pf->font_height;
pf->CFont.height = pf->font_height;
 
CFont[hzk_id(pf)].size = ((pf->CFont.width + 7) / 8) *
pf->CFont.height * charset;
pf->CFont.size = ((pf->CFont.width + 7) / 8) * pf->CFont.height * charset;
 
if(pf->CFont.size < charset * 8)
return FALSE;
 
strcpy(CFont[hzk_id(pf)].file,HZK_FONT_DIR);
strcpy(pf->CFont.file,HZK_FONT_DIR);
 
if(pf->font_height==16)
{
strcat(CFont[hzk_id(pf)].file,"/hzk16");
strcat(pf->CFont.file,"/hzk16");
}
else
{
strcat(CFont[hzk_id(pf)].file,"/hzk12");
strcat(pf->CFont.file,"/hzk12");
}
 
if (use_big5)
{
CFont[hzk_id(pf)].file[strlen(pf->CFont.file)-3]+=use_big5;
pf->CFont.file[strlen(pf->CFont.file)-3]+=use_big5;
}
 
return TRUE;
}
 
/* This function get ASCII font info from etc file.*/
static MWBOOL GetAFontInfo( PMWHZKFONT pf )
{
AFont[hzk_id(pf)].width = pf->afont_width;
pf->AFont.width = pf->afont_width;
 
AFont[hzk_id(pf)].height = pf->font_height;
pf->AFont.height = pf->font_height;
 
AFont[hzk_id(pf)].size = ((pf->AFont.width + 7) / 8) *
pf->AFont.height * 255;
pf->AFont.size = ((pf->AFont.width + 7) / 8) * pf->AFont.height * 255;
if(pf->AFont.size < 255 * 8)
return FALSE;
 
strcpy(AFont[hzk_id(pf)].file,HZK_FONT_DIR);
strcpy(pf->AFont.file,HZK_FONT_DIR);
if(pf->font_height==16)
{
strcat(AFont[hzk_id(pf)].file,"/asc16");
strcat(pf->AFont.file,"/asc16");
}
else
{
strcat(AFont[hzk_id(pf)].file,"/asc12");
strcat(pf->AFont.file,"/asc12");
}
return TRUE;
}
 
/* This function load system font into memory.*/
static MWBOOL LoadFont( PMWHZKFONT pf )
{
FILE* fp;
 
if(!GetCFontInfo(pf))
{
fprintf (stderr, "Get Chinese HZK font info failure!\n");
return FALSE;
}
if(CFont[hzk_id(pf)].pFont == NULL) /* check font cache*/
{
 
/* Allocate system memory for Chinese font.*/
if( !(CFont[hzk_id(pf)].pFont = (char *)malloc(pf->CFont.size)) )
{
fprintf (stderr, "Allocate memory for Chinese HZK font failure.\n");
return FALSE;
}
/* Open font file and read information to the system memory.*/
fprintf (stderr, "Loading Chinese HZK font from file(%s)..." ,pf->CFont.file);
if(!(fp = fopen(CFont[hzk_id(pf)].file, "rb")))
{
fprintf (stderr, "Error.\nThe Chinese HZK font file can not be found!\n");
return FALSE;
}
if(fread(CFont[hzk_id(pf)].pFont, sizeof(char), pf->CFont.size, fp) < pf->CFont.size)
{
fprintf (stderr, "Error in reading Chinese HZK font file!\n");
fclose(fp);
return FALSE;
}
 
fclose(fp);
 
CFont[hzk_id(pf)].use_count=0;
 
fprintf (stderr, "done.\n" );
 
}
cfont_address = CFont[hzk_id(pf)].pFont;
pf->cfont_address = CFont[hzk_id(pf)].pFont;
pf->CFont.pFont = CFont[hzk_id(pf)].pFont;
 
CFont[hzk_id(pf)].use_count++;
 
if(!GetAFontInfo(pf))
{
fprintf (stderr, "Get ASCII HZK font info failure!\n");
return FALSE;
}
if(AFont[hzk_id(pf)].pFont == NULL) /* check font cache*/
{
/* Allocate system memory for ASCII font.*/
if( !(AFont[hzk_id(pf)].pFont = (char *)malloc(pf->AFont.size)) )
{
fprintf (stderr, "Allocate memory for ASCII HZK font failure.\n");
free(CFont[hzk_id(pf)].pFont);
CFont[hzk_id(pf)].pFont = NULL;
return FALSE;
}
/* Load ASCII font information to the near memory.*/
fprintf (stderr, "Loading ASCII HZK font..." );
if(!(fp = fopen(AFont[hzk_id(pf)].file, "rb")))
{
fprintf (stderr, "Error.\nThe ASCII HZK font file can not be found!\n");
return FALSE;
}
if(fread(AFont[hzk_id(pf)].pFont, sizeof(char), pf->AFont.size, fp) < pf->AFont.size)
{
fprintf (stderr, "Error in reading ASCII HZK font file!\n");
fclose(fp);
return FALSE;
}
fclose(fp);
AFont[hzk_id(pf)].use_count=0;
 
fprintf (stderr, "done.\n" );
 
}
afont_address = AFont[hzk_id(pf)].pFont;
pf->afont_address = AFont[hzk_id(pf)].pFont;
pf->AFont.pFont = AFont[hzk_id(pf)].pFont;
 
AFont[hzk_id(pf)].use_count++;
 
return TRUE;
}
 
/* This function unload system font from memory.*/
static void UnloadFont( PMWHZKFONT pf )
{
CFont[hzk_id(pf)].use_count--;
AFont[hzk_id(pf)].use_count--;
 
if (!CFont[hzk_id(pf)].use_count)
{
free(pf->CFont.pFont);
free(pf->AFont.pFont);
 
CFont[hzk_id(pf)].pFont = NULL;
AFont[hzk_id(pf)].pFont = NULL;
}
}
 
static int
hzk_init(PSD psd)
{
/* FIXME: *.KU file should be opened and
* read in here...*/
return 1;
}
 
static PMWHZKFONT
hzk_createfont(const char *name, MWCOORD height, int attr)
{
PMWHZKFONT pf;
 
if(strcmp(name,"HZKFONT")!=0 && strcmp(name,"HZXFONT")!=0)
return FALSE;
 
/*printf("hzk_createfont(%s,%d)\n",name,height);*/
 
use_big5=name[2]-'K';
 
/* allocate font structure*/
pf = (PMWHZKFONT)calloc(sizeof(MWHZKFONT), 1);
if (!pf)
return NULL;
pf->fontprocs = &hzk_procs;
 
pf->fontsize=height;
#if 0
GdSetFontSize((PMWFONT)pf, height);
#endif
GdSetFontRotation((PMWFONT)pf, 0);
GdSetFontAttr((PMWFONT)pf, attr, 0);
 
if(height==12)
{
afont_width = 6;
cfont_width = 12;
font_height = 12;
 
pf->afont_width = 6;
pf->cfont_width = 12;
pf->font_height = 12;
}
else
{
afont_width = 8;
cfont_width = 16;
font_height = 16;
 
pf->afont_width = 8;
pf->cfont_width = 16;
pf->font_height = 16;
}
 
/* Load the font library to the system memory.*/
if(!LoadFont(pf))
return FALSE;
 
return pf;
}
 
int IsBig5(int i)
{
if ((i>=0xa140 && i<=0xa3bf) || /* a140-a3bf(!a3e0) */
(i>=0xa440 && i<=0xc67e) || /* a440-c67e */
(i>=0xc6a1 && i<=0xc8d3) || /* c6a1-c8d3(!c8fe) */
(i>=0xc940 && i<=0xf9fe)) /* c940-f9fe */
return 1;
else
return 0;
}
 
/*
* following several function is used in hzk_drawtext
*/
 
static int getnextchar(char* s, unsigned char* cc)
{
if( s[0] == '\0') return 0;
 
cc[0] = (unsigned char)(*s);
cc[1] = (unsigned char)(*(s + 1));
 
if (use_big5)
{
if( IsBig5( (int) ( (cc[0] << 8) + cc[1]) ) )
return 1;
}
else
{
if( ((unsigned char)cc[0] > 0xa0) &&
((unsigned char)cc[1] > 0xa0) )
return 1;
}
 
cc[1] = '\0';
 
return 1;
}
 
static void
expandcchar(PMWHZKFONT pf, int bg, int fg, unsigned char* c, MWPIXELVAL* bitmap)
{
int i=0;
int c1, c2, seq;
int x,y;
unsigned char *font;
int b = 0; /* keep gcc happy with b = 0 - MW */
 
int pixelsize;
pixelsize=sizeof(MWPIXELVAL);
 
c1 = c[0];
c2 = c[1];
if (use_big5)
{
seq=0;
/* ladd=loby-(if(loby<127)?64:98)*/
c2-=(c2<127?64:98);
 
/* hadd=(hiby-164)*157*/
if (c1>=0xa4) /* standard font*/
{
seq=(((c1-164)*157)+c2);
if (seq>=5809) seq-=408;
}
 
/* hadd=(hiby-161)*157*/
if (c1<=0xa3) /* special font*/
seq=(((c1-161)*157)+c2)+13094;
}
else
seq=((c1 - 161)*94 + c2 - 161);
 
font = pf->cfont_address + ((seq) *
(pf->font_height * ((pf->cfont_width + 7) / 8)));
 
for (y = 0; y < pf->font_height; y++)
for (x = 0; x < pf->cfont_width; x++)
{
if (x % 8 == 0)
b = *font++;
 
if (b & (128 >> (x % 8))) /* pixel */
bitmap[i++]=fg;
else
bitmap[i++]=bg;
}
}
 
static void expandchar(PMWHZKFONT pf, int bg, int fg, int c, MWPIXELVAL* bitmap)
{
int i=0;
int x,y;
unsigned char *font;
int pixelsize;
int b = 0; /* keep gcc happy with b = 0 - MW */
 
pixelsize=sizeof(MWPIXELVAL);
 
font = pf->afont_address + c * (pf->font_height *
((pf->afont_width + 7) / 8));
 
for (y = 0; y < pf->font_height; y++)
for (x = 0; x < pf->afont_width; x++)
{
if (x % 8 == 0)
b = *font++;
if (b & (128 >> (x % 8))) /* pixel */
bitmap[i++]=fg;
else
bitmap[i++]=bg;
}
}
 
/*
* Draw ASCII text string using HZK type font
*/
static void
hzk_drawtext(PMWFONT pfont, PSD psd, MWCOORD ax, MWCOORD ay,
const void *text, int cc, int flags)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
 
unsigned char c[2];
MWPIXELVAL *bitmap;
unsigned char s1[3];
char *s,*sbegin;
 
s=(char *)text;
 
if(cc==1)
{
s1[0]=*((unsigned char*)text);
s1[1]=0x0;
s1[2]=0x0;
s=s1;
}
 
sbegin=s;
bitmap = (MWPIXELVAL *)ALLOCA(pf->cfont_width * pf->font_height *
sizeof(MWPIXELVAL));
 
while( getnextchar(s, c) )
{
if( c[1] != '\0')
{
expandcchar(pf, gr_background,gr_foreground,
c, bitmap);
/* Now draw the bitmap ... */
if (flags&MWTF_TOP)
GdArea(psd,ax, ay, pf->cfont_width,
pf->font_height, bitmap, MWPF_PIXELVAL);
else
GdArea(psd,ax, ay-pf->font_height+2,
pf->cfont_width, pf->font_height,
bitmap, MWPF_PIXELVAL);
 
s += 2;
ax += pf->cfont_width;
}
else
{
expandchar(pf, gr_background,gr_foreground,
c[0], bitmap);
/* Now draw the bitmap ... */
 
if (flags&MWTF_TOP)
GdArea(psd,ax, ay, pf->afont_width,
pf->font_height, bitmap, MWPF_PIXELVAL);
else
GdArea(psd,ax, ay-pf->font_height+2,
pf->afont_width, pf->font_height,
bitmap, MWPF_PIXELVAL);
 
s += 1;
ax += pf->afont_width;
}
if(s>=sbegin+cc)break;
}
 
FREEA(bitmap);
}
 
/*
* Return information about a specified font.
*/
static MWBOOL
hzk_getfontinfo(PMWFONT pfont, PMWFONTINFO pfontinfo)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
 
int i;
 
pfontinfo->height = pf->font_height;
pfontinfo->maxwidth = pf->cfont_width;
pfontinfo->baseline = pf->font_height-2;
pfontinfo->firstchar = 0;
pfontinfo->lastchar = 0;
pfontinfo->fixed = TRUE;
for(i=0; i<=256; i++)
pfontinfo->widths[i] = pf->afont_width;
 
return TRUE;
}
 
static void
hzk_gettextsize(PMWFONT pfont, const void *text, int cc,
MWCOORD *pwidth, MWCOORD *pheight, MWCOORD *pbase)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
 
unsigned char c[2];
char *s,*sbegin;
unsigned char s1[3];
 
int ax=0;
s=(char *)text;
if(cc==0)
{
*pwidth = 0;
*pheight = pf->font_height;
*pbase = pf->font_height-2;
 
}
if(cc==1)
{
s1[0]=*((unsigned char*)text);
s1[1]=0x0;
s1[2]=0x0;
s=s1;
}
sbegin=s;
while( getnextchar(s, c) )
{
if( c[1] != '\0')
{
s += 2;
ax += pf->cfont_width;
}
else
{
s += 1;
ax += pf->afont_width;
}
if(s>=sbegin+cc) {
/*fprintf(stderr,"s=%x,sbegin=%x,cc=%x\n",s,sbegin,cc);*/
break;
}
 
}
/*fprintf(stderr,"ax=%d,\n",ax);*/
 
*pwidth = ax;
*pheight = pf->font_height;
*pbase = pf->font_height-2;
}
 
static void
hzk_destroyfont(PMWFONT pfont)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
UnloadFont(pf);
free(pf);
}
 
static void
hzk_setfontsize(PMWFONT pfont, MWCOORD fontsize)
{
PMWHZKFONT pf=(PMWHZKFONT)pfont;
/* jmt: hzk_setfontsize not supported*/
/* & pf->fontsize can't be changed*/
/* because of hzk_id() :p*/
pf->fontsize=pf->font_height;
}
#endif /* HAVE_HZK_SUPPORT*/
 
/* FIXME: this routine should work for all font renderers...*/
int
GdGetTextSizeEx(PMWFONT pfont, const void *str, int cc,int nMaxExtent,
int* lpnFit, int* alpDx,MWCOORD *pwidth,MWCOORD *pheight,
MWCOORD *pbase, int flags)
{
#ifdef HAVE_FREETYPE_SUPPORT
unsigned short buf[256];
unsigned short* text;
PMWFREETYPEFONT pf = (PMWFREETYPEFONT)pfont;
int defencoding = pf->fontprocs->encoding;
int x = 0;
int i;
TT_UShort curchar;
TT_Glyph_Metrics metrics;
TT_Face_Properties properties;
TT_Instance_Metrics imetrics;
 
if ((cc<0)||(!str))
{
*pwidth = *pheight = *pbase = 0;
return 0;
}
/* convert encoding if required*/
if((flags & MWTF_PACKMASK) != defencoding)
{
cc = GdConvertEncoding(str, flags, cc, buf, defencoding);
flags &= ~MWTF_PACKMASK;
flags |= defencoding;
text=buf;
} else text =(unsigned short*)str;
if(cc <= 0)
{
*pwidth = *pheight = *pbase = 0;
return 0;
}
 
TT_Get_Face_Properties (pf->face, &properties);
TT_Get_Instance_Metrics(pf->instance, &imetrics);
pf->last_glyph_code = -1; /* reset kerning*/
pf->last_pen_pos = -32767;
if (lpnFit)
*lpnFit=-1;
for (i = 0; i < cc; i++)
{
curchar = TT_Char_Index (pf->char_map,text[i]);
if (TT_Load_Glyph (pf->instance, pf->glyph, curchar,
TTLOAD_SCALE_GLYPH|TTLOAD_HINT_GLYPH) != TT_Err_Ok)
{
fprintf(stderr, "Unable to load glyph with index=%d\n",curchar);
return 0;
}
TT_Get_Glyph_Metrics (pf->glyph, &metrics);
if ((pf->fontattr&MWTF_KERNING) && pf->can_kern)
{
x += compute_kernval(pf, curchar) / 64;
}
x += metrics.advance / 64;
if((lpnFit)&&(alpDx))
{
if (x<=nMaxExtent)
alpDx[i]=x;
else
if (*lpnFit==-1)
(*lpnFit)=i;
}
/* Kerning point syndrome avoidance */
if (pf->last_pen_pos > x)
x = pf->last_pen_pos;
pf->last_pen_pos = x;
pf->last_glyph_code = curchar;
}
if ((lpnFit)&&(*lpnFit==-1))
*lpnFit=cc;
*pwidth = x;
*pheight = (((properties.horizontal->Ascender *
imetrics.y_scale)/ 0x10000) >> 6) -
(((properties.horizontal->Descender *
imetrics.y_scale)/ 0x10000) >> 6);
/* FIXME: is it what's required ??*/
if (pbase)
*pbase = (((-properties.horizontal->Descender) *
imetrics.y_scale)/ 0x10000) >> 6;
return 1;
#else /* HAVE_FREETYPE_SUPPORT*/
*pwidth = *pheight = *pbase = 0;
return 0;
#endif
}
 
#ifdef HAVE_FREETYPE_SUPPORT
#include <dirent.h>
/*
* This function is taken almost verbatim from ftdump.c from
* the freetype library (version 1.3.1)
*/
static char *
tt_lookup_name(TT_Face face)
{
TT_Face_Properties prop;
unsigned short i, n;
unsigned short platform, encoding, language, id;
char *string;
char *name_buffer;
unsigned short string_len;
int j, found;
int index = 4; /* I dont know why as yet.. */
int name_len;
 
 
TT_Get_Face_Properties(face, &prop);
n = prop.num_Names;
 
for ( i = 0; i < n; i++ ) {
TT_Get_Name_ID( face, i, &platform, &encoding, &language, &id );
TT_Get_Name_String( face, i, &string, &string_len );
 
if (id == index ) {
/* The following code was inspired from Mark Leisher's */
/* ttf2bdf package */
found = 0;
 
/* Try to find a Microsoft English name */
if ( platform == 3 )
for ( j = 1; j >= 0; j-- )
if ( encoding == j ) /* Microsoft ? */
if ( (language & 0x3FF) == 0x009 ) {
/* English language */
found = 1;
break;
}
 
if ( !found && platform == 0 && language == 0 )
found = 1;
 
/* Found a Unicode Name. */
if ( found ) {
if ( string_len > 512 )
string_len = 512;
 
name_len = 0;
name_buffer = (char*)malloc((string_len / 2) + 1);
 
for ( i = 1; i < string_len; i += 2 )
name_buffer[name_len++] = string[i];
 
name_buffer[name_len] = '\0';
 
return name_buffer;
}
}
}
 
/* Not found */
return NULL;
}
 
static char *
get_tt_name(char *p)
{
TT_Face face;
char *ret;
 
/*printf("Trying to open: %s!\n",p);*/
 
if (TT_Open_Face(engine, p, &face) != TT_Err_Ok) {
fprintf(stderr, "Error opening font: %s\n", p);
return NULL;
}
 
ret = tt_lookup_name(face);
 
TT_Close_Face(face);
 
return ret;
}
 
void
GdFreeFontList(MWFONTLIST ***fonts, int n)
{
int i;
MWFONTLIST *g, **list = *fonts;
 
for (i = 0; i < n; i++) {
g = list[i];
if(g) {
if(g->mwname)
free(g->mwname);
if(g->ttname)
free(g->ttname);
free(g);
}
}
free(list);
*fonts = 0;
}
 
void
GdGetFontList(MWFONTLIST ***fonts, int *numfonts)
{
DIR *dir;
struct dirent *dent;
char *p, *ftmp;
int pl, idx = 0;
MWFONTLIST **list;
 
if (TT_Err_Ok != TT_Init_FreeType(&engine)) {
fprintf(stderr, "Unable to initialize freetype\n");
*numfonts = -1;
return ;
}
 
dir = opendir(FREETYPE_FONT_DIR);
 
if (dir <= 0) {
fprintf(stderr, "Error opening font directory\n");
*numfonts = -1;
return ;
}
 
/* get the number of strings we need to allocate */
while ((dent = readdir(dir)) != NULL) {
p = strrchr(dent->d_name, '.');
if (strcasecmp(p, ".ttf") == 0)
idx++;
}
 
*numfonts = idx;
rewinddir(dir);
 
/* allocate strings */
list = (MWFONTLIST**)malloc(idx * sizeof(MWFONTLIST*));
for (pl = 0; pl < idx; pl++)
list[pl] = (MWFONTLIST*)malloc(sizeof(MWFONTLIST));
 
*fonts = list;
 
idx = 0;
 
while ((dent = readdir(dir)) != NULL) {
/* check extension */
p = strrchr(dent->d_name, '.');
 
if (strcasecmp(p, ".ttf") == 0) {
/* get full path */
p = 0;
pl = strlen(FREETYPE_FONT_DIR) + strlen(dent->d_name) *
sizeof(char) + 2;
p = (char*)malloc(pl);
p = (char*)memset(p, '\0', pl);
p = (char*)strcat(p, FREETYPE_FONT_DIR);
p = (char*)strcat(p, "/");
p = (char*)strcat(p, dent->d_name);
 
 
if((ftmp = get_tt_name(p)) != NULL) {
list[idx]->ttname = ftmp;
list[idx]->mwname = malloc(strlen(dent->d_name) + 1);
list[idx]->mwname = strcpy(list[idx]->mwname, dent->d_name);
 
idx++;
}
 
free(p);
}
}
closedir(dir);
}
#else /* !HAVE_FREETYPE_SUPPORT*/
 
void
GdFreeFontList(MWFONTLIST ***fonts, int n)
{
}
 
void
GdGetFontList(MWFONTLIST ***fonts, int *numfonts)
{
*numfonts = -1;
}
#endif /* !HAVE_FREETYPE_SUPPORT*/
/devrgn2.c
0,0 → 1,910
/*
* Portions Copyright (c) 2000 Greg Haerr <greg@censoft.com>
* Somewhat less shamelessly ripped from the Wine distribution
* and the X Window System.
*
* Device-independent Microwindows polygon regions, implemented using
* multiple rectangles.
*
* Shamelessly ripped out from the X11 distribution
* Thanks for the nice licence.
*
* Copyright 1993, 1994, 1995 Alexandre Julliard
* Modifications and additions: Copyright 1998 Huw Davies
*/
 
/************************************************************************
 
Copyright (c) 1987, 1988 X Consortium
 
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.
 
 
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
 
All Rights Reserved
 
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
 
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
 
************************************************************************/
 
#include <stdio.h>
#include <stdlib.h>
#include "device.h"
 
#if POLYREGIONS
 
/*
* number of points to buffer before sending them off
* to scanlines() : Must be an even number
*/
#define NUMPTSTOBUFFER 200
/*
* used to allocate buffers for points and link
* the buffers together
*/
 
typedef struct _POINTBLOCK {
MWPOINT pts[NUMPTSTOBUFFER];
struct _POINTBLOCK *next;
} POINTBLOCK;
 
/*
* This file contains a few macros to help track
* the edge of a filled object. The object is assumed
* to be filled in scanline order, and thus the
* algorithm used is an extension of Bresenham's line
* drawing algorithm which assumes that y is always the
* major axis.
* Since these pieces of code are the same for any filled shape,
* it is more convenient to gather the library in one
* place, but since these pieces of code are also in
* the inner loops of output primitives, procedure call
* overhead is out of the question.
* See the author for a derivation if needed.
*/
 
/*
* In scan converting polygons, we want to choose those pixels
* which are inside the polygon. Thus, we add .5 to the starting
* x coordinate for both left and right edges. Now we choose the
* first pixel which is inside the pgon for the left edge and the
* first pixel which is outside the pgon for the right edge.
* Draw the left pixel, but not the right.
*
* How to add .5 to the starting x coordinate:
* If the edge is moving to the right, then subtract dy from the
* error term from the general form of the algorithm.
* If the edge is moving to the left, then add dy to the error term.
*
* The reason for the difference between edges moving to the left
* and edges moving to the right is simple: If an edge is moving
* to the right, then we want the algorithm to flip immediately.
* If it is moving to the left, then we don't want it to flip until
* we traverse an entire pixel.
*/
 
#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
int dx; /* local storage */ \
\
/* \
* if the edge is horizontal, then it is ignored \
* and assumed not to be processed. Otherwise, do this stuff. \
*/ \
if ((dy) != 0) { \
xStart = (x1); \
dx = (x2) - xStart; \
if (dx < 0) { \
m = dx / (dy); \
m1 = m - 1; \
incr1 = (-2) * (dx) + 2 * (dy) * (m1); \
incr2 = (-2) * (dx) + 2 * (dy) * (m); \
d = 2 * (m) * (dy) - 2 * (dx) - 2 * (dy); \
} else { \
m = dx / (dy); \
m1 = m + 1; \
incr1 = (2 * dx) - 2 * (dy) * m1; \
incr2 = (2 * dx) - 2 * (dy) * m; \
d = (-2) * m * (dy) + 2 * dx; \
} \
} \
}
 
#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
if (m1 > 0) { \
if (d > 0) { \
minval += m1; \
d += incr1; \
} \
else { \
minval += m; \
d += incr2; \
} \
} else {\
if (d >= 0) { \
minval += m1; \
d += incr1; \
} \
else { \
minval += m; \
d += incr2; \
} \
} \
}
 
 
/*
* This structure contains all of the information needed
* to run the bresenham algorithm.
* The variables may be hardcoded into the declarations
* instead of using this structure to make use of
* register declarations.
*/
typedef struct {
MWCOORD minor_axis; /* minor axis */
int d; /* decision variable */
int m, m1; /* slope and slope+1 */
int incr1, incr2; /* error increments */
} BRESINFO;
 
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
bres.m, bres.m1, bres.incr1, bres.incr2)
 
#define BRESINCRPGONSTRUCT(bres) \
BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
 
 
/*
* These are the data structures needed to scan
* convert regions. Two different scan conversion
* methods are available -- the even-odd method, and
* the winding number method.
* The even-odd rule states that a point is inside
* the polygon if a ray drawn from that point in any
* direction will pass through an odd number of
* path segments.
* By the winding number rule, a point is decided
* to be inside the polygon if a ray drawn from that
* point in any direction passes through a different
* number of clockwise and counter-clockwise path
* segments.
*
* These data structures are adapted somewhat from
* the algorithm in (Foley/Van Dam) for scan converting
* polygons.
* The basic algorithm is to start at the top (smallest y)
* of the polygon, stepping down to the bottom of
* the polygon by incrementing the y coordinate. We
* keep a list of edges which the current scanline crosses,
* sorted by x. This list is called the Active Edge Table (AET)
* As we change the y-coordinate, we update each entry in
* in the active edge table to reflect the edges new xcoord.
* This list must be sorted at each scanline in case
* two edges intersect.
* We also keep a data structure known as the Edge Table (ET),
* which keeps track of all the edges which the current
* scanline has not yet reached. The ET is basically a
* list of ScanLineList structures containing a list of
* edges which are entered at a given scanline. There is one
* ScanLineList per scanline at which an edge is entered.
* When we enter a new edge, we move it from the ET to the AET.
*
* From the AET, we can implement the even-odd rule as in
* (Foley/Van Dam).
* The winding number rule is a little trickier. We also
* keep the EdgeTableEntries in the AET linked by the
* nextWETE (winding EdgeTableEntry) link. This allows
* the edges to be linked just as before for updating
* purposes, but only uses the edges linked by the nextWETE
* link as edges representing spans of the polygon to
* drawn (as with the even-odd rule).
*/
 
/*
* for the winding number rule
*/
#define CLOCKWISE 1
#define COUNTERCLOCKWISE -1
 
typedef struct _EdgeTableEntry {
MWCOORD ymax; /* ycoord at which we exit this edge. */
BRESINFO bres; /* Bresenham info to run the edge */
struct _EdgeTableEntry *next; /* next in the list */
struct _EdgeTableEntry *back; /* for insertion sort */
struct _EdgeTableEntry *nextWETE; /* for winding num rule */
int ClockWise; /* flag for winding number rule */
} EdgeTableEntry;
 
 
typedef struct _ScanLineList{
int scanline; /* the scanline represented */
EdgeTableEntry *edgelist; /* header node */
struct _ScanLineList *next; /* next in the list */
} ScanLineList;
 
 
typedef struct {
MWCOORD ymax; /* ymax for the polygon */
MWCOORD ymin; /* ymin for the polygon */
ScanLineList scanlines; /* header node */
} EdgeTable;
 
 
/*
* Here is a struct to help with storage allocation
* so we can allocate a big chunk at a time, and then take
* pieces from this heap when we need to.
*/
#define SLLSPERBLOCK 25
 
typedef struct _ScanLineListBlock {
ScanLineList SLLs[SLLSPERBLOCK];
struct _ScanLineListBlock *next;
} ScanLineListBlock;
 
/*
*
* a few macros for the inner loops of the fill code where
* performance considerations don't allow a procedure call.
*
* Evaluate the given edge at the given scanline.
* If the edge has expired, then we leave it and fix up
* the active edge table; otherwise, we increment the
* x value to be ready for the next scanline.
* The winding number rule is in effect, so we must notify
* the caller when the edge has been removed so he
* can reorder the Winding Active Edge Table.
*/
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
if (pAET->ymax == y) { /* leaving this edge */ \
pPrevAET->next = pAET->next; \
pAET = pPrevAET->next; \
fixWAET = 1; \
if (pAET) \
pAET->back = pPrevAET; \
} \
else { \
BRESINCRPGONSTRUCT(pAET->bres); \
pPrevAET = pAET; \
pAET = pAET->next; \
} \
}
 
 
/*
* Evaluate the given edge at the given scanline.
* If the edge has expired, then we leave it and fix up
* the active edge table; otherwise, we increment the
* x value to be ready for the next scanline.
* The even-odd rule is in effect.
*/
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
if (pAET->ymax == y) { /* leaving this edge */ \
pPrevAET->next = pAET->next; \
pAET = pPrevAET->next; \
if (pAET) \
pAET->back = pPrevAET; \
} \
else { \
BRESINCRPGONSTRUCT(pAET->bres); \
pPrevAET = pAET; \
pAET = pAET->next; \
} \
}
 
 
 
#define LARGE_COORDINATE 0x7fffffff /* FIXME */
#define SMALL_COORDINATE 0x80000000
 
/*
* REGION_InsertEdgeInET
*
* Insert the given edge into the edge table.
* First we must find the correct bucket in the
* Edge table, then find the right slot in the
* bucket. Finally, we can insert it.
*
*/
static void REGION_InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE,
int scanline, ScanLineListBlock **SLLBlock, int *iSLLBlock)
 
{
EdgeTableEntry *start, *prev;
ScanLineList *pSLL, *pPrevSLL;
ScanLineListBlock *tmpSLLBlock;
 
/*
* find the right bucket to put the edge into
*/
pPrevSLL = &ET->scanlines;
pSLL = pPrevSLL->next;
while (pSLL && (pSLL->scanline < scanline))
{
pPrevSLL = pSLL;
pSLL = pSLL->next;
}
 
/*
* reassign pSLL (pointer to ScanLineList) if necessary
*/
if ((!pSLL) || (pSLL->scanline > scanline))
{
if (*iSLLBlock > SLLSPERBLOCK-1)
{
tmpSLLBlock = malloc( sizeof(ScanLineListBlock));
if(!tmpSLLBlock)
{
return;
}
(*SLLBlock)->next = tmpSLLBlock;
tmpSLLBlock->next = (ScanLineListBlock *)NULL;
*SLLBlock = tmpSLLBlock;
*iSLLBlock = 0;
}
pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
 
pSLL->next = pPrevSLL->next;
pSLL->edgelist = (EdgeTableEntry *)NULL;
pPrevSLL->next = pSLL;
}
pSLL->scanline = scanline;
 
/*
* now insert the edge in the right bucket
*/
prev = (EdgeTableEntry *)NULL;
start = pSLL->edgelist;
while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
{
prev = start;
start = start->next;
}
ETE->next = start;
 
if (prev)
prev->next = ETE;
else
pSLL->edgelist = ETE;
}
 
 
/*
* REGION_CreateEdgeTable
*
* This routine creates the edge table for
* scan converting polygons.
* The Edge Table (ET) looks like:
*
* EdgeTable
* --------
* | ymax | ScanLineLists
* |scanline|-->------------>-------------->...
* -------- |scanline| |scanline|
* |edgelist| |edgelist|
* --------- ---------
* | |
* | |
* V V
* list of ETEs list of ETEs
*
* where ETE is an EdgeTableEntry data structure,
* and there is one ScanLineList per scanline at
* which an edge is initially entered.
*
*/
static void REGION_CreateETandAET(int *Count, int nbpolygons,
MWPOINT *pts, EdgeTable *ET, EdgeTableEntry *AET,
EdgeTableEntry *pETEs, ScanLineListBlock *pSLLBlock)
{
MWPOINT *top, *bottom;
MWPOINT *PrevPt, *CurrPt, *EndPt;
int poly, count;
int iSLLBlock = 0;
int dy;
 
 
/*
* initialize the Active Edge Table
*/
AET->next = (EdgeTableEntry *)NULL;
AET->back = (EdgeTableEntry *)NULL;
AET->nextWETE = (EdgeTableEntry *)NULL;
AET->bres.minor_axis = SMALL_COORDINATE;
 
/*
* initialize the Edge Table.
*/
ET->scanlines.next = (ScanLineList *)NULL;
ET->ymax = SMALL_COORDINATE;
ET->ymin = LARGE_COORDINATE;
pSLLBlock->next = (ScanLineListBlock *)NULL;
 
EndPt = pts - 1;
for(poly = 0; poly < nbpolygons; poly++)
{
count = Count[poly];
EndPt += count;
if(count < 2)
continue;
 
PrevPt = EndPt;
 
/*
* for each vertex in the array of points.
* In this loop we are dealing with two vertices at
* a time -- these make up one edge of the polygon.
*/
while (count--)
{
CurrPt = pts++;
/*
* find out which point is above and which is below.
*/
if (PrevPt->y > CurrPt->y)
{
bottom = PrevPt, top = CurrPt;
pETEs->ClockWise = 0;
}
else
{
bottom = CurrPt, top = PrevPt;
pETEs->ClockWise = 1;
}
 
/*
* don't add horizontal edges to the Edge table.
*/
if (bottom->y != top->y)
{
pETEs->ymax = bottom->y-1;
/* -1 so we don't get last scanline */
 
/*
* initialize integer edge algorithm
*/
dy = bottom->y - top->y;
BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
 
REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
&iSLLBlock);
 
if (PrevPt->y > ET->ymax)
ET->ymax = PrevPt->y;
if (PrevPt->y < ET->ymin)
ET->ymin = PrevPt->y;
pETEs++;
}
 
PrevPt = CurrPt;
}
}
}
 
/*
* REGION_loadAET
*
* This routine moves EdgeTableEntries from the
* EdgeTable into the Active Edge Table,
* leaving them sorted by smaller x coordinate.
*
*/
static void REGION_loadAET(EdgeTableEntry *AET, EdgeTableEntry *ETEs)
{
EdgeTableEntry *pPrevAET;
EdgeTableEntry *tmp;
 
pPrevAET = AET;
AET = AET->next;
while (ETEs)
{
while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
{
pPrevAET = AET;
AET = AET->next;
}
tmp = ETEs->next;
ETEs->next = AET;
if (AET)
AET->back = ETEs;
ETEs->back = pPrevAET;
pPrevAET->next = ETEs;
pPrevAET = ETEs;
 
ETEs = tmp;
}
}
 
/*
* REGION_computeWAET
*
* This routine links the AET by the
* nextWETE (winding EdgeTableEntry) link for
* use by the winding number rule. The final
* Active Edge Table (AET) might look something
* like:
*
* AET
* ---------- --------- ---------
* |ymax | |ymax | |ymax |
* | ... | |... | |... |
* |next |->|next |->|next |->...
* |nextWETE| |nextWETE| |nextWETE|
* --------- --------- ^--------
* | | |
* V-------------------> V---> ...
*
*/
static void REGION_computeWAET(EdgeTableEntry *AET)
{
EdgeTableEntry *pWETE;
int inside = 1;
int isInside = 0;
 
AET->nextWETE = (EdgeTableEntry *)NULL;
pWETE = AET;
AET = AET->next;
while (AET)
{
if (AET->ClockWise)
isInside++;
else
isInside--;
 
if ((!inside && !isInside) ||
( inside && isInside))
{
pWETE->nextWETE = AET;
pWETE = AET;
inside = !inside;
}
AET = AET->next;
}
pWETE->nextWETE = (EdgeTableEntry *)NULL;
}
 
/*
* REGION_InsertionSort
*
* Just a simple insertion sort using
* pointers and back pointers to sort the Active
* Edge Table.
*
*/
static MWBOOL REGION_InsertionSort(EdgeTableEntry *AET)
{
EdgeTableEntry *pETEchase;
EdgeTableEntry *pETEinsert;
EdgeTableEntry *pETEchaseBackTMP;
MWBOOL changed = FALSE;
 
AET = AET->next;
while (AET)
{
pETEinsert = AET;
pETEchase = AET;
while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
pETEchase = pETEchase->back;
 
AET = AET->next;
if (pETEchase != pETEinsert)
{
pETEchaseBackTMP = pETEchase->back;
pETEinsert->back->next = AET;
if (AET)
AET->back = pETEinsert->back;
pETEinsert->next = pETEchase;
pETEchase->back->next = pETEinsert;
pETEchase->back = pETEinsert;
pETEinsert->back = pETEchaseBackTMP;
changed = TRUE;
}
}
return changed;
}
 
/*
* REGION_FreeStorage
*
* Clean up our act.
*/
static void REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
{
ScanLineListBlock *tmpSLLBlock;
 
while (pSLLBlock)
{
tmpSLLBlock = pSLLBlock->next;
free( pSLLBlock );
pSLLBlock = tmpSLLBlock;
}
}
 
 
/*
* REGION_PtsToRegion
*
* Create an array of rectangles from a list of points.
*/
static int REGION_PtsToRegion(int numFullPtBlocks, int iCurPtBlock,
POINTBLOCK *FirstPtBlock, MWCLIPREGION *reg)
{
MWRECT *rects;
MWPOINT *pts;
POINTBLOCK *CurPtBlock;
int i;
MWRECT *extents;
int numRects;
 
extents = &reg->extents;
 
numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
 
if (!(reg->rects = realloc( reg->rects, sizeof(MWRECT) * numRects )))
return(0);
 
reg->size = numRects;
CurPtBlock = FirstPtBlock;
rects = reg->rects - 1;
numRects = 0;
extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
 
for ( ; numFullPtBlocks >= 0; numFullPtBlocks--) {
/* the loop uses 2 points per iteration */
i = NUMPTSTOBUFFER >> 1;
if (!numFullPtBlocks)
i = iCurPtBlock >> 1;
for (pts = CurPtBlock->pts; i--; pts += 2) {
if (pts->x == pts[1].x)
continue;
if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
pts[1].x == rects->right &&
(numRects == 1 || rects[-1].top != rects->top) &&
(i && pts[2].y > pts[1].y)) {
rects->bottom = pts[1].y + 1;
continue;
}
numRects++;
rects++;
rects->left = pts->x; rects->top = pts->y;
rects->right = pts[1].x; rects->bottom = pts[1].y + 1;
if (rects->left < extents->left)
extents->left = rects->left;
if (rects->right > extents->right)
extents->right = rects->right;
}
CurPtBlock = CurPtBlock->next;
}
 
if (numRects) {
extents->top = reg->rects->top;
extents->bottom = rects->bottom;
} else {
extents->left = 0;
extents->top = 0;
extents->right = 0;
extents->bottom = 0;
}
reg->numRects = numRects;
 
return(TRUE);
}
 
/*
* GdAllocPolygonRegion
*/
MWCLIPREGION *
GdAllocPolygonRegion(MWPOINT *points, int count, int mode)
{
return GdAllocPolyPolygonRegion(points, &count, 1, mode );
}
 
/*
* GdAllocPolyPolygonRegion
*/
MWCLIPREGION *
GdAllocPolyPolygonRegion(MWPOINT *points, int *count, int nbpolygons, int mode)
{
MWCLIPREGION *rgn;
EdgeTableEntry *pAET; /* Active Edge Table */
int y; /* current scanline */
int iPts = 0; /* number of pts in buffer */
EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
ScanLineList *pSLL; /* current scanLineList */
MWPOINT *pts; /* output buffer */
EdgeTableEntry *pPrevAET; /* ptr to previous AET */
EdgeTable ET; /* header node for ET */
EdgeTableEntry AET; /* header node for AET */
EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
ScanLineListBlock SLLBlock; /* header for scanlinelist */
int fixWAET = FALSE;
POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
POINTBLOCK *tmpPtBlock;
int numFullPtBlocks = 0;
int poly, total;
 
if(!(rgn = GdAllocRegion()))
return NULL;
/* special case a rectangle */
 
if (((nbpolygons == 1) && ((*count == 4) ||
((*count == 5) && (points[4].x == points[0].x)
&& (points[4].y == points[0].y)))) &&
(((points[0].y == points[1].y) &&
(points[1].x == points[2].x) &&
(points[2].y == points[3].y) &&
(points[3].x == points[0].x)) ||
((points[0].x == points[1].x) &&
(points[1].y == points[2].y) &&
(points[2].x == points[3].x) &&
(points[3].y == points[0].y))))
{
GdSetRectRegion( rgn,
MWMIN(points[0].x, points[2].x), MWMIN(points[0].y, points[2].y),
MWMAX(points[0].x, points[2].x), MWMAX(points[0].y, points[2].y) );
return rgn;
}
 
for(poly = total = 0; poly < nbpolygons; poly++)
total += count[poly];
if (! (pETEs = malloc( sizeof(EdgeTableEntry) * total )))
{
GdDestroyRegion( rgn );
return 0;
}
pts = FirstPtBlock.pts;
REGION_CreateETandAET(count, nbpolygons, points, &ET, &AET,
pETEs, &SLLBlock);
pSLL = ET.scanlines.next;
curPtBlock = &FirstPtBlock;
 
if (mode != MWPOLY_WINDING) {
/*
* for each scanline
*/
for (y = ET.ymin; y < ET.ymax; y++) {
/*
* Add a new edge to the active edge table when we
* get to the next edge.
*/
if (pSLL != NULL && y == pSLL->scanline) {
REGION_loadAET(&AET, pSLL->edgelist);
pSLL = pSLL->next;
}
pPrevAET = &AET;
pAET = AET.next;
 
/*
* for each active edge
*/
while (pAET) {
pts->x = pAET->bres.minor_axis, pts->y = y;
pts++, iPts++;
 
/*
* send out the buffer
*/
if (iPts == NUMPTSTOBUFFER) {
tmpPtBlock = malloc( sizeof(POINTBLOCK));
if(!tmpPtBlock) {
return 0;
}
curPtBlock->next = tmpPtBlock;
curPtBlock = tmpPtBlock;
pts = curPtBlock->pts;
numFullPtBlocks++;
iPts = 0;
}
EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
 
}
REGION_InsertionSort(&AET);
}
}
else {
/*
* for each scanline
*/
for (y = ET.ymin; y < ET.ymax; y++) {
/*
* Add a new edge to the active edge table when we
* get to the next edge.
*/
if (pSLL != NULL && y == pSLL->scanline) {
REGION_loadAET(&AET, pSLL->edgelist);
REGION_computeWAET(&AET);
pSLL = pSLL->next;
}
pPrevAET = &AET;
pAET = AET.next;
pWETE = pAET;
 
/*
* for each active edge
*/
while (pAET) {
/*
* add to the buffer only those edges that
* are in the Winding active edge table.
*/
if (pWETE == pAET) {
pts->x = pAET->bres.minor_axis, pts->y = y;
pts++, iPts++;
 
/*
* send out the buffer
*/
if (iPts == NUMPTSTOBUFFER) {
tmpPtBlock = malloc( sizeof(POINTBLOCK) );
if(!tmpPtBlock) {
return 0;
}
curPtBlock->next = tmpPtBlock;
curPtBlock = tmpPtBlock;
pts = curPtBlock->pts;
numFullPtBlocks++; iPts = 0;
}
pWETE = pWETE->nextWETE;
}
EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
}
 
/*
* recompute the winding active edge table if
* we just resorted or have exited an edge.
*/
if (REGION_InsertionSort(&AET) || fixWAET) {
REGION_computeWAET(&AET);
fixWAET = FALSE;
}
}
}
REGION_FreeStorage(SLLBlock.next);
REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, rgn);
for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) {
tmpPtBlock = curPtBlock->next;
free( curPtBlock );
curPtBlock = tmpPtBlock;
}
free( pETEs );
return rgn;
}
 
#endif /* POLYREGIONS*/
/devclip1.c
0,0 → 1,247
/*
* Copyright (c) 1999 Greg Haerr <greg@censoft.com>
* Copyright (c) 1991 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Device-independent routines to determine clipping regions.
*/
#include "device.h"
 
/* Clip cache rectangle information.
* After calling GdClipPoint, this rectangle is guaranteed to contain the
* specified point (among others), and all points in the rectangle are
* plottable or not according to the value of clipresult.
*/
MWCOORD clipminx; /* minimum x value of cache rectangle */
MWCOORD clipminy; /* minimum y value of cache rectangle */
MWCOORD clipmaxx; /* maximum x value of cache rectangle */
MWCOORD clipmaxy; /* maximum y value of cache rectangle */
 
static MWBOOL clipresult; /* whether clip rectangle is plottable */
int clipcount; /* number of clip rectangles */
MWCLIPRECT cliprects[MAX_CLIPRECTS]; /* clip rectangles */
 
/*
* Set an array of clip rectangles for future drawing actions.
* Each pixel will be drawn only if lies in one or more of the specified
* clip rectangles. As a special case, specifying no rectangles implies
* clipping is for the complete screen. All clip rectangles are modified
* if necessary to lie within the device area. Call only after device
* has been initialized.
*/
void
GdSetClipRects(PSD psd,int count, MWCLIPRECT *table)
{
register MWCLIPRECT *rp; /* current rectangle */
 
/* If there are no clip rectangles, then default to the full device area. */
if (count <= 0) {
clipminx = 0;
clipminy = 0;
clipmaxx = psd->xvirtres - 1;
clipmaxy = psd->yvirtres - 1;
clipcount = 0;
clipresult = TRUE;
return;
}
 
/* Copy the clip table to our own static array, modifying each
* rectangle as necesary to fit within the device area. If the clip
* rectangle lies entirely outside of the device area, then skip it.
*/
rp = cliprects;
clipcount = 0;
if (count > MAX_CLIPRECTS) count = MAX_CLIPRECTS;
while (count-- > 0) {
*rp = *table++;
if (rp->x < 0) {
rp->width += rp->x;
rp->x = 0;
}
if (rp->y < 0) {
rp->height += rp->y;
rp->y = 0;
}
if ((rp->x >= psd->xvirtres) || (rp->width <= 0) ||
(rp->y >= psd->yvirtres) || (rp->height <= 0))
continue;
if (rp->x + rp->width > psd->xvirtres)
rp->width = psd->xvirtres - rp->x;
if (rp->y + rp->height > psd->yvirtres)
rp->height = psd->yvirtres - rp->y;
rp++;
clipcount++;
}
 
/* If there were no surviving clip rectangles, then set the clip
* cache to prevent all drawing.
*/
if (clipcount == 0) {
clipminx = MIN_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return;
}
 
/* There was at least one valid clip rectangle. Default the clip
* cache to be the first clip rectangle.
*/
clipminx = cliprects[0].x;
clipminy = cliprects[0].y;
clipmaxx = clipminx + cliprects[0].width - 1;
clipmaxy = clipminy + cliprects[0].height - 1;
clipresult = TRUE;
}
 
 
/* Check a point against the list of clip rectangles.
* Returns TRUE if the point is within one or more rectangles and thus
* can be plotted, or FALSE if the point is not within any rectangle and
* thus cannot be plotted. Also remembers the coordinates of a clip cache
* rectangle containing the specified point such that every point in the
* rectangle would give the same result. By examining this clip cache
* rectangle after a call to this routine, the caller can efficiently
* check many nearby points without needing any further calls. If the
* point lies within the cursor, then the cursor is removed.
*/
MWBOOL
GdClipPoint(PSD psd,MWCOORD x,MWCOORD y)
{
int count;
MWCLIPRECT *rp;
MWCOORD temp;
 
/* First see whether the point lies within the current clip cache
* rectangle. If so, then we already know the result.
*/
if ((x >= clipminx) && (x <= clipmaxx) &&
(y >= clipminy) && (y <= clipmaxy)) {
if (clipresult) GdCheckCursor(psd, x, y, x, y);
return clipresult;
}
 
/* If the point is outside of the screen area, then it is not
* plottable, and the clip cache rectangle is the whole half-plane
* outside of the screen area.
*/
if (x < 0) {
clipminx = MIN_MWCOORD;
clipmaxx = -1;
clipminy = MIN_MWCOORD;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return FALSE;
}
if (y < 0) {
clipminx = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxy = -1;
clipresult = FALSE;
return FALSE;
}
if (x >= psd->xvirtres) {
clipminx = psd->xvirtres;
clipmaxx = MAX_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return FALSE;
}
if (y >= psd->yvirtres) {
clipminx = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipminy = psd->yvirtres;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return FALSE;
}
 
/* The point is within the screen area. If there are no clip
* rectangles, then the point is plottable and the rectangle is the
* whole screen.
*/
count = clipcount;
if (count <= 0) {
clipminx = 0;
clipmaxx = psd->xvirtres - 1;
clipminy = 0;
clipmaxy = psd->yvirtres - 1;
clipresult = TRUE;
GdCheckCursor(psd, x, y, x, y);
return TRUE;
}
 
/* We need to scan the list of clip rectangles to calculate a new
* clip cache rectangle containing this point, and the result. First
* see if the point lies within any of the clip rectangles. If so,
* then it is plottable and use that clip rectangle as the cache
* rectangle. This is not necessarily the best result, but works ok
* and is fast.
*/
for (rp = cliprects; count-- > 0; rp++) {
if ((x >= rp->x) && (y >= rp->y) && (x < rp->x + rp->width)
&& (y < rp->y + rp->height)) {
clipminx = rp->x;
clipminy = rp->y;
clipmaxx = rp->x + rp->width - 1;
clipmaxy = rp->y + rp->height - 1;
clipresult = TRUE;
GdCheckCursor(psd, x, y, x, y);
return TRUE;
}
}
 
/* The point is not plottable. Scan the clip rectangles again to
* determine a rectangle containing more non-plottable points.
* Simply pick the largest rectangle whose area doesn't contain any
* of the same coordinates as appropriate sides of the clip
* rectangles. This is not necessarily the best result, but works ok
* and is fast.
*/
clipminx = MIN_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipmaxy = MAX_MWCOORD;
count = clipcount;
for (rp = cliprects; count-- > 0; rp++) {
if ((x < rp->x) && (rp->x <= clipmaxx)) clipmaxx = rp->x - 1;
temp = rp->x + rp->width - 1;
if ((x > temp) && (temp >= clipminx)) clipminx = temp + 1;
if ((y < rp->y) && (rp->y <= clipmaxy)) clipmaxy = rp->y - 1;
temp = rp->y + rp->height - 1;
if ((y > temp) && (temp >= clipminy)) clipminy = temp + 1;
}
clipresult = FALSE;
return FALSE;
}
 
 
/* Check the area determined by the specified pair of points against the
* list of clip rectangles. The area will either be totally visible,
* totally visible, or possibly partially visible. This routine updates
* the clip cache rectangle, and returns one of the following values:
* CLIP_VISIBLE The whole rectangle is visible
* CLIP_INVISIBLE The whole rectangle is invisible
* CLIP_PARTIAL The rectangle may be partially visible
* In the case that the area is totally visible, the cursor is removed
* if it overlaps the clip area.
*/
int
GdClipArea(PSD psd,MWCOORD x1, MWCOORD y1, MWCOORD x2, MWCOORD y2)
{
if ((x1 < clipminx) || (x1 > clipmaxx) ||
(y1 < clipminy) || (y1 > clipmaxy))
GdClipPoint(psd, x1, y1);
 
if ((x2 >= clipminx) && (x2 <= clipmaxx) &&
(y2 >= clipminy) && (y2 <= clipmaxy)) {
if (!clipresult) return CLIP_INVISIBLE;
GdCheckCursor(psd, x1, y1, x2, y2);
return CLIP_VISIBLE;
}
return CLIP_PARTIAL;
}
/devclip2.c
0,0 → 1,248
/*
* Copyright (c) 2000 Greg Haerr <greg@censoft.com>
* Copyright (c) 1991 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* DYNAMICREGIONS Device-independent routines to set clipping regions.
*/
#include <stdio.h>
#include "device.h"
 
/* Clip cache rectangle information.
* After calling GdClipPoint, this rectangle is guaranteed to contain the
* specified point (among others), and all points in the rectangle are
* plottable or not according to the value of clipresult.
*/
MWCOORD clipminx; /* minimum x value of cache rectangle */
MWCOORD clipminy; /* minimum y value of cache rectangle */
MWCOORD clipmaxx; /* maximum x value of cache rectangle */
MWCOORD clipmaxy; /* maximum y value of cache rectangle */
 
static MWBOOL clipresult; /* whether clip rectangle is plottable */
MWCLIPREGION *clipregion = NULL;
 
/*
* Set a clip region for future drawing actions.
* Each pixel will be drawn only if lies in one or more of the contained
* clip rectangles. All clip rectangles are modified
* if necessary to lie within the device area. Call only after device
* has been initialized.
*/
void
GdSetClipRegion(PSD psd, MWCLIPREGION *reg)
{
if(clipregion)
GdDestroyRegion(clipregion);
 
if(!reg)
reg = GdAllocRegion();
 
clipregion = reg;
 
 
#if 0
MWRECT rc;
/* Copy the clip table to our own static array, modifying each
* rectangle as necesary to fit within the device area. If the clip
* rectangle lies entirely outside of the device area, then skip it.
*/
while (count-- > 0) {
MWCLIPRECT cr;
MWCLIPRECT *rp = &cr;
 
*rp = *table++;
if (rp->x < 0) {
rp->width += rp->x;
rp->x = 0;
}
if (rp->y < 0) {
rp->height += rp->y;
rp->y = 0;
}
if ((rp->x >= psd->xvirtres) || (rp->width <= 0) ||
(rp->y >= psd->yvirtres) || (rp->height <= 0))
continue;
if (rp->x + rp->width > psd->xvirtres)
rp->width = psd->xvirtres - rp->x;
if (rp->y + rp->height > psd->yvirtres)
rp->height = psd->yvirtres - rp->y;
rc.left = rp->x;
rc.top = rp->y;
rc.right = rp->x+rp->width;
rc.bottom = rp->y+rp->height;
GdUnionRectWithRegion(&rc, clipregion);
}
#endif
 
/* If there were no surviving clip rectangles, then set the clip
* cache to prevent all drawing.
*/
if (clipregion->numRects == 0) {
clipminx = MIN_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return;
}
 
/* There was at least one valid clip rectangle. Default the clip
* cache to be the first clip rectangle.
*/
clipminx = clipregion->rects[0].left;
clipminy = clipregion->rects[0].top;
clipmaxx = clipregion->rects[0].right - 1;
clipmaxy = clipregion->rects[0].bottom - 1;
clipresult = TRUE;
}
 
 
/* Check a point against the list of clip rectangles.
* Returns TRUE if the point is within one or more rectangles and thus
* can be plotted, or FALSE if the point is not within any rectangle and
* thus cannot be plotted. Also remembers the coordinates of a clip cache
* rectangle containing the specified point such that every point in the
* rectangle would give the same result. By examining this clip cache
* rectangle after a call to this routine, the caller can efficiently
* check many nearby points without needing any further calls. If the
* point lies within the cursor, then the cursor is removed.
*/
MWBOOL
GdClipPoint(PSD psd,MWCOORD x,MWCOORD y)
{
int count;
MWRECT *rp;
MWCOORD temp;
 
/* First see whether the point lies within the current clip cache
* rectangle. If so, then we already know the result.
*/
if ((x >= clipminx) && (x <= clipmaxx) &&
(y >= clipminy) && (y <= clipmaxy)) {
if (clipresult) GdCheckCursor(psd, x, y, x, y);
return clipresult;
}
 
/* If the point is outside of the screen area, then it is not
* plottable, and the clip cache rectangle is the whole half-plane
* outside of the screen area.
*/
if (x < 0) {
clipminx = MIN_MWCOORD;
clipmaxx = -1;
clipminy = MIN_MWCOORD;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return FALSE;
}
if (y < 0) {
clipminx = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxy = -1;
clipresult = FALSE;
return FALSE;
}
if (x >= psd->xvirtres) {
clipminx = psd->xvirtres;
clipmaxx = MAX_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return FALSE;
}
if (y >= psd->yvirtres) {
clipminx = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipminy = psd->yvirtres;
clipmaxy = MAX_MWCOORD;
clipresult = FALSE;
return FALSE;
}
 
/* The point is within the screen area. If there are no clip
* rectangles, then the point is plottable and the rectangle is the
* whole screen.
*/
count = clipregion->numRects;
if (count <= 0) {
clipminx = 0;
clipmaxx = psd->xvirtres - 1;
clipminy = 0;
clipmaxy = psd->yvirtres - 1;
clipresult = TRUE;
GdCheckCursor(psd, x, y, x, y);
return TRUE;
}
 
/* We need to scan the list of clip rectangles to calculate a new
* clip cache rectangle containing this point, and the result. First
* see if the point lies within any of the clip rectangles. If so,
* then it is plottable and use that clip rectangle as the cache
* rectangle. This is not necessarily the best result, but works ok
* and is fast.
*/
for (rp = clipregion->rects; count-- > 0; rp++) {
if ((x >= rp->left) && (y >= rp->top) && (x < rp->right)
&& (y < rp->bottom)) {
clipminx = rp->left;
clipminy = rp->top;
clipmaxx = rp->right - 1;
clipmaxy = rp->bottom - 1;
clipresult = TRUE;
GdCheckCursor(psd, x, y, x, y);
return TRUE;
}
}
 
/* The point is not plottable. Scan the clip rectangles again to
* determine a rectangle containing more non-plottable points.
* Simply pick the largest rectangle whose area doesn't contain any
* of the same coordinates as appropriate sides of the clip
* rectangles. This is not necessarily the best result, but works ok
* and is fast.
*/
clipminx = MIN_MWCOORD;
clipminy = MIN_MWCOORD;
clipmaxx = MAX_MWCOORD;
clipmaxy = MAX_MWCOORD;
count = clipregion->numRects;
for (rp = clipregion->rects; count-- > 0; rp++) {
if ((x < rp->left) && (rp->left <= clipmaxx)) clipmaxx = rp->left - 1;
temp = rp->right - 1;
if ((x > temp) && (temp >= clipminx)) clipminx = temp + 1;
if ((y < rp->top) && (rp->top <= clipmaxy)) clipmaxy = rp->top - 1;
temp = rp->bottom - 1;
if ((y > temp) && (temp >= clipminy)) clipminy = temp + 1;
}
clipresult = FALSE;
return FALSE;
}
 
 
/* Check the area determined by the specified pair of points against the
* list of clip rectangles. The area will either be totally visible,
* totally visible, or possibly partially visible. This routine updates
* the clip cache rectangle, and returns one of the following values:
* CLIP_VISIBLE The whole rectangle is visible
* CLIP_INVISIBLE The whole rectangle is invisible
* CLIP_PARTIAL The rectangle may be partially visible
* In the case that the area is totally visible, the cursor is removed
* if it overlaps the clip area.
*/
int
GdClipArea(PSD psd,MWCOORD x1, MWCOORD y1, MWCOORD x2, MWCOORD y2)
{
if ((x1 < clipminx) || (x1 > clipmaxx) ||
(y1 < clipminy) || (y1 > clipmaxy))
GdClipPoint(psd, x1, y1);
 
if ((x2 >= clipminx) && (x2 <= clipmaxx) &&
(y2 >= clipminy) && (y2 <= clipmaxy)) {
if (!clipresult) return CLIP_INVISIBLE;
GdCheckCursor(psd, x1, y1, x2, y2);
return CLIP_VISIBLE;
}
return CLIP_PARTIAL;
}
/selfont.c
0,0 → 1,813
/*
* Copyright (c) 2000 Greg Haerr <greg@censoft.com>
* Copyright (c) 2000 Morten Rolland
*
* Device-independent font selection routines
*/
/*#define NDEBUG*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h> /* toupper*/
#include <string.h>
 
#include "device.h"
#if (UNIX | DOS_DJGPP)
#define strcmpi strcasecmp
#endif
 
#if FONTMAPPER
 
/* entry points*/
int select_font(const PMWLOGFONT plogfont, char *physname);
 
/*
* The following structure, defines and variables are used to administrate
* a set of fonts that are scanned when a font is requested. The set of
* fonts can be configured with the GdClearFontList and GdAddFont functions.
*/
 
struct available_font {
MWLOGFONT lf;
char *foundry;
char *family;
char *fontname;
int fontclass, alias;
struct available_font *next;
};
 
static struct available_font *all_fonts = 0;
 
/*
* Stupid little function to perform a comparison of two strings,
* returning one of STREQ_EXACT, STREQ_CASE or STREQ_NOMATCH.
*/
#define STREQ_EXACT 0
#define STREQ_CASE 1
#define STREQ_NOMATCH 2
 
static int streq(const char *a, const char *b)
{
int rc;
 
for ( rc = STREQ_EXACT; *a != 0; a++, b++ ) {
if ( *a == *b )
continue;
if ( toupper((unsigned char)*a) != toupper((unsigned char)*b) )
return STREQ_NOMATCH;
rc = STREQ_CASE;
}
if ( *b != 0 )
return STREQ_NOMATCH;
return rc;
}
 
/*
* Decode the "foundry" information into a MWLF_CLASS_ value denoting
* which rendering system should be used to render the font.
*/
static int decode_font_class(const char *class)
{
if ( class == NULL )
return 0;
if ( !strcmp("T1",class) )
return MWLF_CLASS_T1LIB;
if ( !strcmp("FT",class) )
return MWLF_CLASS_FREETYPE;
if ( !strcmp("MWF",class) )
return MWLF_CLASS_BUILTIN;
return 0;
}
 
/*
* Try to find a font that matches the foundry and font name
* requested.
*/
void test_font_naming(const char *foundry, const char *fontname,
struct available_font *af,
struct available_font **best, int *goodness)
{
int penalty = 0;
 
if ( foundry != 0 ) {
if ( af->foundry != 0 ) {
switch ( streq(foundry,af->foundry) ) {
case STREQ_EXACT:
break;
case STREQ_CASE:
penalty += 2;
break;
default:
penalty += 8;
break;
}
} else {
penalty += 4;
}
}
 
switch ( streq(fontname,af->fontname) ) {
case STREQ_EXACT:
break;
case STREQ_CASE:
penalty += 1;
break;
default:
penalty += 16;
break;
}
 
if ( *goodness < 0 || penalty < *goodness ) {
*best = af;
*goodness = penalty;
}
}
 
 
/*
* The 'test_font_goodness' function attempts to find how suitable a font is
* compared to a desired one. The desired font is specified by:
*
* foundry (can be NULL), family and the MWLOGFONT
* structure (can be NULL).
*
* If any fonts are configured, one will always be returned from here,
* but the goodness may be very bad. The goodness (or similarity)
* factor is computed by adding up:
*/
 
#define GOODNESS_NO_FONTNAME 1000 /* No matching font-name found*/
#define GOODNESS_WEIGHT_DIFF 1 /* 0-900 for weight difference*/
 
#define GOODNESS_NO_FOUNDRY 100 /* No foundry */
 
#define GOODNESS_FOUNDRY_UNKNOWN 16 /* Foundry unknown */
#define GOODNESS_CASE_FAMILY 8
#define GOODNESS_CASE_FONTNAME 4
#define GOODNESS_CASE_FOUNDRY 2
#define GOODNESS_EXACT_FAMILY 1 /* Matched font family */
 
#define GOODNESS_EXACT_FOUNDRY 0 /* Clean match */
#define GOODNESS_EXACT_FONTNAME 0 /* Clean match */
 
#define GOODNESS_FAMILY_UNKNOWN 3000
#define GOODNESS_NOMATCH_FAMILY 10000
 
#define GOODNESS_EXACT_FONTFAMILY 0
#define GOODNESS_CASE_FONTFAMILY 32
#define GOODNESS_CLOSE_SLANT 128
#define GOODNESS_BAD_SLANT 256
#define GOODNESS_WRONG_SPACING 2048
 
#define GOODNESS_WRONG_SERIFSTYLE 1024
 
#define GOODNESS_WANTED_SMALLCAPS_NOT_AVAILABLE 4096
#define GOODNESS_ONLY_SMALLCAPS_AVAILABLE 8192
 
 
static int find_foundry_penalty(const struct available_font *have,
const char *foundry)
{
if ( foundry == 0 )
return 0;
 
if ( have->foundry == 0 )
return GOODNESS_FOUNDRY_UNKNOWN;
 
switch ( streq(foundry,have->foundry) ) {
case STREQ_EXACT:
return GOODNESS_EXACT_FOUNDRY;
break;
case STREQ_CASE:
return GOODNESS_CASE_FOUNDRY;
break;
default:
return GOODNESS_NO_FOUNDRY;
break;
}
}
 
static int find_family_penalty(const struct available_font *have,
const char *family)
{
if ( family == 0 )
return 0;
 
if ( have->family == 0 )
return GOODNESS_FAMILY_UNKNOWN;
 
switch ( streq(family,have->family) ) {
case STREQ_EXACT:
return GOODNESS_EXACT_FAMILY;
break;
case STREQ_CASE:
return GOODNESS_CASE_FAMILY;
break;
default:
return GOODNESS_NOMATCH_FAMILY;
break;
}
}
 
static int find_fontname_penalty(const struct available_font *have,
const char *fontname)
{
switch ( streq(have->fontname,fontname) ) {
case STREQ_EXACT:
return GOODNESS_EXACT_FONTNAME;
break;
case STREQ_CASE:
return GOODNESS_CASE_FONTNAME;
break;
default:
break;
}
 
/* Test Fontname against font family name */
if ( have->family != 0 ) {
switch ( streq(have->family,fontname) ) {
case STREQ_EXACT:
return GOODNESS_EXACT_FONTFAMILY;
break;
case STREQ_CASE:
return GOODNESS_CASE_FONTFAMILY;
break;
default:
/* No suitable fontname found */
break;
}
}
return GOODNESS_NO_FONTNAME;
}
 
static int find_weight_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
int weight_diff;
 
weight_diff = want->lfWeight - have->lfWeight;
if ( weight_diff < 0 )
weight_diff = -weight_diff;
return weight_diff * GOODNESS_WEIGHT_DIFF;
}
 
static int find_slant_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
/* See if slant is acceptable */
 
if ( !want->lfItalic && !want->lfRoman && !want->lfOblique ) {
/* Try to default to Romans if not specified */
if ( have->lfItalic || have->lfOblique )
return GOODNESS_CLOSE_SLANT;
return 0;
}
 
if ( want->lfItalic && have->lfItalic )
return 0;
 
if ( want->lfRoman && have->lfRoman )
return 0;
 
if ( want->lfOblique && have->lfOblique )
return 0;
 
/* No perfect match for the slant, try "closest" one */
 
if ( want->lfItalic && have->lfOblique )
return GOODNESS_CLOSE_SLANT;
 
if ( want->lfOblique && have->lfItalic )
return GOODNESS_CLOSE_SLANT;
 
return GOODNESS_BAD_SLANT;
}
 
static int find_spacing_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
if ( want->lfProportional && have->lfProportional )
return 0;
if ( want->lfMonospace && have->lfMonospace )
return 0;
if ( want->lfMonospace || want->lfProportional )
return GOODNESS_WRONG_SPACING;
 
return 0; /* No special desires */
}
 
static int find_serif_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
if ( !want->lfSerif && !want->lfSansSerif )
return 0;
if ( want->lfSerif && have->lfSerif )
return 0;
if ( want->lfSansSerif && have->lfSansSerif )
return 0;
 
return GOODNESS_WRONG_SERIFSTYLE;
}
 
static int find_smallcaps_penalty(PMWLOGFONT want, PMWLOGFONT have)
{
if ( !want->lfSmallCaps && !have->lfSmallCaps )
return 0;
if ( want->lfSmallCaps && have->lfSmallCaps )
return 0;
if ( want->lfSmallCaps )
return GOODNESS_WANTED_SMALLCAPS_NOT_AVAILABLE;
return GOODNESS_ONLY_SMALLCAPS_AVAILABLE;
}
 
static void test_font_goodness(const char *foundry, const char *family,
const char *fontname, const PMWLOGFONT lf,
struct available_font *af,
struct available_font **best, int *goodness)
{
int penalty = 0;
 
penalty += find_foundry_penalty(af,foundry);
penalty += find_family_penalty(af,family);
 
/* Test Fontname, but only if there is no family */
if ( family == 0 )
penalty += find_fontname_penalty(af,fontname);
 
if ( lf != 0 ) {
/* Check logical font attributes */
penalty += find_weight_penalty(lf,&af->lf);
penalty += find_slant_penalty(lf,&af->lf);
penalty += find_spacing_penalty(lf,&af->lf);
penalty += find_serif_penalty(lf,&af->lf);
penalty += find_smallcaps_penalty(lf,&af->lf);
}
 
/* See if this font is better than the previous one */
if ( *goodness < 0 || penalty < *goodness ) {
/* Yes, this font is better; change to it */
*best = af;
*goodness = penalty;
}
}
 
static struct available_font *find_suitable_font(const char *foundry,
const char *fontname,
const PMWLOGFONT plogfont)
{
struct available_font *af, *best;
char *family;
int goodness;
 
/*
* Try to find a font that matches the name specified as the
* desired font (and foundry if possible). If we find a
* suitable font, we will use the family name when trying to
* find a font that matches the MWLOGFONT attributes. This
* makes it possible to ask for an Italic version of
* "Times Roman" and the expected thing will happen (get the
* font "Times Italic").
*/
goodness = -1;
for ( af = best = all_fonts; af != 0; af = af->next ) {
test_font_naming(foundry,fontname,af,&best,&goodness);
}
family = 0;
if ( goodness != -1 ) {
/* A font with a name that kind of matched was found,
* make a note of its family. If it has no family, we
* can't make any use of the
*/
family = best->family;
}
 
/*
* Try to find the closest font that matches the font family
* we have established. If no family was found above, all
* fonts will be considered.
*/
goodness = -1;
for ( af = best = all_fonts; af != 0; af = af->next ) {
test_font_goodness(foundry,family,fontname,plogfont,af,
&best,&goodness);
}
return best;
}
 
 
int select_font(const PMWLOGFONT plogfont, char *physname)
{
struct available_font *font;
char fndry[128], *foundry;
const char *fontname;
char *tmp;
int t, comma;
int fontclass = 0;
int found_font = 0;
 
fontname = plogfont->lfFaceName;
 
for ( t=0; t < 20; t++ ) {
/* Only follow 20 aliases deep, assume failure if more ... */
 
/* Find foundry for the current font */
foundry = NULL;
if ( (tmp = index(fontname,',')) != NULL ) {
/*
* We have a font name like T1,c0934345 or
* Adobe,Times (e.g. it includes foundry or
* rendering method). Separate them here.
*/
comma = tmp - fontname;
tmp++;
strncpy(fndry,fontname,comma);
fndry[comma] = '\0';
foundry = fndry;
fontname = tmp;
}
 
fontclass = decode_font_class(foundry);
 
if ( plogfont == NULL && fontclass == 0 )
fontclass = MWLF_CLASS_BUILTIN;
 
if ( fontclass ) {
/* The font is a "physical" font, use it directly */
strcpy(physname,fontname);
return fontclass;
}
 
if ( found_font ) {
/* Oops, should not get here, unless a font definition
* resulted in a non-existent font, e.g. the fontclass
* is unknown.
*/
goto default_font;
}
 
font = find_suitable_font(foundry,fontname,plogfont);
 
if ( font == NULL ) {
goto default_font;
}
 
if ( !font->alias )
found_font = 1;
 
fontname = font->lf.lfFaceName;
}
 
default_font:
 
strcpy(physname, MWFONT_SYSTEM_VAR);
return MWLF_CLASS_BUILTIN;
}
 
/* This function can be used to clear the existing, possibly default list
* of fonts on the system. This is typically done before reading a
* configuration file that defines the available fonts.
*/
void
GdClearFontList(void)
{
struct available_font *font, *next_font;
 
font = all_fonts;
while ( font != 0 ) {
next_font = font->next;
if ( font->foundry != 0 )
free(font->foundry);
if ( font->family != 0 )
free(font->family);
free(font->fontname);
free(font);
font = next_font;
}
 
all_fonts = 0;
}
 
/* This function will add a font to the list of available fonts.
* The physical name is the name as used by the underlying font
* rendering engine.
*/
int
GdAddFont(char *fndry, char *fmly, char *fontname, PMWLOGFONT lf,
unsigned int flags)
{
struct available_font *font, *walk;
int fontclass = 0;
char *physname = lf->lfFaceName;
 
if ( !strncmp(physname,"T1,",3) ) {
#ifdef HAVE_T1LIB_SUPPORT
/* Can handle Type 1 fonts */
physname += 3;
fontclass = MWLF_CLASS_T1LIB;
goto do_font;
#else
/* Can't handle Type 1 fonts */
return -1;
#endif
}
 
if ( !strncmp(physname,"FT,",3) ) {
#if HAVE_FREETYPE_SUPPORT
/* Can handle FreeType fonts */
physname += 3;
fontclass = MWLF_CLASS_FREETYPE;
goto do_font;
#else
/* Can't handle Type 1 fonts */
return -1;
#endif
}
 
if ( !strncmp(physname,"MWF,",4) ) {
/* This is a Microwindows built in font */
physname += 4;
fontclass = MWLF_CLASS_BUILTIN;
goto do_font;
}
 
/* Only aliases does not need to use T1, FT or MWF description */
if ( !(flags & MWLF_FLAGS_ALIAS) )
return -1;
 
do_font:
 
font = malloc(sizeof(*font));
if ( font == 0 )
return -1;
 
font->foundry = 0;
if ( strcmp("-",fndry) ) {
font->foundry = strdup(fndry);
if ( font->foundry == 0 ) {
free(font);
return -1;
}
}
 
font->family = 0;
if ( strcmp("-",fmly) ) {
font->family = strdup(fmly);
if ( font->family == 0 ) {
free(font->foundry);
free(font);
return -1;
}
}
 
font->fontname = strdup(fontname);
if ( font->fontname == 0 ) {
free(font->foundry);
free(font->family);
free(font);
return -1;
}
 
memcpy(&font->lf,lf,sizeof(*lf));
 
printf("Adding font: '%s' '%s' '%s' '%s'\n",font->foundry,
font->family,font->fontname,font->lf.lfFaceName);
 
font->next = 0;
font->alias = (flags & MWLF_FLAGS_ALIAS) ? 1 : 0;
font->fontclass = fontclass;
 
/* Stupid append at end of list code */
if ( all_fonts == 0 ) {
all_fonts = font;
} else {
for ( walk = all_fonts; walk->next != 0; walk = walk->next )
;
walk->next = font;
}
 
return 0;
}
 
/*
* These functions are used to set attributes in a logical font
* structure, called through a table of function pointers.
*/
static void font_set_light(PMWLOGFONT lf)
{ lf->lfWeight = MWLF_WEIGHT_LIGHT; }
static void font_set_regular(PMWLOGFONT lf)
{ lf->lfWeight = MWLF_WEIGHT_REGULAR; }
static void font_set_medium(PMWLOGFONT lf)
{ lf->lfWeight = MWLF_WEIGHT_MEDIUM; }
static void font_set_demibold(PMWLOGFONT lf)
{ lf->lfWeight = MWLF_WEIGHT_DEMIBOLD; }
static void font_set_bold(PMWLOGFONT lf)
{ lf->lfWeight = MWLF_WEIGHT_BOLD; }
static void font_set_black(PMWLOGFONT lf)
{ lf->lfWeight = MWLF_WEIGHT_BLACK; }
 
static void font_set_italic(PMWLOGFONT lf) { lf->lfItalic = 1; }
static void font_set_roman(PMWLOGFONT lf) { lf->lfRoman = 1; }
static void font_set_oblique(PMWLOGFONT lf) { lf->lfOblique = 1; }
 
static void font_set_normal(PMWLOGFONT lf)
{ lf->lfPitch = MWLF_PITCH_NORMAL; }
static void font_set_semicondensed(PMWLOGFONT lf)
{ lf->lfPitch = MWLF_PITCH_SEMICONDENSED; }
static void font_set_condensed(PMWLOGFONT lf)
{ lf->lfPitch = MWLF_PITCH_CONDENSED; }
 
static void font_set_serif(PMWLOGFONT lf) { lf->lfSerif = 1; }
static void font_set_sansserif(PMWLOGFONT lf) { lf->lfSansSerif = 1; }
static void font_set_monospace(PMWLOGFONT lf) { lf->lfMonospace = 1; }
static void font_set_proportional(PMWLOGFONT lf) { lf->lfProportional = 1; }
 
int config_font(char *file, int line, int argc, char *argv[])
{
unsigned int flags = 0;
MWLOGFONT lf;
char tmp[512];
char *p, *q, *fndry, *family, *fontname;
int size, t;
 
static struct {
char *name;
void (*function)(PMWLOGFONT lf);
} attrs[] = {
/* Weight */
{ "Light", font_set_light },
{ "Regular", font_set_regular },
{ "Medium", font_set_medium },
{ "DemiBold", font_set_demibold },
{ "Demibold", font_set_demibold },
{ "Bold", font_set_bold },
{ "Black", font_set_black },
 
/* Slant */
{ "Italic", font_set_italic },
{ "Italics", font_set_italic },
{ "Roman", font_set_roman },
{ "Oblique", font_set_oblique },
 
/* Width */
{ "Normal", font_set_normal },
{ "Semicondensed", font_set_semicondensed },
{ "Condensed", font_set_condensed },
 
/* Class */
{ "Serif", font_set_serif },
{ "Sans-serif", font_set_sansserif },
{ "Monospace", font_set_monospace },
{ "Proportional", font_set_proportional },
 
{ 0, 0 }
};
 
MWLF_Clear(&lf);
 
if ( argc != 6 ) {
fprintf(stderr,"Bad font description %s:%d\n",file,line);
return 1;
}
 
if ( !strcmp("alias",argv[1]) ) {
flags |= MWLF_FLAGS_ALIAS;
fndry = "-";
} else {
fndry = argv[1];
}
 
family = argv[2];
fontname = argv[3];
strcpy(lf.lfFaceName,argv[5]);
p = argv[4];
 
while ( *p != '\0' ) {
/* Parse attributes */
q = strchr(p,',');
if ( q != 0 ) {
size = q - p;
strncpy(tmp,p,size);
tmp[size] = '\0';
p = q + 1;
} else {
strcpy(tmp,p);
p += strlen(tmp);
}
 
for ( t = 0; attrs[t].name != 0; t++ ) {
if ( !strcmp(attrs[t].name,tmp) ) {
attrs[t].function(&lf);
goto next;
}
}
 
fprintf(stderr,"No such font attribute '%s' in %s:%d\n",
tmp,file,line);
return 1;
 
next: ;
}
 
GdAddFont(fndry,family,fontname,&lf,flags);
 
return 0;
}
 
/*
* Handle a single configuration line entery. Arguments as for
* function 'main(int argc, char **argv)' -- argv[0] is name of
* original configuration file. Return negative value for error,
* zero for OK.
*/
 
int config_line(char *file, int line, int argc, char *argv[])
{
if ( !argc )
return 0; /* Empty line */
 
if ( argv[0][0] == '#' )
return 0; /* Comment line */
 
if ( !strcmp("font", argv[0]) )
return config_font(file,line,argc,argv);
 
if ( !strcmp("clear-fonts", argv[0]) ) {
GdClearFontList();
return 0;
}
 
return -1;
}
 
 
/*
* Read (one of) the configuration files.
*/
#define MAXCONFIGLINESIZE 1024
#define MAXCONFIGELEMENTS 64
 
int read_configfile(char *file)
{
FILE *cf;
char buffer[MAXCONFIGLINESIZE+1];
char *args[MAXCONFIGELEMENTS+1];
unsigned char *p;
int argc, s, rc, t, line;
 
if ( (cf = fopen(file,"r")) == 0 ) {
fprintf(stderr,"Unable to read config file '%s'\n",file);
return -1;
}
 
line = 0;
while ( !feof(cf) ) {
if ( fgets(buffer,1000,cf) == 0 )
break;
line++;
s = strlen(buffer) - 1;
while ( s >= 0 && buffer[s] == '\n' )
buffer[s--] = '\0';
p = (unsigned char *)buffer;
argc = 0;
for ( t=0; t < MAXCONFIGELEMENTS; t++ ) {
while ( *p != '\0' && isspace(*p) )
p++;
if ( *p == '\"' ) {
/* Quoted string */
p++;
args[t] = p;
argc++;
while ( *p != '\0' && *p != '\"' )
p++;
if ( *p == '\0' ) {
fprintf(stderr,"Unbalanced quotes in %s:%d\n",
file,line);
break;
}
*p++ = '\0';
} else {
if ( *p == '\0' )
break;
args[t] = p;
argc++;
while ( *p != '\0' && !isspace(*p) )
p++;
*p++ = '\0';
}
}
#if 0
{
int t;
for ( t=0; t < argc; t++ )
printf("#%d: '%s'\n",t,args[t]);
}
#endif
rc = config_line(file, line, argc, args);
if ( rc < 0 )
return rc;
}
 
fclose(cf);
 
return 0;
}
#endif /* FONTMAPPER*/
/devlist.c
0,0 → 1,59
#include <stdio.h>
#include <stdlib.h>
#include "device.h"
/*
* linked list routines
*
* 1/28/98 g haerr
* Copyright (c) 1999 Greg Haerr <greg@censoft.com>
*/
 
void *
GdItemAlloc(unsigned int size)
{
return (void *)calloc(size, 1);
}
 
/* insert at tail of list*/
void
GdListAdd(PMWLISTHEAD pHead,PMWLIST pItem)
{
if( pHead->tail) {
pItem->prev = pHead->tail;
pHead->tail->next = pItem;
} else
pItem->prev = NULL;
pItem->next = NULL;
pHead->tail = pItem;
if( !pHead->head)
pHead->head = pItem;
}
 
/* insert at head of list*/
void
GdListInsert(PMWLISTHEAD pHead,PMWLIST pItem)
{
if( pHead->head) {
pItem->next = pHead->head;
pHead->head->prev = pItem;
} else
pItem->next = NULL;
pItem->prev = NULL;
pHead->head = pItem;
if( !pHead->head)
pHead->head = pItem;
}
 
void
GdListRemove(PMWLISTHEAD pHead,PMWLIST pItem)
{
if( pItem->next)
pItem->next->prev = pItem->prev;
if( pItem->prev)
pItem->prev->next = pItem->next;
if( pHead->head == pItem)
pHead->head = pItem->next;
if( pHead->tail == pItem)
pHead->tail = pItem->prev;
pItem->next = pItem->prev = NULL;
}
/devtimer.c
0,0 → 1,215
/*
* Copyright (c) 2000 Alex Holden <alex@linuxhacker.org>
*
* This file implements the device independant timer functions.
*
* When a part of the server wishes to set a timer, it should call the
* GdAddTimer() function with the timeout parameter set to the number of
* milliseconds before the timer should activate, the callback argument
* set to the function which should be called when the timer expires, and
* the arg argument set to the (void * type) argument which should be supplied
* to the timer handler function. The GdAddTimer() returns a pointer to the
* timer structure * which was created (or NULL if the creation failed for
* some reason). The prototype for the callback function should look like:
* void callbackfn(void *arg);
*
* If a part of the server wishes to destroy a timer before it has expired
* (it is not necessary to do so after the timer has expired, as the timer
* structure is automatically destroyed after the callback function is called),
* it should call the GdDestroyTimer() function with the address of the timer
* structure (which was returned by GdAddTimer()).
*
* If a part of the server wishes to destroy a timer but does not know the
* address of it's timer structure, it can call GdFindTimer() with the
* callback argument as a parameter. The argument must be unique to that
* timer (the address of a structure or function is probably a good choice).
* This function returns the address of the first timer found with that
* argument, or NULL if no matching timer was found.
*
* The main select() loop needs to be called with a timeout obtained using the
* GdGetNextTimeout(). GdGetNextTimeout() is called with the event loop
* timeout in ms, and fills in the specified timeout structure, which should
* be used as the argument to the select() call. The timeout returned by the
* GdGetNextTimeout() call is decided by looking through the timer list for
* the timer with the shortest amount of time remaining, and also at the
* maximum delay parameter. If there are no timers on the timer list and the
* timeout argument is 0, it will return FALSE, otherwise it will return TRUE.
*
* When the main select() loop times out, the GdTimeout() function should be
* called. This will go through the timer list and call the callback functions
* of all timers which have expired, then remove them from the timer list. At
* the same time, you should check the value of the maximum timeout parameter
* to see if it has expired (in which case you can then return to the client
* with a timeout event). This function returns TRUE if the timeout specified in
* the last GdGetNextTimeout() call has expired, or FALSE otherwise.
*
* Note that no guarantees can be made as to when exactly the timer callback
* will be called as it depends on how often the GdTimeout() function is
* called and how long any other timeouts in the queue before you take to
* complete. Especially in the case where the client is linked into the server,
* the client must call into the server on a regular basis, otherwise the
* timers may run late.
*/
 
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "device.h"
 
static MWTIMER *timerlist = NULL;
static struct timeval mainloop_timeout;
static struct timeval current_time;
 
static void calculate_timeval(struct timeval *tv, MWTIMEOUT to);
static signed long time_to_expiry(struct timeval *t);
 
MWTIMER *GdAddTimer(MWTIMEOUT timeout, MWTIMERCB callback, void *arg)
{
MWTIMER *newtimer;
 
if(!(newtimer = malloc(sizeof(MWTIMER)))) return NULL;
 
gettimeofday(&current_time, NULL);
 
if(timerlist) timerlist->prev = newtimer;
 
calculate_timeval(&newtimer->timeout, timeout);
newtimer->callback = callback;
newtimer->arg = arg;
newtimer->next = timerlist;
newtimer->prev = NULL;
newtimer->type = MWTIMER_ONESHOT;
newtimer->period = timeout;
timerlist = newtimer;
 
return newtimer;
}
 
MWTIMER *GdAddPeriodicTimer(MWTIMEOUT timeout, MWTIMERCB callback, void *arg)
{
MWTIMER *newtimer;
 
if(!(newtimer = malloc(sizeof(MWTIMER)))) return NULL;
 
gettimeofday (&current_time, NULL);
if (timerlist) timerlist->prev = newtimer;
calculate_timeval (&newtimer->timeout, timeout);
newtimer->callback = callback;
newtimer->arg = arg;
newtimer->next = timerlist;
newtimer->prev = NULL;
newtimer->type = MWTIMER_PERIODIC;
newtimer->period = timeout;
timerlist = newtimer;
return newtimer;
}
 
void GdDestroyTimer(MWTIMER *timer)
{
if(timer->next) timer->next->prev = timer->prev;
if(timer->prev) timer->prev->next = timer->next;
if(timer == timerlist) {
if(timer->next) timerlist = timer->next;
else timerlist = timer->prev;
}
free(timer);
}
 
MWTIMER *GdFindTimer(void *arg)
{
MWTIMER *t = timerlist;
 
while(t) {
if(t->arg == arg) break;
t = t->next;
}
 
return t;
}
 
MWBOOL GdGetNextTimeout(struct timeval *tv, MWTIMEOUT timeout)
{
signed long i, lowest_timeout;
MWTIMER *t = timerlist;
 
if(!timeout && !timerlist) return FALSE;
 
gettimeofday(&current_time, NULL);
 
if(timeout) {
calculate_timeval(&mainloop_timeout, timeout);
lowest_timeout = time_to_expiry(&mainloop_timeout);
} else {
lowest_timeout = time_to_expiry(&t->timeout);
mainloop_timeout.tv_sec = -1;
t = t->next;
}
 
while(t) {
i = time_to_expiry(&t->timeout);
if(i < lowest_timeout) lowest_timeout = i;
t = t->next;
}
 
if(lowest_timeout <= 0) {
tv->tv_sec = 0;
tv->tv_usec = 0;
} else {
tv->tv_sec = lowest_timeout / 1000;
tv->tv_usec = (lowest_timeout % 1000) * 1000;
}
 
return TRUE;
}
 
MWBOOL GdTimeout(void)
{
MWTIMER *n, *t = timerlist;
 
gettimeofday(&current_time, NULL);
 
while(t) {
n = t->next;
if(time_to_expiry(&t->timeout) <= 0) {
t->callback(t->arg);
if (t->type == MWTIMER_ONESHOT)
{
/* One shot timer, is finished delete it now */
GdDestroyTimer(t);
}
else
{
/* Periodic timer needs to be reset */
calculate_timeval (&t->timeout, t->period);
}
}
t = n;
}
 
if(mainloop_timeout.tv_sec > 0 || mainloop_timeout.tv_usec > 0)
if(time_to_expiry(&mainloop_timeout) <= 0)
return TRUE;
 
return FALSE;
}
 
static void calculate_timeval(struct timeval *tv, MWTIMEOUT to)
{
tv->tv_sec = current_time.tv_sec + (to / 1000);
tv->tv_usec = current_time.tv_usec + ((to % 1000) * 1000);
if(tv->tv_usec > 1000000) {
tv->tv_sec++;
tv->tv_usec -= 1000000;
}
}
 
static signed long time_to_expiry(struct timeval *t)
{
MWTIMEOUT ret = (((t->tv_sec - current_time.tv_sec) * 1000) +
((t->tv_usec - current_time.tv_usec) / 1000));
 
return ret;
}
/devimage.c
0,0 → 1,2460
#define FASTJPEG 1 /* =1 for temp quick jpeg 8bpp display */
#ifdef __ECOS
// Why isn't this handled in the global config file?
#undef HAVE_MMAP
#else
#define HAVE_MMAP 1 /* =1 to use mmap if available */
#endif
 
#if defined(HAVE_FILEIO) /* temp for entire file*/
 
/*
* Copyright (c) 2000, 2001 Greg Haerr <greg@censoft.com>
* Portions Copyright (c) 2000 Martin Jolicoeur <martinj@visuaide.com>
* Portions Copyright (c) 2000 Alex Holden <alex@linuxhacker.org>
* Portions Copyright (c) Independant JPEG group (ijg)
*
* Image load/cache/resize/display routines
*
* GIF, BMP, JPEG, PPM, PGM, PBM, PNG, and XPM formats are supported.
* JHC: Instead of working with a file, we work with a buffer
* (either provided by the user or through mmap). This
* improves speed, and provides a mechanism by which the
* client can send image data directly to the engine
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
#include "device.h"
#include "swap.h"
 
/* cached image list*/
typedef struct {
MWLIST link; /* link list*/
int id; /* image id*/
PMWIMAGEHDR pimage; /* image data*/
PSD psd; /* FIXME shouldn't need this*/
} IMAGEITEM, *PIMAGEITEM;
 
static MWLISTHEAD imagehead; /* global image list*/
static int nextimageid = 1;
 
typedef struct { /* structure for reading images from buffer */
void *start; /* The pointer to the beginning of the buffer */
int offset; /* The current offset within the buffer */
int size; /* The total size of the buffer */
} buffer_t;
 
static void ComputePitch(int bpp, int width, int *pitch, int *bytesperpixel);
#if defined(HAVE_BMP_SUPPORT)
static int LoadBMP(buffer_t *src, PMWIMAGEHDR pimage);
#endif
#if defined(HAVE_JPEG_SUPPORT)
static int LoadJPEG(buffer_t *src, PMWIMAGEHDR pimage, PSD psd,
MWBOOL fast_grayscale);
#endif
#if defined(HAVE_PNG_SUPPORT)
static int LoadPNG(buffer_t *src, PMWIMAGEHDR pimage);
#endif
#if defined(HAVE_GIF_SUPPORT)
static int LoadGIF(buffer_t *src, PMWIMAGEHDR pimage);
#endif
#if defined(HAVE_PNM_SUPPORT)
static int LoadPNM(buffer_t *src, PMWIMAGEHDR pimage);
#endif
#if defined(HAVE_XPM_SUPPORT)
static int LoadXPM(buffer_t *src, PMWIMAGEHDR pimage, PSD psd) ;
#endif
 
/*
* Buffered input functions to replace stdio functions
*/
static void
binit(void *in, int size, buffer_t *dest)
{
dest->start = in;
dest->offset = 0;
dest->size = size;
}
static int
bseek(buffer_t *buffer, int offset, int whence)
{
int new;
 
switch(whence) {
case SEEK_SET:
if (offset >= buffer->size || offset < 0)
return(-1);
buffer->offset = offset;
return(0);
 
case SEEK_CUR:
new = buffer->offset + offset;
if (new >= buffer->size || new < 0)
return(-1);
buffer->offset = new;
return(0);
 
case SEEK_END:
if (offset >= buffer->size || offset > 0)
return(-1);
buffer->offset = (buffer->size - 1) - offset;
return(0);
 
default:
return(-1);
}
}
static int
bread(buffer_t *buffer, void *dest, int size)
{
int copysize = size;
 
if (buffer->offset == buffer->size)
return(0);
 
if (buffer->offset + size > buffer->size)
copysize = (buffer->size - buffer->offset);
 
memcpy((void *)dest, (void *)(buffer->start + buffer->offset),copysize);
 
buffer->offset += copysize;
return(copysize);
}
static int
bgetc(buffer_t *buffer)
{
int ch;
 
if (buffer->offset == buffer->size)
return(EOF);
 
ch = *((unsigned char *) (buffer->start + buffer->offset));
buffer->offset++;
return(ch);
}
static char *
bgets(buffer_t *buffer, char *dest, int size)
{
int i,o;
int copysize = size - 1;
 
if (buffer->offset == buffer->size)
return(0);
 
if (buffer->offset + copysize > buffer->size)
copysize = buffer->size - buffer->offset;
 
for(o=0, i=buffer->offset; i < buffer->offset + copysize; i++, o++) {
dest[o] = *((char *) (buffer->start + i));
if (dest[o] == '\n')
break;
}
 
buffer->offset = i + 1;
dest[o + 1] = 0;
 
return(dest);
}
static int
beof(buffer_t *buffer)
{
return (buffer->offset == buffer->size);
}
/*
* Image decoding and display
* NOTE: This routine and APIs will change in subsequent releases.
*
* Decodes and loads a graphics file, then resizes to width/height,
* then displays image at x, y
* If width/height == -1, don't resize, use image size.
* Clipping is not currently supported, just stretch/shrink to fit.
*
*/
 
static int GdDecodeImage(PSD psd, buffer_t *src, int flags);
 
int
GdLoadImageFromBuffer(PSD psd, void *buffer, int size, int flags)
{
buffer_t src;
binit(buffer, size, &src);
 
return(GdDecodeImage(psd, &src, flags));
}
 
void
GdDrawImageFromBuffer(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width,
MWCOORD height, void *buffer, int size, int flags)
{
int id;
buffer_t src;
 
binit(buffer, size, &src);
id = GdDecodeImage(psd, &src, flags);
 
if (id) {
GdDrawImageToFit(psd, x, y, width, height, id);
GdFreeImage(id);
}
}
 
void
GdDrawImageFromFile(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width,
MWCOORD height, char *path, int flags)
{
int id;
 
id = GdLoadImageFromFile(psd, path, flags);
if (id) {
GdDrawImageToFit(psd, x, y, width, height, id);
GdFreeImage(id);
}
}
 
int
GdLoadImageFromFile(PSD psd, char *path, int flags)
{
int fd, id;
struct stat s;
void *buffer = 0;
buffer_t src;
fd = open(path, O_RDONLY);
if (fd <= 0) {
EPRINTF("GdLoadImageFromFile: can't open image: %s\n", path);
return(0);
}
fstat(fd, &s);
 
#ifdef HAVE_MMAP
buffer = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
 
if (!buffer) {
EPRINTF("GdLoadImageFromFile: Couldn't map image %s\n", path);
close(fd);
return(0);
}
#else
buffer = malloc(s.st_size);
if (!buffer) {
EPRINTF("GdLoadImageFromFile: Couldn't load image %s\n", path);
close(fd);
return(0);
}
if (read(fd, buffer, s.st_size) != s.st_size) {
EPRINTF("GdLoadImageFromFile: Couldn't load image %s\n", path);
close(fd);
return(0);
}
#endif
 
binit(buffer, s.st_size, &src);
id = GdDecodeImage(psd, &src, flags);
#ifdef HAVE_MMAP
munmap(buffer, s.st_size);
#else
free(buffer);
#endif
 
close(fd);
return(id);
}
 
static int
GdDecodeImage(PSD psd, buffer_t * src, int flags)
{
int loadOK = 0;
PMWIMAGEHDR pimage;
PIMAGEITEM pItem;
 
/* allocate image struct*/
pimage = (PMWIMAGEHDR)malloc(sizeof(MWIMAGEHDR));
if(!pimage) {
return 0;
}
pimage->imagebits = NULL;
pimage->palette = NULL;
pimage->transcolor = -1L;
 
#if defined(HAVE_BMP_SUPPORT)
if (loadOK == 0)
loadOK = LoadBMP(src, pimage);
#endif
#if defined(HAVE_GIF_SUPPORT)
if (loadOK == 0)
loadOK = LoadGIF(src, pimage);
#endif
#if defined(HAVE_JPEG_SUPPORT)
if (loadOK == 0)
loadOK = LoadJPEG(src, pimage, psd, flags);
#endif
#if defined(HAVE_PNG_SUPPORT)
if (loadOK == 0)
loadOK = LoadPNG(src, pimage);
#endif
#if defined(HAVE_PNM_SUPPORT)
if(loadOK == 0)
loadOK = LoadPNM(src, pimage);
#endif
#if defined(HAVE_XPM_SUPPORT)
if (loadOK == 0)
loadOK = LoadXPM(src, pimage, psd);
#endif
 
if (loadOK == 0) {
EPRINTF("GdLoadImageFromFile: unknown image type:\n");
// EPRINTF("GdLoadImageFromFile: unknown image type: \n", path);
goto err; /* image loading error*/
}
if (loadOK != 1)
goto err; /* image loading error*/
 
/* allocate id*/
pItem = GdItemNew(IMAGEITEM);
if (!pItem)
goto err;
pItem->id = nextimageid++;
pItem->pimage = pimage;
pItem->psd = psd;
GdListAdd(&imagehead, &pItem->link);
 
return pItem->id;
 
err:
free(pimage);
return 0; /* image loading error*/
}
 
static PIMAGEITEM
findimage(int id)
{
PMWLIST p;
PIMAGEITEM pimagelist;
 
for (p=imagehead.head; p; p=p->next) {
pimagelist = GdItemAddr(p, IMAGEITEM, link);
if (pimagelist->id == id)
return pimagelist;
}
return NULL;
}
 
void
GdDrawImageToFit(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height,
int id)
{
PIMAGEITEM pItem;
PMWIMAGEHDR pimage;
 
pItem = findimage(id);
if (!pItem)
return;
pimage = pItem->pimage;
 
/*
* Display image, possibly stretch/shrink to resize
*/
if (height < 0)
height = pimage->height;
if (width < 0)
width = pimage->width;
 
if (height != pimage->height || width != pimage->width) {
MWCLIPRECT rcDst;
MWIMAGEHDR image2;
 
/* create similar image, different width/height*/
 
image2.width = width;
image2.height = height;
image2.planes = pimage->planes;
image2.bpp = pimage->bpp;
ComputePitch(pimage->bpp, width, &image2.pitch,
&image2.bytesperpixel);
image2.compression = pimage->compression;
image2.palsize = pimage->palsize;
image2.palette = pimage->palette; /* already allocated*/
image2.transcolor = pimage->transcolor;
if( (image2.imagebits = malloc(image2.pitch*height)) == NULL) {
EPRINTF("GdDrawImageToFit: no memory\n");
return;
}
 
rcDst.x = 0;
rcDst.y = 0;
rcDst.width = width;
rcDst.height = height;
 
/* Stretch full soruce to destination rectangle*/
GdStretchImage(pimage, NULL, &image2, &rcDst);
GdDrawImage(psd, x, y, &image2);
free(image2.imagebits);
} else
GdDrawImage(psd, x, y, pimage);
}
 
void
GdFreeImage(int id)
{
PIMAGEITEM pItem;
PMWIMAGEHDR pimage;
 
pItem = findimage(id);
if (pItem) {
GdListRemove(&imagehead, &pItem->link);
pimage = pItem->pimage;
 
/* delete image bits*/
if(pimage->imagebits)
free(pimage->imagebits);
if(pimage->palette)
free(pimage->palette);
 
free(pimage);
GdItemFree(pItem);
}
}
 
MWBOOL
GdGetImageInfo(int id, PMWIMAGEINFO pii)
{
PMWIMAGEHDR pimage;
PIMAGEITEM pItem;
int i;
 
pItem = findimage(id);
if (!pItem) {
memset(pii, 0, sizeof(*pii));
return FALSE;
}
pimage = pItem->pimage;
pii->id = id;
pii->width = pimage->width;
pii->height = pimage->height;
pii->planes = pimage->planes;
pii->bpp = pimage->bpp;
pii->pitch = pimage->pitch;
pii->bytesperpixel = pimage->bytesperpixel;
pii->compression = pimage->compression;
pii->palsize = pimage->palsize;
if (pimage->palsize) {
if (pimage->palette) {
for (i=0; i<pimage->palsize; ++i)
pii->palette[i] = pimage->palette[i];
} else {
/* FIXME handle jpeg's without palette*/
GdGetPalette(pItem->psd, 0, pimage->palsize,
pii->palette);
}
}
return TRUE;
}
 
#define PIX2BYTES(n) (((n)+7)/8)
/*
* compute image line size and bytes per pixel
* from bits per pixel and width
*/
static void
ComputePitch(int bpp, int width, int *pitch, int *bytesperpixel)
{
int linesize;
int bytespp = 1;
 
if(bpp == 1)
linesize = PIX2BYTES(width);
else if(bpp <= 4)
linesize = PIX2BYTES(width<<2);
else if(bpp <= 8)
linesize = width;
else if(bpp <= 16) {
linesize = width * 2;
bytespp = 2;
} else if(bpp <= 24) {
linesize = width * 3;
bytespp = 3;
} else {
linesize = width * 4;
bytespp = 4;
}
 
/* rows are DWORD right aligned*/
*pitch = (linesize + 3) & ~3;
*bytesperpixel = bytespp;
}
 
/*
* StretchImage - Resize an image
*
* Major portions from SDL Simple DirectMedia Layer by Sam Lantinga
* Copyright (C) 1997, 1998, 1999, 2000 Sam Lantinga <slouken@devolution.com>
* This a stretch blit implementation based on ideas given to me by
* Tomasz Cejner - thanks! :)
*/
/*
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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
 
#define DEFINE_COPY_ROW(name, type) \
static void name(type *src, int src_w, type *dst, int dst_w) \
{ \
int i; \
int pos, inc; \
type pixel = 0; \
\
pos = 0x10000; \
inc = (src_w << 16) / dst_w; \
for ( i=dst_w; i>0; --i ) { \
while ( pos >= 0x10000L ) { \
pixel = *src++; \
pos -= 0x10000L; \
} \
*dst++ = pixel; \
pos += inc; \
} \
}
 
DEFINE_COPY_ROW(copy_row1, unsigned char)
DEFINE_COPY_ROW(copy_row2, unsigned short)
DEFINE_COPY_ROW(copy_row4, unsigned long)
 
static void copy_row3(unsigned char *src, int src_w, unsigned char *dst,
int dst_w)
{
int i;
int pos, inc;
unsigned char r = 0;
unsigned char g = 0;
unsigned char b = 0;
 
pos = 0x10000;
inc = (src_w << 16) / dst_w;
for ( i=dst_w; i>0; --i ) {
while ( pos >= 0x10000L ) {
b = *src++;
g = *src++;
r = *src++;
pos -= 0x10000L;
}
*dst++ = b;
*dst++ = g;
*dst++ = r;
pos += inc;
}
}
 
/* Perform a stretch blit between two image structs of the same format.*/
void
GdStretchImage(PMWIMAGEHDR src, MWCLIPRECT *srcrect, PMWIMAGEHDR dst,
MWCLIPRECT *dstrect)
{
int pos, inc;
int bytesperpixel;
int dst_maxrow;
int src_row, dst_row;
MWUCHAR *srcp = 0;
MWUCHAR *dstp;
MWCLIPRECT full_src;
MWCLIPRECT full_dst;
 
if ( src->bytesperpixel != dst->bytesperpixel ) {
EPRINTF("GdStretchImage: bytesperpixel mismatch\n");
return;
}
 
/* Verify the blit rectangles */
if ( srcrect ) {
if ( (srcrect->x < 0) || (srcrect->y < 0) ||
((srcrect->x+srcrect->width) > src->width) ||
((srcrect->y+srcrect->height) > src->height) ) {
EPRINTF("GdStretchImage: invalid source rect\n");
return;
}
} else {
full_src.x = 0;
full_src.y = 0;
full_src.width = src->width;
full_src.height = src->height;
srcrect = &full_src;
}
if ( dstrect ) {
/* if stretching to nothing, return*/
if (!dstrect->width || !dstrect->height)
return;
if ( (dstrect->x < 0) || (dstrect->y < 0) ||
((dstrect->x+dstrect->width) > dst->width) ||
((dstrect->y+dstrect->height) > dst->height) ) {
EPRINTF("GdStretchImage: invalid dest rect\n");
return;
}
} else {
full_dst.x = 0;
full_dst.y = 0;
full_dst.width = dst->width;
full_dst.height = dst->height;
dstrect = &full_dst;
}
 
/* Set up the data... */
pos = 0x10000;
inc = (srcrect->height << 16) / dstrect->height;
src_row = srcrect->y;
dst_row = dstrect->y;
bytesperpixel = dst->bytesperpixel;
 
/* Perform the stretch blit */
for ( dst_maxrow = dst_row+dstrect->height; dst_row<dst_maxrow;
++dst_row ) {
dstp = (MWUCHAR *)dst->imagebits + (dst_row*dst->pitch)
+ (dstrect->x*bytesperpixel);
while ( pos >= 0x10000L ) {
srcp = (MWUCHAR *)src->imagebits + (src_row*src->pitch)
+ (srcrect->x*bytesperpixel);
++src_row;
pos -= 0x10000L;
}
 
switch (bytesperpixel) {
case 1:
copy_row1(srcp, srcrect->width, dstp, dstrect->width);
break;
case 2:
copy_row2((unsigned short *)srcp, srcrect->width,
(unsigned short *)dstp, dstrect->width);
break;
case 3:
copy_row3(srcp, srcrect->width, dstp, dstrect->width);
break;
case 4:
copy_row4((unsigned long *)srcp, srcrect->width,
(unsigned long *)dstp, dstrect->width);
break;
}
 
pos += inc;
}
}
 
#if defined(HAVE_FILEIO) && defined(HAVE_JPEG_SUPPORT)
#include "jpeglib.h"
/*
* JPEG decompression routine
*
* JPEG support must be enabled (see README.txt in contrib/jpeg)
*
* SOME FINE POINTS: (from libjpeg)
* In the below code, we ignored the return value of jpeg_read_scanlines,
* which is the number of scanlines actually read. We could get away with
* this because we asked for only one line at a time and we weren't using
* a suspending data source. See libjpeg.doc for more info.
*
* We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
* we should have done it beforehand to ensure that the space would be
* counted against the JPEG max_memory setting. In some systems the above
* code would risk an out-of-memory error. However, in general we don't
* know the output image dimensions before jpeg_start_decompress(), unless we
* call jpeg_calc_output_dimensions(). See libjpeg.doc for more about this.
*
* Scanlines are returned in the same order as they appear in the JPEG file,
* which is standardly top-to-bottom. If you must emit data bottom-to-top,
* you can use one of the virtual arrays provided by the JPEG memory manager
* to invert the data. See wrbmp.c for an example.
*
* As with compression, some operating modes may require temporary files.
* On some systems you may need to set up a signal handler to ensure that
* temporary files are deleted if the program is interrupted. See libjpeg.doc.
*/
static int
LoadJPEG(buffer_t *src, PMWIMAGEHDR pimage, PSD psd, MWBOOL fast_grayscale)
{
int i;
int ret = 2; /* image load error*/
unsigned char magic[4];
 
#if FASTJPEG
extern MWPALENTRY mwstdpal8[256];
#else
MWPALENTRY palette[256];
#endif
 
struct jpeg_source_mgr smgr;
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
static void init_source(j_compress_ptr dinfo) {
smgr.next_input_byte = src->start;
smgr.bytes_in_buffer = src->size;
}
 
static void fill_input_buffer(j_compress_ptr dinfo) {
return;
}
 
static void skip_input_data(j_compress_ptr dinfo, int num_bytes) {
if (num_bytes >= src->size) return;
smgr.next_input_byte += num_bytes;
smgr.bytes_in_buffer -= num_bytes;
}
 
static int resync_to_restart(j_compress_ptr dinfo, int desired ) {
return(jpeg_resync_to_restart(dinfo, desired));
}
 
static void term_source(j_compress_ptr dinfo) {
return;
}
/* first determine if JPEG file since decoder will error if not*/
bseek(src, 0, SEEK_SET);
if (!bread(src, magic, 2))
return(0);
if (magic[0] != 0xFF || magic[1] != 0xD8)
return(0); /* not JPEG image*/
bread(src, magic, 4);
bread(src, magic, 4);
if (strncmp(magic, "JFIF", 4) != 0)
return(0); /* not JPEG image*/
bread(src, 0, SEEK_SET);
pimage->imagebits = NULL;
pimage->palette = NULL;
/* Step 1: allocate and initialize JPEG decompression object */
/* We set up the normal JPEG error routines. */
cinfo.err = jpeg_std_error (&jerr);
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress (&cinfo);
/* Step 2: Setup the source manager */
 
smgr.init_source = init_source;
smgr.fill_input_buffer = fill_input_buffer;
smgr.skip_input_data = skip_input_data;
smgr.resync_to_restart = resync_to_restart;
smgr.term_source = term_source;
cinfo.src = &smgr;
 
/* Step 2: specify data source (eg, a file) */
/* jpeg_stdio_src (&cinfo, fp); */
/* Step 3: read file parameters with jpeg_read_header() */
jpeg_read_header (&cinfo, TRUE);
 
/* Step 4: set parameters for decompression */
cinfo.out_color_space = fast_grayscale? JCS_GRAYSCALE: JCS_RGB;
cinfo.quantize_colors = FALSE;
 
#if FASTJPEG
goto fastjpeg;
#endif
if (!fast_grayscale)
{
if (psd->pixtype == MWPF_PALETTE)
{
fastjpeg:
cinfo.quantize_colors = TRUE;
 
#if FASTJPEG
cinfo.actual_number_of_colors = 256;
#else
/* Get system palette */
cinfo.actual_number_of_colors =
GdGetPalette(psd, 0, psd->ncolors, palette);
#endif
/* Allocate jpeg colormap space */
cinfo.colormap = (*cinfo.mem->alloc_sarray)
((j_common_ptr) &cinfo, JPOOL_IMAGE,
(JDIMENSION)cinfo.actual_number_of_colors,
(JDIMENSION)3);
 
/* Set colormap from system palette */
for(i = 0; i < cinfo.actual_number_of_colors; ++i)
{
#if FASTJPEG
cinfo.colormap[0][i] = mwstdpal8[i].r;
cinfo.colormap[1][i] = mwstdpal8[i].g;
cinfo.colormap[2][i] = mwstdpal8[i].b;
#else
cinfo.colormap[0][i] = palette[i].r;
cinfo.colormap[1][i] = palette[i].g;
cinfo.colormap[2][i] = palette[i].b;
#endif
}
}
}
else
{
/* Grayscale output asked */
cinfo.quantize_colors = TRUE;
cinfo.out_color_space = JCS_GRAYSCALE;
cinfo.desired_number_of_colors = psd->ncolors;
}
jpeg_calc_output_dimensions(&cinfo);
 
pimage->width = cinfo.output_width;
pimage->height = cinfo.output_height;
pimage->planes = 1;
#if FASTJPEG
pimage->bpp = 8;
#else
pimage->bpp = (fast_grayscale || psd->pixtype == MWPF_PALETTE)?
8: cinfo.output_components*8;
#endif
ComputePitch(pimage->bpp, pimage->width, &pimage->pitch,
&pimage->bytesperpixel);
pimage->compression = MWIMAGE_RGB; /* RGB not BGR order*/
pimage->palsize = (pimage->bpp == 8)? 256: 0;
pimage->imagebits = malloc(pimage->pitch * pimage->height);
if(!pimage->imagebits)
goto err;
pimage->palette = NULL;
#if FASTJPEG
if(pimage->bpp == 8) {
pimage->palette = malloc(256*sizeof(MWPALENTRY));
if(!pimage->palette)
goto err;
for (i=0; i<256; ++i)
pimage->palette[i] = mwstdpal8[i];
}
#endif
 
/* Step 5: Start decompressor */
jpeg_start_decompress (&cinfo);
 
/* Step 6: while (scan lines remain to be read) */
while(cinfo.output_scanline < cinfo.output_height) {
JSAMPROW rowptr[1];
rowptr[0] = (JSAMPROW)(pimage->imagebits +
cinfo.output_scanline * pimage->pitch);
jpeg_read_scanlines (&cinfo, rowptr, 1);
}
ret = 1;
 
err:
/* Step 7: Finish decompression */
jpeg_finish_decompress (&cinfo);
 
/* Step 8: Release JPEG decompression object */
jpeg_destroy_decompress (&cinfo);
 
/* May want to check to see whether any corrupt-data
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
*/
return ret;
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_JPEG_SUPPORT)*/
 
#if defined(HAVE_FILEIO) && defined(HAVE_PNG_SUPPORT)
#include "png.h"
/* png_jmpbuf() macro is not defined prior to libpng-1.0.6*/
#ifndef png_jmpbuf
#define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
#endif
/*
* Load a PNG file.
* Currently for simplicity we get the PNG library to convert the file to
* 24 bit RGB format with no alpha channel information even if we could
* potentially store the image more efficiently by taking note of the image
* type and depth and acting accordingly. Similarly, > 8 bits per channel,
* gamma correction, etc. are not supported.
*/
static int
LoadPNG(buffer_t * src, PMWIMAGEHDR pimage)
{
unsigned char hdr[8], **rows;
png_structp state;
png_infop pnginfo;
png_uint_32 width, height;
int bit_depth, colourtype, i;
 
bseek(src, 0L, 0);
 
if(bread(src, hdr, 8) != 8) return 0;
 
if(png_sig_cmp(hdr, 0, 8)) return 0;
 
if(!(state = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
NULL, NULL))) goto nomem;
 
if(!(pnginfo = png_create_info_struct(state))) {
png_destroy_read_struct(&state, NULL, NULL);
goto nomem;
}
 
if(setjmp(png_jmpbuf(state))) {
png_destroy_read_struct(&state, &pnginfo, NULL);
return 2;
}
 
png_init_io(state, fp);
png_set_sig_bytes(state, 8);
png_read_info(state, pnginfo);
png_get_IHDR(state, pnginfo, &width, &height, &bit_depth, &colourtype,
NULL, NULL, NULL);
 
pimage->width = width;
pimage->height = height;
pimage->bpp = 24;
pimage->planes = 1;
ComputePitch(pimage->bpp, pimage->width, &pimage->pitch,
&pimage->bytesperpixel);
pimage->compression = MWIMAGE_RGB;
if(!(pimage->imagebits = malloc(pimage->pitch * pimage->height))) {
png_destroy_read_struct(&state, &pnginfo, NULL);
goto nomem;
}
if(!(rows = malloc(pimage->height * sizeof(unsigned char *)))) {
png_destroy_read_struct(&state, &pnginfo, NULL);
goto nomem;
}
for(i = 0; i < pimage->height; i++)
rows[i] = pimage->imagebits + (i * pimage->pitch);
 
png_set_expand(state);
if(bit_depth == 16)
png_set_strip_16(state);
if(colourtype & PNG_COLOR_MASK_ALPHA)
png_set_strip_alpha(state);
if(colourtype == PNG_COLOR_TYPE_GRAY ||
colourtype == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(state);
 
png_read_image(state, rows);
 
png_read_end(state, NULL);
free(rows);
png_destroy_read_struct(&state, &pnginfo, NULL);
 
return 1;
 
nomem:
EPRINTF("LoadPNG: Out of memory\n");
return 2;
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_PNG_SUPPORT)*/
 
#if defined(HAVE_FILEIO) && defined(HAVE_BMP_SUPPORT)
/* BMP stuff*/
#define BI_RGB 0L
#define BI_RLE8 1L
#define BI_RLE4 2L
#define BI_BITFIELDS 3L
 
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
 
typedef struct {
/* BITMAPFILEHEADER*/
BYTE bfType[2];
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BMPFILEHEAD;
 
#define FILEHEADSIZE 14
 
/* windows style*/
typedef struct {
/* BITMAPINFOHEADER*/
DWORD BiSize;
DWORD BiWidth;
DWORD BiHeight;
WORD BiPlanes;
WORD BiBitCount;
DWORD BiCompression;
DWORD BiSizeImage;
DWORD BiXpelsPerMeter;
DWORD BiYpelsPerMeter;
DWORD BiClrUsed;
DWORD BiClrImportant;
} BMPINFOHEAD;
 
#define INFOHEADSIZE 40
 
/* os/2 style*/
typedef struct {
/* BITMAPCOREHEADER*/
DWORD bcSize;
WORD bcWidth;
WORD bcHeight;
WORD bcPlanes;
WORD bcBitCount;
} BMPCOREHEAD;
 
#define COREHEADSIZE 12
 
static int DecodeRLE8(MWUCHAR *buf, buffer_t *src);
static int DecodeRLE4(MWUCHAR *buf, buffer_t *src);
static void put4(int b);
 
/*
* BMP decoding routine
*/
 
/* Changed by JHC to allow a buffer instead of a filename */
 
static int
LoadBMP(buffer_t *src, PMWIMAGEHDR pimage)
{
int h, i, compression;
int headsize;
MWUCHAR *imagebits;
BMPFILEHEAD bmpf;
BMPINFOHEAD bmpi;
BMPCOREHEAD bmpc;
MWUCHAR headbuffer[INFOHEADSIZE];
 
bseek(src, 0, SEEK_SET);
 
pimage->imagebits = NULL;
pimage->palette = NULL;
 
/* read BMP file header*/
if (bread(src, &headbuffer, FILEHEADSIZE) != FILEHEADSIZE)
return(0);
 
bmpf.bfType[0] = headbuffer[0];
bmpf.bfType[1] = headbuffer[1];
 
/* Is it really a bmp file ? */
if (*(WORD*)&bmpf.bfType[0] != wswap(0x4D42)) /* 'BM' */
return 0; /* not bmp image*/
 
/*bmpf.bfSize = dwswap(dwread(&headbuffer[2]));*/
bmpf.bfOffBits = dwswap(dwread(&headbuffer[10]));
 
/* Read remaining header size */
if (bread(src,&headsize,sizeof(DWORD)) != sizeof(DWORD))
return 0; /* not bmp image*/
headsize = dwswap(headsize);
 
/* might be windows or os/2 header */
if(headsize == COREHEADSIZE) {
 
/* read os/2 header */
if(bread(src, &headbuffer, COREHEADSIZE-sizeof(DWORD)) !=
COREHEADSIZE-sizeof(DWORD))
return 0; /* not bmp image*/
 
/* Get data */
bmpc.bcWidth = wswap(*(WORD*)&headbuffer[0]);
bmpc.bcHeight = wswap(*(WORD*)&headbuffer[2]);
bmpc.bcPlanes = wswap(*(WORD*)&headbuffer[4]);
bmpc.bcBitCount = wswap(*(WORD*)&headbuffer[6]);
pimage->width = (int)bmpc.bcWidth;
pimage->height = (int)bmpc.bcHeight;
pimage->bpp = bmpc.bcBitCount;
if (pimage->bpp <= 8)
pimage->palsize = 1 << pimage->bpp;
else pimage->palsize = 0;
compression = BI_RGB;
} else {
/* read windows header */
if(bread(src, &headbuffer, INFOHEADSIZE-sizeof(DWORD)) !=
INFOHEADSIZE-sizeof(DWORD))
return 0; /* not bmp image*/
 
/* Get data */
bmpi.BiWidth = dwswap(*(DWORD*)&headbuffer[0]);
bmpi.BiHeight = dwswap(*(DWORD*)&headbuffer[4]);
bmpi.BiPlanes = wswap(*(WORD*)&headbuffer[8]);
bmpi.BiBitCount = wswap(*(WORD*)&headbuffer[10]);
bmpi.BiCompression = dwswap(*(DWORD*)&headbuffer[12]);
bmpi.BiSizeImage = dwswap(*(DWORD*)&headbuffer[16]);
bmpi.BiXpelsPerMeter = dwswap(*(DWORD*)&headbuffer[20]);
bmpi.BiYpelsPerMeter = dwswap(*(DWORD*)&headbuffer[24]);
bmpi.BiClrUsed = dwswap(*(DWORD*)&headbuffer[28]);
bmpi.BiClrImportant = dwswap(*(DWORD*)&headbuffer[32]);
 
pimage->width = (int)bmpi.BiWidth;
pimage->height = (int)bmpi.BiHeight;
pimage->bpp = bmpi.BiBitCount;
pimage->palsize = (int)bmpi.BiClrUsed;
if (pimage->palsize > 256)
pimage->palsize = 0;
else if(pimage->palsize == 0 && pimage->bpp <= 8)
pimage->palsize = 1 << pimage->bpp;
compression = bmpi.BiCompression;
}
pimage->compression = MWIMAGE_BGR; /* right side up, BGR order*/
pimage->planes = 1;
 
/* currently only 1, 4, 8 and 24 bpp bitmaps*/
if(pimage->bpp > 8 && pimage->bpp != 24) {
EPRINTF("LoadBMP: image bpp not 1, 4, 8 or 24\n");
return 2; /* image loading error*/
}
 
/* compute byte line size and bytes per pixel*/
ComputePitch(pimage->bpp, pimage->width, &pimage->pitch,
&pimage->bytesperpixel);
 
/* Allocate image */
if( (pimage->imagebits = malloc(pimage->pitch*pimage->height)) == NULL)
goto err;
if( (pimage->palette = malloc(256*sizeof(MWPALENTRY))) == NULL)
goto err;
 
/* get colormap*/
if(pimage->bpp <= 8) {
for(i=0; i<pimage->palsize; i++) {
pimage->palette[i].b = bgetc(src);
pimage->palette[i].g = bgetc(src);
pimage->palette[i].r = bgetc(src);
if(headsize != COREHEADSIZE)
bgetc(src);
}
}
 
/* decode image data*/
bseek(src, bmpf.bfOffBits, SEEK_SET);
 
h = pimage->height;
/* For every row ... */
while (--h >= 0) {
/* turn image rightside up*/
imagebits = pimage->imagebits + h*pimage->pitch;
 
/* Get row data from file */
if(compression == BI_RLE8) {
if(!DecodeRLE8(imagebits, src))
break;
} else if(compression == BI_RLE4) {
if(!DecodeRLE4(imagebits, src))
break;
} else {
if(bread(src, imagebits, pimage->pitch) !=
pimage->pitch)
goto err;
}
}
return 1; /* bmp image ok*/
err:
EPRINTF("LoadBMP: image loading error\n");
if(pimage->imagebits)
free(pimage->imagebits);
if(pimage->palette)
free(pimage->palette);
return 2; /* bmp image error*/
}
 
/*
* Decode one line of RLE8, return 0 when done with all bitmap data
*/
static int
DecodeRLE8(MWUCHAR *buf, buffer_t *src)
{
int c, n;
MWUCHAR * p = buf;
 
for( ;;) {
switch( n = bgetc(src)) {
case EOF:
return( 0);
case 0: /* 0 = escape*/
switch( n = bgetc(src)) {
case 0: /* 0 0 = end of current scan line*/
return( 1);
case 1: /* 0 1 = end of data*/
return( 1);
case 2: /* 0 2 xx yy delta mode NOT SUPPORTED*/
(void)bgetc(src);
(void)bgetc(src);
continue;
default: /* 0 3..255 xx nn uncompressed data*/
for( c=0; c<n; c++)
*p++ = bgetc(src);
if( n & 1)
(void)bgetc(src);
continue;
}
default:
c = bgetc(src);
while( n--)
*p++ = c;
continue;
}
}
}
 
/*
* Decode one line of RLE4, return 0 when done with all bitmap data
*/
static MWUCHAR *p;
static int once;
 
static void
put4(int b)
{
static int last;
 
last = (last << 4) | b;
if( ++once == 2) {
*p++ = last;
once = 0;
}
}
static int
DecodeRLE4(MWUCHAR *buf, buffer_t *src)
{
int c, n, c1, c2;
 
p = buf;
once = 0;
c1 = 0;
 
for( ;;) {
switch( n = bgetc(src)) {
case EOF:
return( 0);
case 0: /* 0 = escape*/
switch( n = bgetc(src)) {
case 0: /* 0 0 = end of current scan line*/
if( once)
put4( 0);
return( 1);
case 1: /* 0 1 = end of data*/
if( once)
put4( 0);
return( 1);
case 2: /* 0 2 xx yy delta mode NOT SUPPORTED*/
(void)bgetc(src);
(void)bgetc(src);
continue;
default: /* 0 3..255 xx nn uncompressed data*/
c2 = (n+3) & ~3;
for( c=0; c<c2; c++) {
if( (c & 1) == 0)
c1 = bgetc(src);
if( c < n)
put4( (c1 >> 4) & 0x0f);
c1 <<= 4;
}
continue;
}
default:
c = bgetc(src);
c1 = (c >> 4) & 0x0f;
c2 = c & 0x0f;
for( c=0; c<n; c++)
put4( (c&1)? c2: c1);
continue;
}
}
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_BMP_SUPPORT)*/
 
#if 0
void print_image(PMWIMAGEHDR image)
{
int i;
 
DPRINTF("Image:\n\n");
DPRINTF("height: %d\n", image->height);
DPRINTF("width: %d\n", image->width);
DPRINTF("planes: %d\n", image->planes);
DPRINTF("bpp: %d\n", image->bpp);
DPRINTF("compression: %d\n", image->compression);
DPRINTF("palsize: %d\n", image->palsize);
 
for (i=0;i<image->palsize;i++)
DPRINTF("palette: %d, %d, %d\n", image->palette[i].r,
image->palette[i].g, image->palette[i].b);
 
for(i=0;i<(image->width*image->height);i++)
DPRINTF("imagebits: %d\n", image->imagebits[i]);
}
#endif
 
#if defined(HAVE_FILEIO) && defined(HAVE_GIF_SUPPORT)
/* Code for GIF decoding has been adapted from XPaint: */
/* +-------------------------------------------------------------------+ */
/* | Copyright 1990, 1991, 1993 David Koblas. | */
/* | Copyright 1996 Torsten Martinsen. | */
/* | Permission to use, copy, modify, and distribute this software | */
/* | and its documentation for any purpose and without fee is hereby | */
/* | granted, provided that the above copyright notice appear in all | */
/* | copies and that both that copyright notice and this permission | */
/* | notice appear in supporting documentation. This software is | */
/* | provided "as is" without express or implied warranty. | */
/* +-------------------------------------------------------------------+ */
/* Portions Copyright (C) 1999 Sam Lantinga*/
/* Adapted for use in SDL by Sam Lantinga -- 7/20/98 */
/*
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
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* GIF stuff*/
/*
* GIF decoding routine
*/
#define MAXCOLORMAPSIZE 256
#define MAX_LWZ_BITS 12
#define INTERLACE 0x40
#define LOCALCOLORMAP 0x80
 
#define CM_RED 0
#define CM_GREEN 1
#define CM_BLUE 2
 
#define BitSet(byte, bit) (((byte) & (bit)) == (bit))
#define ReadOK(src,buffer,len) bread(src, buffer, len)
#define LM_to_uint(a,b) (((b)<<8)|(a))
 
struct {
unsigned int Width;
unsigned int Height;
unsigned char ColorMap[3][MAXCOLORMAPSIZE];
unsigned int BitPixel;
unsigned int ColorResolution;
unsigned int Background;
unsigned int AspectRatio;
int GrayScale;
} GifScreen;
 
static struct {
int transparent;
int delayTime;
int inputFlag;
int disposal;
} Gif89;
 
static int ReadColorMap(buffer_t *src, int number,
unsigned char buffer[3][MAXCOLORMAPSIZE], int *flag);
static int DoExtension(buffer_t *src, int label);
static int GetDataBlock(buffer_t *src, unsigned char *buf);
static int GetCode(buffer_t *src, int code_size, int flag);
static int LWZReadByte(buffer_t *src, int flag, int input_code_size);
static int ReadImage(buffer_t *src, PMWIMAGEHDR pimage, int len, int height, int,
unsigned char cmap[3][MAXCOLORMAPSIZE],
int gray, int interlace, int ignore);
 
static int
LoadGIF(buffer_t *src, PMWIMAGEHDR pimage)
{
unsigned char buf[16];
unsigned char c;
unsigned char localColorMap[3][MAXCOLORMAPSIZE];
int grayScale;
int useGlobalColormap;
int bitPixel;
int imageCount = 0;
char version[4];
int imageNumber = 1;
int ok = 0;
 
bseek(src, 0, SEEK_SET);
 
pimage->imagebits = NULL;
pimage->palette = NULL;
 
if (!ReadOK(src, buf, 6))
return 0; /* not gif image*/
if (strncmp((char *) buf, "GIF", 3) != 0)
return 0;
strncpy(version, (char *) buf + 3, 3);
version[3] = '\0';
 
if (strcmp(version, "87a") != 0 && strcmp(version, "89a") != 0) {
EPRINTF("LoadGIF: GIF version number not 87a or 89a\n");
return 2; /* image loading error*/
}
Gif89.transparent = -1;
Gif89.delayTime = -1;
Gif89.inputFlag = -1;
Gif89.disposal = 0;
 
if (!ReadOK(src, buf, 7)) {
EPRINTF("LoadGIF: bad screen descriptor\n");
return 2; /* image loading error*/
}
GifScreen.Width = LM_to_uint(buf[0], buf[1]);
GifScreen.Height = LM_to_uint(buf[2], buf[3]);
GifScreen.BitPixel = 2 << (buf[4] & 0x07);
GifScreen.ColorResolution = (((buf[4] & 0x70) >> 3) + 1);
GifScreen.Background = buf[5];
GifScreen.AspectRatio = buf[6];
 
if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
if (ReadColorMap(src, GifScreen.BitPixel, GifScreen.ColorMap,
&GifScreen.GrayScale)) {
EPRINTF("LoadGIF: bad global colormap\n");
return 2; /* image loading error*/
}
}
 
do {
if (!ReadOK(src, &c, 1)) {
EPRINTF("LoadGIF: EOF on image data\n");
goto done;
}
if (c == ';') { /* GIF terminator */
if (imageCount < imageNumber) {
EPRINTF("LoadGIF: no image %d of %d\n", imageNumber,imageCount);
goto done;
}
}
if (c == '!') { /* Extension */
if (!ReadOK(src, &c, 1)) {
EPRINTF("LoadGIF: EOF on extension function code\n");
goto done;
}
DoExtension(src, c);
continue;
}
if (c != ',') { /* Not a valid start character */
continue;
}
++imageCount;
 
if (!ReadOK(src, buf, 9)) {
EPRINTF("LoadGIF: bad image size\n");
goto done;
}
useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP);
 
bitPixel = 1 << ((buf[8] & 0x07) + 1);
 
if (!useGlobalColormap) {
if (ReadColorMap(src, bitPixel, localColorMap, &grayScale)) {
EPRINTF("LoadGIF: bad local colormap\n");
goto done;
}
ok = ReadImage(src, pimage, LM_to_uint(buf[4], buf[5]),
LM_to_uint(buf[6], buf[7]),
bitPixel, localColorMap, grayScale,
BitSet(buf[8], INTERLACE),
imageCount != imageNumber);
} else {
ok = ReadImage(src, pimage, LM_to_uint(buf[4], buf[5]),
LM_to_uint(buf[6], buf[7]),
GifScreen.BitPixel, GifScreen.ColorMap,
GifScreen.GrayScale, BitSet(buf[8], INTERLACE),
imageCount != imageNumber);
}
} while (ok == 0);
 
/* set transparent color, if any*/
pimage->transcolor = Gif89.transparent;
 
if (ok)
return 1; /* image load ok*/
 
done:
if (pimage->imagebits)
free(pimage->imagebits);
if (pimage->palette)
free(pimage->palette);
return 2; /* image load error*/
}
 
static int
ReadColorMap(buffer_t *src, int number, unsigned char buffer[3][MAXCOLORMAPSIZE],
int *gray)
{
int i;
unsigned char rgb[3];
int flag;
 
flag = TRUE;
 
for (i = 0; i < number; ++i) {
if (!ReadOK(src, rgb, sizeof(rgb)))
return 1;
buffer[CM_RED][i] = rgb[0];
buffer[CM_GREEN][i] = rgb[1];
buffer[CM_BLUE][i] = rgb[2];
flag &= (rgb[0] == rgb[1] && rgb[1] == rgb[2]);
}
 
#if 0
if (flag)
*gray = (number == 2) ? PBM_TYPE : PGM_TYPE;
else
*gray = PPM_TYPE;
#else
*gray = 0;
#endif
 
return FALSE;
}
 
static int
DoExtension(buffer_t *src, int label)
{
static unsigned char buf[256];
 
switch (label) {
case 0x01: /* Plain Text Extension */
break;
case 0xff: /* Application Extension */
break;
case 0xfe: /* Comment Extension */
while (GetDataBlock(src, (unsigned char *) buf) != 0);
return FALSE;
case 0xf9: /* Graphic Control Extension */
GetDataBlock(src, (unsigned char *) buf);
Gif89.disposal = (buf[0] >> 2) & 0x7;
Gif89.inputFlag = (buf[0] >> 1) & 0x1;
Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
if ((buf[0] & 0x1) != 0)
Gif89.transparent = buf[3];
 
while (GetDataBlock(src, (unsigned char *) buf) != 0);
return FALSE;
default:
break;
}
 
while (GetDataBlock(src, (unsigned char *) buf) != 0);
 
return FALSE;
}
 
static int ZeroDataBlock = FALSE;
 
static int
GetDataBlock(buffer_t *src, unsigned char *buf)
{
unsigned char count;
 
if (!ReadOK(src, &count, 1))
return -1;
ZeroDataBlock = count == 0;
 
if ((count != 0) && (!ReadOK(src, buf, count)))
return -1;
return count;
}
 
static int
GetCode(buffer_t *src, int code_size, int flag)
{
static unsigned char buf[280];
static int curbit, lastbit, done, last_byte;
int i, j, ret;
unsigned char count;
 
if (flag) {
curbit = 0;
lastbit = 0;
done = FALSE;
return 0;
}
if ((curbit + code_size) >= lastbit) {
if (done) {
if (curbit >= lastbit)
EPRINTF("LoadGIF: bad decode\n");
return -1;
}
buf[0] = buf[last_byte - 2];
buf[1] = buf[last_byte - 1];
 
if ((count = GetDataBlock(src, &buf[2])) == 0)
done = TRUE;
 
last_byte = 2 + count;
curbit = (curbit - lastbit) + 16;
lastbit = (2 + count) * 8;
}
ret = 0;
for (i = curbit, j = 0; j < code_size; ++i, ++j)
ret |= ((buf[i / 8] & (1 << (i % 8))) != 0) << j;
 
curbit += code_size;
 
return ret;
}
 
static int
LWZReadByte(buffer_t *src, int flag, int input_code_size)
{
int code, incode;
register int i;
static int fresh = FALSE;
static int code_size, set_code_size;
static int max_code, max_code_size;
static int firstcode, oldcode;
static int clear_code, end_code;
static int table[2][(1 << MAX_LWZ_BITS)];
static int stack[(1 << (MAX_LWZ_BITS)) * 2], *sp;
 
if (flag) {
set_code_size = input_code_size;
code_size = set_code_size + 1;
clear_code = 1 << set_code_size;
end_code = clear_code + 1;
max_code_size = 2 * clear_code;
max_code = clear_code + 2;
 
GetCode(src, 0, TRUE);
 
fresh = TRUE;
 
for (i = 0; i < clear_code; ++i) {
table[0][i] = 0;
table[1][i] = i;
}
for (; i < (1 << MAX_LWZ_BITS); ++i)
table[0][i] = table[1][0] = 0;
 
sp = stack;
 
return 0;
} else if (fresh) {
fresh = FALSE;
do {
firstcode = oldcode = GetCode(src, code_size, FALSE);
} while (firstcode == clear_code);
return firstcode;
}
if (sp > stack)
return *--sp;
 
while ((code = GetCode(src, code_size, FALSE)) >= 0) {
if (code == clear_code) {
for (i = 0; i < clear_code; ++i) {
table[0][i] = 0;
table[1][i] = i;
}
for (; i < (1 << MAX_LWZ_BITS); ++i)
table[0][i] = table[1][i] = 0;
code_size = set_code_size + 1;
max_code_size = 2 * clear_code;
max_code = clear_code + 2;
sp = stack;
firstcode = oldcode = GetCode(src, code_size, FALSE);
return firstcode;
} else if (code == end_code) {
int count;
unsigned char buf[260];
 
if (ZeroDataBlock)
return -2;
 
while ((count = GetDataBlock(src, buf)) > 0);
 
if (count != 0) {
/*
* EPRINTF("missing EOD in data stream (common occurence)");
*/
}
return -2;
}
incode = code;
 
if (code >= max_code) {
*sp++ = firstcode;
code = oldcode;
}
while (code >= clear_code) {
*sp++ = table[1][code];
if (code == table[0][code])
EPRINTF("LoadGIF: circular table entry\n");
code = table[0][code];
}
 
*sp++ = firstcode = table[1][code];
 
if ((code = max_code) < (1 << MAX_LWZ_BITS)) {
table[0][code] = oldcode;
table[1][code] = firstcode;
++max_code;
if ((max_code >= max_code_size) &&
(max_code_size < (1 << MAX_LWZ_BITS))) {
max_code_size *= 2;
++code_size;
}
}
oldcode = incode;
 
if (sp > stack)
return *--sp;
}
return code;
}
 
static int
ReadImage(buffer_t* src, PMWIMAGEHDR pimage, int len, int height, int cmapSize,
unsigned char cmap[3][MAXCOLORMAPSIZE],
int gray, int interlace, int ignore)
{
unsigned char c;
int i, v;
int xpos = 0, ypos = 0, pass = 0;
 
/*
* Initialize the compression routines
*/
if (!ReadOK(src, &c, 1)) {
EPRINTF("LoadGIF: EOF on image data\n");
return 0;
}
if (LWZReadByte(src, TRUE, c) < 0) {
EPRINTF("LoadGIF: error reading image\n");
return 0;
}
 
/*
* If this is an "uninteresting picture" ignore it.
*/
if (ignore) {
while (LWZReadByte(src, FALSE, c) >= 0);
return 0;
}
/*image = ImageNewCmap(len, height, cmapSize);*/
pimage->width = len;
pimage->height = height;
pimage->planes = 1;
pimage->bpp = 8;
ComputePitch(8, len, &pimage->pitch, &pimage->bytesperpixel);
pimage->compression = 0;
pimage->palsize = cmapSize;
pimage->palette = malloc(256*sizeof(MWPALENTRY));
pimage->imagebits = malloc(height*pimage->pitch);
if(!pimage->imagebits || !pimage->palette)
return 0;
 
for (i = 0; i < cmapSize; i++) {
/*ImageSetCmap(image, i, cmap[CM_RED][i],
cmap[CM_GREEN][i], cmap[CM_BLUE][i]);*/
pimage->palette[i].r = cmap[CM_RED][i];
pimage->palette[i].g = cmap[CM_GREEN][i];
pimage->palette[i].b = cmap[CM_BLUE][i];
}
 
while ((v = LWZReadByte(src, FALSE, c)) >= 0) {
pimage->imagebits[ypos * pimage->pitch + xpos] = v;
 
++xpos;
if (xpos == len) {
xpos = 0;
if (interlace) {
switch (pass) {
case 0:
case 1:
ypos += 8;
break;
case 2:
ypos += 4;
break;
case 3:
ypos += 2;
break;
}
 
if (ypos >= height) {
++pass;
switch (pass) {
case 1:
ypos = 4;
break;
case 2:
ypos = 2;
break;
case 3:
ypos = 1;
break;
default:
goto fini;
}
}
} else {
++ypos;
}
}
if (ypos >= height)
break;
}
 
fini:
return 1;
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_GIF_SUPPORT)*/
 
#if defined(HAVE_FILEIO) && defined(HAVE_PNM_SUPPORT)
enum {
PNM_TYPE_NOTPNM,
PNM_TYPE_PBM,
PNM_TYPE_PGM,
PNM_TYPE_PPM
};
static int LoadPNM(buffer_t *src, PMWIMAGEHDR pimage)
{
char buf[256], *p;
int type = PNM_TYPE_NOTPNM, binary = 0, gothdrs = 0, scale = 0;
int ch, x = 0, y = 0, i, n, mask, col1, col2, col3;
 
bseek(src, 0L, 0);
 
if(!bgets(src,buf, 4)) return 0;
 
if(!strcmp("P1\n", buf)) type = PNM_TYPE_PBM;
else if(!strcmp("P2\n", buf)) type = PNM_TYPE_PGM;
else if(!strcmp("P3\n", buf)) type = PNM_TYPE_PPM;
else if(!strcmp("P4\n", buf)) {
type = PNM_TYPE_PBM;
binary = 1;
}
else if(!strcmp("P5\n", buf)) {
type = PNM_TYPE_PGM;
binary = 1;
}
else if(!strcmp("P6\n", buf)) {
type = PNM_TYPE_PPM;
binary = 1;
}
 
if(type == PNM_TYPE_NOTPNM) return 0;
 
n = 0;
while((p = bgets(src, buf, 256))) {
if(*buf == '#') continue;
if(type == PNM_TYPE_PBM) {
if(sscanf(buf, "%i %i", &pimage->width,
&pimage->height) == 2) {
pimage->bpp = 1;
gothdrs = 1;
if(!(pimage->palette = malloc(
sizeof(MWPALENTRY) * 2))) {
EPRINTF("Out of memory\n");
return 2;
}
pimage->palsize = 2;
pimage->palette[0].r = 0xff;
pimage->palette[0].g = 0xff;
pimage->palette[0].b = 0xff;
pimage->palette[1].r = 0;
pimage->palette[1].g = 0;
pimage->palette[1].b = 0;
}
break;
}
if((type == PNM_TYPE_PGM) || (type == PNM_TYPE_PPM)) {
if(!n++) {
if(sscanf(buf, "%i %i", &pimage->width,
&pimage->height) != 2) break;
} else {
if(sscanf(buf, "%i", &i) != 1) break;
pimage->bpp = 24;
if(i > 255) {
EPRINTF("LoadPNM: PPM files must be "
"24bpp\n");
return 2;
}
for(scale = 7, n = 2; scale; scale--, n *= 2)
if(i < n) break;
gothdrs = 1;
break;
}
}
}
 
if(!gothdrs) {
EPRINTF("LoadPNM: bad image headers\n");
if(pimage->palette) free(pimage->palette);
return 2;
}
 
pimage->planes = 1;
ComputePitch(pimage->bpp, pimage->width, &pimage->pitch,
&pimage->bytesperpixel);
pimage->compression = MWIMAGE_RGB;
if(!(pimage->imagebits = malloc(pimage->pitch * pimage->height))) {
EPRINTF("LoadPNM: couldn't allocate memory for image\n");
if(pimage->palette) free(pimage->palette);
return 2;
}
 
p = pimage->imagebits;
 
if(type == PNM_TYPE_PBM) {
if(binary) {
x = 0;
y = 0;
while((ch = bgetc(src)) != EOF) {
for(i = 0; i < 8; i++) {
mask = 0x80 >> i;
if(ch & mask) *p |= mask;
else *p &= ~mask;
if(++x == pimage->width) {
if(++y == pimage->height)
return 1;
p = pimage->imagebits - 1 +
(y * pimage->pitch);
x = 0;
break;
}
}
p++;
}
} else {
n = 0;
while((ch = bgetc(src)) != EOF) {
if(isspace(ch)) continue;
mask = 0x80 >> n;
if(ch == '1') *p |= mask;
else if(ch == '0') *p &= ~mask;
else goto baddata;
if(++n == 8) {
n = 0;
p++;
}
if(++x == pimage->width) {
if(++y == pimage->height)
return 1;
p = pimage->imagebits +
(y * pimage->pitch);
n = 0;
x = 0;
}
}
}
} else {
while(1) {
if(type == PNM_TYPE_PGM) {
if(binary) {
if((ch = bgetc(src)) == EOF)
goto baddata;
} else {
// if(fscanf(fp, "%i", &ch) != 1)
goto baddata;
}
*p++ = ch << scale;
*p++ = ch << scale;
*p++ = ch << scale;
} else {
if(binary) {
if(((col1 = bgetc(src)) == EOF) ||
((col2 = bgetc(src)) == EOF) ||
((col3 = bgetc(src)) == EOF))
goto baddata;
} else {
// if(fscanf(fp, "%i %i %i", &col1, &col2,
// &col3) != 3)
goto baddata;
}
*p++ = col1 << scale;
*p++ = col2 << scale;
*p++ = col3 << scale;
}
if(++x == pimage->width) {
if(++y == pimage->height) return 1;
p = pimage->imagebits + (y * pimage->pitch);
x = 0;
}
}
}
 
baddata:
EPRINTF("LoadPNM: bad image data\n");
free(pimage->imagebits);
if(pimage->palette) free(pimage->palette);
return 2;
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_PNM_SUPPORT) */
 
#if defined(HAVE_FILEIO) && defined(HAVE_XPM_SUPPORT)
struct xpm_cmap {
char mapstr[3];
long palette_entry;
long color;
struct xpm_cmap *next;
};
 
static long XPM_parse_color(char *color)
{
/* This will parse the string into a color value of some sort */
 
if (color[0] != '#')
{
if (!strcmp(color, "None"))
return(-1); /* Transparent */
else
return(0); /* If its an X color, then we bail */
}
else
{
/* This is ugly! */
 
char *sptr = color + 1;
char rstr[5], gstr[5], bstr[5];
long r,g,b;
 
switch(strlen(sptr))
{
case 6:
return(strtol(sptr, NULL, 16));
 
case 9: /* RRRGGGBBB */
strncpy(rstr, sptr, 3);
strncpy(gstr, sptr + 3, 3);
strncpy(bstr, sptr + 6, 3);
 
rstr[3] = 0;
gstr[3] = 0;
bstr[3] = 0;
 
r = strtol(rstr, NULL, 16) >> 4;
g = strtol(gstr, NULL, 16) >> 4;
b = strtol(bstr, NULL, 16) >> 4;
 
return( (long) ( r << 16 | g << 8 | b));
 
case 12:
strncpy(rstr, sptr, 4);
strncpy(gstr, sptr + 4, 4);
strncpy(bstr, sptr + 8, 4);
rstr[4] = 0;
gstr[4] = 0;
bstr[4] = 0;
 
r = strtol(rstr, NULL, 16) >> 8;
g = strtol(gstr, NULL, 16) >> 8;
b = strtol(bstr, NULL, 16) >> 8;
return( (long) ( (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF)));
}
}
 
return(0);
}
 
/* A series of status indicators that let us know whats going on */
/* It could be an enum if you want */
 
#define LOAD_HEADER 1
#define LOAD_COLORS 2
#define LOAD_PALETTE 3
#define LOAD_PIXELS 4
#define LOAD_DONE 5
 
/* The magic that "should" indicate an XPM (does it really?) */
#define XPM_MAGIC "/* XPM */"
#define XPM_TRANSCOLOR 0x01000000
 
static int LoadXPM(buffer_t *src, PMWIMAGEHDR pimage, PSD psd)
{
struct xpm_cmap *colorheap = 0; /* A "heap" of color structs */
struct xpm_cmap *colormap[256]; /* A quick hash of 256 spots for colors */
unsigned char *imageptr = 0;
 
MWSCREENINFO sinfo;
 
char xline[300];
char dline[300];
 
char *c;
int a;
 
int col, row, colors, cpp;
int in_color = 0;
int read_xline = 0;
 
int status = LOAD_HEADER;
 
/* Very first thing, get the screen info */
GdGetScreenInfo(psd, &sinfo);
 
for(a = 0; a < 256; a++)
colormap[a] = 0;
 
pimage->imagebits = NULL;
pimage->palette = NULL;
 
/* Start over at the beginning with the file */
bseek(src, 0, SEEK_SET);
bgets(src, xline, 300);
/* Chop the EOL */
xline[strlen(xline) - 1] = 0;
 
/* Check the magic */
if (strncmp(xline, XPM_MAGIC, sizeof(XPM_MAGIC))) return(0);
 
while(!beof(src))
{
/* Get the next line from the file */
bgets(src,xline, 300);
xline[strlen(xline) - 1] = 0;
 
/* Check it out */
if (xline[0] == '/' && xline[1] == '*') /* Comment */
continue;
 
if (xline[0] != '\"')
continue;
 
/* remove the quotes from the line */
for(c = xline + 1, a = 0; *c != '\"' && *c != 0; c++, a++)
dline[a] = *c;
 
dline[a] = 0;
 
/* Is it the header? */
if (status == LOAD_HEADER)
{
sscanf(dline, "%i %i %i %i", &col, &row, &colors, &cpp);
 
pimage->width = col;
pimage->height = row;
pimage->planes = 1;
 
if (sinfo.bpp <= 8)
{
pimage->bpp = sinfo.bpp;
pimage->compression = 0;
pimage->transcolor = -1;
}
else
{
pimage->bpp = 32;
pimage->transcolor = XPM_TRANSCOLOR;
pimage->compression = MWIMAGE_BGR;
}
 
pimage->palsize = colors;
 
ComputePitch(pimage->bpp, col, &pimage->pitch, &pimage->bytesperpixel);
 
pimage->imagebits = malloc(pimage->pitch * pimage->height);
imageptr = (unsigned char *) pimage->imagebits;
 
/* Allocate enough room for all the colors */
colorheap = (struct xpm_cmap *) malloc(colors * sizeof(struct xpm_cmap));
 
/* Allocate the palette space (if required) */
 
if (sinfo.bpp <= 8)
pimage->palette = malloc(256*sizeof(MWPALENTRY));
 
if (!colorheap)
{
EPRINTF("Couldn't allocate any memory for the colors\n");
return(0);
}
 
status = LOAD_COLORS;
in_color = 0;
continue;
}
 
/* Are we in load colors? */
if (status == LOAD_COLORS)
{
struct xpm_cmap *n;
 
char tstr[5];
char cstr[256];
 
unsigned char m;
 
c = dline;
 
/* Go at at least 1 charater, and then count until we have
two spaces in a row */
 
strncpy(tstr, c, cpp);
 
c += cpp;
for(; *c == '\t' || *c == ' '; c++); /* Skip over whitespace */
 
/* FIXME: We assume that a 'c' follows. What if it doesn't? */
c +=2;
tstr[cpp] = 0;
 
/* Now we put it into the array for easy lookup */
/* We base it off the first charater, even though */
/* there may be up to 4 */
 
m = tstr[0];
if (colormap[m])
{
n = colormap[m];
while(n->next) n = n->next;
n->next = &colorheap[in_color];
n = n->next;
}
else
{
colormap[m] = &colorheap[in_color];
n = colormap[m];
}
n->next = 0;
 
/* Record the string */
strncpy(n->mapstr, tstr, cpp);
n->mapstr[cpp] = 0;
 
/* Now record the palette entry */
n->palette_entry = (long) in_color;
 
/* This is the color */
sscanf(c, "%65535s", cstr);
 
/* Turn it into a real value */
n->color = XPM_parse_color(cstr);
 
/* If we are in palette mode, then we need to */
/* load the palette (duh..) */
 
if (sinfo.bpp <= 8)
{
if (n->color == -1)
{
pimage->transcolor = in_color;
n->color = -1;
}
pimage->palette[in_color].r = (n->color >> 16) & 0xFF;
pimage->palette[in_color].g = (n->color >> 8) & 0xFF;
pimage->palette[in_color].b = n->color & 0xFF;
}
else
{
if (n->color == -1)
n->color = XPM_TRANSCOLOR;
}
 
if (++in_color == colors)
{
read_xline = 0;
status = LOAD_PIXELS;
}
 
continue;
}
if (status == LOAD_PIXELS)
{
int bytecount = 0;
int bitcount = 0;
long dwordcolor = 0;
int i;
char pxlstr[3];
 
c = dline;
while(*c)
{
unsigned char z = 0;
 
if (cpp == 1)
{
z = *c;
if (!colormap[z])
{
EPRINTF("No color entry for (%c)\n", z);
return(0);
}
 
if (sinfo.bpp <= 8)
dwordcolor = (long) colormap[z]->palette_entry;
else
dwordcolor = colormap[z]->color;
 
c++;
}
else
{
struct xpm_cmap *n;
 
/* We grab the largest possible, and then compare */
 
strncpy(pxlstr, c, cpp);
z = pxlstr[0];
 
if (!colormap[z])
{
EPRINTF("No color entry for (%s)\n", pxlstr);
return(0);
}
n = colormap[z];
 
while(n)
{
if (!strncmp(n->mapstr, pxlstr, cpp))
break;
 
n = n->next;
}
 
if (!n)
{
EPRINTF("No color found for (%s)\n", pxlstr);
return(0);
}
 
if (sinfo.bpp <= 8)
dwordcolor = (long) n->palette_entry;
else
dwordcolor = n->color;
c += cpp;
}
 
/*
* This ugly thing is needed to ensure that we
* work well in all modes.
*/
switch(sinfo.bpp)
{
case 2:
if (bitcount == 0)
imageptr[0] = 0;
imageptr[0] |= (dwordcolor & 0x3) << (4 - bitcount);
bitcount++;
if (bitcount == 4)
{
imageptr++;
bytecount += pimage->bytesperpixel;
bitcount = 0;
}
break;
 
case 4:
if (bitcount == 0)
imageptr[0] = 0;
imageptr[0] |= (dwordcolor & 0xF) << (2 - bitcount);
bitcount++;
if (bitcount == 2)
{
imageptr++;
bytecount += pimage->bytesperpixel;
bitcount = 0;
}
break;
 
case 8:
case 16:
case 24:
case 32:
for(i = 0; i < pimage->bytesperpixel; i++)
imageptr[i] = (dwordcolor >> (8 * i)) & 0xFF;
imageptr += pimage->bytesperpixel;
bytecount += pimage->bytesperpixel;
break;
 
#ifdef NOTUSED
case 8:
imageptr[0] = (unsigned char) (dwordcolor & 0xFF);
imageptr += pimage->bytesperpixel;
bytecount += pimage->bytesperpixel;
break;
 
case 16:
case 24:
case 32:
imageptr[0] = (unsigned char) (dwordcolor >> 24) & 0xFF;
imageptr[1] = (unsigned char) (dwordcolor >> 16) & 0xFF;
imageptr[2] = (unsigned char) (dwordcolor >> 8) & 0xFF;
imageptr[3] = (unsigned char) (dwordcolor & 0xFF);
imageptr += pimage->bytesperpixel;
bytecount += pimage->bytesperpixel;
break;
#endif
}
}
 
/* Pad to the end of the line */
if (bytecount < pimage->pitch)
for(i = 0; i < (pimage->pitch - bytecount); i++)
*imageptr++ = 0x00;
 
read_xline++;
if (read_xline == row)
status = LOAD_DONE;
 
continue;
}
}
 
free(colorheap);
 
if (status != LOAD_DONE)
return(-1);
return(1);
}
#endif /* defined(HAVE_FILEIO) && defined(HAVE_XPM_SUPPORT)*/
 
#endif /* defined(HAVE_FILEIO)*/
/devpoly.c
0,0 → 1,636
#include <stdio.h>
#include <stdlib.h>
#include "device.h"
/*
* Microwindows polygon outline and fill routines.
* Copyright (c) 1999, 2000, 2001 Greg Haerr <greg@censoft.com>
* Portions Copyright (c) 1991 David I. Bell
*
* There are currently three implementations of the polygon
* fill routine. The version from X11 most properly
* fills polygons that must also be outlined as well. All are
* controlled with #if directive in this file.
*/
 
/* extern definitions*/
void drawpoint(PSD psd,MWCOORD x, MWCOORD y);
void drawrow(PSD psd,MWCOORD x1,MWCOORD x2,MWCOORD y);
extern int gr_mode; /* drawing mode */
 
/* Draw a polygon in the foreground color, applying clipping if necessary.
* The polygon is only closed if the first point is repeated at the end.
* Some care is taken to plot the endpoints correctly if the current
* drawing mode is XOR. However, internal crossings are not handled
* correctly.
*/
void
GdPoly(PSD psd, int count, MWPOINT *points)
{
MWCOORD firstx;
MWCOORD firsty;
MWBOOL didline;
 
if (count < 2)
return;
firstx = points->x;
firsty = points->y;
didline = FALSE;
 
while (count-- > 1) {
if (didline && (gr_mode == MWMODE_XOR))
drawpoint(psd, points->x, points->y);
/* note: change to drawline*/
GdLine(psd, points[0].x, points[0].y, points[1].x, points[1].y, TRUE);
points++;
didline = TRUE;
}
if (gr_mode == MWMODE_XOR) {
points--;
if (points->x == firstx && points->y == firsty)
drawpoint(psd, points->x, points->y);
}
GdFixCursor(psd);
}
 
#if 1 /* improved convex polygon fill routine*/
/***********************************************************
Copyright (c) 1987 X Consortium
 
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.
 
 
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
 
All Rights Reserved
 
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
 
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
 
/*
* Written by Brian Kelleher; Dec. 1985.
* Adapted for Microwindows Sep 2001 by Greg Haerr <greg@censoft.com>
*
* Fill a convex polygon in the fg color, with clipping.
* If the given polygon
* is not convex, then the result is undefined.
* The algorithm is to order the edges from smallest
* y to largest by partitioning the array into a left
* edge list and a right edge list. The algorithm used
* to traverse each edge is an extension of Bresenham's
* line algorithm with y as the major axis.
*
* This file contains a few macros to help track
* the edge of a filled object. The object is assumed
* to be filled in scanline order, and thus the
* algorithm used is an extension of Bresenham's line
* drawing algorithm which assumes that y is always the
* major axis.
*
* In scan converting polygons, we want to choose those pixels
* which are inside the polygon. Thus, we add .5 to the starting
* x coordinate for both left and right edges. Now we choose the
* first pixel which is inside the pgon for the left edge and the
* first pixel which is outside the pgon for the right edge.
* Draw the left pixel, but not the right.
*
* How to add .5 to the starting x coordinate:
* If the edge is moving to the right, then subtract dy from the
* error term from the general form of the algorithm.
* If the edge is moving to the left, then add dy to the error term.
*
* The reason for the difference between edges moving to the left
* and edges moving to the right is simple: If an edge is moving
* to the right, then we want the algorithm to flip immediately.
* If it is moving to the left, then we don't want it to flip until
* we traverse an entire pixel.
*/
#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
int dx; /* local storage */ \
\
/* \
* if the edge is horizontal, then it is ignored \
* and assumed not to be processed. Otherwise, do this stuff. \
*/ \
if ((dy) != 0) { \
xStart = (x1); \
dx = (x2) - xStart; \
if (dx < 0) { \
m = dx / (dy); \
m1 = m - 1; \
incr1 = -2 * dx + 2 * (dy) * m1; \
incr2 = -2 * dx + 2 * (dy) * m; \
d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
} else { \
m = dx / (dy); \
m1 = m + 1; \
incr1 = 2 * dx - 2 * (dy) * m1; \
incr2 = 2 * dx - 2 * (dy) * m; \
d = -2 * m * (dy) + 2 * dx; \
} \
} \
}
 
#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
if (m1 > 0) { \
if (d > 0) { \
minval += m1; \
d += incr1; \
} \
else { \
minval += m; \
d += incr2; \
} \
} else {\
if (d >= 0) { \
minval += m1; \
d += incr1; \
} \
else { \
minval += m; \
d += incr2; \
} \
} \
}
 
/*
* Find the index of the point with the smallest y.
*/
static int
getPolyYBounds(MWPOINT *pts, int n, int *by, int *ty)
{
MWPOINT *ptMin;
int ymin, ymax;
MWPOINT *ptsStart = pts;
 
ptMin = pts;
ymin = ymax = (pts++)->y;
 
while (--n > 0) {
if (pts->y < ymin)
{
ptMin = pts;
ymin = pts->y;
}
if(pts->y > ymax)
ymax = pts->y;
 
pts++;
}
 
*by = ymin;
*ty = ymax;
return(ptMin-ptsStart);
}
 
void
GdFillPoly(PSD psd, int count, MWPOINT *pointtable)
{
MWCOORD xl = 0, xr = 0; /* x vals of left and right edges */
int dl = 0, dr = 0; /* decision variables */
int ml = 0, m1l = 0; /* left edge slope and slope+1 */
int mr = 0, m1r = 0; /* right edge slope and slope+1 */
int incr1l = 0, incr2l = 0; /* left edge error increments */
int incr1r = 0, incr2r = 0; /* right edge error increments */
int dy; /* delta y */
MWCOORD y; /* current scanline */
int left, right; /* indices to first endpoints */
int i; /* loop counter */
int nextleft, nextright; /* indices to second endpoints */
MWPOINT *ptsOut, *FirstPoint;/* output buffer */
MWCOORD *width, *FirstWidth;/* output buffer */
int imin; /* index of smallest vertex (in y)*/
int ymin; /* y-extents of polygon */
int ymax;
 
/*
* find leftx, bottomy, rightx, topy, and the index
* of bottomy.
*/
imin = getPolyYBounds(pointtable, count, &ymin, &ymax);
 
dy = ymax - ymin + 1;
if ((count < 3) || (dy < 0))
return;
ptsOut = FirstPoint = (MWPOINT *)ALLOCA(sizeof(MWPOINT) * dy);
width = FirstWidth = (MWCOORD *)ALLOCA(sizeof(MWCOORD) * dy);
if(!FirstPoint || !FirstWidth)
{
if (FirstWidth) FREEA(FirstWidth);
if (FirstPoint) FREEA(FirstPoint);
return;
}
 
nextleft = nextright = imin;
y = pointtable[nextleft].y;
 
/*
* loop through all edges of the polygon
*/
do {
/*
* add a left edge if we need to
*/
if (pointtable[nextleft].y == y) {
left = nextleft;
 
/*
* find the next edge, considering the end
* conditions of the array.
*/
nextleft++;
if (nextleft >= count)
nextleft = 0;
 
/*
* now compute all of the random information
* needed to run the iterative algorithm.
*/
BRESINITPGON(pointtable[nextleft].y-pointtable[left].y,
pointtable[left].x,pointtable[nextleft].x,
xl, dl, ml, m1l, incr1l, incr2l);
}
 
/*
* add a right edge if we need to
*/
if (pointtable[nextright].y == y) {
right = nextright;
 
/*
* find the next edge, considering the end
* conditions of the array.
*/
nextright--;
if (nextright < 0)
nextright = count-1;
 
/*
* now compute all of the random information
* needed to run the iterative algorithm.
*/
BRESINITPGON(pointtable[nextright].y-pointtable[right].y,
pointtable[right].x,pointtable[nextright].x,
xr, dr, mr, m1r, incr1r, incr2r);
}
 
/*
* generate scans to fill while we still have
* a right edge as well as a left edge.
*/
i = MWMIN(pointtable[nextleft].y, pointtable[nextright].y) - y;
/* in case we're called with non-convex polygon */
if(i < 0)
{
FREEA(FirstWidth);
FREEA(FirstPoint);
return;
}
while (i-- > 0)
{
ptsOut->y = y;
 
/*
* reverse the edges if necessary
*/
if (xl < xr)
{
*(width++) = xr - xl;
(ptsOut++)->x = xl;
}
else
{
*(width++) = xl - xr;
(ptsOut++)->x = xr;
}
y++;
 
/* increment down the edges */
BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l);
BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r);
}
} while (y != ymax);
 
/*
* Finally, fill the spans
*/
i = ptsOut-FirstPoint;
ptsOut = FirstPoint;
width = FirstWidth;
while (--i >= 0) {
/* calc x extent from width*/
int e = *width++ - 1;
if (e >= 0) {
drawrow(psd, ptsOut->x, ptsOut->x + e, ptsOut->y);
}
++ptsOut;
}
 
FREEA(FirstWidth);
FREEA(FirstPoint);
GdFixCursor(psd);
}
#endif
 
#if 0 /* original convex only polygon fill routine*/
/*
* Fill a polygon in the foreground color, applying clipping if necessary.
* The last point may be a duplicate of the first point, but this is
* not required.
* Note: this routine currently only correctly fills convex polygons.
*/
 
/* Utility routine for filling polygons. Find the intersection point (if
* any) of a horizontal line with an arbitrary line, and extend the current
* minimum and maximum x values as needed to include the intersection point.
* Input parms:
* y row to check for intersection
* x1, y1 first endpoint
* x2, y2 second enpoint
* minxptr address of current minimum x
* maxxptr address of current maximum x
*/
static void
extendrow(MWCOORD y,MWCOORD x1,MWCOORD y1,MWCOORD x2,MWCOORD y2,
MWCOORD *minxptr,MWCOORD *maxxptr)
{
MWCOORD x; /* x coordinate of intersection */
typedef long NUM;
NUM num; /* numerator of fraction */
 
/* First make sure the specified line segment includes the specified
* row number. If not, then there is no intersection.
*/
if (((y < y1) || (y > y2)) && ((y < y2) || (y > y1)))
return;
 
/* If a horizontal line, then check the two endpoints. */
if (y1 == y2) {
if (*minxptr > x1) *minxptr = x1;
if (*minxptr > x2) *minxptr = x2;
if (*maxxptr < x1) *maxxptr = x1;
if (*maxxptr < x2) *maxxptr = x2;
return;
}
 
/* If a vertical line, then check the x coordinate. */
if (x1 == x2) {
if (*minxptr > x1) *minxptr = x1;
if (*maxxptr < x1) *maxxptr = x1;
return;
}
 
/* An arbitrary line. Calculate the intersection point using the
* formula x = x1 + (y - y1) * (x2 - x1) / (y2 - y1).
*/
num = ((NUM) (y - y1)) * (x2 - x1);
x = x1 + num / (y2 - y1);
if (*minxptr > x) *minxptr = x;
if (*maxxptr < x) *maxxptr = x;
}
 
void
GdFillPoly(PSD psd, int count, MWPOINT *points)
{
MWPOINT *pp; /* current point */
MWCOORD miny; /* minimum row */
MWCOORD maxy; /* maximum row */
MWCOORD minx; /* minimum column */
MWCOORD maxx; /* maximum column */
int i; /* counter */
 
if (count <= 0)
return;
 
/* First determine the minimum and maximum rows for the polygon. */
pp = points;
miny = pp->y;
maxy = pp->y;
for (i = count; i-- > 0; pp++) {
if (miny > pp->y) miny = pp->y;
if (maxy < pp->y) maxy = pp->y;
}
if (miny < 0)
miny = 0;
if (maxy >= psd->yvirtres)
maxy = psd->yvirtres - 1;
if (miny > maxy)
return;
 
/* Now for each row, scan the list of points and determine the
* minimum and maximum x coordinate for each line, and plot the row.
* The last point connects with the first point automatically.
*/
for (; miny <= maxy; miny++) {
minx = MAX_MWCOORD;
maxx = MIN_MWCOORD;
pp = points;
for (i = count; --i > 0; pp++)
extendrow(miny, pp[0].x, pp[0].y, pp[1].x, pp[1].y,
&minx, &maxx);
extendrow(miny, pp[0].x, pp[0].y, points[0].x, points[0].y,
&minx, &maxx);
 
if (minx <= maxx)
drawrow(psd, minx, maxx, miny);
}
GdFixCursor(psd);
}
#endif
 
#if 0 /* irregular polygon fill, uses edge table, malloc, qsort*/
/*
* Fill a polygon in the foreground color, applying clipping if necessary.
* The last point may be a duplicate of the first point, but this is
* not required.
* Note: this routine correctly draws convex, concave, regular,
* and irregular polygons.
*/
#define USE_FLOAT HAVEFLOAT /* set to use floating point*/
 
#define swap(a,b) do { a ^= b; b ^= a; a ^= b; } while (0)
 
typedef struct {
int x1, y1, x2, y2;
#if USE_FLOAT
double x, m;
#else
int cx, fn, mn, d;
#endif
} edge_t;
 
static int
edge_cmp(const void *lvp, const void *rvp)
{
/* convert from void pointers to structure pointers */
const edge_t *lp = (const edge_t *)lvp;
const edge_t *rp = (const edge_t *)rvp;
 
/* if the minimum y values are different, sort on minimum y */
if (lp->y1 != rp->y1)
return lp->y1 - rp->y1;
 
/* if the current x values are different, sort on current x */
#if USE_FLOAT
if (lp->x < rp->x)
return -1;
else if (lp->x > rp->x)
return +1;
#else
if (lp->cx != rp->cx)
return lp->cx - rp->cx;
#endif
 
/* otherwise they are equal */
return 0;
}
 
void
GdFillPoly(PSD psd, int count, MWPOINT * pointtable)
{
edge_t *get; /* global edge table */
int nge = 0; /* num global edges */
int cge = 0; /* cur global edge */
 
edge_t *aet; /* active edge table */
int nae = 0; /* num active edges */
 
int i, y;
 
if (count < 3) {
/* error, polygons require at least three edges (a triangle) */
return;
}
get = (edge_t *) calloc(count, sizeof(edge_t));
aet = (edge_t *) calloc(count, sizeof(edge_t));
 
if ((get == 0) || (aet == 0)) {
/* error, couldn't allocate one or both of the needed tables */
if (get)
free(get);
if (aet)
free(aet);
return;
}
/* setup the global edge table */
for (i = 0; i < count; ++i) {
get[nge].x1 = pointtable[i].x;
get[nge].y1 = pointtable[i].y;
get[nge].x2 = pointtable[(i + 1) % count].x;
get[nge].y2 = pointtable[(i + 1) % count].y;
if (get[nge].y1 != get[nge].y2) {
if (get[nge].y1 > get[nge].y2) {
swap(get[nge].x1, get[nge].x2);
swap(get[nge].y1, get[nge].y2);
}
#if USE_FLOAT
get[nge].x = get[nge].x1;
get[nge].m = get[nge].x2 - get[nge].x1;
get[nge].m /= get[nge].y2 - get[nge].y1;
#else
get[nge].cx = get[nge].x1;
get[nge].mn = get[nge].x2 - get[nge].x1;
get[nge].d = get[nge].y2 - get[nge].y1;
get[nge].fn = get[nge].mn / 2;
#endif
++nge;
}
}
 
qsort(get, nge, sizeof(get[0]), edge_cmp);
 
/* start with the lowest y in the table */
y = get[0].y1;
 
do {
 
/* add edges to the active table from the global table */
while ((nge > 0) && (get[cge].y1 == y)) {
aet[nae] = get[cge++];
--nge;
aet[nae++].y1 = 0;
}
 
qsort(aet, nae, sizeof(aet[0]), edge_cmp);
 
/* using odd parity, render alternating line segments */
for (i = 1; i < nae; i += 2) {
#if USE_FLOAT
int l = (int)aet[i - 1].x;
int r = (int)aet[i].x;
#else
int l = (int)aet[i - 1].cx;
int r = (int)aet[i].cx;
#endif
if (r > l)
drawrow(psd, l, r - 1, y);
}
 
/* prepare for the next scan line */
++y;
 
/* remove inactive edges from the active edge table */
/* or update the current x position of active edges */
for (i = 0; i < nae; ++i) {
if (aet[i].y2 == y)
aet[i--] = aet[--nae];
else {
#if USE_FLOAT
aet[i].x += aet[i].m;
#else
aet[i].fn += aet[i].mn;
if (aet[i].fn < 0) {
aet[i].cx += aet[i].fn / aet[i].d - 1;
aet[i].fn %= aet[i].d;
aet[i].fn += aet[i].d;
}
if (aet[i].fn >= aet[i].d) {
aet[i].cx += aet[i].fn / aet[i].d;
aet[i].fn %= aet[i].d;
}
#endif
}
}
 
/* keep doing this while there are any edges left */
} while ((nae > 0) || (nge > 0));
 
/* all done, free the edge tables */
free(get);
free(aet);
 
GdFixCursor(psd);
}
#endif
/devpalgray4.c
0,0 → 1,23
/*
* 4bpp (16 color) grayscale palette
*/
#include "device.h"
 
MWPALENTRY mwstdpal4[16] = {
RGBDEF( 0, 0, 0 ),
RGBDEF( 17, 17, 17 ),
RGBDEF( 34, 34, 34 ),
RGBDEF( 51, 51, 51 ),
RGBDEF( 68, 68, 68 ),
RGBDEF( 85, 85, 85 ),
RGBDEF( 102, 102, 102 ),
RGBDEF( 119, 119, 119 ),
RGBDEF( 136, 136, 136 ),
RGBDEF( 153, 153, 153 ),
RGBDEF( 170, 170, 170 ),
RGBDEF( 187, 187, 187 ),
RGBDEF( 204, 204, 204 ),
RGBDEF( 221, 221, 221 ),
RGBDEF( 238, 238, 238 ),
RGBDEF( 255, 255, 255 )
};
/devrgn.c
0,0 → 1,1426
/*
* Portions Copyright (c) 1999, 2000 Greg Haerr <greg@censoft.com>
* Somewhat less shamelessly ripped from the Wine distribution
*
* Device-independent multi-rectangle clipping routines.
*
* GDI region objects. Shamelessly ripped out from the X11 distribution
* Thanks for the nice licence.
*
* Copyright 1993, 1994, 1995 Alexandre Julliard
* Modifications and additions: Copyright 1998 Huw Davies
*/
/************************************************************************
 
Copyright (c) 1987, 1988 X Consortium
 
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.
 
 
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
 
All Rights Reserved
 
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Digital not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
 
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
 
************************************************************************/
/*
* The functions in this file implement the Region abstraction, similar to one
* used in the X11 sample server. A Region is simply an area, as the name
* implies, and is implemented as a "y-x-banded" array of rectangles. To
* explain: Each Region is made up of a certain number of rectangles sorted
* by y coordinate first, and then by x coordinate.
*
* Furthermore, the rectangles are banded such that every rectangle with a
* given upper-left y coordinate (y1) will have the same lower-right y
* coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
* will span the entire vertical distance of the band. This means that some
* areas that could be merged into a taller rectangle will be represented as
* several shorter rectangles to account for shorter rectangles to its left
* or right but within its "vertical scope".
*
* An added constraint on the rectangles is that they must cover as much
* horizontal area as possible. E.g. no two rectangles in a band are allowed
* to touch.
*
* Whenever possible, bands will be merged together to cover a greater vertical
* distance (and thus reduce the number of rectangles). Two bands can be merged
* only if the bottom of one touches the top of the other and they have
* rectangles in the same places (of the same width, of course). This maintains
* the y-x-banding that's so nice to have...
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "device.h"
 
typedef void (*voidProcp)();
 
/* 1 if two RECTs overlap.
* 0 if two RECTs do not overlap.
*/
#define EXTENTCHECK(r1, r2) \
((r1)->right > (r2)->left && \
(r1)->left < (r2)->right && \
(r1)->bottom > (r2)->top && \
(r1)->top < (r2)->bottom)
 
/*
* Check to see if there is enough memory in the present region.
*/
#define MEMCHECK(reg, rect, firstrect){\
if ((reg)->numRects >= ((reg)->size - 1)){\
(firstrect) = realloc(\
(firstrect), (2 * (sizeof(MWRECT)) * ((reg)->size)));\
if ((firstrect) == 0)\
return;\
(reg)->size *= 2;\
(rect) = &(firstrect)[(reg)->numRects];\
}\
}
 
#define REGION_NOT_EMPTY(pReg) pReg->numRects
 
#define EMPTY_REGION(pReg) { \
(pReg)->numRects = 0; \
(pReg)->extents.left = (pReg)->extents.top = 0; \
(pReg)->extents.right = (pReg)->extents.bottom = 0; \
(pReg)->type = MWREGION_NULL; \
}
 
#define INRECT(r, x, y) \
( ( ((r).right > x)) && \
( ((r).left <= x)) && \
( ((r).bottom > y)) && \
( ((r).top <= y)) )
 
/* return TRUE if point is in region*/
MWBOOL
GdPtInRegion(MWCLIPREGION *rgn, MWCOORD x, MWCOORD y)
{
int i;
 
if (rgn->numRects > 0 && INRECT(rgn->extents, x, y))
for (i = 0; i < rgn->numRects; i++)
if (INRECT (rgn->rects[i], x, y))
return TRUE;
return FALSE;
}
 
/* return whether rectangle is all in, partly in, or out of region*/
int
GdRectInRegion(MWCLIPREGION *rgn, const MWRECT *rect)
{
MWRECT * pCurRect;
MWRECT * pRectEnd;
MWCOORD rx, ry;
MWBOOL partIn, partOut;
 
/* this is (just) a useful optimization */
if (!rgn->numRects || !EXTENTCHECK(&rgn->extents, rect))
return MWRECT_OUT;
 
partOut = FALSE;
partIn = FALSE;
rx = rect->left;
ry = rect->top;
 
/*
* can stop when both partOut and partIn are TRUE,
* or we reach rect->bottom
*/
for (pCurRect = rgn->rects, pRectEnd = pCurRect + rgn->numRects;
pCurRect < pRectEnd; pCurRect++) {
 
if (pCurRect->bottom <= ry)
continue; /* not far enough down yet*/
 
if (pCurRect->top > ry) {
partOut = TRUE; /* missed part of rectangle above */
if (partIn || (pCurRect->top >= rect->bottom))
break;
ry = pCurRect->top; /* x guaranteed to be == rect->left */
}
 
if (pCurRect->right <= rx)
continue; /* not far enough over yet */
 
if (pCurRect->left > rx) {
partOut = TRUE; /* missed part of rectangle to left */
if (partIn)
break;
}
 
if (pCurRect->left < rect->right) {
partIn = TRUE; /* definitely overlap */
if (partOut)
break;
}
 
if (pCurRect->right >= rect->right) {
ry = pCurRect->bottom; /* finished with this band */
if (ry >= rect->bottom)
break;
rx = rect->left; /* reset x out to left again */
} else {
/*
* Because boxes in a band are maximal width, if the first box
* to overlap the rectangle doesn't completely cover it in that
* band, the rectangle must be partially out, since some of it
* will be uncovered in that band. partIn will have been set true
* by now...
*/
break;
}
}
 
return(partIn ? ((ry < rect->bottom) ? MWRECT_PARTIN : MWRECT_ALLIN) :
MWRECT_OUT);
}
 
#if 0000
/* Returns TRUE if rect is at least partly inside rgn*/
MWBOOL
GdRectInRegion(MWCLIPREGION *rgn, const MWRECT *rect)
{
MWRECT *pCurRect, *pRectEnd;
MWBOOL ret = FALSE;
 
/* this is (just) a useful optimization */
if ((rgn->numRects > 0) && EXTENTCHECK(&rgn->extents, rect))
{
for (pCurRect = rgn->rects, pRectEnd = pCurRect +
rgn->numRects; pCurRect < pRectEnd; pCurRect++)
{
if (pCurRect->bottom <= rect->top)
continue; /* not far enough down yet */
 
if (pCurRect->top >= rect->bottom) {
ret = FALSE; /* too far down */
break;
}
 
if (pCurRect->right <= rect->left)
continue; /* not far enough over yet */
 
if (pCurRect->left >= rect->right) {
continue;
}
 
ret = TRUE;
break;
}
}
return ret;
}
#endif
 
static MWBOOL
EQUALRECT(MWRECT *r1, MWRECT *r2)
{
return ((r1->left == r2->left) && (r1->right == r2->right) &&
(r1->top == r2->top) && (r1->bottom == r2->bottom));
}
 
MWBOOL
GdEqualRegion(MWCLIPREGION *r1, MWCLIPREGION *r2)
{
int i;
 
if (r1->numRects != r2->numRects)
return FALSE;
if (r1->numRects == 0)
return TRUE;
if (!EQUALRECT(&r1->extents, &r2->extents))
return FALSE;
for (i = 0; i < r1->numRects; i++) {
if (!EQUALRECT(r1->rects + i, r2->rects + i))
return FALSE;
}
return TRUE;
}
 
MWBOOL
GdEmptyRegion(MWCLIPREGION *rgn)
{
return rgn->numRects == 0;
}
 
/*
* Create a new empty MWCLIPREGION.
*/
MWCLIPREGION *
GdAllocRegion(void)
{
MWCLIPREGION *rgn;
 
if ((rgn = malloc(sizeof( MWCLIPREGION ))))
{
if ((rgn->rects = malloc(sizeof( MWRECT ))))
{
rgn->size = 1;
EMPTY_REGION(rgn);
return rgn;
}
free(rgn);
}
return NULL;
}
 
MWCLIPREGION *
GdAllocRectRegion(MWCOORD left, MWCOORD top, MWCOORD right, MWCOORD bottom)
{
MWCLIPREGION *rgn;
 
rgn = GdAllocRegion();
if (rgn)
GdSetRectRegion(rgn, left, top, right, bottom);
return rgn;
}
 
MWCLIPREGION *
GdAllocRectRegionIndirect(MWRECT *prc)
{
return GdAllocRectRegion(prc->left, prc->top, prc->right, prc->bottom);
}
 
void
GdSetRectRegion(MWCLIPREGION *rgn, MWCOORD left, MWCOORD top, MWCOORD right,
MWCOORD bottom)
{
if (left != right && top != bottom) {
rgn->rects->left = rgn->extents.left = left;
rgn->rects->top = rgn->extents.top = top;
rgn->rects->right = rgn->extents.right = right;
rgn->rects->bottom = rgn->extents.bottom = bottom;
rgn->numRects = 1;
rgn->type = MWREGION_SIMPLE;
} else
EMPTY_REGION(rgn);
}
 
void
GdSetRectRegionIndirect(MWCLIPREGION *rgn, MWRECT *prc)
{
GdSetRectRegion(rgn, prc->left, prc->top, prc->right, prc->bottom);
}
 
void
GdDestroyRegion(MWCLIPREGION *rgn)
{
if(rgn) {
free(rgn->rects);
free(rgn);
}
}
 
void
GdOffsetRegion(MWCLIPREGION *rgn, MWCOORD x, MWCOORD y)
{
int nbox = rgn->numRects;
MWRECT *pbox = rgn->rects;
 
if(nbox && (x || y)) {
while(nbox--) {
pbox->left += x;
pbox->right += x;
pbox->top += y;
pbox->bottom += y;
pbox++;
}
rgn->extents.left += x;
rgn->extents.right += x;
rgn->extents.top += y;
rgn->extents.bottom += y;
}
}
 
/* get bounding box for region, return region type*/
int
GdGetRegionBox(MWCLIPREGION *rgn, MWRECT *prc)
{
*prc = rgn->extents;
return rgn->type;
}
 
/***********************************************************************
* GdUnionRectWithRegion
* Adds a rectangle to a MWCLIPREGION
*/
void
GdUnionRectWithRegion(const MWRECT *rect, MWCLIPREGION *rgn)
{
MWCLIPREGION region;
 
region.rects = &region.extents;
region.numRects = 1;
region.size = 1;
region.type = MWREGION_SIMPLE;
region.extents = *rect;
GdUnionRegion(rgn, rgn, &region);
}
 
/***********************************************************************
* GdSubtractRectWithRegion
* Subtracts a rectangle from a MWCLIPREGION
*/
void
GdSubtractRectFromRegion(const MWRECT *rect, MWCLIPREGION *rgn)
{
MWCLIPREGION region;
 
region.rects = &region.extents;
region.numRects = 1;
region.size = 1;
region.type = MWREGION_SIMPLE;
region.extents = *rect;
GdSubtractRegion(rgn, rgn, &region);
}
 
 
/***********************************************************************
* GdCopyRegion
*/
void
GdCopyRegion(MWCLIPREGION *dst, MWCLIPREGION *src)
{
if (dst != src) /* don't want to copy to itself */
{
if (dst->size < src->numRects)
{
if (! (dst->rects = realloc( dst->rects, src->numRects * sizeof(MWRECT))))
return;
dst->size = src->numRects;
}
dst->numRects = src->numRects;
dst->extents.left = src->extents.left;
dst->extents.top = src->extents.top;
dst->extents.right = src->extents.right;
dst->extents.bottom = src->extents.bottom;
dst->type = src->type;
 
memcpy((char *) dst->rects, (char *) src->rects,
(int) (src->numRects * sizeof(MWRECT)));
}
}
 
 
/***********************************************************************
* REGION_SetExtents
* Re-calculate the extents of a region
*/
static void
REGION_SetExtents (MWCLIPREGION *pReg)
{
MWRECT *pRect, *pRectEnd, *pExtents;
 
if (pReg->numRects == 0)
{
pReg->extents.left = 0;
pReg->extents.top = 0;
pReg->extents.right = 0;
pReg->extents.bottom = 0;
return;
}
 
pExtents = &pReg->extents;
pRect = pReg->rects;
pRectEnd = &pRect[pReg->numRects - 1];
 
/*
* Since pRect is the first rectangle in the region, it must have the
* smallest top and since pRectEnd is the last rectangle in the region,
* it must have the largest bottom, because of banding. Initialize left and
* right from pRect and pRectEnd, resp., as good things to initialize them
* to...
*/
pExtents->left = pRect->left;
pExtents->top = pRect->top;
pExtents->right = pRectEnd->right;
pExtents->bottom = pRectEnd->bottom;
 
while (pRect <= pRectEnd)
{
if (pRect->left < pExtents->left)
pExtents->left = pRect->left;
if (pRect->right > pExtents->right)
pExtents->right = pRect->right;
pRect++;
}
}
 
 
/***********************************************************************
* REGION_Coalesce
*
* Attempt to merge the rects in the current band with those in the
* previous one. Used only by REGION_RegionOp.
*
* Results:
* The new index for the previous band.
*
* Side Effects:
* If coalescing takes place:
* - rectangles in the previous band will have their bottom fields
* altered.
* - pReg->numRects will be decreased.
*
*/
static MWCOORD
REGION_Coalesce (
MWCLIPREGION *pReg, /* Region to coalesce */
MWCOORD prevStart, /* Index of start of previous band */
MWCOORD curStart /* Index of start of current band */
) {
MWRECT *pPrevRect; /* Current rect in previous band */
MWRECT *pCurRect; /* Current rect in current band */
MWRECT *pRegEnd; /* End of region */
MWCOORD curNumRects; /* Number of rectangles in current band */
MWCOORD prevNumRects; /* Number of rectangles in previous band */
MWCOORD bandtop; /* top coordinate for current band */
 
pRegEnd = &pReg->rects[pReg->numRects];
 
pPrevRect = &pReg->rects[prevStart];
prevNumRects = curStart - prevStart;
 
/*
* Figure out how many rectangles are in the current band. Have to do
* this because multiple bands could have been added in REGION_RegionOp
* at the end when one region has been exhausted.
*/
pCurRect = &pReg->rects[curStart];
bandtop = pCurRect->top;
for (curNumRects = 0;
(pCurRect != pRegEnd) && (pCurRect->top == bandtop);
curNumRects++)
{
pCurRect++;
}
if (pCurRect != pRegEnd)
{
/*
* If more than one band was added, we have to find the start
* of the last band added so the next coalescing job can start
* at the right place... (given when multiple bands are added,
* this may be pointless -- see above).
*/
pRegEnd--;
while (pRegEnd[-1].top == pRegEnd->top)
{
pRegEnd--;
}
curStart = pRegEnd - pReg->rects;
pRegEnd = pReg->rects + pReg->numRects;
}
if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
pCurRect -= curNumRects;
/*
* The bands may only be coalesced if the bottom of the previous
* matches the top scanline of the current.
*/
if (pPrevRect->bottom == pCurRect->top)
{
/*
* Make sure the bands have rects in the same places. This
* assumes that rects have been added in such a way that they
* cover the most area possible. I.e. two rects in a band must
* have some horizontal space between them.
*/
do
{
if ((pPrevRect->left != pCurRect->left) ||
(pPrevRect->right != pCurRect->right))
{
/*
* The bands don't line up so they can't be coalesced.
*/
return (curStart);
}
pPrevRect++;
pCurRect++;
prevNumRects -= 1;
} while (prevNumRects != 0);
 
pReg->numRects -= curNumRects;
pCurRect -= curNumRects;
pPrevRect -= curNumRects;
 
/*
* The bands may be merged, so set the bottom of each rect
* in the previous band to that of the corresponding rect in
* the current band.
*/
do
{
pPrevRect->bottom = pCurRect->bottom;
pPrevRect++;
pCurRect++;
curNumRects -= 1;
} while (curNumRects != 0);
 
/*
* If only one band was added to the region, we have to backup
* curStart to the start of the previous band.
*
* If more than one band was added to the region, copy the
* other bands down. The assumption here is that the other bands
* came from the same region as the current one and no further
* coalescing can be done on them since it's all been done
* already... curStart is already in the right place.
*/
if (pCurRect == pRegEnd)
{
curStart = prevStart;
}
else
{
do
{
*pPrevRect++ = *pCurRect++;
} while (pCurRect != pRegEnd);
}
}
}
return (curStart);
}
 
/***********************************************************************
* REGION_RegionOp
*
* Apply an operation to two regions. Called by GdUnion,
* GdXor, GdSubtract, GdIntersect...
*
* Results:
* None.
*
* Side Effects:
* The new region is overwritten.
*
* Notes:
* The idea behind this function is to view the two regions as sets.
* Together they cover a rectangle of area that this function divides
* into horizontal bands where points are covered only by one region
* or by both. For the first case, the nonOverlapFunc is called with
* each the band and the band's upper and lower extents. For the
* second, the overlapFunc is called to process the entire band. It
* is responsible for clipping the rectangles in the band, though
* this function provides the boundaries.
* At the end of each band, the new region is coalesced, if possible,
* to reduce the number of rectangles in the region.
*
*/
static void
REGION_RegionOp(
MWCLIPREGION *newReg, /* Place to store result */
MWCLIPREGION *reg1, /* First region in operation */
MWCLIPREGION *reg2, /* 2nd region in operation */
void (*overlapFunc)(), /* Function to call for over-lapping bands */
void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
void (*nonOverlap2Func)() /* Function to call for non-overlapping bands in region 2 */
) {
MWRECT *r1; /* Pointer into first region */
MWRECT *r2; /* Pointer into 2d region */
MWRECT *r1End; /* End of 1st region */
MWRECT *r2End; /* End of 2d region */
MWCOORD ybot; /* Bottom of intersection */
MWCOORD ytop; /* Top of intersection */
MWRECT *oldRects; /* Old rects for newReg */
MWCOORD prevBand; /* Index of start of
* previous band in newReg */
MWCOORD curBand; /* Index of start of current
* band in newReg */
MWRECT *r1BandEnd; /* End of current band in r1 */
MWRECT *r2BandEnd; /* End of current band in r2 */
MWCOORD top; /* Top of non-overlapping band */
MWCOORD bot; /* Bottom of non-overlapping band */
/*
* Initialization:
* set r1, r2, r1End and r2End appropriately, preserve the important
* parts of the destination region until the end in case it's one of
* the two source regions, then mark the "new" region empty, allocating
* another array of rectangles for it to use.
*/
r1 = reg1->rects;
r2 = reg2->rects;
r1End = r1 + reg1->numRects;
r2End = r2 + reg2->numRects;
 
/*
* newReg may be one of the src regions so we can't empty it. We keep a
* note of its rects pointer (so that we can free them later), preserve its
* extents and simply set numRects to zero.
*/
 
oldRects = newReg->rects;
newReg->numRects = 0;
 
/*
* Allocate a reasonable number of rectangles for the new region. The idea
* is to allocate enough so the individual functions don't need to
* reallocate and copy the array, which is time consuming, yet we don't
* have to worry about using too much memory. I hope to be able to
* nuke the Xrealloc() at the end of this function eventually.
*/
newReg->size = MWMAX(reg1->numRects,reg2->numRects) * 2;
 
if (! (newReg->rects = malloc( sizeof(MWRECT) * newReg->size )))
{
newReg->size = 0;
return;
}
/*
* Initialize ybot and ytop.
* In the upcoming loop, ybot and ytop serve different functions depending
* on whether the band being handled is an overlapping or non-overlapping
* band.
* In the case of a non-overlapping band (only one of the regions
* has points in the band), ybot is the bottom of the most recent
* intersection and thus clips the top of the rectangles in that band.
* ytop is the top of the next intersection between the two regions and
* serves to clip the bottom of the rectangles in the current band.
* For an overlapping band (where the two regions intersect), ytop clips
* the top of the rectangles of both regions and ybot clips the bottoms.
*/
if (reg1->extents.top < reg2->extents.top)
ybot = reg1->extents.top;
else
ybot = reg2->extents.top;
/*
* prevBand serves to mark the start of the previous band so rectangles
* can be coalesced into larger rectangles. qv. miCoalesce, above.
* In the beginning, there is no previous band, so prevBand == curBand
* (curBand is set later on, of course, but the first band will always
* start at index 0). prevBand and curBand must be indices because of
* the possible expansion, and resultant moving, of the new region's
* array of rectangles.
*/
prevBand = 0;
do
{
curBand = newReg->numRects;
 
/*
* This algorithm proceeds one source-band (as opposed to a
* destination band, which is determined by where the two regions
* intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
* rectangle after the last one in the current band for their
* respective regions.
*/
r1BandEnd = r1;
while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
{
r1BandEnd++;
}
r2BandEnd = r2;
while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
{
r2BandEnd++;
}
/*
* First handle the band that doesn't intersect, if any.
*
* Note that attention is restricted to one band in the
* non-intersecting region at once, so if a region has n
* bands between the current position and the next place it overlaps
* the other, this entire loop will be passed through n times.
*/
if (r1->top < r2->top)
{
top = MWMAX(r1->top,ybot);
bot = MWMIN(r1->bottom,r2->top);
 
if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
{
(* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
}
 
ytop = r2->top;
}
else if (r2->top < r1->top)
{
top = MWMAX(r2->top,ybot);
bot = MWMIN(r2->bottom,r1->top);
 
if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
{
(* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
}
 
ytop = r1->top;
}
else
{
ytop = r1->top;
}
 
/*
* If any rectangles got added to the region, try and coalesce them
* with rectangles from the previous band. Note we could just do
* this test in miCoalesce, but some machines incur a not
* inconsiderable cost for function calls, so...
*/
if (newReg->numRects != curBand)
{
prevBand = REGION_Coalesce (newReg, prevBand, curBand);
}
 
/*
* Now see if we've hit an intersecting band. The two bands only
* intersect if ybot > ytop
*/
ybot = MWMIN(r1->bottom, r2->bottom);
curBand = newReg->numRects;
if (ybot > ytop)
{
(* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
 
}
if (newReg->numRects != curBand)
{
prevBand = REGION_Coalesce (newReg, prevBand, curBand);
}
 
/*
* If we've finished with a band (bottom == ybot) we skip forward
* in the region to the next band.
*/
if (r1->bottom == ybot)
{
r1 = r1BandEnd;
}
if (r2->bottom == ybot)
{
r2 = r2BandEnd;
}
} while ((r1 != r1End) && (r2 != r2End));
 
/*
* Deal with whichever region still has rectangles left.
*/
curBand = newReg->numRects;
if (r1 != r1End)
{
if (nonOverlap1Func != (void (*)())NULL)
{
do
{
r1BandEnd = r1;
while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
{
r1BandEnd++;
}
(* nonOverlap1Func) (newReg, r1, r1BandEnd,
MWMAX(r1->top,ybot), r1->bottom);
r1 = r1BandEnd;
} while (r1 != r1End);
}
}
else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
{
do
{
r2BandEnd = r2;
while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
{
r2BandEnd++;
}
(* nonOverlap2Func) (newReg, r2, r2BandEnd,
MWMAX(r2->top,ybot), r2->bottom);
r2 = r2BandEnd;
} while (r2 != r2End);
}
 
if (newReg->numRects != curBand)
{
(void) REGION_Coalesce (newReg, prevBand, curBand);
}
 
/*
* A bit of cleanup. To keep regions from growing without bound,
* we shrink the array of rectangles to match the new number of
* rectangles in the region. This never goes to 0, however...
*
* Only do this stuff if the number of rectangles allocated is more than
* twice the number of rectangles in the region (a simple optimization...).
*/
if (newReg->numRects < (newReg->size >> 1))
{
if (REGION_NOT_EMPTY(newReg))
{
MWRECT *prev_rects = newReg->rects;
newReg->size = newReg->numRects;
newReg->rects = realloc( newReg->rects, sizeof(MWRECT) * newReg->size );
if (! newReg->rects)
newReg->rects = prev_rects;
}
else
{
/*
* No point in doing the extra work involved in an Xrealloc if
* the region is empty
*/
newReg->size = 1;
free( newReg->rects );
newReg->rects = malloc( sizeof(MWRECT) );
}
}
free( oldRects );
}
 
/***********************************************************************
* Region Intersection
***********************************************************************/
 
 
/***********************************************************************
* REGION_IntersectO
*
* Handle an overlapping band for REGION_Intersect.
*
* Results:
* None.
*
* Side Effects:
* Rectangles may be added to the region.
*
*/
static void
REGION_IntersectO(MWCLIPREGION *pReg, MWRECT *r1, MWRECT *r1End,
MWRECT *r2, MWRECT *r2End, MWCOORD top, MWCOORD bottom)
 
{
MWCOORD left, right;
MWRECT *pNextRect;
 
pNextRect = &pReg->rects[pReg->numRects];
 
while ((r1 != r1End) && (r2 != r2End))
{
left = MWMAX(r1->left, r2->left);
right = MWMIN(r1->right, r2->right);
 
/*
* If there's any overlap between the two rectangles, add that
* overlap to the new region.
* There's no need to check for subsumption because the only way
* such a need could arise is if some region has two rectangles
* right next to each other. Since that should never happen...
*/
if (left < right)
{
MEMCHECK(pReg, pNextRect, pReg->rects);
pNextRect->left = left;
pNextRect->top = top;
pNextRect->right = right;
pNextRect->bottom = bottom;
pReg->numRects += 1;
pNextRect++;
}
 
/*
* Need to advance the pointers. Shift the one that extends
* to the right the least, since the other still has a chance to
* overlap with that region's next rectangle, if you see what I mean.
*/
if (r1->right < r2->right)
{
r1++;
}
else if (r2->right < r1->right)
{
r2++;
}
else
{
r1++;
r2++;
}
}
}
 
/***********************************************************************
* GdIntersectRegion
*/
void
GdIntersectRegion(MWCLIPREGION *newReg, MWCLIPREGION *reg1, MWCLIPREGION *reg2)
{
/* check for trivial reject */
if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
(!EXTENTCHECK(&reg1->extents, &reg2->extents)))
newReg->numRects = 0;
else
REGION_RegionOp (newReg, reg1, reg2,
(voidProcp) REGION_IntersectO, (voidProcp) NULL, (voidProcp) NULL);
/*
* Can't alter newReg's extents before we call miRegionOp because
* it might be one of the source regions and miRegionOp depends
* on the extents of those regions being the same. Besides, this
* way there's no checking against rectangles that will be nuked
* due to coalescing, so we have to examine fewer rectangles.
*/
REGION_SetExtents(newReg);
newReg->type = (newReg->numRects) ? MWREGION_COMPLEX : MWREGION_NULL ;
}
 
/***********************************************************************
* Region Union
***********************************************************************/
 
/***********************************************************************
* REGION_UnionNonO
*
* Handle a non-overlapping band for the union operation. Just
* Adds the rectangles into the region. Doesn't have to check for
* subsumption or anything.
*
* Results:
* None.
*
* Side Effects:
* pReg->numRects is incremented and the final rectangles overwritten
* with the rectangles we're passed.
*
*/
static void
REGION_UnionNonO(MWCLIPREGION *pReg,MWRECT *r,MWRECT *rEnd,MWCOORD top,
MWCOORD bottom)
{
MWRECT *pNextRect;
 
pNextRect = &pReg->rects[pReg->numRects];
 
while (r != rEnd)
{
MEMCHECK(pReg, pNextRect, pReg->rects);
pNextRect->left = r->left;
pNextRect->top = top;
pNextRect->right = r->right;
pNextRect->bottom = bottom;
pReg->numRects += 1;
pNextRect++;
r++;
}
}
 
/***********************************************************************
* REGION_UnionO
*
* Handle an overlapping band for the union operation. Picks the
* left-most rectangle each time and merges it into the region.
*
* Results:
* None.
*
* Side Effects:
* Rectangles are overwritten in pReg->rects and pReg->numRects will
* be changed.
*
*/
static void
REGION_UnionO(MWCLIPREGION *pReg, MWRECT *r1, MWRECT *r1End,
MWRECT *r2, MWRECT *r2End, MWCOORD top, MWCOORD bottom)
{
MWRECT *pNextRect;
pNextRect = &pReg->rects[pReg->numRects];
 
#define MERGERECT(r) \
if ((pReg->numRects != 0) && \
(pNextRect[-1].top == top) && \
(pNextRect[-1].bottom == bottom) && \
(pNextRect[-1].right >= r->left)) \
{ \
if (pNextRect[-1].right < r->right) \
{ \
pNextRect[-1].right = r->right; \
} \
} \
else \
{ \
MEMCHECK(pReg, pNextRect, pReg->rects); \
pNextRect->top = top; \
pNextRect->bottom = bottom; \
pNextRect->left = r->left; \
pNextRect->right = r->right; \
pReg->numRects += 1; \
pNextRect += 1; \
} \
r++;
while ((r1 != r1End) && (r2 != r2End))
{
if (r1->left < r2->left)
{
MERGERECT(r1);
}
else
{
MERGERECT(r2);
}
}
if (r1 != r1End)
{
do
{
MERGERECT(r1);
} while (r1 != r1End);
}
else while (r2 != r2End)
{
MERGERECT(r2);
}
}
 
/***********************************************************************
* GdUnionRegion
*/
void
GdUnionRegion(MWCLIPREGION *newReg, MWCLIPREGION *reg1, MWCLIPREGION *reg2)
{
/* checks all the simple cases */
 
/*
* Region 1 and 2 are the same or region 1 is empty
*/
if ( (reg1 == reg2) || (!(reg1->numRects)) )
{
if (newReg != reg2)
GdCopyRegion(newReg, reg2);
return;
}
 
/*
* if nothing to union (region 2 empty)
*/
if (!(reg2->numRects))
{
if (newReg != reg1)
GdCopyRegion(newReg, reg1);
return;
}
 
/*
* Region 1 completely subsumes region 2
*/
if ((reg1->numRects == 1) &&
(reg1->extents.left <= reg2->extents.left) &&
(reg1->extents.top <= reg2->extents.top) &&
(reg1->extents.right >= reg2->extents.right) &&
(reg1->extents.bottom >= reg2->extents.bottom))
{
if (newReg != reg1)
GdCopyRegion(newReg, reg1);
return;
}
 
/*
* Region 2 completely subsumes region 1
*/
if ((reg2->numRects == 1) &&
(reg2->extents.left <= reg1->extents.left) &&
(reg2->extents.top <= reg1->extents.top) &&
(reg2->extents.right >= reg1->extents.right) &&
(reg2->extents.bottom >= reg1->extents.bottom))
{
if (newReg != reg2)
GdCopyRegion(newReg, reg2);
return;
}
 
REGION_RegionOp (newReg, reg1, reg2, (voidProcp) REGION_UnionO,
(voidProcp) REGION_UnionNonO, (voidProcp) REGION_UnionNonO);
 
newReg->extents.left = MWMIN(reg1->extents.left, reg2->extents.left);
newReg->extents.top = MWMIN(reg1->extents.top, reg2->extents.top);
newReg->extents.right = MWMAX(reg1->extents.right, reg2->extents.right);
newReg->extents.bottom = MWMAX(reg1->extents.bottom, reg2->extents.bottom);
newReg->type = (newReg->numRects) ? MWREGION_COMPLEX : MWREGION_NULL ;
}
 
/***********************************************************************
* Region Subtraction
***********************************************************************/
 
/***********************************************************************
* REGION_SubtractNonO1
*
* Deal with non-overlapping band for subtraction. Any parts from
* region 2 we discard. Anything from region 1 we add to the region.
*
* Results:
* None.
*
* Side Effects:
* pReg may be affected.
*
*/
static void
REGION_SubtractNonO1(MWCLIPREGION *pReg, MWRECT *r, MWRECT *rEnd,
MWCOORD top, MWCOORD bottom)
{
MWRECT *pNextRect;
pNextRect = &pReg->rects[pReg->numRects];
while (r != rEnd)
{
MEMCHECK(pReg, pNextRect, pReg->rects);
pNextRect->left = r->left;
pNextRect->top = top;
pNextRect->right = r->right;
pNextRect->bottom = bottom;
pReg->numRects += 1;
pNextRect++;
r++;
}
}
 
 
/***********************************************************************
* REGION_SubtractO
*
* Overlapping band subtraction. x1 is the left-most point not yet
* checked.
*
* Results:
* None.
*
* Side Effects:
* pReg may have rectangles added to it.
*
*/
static void
REGION_SubtractO(MWCLIPREGION *pReg, MWRECT *r1, MWRECT *r1End,
MWRECT *r2, MWRECT *r2End, MWCOORD top, MWCOORD bottom)
{
MWRECT *pNextRect;
MWCOORD left;
left = r1->left;
pNextRect = &pReg->rects[pReg->numRects];
 
while ((r1 != r1End) && (r2 != r2End))
{
if (r2->right <= left)
{
/*
* Subtrahend missed the boat: go to next subtrahend.
*/
r2++;
}
else if (r2->left <= left)
{
/*
* Subtrahend preceeds minuend: nuke left edge of minuend.
*/
left = r2->right;
if (left >= r1->right)
{
/*
* Minuend completely covered: advance to next minuend and
* reset left fence to edge of new minuend.
*/
r1++;
if (r1 != r1End)
left = r1->left;
}
else
{
/*
* Subtrahend now used up since it doesn't extend beyond
* minuend
*/
r2++;
}
}
else if (r2->left < r1->right)
{
/*
* Left part of subtrahend covers part of minuend: add uncovered
* part of minuend to region and skip to next subtrahend.
*/
MEMCHECK(pReg, pNextRect, pReg->rects);
pNextRect->left = left;
pNextRect->top = top;
pNextRect->right = r2->left;
pNextRect->bottom = bottom;
pReg->numRects += 1;
pNextRect++;
left = r2->right;
if (left >= r1->right)
{
/*
* Minuend used up: advance to new...
*/
r1++;
if (r1 != r1End)
left = r1->left;
}
else
{
/*
* Subtrahend used up
*/
r2++;
}
}
else
{
/*
* Minuend used up: add any remaining piece before advancing.
*/
if (r1->right > left)
{
MEMCHECK(pReg, pNextRect, pReg->rects);
pNextRect->left = left;
pNextRect->top = top;
pNextRect->right = r1->right;
pNextRect->bottom = bottom;
pReg->numRects += 1;
pNextRect++;
}
r1++;
left = r1->left;
}
}
 
/*
* Add remaining minuend rectangles to region.
*/
while (r1 != r1End)
{
MEMCHECK(pReg, pNextRect, pReg->rects);
pNextRect->left = left;
pNextRect->top = top;
pNextRect->right = r1->right;
pNextRect->bottom = bottom;
pReg->numRects += 1;
pNextRect++;
r1++;
if (r1 != r1End)
{
left = r1->left;
}
}
}
/***********************************************************************
* GdSubtractRegion
*
* Subtract regS from regM and leave the result in regD.
* S stands for subtrahend, M for minuend and D for difference.
*
* Results:
* TRUE.
*
* Side Effects:
* regD is overwritten.
*
*/
void
GdSubtractRegion(MWCLIPREGION *regD, MWCLIPREGION *regM, MWCLIPREGION *regS )
{
/* check for trivial reject */
if ( (!(regM->numRects)) || (!(regS->numRects)) ||
(!EXTENTCHECK(&regM->extents, &regS->extents)) )
{
GdCopyRegion(regD, regM);
return;
}
REGION_RegionOp (regD, regM, regS, (voidProcp) REGION_SubtractO,
(voidProcp) REGION_SubtractNonO1, (voidProcp) NULL);
 
/*
* Can't alter newReg's extents before we call miRegionOp because
* it might be one of the source regions and miRegionOp depends
* on the extents of those regions being the unaltered. Besides, this
* way there's no checking against rectangles that will be nuked
* due to coalescing, so we have to examine fewer rectangles.
*/
REGION_SetExtents (regD);
regD->type = (regD->numRects) ? MWREGION_COMPLEX : MWREGION_NULL ;
}
 
/***********************************************************************
* GdXorRegion
*/
void
GdXorRegion(MWCLIPREGION *dr, MWCLIPREGION *sra, MWCLIPREGION *srb)
{
MWCLIPREGION *tra, *trb;
 
if ((! (tra = GdAllocRegion())) || (! (trb = GdAllocRegion())))
return;
GdSubtractRegion(tra,sra,srb);
GdSubtractRegion(trb,srb,sra);
GdUnionRegion(dr,tra,trb);
GdDestroyRegion(tra);
GdDestroyRegion(trb);
}
 
#if 0
/***********************************************************************
* DumpRegion
* Outputs the contents of a MWCLIPREGION
*/
void
DumpRegion(MWCLIPREGION *pReg)
{
MWRECT *pRect, *pRectEnd = pReg->rects + pReg->numRects;
 
DPRINTF("Region %p: %d,%d - %d,%d %d rects\n", pReg,
pReg->extents.left, pReg->extents.top,
pReg->extents.right, pReg->extents.bottom, pReg->numRects);
for(pRect = pReg->rects; pRect < pRectEnd; pRect++)
DPRINTF("\t%d,%d - %d,%d\n", pRect->left, pRect->top,
pRect->right, pRect->bottom);
}
#endif
/devclip.c
0,0 → 1,7
#include "device.h"
 
#if DYNAMICREGIONS
#include "devclip2.c"
#else
#include "devclip1.c"
#endif
/devmouse.c
0,0 → 1,452
/*
* Copyright (c) 1999, 2000 Greg Haerr <greg@censoft.com>
* Copyright (C) 1999 Bradley D. LaRonde (brad@ltc.com)
* Copyright (c) 1991 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Device-independent top level mouse and cursor routines
*
* Reads data from mouse driver and tracks real position on the screen.
* Intersection detection for cursor with auto removal
*
* Bradley D. LaRonde added absolute coordinates and z (pen pressure) Oct-1999
*/
#include <string.h>
#include "device.h"
 
/*
* The following define specifies whether returned mouse
* driver coordinates are adjusted when running in portrait
* mode. If the mouse driver doesn't adjust returned values
* when in portrait mode (as is the case for the iPAQ), then
* this define should be set on.
*/
#define FLIP_MOUSE_IN_PORTRAIT_MODE 1
 
static MWCOORD xpos; /* current x position of mouse */
static MWCOORD ypos; /* current y position of mouse */
static MWCOORD minx; /* minimum allowed x position */
static MWCOORD maxx; /* maximum allowed x position */
static MWCOORD miny; /* minimum allowed y position */
static MWCOORD maxy; /* maximum allowed y position */
static int scale; /* acceleration scale factor */
static int thresh; /* acceleration threshhold */
static int buttons; /* current state of buttons */
static MWBOOL changed; /* mouse state has changed */
 
static MWCOORD curminx; /* minimum x value of cursor */
static MWCOORD curminy; /* minimum y value of cursor */
static MWCOORD curmaxx; /* maximum x value of cursor */
static MWCOORD curmaxy; /* maximum y value of cursor */
static int curvisible; /* >0 if cursor is visible*/
static MWBOOL curneedsrestore;/* cursor needs restoration after drawing*/
static MWCOORD cursavx; /* saved cursor location*/
static MWCOORD cursavy;
static MWCOORD cursavx2;
static MWCOORD cursavy2;
static MWPIXELVAL curfg; /* foreground color of cursor */
static MWPIXELVAL curbg; /* background color of cursor */
static MWPIXELVAL cursavbits[MWMAX_CURSOR_SIZE * MWMAX_CURSOR_SIZE];
static MWIMAGEBITS cursormask[MWMAX_CURSOR_SIZE];
static MWIMAGEBITS cursorcolor[MWMAX_CURSOR_SIZE];
 
extern int gr_mode;
 
/*
* Initialize the mouse.
* This sets its position to (0, 0) with no boundaries and no buttons pressed.
* Returns < 0 on error, or mouse fd on success
*/
int
GdOpenMouse(void)
{
int fd;
 
/* init mouse position info*/
buttons = 0;
xpos = 0;
ypos = 0;
minx = MIN_MWCOORD;
miny = MIN_MWCOORD;
maxx = MAX_MWCOORD;
maxy = MAX_MWCOORD;
changed = TRUE;
 
/* init cursor position and size info*/
curvisible = 0;
curneedsrestore = FALSE;
curminx = minx;
curminy = miny;
curmaxx = curminx + MWMAX_CURSOR_SIZE - 1;
curmaxy = curminy + MWMAX_CURSOR_SIZE - 1;
 
if ((fd = mousedev.Open(&mousedev)) == -1)
return -1;
 
/* get default acceleration settings*/
mousedev.GetDefaultAccel(&scale, &thresh);
 
/* handle null mouse driver by hiding cursor*/
if(fd == -2)
GdHideCursor(&scrdev);
return fd;
}
 
/*
* Terminate the use of the mouse.
*/
void
GdCloseMouse(void)
{
mousedev.Close();
}
 
void
GdGetButtonInfo(int *buttons)
{
*buttons = mousedev.GetButtonInfo();
}
 
/*
* Restrict the coordinates of the mouse to the specified coordinates.
*/
void
GdRestrictMouse(MWCOORD newminx, MWCOORD newminy, MWCOORD newmaxx,
MWCOORD newmaxy)
{
minx = newminx;
miny = newminy;
maxx = newmaxx;
maxy = newmaxy;
GdMoveMouse(xpos, ypos);
}
 
/*
* Set the acceleration threshhold and scale factors.
* Acceleration makes the cursor move further for faster movements.
* Basically, at mouse speeds above the threshold, the excess distance
* moved is multiplied by the scale factor. For example, with a threshhold
* of 5 and a scale of 3, the following gives examples of the original and
* modified mouse movements:
* input: 0 4 5 6 9 20
* output: 0 4 5 8 17 50
*/
void
GdSetAccelMouse(int newthresh, int newscale)
{
if (newthresh < 0)
newthresh = 0;
if (newscale < 0)
newscale = 0;
thresh = newthresh;
scale = newscale;
}
 
/*
* Move the mouse to the specified coordinates.
* The location is limited by the current mouse coordinate restrictions.
*/
void
GdMoveMouse(MWCOORD newx, MWCOORD newy)
{
if (newx < minx)
newx = minx;
if (newx > maxx)
newx = maxx;
if (newy < miny)
newy = miny;
if (newy > maxy)
newy = maxy;
if (newx == xpos && newy == ypos)
return;
 
changed = TRUE;
xpos = newx;
ypos = newy;
}
 
/*
* Read the current location and button states of the mouse.
* Returns -1 on read error.
* Returns 0 if no new data is available from the mouse driver,
* or if the new data shows no change in button state or position.
* Returns 1 if the mouse driver tells us a changed button state
* or position. Button state and position are always both returned,
* even if only one or the other changes.
* Do not block.
*/
int
GdReadMouse(MWCOORD *px, MWCOORD *py, int *pb)
{
MWCOORD x, y, z;
int newbuttons; /* new button state */
int sign; /* sign of change */
int status; /* status of reading mouse */
 
*px = xpos;
*py = ypos;
*pb = buttons;
 
if (changed) {
changed = FALSE;
return 1;
}
 
/* read the mouse position */
status = mousedev.Read(&x, &y, &z, &newbuttons);
if (status < 0)
return -1;
 
/* no new info from the mouse driver? */
if (status == 0)
return 0;
 
/* has the button state changed? */
if (buttons != newbuttons) {
changed = TRUE;
buttons = newbuttons;
}
 
/* depending on the kind of data that we have */
switch(status) {
case 1: /* relative position change reported, figure new position */
sign = 1;
if (x < 0) {
sign = -1;
x = -x;
}
if (x > thresh)
x = thresh + (x - thresh) * scale;
x *= sign;
 
sign = 1;
if (y < 0) {
sign = -1;
y = -y;
}
if (y > thresh)
y = thresh + (y - thresh) * scale;
y *= sign;
 
#if FLIP_MOUSE_IN_PORTRAIT_MODE
if (scrdev.portrait == MWPORTRAIT_RIGHT)
GdMoveMouse(xpos + y, ypos - x); /* right*/
else if (scrdev.portrait == MWPORTRAIT_LEFT)
GdMoveMouse(xpos - y, ypos + x); /* left*/
else if (scrdev.portrait == MWPORTRAIT_DOWN)
GdMoveMouse(xpos + x, ypos - y); /* down*/
else
#endif
GdMoveMouse(xpos + x, ypos + y);
break;
 
case 2: /* absolute position reported */
#if FLIP_MOUSE_IN_PORTRAIT_MODE
if (scrdev.portrait == MWPORTRAIT_RIGHT)
GdMoveMouse(y, scrdev.xres - x - 1); /* right*/
else if (scrdev.portrait == MWPORTRAIT_LEFT)
GdMoveMouse(scrdev.yres - y - 1, x); /* left*/
else if (scrdev.portrait == MWPORTRAIT_DOWN)
GdMoveMouse(x, scrdev.yres - y - 1); /* down?*/
else
#endif
GdMoveMouse(x, y);
break;
 
case 3: /* only button data is available */
break;
}
/* didn't anything change? */
if (!changed)
return 0;
 
/* report new mouse data */
changed = FALSE;
*px = xpos;
*py = ypos;
*pb = buttons;
return 1;
}
 
/*
* Set the cursor position.
*/
void
GdMoveCursor(MWCOORD newx, MWCOORD newy)
{
MWCOORD shiftx;
MWCOORD shifty;
 
shiftx = newx - curminx;
shifty = newy - curminy;
if(shiftx == 0 && shifty == 0)
return;
curminx += shiftx;
curmaxx += shiftx;
curminy += shifty;
curmaxy += shifty;
 
/* Restore the screen under the mouse pointer*/
GdHideCursor(&scrdev);
 
/* Draw the new pointer*/
GdShowCursor(&scrdev);
}
 
/* return current mouse position in x, y*/
MWBOOL
GdGetCursorPos(MWCOORD *px, MWCOORD *py)
{
*px = xpos;
*py = ypos;
return curvisible > 0; /* return TRUE if visible*/
}
 
/*
* Set the cursor size and bitmaps.
*/
void
GdSetCursor(PMWCURSOR pcursor)
{
int bytes;
 
GdHideCursor(&scrdev);
curmaxx = curminx + pcursor->width - 1;
curmaxy = curminy + pcursor->height - 1;
 
curfg = GdFindColor(pcursor->fgcolor);
curbg = GdFindColor(pcursor->bgcolor);
bytes = MWIMAGE_WORDS(pcursor->width) * pcursor->height
* sizeof(MWIMAGEBITS);
memcpy(cursorcolor, pcursor->image, bytes);
memcpy(cursormask, pcursor->mask, bytes);
 
GdShowCursor(&scrdev);
}
 
 
/*
* Draw the mouse pointer. Save the screen contents underneath
* before drawing. Returns previous cursor state.
*/
int
GdShowCursor(PSD psd)
{
MWCOORD x;
MWCOORD y;
MWPIXELVAL * saveptr;
MWIMAGEBITS * cursorptr;
MWIMAGEBITS * maskptr;
MWIMAGEBITS curbit, cbits, mbits;
MWPIXELVAL oldcolor;
MWPIXELVAL newcolor;
int oldmode;
int prevcursor = curvisible;
 
if(++curvisible != 1)
return prevcursor;
oldmode = gr_mode;
gr_mode = MWMODE_COPY;
 
saveptr = cursavbits;
cursavx = curminx;
cursavy = curminy;
cursavx2 = curmaxx;
cursavy2 = curmaxy;
cursorptr = cursorcolor;
maskptr = cursormask;
 
for (y = curminy; y <= curmaxy; y++) {
cbits = *cursorptr++;
mbits = *maskptr++;
curbit = MWIMAGE_FIRSTBIT;
for (x = curminx; x <= curmaxx; x++) {
if(x >= 0 && x < psd->xvirtres &&
y >= 0 && y < psd->yvirtres) {
oldcolor = psd->ReadPixel(psd, x, y);
if (curbit & mbits) {
newcolor = (curbit&cbits)? curbg: curfg;
if (oldcolor != newcolor)
psd->DrawPixel(psd, x, y, newcolor);
}
*saveptr++ = oldcolor;
}
curbit = MWIMAGE_NEXTBIT(curbit);
}
}
 
gr_mode = oldmode;
return prevcursor;
}
 
/*
* Restore the screen overwritten by the cursor.
*/
int
GdHideCursor(PSD psd)
{
MWPIXELVAL * saveptr;
MWCOORD x, y;
int oldmode;
int prevcursor = curvisible;
 
if(curvisible-- <= 0)
return prevcursor;
oldmode = gr_mode;
gr_mode = MWMODE_COPY;
 
saveptr = cursavbits;
for (y = cursavy; y <= cursavy2; y++) {
for (x = cursavx; x <= cursavx2; x++) {
if(x >= 0 && x < psd->xvirtres &&
y >= 0 && y < psd->yvirtres) {
psd->DrawPixel(psd, x, y, *saveptr++);
}
}
}
gr_mode = oldmode;
return prevcursor;
}
 
/* Check to see if the mouse pointer is about to be overwritten.
* If so, then remove the cursor so that the graphics operation
* works correctly. If the cursor is removed, then this fact will
* be remembered and a later call to GdFixCursor will restore it.
*/
void
GdCheckCursor(PSD psd,MWCOORD x1,MWCOORD y1,MWCOORD x2,MWCOORD y2)
{
MWCOORD temp;
 
if (curvisible <= 0 || (psd->flags & PSF_SCREEN) == 0)
return;
 
if (x1 > x2) {
temp = x1;
x1 = x2;
x2 = temp;
}
if (y1 > y2) {
temp = y1;
y1 = y2;
y2 = temp;
}
if (x1 > curmaxx || x2 < curminx || y1 > curmaxy || y2 < curminy)
return;
 
GdHideCursor(psd);
curneedsrestore = TRUE;
}
 
 
/* Redisplay the cursor if it was removed because of a graphics operation. */
void
GdFixCursor(PSD psd)
{
if (curneedsrestore && (psd->flags & PSF_SCREEN)) {
GdShowCursor(psd);
curneedsrestore = FALSE;
}
}
/error.c
0,0 → 1,32
/*
* Reconfigurable error handler
*/
 
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#if (UNIX | DOS_DJGPP)
#include <unistd.h>
#endif
#include "device.h"
 
/* output error message and return -1*/
int
GdError(const char *format, ...)
{
va_list args;
char buf[512];
 
va_start(args, format);
vsprintf(buf, format, args);
va_end(args);
write(2, buf, strlen(buf));
return -1;
}
 
/* null routine to consume messages */
int
GdErrorNull(const char *format, ...)
{
return -1;
}
/Makefile
0,0 → 1,53
##############################################################################
# Microwindows template Makefile
# Copyright (c) 2000, 2002 Martin Jolicoeur, Greg Haerr
##############################################################################
 
include $(CONFIG)
 
VPATH := $(TOP)/engine
 
######################## Additional Flags section ############################
 
# Directories list for header files
INCLUDEDIRS +=
# Defines for preprocessor
DEFINES +=
 
# Compilation flags for C files OTHER than include directories
CFLAGS +=
# Preprocessor flags OTHER than defines
CPPFLAGS +=
# Linking flags
LDFLAGS +=
 
############################# targets section ################################
 
# If you want to create a library with the objects files, define the name here
LIBNAME = libmwengine.a
LIBNAMESO = libmwengine.so
 
# List of objects to compile
OBJS = devopen.o devdraw.o devfont.o devmouse.o devkbd.o devclip.o devrgn.o \
devpal1.o devpal2.o devimage.o devlist.o selfont.o error.o \
devrgn2.o devarc.o devpoly.o
 
#ifeq ($(UNIX), 1)
OBJS += devtimer.o
#endif
 
ifneq ($(ARCH), ELKS)
OBJS += devpal8.o
endif
 
ifeq ($(GRAYPALETTE), Y)
OBJS += devpalgray4.o
else
OBJS += devpal4.o
endif
 
######################### Makefile.rules section #############################
 
include $(TOP)/Makefile.rules
 
######################## Tools targets section ###############################
/devpal1.c
0,0 → 1,14
/*
* Copyright (c) 1999 Greg Haerr <greg@censoft.com>
*
* 1bpp (2 color) standard palette definition
*/
#include "device.h"
 
/*
* Standard palette for 2 color (monochrome) systems.
*/
MWPALENTRY mwstdpal1[2] = {
RGBDEF( 0 , 0 , 0 ), /* black*/
RGBDEF( 255, 255, 255 ) /* white*/
};
/devdraw.c
0,0 → 1,1482
/*
* Copyright (c) 1999, 2000, 2001 Greg Haerr <greg@censoft.com>
* Portions Copyright (c) 1991 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
*
* Device-independent mid level drawing and color routines.
*
* These routines do the necessary range checking, clipping, and cursor
* overwriting checks, and then call the lower level device dependent
* routines to actually do the drawing. The lower level routines are
* only called when it is known that all the pixels to be drawn are
* within the device area and are visible.
*/
/*#define NDEBUG*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "device.h"
 
extern MWPIXELVAL gr_foreground; /* current foreground color */
extern MWPIXELVAL gr_background; /* current background color */
extern MWBOOL gr_usebg; /* TRUE if background drawn in pixmaps */
extern int gr_mode; /* drawing mode */
extern MWPALENTRY gr_palette[256]; /* current palette*/
extern int gr_firstuserpalentry;/* first user-changable palette entry*/
extern int gr_nextpalentry; /* next available palette entry*/
 
/*static*/ void drawpoint(PSD psd,MWCOORD x, MWCOORD y);
/*static*/ void drawrow(PSD psd,MWCOORD x1,MWCOORD x2,MWCOORD y);
static void drawcol(PSD psd,MWCOORD x,MWCOORD y1,MWCOORD y2);
 
/*
* Set the drawing mode for future calls.
*/
int
GdSetMode(int mode)
{
int oldmode = gr_mode;
 
gr_mode = mode;
return oldmode;
}
 
/*
* Set whether or not the background is used for drawing pixmaps and text.
*/
MWBOOL
GdSetUseBackground(MWBOOL flag)
{
MWBOOL oldusebg = gr_usebg;
 
gr_usebg = flag;
return oldusebg;
}
 
/*
* Set the foreground color for drawing.
*/
MWPIXELVAL
GdSetForeground(MWPIXELVAL fg)
{
MWPIXELVAL oldfg = gr_foreground;
 
gr_foreground = fg;
return oldfg;
}
 
/*
* Set the background color for bitmap and text backgrounds.
*/
MWPIXELVAL
GdSetBackground(MWPIXELVAL bg)
{
MWPIXELVAL oldbg = gr_background;
 
gr_background = bg;
return oldbg;
}
 
/*
* Draw a point using the current clipping region and foreground color.
*/
void
GdPoint(PSD psd, MWCOORD x, MWCOORD y)
{
if (GdClipPoint(psd, x, y)) {
psd->DrawPixel(psd, x, y, gr_foreground);
GdFixCursor(psd);
}
}
 
/*
* Draw an arbitrary line using the current clipping region and foreground color
* If bDrawLastPoint is FALSE, draw up to but not including point x2, y2.
*
* This routine is the only routine that adjusts coordinates for supporting
* two different types of upper levels, those that draw the last point
* in a line, and those that draw up to the last point. All other local
* routines draw the last point. This gives this routine a bit more overhead,
* but keeps overall complexity down.
*/
void
GdLine(PSD psd, MWCOORD x1, MWCOORD y1, MWCOORD x2, MWCOORD y2,
MWBOOL bDrawLastPoint)
{
int xdelta; /* width of rectangle around line */
int ydelta; /* height of rectangle around line */
int xinc; /* increment for moving x coordinate */
int yinc; /* increment for moving y coordinate */
int rem; /* current remainder */
MWCOORD temp;
 
/* See if the line is horizontal or vertical. If so, then call
* special routines.
*/
if (y1 == y2) {
/*
* Adjust coordinates if not drawing last point. Tricky.
*/
if(!bDrawLastPoint) {
if (x1 > x2) {
temp = x1;
x1 = x2 + 1;
x2 = temp;
} else
--x2;
}
 
/* call faster line drawing routine*/
drawrow(psd, x1, x2, y1);
GdFixCursor(psd);
return;
}
if (x1 == x2) {
/*
* Adjust coordinates if not drawing last point. Tricky.
*/
if(!bDrawLastPoint) {
if (y1 > y2) {
temp = y1;
y1 = y2 + 1;
y2 = temp;
} else
--y2;
}
 
/* call faster line drawing routine*/
drawcol(psd, x1, y1, y2);
GdFixCursor(psd);
return;
}
 
/* See if the line is either totally visible or totally invisible. If
* so, then the line drawing is easy.
*/
switch (GdClipArea(psd, x1, y1, x2, y2)) {
case CLIP_VISIBLE:
/*
* For size considerations, there's no low-level bresenham
* line draw, so we've got to draw all non-vertical
* and non-horizontal lines with per-point
* clipping for the time being
psd->Line(psd, x1, y1, x2, y2, gr_foreground);
GdFixCursor(psd);
return;
*/
break;
case CLIP_INVISIBLE:
return;
}
 
/* The line may be partially obscured. Do the draw line algorithm
* checking each point against the clipping regions.
*/
xdelta = x2 - x1;
ydelta = y2 - y1;
if (xdelta < 0) xdelta = -xdelta;
if (ydelta < 0) ydelta = -ydelta;
xinc = (x2 > x1) ? 1 : -1;
yinc = (y2 > y1) ? 1 : -1;
if (GdClipPoint(psd, x1, y1))
psd->DrawPixel(psd, x1, y1, gr_foreground);
if (xdelta >= ydelta) {
rem = xdelta / 2;
for(;;) {
if(!bDrawLastPoint && x1 == x2)
break;
x1 += xinc;
rem += ydelta;
if (rem >= xdelta) {
rem -= xdelta;
y1 += yinc;
}
if (GdClipPoint(psd, x1, y1))
psd->DrawPixel(psd, x1, y1, gr_foreground);
if(bDrawLastPoint && x1 == x2)
break;
}
} else {
rem = ydelta / 2;
for(;;) {
if(!bDrawLastPoint && y1 == y2)
break;
y1 += yinc;
rem += xdelta;
if (rem >= ydelta) {
rem -= ydelta;
x1 += xinc;
}
if (GdClipPoint(psd, x1, y1))
psd->DrawPixel(psd, x1, y1, gr_foreground);
if(bDrawLastPoint && y1 == y2)
break;
}
}
GdFixCursor(psd);
}
 
/* Draw a point in the foreground color, applying clipping if necessary*/
/*static*/ void
drawpoint(PSD psd, MWCOORD x, MWCOORD y)
{
if (GdClipPoint(psd, x, y))
psd->DrawPixel(psd, x, y, gr_foreground);
}
 
/* Draw a horizontal line from x1 to and including x2 in the
* foreground color, applying clipping if necessary.
*/
/*static*/ void
drawrow(PSD psd, MWCOORD x1, MWCOORD x2, MWCOORD y)
{
MWCOORD temp;
 
/* reverse endpoints if necessary*/
if (x1 > x2) {
temp = x1;
x1 = x2;
x2 = temp;
}
 
/* clip to physical device*/
if (x1 < 0)
x1 = 0;
if (x2 >= psd->xvirtres)
x2 = psd->xvirtres - 1;
 
/* check cursor intersect once for whole line*/
GdCheckCursor(psd, x1, y, x2, y);
 
while (x1 <= x2) {
if (GdClipPoint(psd, x1, y)) {
temp = MWMIN(clipmaxx, x2);
psd->DrawHorzLine(psd, x1, temp, y, gr_foreground);
} else
temp = MWMIN(clipmaxx, x2);
x1 = temp + 1;
}
}
 
/* Draw a vertical line from y1 to and including y2 in the
* foreground color, applying clipping if necessary.
*/
static void
drawcol(PSD psd, MWCOORD x,MWCOORD y1,MWCOORD y2)
{
MWCOORD temp;
 
/* reverse endpoints if necessary*/
if (y1 > y2) {
temp = y1;
y1 = y2;
y2 = temp;
}
 
/* clip to physical device*/
if (y1 < 0)
y1 = 0;
if (y2 >= psd->yvirtres)
y2 = psd->yvirtres - 1;
 
/* check cursor intersect once for whole line*/
GdCheckCursor(psd, x, y1, x, y2);
 
while (y1 <= y2) {
if (GdClipPoint(psd, x, y1)) {
temp = MWMIN(clipmaxy, y2);
psd->DrawVertLine(psd, x, y1, temp, gr_foreground);
} else
temp = MWMIN(clipmaxy, y2);
y1 = temp + 1;
}
}
 
/* Draw a rectangle in the foreground color, applying clipping if necessary.
* This is careful to not draw points multiple times in case the rectangle
* is being drawn using XOR.
*/
void
GdRect(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height)
{
MWCOORD maxx;
MWCOORD maxy;
 
if (width <= 0 || height <= 0)
return;
maxx = x + width - 1;
maxy = y + height - 1;
drawrow(psd, x, maxx, y);
if (height > 1)
drawrow(psd, x, maxx, maxy);
if (height < 3)
return;
y++;
maxy--;
drawcol(psd, x, y, maxy);
if (width > 1)
drawcol(psd, maxx, y, maxy);
GdFixCursor(psd);
}
 
/* Draw a filled in rectangle in the foreground color, applying
* clipping if necessary.
*/
void
GdFillRect(PSD psd, MWCOORD x1, MWCOORD y1, MWCOORD width, MWCOORD height)
{
MWCOORD x2 = x1+width-1;
MWCOORD y2 = y1+height-1;
 
if (width <= 0 || height <= 0)
return;
 
/* See if the rectangle is either totally visible or totally
* invisible. If so, then the rectangle drawing is easy.
*/
switch (GdClipArea(psd, x1, y1, x2, y2)) {
case CLIP_VISIBLE:
psd->FillRect(psd, x1, y1, x2, y2, gr_foreground);
GdFixCursor(psd);
return;
 
case CLIP_INVISIBLE:
return;
}
 
/* The rectangle may be partially obstructed. So do it line by line. */
while (y1 <= y2)
drawrow(psd, x1, x2, y1++);
GdFixCursor(psd);
}
 
/*
* Draw a rectangular area using the current clipping region and the
* specified bit map. This differs from rectangle drawing in that the
* rectangle is drawn using the foreground color and possibly the background
* color as determined by the bit map. Each row of bits is aligned to the
* next bitmap word boundary (so there is padding at the end of the row).
* The background bit values are only written if the gr_usebg flag
* is set.
*/
void
GdBitmap(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height,
MWIMAGEBITS *imagebits)
{
MWCOORD minx;
MWCOORD maxx;
MWPIXELVAL savecolor; /* saved foreground color */
MWIMAGEBITS bitvalue = 0; /* bitmap word value */
int bitcount; /* number of bits left in bitmap word */
 
switch (GdClipArea(psd, x, y, x + width - 1, y + height - 1)) {
case CLIP_VISIBLE:
/*
* For size considerations, there's no low-level bitmap
* draw so we've got to draw everything with per-point
* clipping for the time being.
if (gr_usebg)
psd->FillRect(psd, x, y, x + width - 1, y + height - 1,
gr_background);
psd->DrawBitmap(psd, x, y, width, height, imagebits, gr_foreground);
return;
*/
break;
 
case CLIP_INVISIBLE:
return;
}
 
/* The rectangle is partially visible, so must do clipping. First
* fill a rectangle in the background color if necessary.
*/
if (gr_usebg) {
savecolor = gr_foreground;
gr_foreground = gr_background;
/* note: change to fillrect*/
GdFillRect(psd, x, y, width, height);
gr_foreground = savecolor;
}
minx = x;
maxx = x + width - 1;
bitcount = 0;
while (height > 0) {
if (bitcount <= 0) {
bitcount = MWIMAGE_BITSPERIMAGE;
bitvalue = *imagebits++;
}
if (MWIMAGE_TESTBIT(bitvalue) && GdClipPoint(psd, x, y))
psd->DrawPixel(psd, x, y, gr_foreground);
bitvalue = MWIMAGE_SHIFTBIT(bitvalue);
bitcount--;
if (x++ == maxx) {
x = minx;
y++;
height--;
bitcount = 0;
}
}
GdFixCursor(psd);
}
 
/*
* Return true if color is in palette
*/
MWBOOL
GdColorInPalette(MWCOLORVAL cr,MWPALENTRY *palette,int palsize)
{
int i;
 
for(i=0; i<palsize; ++i)
if(GETPALENTRY(palette, i) == cr)
return TRUE;
return FALSE;
}
 
/*
* Create a MWPIXELVAL conversion table between the passed palette
* and the in-use palette. The system palette is loaded/merged according
* to fLoadType.
*/
void
GdMakePaletteConversionTable(PSD psd,MWPALENTRY *palette,int palsize,
MWPIXELVAL *convtable,int fLoadType)
{
int i;
MWCOLORVAL cr;
int newsize, nextentry;
MWPALENTRY newpal[256];
 
/*
* Check for load palette completely, or add colors
* from passed palette to system palette until full.
*/
if(psd->pixtype == MWPF_PALETTE) {
switch(fLoadType) {
case LOADPALETTE:
/* Load palette from beginning with image's palette.
* First palette entries are Microwindows colors
* and not changed.
*/
GdSetPalette(psd, gr_firstuserpalentry, palsize, palette);
break;
 
case MERGEPALETTE:
/* get system palette*/
for(i=0; i<(int)psd->ncolors; ++i)
newpal[i] = gr_palette[i];
 
/* merge passed palette into system palette*/
newsize = 0;
nextentry = gr_nextpalentry;
 
/* if color missing and there's room, add it*/
for(i=0; i<palsize && nextentry < (int)psd->ncolors; ++i) {
cr = GETPALENTRY(palette, i);
if(!GdColorInPalette(cr, newpal, nextentry)) {
newpal[nextentry++] = palette[i];
++newsize;
}
}
 
/* set the new palette if any color was added*/
if(newsize) {
GdSetPalette(psd, gr_nextpalentry, newsize,
&newpal[gr_nextpalentry]);
gr_nextpalentry += newsize;
}
break;
}
}
 
/*
* Build conversion table from inuse system palette and
* passed palette. This will load RGB values directly
* if running truecolor, otherwise it will find the
* nearest color from the inuse palette.
* FIXME: tag the conversion table to the bitmap image
*/
for(i=0; i<palsize; ++i) {
cr = GETPALENTRY(palette, i);
convtable[i] = GdFindColor(cr);
}
}
 
/*
* Draw a color bitmap image in 1, 4, 8, 24 or 32 bits per pixel. The
* Microwindows color image format is DWORD padded bytes, with
* the upper bits corresponding to the left side (identical to
* the MS Windows format). This format is currently different
* than the MWIMAGEBITS format, which uses word-padded bits
* for monochrome display only, where the upper bits in the word
* correspond with the left side.
*/
void
GdDrawImage(PSD psd, MWCOORD x, MWCOORD y, PMWIMAGEHDR pimage)
{
MWCOORD minx;
MWCOORD maxx;
MWUCHAR bitvalue = 0;
int bitcount;
MWUCHAR *imagebits;
MWCOORD height, width;
MWPIXELVAL pixel;
int clip;
int extra, linesize;
int rgborder;
MWCOLORVAL cr;
MWCOORD yoff;
unsigned long transcolor;
MWPIXELVAL convtable[256];
 
height = pimage->height;
width = pimage->width;
 
/* determine if entire image is clipped out, save clipresult for later*/
clip = GdClipArea(psd, x, y, x + width - 1, y + height - 1);
if(clip == CLIP_INVISIBLE)
return;
 
transcolor = pimage->transcolor;
 
/*
* Merge the images's palette and build a palette index conversion table.
*/
if (pimage->bpp <= 8) {
if(!pimage->palette) {
/* for jpeg's without a palette*/
for(yoff=0; yoff<pimage->palsize; ++yoff)
convtable[yoff] = yoff;
} else GdMakePaletteConversionTable(psd, pimage->palette,
pimage->palsize, convtable, MERGEPALETTE);
 
/* The following is no longer used. One reason is that it required */
/* the transparent color to be unique, which was unnessecary */
 
/* convert transcolor to converted palette index for speed*/
/* if (transcolor != -1L)
transcolor = (unsigned long) convtable[transcolor]; */
}
 
minx = x;
maxx = x + width - 1;
imagebits = pimage->imagebits;
 
/* check for bottom-up image*/
if(pimage->compression & MWIMAGE_UPSIDEDOWN) {
y += height - 1;
yoff = -1;
} else
yoff = 1;
 
#define PIX2BYTES(n) (((n)+7)/8)
/* imagebits are dword aligned*/
switch(pimage->bpp) {
default:
case 8:
linesize = width;
break;
case 32:
linesize = width*4;
break;
case 24:
linesize = width*3;
break;
case 4:
linesize = PIX2BYTES(width<<2);
break;
case 1:
linesize = PIX2BYTES(width);
break;
}
extra = pimage->pitch - linesize;
 
/* 24bpp RGB rather than BGR byte order?*/
rgborder = pimage->compression & MWIMAGE_RGB;
 
bitcount = 0;
while(height > 0) {
unsigned long trans = 0;
 
if (bitcount <= 0) {
bitcount = sizeof(MWUCHAR) * 8;
bitvalue = *imagebits++;
}
switch(pimage->bpp) {
case 24:
case 32:
cr = rgborder? MWRGB(bitvalue, imagebits[0], imagebits[1]):
MWRGB(imagebits[1], imagebits[0], bitvalue);
/* Include the upper bits for transcolor stuff */
if (imagebits[2]) /* FIXME: 24bpp error*/
trans = cr | 0x01000000L;
 
if (pimage->bpp == 32)
imagebits += 3;
else imagebits += 2;
bitcount = 0;
 
/* handle transparent color*/
if (transcolor == trans)
goto next;
 
switch(psd->pixtype) {
case MWPF_PALETTE:
default:
pixel = GdFindColor(cr);
break;
case MWPF_TRUECOLOR0888:
case MWPF_TRUECOLOR888:
pixel = COLOR2PIXEL888(cr);
break;
case MWPF_TRUECOLOR565:
pixel = COLOR2PIXEL565(cr);
break;
case MWPF_TRUECOLOR555:
pixel = COLOR2PIXEL555(cr);
break;
case MWPF_TRUECOLOR332:
pixel = COLOR2PIXEL332(cr);
break;
}
break;
default:
case 8:
bitcount = 0;
if (bitvalue == transcolor)
goto next;
 
pixel = convtable[bitvalue];
break;
case 4:
if (((bitvalue & 0xf0) >> 4) == transcolor) {
bitvalue <<= 4;
bitcount -= 4;
goto next;
}
 
pixel = convtable[(bitvalue & 0xf0) >> 4];
bitvalue <<= 4;
bitcount -= 4;
break;
case 1:
--bitcount;
if (((bitvalue & 0x80) ? 1 : 0) == transcolor) {
bitvalue <<= 1;
goto next;
}
pixel = convtable[(bitvalue & 0x80)? 1: 0];
bitvalue <<= 1;
break;
}
 
/* if((unsigned long)pixel != transcolor &&*/
if (clip == CLIP_VISIBLE || GdClipPoint(psd, x, y))
psd->DrawPixel(psd, x, y, pixel);
#if 0
/* fix: use clipmaxx to clip quicker*/
else if(clip != CLIP_VISIBLE && !clipresult && x > clipmaxx) {
x = maxx;
}
#endif
next:
if(x++ == maxx) {
x = minx;
y += yoff;
height--;
bitcount = 0;
imagebits += extra;
}
}
GdFixCursor(psd);
}
 
/*
* Read a rectangular area of the screen.
* The color table is indexed row by row.
*/
void
GdReadArea(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height,
MWPIXELVAL *pixels)
{
MWCOORD row;
MWCOORD col;
 
if (width <= 0 || height <= 0)
return;
 
GdCheckCursor(psd, x, y, x+width-1, y+height-1);
for (row = y; row < height+y; row++)
for (col = x; col < width+x; col++)
if (row < 0 || row >= psd->yvirtres ||
col < 0 || col >= psd->xvirtres)
*pixels++ = 0;
else *pixels++ = psd->ReadPixel(psd, col, row);
 
GdFixCursor(psd);
}
 
/* Draw a rectangle of color values, clipping if necessary.
* If a color matches the background color,
* then that pixel is only drawn if the gr_usebg flag is set.
*
* The pixels are packed according to pixtype:
*
* pixtype array of
* MWPF_RGB MWCOLORVAL (unsigned long)
* MWPF_PIXELVAL MWPIXELVAL (compile-time dependent)
* MWPF_PALETTE unsigned char
* MWPF_TRUECOLOR0888 unsigned long
* MWPF_TRUECOLOR888 packed struct {char r,char g,char b} (24 bits)
* MWPF_TRUECOLOR565 unsigned short
* MWPF_TRUECOLOR555 unsigned short
* MWPF_TRUECOLOR332 unsigned char
*
* NOTE: Currently, no translation is performed if the pixtype
* is not MWPF_RGB. Pixtype is only then used to determine the
* packed size of the pixel data, and is then stored unmodified
* in a MWPIXELVAL and passed to the screen driver. Virtually,
* this means there's only three reasonable options for client
* programs: (1) pass all data as RGB MWCOLORVALs, (2) pass
* data as unpacked 32-bit MWPIXELVALs in the format the current
* screen driver is running, or (3) pass data as packed values
* in the format the screen driver is running. Options 2 and 3
* are identical except for the packing structure.
*/
void
GdArea(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height, void *pixels,
int pixtype)
{
unsigned char *PIXELS = pixels; /* for ANSI compilers, can't use void*/
long cellstodo; /* remaining number of cells */
long count; /* number of cells of same color */
long cc; /* current cell count */
long rows; /* number of complete rows */
MWCOORD minx; /* minimum x value */
MWCOORD maxx; /* maximum x value */
MWPIXELVAL savecolor; /* saved foreground color */
MWBOOL dodraw; /* TRUE if draw these points */
MWCOLORVAL rgbcolor = 0L;
int pixsize;
unsigned char r, g, b;
 
minx = x;
maxx = x + width - 1;
 
/* Set up area clipping, and just return if nothing is visible */
if ( GdClipArea(psd, minx, y, maxx, y + height - 1) == CLIP_INVISIBLE )
return;
 
/* psd->DrawArea driver call temp removed, doesn't work with new blit routines*/
#if 0000
{
driver_gc_t hwgc;
int px1, px2, py1, py2, pw, ph, rx1, rx2, ry1, ry2;
#if DYNAMICREGIONS
MWRECT *prc;
extern MWCLIPREGION *clipregion;
#else
MWCLIPRECT *prc;
extern MWCLIPRECT cliprects[];
extern int clipcount;
#endif
 
#if HAVE_T1LIB_SUPPORT | HAVE_FREETYPE_SUPPORT
/* can't use drawarea driver in 16 bpp mode yet with font routines*/
goto fallback;
#endif
if ( !(psd->flags & PSF_HAVEOP_COPY) )
goto fallback;
 
#if DYNAMICREGIONS
prc = clipregion->rects;
count = clipregion->numRects;
#else
prc = cliprects;
count = clipcount;
#endif
 
hwgc.pixels = PIXELS;
hwgc.src_linelen = width;
hwgc.gr_usebg = gr_usebg;
hwgc.bg_color = gr_background;
 
while ( count-- > 0 ) {
#if DYNAMICREGIONS
rx1 = prc->left;
ry1 = prc->top;
rx2 = prc->right;
ry2 = prc->bottom;
#else
/* New clip-code by Morten */
rx1 = prc->x;
ry1 = prc->y;
rx2 = prc->x + prc->width;
ry2 = prc->y + prc->height;
#endif
 
/* Check if this rect intersects with the one we draw */
px1 = x;
py1 = y;
px2 = x + width;
py2 = y + height;
if ( px1 < rx1 ) px1 = rx1;
if ( py1 < ry1 ) py1 = ry1;
if ( px2 > rx2 ) px2 = rx2;
if ( py2 > ry2 ) py2 = ry2;
 
pw = px2 - px1;
ph = py2 - py1;
 
if ( pw > 0 && ph > 0 ) {
hwgc.dstx = px1;
hwgc.dsty = py1;
hwgc.dstw = pw;
hwgc.dsth = ph;
hwgc.srcx = px1 - x;
hwgc.srcy = py1 - y;
GdCheckCursor(psd,px1,py1,px1+pw-1,py1+ph-1);
psd->DrawArea(psd,&hwgc,PSDOP_COPY);
}
prc++;
}
GdFixCursor(psd);
return;
fallback:
}
#endif /* if 0000 temp removed*/
 
/* Calculate size of packed pixels*/
switch(pixtype) {
case MWPF_RGB:
pixsize = sizeof(MWCOLORVAL);
break;
case MWPF_PIXELVAL:
pixsize = sizeof(MWPIXELVAL);
break;
case MWPF_PALETTE:
case MWPF_TRUECOLOR332:
pixsize = sizeof(unsigned char);
break;
case MWPF_TRUECOLOR0888:
pixsize = sizeof(unsigned long);
break;
case MWPF_TRUECOLOR888:
pixsize = 3;
break;
case MWPF_TRUECOLOR565:
case MWPF_TRUECOLOR555:
pixsize = sizeof(unsigned short);
break;
default:
return;
}
 
savecolor = gr_foreground;
cellstodo = (long)width * height;
while (cellstodo > 0) {
/* read the pixel value from the pixtype*/
switch(pixtype) {
case MWPF_RGB:
rgbcolor = *(MWCOLORVAL *)PIXELS;
PIXELS += sizeof(MWCOLORVAL);
gr_foreground = GdFindColor(rgbcolor);
break;
case MWPF_PIXELVAL:
gr_foreground = *(MWPIXELVAL *)PIXELS;
PIXELS += sizeof(MWPIXELVAL);
break;
case MWPF_PALETTE:
case MWPF_TRUECOLOR332:
gr_foreground = *PIXELS++;
break;
case MWPF_TRUECOLOR0888:
gr_foreground = *(unsigned long *)PIXELS;
PIXELS += sizeof(unsigned long);
break;
case MWPF_TRUECOLOR888:
r = *PIXELS++;
g = *PIXELS++;
b = *PIXELS++;
gr_foreground = (MWPIXELVAL)MWRGB(r, g, b);
break;
case MWPF_TRUECOLOR565:
case MWPF_TRUECOLOR555:
gr_foreground = *(unsigned short *)PIXELS;
PIXELS += sizeof(unsigned short);
break;
}
dodraw = (gr_usebg || (gr_foreground != gr_background));
count = 1;
--cellstodo;
 
/* See how many of the adjacent remaining points have the
* same color as the next point.
*
* NOTE: Yes, with the addition of the pixel unpacking,
* it's almost slower to look ahead than to just draw
* the pixel... FIXME
*/
while (cellstodo > 0) {
switch(pixtype) {
case MWPF_RGB:
if(rgbcolor != *(MWCOLORVAL *)PIXELS)
goto breakwhile;
PIXELS += sizeof(MWCOLORVAL);
break;
case MWPF_PIXELVAL:
if(gr_foreground != *(MWPIXELVAL *)PIXELS)
goto breakwhile;
PIXELS += sizeof(MWPIXELVAL);
break;
case MWPF_PALETTE:
case MWPF_TRUECOLOR332:
if(gr_foreground != *(unsigned char *)PIXELS)
goto breakwhile;
++PIXELS;
break;
case MWPF_TRUECOLOR0888:
if(gr_foreground != *(unsigned long *)PIXELS)
goto breakwhile;
PIXELS += sizeof(unsigned long);
break;
case MWPF_TRUECOLOR888:
r = *(unsigned char *)PIXELS;
g = *(unsigned char *)(PIXELS + 1);
b = *(unsigned char *)(PIXELS + 2);
if(gr_foreground != (MWPIXELVAL)MWRGB(r, g, b))
goto breakwhile;
PIXELS += 3;
break;
case MWPF_TRUECOLOR565:
case MWPF_TRUECOLOR555:
if(gr_foreground != *(unsigned short *)PIXELS)
goto breakwhile;
PIXELS += sizeof(unsigned short);
break;
}
++count;
--cellstodo;
}
breakwhile:
 
/* If there is only one point with this color, then draw it
* by itself.
*/
if (count == 1) {
if (dodraw)
drawpoint(psd, x, y);
if (++x > maxx) {
x = minx;
y++;
}
continue;
}
 
/* There are multiple points with the same color. If we are
* not at the start of a row of the rectangle, then draw this
* first row specially.
*/
if (x != minx) {
cc = count;
if (x + cc - 1 > maxx)
cc = maxx - x + 1;
if (dodraw)
drawrow(psd, x, x + cc - 1, y);
count -= cc;
x += cc;
if (x > maxx) {
x = minx;
y++;
}
}
 
/* Now the x value is at the beginning of a row if there are
* any points left to be drawn. Draw all the complete rows
* with one call.
*/
rows = count / width;
if (rows > 0) {
if (dodraw) {
/* note: change to fillrect, (parm types changed)*/
/*GdFillRect(psd, x, y, maxx, y + rows - 1);*/
GdFillRect(psd, x, y, maxx - x + 1, rows);
}
count %= width;
y += rows;
}
 
/* If there is a final partial row of pixels left to be
* drawn, then do that.
*/
if (count > 0) {
if (dodraw)
drawrow(psd, x, x + count - 1, y);
x += count;
}
}
gr_foreground = savecolor;
GdFixCursor(psd);
}
 
#if NOTYET
/* Copy a rectangular area from one screen area to another.
* This bypasses clipping.
*/
void
GdCopyArea(PSD psd, MWCOORD srcx, MWCOORD srcy, MWCOORD width, MWCOORD height,
MWCOORD destx, MWCOORD desty)
{
if (width <= 0 || height <= 0)
return;
 
if (srcx == destx && srcy == desty)
return;
GdCheckCursor(psd, srcx, srcy, srcx + width - 1, srcy + height - 1);
GdCheckCursor(psd, destx, desty, destx + width - 1, desty + height - 1);
psd->CopyArea(psd, srcx, srcy, width, height, destx, desty);
GdFixCursor(psd);
}
#endif
 
/* Copy source rectangle of pixels to destination rectangle quickly*/
void
GdBlit(PSD dstpsd, MWCOORD dstx, MWCOORD dsty, MWCOORD width, MWCOORD height,
PSD srcpsd, MWCOORD srcx, MWCOORD srcy, long rop)
{
int rx1, rx2, ry1, ry2;
int px1, px2, py1, py2;
int pw, ph;
int count;
#if DYNAMICREGIONS
MWRECT * prc;
extern MWCLIPREGION *clipregion;
#else
MWCLIPRECT * prc;
extern MWCLIPRECT cliprects[];
extern int clipcount;
#endif
 
/*FIXME: compare bpp's and convert if necessary*/
assert(dstpsd->planes == srcpsd->planes);
assert(dstpsd->bpp == srcpsd->bpp);
 
/* temporary assert() until rotation blits completed*/
assert(dstpsd->portrait == srcpsd->portrait);
/* clip blit rectangle to source screen/bitmap size*/
/* we must do this because there isn't any source clipping setup*/
if(srcx < 0) {
width += srcx;
dstx -= srcx;
srcx = 0;
}
if(srcy < 0) {
height += srcy;
dsty -= srcy;
srcy = 0;
}
if(srcx+width > srcpsd->xvirtres)
width = srcpsd->xvirtres - srcx;
if(srcy+height > srcpsd->yvirtres)
height = srcpsd->yvirtres - srcy;
 
switch(GdClipArea(dstpsd, dstx, dsty, dstx+width-1, dsty+height-1)) {
case CLIP_VISIBLE:
/* check cursor in src region*/
GdCheckCursor(dstpsd, srcx, srcy, srcx+width-1, srcy+height-1);
dstpsd->Blit(dstpsd, dstx, dsty, width, height,
srcpsd, srcx, srcy, rop);
GdFixCursor(dstpsd);
return;
 
case CLIP_INVISIBLE:
return;
}
 
/* Partly clipped, we'll blit using destination clip
* rectangles, and offset the blit accordingly.
* Since the destination is already clipped, we
* only need to clip the source here.
*/
#if DYNAMICREGIONS
prc = clipregion->rects;
count = clipregion->numRects;
#else
prc = cliprects;
count = clipcount;
#endif
while(--count >= 0) {
#if DYNAMICREGIONS
rx1 = prc->left;
ry1 = prc->top;
rx2 = prc->right;
ry2 = prc->bottom;
#else
rx1 = prc->x;
ry1 = prc->y;
rx2 = prc->x + prc->width;
ry2 = prc->y + prc->height;
#endif
/* Check: does this rect intersect the one we want to draw? */
px1 = dstx;
py1 = dsty;
px2 = dstx + width;
py2 = dsty + height;
if (px1 < rx1) px1 = rx1;
if (py1 < ry1) py1 = ry1;
if (px2 > rx2) px2 = rx2;
if (py2 > ry2) py2 = ry2;
 
pw = px2 - px1;
ph = py2 - py1;
if(pw > 0 && ph > 0) {
/* check cursor in dest and src regions*/
GdCheckCursor(dstpsd, px1, py1, px2-1, py2-1);
GdCheckCursor(dstpsd, srcx, srcy,
srcx+width, srcy+height);
dstpsd->Blit(dstpsd, px1, py1, pw, ph, srcpsd,
srcx + (px1-dstx), srcy + (py1-dsty), rop);
}
++prc;
}
GdFixCursor(dstpsd);
}
 
/* experimental globals for ratio bug when src != 0*/
int g_row_inc, g_col_inc;
/* Stretch source rectangle of pixels to destination rectangle quickly*/
void
GdStretchBlit(PSD dstpsd, MWCOORD dstx, MWCOORD dsty, MWCOORD dstw,
MWCOORD dsth, PSD srcpsd, MWCOORD srcx, MWCOORD srcy, MWCOORD srcw,
MWCOORD srch, long rop)
{
int count;
#if DYNAMICREGIONS
MWRECT * prc;
extern MWCLIPREGION *clipregion;
#else
MWCLIPRECT * prc;
extern MWCLIPRECT cliprects[];
extern int clipcount;
#endif
 
g_row_inc = g_col_inc = 0;
 
/* check for driver stretch blit implementation*/
if (!dstpsd->StretchBlit)
return;
 
/*FIXME: compare bpp's and convert if necessary*/
assert(dstpsd->planes == srcpsd->planes);
assert(dstpsd->bpp == srcpsd->bpp);
/* clip blit rectangle to source screen/bitmap size*/
/* we must do this because there isn't any source clipping setup*/
if(srcx < 0) {
srcw += srcx;
/*dstx -= srcx;*/
srcx = 0;
}
if(srcy < 0) {
srch += srcy;
/*dsty -= srcy;*/
srcy = 0;
}
if(srcx+srcw > srcpsd->xvirtres)
srcw = srcpsd->xvirtres - srcx;
if(srcy+srch > srcpsd->yvirtres)
srch = srcpsd->yvirtres - srcy;
 
/* temp dest clipping for partially visible case*/
if(dstx+dstw > dstpsd->xvirtres)
dstw = dstpsd->xvirtres - dstx;
if(dsty+dsth > dstpsd->yvirtres)
dsth = dstpsd->yvirtres - dsty;
 
switch(GdClipArea(dstpsd, dstx, dsty, dstx+dstw-1, dsty+dsth-1)) {
case CLIP_VISIBLE:
/* check cursor in src region*/
GdCheckCursor(dstpsd, srcx, srcy, srcx+srcw-1, srcy+srch-1);
dstpsd->StretchBlit(dstpsd, dstx, dsty, dstw, dsth,
srcpsd, srcx, srcy, srcw, srch, rop);
GdFixCursor(dstpsd);
return;
 
case CLIP_INVISIBLE:
return;
}
 
/* Partly clipped, we'll blit using destination clip
* rectangles, and offset the blit accordingly.
* Since the destination is already clipped, we
* only need to clip the source here.
*/
#if DYNAMICREGIONS
prc = clipregion->rects;
count = clipregion->numRects;
#else
prc = cliprects;
count = clipcount;
#endif
while(--count >= 0) {
int rx1, rx2, ry1, ry2;
int px1, px2, py1, py2;
int pw, ph;
int sx, sy, sw, sh;
#if DYNAMICREGIONS
rx1 = prc->left;
ry1 = prc->top;
rx2 = prc->right;
ry2 = prc->bottom;
#else
rx1 = prc->x;
ry1 = prc->y;
rx2 = prc->x + prc->width;
ry2 = prc->y + prc->height;
#endif
/* Check: does this rect intersect the one we want to draw? */
px1 = dstx;
py1 = dsty;
px2 = dstx + dstw;
py2 = dsty + dsth;
if (px1 < rx1) px1 = rx1;
if (py1 < ry1) py1 = ry1;
if (px2 > rx2) px2 = rx2;
if (py2 > ry2) py2 = ry2;
 
pw = px2 - px1;
ph = py2 - py1;
if(pw > 0 && ph > 0) {
/* calc proper src/dst offset for stretch rect*/
g_row_inc = (srch << 16) / dsth;
g_col_inc = (srcw << 16) / dstw;
sw = pw * srcw / dstw;
sh = ph * srch / dsth;
 
if (sw > 0 && sh > 0) {
sx = srcx + (px1-dstx) * srcw / dstw;
sy = srcy + (py1-dsty) * srch / dsth;
/*printf("P %d,%d,%d,%d %d,%d\n", sx, sy, sw, sh, g_row_inc, g_col_inc);*/
 
/* check cursor in dest and src regions*/
GdCheckCursor(dstpsd, px1, py1, px2-1, py2-1);
GdCheckCursor(dstpsd, srcx, srcy, srcx+srcw, srcy+srch);
dstpsd->StretchBlit(dstpsd, px1, py1, pw, ph, srcpsd,
sx, sy, sw, sh, rop);
}
}
++prc;
}
GdFixCursor(dstpsd);
}
 
/*
* Calculate size and linelen of memory gc.
* If bpp or planes is 0, use passed psd's bpp/planes.
* Note: linelen is calculated to be DWORD aligned for speed
* for bpp <= 8. Linelen is converted to bytelen for bpp > 8.
*/
int
GdCalcMemGCAlloc(PSD psd, unsigned int width, unsigned int height, int planes,
int bpp, int *psize, int *plinelen)
{
int bytelen, linelen, tmp;
 
if(!planes)
planes = psd->planes;
if(!bpp)
bpp = psd->bpp;
/*
* swap width and height in left/right portrait modes,
* so imagesize is calculated properly
*/
if(psd->portrait & (MWPORTRAIT_LEFT|MWPORTRAIT_RIGHT)) {
tmp = width;
width = height;
height = tmp;
}
 
/*
* use bpp and planes to create size and linelen.
* linelen is in bytes for bpp 1, 2, 4, 8, and pixels for bpp 16,24,32.
*/
if(planes == 1) {
switch(bpp) {
case 1:
linelen = (width+7)/8;
bytelen = linelen = (linelen+3) & ~3;
break;
case 2:
linelen = (width+3)/4;
bytelen = linelen = (linelen+3) & ~3;
break;
case 4:
linelen = (width+1)/2;
bytelen = linelen = (linelen+3) & ~3;
break;
case 8:
bytelen = linelen = (width+3) & ~3;
break;
case 16:
linelen = width;
bytelen = width * 2;
break;
case 24:
linelen = width;
bytelen = width * 3;
break;
case 32:
linelen = width;
bytelen = width * 4;
break;
default:
return 0;
}
} else if(planes == 4) {
/* FIXME assumes VGA 4 planes 4bpp*/
/* we use 4bpp linear for memdc format*/
linelen = (width+1)/2;
linelen = (linelen+3) & ~3;
bytelen = linelen;
} else {
*psize = *plinelen = 0;
return 0;
}
 
*plinelen = linelen;
*psize = bytelen * height;
return 1;
}
 
/* Translate a rectangle of color values
*
* The pixels are packed according to inpixtype/outpixtype:
*
* pixtype array of
* MWPF_RGB MWCOLORVAL (unsigned long)
* MWPF_PIXELVAL MWPIXELVAL (compile-time dependent)
* MWPF_PALETTE unsigned char
* MWPF_TRUECOLOR0888 unsigned long
* MWPF_TRUECOLOR888 packed struct {char r,char g,char b} (24 bits)
* MWPF_TRUECOLOR565 unsigned short
* MWPF_TRUECOLOR555 unsigned short
* MWPF_TRUECOLOR332 unsigned char
*/
void
GdTranslateArea(MWCOORD width, MWCOORD height, void *in, int inpixtype,
MWCOORD inpitch, void *out, int outpixtype, int outpitch)
{
unsigned char * inbuf = in;
unsigned char * outbuf = out;
unsigned long pixelval;
MWCOLORVAL colorval;
MWCOORD x, y;
unsigned char r, g, b;
extern MWPALENTRY gr_palette[256];
int gr_palsize = 256; /* FIXME*/
 
for(y=0; y<height; ++y) {
for(x=0; x<width; ++x) {
/* read pixel value and convert to BGR colorval (0x00BBGGRR)*/
switch (inpixtype) {
case MWPF_RGB:
colorval = *(MWCOLORVAL *)inbuf;
inbuf += sizeof(MWCOLORVAL);
break;
case MWPF_PIXELVAL:
pixelval = *(MWPIXELVAL *)inbuf;
inbuf += sizeof(MWPIXELVAL);
/* convert based on compile-time MWPIXEL_FORMAT*/
#if MWPIXEL_FORMAT == MWPF_PALETTE
colorval = GETPALENTRY(gr_palette, pixelval);
#else
colorval = PIXELVALTOCOLORVAL(pixelval);
#endif
break;
case MWPF_PALETTE:
pixelval = *inbuf++;
colorval = GETPALENTRY(gr_palette, pixelval);
break;
case MWPF_TRUECOLOR332:
pixelval = *inbuf++;
colorval = PIXEL332TOCOLORVAL(pixelval);
break;
case MWPF_TRUECOLOR0888:
pixelval = *(unsigned long *)inbuf;
colorval = PIXEL888TOCOLORVAL(pixelval);
inbuf += sizeof(unsigned long);
break;
case MWPF_TRUECOLOR888:
r = *inbuf++;
g = *inbuf++;
b = *inbuf++;
colorval = (MWPIXELVAL)MWRGB(r, g, b);
break;
case MWPF_TRUECOLOR565:
pixelval = *(unsigned short *)inbuf;
colorval = PIXEL565TOCOLORVAL(pixelval);
inbuf += sizeof(unsigned short);
break;
case MWPF_TRUECOLOR555:
pixelval = *(unsigned short *)inbuf;
colorval = PIXEL555TOCOLORVAL(pixelval);
inbuf += sizeof(unsigned short);
break;
default:
return;
}
 
/* convert from BGR colorval to desired output pixel format*/
switch (outpixtype) {
case MWPF_RGB:
*(MWCOLORVAL *)outbuf = colorval;
outbuf += sizeof(MWCOLORVAL);
break;
case MWPF_PIXELVAL:
/* convert based on compile-time MWPIXEL_FORMAT*/
#if MWPIXEL_FORMAT == MWPF_PALETTE
*(MWPIXELVAL *)outbuf = GdFindNearestColor(gr_palette,
gr_palsize, colorval);
#else
*(MWPIXELVAL *)outbuf = COLORVALTOPIXELVAL(colorval);
#endif
outbuf += sizeof(MWPIXELVAL);
break;
case MWPF_PALETTE:
*outbuf++ = GdFindNearestColor(gr_palette, gr_palsize,
colorval);
break;
case MWPF_TRUECOLOR332:
*outbuf++ = COLOR2PIXEL332(colorval);
break;
case MWPF_TRUECOLOR0888:
*(unsigned long *)outbuf = COLOR2PIXEL888(colorval);
outbuf += sizeof(unsigned long);
break;
case MWPF_TRUECOLOR888:
*outbuf++ = REDVALUE(colorval);
*outbuf++ = GREENVALUE(colorval);
*outbuf++ = BLUEVALUE(colorval);
break;
case MWPF_TRUECOLOR565:
*(unsigned short *)outbuf = COLOR2PIXEL565(colorval);
outbuf += sizeof(unsigned short);
break;
case MWPF_TRUECOLOR555:
*(unsigned short *)outbuf = COLOR2PIXEL555(colorval);
outbuf += sizeof(unsigned short);
break;
}
}
 
/* adjust line widths, if necessary*/
if(inpitch > width)
inbuf += inpitch - width;
if(outpitch > width)
outbuf += outpitch - width;
}
}
/devpal2.c
0,0 → 1,18
/*
* Copyright (c) 1999 Greg Haerr <greg@censoft.com>
*
* 2pbb (4 color) standard palette definition
*/
#include "device.h"
 
/*
* Standard palette for Everex Freestyle Palm PC
* This palette is in reverse order from some 2bpp systems.
* That is, white is pixel value 0, while black is 3.
*/
MWPALENTRY mwstdpal2[4] = {
RGBDEF( 255, 255, 255 ), /* white*/
RGBDEF( 192, 192, 192 ), /* ltgray*/
RGBDEF( 128, 128, 128 ), /* gray*/
RGBDEF( 0 , 0 , 0 ) /* black*/
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.