#ifndef lint static char sccsid[] = "@(#)textrend.c 9.3 88/01/19 Copyright 1985 Sun Micro"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ /*- Routines having to do with text rendering textrend.c, Thu Jan 2 17:24:09 1986 James Gosling, Sun Microsystems */ #ifdef REF #include #include #endif #include "shape.h" #include "font.h" #include "fontcache.h" #include "cursor.h" #define yes(a) a #define no(a) #define slowmap(a,b) (remap ? (a) : (b)) #define yesmap(a,b) (a) #define nomap(a,b) (b) int rendering_info_length, rendering_info_size; struct rendering_info *rendering_info; /* * rendering_info_left|top|width|height are set to the rough bounding box of * the text encountered during the call the get rending info. These values are * undefined if !cv_cursor.up. (MOVE to font.h) */ short rendering_info_left, rendering_info_top, rendering_info_width, rendering_info_height; #define modloop(modall, modone, figurebbox, doremap) \ while (--size >= 0) { \ register struct wglyph *wg; \ if ((temp = doremap(remap[*str++], *str++)) >= maxchar) \ continue; \ wg = &f->glyphs[temp]; \ p->pos.x = xs; \ p->pos.y = ys; \ xs += wg->width.x; \ ys += wg->width.y; \ if (((struct glyph *) wg = wg->glyph) == 0) { \ register (*bc)(); \ bc = ((struct fontfamily *) f->name)->m.buildchar; \ if (bc == 0) \ continue; \ wg = &f->glyphs[temp]; \ xs -= wg->width.x; \ ys -= wg->width.y; \ (*bc)(f, temp, ((struct fontfamily *) f->name)->directory, \ p->pos.x, p->pos.y, 0); \ xs += wg->width.x; \ ys += wg->width.y; \ if (((struct glyph *) wg = wg->glyph) == 0) \ continue; \ } \ p->g = (struct glyph *) wg; \ p->bits = ((struct generic_glyph *) wg)->bits; \ modall((xs += mods->alldelta.x, \ ys += mods->alldelta.y)); \ modone(temp == mods->c ? (xs += mods->cdelta.x, \ ys += mods->cdelta.y) : 0); \ figurebbox( \ if (xs < left) \ left = xs; \ if (ys < top) \ top = ys; \ if (xs > right) \ right = xs; \ if (ys > bottom) \ bottom = ys;) \ p++; rendering_info_length++; \ } struct rendering_info * prtxt_get_rendering_info(f, str, size, xs, ys, mods, remap) register struct font *f; unsigned char *str; register size; register fract xs, ys; register struct text_modifiers *mods; unsigned short *remap; { register struct rendering_info *p; register temp; register maxchar = f->nglyphs; fract left, right, top, bottom; rendering_info_length = 0; /* * We add .5 to xs and ys here so that subsequent conversions from fract * to integer can use floor instead of round */ xs += fraction(1, 2); ys += fraction(1, 2); /* Count string size if not supplied */ if (size < 0) { register unsigned char *strp = str; while (*strp++); size = strp - str - 1; } if (size >= rendering_info_size) { if (rendering_info) free(rendering_info); rendering_info = (struct rendering_info *) snoopalloc("textrend.c", (rendering_info_size = size + 50) * sizeof(struct rendering_info)); } p = rendering_info; /* Start cursor clipping computation if cursor visible on screen */ if (cv_cursor.up) { /* Remember starting position */ left = xs; top = ys; /* See if won't be able to compute bbox from ending xs, xy */ if (!(f->left_to_right || f->monotonic)) { /* The following modloop adjusts right and bottom */ right = xs; bottom = ys; /* Bailout on font that is not well behaved */ modloop(yes, yes, yes, slowmap); goto Finish; } } /* Use modloop macro to gather rendering info */ if (remap) { modloop(yes, yes, no, yesmap); } else { if (mods == 0) goto AllZero; if (mods->c < 0) if (mods->alldelta.x == 0 && mods->alldelta.y == 0) { AllZero: modloop(no, no, no, nomap); } else { modloop(yes, no, no, nomap); } else if (mods->alldelta.x == 0 && mods->alldelta.y == 0) { modloop(no, yes, no, nomap); } else { modloop(yes, yes, no, nomap); } } /* * Finish cursor clipping computation if cursor visible on screen. xs & ys * are one char past the end of str, but its close enough for cursor * bounding box computation. */ if (cv_cursor.up) { right = xs; bottom = ys; if (f->monotonic) { fract tmp_fract; /* Sort extents */ if (left > right) { tmp_fract = left; left = right; right = tmp_fract; } if (top > bottom) { tmp_fract = top; top = bottom; bottom = tmp_fract; } } Finish: /* * Adjust extent left & top to account for offset added above. Since * we are being sloppy, we don't bother for right & bottom. */ left -= fraction(1, 2); top -= fraction(1, 2); /* Generate rough bounding box */ rendering_info_left = cfloorfr(left) - f->origin.x; rendering_info_top = cfloorfr(top) - f->origin.y; rendering_info_width = cfloorfr(right) + f->size.x - f->origin.x - rendering_info_left + 1; rendering_info_height = cfloorfr(bottom) + f->size.y - f->origin.y - rendering_info_top + 1; } p->g = 0; p->pos.x = xs - fraction(1, 2); p->pos.y = ys - fraction(1, 2); /* rendering_info_left|top|width|height undefined if !cv_cursor.up */ } prtxt_get_stringwidth(f, str, size, remap) struct font *f; unsigned char *str; register size; register unsigned short *remap; { register struct rendering_info *p; register temp; register maxchar = f->nglyphs; register fract x, y; if (size < 0) { register unsigned char *strp = str; while (*strp++); size = strp - str - 1; } x = 0; y = 0; while (--size >= 0) { register struct wglyph *wg; temp = *str++; if (remap) temp = remap[temp]; if (temp > maxchar) continue; wg = &f->glyphs[temp]; if (wg->glyph == 0 && wg->width.x == 0 && wg->width.y == 0) { register (*bc)(); bc = ((struct fontfamily *) f->name)->m.buildchar; if (bc == 0) continue; (*bc)(f, temp, ((struct fontfamily *) f->name)->directory, 0, 0, 1); } x += wg->width.x; y += wg->width.y; } shape_point.x = x; shape_point.y = y; } struct rendering_info * prtxt_get_rendering_info_JISC6226(f, str, size, xs, ys, mods) struct font *f; unsigned char *str; register size; register fract xs, ys; register struct text_modifiers *mods; { register struct rendering_info *p; register temp; register maxchar = f->nglyphs; static struct text_modifiers nullmods; fract left, right, top, bottom; if (mods == 0) mods = &nullmods; rendering_info_length = 0; /* Count string size if not supplied */ if (size < 0) { register unsigned char *strp = str; while (*strp++); size = strp - str - 1; } if (size >= rendering_info_size) { if (rendering_info) free(rendering_info); rendering_info = (struct rendering_info *) snoopalloc("textrend.c", (rendering_info_size = size + 50) * sizeof(struct rendering_info)); } /* Initialize extent trackers */ left = right = xs; top = bottom = ys; p = rendering_info; while (--size >= 0) { register struct glyph *g; register struct wglyph *wg; if ((temp = *str++) & 0200) { if (--size < 0) continue; temp = (temp - 0241) * 96 + (*str++ - 0241) + 128; } if (temp < 0 || temp > maxchar) continue; if ((g = (wg = &f->glyphs[temp])->glyph) == 0) continue; p->pos.x = xs; p->pos.y = ys; p->g = g; p->bits = ((struct generic_glyph *) g)->bits; xs += wg->width.x; ys += wg->width.y; xs += mods->alldelta.x; ys += mods->alldelta.y; if (temp == mods->c) { xs += mods->cdelta.x; ys += mods->cdelta.y; } /* Detect extent */ if (cv_cursor.up) { if (xs < left) left = xs; if (ys < top) top = ys; if (xs > right) right = xs; if (ys > bottom) bottom = ys; } p++; rendering_info_length++; } /* * Finish cursor clipping computation if cursor visible on screen. xs & ys * are one char past the end of str, but its close enough for cursor * bounding box computation. */ if (cv_cursor.up) { /* * Adjust extent left & top to account for offset added above. Since * we are being sloppy, we don't bother for right & bottom. */ left -= fraction(1, 2); top -= fraction(1, 2); /* Generate rough bounding box */ rendering_info_left = cfloorfr(left) - f->origin.x; rendering_info_top = cfloorfr(top) - f->origin.y; rendering_info_width = cfloorfr(right) + f->size.x - f->origin.x - rendering_info_left + 1; rendering_info_height = cfloorfr(bottom) + f->size.y - f->origin.y - rendering_info_top + 1; } p->g = 0; p->pos.x = xs; p->pos.y = ys; /* rendering_info_left|top|width|height undefined if !cv_cursor.up */ } prtxt_get_stringwidth_JISC6226(f, str, size) struct font *f; unsigned char *str; register size; { register struct rendering_info *p; register temp; register maxchar = f->nglyphs; if (size < 0) { register unsigned char *strp = str; while (*strp++); size = strp - str - 1; } shape_point.x = 0; shape_point.y = 0; while (--size >= 0) { register struct wglyph *wg; if ((temp = *str++) & 0200) { if (--size < 0) break; temp = (temp - 0241) * 96 + (*str++ - 0241) + 128; } if (temp < 0 || temp > maxchar) continue; wg = &f->glyphs[temp]; shape_point.x += wg->width.x; shape_point.y += wg->width.y; } }