#ifndef lint static char sccsid[] = "@(#)fontdict.c 9.2 88/01/19 Copyright 1987 Sun Micro"; #endif /* * Copyright (c) 1987 by Sun Microsystems, Inc. */ /*- Font dictionary operations fontdict.c, Fri Apr 11 10:48:36 1986 James Gosling, Sun Microsystems */ #ifdef REF #include #include #endif #include "PostScript.h" #include "font.h" #define ix_FontBBox 0 #define ix_FontMatrix 1 #define ix_FontName 2 #define ix_IsFixedPitch 3 #define ix_WidthArray 4 #define ix_BuildChar 5 static struct body *FontDirectory; /* The PostScript repository for all * fonts */ static struct body *AdobeSequence; /* Dictionary mapping Adobe names to * Adobe indexes */ static fontidtransform(font, ipoint, opoint) register struct font *font; struct fpoint ipoint; register struct fpoint *opoint; { register fract num, denom; denom = frmul(font->matrix[1][0], font->matrix[0][1]) - frmul(font->matrix[1][1], font->matrix[0][0]); num = frmul(font->matrix[1][0], ipoint.y) - frmul(font->matrix[1][1], ipoint.x); if (denom == 0) { opoint->x = 0; opoint->y = 0; } else { opoint->x = frdiv(num, denom); if (font->matrix[1][1]) opoint->y = frdiv(ipoint.y - frmul(font->matrix[0][1], opoint->x), font->matrix[1][1]); else if (font->matrix[1][0]) opoint->y = frdiv(ipoint.x - frmul(font->matrix[0][0], opoint->x), font->matrix[1][0]); else opoint->y = 0; } } static fontaccess(obj, set, value) register struct body *obj; int set; register struct object value; { register struct execution_environment *ee = current_process; register struct font *pf; register struct object *bbox; assert(obj != 0); if (obj->type != font_id_type) { ee->error_code = unregistered_error_code; return; } switch (set) { case GET_MAGIC(ix_FontBBox): { struct fcorner_bbox bb; cs_get_psf_bbox(obj->body.font, &ee->gontext, &bb, 0); *ee->optop = make_array(4); bbox = body_of(ee->optop)->body.array.objects; set_fixed_object(bbox, bb.ll.x); set_fixed_object(bbox + 1, bb.ll.y); set_fixed_object(bbox + 2, bb.ur.x); set_fixed_object(bbox + 3, bb.ur.y); ee->optop++; } break; case GET_MAGIC(ix_FontMatrix): { register struct psfont *lpf; lpf = obj->body.font; *ee->optop = make_array(6); bbox = body_of(ee->optop)->body.array.objects; ee->optop->value.substring.length = 6; set_fixed_object(bbox, lpf->matrix[0][0]); set_fixed_object(bbox + 1, lpf->matrix[0][1]); set_fixed_object(bbox + 2, lpf->matrix[1][0]); set_fixed_object(bbox + 3, lpf->matrix[1][1]); set_fixed_object(bbox + 4, 0); set_fixed_object(bbox + 5, 0); ee->optop++; } break; case GET_MAGIC(ix_FontName): { register char *name; name = obj->body.font->family->FamilyName; set_typed_bodied_object(ee->optop, keyword_type, get_name(name, strlen(name))); ee->optop++; } break; case GET_MAGIC(ix_IsFixedPitch): { register struct psfont *lpf; lpf = cs_currentfont(&ee->gontext); psf_incref(lpf); cs_setfont(&ee->gontext, obj->body.font); set_typed_object(ee->optop, boolean_type); ee->optop->value.fixed = fracti(cs_concretefont(&ee->gontext)->fixed_width); ee->optop++; cs_setfont(&ee->gontext, lpf); psf_decref(lpf); } break; case GET_MAGIC(ix_WidthArray): { register struct font *font; register struct object *element; register i; register struct psfont *lpf; register struct wglyph *wg; lpf = cs_currentfont(&ee->gontext); psf_incref(lpf); cs_setfont(&ee->gontext, obj->body.font); set_typed_object(ee->optop, boolean_type); font = cs_concretefont(&ee->gontext); *ee->optop = make_array(font->nglyphs * 2); ee->optop->value.substring.length = font->nglyphs * 2; element = body_of(ee->optop)->body.array.objects; for (i = 0; i < font->nglyphs; i++) { set_typed_object(element, fixed_type); set_typed_object(element + 1, fixed_type); if (lpf->remap) wg = &font->glyphs[lpf->remap[i]]; else wg = &font->glyphs[i]; cs_fridtransform(&ee->gontext, wg->width.x, wg->width.y, &element[0].value.fixed, &element[1].value.fixed); element += 2; } ee->optop++; cs_setfont(&ee->gontext, lpf); psf_decref(lpf); } break; case GET_MAGIC(ix_BuildChar): set_typed_bodied_object(ee->optop, font_id_type, obj); incref(obj); ee->optop++; break; #ifdef notdef case SET_MAGIC(ix_FontBBox): case SET_MAGIC(ix_FontMatrix): case SET_MAGIC(ix_FontName): case SET_MAGIC(ix_IsFixedPitch): case SET_MAGIC(ix_WidthArray): #endif default: ee->error_code = invalidaccess_error_code; break; } } static findfilefont(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop - 1; register struct psfont *f; extern struct psfont *cs_findfilefont(); register struct body *b; if (optop->type != string_type) { ee->error_code = typecheck_error_code; return; } f = cs_findfilefont(body_of(optop)->body.string.chars + optop->value.substring.start, optop->value.substring.length); if (f == 0) { ee->error_code = invalidfont_error_code; return; } object_decref(optop); b = new_body(font); set_typed_bodied_object(optop, font_id_type, b); b->type = font_id_type; b->body.font = f; { register char *name; struct object nameob; name = f->family->FamilyName; set_typed_bodied_object(&nameob, keyword_type, get_name(name, strlen(name))); define_object_in_dictionary(nameob, optop[0], FontDirectory, 0); incref(b); } } static fontprop(ee) register struct execution_environment *ee; { register struct object *o = ee->optop - 1; register struct psfont *font; register fract val; struct fcorner_bbox bb; if (o->type != font_id_type) { ee->error_code = typecheck_error_code; return; } font = body_of(o)->body.font; cs_get_psf_bbox(font, &ee->gontext, &bb, 1); switch (ee->execee.value.def->index) { case 0: val = bb.ur.y - bb.ll.y; break; case 1: val = font->matrix[1][1] >= 0 ? bb.ur.y : -bb.ll.y; break; case 2: val = font->matrix[1][1] < 0 ? bb.ur.y : -bb.ll.y; break; } object_decref(o); set_fixed_object(o, val); } static findfont(ee) register struct execution_environment *ee; { register struct object *o; switch (ee->optop[-1].type) { default: ee->error_code = typecheck_error_code; return; case string_type: convert_string_to_name(ee->optop - 1); case keyword_type: break; } o = find_object_in_dictionary(ee->optop[-1], FontDirectory); if (o == 0 || o->type != font_id_type) { ee->error_code = invalidfont_error_code; return; } ee->optop[-1] = *o; object_incref(o); } static struct object FontName; struct object BuildChar; static struct object FID; struct object FontMatrix; struct object FontBBox; struct object Encoding; static definefont(ee) register struct execution_environment *ee; { extern buildchar(); extern struct psfont *cs_definefont(); register struct psfont *font; register struct object *optop = ee->optop; register struct body *dict, *b; register struct object *obj; struct object new; if (optop[-1].type != dictionary_type) { typecheck: ee->error_code = typecheck_error_code; return; } dict = body_of(optop - 1); if ((obj = find_object_in_dictionary(BuildChar, dict)) == 0) { undefined: ee->error_code = undefined_error_code; return; } if (obj->type == font_id_type) { /* Redefining based on a built-in * font! */ #define CSET_LEN 256 unsigned short newenc[CSET_LEN]; int enclen, changes; register inx; register struct object *enc; enc = find_object_in_dictionary(Encoding, dict); changes = 0; if (enc) { if (enc->type != array_type) goto typecheck; enclen = enc->value.substring.length; enc = body_of(enc)->body.array.objects + enc->value.substring.start; if (enclen > CSET_LEN) enclen = CSET_LEN; for (inx = enclen; --inx >= 0;) { register struct object *newval; newval = find_object_in_dictionary(enc[inx], AdobeSequence); if (newval && newval->type == fixed_type) { newenc[inx] = cfloorfr(newval->value.fixed); if (newenc[inx] != inx) changes++; } else newenc[inx] = inx; } } decref(dict); if (changes && enclen) { /* * This font has a new encoding. We look up in the cache of * encodings that we've already seen so that we can avoid * generating a stack of new ones. */ #define MAP_CACHE_LEN 10 struct map_cache { int hash; unsigned short remap[CSET_LEN]; }; static struct map_cache *map_cache[MAP_CACHE_LEN]; register hash; for (inx = enclen; inx < CSET_LEN; inx++) newenc[inx] = inx; /* Fill the unfilled slots */ { /* Remapping a remapped font: apply the * transitive closure */ register unsigned short *othermap; if (othermap = body_of(obj)->body.font->remap) for (inx = 0; inx < CSET_LEN; inx++) newenc[inx] = othermap[newenc[inx] & 0xFF]; } b = new_body(font); /* Build a font object */ b->type = font_id_type; b->body.font = cs_frscalefont(body_of(obj)->body.font, fracti(1)); hash = 0; /* Compute a hash value for the array */ for (inx = CSET_LEN; --inx >= 0;) hash = (hash << 3) - hash + newenc[inx]; for (inx = 0; inx < MAP_CACHE_LEN; inx++) /* Find a matching array */ if (map_cache[inx] && map_cache[inx]->hash == hash && bcmp(newenc, map_cache[inx]->remap, sizeof newenc) == 0) break; if (inx < MAP_CACHE_LEN) /* Cache hit */ b->body.font->remap = map_cache[inx]->remap; else { /* Cache miss */ static map_slot; QALLOC(map_cache[map_slot], sizeof *map_cache[map_slot], (struct map_cache *)); bcopy(newenc, map_cache[map_slot]->remap, sizeof newenc); map_cache[map_slot]->hash = hash; b->body.font->remap = map_cache[map_slot]->remap; map_slot++; if (map_slot >= CSET_LEN) map_slot = 0; } set_typed_bodied_object(&new, font_id_type, b); incref(b); define_object_in_dictionary(optop[-2], new, FontDirectory, 0); optop[-2] = new; } else { /* No encoding change, just return the old * font */ incref(body_of(obj)); incref(body_of(obj)); define_object_in_dictionary(optop[-2], *obj, FontDirectory, 0); optop[-2] = *obj; } ee->optop--; return; } obj = find_object_in_dictionary(FontMatrix, dict); if (obj == 0) goto undefined; if (obj->type != array_type || obj->value.substring.length != 6) goto typecheck; body_of(obj)->readonly = 1; dict->readonly = 1; obj = body_of(obj)->body.array.objects + obj->value.substring.start; { register i; for (i = 6; --i >= 0;) if (obj[i].type != fixed_type) goto typecheck; } { register struct object *BBox = find_object_in_dictionary(FontBBox, dict); register i; if (BBox == 0) goto undefined; if (BBox->type != array_type || BBox->value.substring.length != 4) goto typecheck; BBox = body_of(BBox)->body.array.objects + BBox->value.substring.start; for (i = 4; --i >= 0;) if ((BBox++)->type != fixed_type) goto typecheck; } { register char *key; register keylen; switch (optop[2].type) { case string_type: convert_string_to_name(optop - 2); case keyword_type: key = body_of(optop - 2)->body.keyword.name; keylen = body_of(optop - 2)->body.keyword.namelen; break; default: key = "?"; keylen = 1; break; } font = cs_definefont(key, keylen, buildchar, dict); } font->matrix[0][0] = obj[0].value.fixed; font->matrix[0][1] = obj[1].value.fixed; font->matrix[1][0] = obj[3].value.fixed; font->matrix[1][1] = obj[4].value.fixed; object_decref(optop - 2); b = new_body(font); set_typed_bodied_object(&new, font_id_type, b); b->type = font_id_type; b->body.font = font; define_object_in_dictionary(FontName, optop[-2], dict, 0); define_object_in_dictionary(optop[-2], new, FontDirectory, 0); define_object_in_dictionary(FID, new, dict, 0); incref(b); optop[-2] = new; ee->optop--; } initialize_fontdict() { register struct body *fd = new_dict(20); register struct body *fid = new_dict(20); struct object o; dict_table[(int) font_id_type] = fd; set_typed_bodied_object(&BuildChar, keyword_type, get_name("BuildChar", -1)); set_typed_bodied_object(&Encoding, keyword_type, get_name("Encoding", -1)); set_typed_bodied_object(&FID, keyword_type, get_name("FID", -1)); set_typed_bodied_object(&FontBBox, keyword_type, get_name("FontBBox", -1)); set_typed_bodied_object(&FontMatrix, keyword_type, get_name("FontMatrix", -1)); set_typed_bodied_object(&FontName, keyword_type, get_name("FontName", -1)); FontDirectory = new_dict(100); fd->refcnt = maximum_refcnt; fid->refcnt = maximum_refcnt; FontDirectory->refcnt = maximum_refcnt; set_typed_bodied_object(&o, dictionary_type, fd); o.value.substring.length = fd->body.dict.size; define_object(system_dictionary, "magic:fontdict", o); set_typed_bodied_object(&o, dictionary_type, fid); o.value.substring.length = fid->body.dict.size; define_object(fd, "FontInfo", o); set_typed_bodied_object(&o, dictionary_type, FontDirectory); AdobeSequence = new_dict(300); o.value.substring.length = FontDirectory->body.dict.size; define_object(system_dictionary, "FontDirectory", o); AdobeSequence->refcnt = maximum_refcnt; set_typed_bodied_object(&o, dictionary_type, AdobeSequence); o.value.substring.length = AdobeSequence->body.dict.size; define_object(system_dictionary, "magic:AdobeSequence", o); define_magic("FontBBox", fd, fontaccess, ix_FontBBox, 0, 1); define_magic("FontMatrix", fd, fontaccess, ix_FontMatrix, 0, 1); define_magic("FontName", fd, fontaccess, ix_FontName, 0, 1); define_magic("IsFixedPitch", fd, fontaccess, ix_IsFixedPitch, 0, 1); define_magic("WidthArray", fd, fontaccess, ix_WidthArray, 0, 1); define_magic("BuildChar", fd, fontaccess, ix_BuildChar, 0, 1); define_operator("findfilefont", findfilefont, 0, 1, 1); define_operator("findfont", findfont, 0, 1, 1); define_operator("definefont", definefont, 0, 2, 1); define_operator("fontheight", fontprop, 0, 1, 1); define_operator("fontascent", fontprop, 1, 1, 1); define_operator("fontdescent", fontprop, 2, 1, 1); }