DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T g

⟦0c4a2b07c⟧ TextFile

    Length: 18768 (0x4950)
    Types: TextFile
    Names: »gschar.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦ff23ba0e6⟧ »./ghostscript-1.3.tar.Z« 
        └─⟦a24a58cd3⟧ 
            └─⟦this⟧ »gschar.c« 

TextFile

/* Copyright (C) 1989 Aladdin Enterprises.  All rights reserved.
   Distributed by Free Software Foundation, Inc.

This file is part of Ghostscript.

Ghostscript is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
to anyone for the consequences of using it or for whether it serves any
particular purpose or works at all, unless he says so in writing.  Refer
to the Ghostscript General Public License for full details.

Everyone is granted permission to copy, modify and redistribute
Ghostscript, but only under the conditions described in the Ghostscript
General Public License.  A copy of this license is supposed to have been
given to you along with Ghostscript so you can know your rights and
responsibilities.  It should be in a file named COPYING.  Among other
things, the copyright notice and this notice must be preserved on all
copies.  */

/* gschar.c */
/* Character writing operators for GhostScript library */
#include "gx.h"
#include "memory_.h"
#include "gserrors.h"
#include "gxfixed.h"			/* ditto */
#include "gxmatrix.h"
#include "gzstate.h"			/* must precede gzdevice */
#include "gzdevice.h"			/* must precede gxchar */
#include "gxdevmem.h"
#include "gxfont.h"
#include "gxchar.h"
#include "gxpath.h"
#include "gzcolor.h"

/* Export the FontType that corresponds to */
/* the particular outline encoding implemented here. */
int gs_addcharpath_FontType = 7;
#define log2_scale 2
int gs_addcharpath_log2_scale = log2_scale;

/* Exported size of enumerator */
int gs_show_enum_sizeof = sizeof(gs_show_enum);

/* Forward declarations */
private int continue_show(P1(gs_show_enum *));
private int continue_show_update(P1(gs_show_enum *));
private int continue_stringwidth(P1(gs_show_enum *));
private int continue_stringwidth_update(P1(gs_show_enum *));
private int show_setup(P3(gs_show_enum *, gs_state *, char *));
private int stringwidth_setup(P3(gs_show_enum *, gs_state *, char *));

/* ------ String writing operators ------ */

/* Setup macros for show operators */
#define setup_show()\
  penum->use_size = 0
#define setup_show_n()\
  penum->use_size = 1, penum->size = size
#define setup_a()\
  penum->add = 1, penum->ax = ax, penum->ay = ay,\
  penum->slow_show = 1
#define setup_width()\
  penum->chr = chr, penum->cx = cx, penum->cy = cy,\
  penum->slow_show = 1
#define no_chr 0x100

/* show[_n] */
int
gs_show_init(register gs_show_enum *penum,
  gs_state *pgs, char *str)
{	setup_show();
	penum->slow_show = 0;
	return show_setup(penum, pgs, str);
}
int
gs_show_n_init(register gs_show_enum *penum,
  gs_state *pgs, char *str, uint size)
{	setup_show_n();
	penum->slow_show = 0;
	return show_setup(penum, pgs, str);
}

/* ashow[_n] */
int
gs_ashow_init(register gs_show_enum *penum,
  gs_state *pgs, floatp ax, floatp ay, char *str)
{	int code;
	setup_show();
	code = show_setup(penum, pgs, str);
	setup_a();
	return code;
}
int
gs_ashow_n_init(register gs_show_enum *penum,
  gs_state *pgs, floatp ax, floatp ay, char *str, uint size)
{	int code;
	setup_show_n();
	code = show_setup(penum, pgs, str);
	setup_a();
	return code;
}

/* widthshow[_n] */
int
gs_widthshow_init(register gs_show_enum *penum,
  gs_state *pgs, floatp cx, floatp cy, char chr, char *str)
{	int code;
	setup_show();
	code = show_setup(penum, pgs, str);
	setup_width();
	return code;
}
int
gs_widthshow_n_init(register gs_show_enum *penum,
  gs_state *pgs, floatp cx, floatp cy, char chr, char *str, uint size)
{	int code;
	setup_show_n();
	code = show_setup(penum, pgs, str);
	setup_width();
	return code;
}

/* awidthshow[_n] */
int
gs_awidthshow_init(register gs_show_enum *penum,
  gs_state *pgs, floatp cx, floatp cy, char chr, floatp ax, floatp ay,
  char *str)
{	int code;
	setup_show();
	code = show_setup(penum, pgs, str);
	setup_a();
	setup_width();
	return code;
}
int
gs_awidthshow_n_init(register gs_show_enum *penum,
  gs_state *pgs, floatp cx, floatp cy, char chr, floatp ax, floatp ay,
  char *str, uint size)
{	int code;
	setup_show_n();
	code = show_setup(penum, pgs, str);
	setup_a();
	setup_width();
	return code;
}

/* kshow[_n] */
int
gs_kshow_init(register gs_show_enum *penum,
  gs_state *pgs, char *str)
{	int code;
	setup_show();
	code = show_setup(penum, pgs, str);
	penum->do_kern = penum->slow_show = 1;
	return code;
}
int
gs_kshow_n_init(register gs_show_enum *penum,
  gs_state *pgs, char *str, uint size)
{	int code;
	setup_show_n();
	code = show_setup(penum, pgs, str);
	penum->do_kern = penum->slow_show = 1;
	return code;
}

/* ------ Related operators ------ */

/* stringwidth[_n] */
int
gs_stringwidth_init(gs_show_enum *penum, gs_state *pgs, char *str)
{	setup_show();
	return stringwidth_setup(penum, pgs, str);
}
int
gs_stringwidth_n_init(gs_show_enum *penum, gs_state *pgs, char *str, uint size)
{	setup_show_n();
	return stringwidth_setup(penum, pgs, str);
}

/* Common code for stringwidth[_n] */
private int
stringwidth_setup(gs_show_enum *penum, gs_state *pgs, char *str)
{	int code = show_setup(penum, pgs, str);
	gs_fixed_point pt;
	if ( code < 0 ) return_error(code);
	penum->continue_proc = continue_stringwidth;
	/* Do an extra gsave and suppress output */
	if ( (code = gs_gsave(pgs)) < 0 ) return code;
	gx_device_no_output(pgs);
	/* If there is no current point, move to (0,0) */
	if ( gx_path_current_point(pgs->path, &pt) < 0 )
		gx_path_add_point(pgs->path, (fixed)0, (fixed)0);
	return 0;
}

/* charpath[_n] */
int
gs_charpath_init(gs_show_enum *penum, gs_state *pgs,
  char *str, int bool)
{	int code;
	setup_show();
	code = show_setup(penum, pgs, str);
	penum->charpath_flag = bool;
	penum->can_cache = 0;
	return code;
}
int
gs_charpath_n_init(gs_show_enum *penum, gs_state *pgs,
  char *str, uint size, int bool)
{	int code;
	setup_show_n();
	code = show_setup(penum, pgs, str);
	penum->charpath_flag = bool;
	penum->can_cache = 0;
	return code;
}

/* addcharpath */
int
gs_addcharpath(gs_state *pgs, byte *str, uint len)
{	int code;
	byte *bp = str;
	byte *end = str + len;
	gx_path *ppath = pgs->path;
	/* We could do all of this with the gs path interface, */
	/* but it's a lot faster to use the gx interface and */
	/* avoid the floating point arithmetic. */
	fixed	mxx = float2fixed(pgs->ctm.xx),
		mxy = float2fixed(pgs->ctm.xy),
		myx = float2fixed(pgs->ctm.yx),
		myy = float2fixed(pgs->ctm.yy),
		mtx = pgs->ctm.tx_fixed << log2_scale,
		mty = pgs->ctm.ty_fixed << log2_scale;
	while ( bp != end )
	   {	int first = 1;
		int b;
		fixed ptx = mtx, pty = mty;	/* current point */
		while ( (b = *bp++) != 0x88 )
		   {	int dx = b >> 4, dy = b & 0xf;
			if ( dx == 0 )	dx = *bp++ - 0x80;
			else		dx -= 8;
			if ( dy == 0 )	dy = *bp++ - 0x80;
			else		dy -= 8;
			ptx += mxx * dx + myx * dy;
			pty += mxy * dx + myy * dy;
			if ( (code = (first ?
				(first = 0,
				 gx_path_add_point(ppath,
						   ptx >> log2_scale,
						   pty >> log2_scale)) :
				 gx_path_add_line(ppath,
						  ptx >> log2_scale,
						  pty >> log2_scale)))
			      < 0 )
				return code;
		   }
		code = gx_path_close_subpath(ppath);
		if ( code < 0 ) break;
	   }
	return 0;
}

/* ------ Width/cache operators ------ */

/* setcachedevice */
int
gs_setcachedevice(register gs_show_enum *penum,
  floatp wx, floatp wy, floatp llx, floatp lly, floatp urx, floatp ury)
{	int code = gs_setcharwidth(penum, wx, wy);	/* default is don't cache */
	gs_state *pgs = penum->pgs;
	if ( code < 0 ) return code;
	/* See if we want to cache this character. */
	if ( pgs->in_show )		/* no recursion! */
		return 0;
	pgs->in_show = 1;	/* disable color/gray/image operators */
	if ( !penum->can_cache )
		return 0;
	   {	gs_font_dir *dir = pgs->font->dir;
		float cwidth = urx - llx, cheight = ury - lly;
		gs_fixed_point cll, cur, cdim;
		unsigned long iwidth, iheight;
		cached_char *cc;
		gs_distance_transform2fixed(&pgs->ctm, cwidth, cheight, &cdim);
		if ( cdim.x < 0 ) cdim.x = -cdim.x;
		if ( cdim.y < 0 ) cdim.y = -cdim.y;
		iwidth = fixed2int(cdim.x) + 1;
		iheight = fixed2int(cdim.y) + 1;
		if (	iwidth > (unsigned short)(-1) ||
			iheight > (unsigned short)(-1)
		   )
		  return 0;		/* much too big */
		if ( !penum->dev_cache_set )
		   {	/* Set up the memory device for the character cache */
			device *dev = &penum->dev_cache_dev;
			penum->dev_cache_info = mem_mono_device;
			dev->info = (gx_device *)&penum->dev_cache_info;
			dev->is_band_device = 0;
			dev->white = 1;
			dev->black = 1;
			penum->dev_cache_set = 1;
		   }
		if ( (cc = gx_alloc_char_bits(dir,
					(gx_device_memory *)&penum->dev_cache_info,
					(unsigned short)iwidth,
					(unsigned short)iheight)) == 0 )
		  return 0;		/* too big for cache */
		gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cll);
		gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cur);
		cc->offset.x = -min(cll.x, cur.x);
		cc->offset.y = -min(cll.y, cur.y);
		gx_color_render(pgs->color, pgs);
		if ( !color_is_pure(pgs->color) )	/* can't use cache */
		   {	gx_unalloc_cached_char(dir, cc);
			return code;
		   }
		if ( (code = gs_gsave(pgs)) < 0 )
		   {	gx_unalloc_cached_char(dir, cc);
			return code;
		   }
		/* Nothing can go wrong now.... */
		penum->cc = cc;
		cc->code = gs_show_current_char(penum);
		cc->wxy = penum->wxy;
		/* Install the device */
		pgs->device = &penum->dev_cache_dev;
		pgs->device_is_shared = 1;	/* don't deallocate */
		/* Adjust the translation in the graphics context */
		/* so that the character lines up with the cache. */
		   {	gs_matrix mat;
			gs_currentmatrix(pgs, &mat);
			mat.tx = fixed2float(cc->offset.x);
			mat.ty = fixed2float(cc->offset.y);
			gs_setmatrix(pgs, &mat);
			gx_path_add_point(pgs->path, cc->offset.x, cc->offset.y);
		   }
		/* Reset the clipping path to match the metrics. */
		if ( (code = gx_clip_to_rectangle(pgs, (fixed)0, (fixed)0, int2fixed(iwidth), int2fixed(iheight))) < 0 )
		  return code;
		/* Set the color to black. */
		pgs->in_show = 0;
		gs_setgray(pgs, 0.0);
		pgs->in_show = 1;
	   }
	penum->width_set = sws_cache;
	return 0;
}

/* setcharwidth */
int
gs_setcharwidth(register gs_show_enum *penum, floatp wx, floatp wy)
{	if ( penum->width_set != sws_none )
		return_error(gs_error_undefined);
	gs_distance_transform2fixed(&penum->pgs->ctm, wx, wy, &penum->wxy);
	penum->width_set = sws_no_cache;
	return 0;
}

/* ------ Enumerator ------ */

/* Do the next step of a show (or stringwidth) operation */
int
gs_show_next(gs_show_enum *penum)
{	return (*penum->continue_proc)(penum);
}

/* Continuation procedures for show (all varieties) */
#define show_fast_move(wxy, pgs)\
  gx_path_add_relative_point(pgs->path, wxy.x, wxy.y)
int show_update(P1(register gs_show_enum *penum));
int show_move(P1(register gs_show_enum *penum));
int show_proceed(P1(register gs_show_enum *penum));
private int
continue_show_update(register gs_show_enum *penum)
{	int code = show_update(penum);
	if ( code < 0 ) return code;
	code = show_move(penum);
	if ( code != 0 ) return code;
	return show_proceed(penum);
}
private int
continue_show(register gs_show_enum *penum)
{	return show_proceed(penum);
}
/* Update position for show */
private int
show_update(register gs_show_enum *penum)
{	register gs_state *pgs = penum->pgs;
	/* Update position for last character */
	switch ( penum->width_set )
	   {
	case sws_none:
		return_error(gs_error_undefinedresult);	/* WRONG */
	case sws_cache:
	   {	/* Finish installing the cache entry. */
		cached_char *cc = penum->cc;
		int code;
		gx_add_cached_char(pgs->font->dir, cc, gx_lookup_fm_pair(pgs));
		gs_grestore(pgs);
		/* Copy the bits to the screen. */
		gx_color_render(pgs->color, pgs);
		code = gx_copy_cached_char(penum, cc);
		if ( code < 0 ) return code;
	   }
	case sws_no_cache: ;
	   }
	gs_grestore(pgs);
	return 0;
}
/* Move to next character for show */
private int
show_move(register gs_show_enum *penum)
{	register gs_state *pgs = penum->pgs;
	if ( penum->add )
		gs_rmoveto(pgs, penum->ax, penum->ay);
	if ( penum->str[penum->index - 1] == penum->chr )
		gs_rmoveto(pgs, penum->cx, penum->cy);
	/* wxy is in device coordinates */
	   {	int code = show_fast_move(penum->wxy, pgs);
		if ( code < 0 ) return code;
	   }
	/* Check for kerning */
	if ( penum->do_kern )
	   {	penum->continue_proc = continue_show;
		return gs_show_kern;
	   }
	return 0;
}
/* Process next character for show */
private int
show_proceed(register gs_show_enum *penum)
{	register gs_state *pgs = penum->pgs;
	byte *str = penum->str;
	uint index;
	int color_loaded = 0;
	cached_fm_pair *pair = 0;
	byte chr;
	int code;
more:	/* Proceed to next character */
	index = penum->index;
	chr = str[index];
	if ( (penum->use_size ? index == penum->size : !chr) )
	  { /* All done. */
	    return 0;
	  }
	penum->index++;
	if ( penum->can_cache )		/* Check cache first */
	   {	cached_char *cc;
		if ( pair == 0 )
			pair = gx_lookup_fm_pair(pgs);
		cc = gx_lookup_cached_char(pgs, pair, chr);
		if ( cc != 0 )
		   {	/* Character is in cache. */
			if ( !color_loaded )
			   {	gs_color *pcolor = pgs->color;
				gx_color_render(pgs->color, pgs);
				if ( !color_is_pure(pcolor) )
					goto no_cache;
				color_loaded = 1;
			   }
			code = gx_copy_cached_char(penum, cc);
			if ( code < 0 ) return code;
			if ( penum->slow_show )
			   {	penum->wxy = cc->wxy;
				code = show_move(penum);
			   }
			else
				code = show_fast_move(cc->wxy, pgs);
			if ( code ) return code;
			goto more;
		   }
	   }
no_cache:
	/* Character is not cached, client must render it. */
	if ( (code = gs_gsave(pgs)) < 0 ) return code;
	gs_setmatrix(pgs, &pgs->char_tm);
	penum->width_set = sws_none;
	penum->continue_proc = continue_show_update;
	/* Try using the build procedure in the font. */
	/* < 0 means error, 0 means success, 1 means failure. */
	   {	gs_font *font = pgs->font;
		code = (*font->build_char_proc)(penum, pgs, font, chr, font->build_char_data);
		if ( code < 0 ) return code;
		if ( code == 0 )
		   {	code = show_update(penum);
			if ( code < 0 ) return code;
			color_loaded = 0;
			code = show_move(penum);
			if ( code ) return code;
			goto more;
		   }
	   }
	return gs_show_render;
}

/* Continuation procedures for stringwidth */
int stringwidth_update(P1(register gs_show_enum *penum));
int stringwidth_move(P1(register gs_show_enum *penum));
int stringwidth_proceed(P1(register gs_show_enum *penum));
private int
continue_stringwidth_update(register gs_show_enum *penum)
{	int code = stringwidth_update(penum);
	if ( code < 0 ) return code;
	code = stringwidth_move(penum);
	if ( code != 0 ) return code;
	return stringwidth_proceed(penum);
}
private int
continue_stringwidth(register gs_show_enum *penum)
{	return stringwidth_proceed(penum);
}
/* Update position for stringwidth */
private int
stringwidth_update(register gs_show_enum *penum)
{	register gs_state *pgs = penum->pgs;
	/* Update position for last character */
	switch ( penum->width_set )
	   {
	case sws_none:
		return_error(gs_error_undefinedresult);	/* WRONG */
	case sws_cache:
	   {	/* Finish installing the cache entry. */
		gx_add_cached_char(pgs->font->dir, penum->cc, gx_lookup_fm_pair(pgs));
		gs_grestore(pgs);
	   }
	case sws_no_cache: ;
	   }
	gs_grestore(pgs);
	return 0;
}
/* Move to next character for stringwidth */
private int
stringwidth_move(register gs_show_enum *penum)
{	/* wxy is in device coordinates */
	return show_fast_move(penum->wxy, penum->pgs);
}
/* Process next character for stringwidth */
private int
stringwidth_proceed(register gs_show_enum *penum)
{	register gs_state *pgs = penum->pgs;
	byte *str = penum->str;
	uint index;
	cached_fm_pair *pair = 0;
	byte chr;
	int code;
more:	/* Proceed to next character */
	index = penum->index;
	chr = str[index];
	if ( (penum->use_size ? index == penum->size : !chr) )
	  { /* All done.  Since this was a stringwidth, */
	    /* save the accumulated width before returning, */
	    /* and undo the extra gsave. */
	    gs_point end_pt, start_pt;
	    gs_currentpoint(pgs, &end_pt);
	    gs_grestore(pgs);
	    gs_currentpoint(pgs, &start_pt);
	    penum->width.x = end_pt.x - start_pt.x;
	    penum->width.y = end_pt.y - start_pt.y;
	    return 0;
	  }
	penum->index++;
	if ( penum->can_cache )		/* Check cache first */
	   {	cached_char *cc;
		if ( pair == 0 )
			pair = gx_lookup_fm_pair(pgs);
		cc = gx_lookup_cached_char(pgs, pair, chr);
		if ( cc != 0 )
		   {	/* Character is in cache. */
			penum->wxy = cc->wxy;
			penum->width_set = sws_no_cache;
			code = stringwidth_move(penum);
			if ( code ) return code;
			goto more;
		   }
	   }
	/* Character is not cached, client must render it. */
	if ( (code = gs_gsave(pgs)) < 0 ) return code;
	gs_setmatrix(pgs, &pgs->char_tm);
	penum->width_set = sws_none;
	penum->continue_proc = continue_stringwidth_update;
	/* Try using the build procedure in the font. */
	/* < 0 means error, 0 means success, 1 means failure. */
	   {	gs_font *font = pgs->font;
		code = (*font->build_char_proc)(penum, pgs, font, chr, font->build_char_data);
		if ( code < 0 ) return code;
		if ( code == 0 )
		   {	code = stringwidth_update(penum);
			if ( code < 0 ) return code;
			code = stringwidth_move(penum);
			if ( code ) return code;
			goto more;
		   }
	   }
	return gs_show_render;
}

/* Return the current character for rendering. */
byte
gs_show_current_char(gs_show_enum *penum)
{	return penum->str[penum->index - 1];
}

/* Return the just-displayed character for kerning. */
byte
gs_kshow_previous_char(gs_show_enum *penum)
{	return penum->str[penum->index - 1];
}

/* Return the about-to-be-displayed character for kerning. */
byte
gs_kshow_next_char(gs_show_enum *penum)
{	return penum->str[penum->index];
}

/* Return the accumulated width for stringwidth. */
void
gs_show_width(gs_show_enum *penum, gs_point *ppt)
{	*ppt = penum->width;
}

/* ------ Internal routines ------ */

/* Initialize a show enumerator */
private int
show_setup(register gs_show_enum *penum, gs_state *pgs, char *str)
{	int code;
	penum->pgs = pgs;
	penum->str = (byte *)str;	/* avoid signed chars */
	penum->chr = no_chr;
	penum->add = 0;
	penum->do_kern = 0;
	penum->dev_cache_set = 0;
	penum->index = 0;
	penum->continue_proc = continue_show;
	if ( !pgs->char_tm_valid )
	   {	/* Compute combined transformation */
		code = gs_matrix_multiply(&pgs->font->matrix, &ctm_only(pgs), &pgs->char_tm);
		if ( code < 0 ) return code;
		pgs->char_tm_valid = 1;
	   }
	if ( penum->can_cache =	/* no skewing or non-rectangular rotation */
		(pgs->char_tm.xy == 0 && pgs->char_tm.yx == 0 ||
		 pgs->char_tm.xx == 0 && pgs->char_tm.yy == 0) )
	   {	gs_fixed_rect cbox;
		gx_cpath_box_for_check(pgs->clip_path, &cbox);
		penum->cxmin = fixed2int_ceiling(cbox.xmin);
		penum->cymin = fixed2int_ceiling(cbox.ymin);
		penum->cxmax = fixed2int(cbox.xmax);
		penum->cymax = fixed2int(cbox.ymax);
	   }
	return 0;
}