xref: /plan9/sys/src/cmd/gs/src/gxccache.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gxccache.c,v 1.34 2005/06/15 18:40:07 igor Exp $ */
18 /* Fast case character cache routines for Ghostscript library */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gpcheck.h"
22 #include "gserrors.h"
23 #include "gsstruct.h"
24 #include "gscencs.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(const cached_char *, gs_memory_t *);
42 
43 /* Define a scale factor of 1. */
44 private const gs_log2_scale_point scale_log2_1 =
45 {0, 0};
46 
47 void
gx_compute_char_matrix(const gs_matrix * char_tm,const gs_log2_scale_point * log2_scale,float * mxx,float * mxy,float * myx,float * myy)48 gx_compute_char_matrix(const gs_matrix *char_tm, const gs_log2_scale_point *log2_scale,
49     float *mxx, float *mxy, float *myx, float *myy)
50 {
51     int scale_x = 1 << log2_scale->x;
52     int scale_y = 1 << log2_scale->y;
53 
54     *mxx = char_tm->xx * scale_x;
55     *mxy = char_tm->xy * scale_x;
56     *myx = char_tm->yx * scale_y;
57     *myy = char_tm->yy * scale_y;
58 }
59 
60 void
gx_compute_ccache_key(gs_font * pfont,const gs_matrix * char_tm,const gs_log2_scale_point * log2_scale,bool design_grid,float * mxx,float * mxy,float * myx,float * myy)61 gx_compute_ccache_key(gs_font * pfont, const gs_matrix *char_tm,
62     const gs_log2_scale_point *log2_scale, bool design_grid,
63     float *mxx, float *mxy, float *myx, float *myy)
64 {
65     if (design_grid &&
66 	    (pfont->FontType == ft_TrueType || pfont->FontType == ft_CID_TrueType)) {
67 	/*
68 	 * We need a special face for this case, because the TT interpreter
69 	 * can't generate both grid_fitted and non-grid-fitted outlines
70 	 * with a same face instance. This happens due to control
71 	 * values in 'cvt' must be different.
72 	 * Since a single face satisfies all font sizes,
73 	 * we use a zero matrix as the cache entry key.
74 	 */
75 	*mxx = *mxy = *myx = *myy = 0;
76     } else
77 	gx_compute_char_matrix(char_tm, log2_scale, mxx, mxy, myx, myy);
78 }
79 
80 /* Look up, and if necessary add, a font/matrix pair in the cache */
81 int
gx_lookup_fm_pair(gs_font * pfont,const gs_matrix * char_tm,const gs_log2_scale_point * log2_scale,bool design_grid,cached_fm_pair ** ppair)82 gx_lookup_fm_pair(gs_font * pfont, const gs_matrix *char_tm,
83     const gs_log2_scale_point *log2_scale, bool design_grid, cached_fm_pair **ppair)
84 {
85     float mxx, mxy, myx, myy;
86     gs_font *font = pfont;
87     register gs_font_dir *dir = font->dir;
88     register cached_fm_pair *pair =
89     dir->fmcache.mdata + dir->fmcache.mnext;
90     int count = dir->fmcache.mmax;
91     gs_uid uid;
92 
93     gx_compute_ccache_key(pfont, char_tm, log2_scale, design_grid,
94 			    &mxx, &mxy, &myx, &myy);
95     if (font->FontType == ft_composite || font->PaintType != 0) {	/* We can't cache by UID alone. */
96 	uid_set_invalid(&uid);
97     } else {
98 	uid = ((gs_font_base *) font)->UID;
99 	if (uid_is_valid(&uid))
100 	    font = 0;
101     }
102     while (count--) {
103 	if (pair == dir->fmcache.mdata)
104 	    pair += dir->fmcache.mmax;
105 	pair--;
106 	/* We have either a non-zero font and an invalid UID, */
107 	/* or a zero font and a valid UID. */
108 	/* We have to break up the test */
109 	/* because of a bug in the Zortech compiler. */
110 	if (font != 0) {
111 	    if (pair->font != font)
112 		continue;
113 	} else {
114 	    if (!uid_equal(&pair->UID, &uid) ||
115 		pair->FontType != pfont->FontType
116 		)
117 		continue;
118 	}
119 	if (pair->mxx == mxx && pair->mxy == mxy &&
120 	    pair->myx == myx && pair->myy == myy
121 	    && pair->design_grid == design_grid) {
122 	    if (pair->font == 0) {
123 		pair->font = pfont;
124 		if_debug2('k', "[k]updating pair 0x%lx with font 0x%lx\n",
125 			  (ulong) pair, (ulong) pfont);
126 	    } else {
127 		if_debug2('k', "[k]found pair 0x%lx: font=0x%lx\n",
128 			  (ulong) pair, (ulong) pair->font);
129 	    }
130 	    *ppair = pair;
131 	    return 0;
132 	}
133     }
134     return gx_add_fm_pair(dir, pfont, &uid, char_tm, log2_scale, design_grid, ppair);
135 }
136 
137 /* Look up a glyph with the right depth in the cache. */
138 /* Return the cached_char or 0. */
139 cached_char *
gx_lookup_cached_char(const gs_font * pfont,const cached_fm_pair * pair,gs_glyph glyph,int wmode,int depth,gs_fixed_point * subpix_origin)140 gx_lookup_cached_char(const gs_font * pfont, const cached_fm_pair * pair,
141 		      gs_glyph glyph, int wmode, int depth,
142 		      gs_fixed_point *subpix_origin)
143 {
144     gs_font_dir *dir = pfont->dir;
145     uint chi = chars_head_index(glyph, pair);
146     register cached_char *cc;
147 
148     while ((cc = dir->ccache.table[chi & dir->ccache.table_mask]) != 0) {
149 	if (cc->code == glyph && cc_pair(cc) == pair &&
150 	    cc->subpix_origin.x == subpix_origin->x &&
151 	    cc->subpix_origin.y == subpix_origin->y &&
152 	    cc->wmode == wmode && cc_depth(cc) == depth
153 	    ) {
154 	    if_debug4('K', "[K]found 0x%lx (depth=%d) for glyph=0x%lx, wmode=%d\n",
155 		      (ulong) cc, cc_depth(cc), (ulong) glyph, wmode);
156 	    return cc;
157 	}
158 	chi++;
159     }
160     if_debug3('K', "[K]not found: glyph=0x%lx, wmode=%d, depth=%d\n",
161 	      (ulong) glyph, wmode, depth);
162     return 0;
163 }
164 
165 /* Look up a character in an external font. */
166 /* Return the cached_char or 0. */
167 cached_char *
gx_lookup_xfont_char(const gs_state * pgs,cached_fm_pair * pair,gs_char chr,gs_glyph glyph,int wmode)168 gx_lookup_xfont_char(const gs_state * pgs, cached_fm_pair * pair,
169 		     gs_char chr, gs_glyph glyph, int wmode)
170 {
171     gs_font *font = pair->font;
172     int enc_index;
173     gx_xfont *xf;
174     gx_xglyph xg;
175     gs_log2_scale_point log2_scale;
176     gs_point wxy;
177     gs_int_rect bbox;
178     cached_char *cc;
179 
180     if (font == 0)
181 	return NULL;
182     enc_index =
183 	(font->FontType == ft_composite ? -1 :
184 	 ((gs_font_base *) font)->nearest_encoding_index);
185     if (!pair->xfont_tried) {	/* Look for an xfont now. */
186 	gx_lookup_xfont(pgs, pair, enc_index);
187 	pair->xfont_tried = true;
188     }
189     xf = pair->xfont;
190     if (xf == 0)
191 	return NULL;
192     {
193 	const gx_xfont_procs *procs = xf->common.procs;
194 	gs_const_string gstr;
195 	int code = font->procs.glyph_name(font, glyph, &gstr);
196 
197 	if (code < 0)
198 	    return NULL;
199 	if (enc_index >= 0 && ((gs_font_base *)font)->encoding_index < 0) {
200 	    /*
201 	     * Use the registered encoding only if this glyph
202 	     * is the same as the one in the registered encoding.
203 	     */
204 	    gs_const_string kstr;
205 
206 	    if (gs_c_glyph_name(gs_c_known_encode(chr, enc_index), &kstr) < 0 ||
207 		kstr.size != gstr.size ||
208 		memcmp(kstr.data, gstr.data, kstr.size)
209 		)
210 		enc_index = -1;
211 	}
212 	xg = procs->char_xglyph(xf, chr, enc_index, glyph, &gstr);
213 	if (xg == gx_no_xglyph)
214 	    return NULL;
215 	if ((*procs->char_metrics) (xf, xg, wmode, &wxy, &bbox) < 0)
216 	    return NULL;
217     }
218     log2_scale.x = log2_scale.y = 1;
219     cc = gx_alloc_char_bits(font->dir, NULL, NULL,
220 		(ushort)(bbox.q.x - bbox.p.x), (ushort)(bbox.q.y - bbox.p.y),
221 		&log2_scale, 1);
222     if (cc == 0)
223 	return NULL;
224     /* Success.  Make the cache entry. */
225     cc->code = glyph;
226     cc->wmode = wmode;
227     cc->xglyph = xg;
228     cc->wxy.x = float2fixed(wxy.x);
229     cc->wxy.y = float2fixed(wxy.y);
230     cc->offset.x = int2fixed(-bbox.p.x);
231     cc->offset.y = int2fixed(-bbox.p.y);
232     cc_set_pair(cc, pair);
233     if_debug5('k', "[k]xfont %s char %d/0x%x#0x%lx=>0x%lx\n",
234 	      font->font_name.chars, enc_index, (int)chr,
235 	      (ulong) glyph, (ulong) xg);
236     if_debug6('k', "     wxy=(%g,%g) bbox=(%d,%d),(%d,%d)\n",
237 	      wxy.x, wxy.y, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
238     gx_add_cached_char(font->dir, NULL, cc, pair, &scale_log2_1);
239     return cc;
240 }
241 
242 /* Copy a cached character to the screen. */
243 /* Assume the caller has already done gx_color_load. */
244 /* Return 0 if OK, 1 if we couldn't do the operation but no error */
245 /* should be signalled, or a negative error code. */
246 int
gx_image_cached_char(register gs_show_enum * penum,register cached_char * cc)247 gx_image_cached_char(register gs_show_enum * penum, register cached_char * cc)
248 {
249     register gs_state *pgs = penum->pgs;
250     gx_device_color *pdevc = pgs->dev_color;
251     int x, y, w, h, depth;
252     int code;
253     gs_fixed_point pt;
254     gx_device *dev = penum->dev;
255     gx_device *imaging_dev = penum->imaging_dev ? penum->imaging_dev : dev;
256     gx_device *orig_dev = imaging_dev;
257     gx_device_clip cdev;
258     gx_xglyph xg = cc->xglyph;
259     gx_xfont *xf;
260     byte *bits;
261 
262   top:code = gx_path_current_point_inline(pgs->path, &pt);
263     if (code < 0)
264 	return code;
265     /*
266      * If the character doesn't lie entirely within the inner
267      * clipping rectangle, we set up an intermediate clipping device.
268      * Note that if the original device implements fill_mask, we may
269      * never actually use the clipping device.
270      */
271     pt.x -= cc->offset.x + cc->subpix_origin.x;
272     x = fixed2int_var_rounded(pt.x) + penum->ftx;
273     pt.y -= cc->offset.y + cc->subpix_origin.y;
274     y = fixed2int_var_rounded(pt.y) + penum->fty;
275     w = cc->width;
276     h = cc->height;
277 #ifdef DEBUG
278     if (gs_debug_c('K')) {
279 	if (cc_has_bits(cc))
280 	    debug_dump_bitmap(cc_bits(cc), cc_raster(cc), h,
281 			      "[K]bits");
282 	else
283 	    dputs("[K]no bits\n");
284 	dlprintf3("[K]copying 0x%lx, offset=(%g,%g)\n", (ulong) cc,
285 		  fixed2float(-cc->offset.x),
286 		  fixed2float(-cc->offset.y));
287 	dlprintf6("   at (%g,%g)+(%d,%d)->(%d,%d)\n",
288 		  fixed2float(pt.x), fixed2float(pt.y),
289 		  penum->ftx, penum->fty, x, y);
290     }
291 #endif
292     if ((x < penum->ibox.p.x || x + w > penum->ibox.q.x ||
293 	 y < penum->ibox.p.y || y + h > penum->ibox.q.y) &&
294 	imaging_dev != (gx_device *) & cdev	/* might be 2nd time around */
295 	) {			/* Check for the character falling entirely outside */
296 	/* the clipping region. */
297 	gx_clip_path *pcpath;
298 
299 	if (x >= penum->obox.q.x || x + w <= penum->obox.p.x ||
300 	    y >= penum->obox.q.y || y + h <= penum->obox.p.y
301 	    )
302 	    return 0;		/* nothing to do */
303 	code = gx_effective_clip_path(pgs, &pcpath);
304 	if (code < 0)
305 	    return code;
306 	gx_make_clip_device(&cdev, gx_cpath_list(pcpath));
307 	cdev.target = imaging_dev;
308 	imaging_dev = (gx_device *) & cdev;
309 	(*dev_proc(imaging_dev, open_device)) (imaging_dev);
310 	if_debug0('K', "[K](clipping)\n");
311     }
312     gx_set_dev_color(pgs);
313     /* If an xfont can render this character, use it. */
314     if (xg != gx_no_xglyph && (xf = cc_pair(cc)->xfont) != 0) {
315 	int cx = x + fixed2int(cc->offset.x);
316 	int cy = y + fixed2int(cc->offset.y);
317 
318 	/*
319 	 * Note that we prefer a 1-bit xfont implementation over
320 	 * a multi-bit cached bitmap.  Eventually we should change
321 	 * the xfont interface so it can deliver multi-bit bitmaps,
322 	 * or else implement oversampling for xfonts.
323 	 */
324 	if (gs_color_writes_pure(pgs)) {
325 	    code = (*xf->common.procs->render_char) (xf, xg,
326 					imaging_dev, cx, cy,
327 					pdevc->colors.pure, 0);
328 	    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",
329 		      (ulong) xf, (ulong) xg, (ulong) imaging_dev,
330 		      imaging_dev->dname, cx, cy,
331 		      (ulong) pdevc->colors.pure, code);
332 	    if (code == 0)
333 		return_check_interrupt(penum->memory, 0);
334 	}
335 	/* Can't render directly.  If we don't have a bitmap yet, */
336 	/* get it from the xfont now. */
337 	if (!cc_has_bits(cc)) {
338 	    gx_device_memory mdev;
339 
340 	    gs_make_mem_mono_device(&mdev, dev->memory, imaging_dev);
341 	    gx_open_cache_device(&mdev, cc);
342 	    code = (*xf->common.procs->render_char) (xf, xg,
343 				       (gx_device *) & mdev, cx - x, cy - y,
344 						     (gx_color_index) 1, 1);
345 	    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",
346 		      (ulong) xf, (ulong) xg, (ulong) & mdev,
347 		      mdev.dname, cx - x, cy - y, code);
348 	    if (code != 0)
349 		return_check_interrupt(penum->memory, 1);
350 	    gx_add_char_bits(cc_pair(cc)->font->dir,
351 			     cc, &scale_log2_1);
352 	    /* gx_add_char_bits may change width, height, */
353 	    /* raster, and/or offset.  It's easiest to */
354 	    /* start over from the top.  Clear xg so that */
355 	    /* we don't waste time trying render_char again. */
356 	    xg = gx_no_xglyph;
357 	    goto top;
358 	}
359     }
360     /*
361      * No xfont.  Render from the cached bits.  If the cached bits
362      * have more than 1 bit of alpha, and the color isn't pure or
363      * the copy_alpha operation fails, construct a single-bit mask
364      * by taking the high-order alpha bit.
365      */
366     bits = cc_bits(cc);
367     /* With 4x2 scale, depth == 3.
368      * An example is -dTextAlphaBits=4 comparefiles/fonttest.pdf .
369      * We need to map 4 bitmap bits to 2 alpha bits.
370      */
371     depth = (cc_depth(cc) == 3 ? 2 : cc_depth(cc));
372     if (dev_proc(orig_dev, fill_mask) != gx_default_fill_mask ||
373 	!lop_no_S_is_T(pgs->log_op)
374 	) {
375 	gx_clip_path *pcpath;
376 
377 	code = gx_effective_clip_path(pgs, &pcpath);
378 	if (code >= 0) {
379 	    code = (*dev_proc(orig_dev, fill_mask))
380 		(orig_dev, bits, 0, cc_raster(cc), cc->id,
381 		 x, y, w, h, pdevc, depth, pgs->log_op, pcpath);
382 	    if (code >= 0)
383 		goto done;
384 	}
385     } else if (gs_color_writes_pure(pgs)) {
386 	gx_color_index color = pdevc->colors.pure;
387 
388 	if (depth > 1) {
389 	    code = (*dev_proc(imaging_dev, copy_alpha))
390 		(imaging_dev, bits, 0, cc_raster(cc), cc->id,
391 		 x, y, w, h, color, depth);
392 	    if (code >= 0)
393 		return_check_interrupt(penum->memory, 0);
394 	    /* copy_alpha failed, construct a monobit mask. */
395 	    bits = compress_alpha_bits(cc, penum->memory->non_gc_memory);
396 	    if (bits == 0)
397 		return 1;	/* VMerror, but recoverable */
398 	}
399 	code = (*dev_proc(imaging_dev, copy_mono))
400 	    (imaging_dev, bits, 0, bitmap_raster(w), gs_no_id,
401 	     x, y, w, h, gx_no_color_index, color);
402 	goto done;
403     }
404     if (depth > 1) {		/* Complex color or fill_mask / copy_alpha failed, */
405 	/* construct a monobit mask. */
406 	bits = compress_alpha_bits(cc, penum->memory->non_gc_memory);
407 	if (bits == 0)
408 	    return 1;		/* VMerror, but recoverable */
409 
410     } {				/* Use imagemask to render the character. */
411 	gs_memory_t *mem = penum->memory->non_gc_memory;
412 	gs_image_enum *pie =
413 	    gs_image_enum_alloc(mem, "image_char(image_enum)");
414 	gs_image_t image;
415 	int iy;
416 	uint used, raster = (bits == cc_bits(cc) ? cc_raster(cc)
417 			     : bitmap_raster(cc->width) );
418 	int code1;
419 
420 	if (pie == 0) {
421 	    if (bits != cc_bits(cc))
422 		gs_free_object(mem, bits,
423 			       "compress_alpha_bits");
424 	    return 1;		/* VMerror, but recoverable */
425 	}
426 	/* Make a matrix that will place the image */
427 	/* at (x,y) with no transformation. */
428 	gs_image_t_init_mask(&image, true);
429 #define mat image.ImageMatrix
430 	gs_make_translation((floatp) - x, (floatp) - y, &mat);
431 	gs_matrix_multiply(&ctm_only(pgs), &mat, &mat);
432 #undef mat
433 	image.Width = w;
434 	image.Height = h;
435 	image.adjust = false;
436 	code = gs_image_init(pie, &image, false, pgs);
437 	switch (code) {
438 	    case 1:		/* empty image */
439 		code = 0;
440 	    default:
441 		break;
442 	    case 0:
443 		for (iy = 0; iy < h && code >= 0; iy++)
444 		    code = gs_image_next(pie, bits + iy * raster,
445 					 (w + 7) >> 3, &used);
446 	}
447 	code1 = gs_image_cleanup_and_free_enum(pie);
448 	if (code >= 0 && code1 < 0)
449 	    code = code1;
450     }
451   done:if (bits != cc_bits(cc))
452 	gs_free_object(penum->memory->non_gc_memory, bits, "compress_alpha_bits");
453     if (code > 0)
454 	code = 0;
455     return_check_interrupt(penum->memory, code);
456 }
457 
458 /* ------ Image manipulation ------ */
459 
460 /*
461  * Compress a mask with 2 or 4 bits of alpha to a monobit mask.
462  * Allocate and return the address of the monobit mask.
463  */
464 private byte *
compress_alpha_bits(const cached_char * cc,gs_memory_t * mem)465 compress_alpha_bits(const cached_char * cc, gs_memory_t * mem)
466 {
467     const byte *data = cc_const_bits(cc);
468     uint width = cc->width;
469     uint height = cc->height;
470     /* With 4x2 scale, depth == 3.
471      * An example is -dTextAlphaBits=4 comparefiles/fonttest.pdf .
472      * We need to map 4 bitmap bits to 2 alpha bits.
473      */
474     int depth = (cc_depth(cc) == 3 ? 2 : cc_depth(cc));
475     uint sraster = cc_raster(cc);
476     uint sskip = sraster - ((width * depth + 7) >> 3);
477     uint draster = bitmap_raster(width);
478     uint dskip = draster - ((width + 7) >> 3);
479     byte *mask = gs_alloc_bytes(mem, draster * height,
480 				"compress_alpha_bits");
481     const byte *sptr = data;
482     byte *dptr = mask;
483     uint h;
484 
485     if (mask == 0)
486 	return 0;
487     for (h = height; h; --h) {
488 	byte sbit = 0x80;
489 	byte d = 0;
490 	byte dbit = 0x80;
491 	uint w;
492 
493 	for (w = width; w; --w) {
494 	    if (*sptr & sbit)
495 		d += dbit;
496 	    if (!(sbit >>= depth))
497 		sbit = 0x80, sptr++;
498 	    if (!(dbit >>= 1)) {
499 		*dptr++ = d;
500 		dbit = 0x80, d = 0;
501 	    }
502 	}
503 	if (dbit != 0x80)
504 	    *dptr++ = d;
505 	for (w = dskip; w != 0; --w)
506 	    *dptr++ = 0;
507 	if (sbit != 0x80)
508 	    ++sptr;
509 	sptr += sskip;
510     }
511     return mask;
512 }
513