📄 node.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 "troff.h"#include "symbol.h"#include "dictionary.h"#include "hvunits.h"#include "env.h"#include "request.h"#include "node.h"#include "token.h"#include "charinfo.h"#include "font.h"#include "reg.h"#define STORE_WIDTH 1symbol HYPHEN_SYMBOL("hy");// Character used when a hyphen is inserted at a line break.static charinfo *soft_hyphen_char;enum constant_space_type { CONSTANT_SPACE_NONE, CONSTANT_SPACE_RELATIVE, CONSTANT_SPACE_ABSOLUTE };struct special_font_list { int n; special_font_list *next;};special_font_list *global_special_fonts;static int global_ligature_mode = 1;static int global_kern_mode = 1;class track_kerning_function { int non_zero; units min_size; hunits min_amount; units max_size; hunits max_amount;public: track_kerning_function(); track_kerning_function(units, hunits, units, hunits); int operator==(const track_kerning_function &); int operator!=(const track_kerning_function &); hunits compute(int point_size);};// embolden fontno when this is the current fontstruct conditional_bold { conditional_bold *next; int fontno; hunits offset; conditional_bold(int, hunits, conditional_bold * = 0);};struct tfont;class font_info { tfont *last_tfont; int number; font_size last_size; int last_height; int last_slant; symbol internal_name; symbol external_name; font *fm; char is_bold; hunits bold_offset; track_kerning_function track_kern; constant_space_type is_constant_spaced; units constant_space; int last_ligature_mode; int last_kern_mode; conditional_bold *cond_bold_list; void flush();public: special_font_list *sf; font_info(symbol nm, int n, symbol enm, font *f); int contains(charinfo *); void set_bold(hunits); void unbold(); void set_conditional_bold(int, hunits); void conditional_unbold(int); void set_track_kern(track_kerning_function &); void set_constant_space(constant_space_type, units = 0); int is_named(symbol); symbol get_name(); tfont *get_tfont(font_size, int, int, int); hunits get_space_width(font_size, int); hunits get_narrow_space_width(font_size); hunits get_half_narrow_space_width(font_size); int get_bold(hunits *); int is_special(); int is_style();};class tfont_spec {protected: symbol name; int input_position; font *fm; font_size size; char is_bold; char is_constant_spaced; int ligature_mode; int kern_mode; hunits bold_offset; hunits track_kern; // add this to the width hunits constant_space_width; int height; int slant;public: tfont_spec(symbol nm, int pos, font *, font_size, int, int); tfont_spec plain(); int operator==(const tfont_spec &); friend tfont *font_info::get_tfont(font_size fs, int, int, int);};class tfont : public tfont_spec { static tfont *tfont_list; tfont *next; tfont *plain_version;public: tfont(tfont_spec &); int contains(charinfo *); hunits get_width(charinfo *c); int get_bold(hunits *); int get_constant_space(hunits *); hunits get_track_kern(); tfont *get_plain(); font_size get_size(); symbol get_name(); charinfo *get_lig(charinfo *c1, charinfo *c2); int get_kern(charinfo *c1, charinfo *c2, hunits *res); int get_input_position(); int get_character_type(charinfo *); int get_height(); int get_slant(); vunits get_char_height(charinfo *); vunits get_char_depth(charinfo *); hunits get_char_skew(charinfo *); hunits get_italic_correction(charinfo *); hunits get_left_italic_correction(charinfo *); hunits get_subscript_correction(charinfo *); friend tfont *make_tfont(tfont_spec &);};inline int env_definite_font(environment *env){ return env->get_family()->make_definite(env->get_font());}static void invalidate_fontno(int n);/* font_info functions */static font_info **font_table = 0;static int font_table_size = 0;font_info::font_info(symbol nm, int n, symbol enm, font *f): internal_name(nm), external_name(enm), fm(f), number(n), is_constant_spaced(CONSTANT_SPACE_NONE), sf(0), is_bold(0), cond_bold_list(0), last_ligature_mode(1), last_kern_mode(1), last_tfont(0), last_size(0){}inline int font_info::contains(charinfo *ci){ return fm != 0 && fm->contains(ci->get_index());}inline int font_info::is_special(){ return fm != 0 && fm->is_special();}inline int font_info::is_style(){ return fm == 0;}// this is the current_font, fontno is where we found the character,// presumably a special fonttfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno){ if (last_tfont == 0 || fs != last_size || height != last_height || slant != last_slant || global_ligature_mode != last_ligature_mode || global_kern_mode != last_kern_mode || fontno != number) { font_info *f = font_table[fontno]; tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant); for (conditional_bold *p = cond_bold_list; p; p = p->next) if (p->fontno == fontno) { spec.is_bold = 1; spec.bold_offset = p->offset; break; } if (!spec.is_bold && is_bold) { spec.is_bold = 1; spec.bold_offset = bold_offset; } spec.track_kern = track_kern.compute(fs.to_scaled_points()); spec.ligature_mode = global_ligature_mode; spec.kern_mode = global_kern_mode; switch (is_constant_spaced) { case CONSTANT_SPACE_NONE: break; case CONSTANT_SPACE_ABSOLUTE: spec.is_constant_spaced = 1; spec.constant_space_width = constant_space; break; case CONSTANT_SPACE_RELATIVE: spec.is_constant_spaced = 1; spec.constant_space_width = scale(constant_space*fs.to_scaled_points(), units_per_inch, 36*72*sizescale); break; default: assert(0); } if (fontno != number) return make_tfont(spec); last_tfont = make_tfont(spec); last_size = fs; last_height = height; last_slant = slant; last_ligature_mode = global_ligature_mode; last_kern_mode = global_kern_mode; } return last_tfont;}int font_info::get_bold(hunits *res){ if (is_bold) { *res = bold_offset; return 1; } else return 0;}void font_info::unbold(){ if (is_bold) { is_bold = 0; flush(); }}void font_info::set_bold(hunits offset){ if (!is_bold || offset != bold_offset) { is_bold = 1; bold_offset = offset; flush(); }}void font_info::set_conditional_bold(int fontno, hunits offset){ for (conditional_bold *p = cond_bold_list; p; p = p->next) if (p->fontno == fontno) { if (offset != p->offset) { p->offset = offset; flush(); } return; } cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);}conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x) : fontno(f), offset(h), next(x){}void font_info::conditional_unbold(int fontno){ for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next) if ((*p)->fontno == fontno) { conditional_bold *tem = *p; *p = (*p)->next; delete tem; flush(); return; }} void font_info::set_constant_space(constant_space_type type, units x){ if (type != is_constant_spaced || (type != CONSTANT_SPACE_NONE && x != constant_space)) { flush(); is_constant_spaced = type; constant_space = x; }}void font_info::set_track_kern(track_kerning_function &tk){ if (track_kern != tk) { track_kern = tk; flush(); }}void font_info::flush(){ last_tfont = 0;}int font_info::is_named(symbol s){ return internal_name == s;}symbol font_info::get_name(){ return internal_name;}hunits font_info::get_space_width(font_size fs, int space_size){ if (is_constant_spaced == CONSTANT_SPACE_NONE) return scale(hunits(fm->get_space_width(fs.to_scaled_points())), space_size, 12); else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE) return constant_space; else return scale(constant_space*fs.to_scaled_points(), units_per_inch, 36*72*sizescale);}hunits font_info::get_narrow_space_width(font_size fs){ charinfo *ci = get_charinfo(symbol("|")); if (fm->contains(ci->get_index())) return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); else return hunits(fs.to_units()/6);}hunits font_info::get_half_narrow_space_width(font_size fs){ charinfo *ci = get_charinfo(symbol("^")); if (fm->contains(ci->get_index())) return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points())); else return hunits(fs.to_units()/12);}/* tfont */tfont_spec::tfont_spec(symbol nm, int n, font *f, font_size s, int h, int sl) : name(nm), input_position(n), fm(f), size(s), is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1), height(h), slant(sl){ if (height == size.to_scaled_points()) height = 0;}int tfont_spec::operator==(const tfont_spec &spec){ if (fm == spec.fm && size == spec.size && input_position == spec.input_position && name == spec.name && height == spec.height && slant == spec.slant && (is_bold ? (spec.is_bold && bold_offset == spec.bold_offset) : !spec.is_bold) && track_kern == spec.track_kern && (is_constant_spaced ? (spec.is_constant_spaced && constant_space_width == spec.constant_space_width) : !spec.is_constant_spaced) && ligature_mode == spec.ligature_mode && kern_mode == spec.kern_mode) return 1; else return 0;}tfont_spec tfont_spec::plain(){ return tfont_spec(name, input_position, fm, size, height, slant);}hunits tfont::get_width(charinfo *c){ if (is_constant_spaced) return constant_space_width; else if (is_bold) return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) + track_kern + bold_offset); else return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) + track_kern);}vunits tfont::get_char_height(charinfo *c){ vunits v = fm->get_height(c->get_index(), size.to_scaled_points()); if (height != 0 && height != size.to_scaled_points()) return scale(v, height, size.to_scaled_points()); else return v;}vunits tfont::get_char_depth(charinfo *c){ vunits v = fm->get_depth(c->get_index(), size.to_scaled_points()); if (height != 0 && height != size.to_scaled_points()) return scale(v, height, size.to_scaled_points()); else return v;}hunits tfont::get_char_skew(charinfo *c){ return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant));}hunits tfont::get_italic_correction(charinfo *c){ return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points()));}hunits tfont::get_left_italic_correction(charinfo *c){ return hunits(fm->get_left_italic_correction(c->get_index(), size.to_scaled_points()));}hunits tfont::get_subscript_correction(charinfo *c){ return hunits(fm->get_subscript_correction(c->get_index(), size.to_scaled_points()));}inline int tfont::get_input_position(){ return input_position;}inline int tfont::contains(charinfo *ci){ return fm->contains(ci->get_index());}inline int tfont::get_character_type(charinfo *ci){ return fm->get_character_type(ci->get_index());}inline int tfont::get_bold(hunits *res){ if (is_bold) { *res = bold_offset; return 1; } else return 0;}inline int tfont::get_constant_space(hunits *res){ if (is_constant_spaced) { *res = constant_space_width; return 1; } else return 0;}inline hunits tfont::get_track_kern(){ return track_kern;}inline tfont *tfont::get_plain(){ return plain_version;}inline font_size tfont::get_size(){ return size;}inline symbol tfont::get_name(){ return name;}inline int tfont::get_height(){ return height;}inline int tfont::get_slant(){ return slant;}symbol SYMBOL_ff("ff");symbol SYMBOL_fi("fi");symbol SYMBOL_fl("fl");symbol SYMBOL_Fi("Fi");symbol SYMBOL_Fl("Fl");charinfo *tfont::get_lig(charinfo *c1, charinfo *c2){ if (ligature_mode == 0) return 0; charinfo *ci = 0; if (c1->get_ascii_code() == 'f') { switch (c2->get_ascii_code()) { case 'f': if (fm->has_ligature(font::LIG_ff)) ci = get_charinfo(SYMBOL_ff); break; case 'i': if (fm->has_ligature(font::LIG_fi)) ci = get_charinfo(SYMBOL_fi); break; case 'l': if (fm->has_ligature(font::LIG_fl)) ci = get_charinfo(SYMBOL_fl); break; } } else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) { switch (c2->get_ascii_code()) { case 'i': if (fm->has_ligature(font::LIG_ffi)) ci = get_charinfo(SYMBOL_Fi); break; case 'l': if (fm->has_ligature(font::LIG_ffl)) ci = get_charinfo(SYMBOL_Fl); break; } } if (ci != 0 && fm->contains(ci->get_index())) return ci; return 0;}inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res){ if (kern_mode == 0) return 0; else { int n = fm->get_kern(c1->get_index(), c2->get_index(), size.to_scaled_points()); if (n) { *res = hunits(n); return 1; } else return 0; }}tfont *make_tfont(tfont_spec &spec){ for (tfont *p = tfont::tfont_list; p; p = p->next) if (*p == spec) return p; return new tfont(spec);}tfont *tfont::tfont_list = 0;tfont::tfont(tfont_spec &spec) : tfont_spec(spec){ next = tfont_list; tfont_list = this; tfont_spec plain_spec = plain(); for (tfont *p = tfont_list; p; p = p->next) if (*p == plain_spec) { plain_version = p; break; } if (!p) plain_version = new tfont(plain_spec);}/* output_file */class real_output_file : public output_file { int piped; int printing; virtual void really_transparent_char(unsigned char) = 0; virtual void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after) = 0; virtual void really_begin_page(int pageno, vunits page_length) = 0; virtual void really_copy_file(hunits x, vunits y, const char *filename);protected: FILE *fp;public: real_output_file(); ~real_output_file(); void flush(); void transparent_char(unsigned char); void print_line(hunits x, vunits y, node *n, vunits before, vunits after); void begin_page(int pageno, vunits page_length); int is_printing(); void copy_file(hunits x, vunits y, const char *filename);};class suppress_output_file : public real_output_file {public: suppress_output_file(); void really_transparent_char(unsigned char); void really_print_line(hunits x, vunits y, node *n, vunits, vunits); void really_begin_page(int pageno, vunits page_length);};class ascii_output_file : public real_output_file {public: ascii_output_file(); void really_transparent_char(unsigned char); void really_print_line(hunits x, vunits y, node *n, vunits, vunits); void really_begin_page(int pageno, vunits page_length); void outc(unsigned char c); void outs(const char *s);};void ascii_output_file::outc(unsigned char c){ fputc(c, fp);}void ascii_output_file::outs(const char *s){ fputc('<', fp); if (s) fputs(s, fp); fputc('>', fp);}struct hvpair; class troff_output_file : public real_output_file { units hpos; units vpos; units output_vpos; units output_hpos; int force_motion; int current_size; int current_slant; int current_height;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -