📄 font.cc
字号:
// -*- C++ -*-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. Written by James Clark (jjc@jclark.com)This file is part of groff.groff is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.groff is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public License alongwith groff; see the file COPYING. If not, write to the Free SoftwareFoundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include <stdio.h>#include <string.h>#include <ctype.h>#include <assert.h>#include <math.h>#include <stdlib.h>#include "errarg.h"#include "error.h"#include "cset.h"#include "font.h"#include "lib.h"const char *const WS = " \t\n\r";struct font_char_metric { char type; int code; int width; int height; int depth; int pre_math_space; int italic_correction; int subscript_correction;};struct font_kern_list { int i1; int i2; int amount; font_kern_list *next; font_kern_list(int, int, int, font_kern_list * = 0);};struct font_widths_cache { font_widths_cache *next; int point_size; int *width; font_widths_cache(int, int, font_widths_cache *); ~font_widths_cache();};/* text_file */struct text_file { FILE *fp; char *path; int lineno; int size; int skip_comments; char *buf; text_file(FILE *fp, char *p); ~text_file(); int next(); void error(const char *format, const errarg &arg1 = empty_errarg, const errarg &arg2 = empty_errarg, const errarg &arg3 = empty_errarg);};text_file::text_file(FILE *p, char *s) : lineno(0), buf(0), size(0), skip_comments(1), fp(p), path(s){}text_file::~text_file(){ a_delete buf; a_delete path; if (fp) fclose(fp);}int text_file::next(){ if (fp == 0) return 0; if (buf == 0) { buf = new char [128]; size = 128; } for (;;) { int i = 0; for (;;) { int c = getc(fp); if (c == EOF) break; if (illegal_input_char(c)) error("illegal input character code `%1'", int(c)); else { if (i + 1 >= size) { char *old_buf = buf; buf = new char[size*2]; memcpy(buf, old_buf, size); a_delete old_buf; size *= 2; } buf[i++] = c; if (c == '\n') break; } } if (i == 0) break; buf[i] = '\0'; lineno++; char *ptr = buf; while (csspace(*ptr)) ptr++; if (*ptr != 0 && (!skip_comments || *ptr != '#')) return 1; } return 0;}void text_file::error(const char *format, const errarg &arg1, const errarg &arg2, const errarg &arg3){ error_with_file_and_line(path, lineno, format, arg1, arg2, arg3);}/* font functions */font::font(const char *s): special(0), ligatures(0), kern_hash_table(0), space_width(0), ch(0), ch_used(0), ch_size(0), ch_index(0), nindices(0), widths_cache(0){ name = new char[strlen(s) + 1]; strcpy(name, s); internalname = 0; slant = 0.0; // load(); // for testing}font::~font(){ a_delete ch; a_delete ch_index; if (kern_hash_table) { for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) { font_kern_list *kerns = kern_hash_table[i]; while (kerns) { font_kern_list *tem = kerns; kerns = kerns->next; delete tem; } } a_delete kern_hash_table; } a_delete name; a_delete internalname; while (widths_cache) { font_widths_cache *tem = widths_cache; widths_cache = widths_cache->next; delete tem; }}static int scale_round(int n, int x, int y){ assert(x >= 0 && y > 0); int y2 = y/2; if (x == 0) return 0; if (n >= 0) { if (n <= (INT_MAX - y2)/x) return (n*x + y2)/y; return int(n*double(x)/double(y) + .5); } else { if (-(unsigned)n <= (-(unsigned)INT_MIN - y2)/x) return (n*x - y2)/y; return int(n*double(x)/double(y) - .5); }}inline int font::scale(int w, int sz){ return sz == unitwidth ? w : scale_round(w, sz, unitwidth);}int font::get_skew(int c, int point_size, int sl){ int h = get_height(c, point_size); return int(h*tan((slant+sl)*M_PI/180.0) + .5);}int font::contains(int c){ return c >= 0 && c < nindices && ch_index[c] >= 0;}int font::is_special(){ return special;}font_widths_cache::font_widths_cache(int ps, int ch_size, font_widths_cache *p = 0): next(p), point_size(ps){ width = new int[ch_size]; for (int i = 0; i < ch_size; i++) width[i] = -1;}font_widths_cache::~font_widths_cache(){ a_delete width;}int font::get_width(int c, int point_size){ assert(c >= 0 && c < nindices); int i = ch_index[c]; assert(i >= 0); if (point_size == unitwidth) return ch[i].width; if (!widths_cache) widths_cache = new font_widths_cache(point_size, ch_size); else if (widths_cache->point_size != point_size) { for (font_widths_cache **p = &widths_cache; *p; p = &(*p)->next) if ((*p)->point_size == point_size) break; if (*p) { font_widths_cache *tem = *p; *p = (*p)->next; tem->next = widths_cache; widths_cache = tem; } else widths_cache = new font_widths_cache(point_size, ch_size, widths_cache); } int &w = widths_cache->width[i]; if (w < 0) w = scale(ch[i].width, point_size); return w;}int font::get_height(int c, int point_size){ assert(c >= 0 && c < nindices && ch_index[c] >= 0); return scale(ch[ch_index[c]].height, point_size);}int font::get_depth(int c, int point_size){ assert(c >= 0 && c < nindices && ch_index[c] >= 0); return scale(ch[ch_index[c]].depth, point_size);}int font::get_italic_correction(int c, int point_size){ assert(c >= 0 && c < nindices && ch_index[c] >= 0); return scale(ch[ch_index[c]].italic_correction, point_size);}int font::get_left_italic_correction(int c, int point_size){ assert(c >= 0 && c < nindices && ch_index[c] >= 0); return scale(ch[ch_index[c]].pre_math_space, point_size);}int font::get_subscript_correction(int c, int point_size){ assert(c >= 0 && c < nindices && ch_index[c] >= 0); return scale(ch[ch_index[c]].subscript_correction, point_size);}int font::get_space_width(int point_size){ return scale(space_width, point_size);}font_kern_list::font_kern_list(int c1, int c2, int n, font_kern_list *p) : i1(c1), i2(c2), amount(n), next(p){}inline int font::hash_kern(int i1, int i2){ int n = ((i1 << 10) + i2) % KERN_HASH_TABLE_SIZE; return n < 0 ? -n : n;}void font::add_kern(int i1, int i2, int amount){ if (!kern_hash_table) { kern_hash_table = new font_kern_list *[KERN_HASH_TABLE_SIZE]; for (int i = 0; i < KERN_HASH_TABLE_SIZE; i++) kern_hash_table[i] = 0; } font_kern_list **p = kern_hash_table + hash_kern(i1, i2); *p = new font_kern_list(i1, i2, amount, *p);}int font::get_kern(int i1, int i2, int point_size){ if (kern_hash_table) { for (font_kern_list *p = kern_hash_table[hash_kern(i1, i2)]; p; p = p->next) if (i1 == p->i1 && i2 == p->i2) return scale(p->amount, point_size); } return 0;}int font::has_ligature(int mask){ return mask & ligatures;}int font::get_character_type(int c){ assert(c >= 0 && c < nindices && ch_index[c] >= 0); return ch[ch_index[c]].type;}int font::get_code(int c){ assert(c >= 0 && c < nindices && ch_index[c] >= 0); return ch[ch_index[c]].code;}const char *font::get_name(){ return name;}const char *font::get_internal_name(){ return internalname;}void font::alloc_ch_index(int index){ if (nindices == 0) { nindices = 128; if (index >= nindices) nindices = index + 10; ch_index = new short[nindices]; for (int i = 0; i < nindices; i++) ch_index[i] = -1; } else { int old_nindices = nindices; nindices *= 2; if (index >= nindices) nindices = index + 10; short *old_ch_index = ch_index; ch_index = new short[nindices]; memcpy(ch_index, old_ch_index, sizeof(short)*old_nindices); for (int i = old_nindices; i < nindices; i++) ch_index[i] = -1; a_delete old_ch_index; }}void font::extend_ch(){ if (ch == 0) ch = new font_char_metric[ch_size = 16]; else { int old_ch_size = ch_size; ch_size *= 2; font_char_metric *old_ch = ch; ch = new font_char_metric[ch_size]; memcpy(ch, old_ch, old_ch_size*sizeof(font_char_metric)); a_delete old_ch; }}void font::compact(){ for (int i = nindices - 1; i >= 0; i--) if (ch_index[i] >= 0) break; i++; if (i < nindices) { short *old_ch_index = ch_index; ch_index = new short[i]; memcpy(ch_index, old_ch_index, i*sizeof(short)); a_delete old_ch_index; nindices = i; } if (ch_used < ch_size) { font_char_metric *old_ch = ch; ch = new font_char_metric[ch_used]; memcpy(ch, old_ch, ch_used*sizeof(font_char_metric)); a_delete old_ch; ch_size = ch_used; }}void font::add_entry(int index, const font_char_metric &metric){ assert(index >= 0); if (index >= nindices) alloc_ch_index(index); assert(index < nindices); if (ch_used + 1 >= ch_size) extend_ch(); assert(ch_used + 1 < ch_size); ch_index[index] = ch_used; ch[ch_used++] = metric;}void font::copy_entry(int new_index, int old_index){ assert(new_index >= 0 && old_index >= 0 && old_index < nindices); if (new_index >= nindices) alloc_ch_index(new_index); ch_index[new_index] = ch_index[old_index];}font *font::load_font(const char *s, int *not_found){ font *f = new font(s); if (!f->load(not_found)) { delete f; return 0; } return f;}static char *trim_arg(char *p){ if (!p)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -