summaryrefslogtreecommitdiff
path: root/src/include/font.h
blob: 68a82faf264303d8984ad6cf780fbc6e3f82dc66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
// -*- C++ -*-
/* Copyright (C) 1989-2020 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 under
the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or
(at your option) any later version.

groff is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>. */

// A function of this type can be registered to define the semantics of
// arbitrary commands in a font DESC file.
typedef void (*FONT_COMMAND_HANDLER)(const char *,	// command
				     const char *,	// arg
				     const char *,	// file
				     int);		// lineno

// A glyph is represented by a font-independent 'glyph *' pointer.  The
// functions name_to_glyph and number_to_glyph return such a pointer.
//
// There are two types of glyphs:
//
//   - those with a name, and among these in particular:
//     'charNNN' denoting a single 'char' in the input character set,
//     'uXXXX' denoting a Unicode character,
//
//   - those with a number, referring to the font-dependent glyph with
//     the given number.

// The statically allocated information about a glyph.
//
// This is an abstract class; only its subclass 'charinfo' is
// instantiated.  'charinfo' exists in two versions: one in
// roff/troff/input.cpp for troff, and one in
// libs/libgroff/nametoindex.cpp for the preprocessors and the
// postprocessors.
struct glyph {
  int index;			// A font-independent integer value.
  int number;			// Glyph number or -1.
  friend class character_indexer;
};

#define UNDEFINED_GLYPH ((glyph *) 0)

// The next three functions exist in two versions: one in
// roff/troff/input.cpp for troff, and one in
// libs/libgroff/nametoindex.cpp for the preprocessors and the
// postprocessors.
extern glyph *name_to_glyph(const char *);	// Convert the glyph with
			// the given name (arg1) to a 'glyph' object.  This
			// has the same semantics as the groff escape sequence
			// \C'name'.  If such a 'glyph' object does not yet
			// exist, a new one is allocated.
extern glyph *number_to_glyph(int);	// Convert the font-dependent glyph
			// with the given number (in the font) to a 'glyph'
			// object.  This has the same semantics as the groff
			// escape sequence \N'number'.  If such a 'glyph'
			// object does not yet exist, a new one is allocated.
extern const char *glyph_to_name(glyph *);	// Convert the given
			// glyph back to its name.  Return null pointer
			// if the glyph doesn't have a name.
inline int glyph_to_number(glyph *);	// Convert the given glyph back to
			// its number.  Return -1 if it does not designate
			// a numbered character.
inline int glyph_to_index(glyph *);	// Return the unique index that is
			// associated with the given glyph. It is >= 0.
extern int glyph_to_unicode(glyph *);	// Convert the given glyph to its
			// Unicode codepoint.  Return -1 if it does not
			// designate a Unicode character.

inline int glyph_to_number(glyph *g)
{
  return g->number;
}

inline int glyph_to_index(glyph *g)
{
  return g->index;
}

// Types used in non-public members of 'class font'.
struct font_kern_list;
struct font_char_metric;
struct font_widths_cache;

// A 'class font' instance represents the relevant information of a font of
// the given device.  This includes the set of glyphs represented by the
// font, and metrics for each glyph.
class font {
public:
  enum {		// The valid argument values of 'has_ligature'.
    LIG_ff = 1,
    LIG_fi = 2,
    LIG_fl = 4,
    LIG_ffi = 8,
    LIG_ffl = 16
  };

  virtual ~font();	// Destructor.
  bool contains(glyph *);	// This font contains the given glyph.
  bool is_special();	// This font is searched for glyphs not defined
			// in the current font.  See section 'Special
			// Fonts' in the groff Texinfo manual.  Used by
			// make_glyph_node().
  int get_width(glyph *, int);	// A rectangle represents the shape of the
			// given glyph (arg1) at the given point size
			// (arg2).  Return the horizontal dimension of this
			// rectangle.
  int get_height(glyph *, int);	// A rectangle represents the shape of the
			// given glyph (arg1) at the given point size
			// (arg2).  Return the distance between the base
			// line and the top of this rectangle.
			// This is often also called the 'ascent' of the
			// glyph.  If the top is above the baseline, this
			// value is positive.
  int get_depth(glyph *, int);	// A rectangle represents the shape of the
			// given glyph (arg1) at the given point size
			// (arg2).  Return the distance between the base
			// line and the bottom of this rectangle.
			// This is often also called the 'descent' of the
			// glyph.  If the bottom is below the baseline,
			// this value is positive.
  int get_space_width(int);	// Return the normal width of a space at the
			// given point size.
  int get_character_type(glyph *);	// Return a bit mask describing the
			// shape of the given glyph.  Bit 0 is set if the
			// character has a descender.  Bit 1 is set if the
			// character has a tall glyph.  See groff manual,
			// description of \w and the 'ct' register.
  int get_kern(glyph *, glyph *, int);	// Return the kerning between the
			// given glyphs (arg1 and arg2), both at the given
			// point size (arg3).
  int get_skew(glyph *, int, int);	// A rectangle represents the shape
			// of the given glyph (arg1) at the given point size
			// (arg2).  For slanted fonts like Times-Italic, the
			// optical vertical axis is naturally slanted.  The
			// natural slant value (measured in degrees;
			// positive values mean aslant to the right) is
			// specified in the font's description file (see
			// member variable SLANT below).  In addition to
			// this, any font can be artificially slanted.  This
			// artificial slant value (arg3, measured in
			// degrees; positive values mean a slant to the
			// right) is specified with the \S escape.
			//
			// Return the skew value which is the horizontal
			// distance between the upper left corner of the
			// glyph box and the upper left corner of the glyph
			// box thought to be slanted by the sum of the
			// natural and artificial slant.  It basically means
			// how much an accent must be shifted horizontally
			// to put it on the optical axis of the glyph.
  bool has_ligature(int);	// This font has the given ligature type
			// (one of LIG_ff, LIG_fi, ...).
  int get_italic_correction(glyph *, int);	// If the given glyph (arg1)
			// at the given point size (arg2) is followed by an
			// unslanted glyph, some horizontal white space may
			// need to be inserted in between.  See the groff
			// manual, description of \/.  Return the amount
			// (width) of this white space.
  int get_left_italic_correction(glyph *, int);	// If the given glyph (arg1)
			// at the given point size (arg2) is preceded by an
			// unslanted roman glyph, some horizontal white
			// space may need to be inserted in between.  See
			// the groff manual, description of \,.  Return the
			// amount (width) of this white space.
  int get_subscript_correction(glyph *, int);	// If the given glyph (arg1)
			// at the given point size (arg2)is followed by a
			// subscript glyph, the horizontal position may need
			// to be advanced by some (possibly negative)
			// amount.  See groff manual, description of \w and
			// the 'ssc' register.  Return this amount.
  void set_zoom(int);	// Set the font's zoom factor * 1000.  Must be a
  			// non-negative value.
  int get_zoom();	// Return the font's zoom factor * 1000.
  int get_code(glyph *);	// Return the code point in the physical
			// font of the given glyph.
  const char *get_special_device_encoding(glyph *);	// Return
			// special device-dependent information about
			// the given glyph.  Return null pointer if
			// there is no special information.
  const char *get_name();	// Return the name of this font.
  const char *get_internal_name();	// Return the 'internalname'
			// attribute of this font or null pointer if it
			// has none.
  const char *get_image_generator();	// Return the 'image_generator'
			// attribute of this font or null pointer if it
			// has none.
  static bool scan_papersize(const char *, const char **,
			     double *, double *); // Parse the
			// 'papersize' directive in the DESC file name
			// given in arg1.  Update arg2 with the name
			// of the paper format and arg3 and arg4 with
			// its length and width, respectively.  Return
			// whether paper size was successfully set.
  static font *load_font(const char *, bool = false); // Load the font
			// description file with the given name (arg1)
			// and return a pointer to a 'font' object.  If
			// arg2 is true, only the part of the font
			// description file before the 'charset' and
			// 'kernpairs' sections is loaded.  Return null
			// pointer in case of failure.
  static void command_line_font_dir(const char *);	// Prepend given
			// path (arg1) to the list of directories in which
			// to look up fonts.
  static FILE *open_file(const char *, char **);	// Open
			// a font file with the given name (arg1),
			// searching along the current font path.  If
			// arg2 points to a string pointer, set it to
			// the found file name (this depends on the
			// device also).  Return the opened file.  If
			// not found, arg2 is unchanged, and a null
			// pointer is returned.

  // Open the DESC file (depending on the device) and initialize some
  // static variables with info from there.
  static const char *load_desc();
  static FONT_COMMAND_HANDLER
    set_unknown_desc_command_handler(FONT_COMMAND_HANDLER);	// Register
			// a function which defines the semantics of
			// arbitrary commands in the font DESC file.
  // Now the variables from the DESC file, shared by all fonts.
  static int res;	// The 'res' attribute given in the DESC file.
  static int hor;	// The 'hor' attribute given in the DESC file.
  static int vert;	// The 'vert' attribute given in the DESC file.
  static int unitwidth;	// The 'unitwidth' attribute given in the DESC file.
  static int paperwidth;	// The 'paperwidth' attribute given in the
			// DESC file, or derived from the 'papersize'
			// attribute given in the DESC file.
  static int paperlength;	// The 'paperlength' attribute given in the
			// DESC file, or derived from the 'papersize'
			// attribute given in the DESC file.
  static const char *papersize;
  static int biggestfont;	// The 'biggestfont' attribute given in the
			// DESC file.
  static int spare2;
  static int sizescale;	// The 'sizescale' attribute given in the DESC file.
  static bool has_tcommand;	// DESC file has 'tcommand' directive.
  static bool use_unscaled_charwidths;	// DESC file has
			// 'unscaled_charwidths' directive.
  static bool pass_filenames;	// DESC file has 'pass_filenames'
			// directive.
  static bool use_charnames_in_special;	// DESC file has
			// 'use_charnames_in_special' directive.
  static bool is_unicode; // DESC file has the 'unicode' directive.
  static const char *image_generator;	// The 'image_generator' attribute
			// given in the DESC file.
  static const char **font_name_table;	// The 'fonts' attribute given
			// in the DESC file, as a null
			// pointer-terminated array of strings.
  static const char **style_table;	// The 'styles' attribute given
			// in the DESC file, as a null
			// pointer-terminated array of strings.
  static const char *family;	// The 'family' attribute given in the DESC
			// file.
  static int *sizes;	// The 'sizes' attribute given in the DESC file, as
			// an array of intervals of the form { lower1,
			// upper1, ... lowerN, upperN, 0 }.

private:
  unsigned ligatures;	// Bit mask of available ligatures.  Used by
			// has_ligature().
  font_kern_list **kern_hash_table;	// Hash table of kerning pairs.
			// Used by get_kern().
  int space_width;	// The normal width of a space.  Used by
			// get_space_width().
  bool special;		// See public is_special() above.
  char *name;		// The name of this font.  Used by get_name().
  char *internalname;	// The 'internalname' attribute of this font, or
			// a null pointer.  Used by get_internal_name().
  double slant;		// The natural slant angle (in degrees) of this font.
  int zoom;		// The font's magnification, multiplied by 1000.
			// Used by scale().  A zero value means 'no zoom'.
  int *ch_index;	// Conversion table from font-independent character
			// indices to indices for this particular font.
  int nindices;
  font_char_metric *ch;	// Metrics information for every character in this
			// font (if !is_unicode) or for just some characters
			// (if is_unicode).  The indices of this array are
			// font-specific, found as values in ch_index[].
  int ch_used;
  int ch_size;
  font_widths_cache *widths_cache;	// A cache of scaled character
			// widths.  Used by the get_width() function.

  static FONT_COMMAND_HANDLER unknown_desc_command_handler;	// A
			// function defining the semantics of arbitrary
			// commands in the DESC file.
  enum { KERN_HASH_TABLE_SIZE = 503 };	// Size of the hash table of kerning
			// pairs.

  // These methods add new characters to the ch_index[] and ch[] arrays.
  void add_entry(glyph *,			// glyph
		 const font_char_metric &);	// metric
  void copy_entry(glyph *,			// new_glyph
		  glyph *);			// old_glyph
  void alloc_ch_index(int);			// index
  void extend_ch();
  void compact();

  void add_kern(glyph *, glyph *, int);	// Add to the kerning table a
			// kerning amount (arg3) between two given glyphs
			// (arg1 and arg2).
  static int hash_kern(glyph *, glyph *);	// Return a hash code for
			// the pair of glyphs (arg1 and arg2).

  /* Returns w * pointsize / unitwidth, rounded to the nearest integer.  */
  int scale(int w, int pointsize);
  static bool unit_scale(double *, char); // Convert value in arg1 from
			// the given unit (arg2; possible values are
			// 'i', 'c', 'p', and 'P' as documented in the
			// info file of groff, section 'Measurements')
			// to inches.  Store result in arg1 and return
			// whether conversion was successful.
  virtual void handle_unknown_font_command(const char *,	// command
					   const char *,	// arg
					   const char *,	// file
					   int);		// lineno

protected:
  font(const char *);	// Initialize a font with the given name.

  // Load the font description file with the name in member variable
  // `name` into this object.  If arg1 is true, only the part of the
  // font description file before the 'charset' and 'kernpairs' sections
  // is loaded.  Return success/failure status of load.
  bool load(bool = false);
};

// Local Variables:
// fill-column: 72
// mode: C++
// End:
// vim: set cindent noexpandtab shiftwidth=2 textwidth=72: