#ifndef lint static char sccsid[] = "@(#)fontcache.c 9.5 88/02/10 Copyright 1985 Sun Micro"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ /*- Font cache management routines fontcache.c, Mon Dec 2 13:11:53 1985 James Gosling, Sun Microsystems */ #include #ifdef REF #include #include #endif #include "font.h" #include "fontcache.h" #include "shape.h" #include "cscript.h" #include extern prtxt_get_rendering_info(); extern prtxt_get_stringwidth(); static struct font_opsvector ASCIIencoding_vector = { prtxt_get_rendering_info, prtxt_get_stringwidth, 0, }; extern prtxt_get_rendering_info_JISC6226(); extern prtxt_get_stringwidth_JISC6226(); static struct font_opsvector JISC6226Encoding_vector = { prtxt_get_rendering_info_JISC6226, prtxt_get_stringwidth_JISC6226, 0, }; static struct font_opsvector *font_ops[] = { &ASCIIencoding_vector, /* ASCIIencoding */ &ASCIIencoding_vector, /* AdobeEncoding */ &JISC6226Encoding_vector, /* JISC6226Encoding */ &ASCIIencoding_vector, /* CyrillicEncoding */ &ASCIIencoding_vector, /* HangulEncoding */ &ASCIIencoding_vector, /* DevenageriEncoding */ &ASCIIencoding_vector, /* AdobeSymbolEncoding */ }; struct graphics_context *temp_context; static ValidateFont(pf) register struct psfont *pf; { register struct cachedfont *f = pf->lasthit; register struct cachedfont *nf; register struct fontfamily *ff = pf->family; register i; char fname[400]; sprintf(fname, "%s/%s", ff->directory, f->font.name); nf = (struct cachedfont *) cst_readbfont(fname, &((struct cachedfont *) 0)->font); assert(nf != 0); if (nf == 0) { /* try to be semi-graceful about missing font files */ f->font.u.ops = font_ops[(int) nf->font.encoding]; f->font.name = (char *) ff; f->valid = 1; /* current_process->error_code = ioerror_error_code; */ return; } nf->hash = f->hash; nf->valid = 1; nf->next = f->next; nf->font.u.ops = font_ops[(int) nf->font.encoding]; nf->font.name = (char *) ff; if (f == ff->printermatched) ff->printermatched = nf; else { for (i = 0; i < FONTTABLESIZE; i++) if (ff->table[i] == f) ff->table[i] = nf; { register struct cachedfont **prev; prev = &ff->hash[((unsigned short) ((nf->hash >> 16) ^ nf->hash)) % FONTHASHSIZE]; while (*prev && *prev != f) prev = &(*prev)->next; if (*prev) *prev = nf; } } pf->lasthit = nf; nf->refcnt = 1; } struct font * cs_concretefont(gc) register struct graphics_context *gc; { register struct psfont *pf = gc->font; register struct cachedfont *f; fract matrix[2][2]; register scale; if (pf->revision == gc->transform.revision) { return &pf->lasthit->font; } pf->revision = gc->transform.revision; if (pf->lasthit) { pf->lasthit->refcnt--; pf->lasthit = 0; } if (gc->transform.simplescale && pf->simplescale && (!gc->printermatch || pf->family->printermatched == 0)) { if (gc->transform.kind == tro_neg) scale = cfloorfr(min(pf->matrix[0][0],pf->matrix[1][1])); else { register scaley; scale = floorfr(frmul(pf->matrix[0][0], gc->transform.matrix[0][0])); scaley = floorfr(frmul(pf->matrix[1][1], gc->transform.matrix[1][1])); if (scaley < scale) scale = scaley; } if (scale >= 0 && scale < FONTTABLESIZE && (f = pf->family->table[scale]) != 0) { f->refcnt++; pf->lasthit = f; if (!f->valid) ValidateFont(pf); return &pf->lasthit->font; } } { register hash; if (gc->transform.kind == tro_neg) if (pf->simplescale) { matrix[0][0] = pf->matrix[0][0]; matrix[0][1] = 0; matrix[1][0] = 0; matrix[1][1] = pf->matrix[0][0]; } else { matrix[0][0] = pf->matrix[0][0]; matrix[0][1] = pf->matrix[0][1]; matrix[1][0] = pf->matrix[1][0]; matrix[1][1] = pf->matrix[1][1]; } else if (pf->simplescale) { matrix[0][0] = frmul(pf->matrix[0][0], gc->transform.matrix[0][0]); matrix[0][1] = frmul(pf->matrix[0][0], -gc->transform.matrix[0][1]); matrix[1][0] = frmul(pf->matrix[0][0], gc->transform.matrix[1][0]); matrix[1][1] = frmul(pf->matrix[0][0], -gc->transform.matrix[1][1]); } else { matrix[0][0] = frmul(pf->matrix[0][0], gc->transform.matrix[0][0]) + frmul(pf->matrix[0][1], gc->transform.matrix[1][0]); matrix[1][0] = frmul(pf->matrix[1][0], gc->transform.matrix[0][0]) + frmul(pf->matrix[1][1], gc->transform.matrix[1][0]); matrix[0][1] = frmul(pf->matrix[0][0], -gc->transform.matrix[0][1]) + frmul(pf->matrix[0][1], -gc->transform.matrix[1][1]); matrix[1][1] = frmul(pf->matrix[1][0], -gc->transform.matrix[0][1]) + frmul(pf->matrix[1][1], -gc->transform.matrix[1][1]); } hash = HASHFONT(matrix); f = pf->family->hash[((unsigned short) ((hash >> 16) ^ hash)) % FONTHASHSIZE]; pf->lasthit = 0; for (; f; f = f->next) if (f->hash == hash && f->font.matrix[0][0] == matrix[0][0] && f->font.matrix[0][1] == matrix[0][1] && f->font.matrix[1][0] == matrix[1][0] && f->font.matrix[1][1] == matrix[1][1]) { pf->lasthit = f; if (f->font.printermatched != gc->printermatch && pf->family->printermatched != 0) continue; f->refcnt++; if (!f->valid) { ValidateFont(pf); f = pf->lasthit; } return &f->font; } } /* No such font!! */ if (pf->lasthit == 0) { register fract xscale; xscale = roundfr(frhypotenuse(matrix[0][0], matrix[1][0])); scale = roundfr(frhypotenuse(matrix[0][1], matrix[1][1])); if (xscale < scale) scale = xscale; if (scale < FONTTABLESIZE && scale >= 0) /* scale can be -ve in bizarre overflow situations */ pf->lasthit = pf->family->table[scale]; else pf->lasthit = pf->family->table[FONTTABLESIZE - 1]; } if (pf->family->printermatched || pf->lasthit == 0) ComputeMatchingVersion(pf, matrix); if (!pf->lasthit->valid) ValidateFont(pf); pf->lasthit->refcnt++; return &pf->lasthit->font; } #define NSYNTH 2 static struct cachedfont *synthetic_fonts[NSYNTH]; static synth_used; static synth_scan; /* * Given a psfont build a printer matched font that corresponds to it using * the bitmap in pf->lasthit and is sized according to the matrix argument */ ComputeMatchingVersion(pf, matrix) register struct psfont *pf; fract matrix[2][2]; { register struct cachedfont *ret, *fam; register sz; extern bitmap_buildchar(); int genbitmaps = 1; if (pf->family->m.buildchar != bitmap_buildchar) { sz = sizeof(struct cachedfont) + sizeof(struct wglyph) * 255; ret = (struct cachedfont *) snoopalloc("fontcache.c", sz); bzero(ret, sz); bcopy(matrix, ret->font.matrix, sizeof ret->font.matrix); ret->font.printermatched = 1; ret->font.type = LRbitmapFont; ret->font.encoding = ASCIIencoding; ret->font.u.ops = font_ops[(int) ret->font.encoding]; ret->font.nglyphs = 256; ret->valid = 1; } else { assert(pf->lasthit); if (!pf->lasthit->valid) ValidateFont(pf); assert(pf->lasthit->valid); fam = pf->family->printermatched; if (!fam->valid) { struct psfont temp; temp = *pf; temp.lasthit = fam; ValidateFont(&temp); fam = temp.lasthit; } sz = sizeof(struct cachedfont) + sizeof(struct wglyph) * (pf->lasthit->font.nglyphs - 1); ret = (struct cachedfont *) snoopalloc("fontcache.c", sz); bcopy(pf->lasthit, ret, sz); bcopy(matrix, ret->font.matrix, sizeof ret->font.matrix); ret->font.printermatched = 1; if (matrix[1][0] == 0 && matrix[0][1] == 0 && matrix[0][0] > 0 && matrix[1][1] > 0 /*- && ((unsigned) (matrix[0][0] - pf->lasthit->font.matrix[0][0] + fracti(2))) < fracti(4) && ((unsigned) (matrix[1][1] - pf->lasthit->font.matrix[1][1] + fracti(2))) < fracti(4) */ ) genbitmaps = 0; for (sz = ret->font.nglyphs; --sz >= 0;) { register fract x, y; register struct wglyph *g = &fam->font.glyphs[sz]; x = frmul(ret->font.matrix[0][0], g->width.x) + frmul(ret->font.matrix[1][0], -g->width.y); y = frmul(ret->font.matrix[0][1], -g->width.x) + frmul(ret->font.matrix[1][1], g->width.y); g = &ret->font.glyphs[sz]; g->width.x = x; g->width.y = y; if (genbitmaps) g->glyph = 0; } } ret->font.comment = (char *) pf->lasthit; pst_compute_font_properties(&ret->font); if (pf->lasthit && genbitmaps) { /* Guess new font bounding box */ struct spoint ur, ll; struct fpoint urf, llf; register fract frt; { register struct font *ft = &pf->lasthit->font; ur.x = ft->size.x - ft->origin.x; ur.y = ft->origin.y; ll.x = -ft->origin.x; ll.y = ft->origin.y - ft->size.y; } urf.x = matrix[0][0] * ur.x + matrix[1][0] * ur.y; urf.y = matrix[0][1] * ur.x + matrix[1][1] * ur.y; llf = urf; #define DO1(P1,P2,C,I) \ frt = matrix[0][I]*P1.x + matrix[1][I]*P2.y; \ if (frt > urf.C) urf.C = frt; \ if (frt < llf.C) llf.C = frt; #define DO(P1,P2) DO1(P1,P2,x,0); DO1(P1,P2,y,1); DO(ll, ll); DO(ll, ur); DO(ur, ll); frt = pf->lasthit->font.matrix[0][0]; ret->font.origin.x = ceilingfr(frdiv(-llf.x,frt)); ret->font.origin.y = ceilingfr(frdiv(urf.y,frt)); ret->font.size.x = ceilingfr(frdiv(urf.x - llf.x,frt)); ret->font.size.y = ceilingfr(frdiv(urf.y - llf.y,frt)); } pf->lasthit = ret; ret->refcnt = 0; ret->font.name = (char *) pf->family; { register struct cachedfont **ht; register hash; hash = HASHFONT(ret->font.matrix); ht = &pf->family->hash[((unsigned short) ((hash >> 16) ^ hash)) % FONTHASHSIZE]; ret->next = *ht; *ht = ret; ret->hash = hash; } if (synth_used >= NSYNTH) { register limit = NSYNTH; while (--limit >= 0) { if (--synth_scan < 0) synth_scan = NSYNTH - 1; fam = synthetic_fonts[synth_scan]; if (fam->refcnt == 0) { register struct cachedfont **ht; register hash; hash = HASHFONT(fam->font.matrix); ht = &((struct fontfamily *) fam->font.name)->hash [((unsigned short) ((hash >> 16) ^ hash)) % FONTHASHSIZE]; while (*ht && *ht != fam) ht = &(*ht)->next; if (*ht) *ht = fam->next; free(fam); synthetic_fonts[synth_scan] = ret; } } } else { synthetic_fonts[synth_used++] = ret; } if (pf->family->m.buildchar)/* give the buildchar proc a chance to fiddle * with the font */ (*pf->family->m.buildchar) (&ret->font, -1, pf->family->directory, 0, 0, 2); } bitmap_buildchar(font, charindex, dir, px, py, op) register struct font *font; char *dir; { register struct cachedfont *basefont; extern struct pixrectops mem_ops; struct pixrect pix; struct mpr_data mpr; if (op == 2) return; assert(font != 0); basefont = (struct cachedfont *) font->comment; assert(basefont && basefont->valid); mpr.md_offset.x = 0; mpr.md_offset.y = 0; mpr.md_primary = 0; mpr.md_flags = 0; pix.pr_ops = &mem_ops; pix.pr_depth = 1; pix.pr_data = (caddr_t) &mpr; pix.pr_canvas = 0; { extern struct pixrect *cs_scale_and_rotate(); struct glyph *new; register fract x, y; register struct wglyph *g; fract xscale, yscale; register struct pixrect *bashed; extern struct spoint rotated_upper_left; struct shape *outline; g = &font->glyphs[charindex]; new = basefont->font.glyphs[charindex].glyph; g->glyph = new; assert(new != 0); xscale = frdiv(fracti(new->size.x), basefont->font.matrix[0][0]); yscale = frdiv(fracti(new->size.y), basefont->font.matrix[1][1]); cs_set_temp_matrix(font->matrix, xscale, yscale); mpr.md_linebytes = ((new->size.x + 0xF) & ~0xF) >> 3; mpr.md_image = (short *) ((struct generic_glyph *) new)->bits; pix.pr_size.x = new->size.x; pix.pr_size.y = new->size.y; bashed = cs_scale_and_rotate(&pix, temp_context, &outline); if (outline) sh_decref(outline); if (bashed) { if (bashed != &pix) { x = bashed->pr_height * mpr_d(bashed)->md_linebytes; QALLOC(new, (sizeof(struct glyph) + x), (struct glyph *)); bcopy(mpr_d(bashed)->md_image, ((struct generic_glyph *) new)->bits, x); new->size.x = bashed->pr_width; new->size.y = bashed->pr_height; pr_destroy(bashed); xscale = frdiv(fracti(g->glyph->origin.x), basefont->font.matrix[0][0]); yscale = frdiv(fracti(g->glyph->origin.y), basefont->font.matrix[1][1]); new->origin.x = roundfr(frmul(font->matrix[0][0], xscale) + frmul(font->matrix[1][0], -yscale)) + rotated_upper_left.x; new->origin.y = roundfr(frmul(font->matrix[0][1], -xscale) + frmul(font->matrix[1][1], yscale)) + rotated_upper_left.y; g->glyph = new; if (new->size.x > 16) font->narrow = 0; if ((x = new->origin.x - font->origin.x) > 0) { font->origin.x = new->origin.x; font->size.x += x; } if ((y = new->origin.y - font->origin.y) > 0) { font->origin.y = new->origin.y; font->size.y += y; } if ((x = (new->size.x - new->origin.x) - (font->size.x - font->origin.x)) > 0) font->size.x += x; if ((y = (new->size.y - new->origin.y) - (font->size.y - font->origin.y)) > 0) font->size.y += y; } } } } cs_set_temp_matrix(matrix, xscale, yscale) fract matrix[2][2]; { if (temp_context == 0) temp_context = cs_newcontext(mem_create(1, 1, 1)); temp_context->transform.kind = tro_none; temp_context->transform.matrix[0][0] = frmul(matrix[0][0], xscale); temp_context->transform.matrix[0][1] = -frmul(matrix[0][1], xscale); temp_context->transform.matrix[1][0] = frmul(matrix[1][0], yscale); temp_context->transform.matrix[1][1] = -frmul(matrix[1][1], yscale); temp_context->transform.matrix[2][0] = 0; temp_context->transform.matrix[2][1] = 0; cs_setmatrix(temp_context, 0); } cs_get_psf_bbox(font, gc, bb, user_relative) register struct psfont *font; register struct graphics_context *gc; register struct fcorner_bbox *bb; { register struct psfont *lpf; register struct font *pf; struct fcorner_bbox dbb; struct fpoint temp; lpf = cs_currentfont(gc); psf_incref(lpf); cs_setfont(gc, font); pf = cs_concretefont(gc); cs_setfont(gc, lpf); psf_decref(lpf); if (!user_relative) { cs_set_temp_matrix(pf->matrix, fracti(1), fracti(1)); gc = temp_context; } else { temp.x = gc->transform.matrix[2][0]; temp.y = gc->transform.matrix[2][1]; gc->transform.matrix[2][0] = 0; gc->transform.matrix[2][1] = 0; } dbb.ll.x = fracti(-pf->origin.x); dbb.ll.y = fracti(pf->size.y - pf->origin.y); dbb.ur.x = fracti(pf->size.x - pf->origin.x); dbb.ur.y = fracti(-pf->origin.y); /* Invert y coords */ cs_bbitransform(gc, &dbb, bb); if (user_relative) { gc->transform.matrix[2][0] = temp.x; gc->transform.matrix[2][1] = temp.y; } }