📄 ei_plain_text.c
字号:
#ifndef lint#ifdef sccsstatic char sccsid[] = "@(#)ei_plain_text.c 1.1 92/07/30";#endif#endif/* * Copyright (c) 1986 by Sun Microsystems, Inc. *//* * Entity interpreter for ascii characters interpreted as plain text. */#define USING_SETS#include <suntool/primal.h>#include <sys/time.h>#include <stdio.h>#include <ctype.h>#include <pixrect/pixrect.h>#include <pixrect/pr_util.h>#include <pixrect/memvar.h>#include <pixrect/pixfont.h>#include <sunwindow/rect.h>#undef max#include <sunwindow/rectlist.h>#include <sunwindow/pixwin.h>#include <suntool/tool.h>#include <suntool/entity_view.h>extern Es_index es_backup_buf();extern void pw_batch(); /* Used by pw_batch_on/off */#define NEWLINE '\n'#define SPACE ' '#define TAB '\t'typedef struct ei_plain_text_object { PIXFONT *font; int tab_width; /* tab width in 'm's */ unsigned state; struct pr_pos font_home; /* == fonthome(font) */ int font_flags; short tab_pixels; /* tab width in pixels */ short tab_delta_y; /* actually ' ' delta y */} ei_plain_text_object;typedef ei_plain_text_object *Eipt_handle;#define ABS_TO_REP(eih) (Eipt_handle)LINT_CAST(eih->data)/* * Note: font_home, font_flags, tab_pixels, and tab_delta_y are * cached information which must be updated when the font * or the tab_width change. */ /* state values */#define CONTROL_CHARS_USE_FONT 0x0000001 /* font_flags values */#define FF_POSITIVE_X_ADVANCE 0x0000001#define FF_UNIFORM_HEIGHT 0x0000002#define FF_UNIFORM_HOME 0x0000004#define FF_UNIFORM_X_ADVANCE 0x0000008#define FF_UNIFORM_X_PR_ADVANCE 0x0000010#define FF_ZERO_Y_ADVANCE 0x0000020#define FF_ALL 0x000003f#define FF_EASY_Y (FF_UNIFORM_HEIGHT|FF_UNIFORM_HOME| \ FF_ZERO_Y_ADVANCE)extern Ei_handle ei_plain_text_create();static Ei_handle ei_plain_text_destroy();static caddr_t ei_plain_text_get();static int ei_plain_text_line_height();static int ei_plain_text_lines_in_rect();static struct ei_process_result ei_plain_text_process();static int ei_plain_text_set();static struct ei_span_result ei_plain_text_span_of_group();static struct ei_process_result ei_plain_text_expand();struct ei_ops ei_plain_text_ops = { ei_plain_text_destroy, ei_plain_text_get, ei_plain_text_line_height, ei_plain_text_lines_in_rect, ei_plain_text_process, ei_plain_text_set, ei_plain_text_span_of_group, ei_plain_text_expand};/* Used in ei_plain_text_process. Init adv.y = 0 once and for all. */static struct pixchar dummy_for_tab;static intei_plain_text_set_tab_width(eih, tab_width) Ei_handle eih; register int tab_width;{ register Eipt_handle private = ABS_TO_REP(eih); private->tab_width = tab_width; private->tab_pixels = private->font->pf_char['m'].pc_adv.x * tab_width; if (private->tab_pixels == 0) private->tab_pixels = 1;}static intei_plain_text_set_font(eih, font) Ei_handle eih; register PIXFONT *font;{ extern struct pr_pos fonthome(); register Eipt_handle private = ABS_TO_REP(eih); struct pixchar *pc = &font->pf_char[SPACE]; register short i, height, home, adv_x; private->font = font; private->font_home = fonthome(font); ei_plain_text_set_tab_width(eih, private->tab_width); height = pc->pc_pr->pr_height; home = pc->pc_home.y; private->tab_delta_y = home + height; adv_x = pc->pc_adv.x; /* Assume that this is >= 0 */ private->font_flags = FF_ALL; for (i = 0; i < 256; i++) { pc = &font->pf_char[i]; if (adv_x != pc->pc_adv.x) { if (pc->pc_pr) { private->font_flags &= ~(FF_UNIFORM_X_ADVANCE|FF_UNIFORM_X_PR_ADVANCE); } else { private->font_flags &= ~FF_UNIFORM_X_ADVANCE; } if (adv_x < 0) { private->font_flags &= ~FF_POSITIVE_X_ADVANCE; } } if (pc->pc_adv.y != 0) { private->font_flags &= ~FF_ZERO_Y_ADVANCE; } if (pc->pc_pr) { /* Home is meaningless unless pixrect exists for char. */ if (home != pc->pc_home.y) { private->font_flags &= ~FF_UNIFORM_HOME; } if (height != pc->pc_pr->pr_height) { private->font_flags &= ~FF_UNIFORM_HEIGHT; } } }#ifdef DEBUG (void) fprintf(stderr, "Font_flags: %lx\n", private->font_flags);#endif}extern Ei_handleei_plain_text_create(){ extern char *calloc(); register Ei_handle eih = NEW(struct ei_object); Eipt_handle private; if (eih == 0) goto AllocFailed; private = NEW(ei_plain_text_object); if (private == 0) { free((char *)eih); goto AllocFailed; } eih->ops = &ei_plain_text_ops; eih->data = (caddr_t)private; private->tab_width = 8; return(eih);AllocFailed: return(NULL);}static Ei_handleei_plain_text_destroy(eih) Ei_handle eih;{ register Eipt_handle private = ABS_TO_REP(eih); free((char *)eih); free((char *)private); return NULL;}static intei_plain_text_line_height(eih) Ei_handle eih;{ register Eipt_handle private = ABS_TO_REP(eih); return(private->font->pf_defaultsize.y);}static intei_plain_text_lines_in_rect(eih, rect) Ei_handle eih; struct rect *rect;/* * Returns the number of complete lines that will fit in the rect. * Any partial line is ignored; call with one bit shorter rect to check * if partial exists. */{ register int line_height = ei_line_height(eih); int result = rect->r_height/line_height; return(result < 0 ? 0 : result);}static u_short gray17_data[16] = { /* really 16-2/3 */ 0x8208, 0x2082, 0x0410, 0x1041, 0x4104, 0x0820, 0x8208, 0x2082, 0x0410, 0x1041, 0x4104, 0x0820, 0x8208, 0x2082, 0x0410, 0x1041};mpr_static(gray17_pr, 12, 12, 1, gray17_data);/* The following macros (suggested by JAG) make sure the compiler keeps * all the involved quantities as short's. */#define SAdd(_a, _b) (short)((short)(_a) + (short)(_b))#define SSub(_a, _b) (short)((short)(_a) - (short)(_b))#define SRect_edge(_a, _b) \ (short)((short)((short)(_a) + (short)(_b)) - (short)1)#define MAX_PER_BATCH 200static struct ei_process_resultei_plain_text_process(eih, op, esbuf, x, y, rop, pw, rect, tab_origin) Ei_handle eih; int op; Es_buf_handle esbuf; int x, y, rop; struct pixwin *pw; register struct rect *rect; int tab_origin;/* * Arguments are: * eih handle of the entity interpreter whose ei_process op * mapped to this routine. * op see EI_OP_* in entity_interpreter.h. * esbuf chars to be painted/measured. * sizeof_buf number of characters in buffer. * buf the characters themselves. * esh handle of entity stream they came from. * first Es_index into esh. * last_plus_one Es_index into esh. * x position to start painting from. * y position of the largest ascender's top, NOT the baseline. * Probably always == rect.r_top. * rop raster op, usually either PIX_SRC or PIX_SRC|PIX_DST. * pw pixwin to paint into. * rect rectangle to paint into, indicates where to stop with * result.break_reason = EI_HIT_RIGHT, or whether to do * nothing due to result.break_reason = EI_HIT_BOTTOM. * r_left only needs to be different from x if we are * starting to paint later than the beginning of the line, * and op specifies EI_OP_CLEAR_FRONT. * tab_origin x position of zeroth tab stop on the line. * * WARNING! This code has been extensively hand tuned to make sure that * the compiler generates good code. Seemingly trivial changes can impact * the generated code. If you change this code, make sure you look at the * actual assembly code both before and after. */{ register Eipt_handle private = ABS_TO_REP(eih); register struct pixchar *pc; register struct pr_prpos *batch; register short c; register short temp; register Es_index esi; char *buf_rep = (char *)esbuf->buf; struct ei_process_result result; short last_batch_pos_x, last_batch_pos_y; register short bounds_right, rects_right; short bounds_bottom, rects_bottom; short in_white_space = 0, special_char = -1; register int check_vert_bounds = TRUE; struct pr_prpos prpos; struct pr_prpos batch_array[MAX_PER_BATCH+1]; temp = (short)x; last_batch_pos_x = temp; result.bounds.r_left = temp; bounds_right = temp; result.pos.x = SSub(temp, private->font_home.x); result.bounds.r_width = 0; temp = (short)y; last_batch_pos_y = temp; result.bounds.r_top = temp; /* BUG ALERT! The following is not completely correct, as it assumes * that the result.bounds.r_top is at the top of the current * line, not just the current "ink" for the batch. * Make sure that clear|invert|pattern in paint_batch affects * the entire height of the line. */ bounds_bottom = SSub(SAdd(temp, private->font->pf_defaultsize.y), 1); result.pos.y = SSub(temp, private->font_home.y); rects_right = SRect_edge(rect->r_left, rect->r_width); rects_bottom = SRect_edge(rect->r_top, rect->r_height); result.break_reason = EI_PR_BUF_EMPTIED; /* * Construct the batch items for the characters to be displayed. * During the batch construction, result.pos accumulates the advances * along the baseline, and is an absolute position. * After building the batch, it is offset by font_home, thereby being * the accumulation of the advances applied to the original x,y args. * last_batch_pos_x&y is absolute home position of the previous batch * item. * Remember that batch->pos is a relative offset from previous item. */ batch = batch_array; for (esi=esbuf->first; esi<esbuf->last_plus_one; esi++) { c = (unsigned char)(*buf_rep++);Rescan: if ((c == SPACE) || (c == TAB)) { if (in_white_space == 0) in_white_space = 1; if (c == TAB) { pc = &dummy_for_tab; /* dummy_for_tab.pc_adv.y = 0 implicitly due * to declaring dummy_for_tab as a static. */ pc->pc_pr = 0; /* Don't set pc->pc_home as it is never examined */ pc->pc_adv.x = (result.pos.x-tab_origin) % private->tab_pixels; pc->pc_adv.x = private->tab_pixels - pc->pc_adv.x; /* Must explicitly test right boundary hit */ temp = (short)pc->pc_adv.x - (short)1; temp += result.pos.x; if (temp > bounds_right) { if (temp > rects_right) { result.break_reason = EI_PR_HIT_RIGHT; break; } bounds_right = temp; } /* ... and bottom */ if (check_vert_bounds) { temp = (short)private->tab_delta_y; temp += result.pos.y; if (--temp > bounds_bottom) { if (temp > rects_bottom) { result.break_reason = EI_PR_HIT_BOTTOM; break; } bounds_bottom = ++temp; } if (private->font_flags & FF_EASY_Y) check_vert_bounds = FALSE; } goto Skip_pc_pr_tests; } } else if (c == NEWLINE) { in_white_space = 0; pc = &private->font->pf_char[SPACE]; goto Skip_pc_assignment; } else { in_white_space = 0; } pc = &private->font->pf_char[c];Skip_pc_assignment: if (pc->pc_pr && (!iscntrl(c) || in_white_space || c == NEWLINE || (private->state & CONTROL_CHARS_USE_FONT))) { batch->pr = pc->pc_pr; temp = (short)pc->pc_home.x; temp += result.pos.x; if (temp < result.bounds.r_left) { if (temp < rect->r_left) { result.break_reason = EI_PR_HIT_LEFT; break; } result.bounds.r_left = temp; } batch->pos.x = SSub(temp, last_batch_pos_x); last_batch_pos_x = temp; temp += pc->pc_pr->pr_width - 1; if (temp > bounds_right) { if (temp > rects_right) { result.break_reason = EI_PR_HIT_RIGHT; if (special_char < -1) { batch--; result.bounds.r_width = -2-special_char; } break; } bounds_right = temp; } if (check_vert_bounds) { temp = (short)pc->pc_home.y; temp += result.pos.y; if (temp < result.bounds.r_top) { if (temp < rect->r_top) { result.break_reason = EI_PR_HIT_TOP; break; } result.bounds.r_top = temp; } batch->pos.y = SSub(temp, last_batch_pos_y); last_batch_pos_y = temp; temp += pc->pc_pr->pr_height - 1; if (temp > bounds_bottom) { if (temp > rects_bottom) { result.break_reason = EI_PR_HIT_BOTTOM; break; } bounds_bottom = temp; } if (private->font_flags & FF_EASY_Y) check_vert_bounds = FALSE; } else { batch->pos.y = 0; } batch++; } else { special_char = (c < ' ') ? c+64 : '?'; c = '^'; goto Rescan; }Skip_pc_pr_tests: /* Accumulate advances for caller and ourselves. */ result.pos.x += pc->pc_adv.x; result.pos.y += pc->pc_adv.y; if (special_char != -1) { if (special_char >= 0) { c = special_char; special_char = -2-result.bounds.r_width; goto Rescan; } else special_char = -1; } if (c == NEWLINE) break; } if (c == NEWLINE) /* Note following overrides possible EI_PR_HIT_RIGHT above. */ result.break_reason = EI_PR_NEWLINE; result.last_plus_one = esi; result.bounds.r_width = bounds_right - result.bounds.r_left + 1; result.bounds.r_height = bounds_bottom - result.bounds.r_top + 1; result.considered = esi; if (op & EI_OP_MEASURE) { } else { int batch_length = batch - batch_array; /* C does "/ sizeof(struct)" */ paint_batch(op, x, y, rop, pw, rect, prpos, batch_array, batch_length, &result.bounds); } result.pos.x += private->font_home.x; result.pos.y += private->font_home.y; return(result);}staticpaint_batch(op, x, y, rop, pw, rect, prpos, batch, batch_length, bounds) register int op, x, y, rop; register struct pixwin *pw; register struct rect *rect; struct pr_prpos prpos, *batch; int batch_length; register struct rect *bounds;{#define EI_OP_CLEAR_ALL EI_OP_CLEAR_FRONT|EI_OP_CLEAR_INTERIOR|EI_OP_CLEAR_BACK register int temp; /* Write to memory image, if retained */ pw_batch_on(pw); if (op & EI_OP_CLEAR_ALL) {#define bounds_right temp bounds_right = bounds->r_left + bounds->r_width; if ((op & EI_OP_CLEAR_ALL) == EI_OP_CLEAR_INTERIOR) { (void) pw_lock(pw, bounds); } else { struct rect extend_bounds; extend_bounds.r_left = rect->r_left; extend_bounds.r_top = bounds->r_top; extend_bounds.r_width = rect->r_width; extend_bounds.r_height = bounds->r_height; (void) pw_lock(pw, &extend_bounds); } if (op & EI_OP_CLEAR_FRONT) (void) pw_write(pw,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -