#ifndef lint static char sccsid[] = "@(#)definefont.c 9.7 88/02/10 Copyright 1985 Sun Micro"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ /*- User-defined font machinery This should be the only code in NeWS that "knows" the format of fonts and memory pixrects. It also (sadly) knows the format of paths. definefont.c, Mon May 25 16:04:09 1987 James Gosling, Sun Microsystems */ #ifdef REF #include #include #endif #include "PostScript.h" #include "pixrect/memvar.h" #include "font.h" static struct fpoint charwidth; static struct font *targetfont; static targetglyph; static struct glyph *gl; static struct pixrect pr_glyph; static struct mpr_data pr_dataref; static cachelimit; static struct object PaintType; static compute_size_only; static setcachedevice(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; register struct graphics_context *gc = &ee->gontext; struct fpoint ll, ur, ul, lr; struct spoint size; register bytes; int linebytes; if (targetfont == 0) { ee->error_code = invalidaccess_error_code; return; } if (optop[-1].type != fixed_type || optop[-2].type != fixed_type || optop[-3].type != fixed_type || optop[-4].type != fixed_type || optop[-5].type != fixed_type || optop[-6].type != fixed_type) { ee->error_code = typecheck_error_code; return; } cs_frdtransform(gc, optop[-6].value.fixed, optop[-5].value.fixed, &charwidth.x, &charwidth.y); cs_frdtransform(gc, optop[-4].value.fixed, optop[-3].value.fixed, &ll.x, &ll.y); cs_frdtransform(gc, optop[-2].value.fixed, optop[-1].value.fixed, &ur.x, &ur.y); if (ee->gontext.transform.kind == tro_none) { cs_frdtransform(gc, optop[-4].value.fixed, optop[-1].value.fixed, &ul.x, &ul.y); cs_frdtransform(gc, optop[-2].value.fixed, optop[-3].value.fixed, &lr.x, &lr.y); if (ll.x > ur.x) ur.x = ll.x; if (lr.x > ur.x) ur.x = lr.x; if (ul.x > ur.x) ur.x = ul.x; if (ll.y < ur.y) ur.y = ll.y; if (lr.y < ur.y) ur.y = lr.y; if (ul.y < ur.y) ur.y = ul.y; if (ur.x < ll.x) ll.x = ur.x; if (lr.x < ll.x) ll.x = lr.x; if (ul.x < ll.x) ll.x = ul.x; if (ur.y > ll.y) ll.y = ur.y; if (lr.y > ll.y) ll.y = lr.y; if (ul.y > ll.y) ll.y = ul.y; } ll.y = -ll.y - fraction(1, 2); ur.y = -ur.y; ur.x += fraction(1, 2); size.x = ceilingfr(ur.x) - cfloorfr(ll.x); size.y = ceilingfr(ur.y) - cfloorfr(ll.y); linebytes = ((size.x + 15) >> 3) & ~1; bytes = linebytes * size.y; if (bytes <= cachelimit && bytes > 0) { FMATRIX matrix; struct fpoint delta; register gsize = bytes + sizeof(struct glyph); int sv_bottompos, sv_startpos; gl = (struct glyph *) qalloc(gsize); bzero(gl, gsize); gl->length = gsize; gl->size = size; gl->origin.y = size.y + cfloorfr(ll.y); gl->origin.x = -cfloorfr(ll.x); { register diff; if ((diff = gl->origin.y - targetfont->origin.y) > 0) { targetfont->origin.y += diff; targetfont->size.y += diff; } if ((diff = (gl->size.y - gl->origin.y) - (targetfont->size.y - targetfont->origin.y)) > 0) targetfont->size.y += diff; if ((diff = gl->origin.x - targetfont->origin.x) > 0) { targetfont->origin.x += diff; targetfont->size.x += diff; } if ((diff = (gl->size.x - gl->origin.x) - (targetfont->size.x - targetfont->origin.x)) > 0) targetfont->size.x += diff; } if (size.x > 16) targetfont->narrow = 0; delta.x = gc->transform.matrix[2][0] - fracti(gl->origin.x); delta.y = gc->transform.matrix[2][1] - fracti(gl->origin.y); cs_currentmatrix(gc, matrix); sv_bottompos = gc->path.bottompos; sv_startpos = gc->path.startpos; gc->path.bottompos = gc->path.used; pr_glyph.pr_size.x = size.x; pr_glyph.pr_size.y = size.y; pr_dataref.md_linebytes = linebytes; pr_dataref.md_image = (short *) (((char *) gl) + sizeof(struct glyph)); cs_setcanvas(gc, &pr_glyph); cs_frsetgray(gc, 0); matrix[2][0] = -ll.x; matrix[2][1] = -ll.y; cs_setmatrix(gc, matrix); gc->path.bottompos = sv_bottompos; gc->path.startpos = sv_startpos; { /* The PostScript definition isn't clear on * what happens to an existing path when * setcachedevice is executed, for now I'm * assuming that it carries over */ register i; register struct path_element *pe; pe = &gc->path.element[gc->path.startpos]; for (i = gc->path.startpos; i < gc->path.used; i++, pe++) { pe->pos.x -= delta.x; pe->pos.y -= delta.y; } } } else if (compute_size_only) cs_setcanvas(gc, empty_pixrect); ee->optop -= 6; } static setcharwidth(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; if (targetfont == 0) { ee->error_code = invalidaccess_error_code; return; } if (optop[-1].type != fixed_type || optop[-2].type != fixed_type) { ee->error_code = typecheck_error_code; return; } cs_frdtransform(&ee->gontext, optop[-2].value.fixed, optop[-1].value.fixed, &charwidth.x, &charwidth.y); ee->optop -= 2; if (compute_size_only) cs_setcanvas(&ee->gontext, empty_pixrect); } buildchar(f, glyph, dir, x, y, op) struct font *f; struct body *dir; { register struct execution_environment *ee = current_process; struct execution_stack *oldes = ee->execution_stack; extern struct object FontMatrix, BuildChar, FontBBox; register struct object *ob; if (op == 2 && dir) { /* f has just been build, we're being given a * chance to alter it. All we need do is set * the font bbox */ struct fpoint ll, ur; ob = find_object_in_dictionary(FontBBox, dir); assert(ob && ob->type == array_type); ob = body_of(ob)->body.array.objects + ob->value.substring.start; ll.x = frmul(ob[0].value.fixed, f->matrix[0][0]) + frmul(ob[1].value.fixed, f->matrix[1][0]); ll.y = frmul(ob[0].value.fixed, f->matrix[0][1]) + frmul(ob[1].value.fixed, f->matrix[1][1]); ur.x = frmul(ob[2].value.fixed, f->matrix[0][0]) + frmul(ob[3].value.fixed, f->matrix[1][0]); ur.y = frmul(ob[2].value.fixed, f->matrix[0][1]) + frmul(ob[3].value.fixed, f->matrix[1][1]); f->size.x = ceilingfr(ur.x) - cfloorfr(ll.x); f->size.y = ceilingfr(ur.y) - cfloorfr(ll.y); /* BUG: doesn't handle rotation or zero matricies properly */ f->origin.x = -cfloorfr(ll.x); f->origin.y = ceilingfr(ur.y); return; } if (ee->error_code != no_error_code) return; if (ee->optop + 2 >= ee->overflow || ee->pos >= ee->limit) { ee->error_code = stackoverflow_error_code; return; } /*- ob = find_object_in_dictionary(FontMatrix, dir); assert(ob); ob = body_of(ob)->body.array.objects + ob->value.substring.start; ob[0].value.fixed = f->matrix[0][0]; ob[1].value.fixed = f->matrix[0][1]; ob[3].value.fixed = f->matrix[1][0]; ob[4].value.fixed = f->matrix[1][1]; */ cs_gsave(&ee->gontext); cs_newpath(&ee->gontext); ee->gontext.transform.matrix[0][0] = f->matrix[0][0]; ee->gontext.transform.matrix[0][1] = -f->matrix[0][1]; ee->gontext.transform.matrix[1][0] = f->matrix[1][0]; ee->gontext.transform.matrix[1][1] = -f->matrix[1][1]; ee->gontext.transform.matrix[2][0] = x - fraction(1, 2); ee->gontext.transform.matrix[2][1] = y - fraction(1, 2); cs_setmatrix(&ee->gontext, 0); ob = find_object_in_dictionary(BuildChar, dir); assert(ob != 0); /*- assert(ee->execee.type == operator_type || ee->execee.type == called_operator_type); */ ee->pos++; ee->pos->type = undetermined_execution; ee->pos->executed = *ob; object_incref(ob); set_typed_bodied_object(ee->optop, dictionary_type, dir); incref(dir); set_fixed_object(ee->optop + 1, fracti(glyph)); ee->optop += 2; ee->restart_state = 0; ee->execution_stack = ee->pos; targetfont = f; targetglyph = glyph; gl = 0; compute_size_only = op == 1; PostScript(ee); if ((ob = find_object_in_dictionary(PaintType, dir)) != 0 && ob->type == fixed_type) switch (cfloorfr(ob->value.fixed)) { case 0: cs_fill(&ee->gontext); break; case 1: case 2: cs_stroke(&ee->gontext); break; } targetfont = 0; cs_grestore(&ee->gontext); { register struct wglyph *wg = &f->glyphs[glyph]; wg->width.x = charwidth.x; if ((wg->width.y = charwidth.y) != 0 || charwidth.x < 0) { f->left_to_right = 0; f->monotonic = 0; /* For safety */ } f->fixed_width = 0; /* Also for safety */ if (gl) wg->glyph = gl; } ee->execution_stack = oldes; } static setcachelimit(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; if (optop[-1].type != fixed_type) { ee->error_code = typecheck_error_code; return; } cachelimit = roundfr(optop[-1].value.fixed); ee->optop--; } initialize_definefont() { extern struct pixrectops mem_ops; cachelimit = 72 * 72 / 8; set_typed_bodied_object(&PaintType, keyword_type, get_name("PaintType", -1)); define_operator("setcachedevice", setcachedevice, 0, 6, 0); define_operator("setcharwidth", setcharwidth, 0, 2, 0); define_operator("setcachelimit", setcachelimit, 0, 1, 0); pr_glyph.pr_ops = &mem_ops; pr_glyph.pr_depth = 1; pr_glyph.pr_canvas = 0; pr_glyph.pr_data = (caddr_t) &pr_dataref; pr_dataref.md_offset.x = 0; pr_dataref.md_offset.y = 0; pr_dataref.md_flags = 0; pr_dataref.md_primary = 0; }