lilypond-1.3.7
[lilypond.git] / lily / tfm-reader.cc
blob31fea32ab275276ee93c52511bbc324390ca2c4b
1 /*
2 tfm-reader.cc -- implement Tex_font_metric_reader
4 source file of the GNU LilyPond music typesetter
6 (c) 1999 Jan Nieuwenhuizen <janneke@gnu.org>
9 some code shamelessly copied from GNU fontutils-0.6/tfm/tfm_input.c
12 #include "tfm-reader.hh"
13 #include "string-convert.hh"
14 #include "debug.hh"
15 #include "warn.hh"
17 #define format_str String_convert::form_str
18 #define FIX_UNITY (1 << 20)
19 static const Real fix_to_real (Fix f);
22 Tex_font_metric_reader::Tex_font_metric_reader (Tex_font_metric* fp, String name)
23 : input_ (name)
25 tfm_l_=fp;
26 tfm_l_->clear (TFM_SIZE);
27 read_header ();
28 read_params ();
29 read_char_metrics ();
33 Tex_font_metric *
34 Tex_font_metric_reader::read_file (String name)
36 Tex_font_metric * tfmp = new Tex_font_metric;
37 Tex_font_metric_reader tfm_reader (tfmp, name);
39 return tfmp;
45 static const Real
46 fix_to_real (Fix f)
48 Real r = f / FIX_UNITY + ((Real) (f % FIX_UNITY) / (Real) FIX_UNITY);
49 return r;
52 /* Most quantities are fixed-point fractions. */
54 Real
55 Tex_font_metric_reader::get_U32_fix_f ()
57 return fix_to_real (input_.get_U32 ());
60 /* Dimensions are a `Fix' scaled by the design size. */
62 Real
63 Tex_font_metric_reader::get_U32_fix_scaled_f ()
65 return get_U32_fix_f () * tfm_l_->info_.design_size;
68 String
69 Tex_font_metric_reader::get_bcpl_str ()
71 U8 length_u8 = input_.get_U8 ();
72 String str = input_.get_str (length_u8);
73 return str;
76 /* Here we read the information at the beginning of the file. We store
77 the result into the static variables `global_info' and
78 `tfm_header'. */
79 void
80 Tex_font_metric_reader::read_header ()
82 U16 file_length = input_.get_U16 ();
83 (void) file_length;
84 U16 header_length = input_.get_U16 ();
86 tfm_l_->info_.first_charcode = input_.get_U16 ();
87 tfm_l_->info_.last_charcode = input_.get_U16 ();
88 U16 width_word_count = input_.get_U16 ();
89 U16 height_word_count = input_.get_U16 ();
90 U16 depth_word_count = input_.get_U16 ();
91 U16 italic_correction_word_count = input_.get_U16 ();
92 U16 lig_kern_word_count = input_.get_U16 ();
93 U16 kern_word_count = input_.get_U16 ();
94 (void)kern_word_count;
95 U16 extensible_word_count = input_.get_U16 ();
96 (void)extensible_word_count;
98 tfm_l_->header_.param_word_count = input_.get_U16 ();
99 tfm_l_->info_.parameter_count = tfm_l_->header_.param_word_count;
101 tfm_l_->header_.char_info_pos = (6 + header_length) * 4;
102 tfm_l_->header_.width_pos = tfm_l_->header_.char_info_pos
103 + (tfm_l_->info_.last_charcode
104 - tfm_l_->info_.first_charcode + 1) * 4;
105 tfm_l_->header_.height_pos = tfm_l_->header_.width_pos + width_word_count * 4;
106 tfm_l_->header_.depth_pos = tfm_l_->header_.height_pos + height_word_count * 4;
107 tfm_l_->header_.italic_correction_pos = tfm_l_->header_.depth_pos
108 + depth_word_count * 4;
109 tfm_l_->header_.lig_kern_pos = tfm_l_->header_.italic_correction_pos
110 + italic_correction_word_count * 4;
111 tfm_l_->header_.kern_pos = tfm_l_->header_.lig_kern_pos + lig_kern_word_count * 4;
112 /* We don't care about the extensible table. */
114 if (header_length < 2)
115 error (_f ("TFM header of `%s' has only %u word(s)",
116 input_.name_str ().ch_C (), header_length));
118 tfm_l_->info_.checksum = input_.get_U32 ();
119 tfm_l_->info_.design_size = get_U32_fix_f ();
121 /* Although the coding scheme might be interesting to the caller, the
122 font family and face byte probably aren't. So we don't read them. */
123 tfm_l_->info_.coding_scheme = header_length > 2
124 ? get_bcpl_str () : "unspecified";
126 DEBUG_OUT << format_str ("TFM checksum = %u, design_size = %fpt, coding scheme = `%s'.\n",
127 tfm_l_->info_.checksum,
128 tfm_l_->info_.design_size,
129 tfm_l_->info_.coding_scheme.ch_C ());
132 /* Although TFM files are only usable by TeX if they have at least seven
133 parameters, that is not a requirement of the file format itself, so
134 we don't impose it. And they can have many more than seven, of
135 course. We do impose a limit of TFM_MAX_FONT_PARAMETERS. We assume
136 that `tfm_header' has already been filled in. */
138 void
139 Tex_font_metric_reader::read_params ()
141 /* If we have no font parameters at all, we're done. */
142 if (tfm_l_->header_.param_word_count == 0)
143 return;
145 //brrr
146 /* Move to the beginning of the parameter table in the file. */
147 input_.seek_ch_C (-4 * tfm_l_->header_.param_word_count);
149 /* It's unlikely but possible that this TFM file has more fontdimens
150 than we can deal with. */
151 if (tfm_l_->header_.param_word_count > TFM_MAX_FONTDIMENS)
153 warning (_f ("%s: TFM file has %u parameters, which is more than the %u I can handle",
154 input_.name_str ().ch_C (),
155 tfm_l_->header_.param_word_count,
156 TFM_MAX_FONTDIMENS));
157 tfm_l_->header_.param_word_count = TFM_MAX_FONTDIMENS;
160 /* The first parameter is different than all the rest, because it
161 isn't scaled by the design size. */
162 tfm_l_->info_.parameters[(TFM_SLANT_PARAMETER) - 1] = get_U32_fix_f ();
164 for (Char_code i = 2; i <= tfm_l_->header_.param_word_count; i++)
165 tfm_l_->info_.parameters[i - 1] = get_U32_fix_scaled_f ();
167 #ifdef PRINT
168 for (Char_code i = 1; i <= tfm_l_->header_.param_word_count; i++)
169 DEBUG_OUT << format_str ("TFM parameter %d: %.3f", i, tfm_l_->info_.parameters[i - 1]);
170 #endif
173 /* Read every character in the TFM file, storing the result in the
174 static `tfm_char_table'. We return a copy of that variable. */
176 void
177 Tex_font_metric_reader::read_char_metrics ()
179 for (int i = tfm_l_->info_.first_charcode; i <= tfm_l_->info_.last_charcode; i++)
181 Tex_font_char_metric tfm_char = read_char_metric (i);
182 if (tfm_char.exists_b_)
183 tfm_l_->ascii_to_metric_idx_[tfm_char.code_] = tfm_l_->char_metrics_.size ();
184 tfm_l_->char_metrics_.push (tfm_char);
188 /* Read the character CODE. If the character doesn't exist, return
189 NULL. If it does, save the information in `tfm_char_table', as well
190 as returning it. */
192 Tex_font_char_metric
193 Tex_font_metric_reader::read_char_metric (Char_code code)
195 Tex_font_char_metric tfm_char;
197 /* If the character is outside the declared bounds in the file, don't
198 try to read it. */
199 if (code < tfm_l_->info_.first_charcode || code > tfm_l_->info_.last_charcode)
200 return tfm_char;
202 //brr
203 /* Move to the appropriate place in the `char_info' array. */
204 input_.seek_ch_C (tfm_l_->header_.char_info_pos + (code - tfm_l_->info_.first_charcode) * 4);
206 /* Read the character. */
207 tfm_char = read_char ();
209 if (tfm_char.exists_b_)
210 tfm_char.code_ = code;
212 return tfm_char;
216 /* We assume we are positioned at the beginning of a `char_info' word.
217 We read that word to get the indexes into the dimension tables; then
218 we go read the tables to get the values (if the character exists). */
220 Tex_font_char_metric
221 Tex_font_metric_reader::read_char ()
223 /* Read the char_info word. */
224 U8 width_index = input_.get_U8 ();
226 U8 packed;
227 packed = input_.get_U8 ();
228 U8 height_index = (packed & 0xf0) >> 4;
229 U8 depth_index = packed & 0x0f;
231 packed = input_.get_U8 ();
232 U8 italic_correction_index = (packed & 0xfc) >> 6;
233 U8 tag = packed & 0x3;
235 U8 remainder = input_.get_U8 ();
237 Tex_font_char_metric tfm_char;
239 #define GET_CHAR_DIMEN(d) \
240 if (d##_index != 0) \
242 input_.seek_ch_C (tfm_l_->header_.##d##_pos + d##_index*4); \
243 tfm_char.d##_fix_ = input_.get_U32 (); \
244 tfm_char.d##_ = fix_to_real (tfm_char.d##_fix_) \
245 * tfm_l_->info_.design_size; \
248 GET_CHAR_DIMEN (width);
249 GET_CHAR_DIMEN (height);
250 GET_CHAR_DIMEN (depth);
251 GET_CHAR_DIMEN (italic_correction);
253 /* The other condition for a character existing is that it be between
254 the first and last character codes given in the header. We've
255 already assumed that's true (or we couldn't be positioned at a
256 `char_info_word'). */
257 tfm_char.exists_b_ = width_index != 0;
259 #ifdef PRINT
260 DEBUG_OUT << format_str (" width = %f, height = %f, ",
261 tfm_char.width_, tfm_char.height_);
262 DEBUG_OUT << format_str ("depth = %f, ic = %f.\n",
263 tfm_char.depth, tfm_char.italic_correction);
264 #endif
266 if (tag == 1)
268 input_.seek_ch_C (tfm_l_->header_.lig_kern_pos + remainder * 4);
269 read_lig_kern_program (&tfm_char.ligature_arr_, &tfm_char.kern_arr_);
272 /* We don't handle the other tags. */
273 return tfm_char;
276 /* Read a ligature/kern program at the current position, storing the
277 result into *LIGATURE and *KERN. We don't distinguish all the kinds
278 of ligatures that Metafont can output. */
280 #define STOP_FLAG 128
281 #define KERN_FLAG 128
283 void
284 Tex_font_metric_reader::read_lig_kern_program (Array <Tfm_ligature>* ligature_arr_p, Array <Tfm_kern>* kern_arr_p)
286 bool end_b;
290 end_b = input_.get_U8 () >= STOP_FLAG;
292 U8 next_char = input_.get_U8 ();
293 bool kern_step_b = input_.get_U8 () >= KERN_FLAG;
294 U8 remainder = input_.get_U8 ();
296 #ifdef PRINT
297 DEBUG_OUT << format_str (" if next = %u (%c), ", next_char, next_char);
298 #endif
300 if (kern_step_b)
302 Tfm_kern kern_element;
303 kern_element.character = next_char;
305 char const* old_pos = input_.pos_ch_C ();
306 input_.seek_ch_C (tfm_l_->header_.kern_pos + remainder * 4);
307 kern_element.kern = get_U32_fix_scaled_f ();
308 input_.set_pos (old_pos);
310 kern_arr_p->push (kern_element);
312 #ifdef PRINT
313 DEBUG_OUT << format_str ("kern %f.\n", kern_element.kern);
314 #endif
316 else
318 Tfm_ligature ligature_element;
319 ligature_element.character = next_char;
320 ligature_element.ligature = remainder;
321 ligature_arr_p->push (ligature_element);
323 #ifdef PRINT
324 DEBUG_OUT format_str ("ligature %d (hex %x).\n",
325 ligature_element.ligature,
326 ligature_element.ligature);
327 #endif
329 } while (!end_b);