xref: /plan9-contrib/sys/src/cmd/gs/src/gxccache.c (revision d46c239f8612929b7dbade67d0d071633df3a15d)
1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998 Aladdin Enterprises.  All rights reserved.
2 
3   This file is part of AFPL Ghostscript.
4 
5   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
6   distributor accepts any responsibility for the consequences of using it, or
7   for whether it serves any particular purpose or works at all, unless he or
8   she says so in writing.  Refer to the Aladdin Free Public License (the
9   "License") for full details.
10 
11   Every copy of AFPL Ghostscript must include a copy of the License, normally
12   in a plain ASCII text file named PUBLIC.  The License grants you the right
13   to copy, modify and redistribute AFPL Ghostscript, but only under certain
14   conditions described in the License.  Among other things, the License
15   requires that the copyright notice and this notice be preserved on all
16   copies.
17 */
18 
19 /*$Id: gxccache.c,v 1.5 2001/07/05 20:36:55 raph Exp $ */
20 /* Fast case character cache routines for Ghostscript library */
21 #include "gx.h"
22 #include "gpcheck.h"
23 #include "gserrors.h"
24 #include "gsstruct.h"
25 #include "gxfixed.h"
26 #include "gxmatrix.h"
27 #include "gzstate.h"
28 #include "gzpath.h"
29 #include "gxdevice.h"
30 #include "gxdevmem.h"
31 #include "gzcpath.h"
32 #include "gxchar.h"
33 #include "gxfont.h"
34 #include "gxfcache.h"
35 #include "gxxfont.h"
36 #include "gscspace.h"		/* for gsimage.h */
37 #include "gsimage.h"
38 #include "gxhttile.h"
39 
40 /* Forward references */
41 private byte *compress_alpha_bits(P2(const cached_char *, gs_memory_t *));
42 
43 /* Define a scale factor of 1. */
44 static const gs_log2_scale_point scale_log2_1 =
45 {0, 0};
46 
47 /* Look up, and if necessary add, a font/matrix pair in the cache */
48 cached_fm_pair *
49 gx_lookup_fm_pair(gs_font * pfont, register const gs_state * pgs)
50 {
51     float mxx = pgs->char_tm.xx, mxy = pgs->char_tm.xy, myx = pgs->char_tm.yx,
52           myy = pgs->char_tm.yy;
53     gs_font *font = pfont;
54     register gs_font_dir *dir = font->dir;
55     register cached_fm_pair *pair =
56     dir->fmcache.mdata + dir->fmcache.mnext;
57     int count = dir->fmcache.mmax;
58     gs_uid uid;
59 
60     if (font->FontType == ft_composite || font->PaintType != 0) {	/* We can't cache by UID alone. */
61 	uid_set_invalid(&uid);
62     } else {
63 	uid = ((gs_font_base *) font)->UID;
64 	if (uid_is_valid(&uid))
65 	    font = 0;
66     }
67     while (count--) {
68 	if (pair == dir->fmcache.mdata)
69 	    pair += dir->fmcache.mmax;
70 	pair--;
71 	/* We have either a non-zero font and an invalid UID, */
72 	/* or a zero font and a valid UID. */
73 	/* We have to break up the test */
74 	/* because of a bug in the Zortech compiler. */
75 	if (font != 0) {
76 	    if (pair->font != font)
77 		continue;
78 	} else {
79 	    if (!uid_equal(&pair->UID, &uid) ||
80 		pair->FontType != pfont->FontType
81 		)
82 		continue;
83 	}
84 	if (pair->mxx == mxx && pair->mxy == mxy &&
85 	    pair->myx == myx && pair->myy == myy
86 	    ) {
87 	    if (pair->font == 0) {
88 		pair->font = pfont;
89 		if_debug2('k', "[k]updating pair 0x%lx with font 0x%lx\n",
90 			  (ulong) pair, (ulong) pfont);
91 	    } else {
92 		if_debug2('k', "[k]found pair 0x%lx: font=0x%lx\n",
93 			  (ulong) pair, (ulong) pair->font);
94 	    }
95 	    return pair;
96 	}
97     }
98     return gx_add_fm_pair(dir, pfont, &uid, pgs);
99 }
100 
101 /* Look up a glyph in the cache. */
102 /* The character depth must be either 1 or alt_depth. */
103 /* Return the cached_char or 0. */
104 cached_char *
105 gx_lookup_cached_char(const gs_font * pfont, const cached_fm_pair * pair,
106 		      gs_glyph glyph, int wmode, int alt_depth)
107 {
108     gs_font_dir *dir = pfont->dir;
109     uint chi = chars_head_index(glyph, pair);
110     register cached_char *cc;
111 
112     while ((cc = dir->ccache.table[chi & dir->ccache.table_mask]) != 0) {
113 	if (cc->code == glyph && cc_pair(cc) == pair &&
114 	    cc->wmode == wmode && (cc_depth(cc) == 1 || cc_depth(cc) == alt_depth)
115 	    ) {
116 	    if_debug4('K', "[K]found 0x%lx (depth=%d) for glyph=0x%lx, wmode=%d\n",
117 		      (ulong) cc, cc_depth(cc), (ulong) glyph, wmode);
118 	    return cc;
119 	}
120 	chi++;
121     }
122     if_debug3('K', "[K]not found: glyph=0x%lx, wmode=%d, alt_depth=%d\n",
123 	      (ulong) glyph, wmode, alt_depth);
124     return 0;
125 }
126 
127 /* Look up a character in an external font. */
128 /* Return the cached_char or 0. */
129 cached_char *
130 gx_lookup_xfont_char(const gs_state * pgs, cached_fm_pair * pair,
131 gs_char chr, gs_glyph glyph, const gx_xfont_callbacks * callbacks, int wmode)
132 {
133     gs_font *font = pair->font;
134     int enc_index;
135     gx_xfont *xf;
136     gx_xglyph xg;
137     gs_log2_scale_point log2_scale;
138     gs_point wxy;
139     gs_int_rect bbox;
140     cached_char *cc;
141 
142     if (font == 0)
143 	return NULL;
144     enc_index =
145 	(font->FontType == ft_composite ? -1 :
146 	 ((gs_font_base *) font)->nearest_encoding_index);
147     if (!pair->xfont_tried) {	/* Look for an xfont now. */
148 	gx_lookup_xfont(pgs, pair, enc_index);
149 	pair->xfont_tried = true;
150     }
151     xf = pair->xfont;
152     if (xf == 0)
153 	return NULL;
154     {
155 	const gx_xfont_procs *procs = xf->common.procs;
156 
157 	if (procs->char_xglyph2 == 0) {		/* The xfont can't recognize reencoded fonts. */
158 	    /* Use the registered encoding only if this glyph */
159 	    /* is the same as the one in the registered encoding. */
160 	    if (enc_index >= 0 &&
161 		(*callbacks->known_encode) (chr, enc_index) != glyph
162 		)
163 		enc_index = -1;
164 	    xg = (*procs->char_xglyph) (xf, chr, enc_index, glyph,
165 					callbacks->glyph_name);
166 	} else {		/* The xfont can recognize reencoded fonts. */
167 	    xg = (*procs->char_xglyph2) (xf, chr, enc_index, glyph,
168 					 callbacks);
169 	}
170 	if (xg == gx_no_xglyph)
171 	    return NULL;
172 	if ((*procs->char_metrics) (xf, xg, wmode, &wxy, &bbox) < 0)
173 	    return NULL;
174     }
175     log2_scale.x = log2_scale.y = 1;
176     cc = gx_alloc_char_bits(font->dir, NULL, NULL, bbox.q.x - bbox.p.x,
177 			    bbox.q.y - bbox.p.y, &log2_scale, 1);
178     if (cc == 0)
179 	return NULL;
180     /* Success.  Make the cache entry. */
181     cc->code = glyph;
182     cc->wmode = wmode;
183     cc->xglyph = xg;
184     cc->wxy.x = float2fixed(wxy.x);
185     cc->wxy.y = float2fixed(wxy.y);
186     cc->offset.x = int2fixed(-bbox.p.x);
187     cc->offset.y = int2fixed(-bbox.p.y);
188     if_debug5('k', "[k]xfont %s char %d/0x%x#0x%lx=>0x%lx\n",
189 	      font->font_name.chars, enc_index, (int)chr,
190 	      (ulong) glyph, (ulong) xg);
191     if_debug6('k', "     wxy=(%g,%g) bbox=(%d,%d),(%d,%d)\n",
192 	      wxy.x, wxy.y, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
193     gx_add_cached_char(font->dir, NULL, cc, pair, &scale_log2_1);
194     return cc;
195 }
196 
197 /* Copy a cached character to the screen. */
198 /* Assume the caller has already done gx_color_load. */
199 /* Return 0 if OK, 1 if we couldn't do the operation but no error */
200 /* should be signalled, or a negative error code. */
201 int
202 gx_image_cached_char(register gs_show_enum * penum, register cached_char * cc)
203 {
204     register gs_state *pgs = penum->pgs;
205     gx_device_color *pdevc = pgs->dev_color;
206     int x, y, w, h, depth;
207     int code;
208     gs_fixed_point pt;
209     gx_device *dev = penum->dev;
210     gx_device *imaging_dev = penum->imaging_dev ? penum->imaging_dev : dev;
211     gx_device *orig_dev = imaging_dev;
212     gx_device_clip cdev;
213     gx_xglyph xg = cc->xglyph;
214     gx_xfont *xf;
215     byte *bits;
216 
217   top:code = gx_path_current_point_inline(pgs->path, &pt);
218     if (code < 0)
219 	return code;
220     /*
221      * If the character doesn't lie entirely within the inner
222      * clipping rectangle, we set up an intermediate clipping device.
223      * Note that if the original device implements fill_mask, we may
224      * never actually use the clipping device.
225      */
226     pt.x -= cc->offset.x;
227     x = fixed2int_var_rounded(pt.x) + penum->ftx;
228     pt.y -= cc->offset.y;
229     y = fixed2int_var_rounded(pt.y) + penum->fty;
230     w = cc->width;
231     h = cc->height;
232 #ifdef DEBUG
233     if (gs_debug_c('K')) {
234 	if (cc_has_bits(cc))
235 	    debug_dump_bitmap(cc_bits(cc), cc_raster(cc), h,
236 			      "[K]bits");
237 	else
238 	    dputs("[K]no bits\n");
239 	dlprintf3("[K]copying 0x%lx, offset=(%g,%g)\n", (ulong) cc,
240 		  fixed2float(-cc->offset.x),
241 		  fixed2float(-cc->offset.y));
242 	dlprintf6("   at (%g,%g)+(%d,%d)->(%d,%d)\n",
243 		  fixed2float(pt.x), fixed2float(pt.y),
244 		  penum->ftx, penum->fty, x, y);
245     }
246 #endif
247     if ((x < penum->ibox.p.x || x + w > penum->ibox.q.x ||
248 	 y < penum->ibox.p.y || y + h > penum->ibox.q.y) &&
249 	imaging_dev != (gx_device *) & cdev	/* might be 2nd time around */
250 	) {			/* Check for the character falling entirely outside */
251 	/* the clipping region. */
252 	gx_clip_path *pcpath;
253 
254 	if (x >= penum->obox.q.x || x + w <= penum->obox.p.x ||
255 	    y >= penum->obox.q.y || y + h <= penum->obox.p.y
256 	    )
257 	    return 0;		/* nothing to do */
258 	code = gx_effective_clip_path(pgs, &pcpath);
259 	if (code < 0)
260 	    return code;
261 	gx_make_clip_device(&cdev, gx_cpath_list(pcpath));
262 	cdev.target = imaging_dev;
263 	imaging_dev = (gx_device *) & cdev;
264 	(*dev_proc(imaging_dev, open_device)) (imaging_dev);
265 	if_debug0('K', "[K](clipping)\n");
266     }
267     /* If an xfont can render this character, use it. */
268     if (xg != gx_no_xglyph && (xf = cc_pair(cc)->xfont) != 0) {
269 	int cx = x + fixed2int(cc->offset.x);
270 	int cy = y + fixed2int(cc->offset.y);
271 
272 	/*
273 	 * Note that we prefer a 1-bit xfont implementation over
274 	 * a multi-bit cached bitmap.  Eventually we should change
275 	 * the xfont interface so it can deliver multi-bit bitmaps,
276 	 * or else implement oversampling for xfonts.
277 	 */
278 	if (gs_color_writes_pure(pgs)) {
279 	    code = (*xf->common.procs->render_char) (xf, xg,
280 					imaging_dev, cx, cy,
281 					pdevc->colors.pure, 0);
282 	    if_debug8('K', "[K]render_char display: xfont=0x%lx, glyph=0x%lx\n\tdev=0x%lx(%s) x,y=%d,%d, color=0x%lx => %d\n",
283 		      (ulong) xf, (ulong) xg, (ulong) imaging_dev,
284 		      imaging_dev->dname, cx, cy,
285 		      (ulong) pdevc->colors.pure, code);
286 	    if (code == 0)
287 		return_check_interrupt(0);
288 	}
289 	/* Can't render directly.  If we don't have a bitmap yet, */
290 	/* get it from the xfont now. */
291 	if (!cc_has_bits(cc)) {
292 	    gx_device_memory mdev;
293 
294 	    gs_make_mem_mono_device(&mdev, 0, imaging_dev);
295 	    gx_open_cache_device(&mdev, cc);
296 	    code = (*xf->common.procs->render_char) (xf, xg,
297 				       (gx_device *) & mdev, cx - x, cy - y,
298 						     (gx_color_index) 1, 1);
299 	    if_debug7('K', "[K]render_char to bits: xfont=0x%lx, glyph=0x%lx\n\tdev=0x%lx(%s) x,y=%d,%d => %d\n",
300 		      (ulong) xf, (ulong) xg, (ulong) & mdev,
301 		      mdev.dname, cx - x, cy - y, code);
302 	    if (code != 0)
303 		return_check_interrupt(1);
304 	    gx_add_char_bits(cc_pair(cc)->font->dir,
305 			     cc, &scale_log2_1);
306 	    /* gx_add_char_bits may change width, height, */
307 	    /* raster, and/or offset.  It's easiest to */
308 	    /* start over from the top.  Clear xg so that */
309 	    /* we don't waste time trying render_char again. */
310 	    xg = gx_no_xglyph;
311 	    goto top;
312 	}
313     }
314     /*
315      * No xfont.  Render from the cached bits.  If the cached bits
316      * have more than 1 bit of alpha, and the color isn't pure or
317      * the copy_alpha operation fails, construct a single-bit mask
318      * by taking the high-order alpha bit.
319      */
320     bits = cc_bits(cc);
321     depth = cc_depth(cc);
322     if (dev_proc(orig_dev, fill_mask) != gx_default_fill_mask ||
323 	!lop_no_S_is_T(pgs->log_op)
324 	) {
325 	gx_clip_path *pcpath;
326 
327 	code = gx_effective_clip_path(pgs, &pcpath);
328 	if (code >= 0) {
329 	    code = (*dev_proc(orig_dev, fill_mask))
330 		(orig_dev, bits, 0, cc_raster(cc), cc->id,
331 		 x, y, w, h, pdevc, depth, pgs->log_op, pcpath);
332 	    if (code >= 0)
333 		goto done;
334 	}
335     } else if (gs_color_writes_pure(pgs)) {
336 	gx_color_index color = pdevc->colors.pure;
337 
338 	if (depth > 1) {
339 	    code = (*dev_proc(imaging_dev, copy_alpha))
340 		(imaging_dev, bits, 0, cc_raster(cc), cc->id,
341 		 x, y, w, h, color, depth);
342 	    if (code >= 0)
343 		return_check_interrupt(0);
344 	    /* copy_alpha failed, construct a monobit mask. */
345 	    bits = compress_alpha_bits(cc, &gs_memory_default);
346 	    if (bits == 0)
347 		return 1;	/* VMerror, but recoverable */
348 	}
349 	code = (*dev_proc(imaging_dev, copy_mono))
350 	    (imaging_dev, bits, 0, cc_raster(cc), cc->id,
351 	     x, y, w, h, gx_no_color_index, pdevc->colors.pure);
352 	goto done;
353     }
354     if (depth > 1) {		/* Complex color or fill_mask / copy_alpha failed, */
355 	/* construct a monobit mask. */
356 	bits = compress_alpha_bits(cc, &gs_memory_default);
357 	if (bits == 0)
358 	    return 1;		/* VMerror, but recoverable */
359 
360     } {				/* Use imagemask to render the character. */
361 	gs_memory_t *mem = &gs_memory_default;
362 	gs_image_enum *pie =
363 	    gs_image_enum_alloc(mem, "image_char(image_enum)");
364 	gs_image_t image;
365 	int iy;
366 	uint used;
367 
368 	if (pie == 0) {
369 	    if (bits != cc_bits(cc))
370 		gs_free_object(&gs_memory_default, bits,
371 			       "compress_alpha_bits");
372 	    return 1;		/* VMerror, but recoverable */
373 	}
374 	/* Make a matrix that will place the image */
375 	/* at (x,y) with no transformation. */
376 	gs_image_t_init_mask(&image, true);
377 #define mat image.ImageMatrix
378 	gs_make_translation((floatp) - x, (floatp) - y, &mat);
379 	gs_matrix_multiply(&ctm_only(pgs), &mat, &mat);
380 #undef mat
381 	image.Width = w;
382 	image.Height = h;
383 	image.adjust = false;
384 	code = gs_image_init(pie, &image, false, pgs);
385 	switch (code) {
386 	    case 1:		/* empty image */
387 		code = 0;
388 	    default:
389 		break;
390 	    case 0:
391 		for (iy = 0; iy < h && code >= 0; iy++)
392 		    code = gs_image_next(pie, bits + iy * cc_raster(cc),
393 					 (w + 7) >> 3, &used);
394 		gs_image_cleanup(pie);
395 	}
396 	gs_free_object(mem, pie, "image_char(image_enum)");
397     }
398   done:if (bits != cc_bits(cc))
399 	gs_free_object(&gs_memory_default, bits, "compress_alpha_bits");
400     if (code > 0)
401 	code = 0;
402     return_check_interrupt(code);
403 }
404 
405 /* ------ Image manipulation ------ */
406 
407 /*
408  * Compress a mask with 2 or 4 bits of alpha to a monobit mask.
409  * Allocate and return the address of the monobit mask.
410  */
411 private byte *
412 compress_alpha_bits(const cached_char * cc, gs_memory_t * mem)
413 {
414     const byte *data = cc_const_bits(cc);
415     uint width = cc->width;
416     uint height = cc->height;
417     int log2_scale = cc_depth(cc);
418     int scale = 1 << log2_scale;
419     uint sraster = cc_raster(cc);
420     uint sskip = sraster - ((width * scale + 7) >> 3);
421     uint draster = bitmap_raster(width);
422     uint dskip = draster - ((width + 7) >> 3);
423     byte *mask = gs_alloc_bytes(mem, draster * height,
424 				"compress_alpha_bits");
425     const byte *sptr = data;
426     byte *dptr = mask;
427     uint h;
428 
429     if (mask == 0)
430 	return 0;
431     for (h = height; h; --h) {
432 	byte sbit = 0x80;
433 	byte d = 0;
434 	byte dbit = 0x80;
435 	uint w;
436 
437 	for (w = width; w; --w) {
438 	    if (*sptr & sbit)
439 		d += dbit;
440 	    if (!(sbit >>= log2_scale))
441 		sbit = 0x80, sptr++;
442 	    if (!(dbit >>= 1))
443 		dbit = 0x80, dptr++, d = 0;
444 	}
445 	if (dbit != 0x80)
446 	    *dptr++ = d;
447 	for (w = dskip; w != 0; --w)
448 	    *dptr++ = 0;
449 	sptr += sskip;
450     }
451     return mask;
452 }
453