1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
4
5 This file is part of groff.
6
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include "troff.h"
22 #include "symbol.h"
23 #include "dictionary.h"
24 #include "hvunits.h"
25 #include "env.h"
26 #include "request.h"
27 #include "node.h"
28 #include "token.h"
29 #include "charinfo.h"
30 #include "font.h"
31 #include "reg.h"
32
33 #define STORE_WIDTH 1
34
35 symbol HYPHEN_SYMBOL("hy");
36
37 // Character used when a hyphen is inserted at a line break.
38 static charinfo *soft_hyphen_char;
39
40 enum constant_space_type {
41 CONSTANT_SPACE_NONE,
42 CONSTANT_SPACE_RELATIVE,
43 CONSTANT_SPACE_ABSOLUTE
44 };
45
46 struct special_font_list {
47 int n;
48 special_font_list *next;
49 };
50
51 special_font_list *global_special_fonts;
52 static int global_ligature_mode = 1;
53 static int global_kern_mode = 1;
54
55 class track_kerning_function {
56 int non_zero;
57 units min_size;
58 hunits min_amount;
59 units max_size;
60 hunits max_amount;
61 public:
62 track_kerning_function();
63 track_kerning_function(units, hunits, units, hunits);
64 int operator==(const track_kerning_function &);
65 int operator!=(const track_kerning_function &);
66 hunits compute(int point_size);
67 };
68
69 // embolden fontno when this is the current font
70
71 struct conditional_bold {
72 conditional_bold *next;
73 int fontno;
74 hunits offset;
75 conditional_bold(int, hunits, conditional_bold * = 0);
76 };
77
78 struct tfont;
79
80 class font_info {
81 tfont *last_tfont;
82 int number;
83 font_size last_size;
84 int last_height;
85 int last_slant;
86 symbol internal_name;
87 symbol external_name;
88 font *fm;
89 char is_bold;
90 hunits bold_offset;
91 track_kerning_function track_kern;
92 constant_space_type is_constant_spaced;
93 units constant_space;
94 int last_ligature_mode;
95 int last_kern_mode;
96 conditional_bold *cond_bold_list;
97 void flush();
98 public:
99 special_font_list *sf;
100
101 font_info(symbol nm, int n, symbol enm, font *f);
102 int contains(charinfo *);
103 void set_bold(hunits);
104 void unbold();
105 void set_conditional_bold(int, hunits);
106 void conditional_unbold(int);
107 void set_track_kern(track_kerning_function &);
108 void set_constant_space(constant_space_type, units = 0);
109 int is_named(symbol);
110 symbol get_name();
111 tfont *get_tfont(font_size, int, int, int);
112 hunits get_space_width(font_size, int);
113 hunits get_narrow_space_width(font_size);
114 hunits get_half_narrow_space_width(font_size);
115 int get_bold(hunits *);
116 int is_special();
117 int is_style();
118 };
119
120 class tfont_spec {
121 protected:
122 symbol name;
123 int input_position;
124 font *fm;
125 font_size size;
126 char is_bold;
127 char is_constant_spaced;
128 int ligature_mode;
129 int kern_mode;
130 hunits bold_offset;
131 hunits track_kern; // add this to the width
132 hunits constant_space_width;
133 int height;
134 int slant;
135 public:
136 tfont_spec(symbol nm, int pos, font *, font_size, int, int);
137 tfont_spec plain();
138 int operator==(const tfont_spec &);
139 friend tfont *font_info::get_tfont(font_size fs, int, int, int);
140 };
141
142 class tfont : public tfont_spec {
143 static tfont *tfont_list;
144 tfont *next;
145 tfont *plain_version;
146 public:
147 tfont(tfont_spec &);
148 int contains(charinfo *);
149 hunits get_width(charinfo *c);
150 int get_bold(hunits *);
151 int get_constant_space(hunits *);
152 hunits get_track_kern();
153 tfont *get_plain();
154 font_size get_size();
155 symbol get_name();
156 charinfo *get_lig(charinfo *c1, charinfo *c2);
157 int get_kern(charinfo *c1, charinfo *c2, hunits *res);
158 int get_input_position();
159 int get_character_type(charinfo *);
160 int get_height();
161 int get_slant();
162 vunits get_char_height(charinfo *);
163 vunits get_char_depth(charinfo *);
164 hunits get_char_skew(charinfo *);
165 hunits get_italic_correction(charinfo *);
166 hunits get_left_italic_correction(charinfo *);
167 hunits get_subscript_correction(charinfo *);
168 friend tfont *make_tfont(tfont_spec &);
169 };
170
env_definite_font(environment * env)171 inline int env_definite_font(environment *env)
172 {
173 return env->get_family()->make_definite(env->get_font());
174 }
175
176 static void invalidate_fontno(int n);
177
178 /* font_info functions */
179
180 static font_info **font_table = 0;
181 static int font_table_size = 0;
182
font_info(symbol nm,int n,symbol enm,font * f)183 font_info::font_info(symbol nm, int n, symbol enm, font *f)
184 : internal_name(nm), external_name(enm), fm(f), number(n),
185 is_constant_spaced(CONSTANT_SPACE_NONE),
186 sf(0), is_bold(0), cond_bold_list(0),
187 last_ligature_mode(1), last_kern_mode(1),
188 last_tfont(0), last_size(0)
189 {
190 }
191
contains(charinfo * ci)192 inline int font_info::contains(charinfo *ci)
193 {
194 return fm != 0 && fm->contains(ci->get_index());
195 }
196
is_special()197 inline int font_info::is_special()
198 {
199 return fm != 0 && fm->is_special();
200 }
201
is_style()202 inline int font_info::is_style()
203 {
204 return fm == 0;
205 }
206
207 // this is the current_font, fontno is where we found the character,
208 // presumably a special font
209
get_tfont(font_size fs,int height,int slant,int fontno)210 tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno)
211 {
212 if (last_tfont == 0 || fs != last_size
213 || height != last_height || slant != last_slant
214 || global_ligature_mode != last_ligature_mode
215 || global_kern_mode != last_kern_mode
216 || fontno != number) {
217 font_info *f = font_table[fontno];
218 tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant);
219 for (conditional_bold *p = cond_bold_list; p; p = p->next)
220 if (p->fontno == fontno) {
221 spec.is_bold = 1;
222 spec.bold_offset = p->offset;
223 break;
224 }
225 if (!spec.is_bold && is_bold) {
226 spec.is_bold = 1;
227 spec.bold_offset = bold_offset;
228 }
229 spec.track_kern = track_kern.compute(fs.to_scaled_points());
230 spec.ligature_mode = global_ligature_mode;
231 spec.kern_mode = global_kern_mode;
232 switch (is_constant_spaced) {
233 case CONSTANT_SPACE_NONE:
234 break;
235 case CONSTANT_SPACE_ABSOLUTE:
236 spec.is_constant_spaced = 1;
237 spec.constant_space_width = constant_space;
238 break;
239 case CONSTANT_SPACE_RELATIVE:
240 spec.is_constant_spaced = 1;
241 spec.constant_space_width
242 = scale(constant_space*fs.to_scaled_points(),
243 units_per_inch,
244 36*72*sizescale);
245 break;
246 default:
247 assert(0);
248 }
249 if (fontno != number)
250 return make_tfont(spec);
251 last_tfont = make_tfont(spec);
252 last_size = fs;
253 last_height = height;
254 last_slant = slant;
255 last_ligature_mode = global_ligature_mode;
256 last_kern_mode = global_kern_mode;
257 }
258 return last_tfont;
259 }
260
get_bold(hunits * res)261 int font_info::get_bold(hunits *res)
262 {
263 if (is_bold) {
264 *res = bold_offset;
265 return 1;
266 }
267 else
268 return 0;
269 }
270
unbold()271 void font_info::unbold()
272 {
273 if (is_bold) {
274 is_bold = 0;
275 flush();
276 }
277 }
278
set_bold(hunits offset)279 void font_info::set_bold(hunits offset)
280 {
281 if (!is_bold || offset != bold_offset) {
282 is_bold = 1;
283 bold_offset = offset;
284 flush();
285 }
286 }
287
set_conditional_bold(int fontno,hunits offset)288 void font_info::set_conditional_bold(int fontno, hunits offset)
289 {
290 for (conditional_bold *p = cond_bold_list; p; p = p->next)
291 if (p->fontno == fontno) {
292 if (offset != p->offset) {
293 p->offset = offset;
294 flush();
295 }
296 return;
297 }
298 cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list);
299 }
300
conditional_bold(int f,hunits h,conditional_bold * x)301 conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x)
302 : fontno(f), offset(h), next(x)
303 {
304 }
305
conditional_unbold(int fontno)306 void font_info::conditional_unbold(int fontno)
307 {
308 for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next)
309 if ((*p)->fontno == fontno) {
310 conditional_bold *tem = *p;
311 *p = (*p)->next;
312 delete tem;
313 flush();
314 return;
315 }
316 }
317
set_constant_space(constant_space_type type,units x)318 void font_info::set_constant_space(constant_space_type type, units x)
319 {
320 if (type != is_constant_spaced
321 || (type != CONSTANT_SPACE_NONE && x != constant_space)) {
322 flush();
323 is_constant_spaced = type;
324 constant_space = x;
325 }
326 }
327
set_track_kern(track_kerning_function & tk)328 void font_info::set_track_kern(track_kerning_function &tk)
329 {
330 if (track_kern != tk) {
331 track_kern = tk;
332 flush();
333 }
334 }
335
flush()336 void font_info::flush()
337 {
338 last_tfont = 0;
339 }
340
is_named(symbol s)341 int font_info::is_named(symbol s)
342 {
343 return internal_name == s;
344 }
345
get_name()346 symbol font_info::get_name()
347 {
348 return internal_name;
349 }
350
get_space_width(font_size fs,int space_size)351 hunits font_info::get_space_width(font_size fs, int space_size)
352 {
353 if (is_constant_spaced == CONSTANT_SPACE_NONE)
354 return scale(hunits(fm->get_space_width(fs.to_scaled_points())),
355 space_size, 12);
356 else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE)
357 return constant_space;
358 else
359 return scale(constant_space*fs.to_scaled_points(),
360 units_per_inch, 36*72*sizescale);
361 }
362
get_narrow_space_width(font_size fs)363 hunits font_info::get_narrow_space_width(font_size fs)
364 {
365 charinfo *ci = get_charinfo(symbol("|"));
366 if (fm->contains(ci->get_index()))
367 return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
368 else
369 return hunits(fs.to_units()/6);
370 }
371
get_half_narrow_space_width(font_size fs)372 hunits font_info::get_half_narrow_space_width(font_size fs)
373 {
374 charinfo *ci = get_charinfo(symbol("^"));
375 if (fm->contains(ci->get_index()))
376 return hunits(fm->get_width(ci->get_index(), fs.to_scaled_points()));
377 else
378 return hunits(fs.to_units()/12);
379 }
380
381 /* tfont */
382
tfont_spec(symbol nm,int n,font * f,font_size s,int h,int sl)383 tfont_spec::tfont_spec(symbol nm, int n, font *f,
384 font_size s, int h, int sl)
385 : name(nm), input_position(n), fm(f), size(s),
386 is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1),
387 height(h), slant(sl)
388 {
389 if (height == size.to_scaled_points())
390 height = 0;
391 }
392
operator ==(const tfont_spec & spec)393 int tfont_spec::operator==(const tfont_spec &spec)
394 {
395 if (fm == spec.fm
396 && size == spec.size
397 && input_position == spec.input_position
398 && name == spec.name
399 && height == spec.height
400 && slant == spec.slant
401 && (is_bold
402 ? (spec.is_bold && bold_offset == spec.bold_offset)
403 : !spec.is_bold)
404 && track_kern == spec.track_kern
405 && (is_constant_spaced
406 ? (spec.is_constant_spaced
407 && constant_space_width == spec.constant_space_width)
408 : !spec.is_constant_spaced)
409 && ligature_mode == spec.ligature_mode
410 && kern_mode == spec.kern_mode)
411 return 1;
412 else
413 return 0;
414 }
415
plain()416 tfont_spec tfont_spec::plain()
417 {
418 return tfont_spec(name, input_position, fm, size, height, slant);
419 }
420
get_width(charinfo * c)421 hunits tfont::get_width(charinfo *c)
422 {
423 if (is_constant_spaced)
424 return constant_space_width;
425 else if (is_bold)
426 return (hunits(fm->get_width(c->get_index(), size.to_scaled_points()))
427 + track_kern + bold_offset);
428 else
429 return (hunits(fm->get_width(c->get_index(), size.to_scaled_points())) + track_kern);
430 }
431
get_char_height(charinfo * c)432 vunits tfont::get_char_height(charinfo *c)
433 {
434 vunits v = fm->get_height(c->get_index(), size.to_scaled_points());
435 if (height != 0 && height != size.to_scaled_points())
436 return scale(v, height, size.to_scaled_points());
437 else
438 return v;
439 }
440
get_char_depth(charinfo * c)441 vunits tfont::get_char_depth(charinfo *c)
442 {
443 vunits v = fm->get_depth(c->get_index(), size.to_scaled_points());
444 if (height != 0 && height != size.to_scaled_points())
445 return scale(v, height, size.to_scaled_points());
446 else
447 return v;
448 }
449
get_char_skew(charinfo * c)450 hunits tfont::get_char_skew(charinfo *c)
451 {
452 return hunits(fm->get_skew(c->get_index(), size.to_scaled_points(), slant));
453 }
454
get_italic_correction(charinfo * c)455 hunits tfont::get_italic_correction(charinfo *c)
456 {
457 return hunits(fm->get_italic_correction(c->get_index(), size.to_scaled_points()));
458 }
459
get_left_italic_correction(charinfo * c)460 hunits tfont::get_left_italic_correction(charinfo *c)
461 {
462 return hunits(fm->get_left_italic_correction(c->get_index(),
463 size.to_scaled_points()));
464 }
465
get_subscript_correction(charinfo * c)466 hunits tfont::get_subscript_correction(charinfo *c)
467 {
468 return hunits(fm->get_subscript_correction(c->get_index(),
469 size.to_scaled_points()));
470 }
471
get_input_position()472 inline int tfont::get_input_position()
473 {
474 return input_position;
475 }
476
contains(charinfo * ci)477 inline int tfont::contains(charinfo *ci)
478 {
479 return fm->contains(ci->get_index());
480 }
481
get_character_type(charinfo * ci)482 inline int tfont::get_character_type(charinfo *ci)
483 {
484 return fm->get_character_type(ci->get_index());
485 }
486
get_bold(hunits * res)487 inline int tfont::get_bold(hunits *res)
488 {
489 if (is_bold) {
490 *res = bold_offset;
491 return 1;
492 }
493 else
494 return 0;
495 }
496
get_constant_space(hunits * res)497 inline int tfont::get_constant_space(hunits *res)
498 {
499 if (is_constant_spaced) {
500 *res = constant_space_width;
501 return 1;
502 }
503 else
504 return 0;
505 }
506
get_track_kern()507 inline hunits tfont::get_track_kern()
508 {
509 return track_kern;
510 }
511
get_plain()512 inline tfont *tfont::get_plain()
513 {
514 return plain_version;
515 }
516
get_size()517 inline font_size tfont::get_size()
518 {
519 return size;
520 }
521
get_name()522 inline symbol tfont::get_name()
523 {
524 return name;
525 }
526
get_height()527 inline int tfont::get_height()
528 {
529 return height;
530 }
531
get_slant()532 inline int tfont::get_slant()
533 {
534 return slant;
535 }
536
537 symbol SYMBOL_ff("ff");
538 symbol SYMBOL_fi("fi");
539 symbol SYMBOL_fl("fl");
540 symbol SYMBOL_Fi("Fi");
541 symbol SYMBOL_Fl("Fl");
542
get_lig(charinfo * c1,charinfo * c2)543 charinfo *tfont::get_lig(charinfo *c1, charinfo *c2)
544 {
545 if (ligature_mode == 0)
546 return 0;
547 charinfo *ci = 0;
548 if (c1->get_ascii_code() == 'f') {
549 switch (c2->get_ascii_code()) {
550 case 'f':
551 if (fm->has_ligature(font::LIG_ff))
552 ci = get_charinfo(SYMBOL_ff);
553 break;
554 case 'i':
555 if (fm->has_ligature(font::LIG_fi))
556 ci = get_charinfo(SYMBOL_fi);
557 break;
558 case 'l':
559 if (fm->has_ligature(font::LIG_fl))
560 ci = get_charinfo(SYMBOL_fl);
561 break;
562 }
563 }
564 else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) {
565 switch (c2->get_ascii_code()) {
566 case 'i':
567 if (fm->has_ligature(font::LIG_ffi))
568 ci = get_charinfo(SYMBOL_Fi);
569 break;
570 case 'l':
571 if (fm->has_ligature(font::LIG_ffl))
572 ci = get_charinfo(SYMBOL_Fl);
573 break;
574 }
575 }
576 if (ci != 0 && fm->contains(ci->get_index()))
577 return ci;
578 return 0;
579 }
580
get_kern(charinfo * c1,charinfo * c2,hunits * res)581 inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res)
582 {
583 if (kern_mode == 0)
584 return 0;
585 else {
586 int n = fm->get_kern(c1->get_index(),
587 c2->get_index(),
588 size.to_scaled_points());
589 if (n) {
590 *res = hunits(n);
591 return 1;
592 }
593 else
594 return 0;
595 }
596 }
597
make_tfont(tfont_spec & spec)598 tfont *make_tfont(tfont_spec &spec)
599 {
600 for (tfont *p = tfont::tfont_list; p; p = p->next)
601 if (*p == spec)
602 return p;
603 return new tfont(spec);
604 }
605
606 tfont *tfont::tfont_list = 0;
607
tfont(tfont_spec & spec)608 tfont::tfont(tfont_spec &spec) : tfont_spec(spec)
609 {
610 next = tfont_list;
611 tfont_list = this;
612 tfont_spec plain_spec = plain();
613 for (tfont *p = tfont_list; p; p = p->next)
614 if (*p == plain_spec) {
615 plain_version = p;
616 break;
617 }
618 if (!p)
619 plain_version = new tfont(plain_spec);
620 }
621
622 /* output_file */
623
624 class real_output_file : public output_file {
625 int piped;
626 int printing;
627 virtual void really_transparent_char(unsigned char) = 0;
628 virtual void really_print_line(hunits x, vunits y, node *n,
629 vunits before, vunits after) = 0;
630 virtual void really_begin_page(int pageno, vunits page_length) = 0;
631 virtual void really_copy_file(hunits x, vunits y, const char *filename);
632 protected:
633 FILE *fp;
634 public:
635 real_output_file();
636 ~real_output_file();
637 void flush();
638 void transparent_char(unsigned char);
639 void print_line(hunits x, vunits y, node *n, vunits before, vunits after);
640 void begin_page(int pageno, vunits page_length);
641 int is_printing();
642 void copy_file(hunits x, vunits y, const char *filename);
643 };
644
645 class suppress_output_file : public real_output_file {
646 public:
647 suppress_output_file();
648 void really_transparent_char(unsigned char);
649 void really_print_line(hunits x, vunits y, node *n, vunits, vunits);
650 void really_begin_page(int pageno, vunits page_length);
651 };
652
653 class ascii_output_file : public real_output_file {
654 public:
655 ascii_output_file();
656 void really_transparent_char(unsigned char);
657 void really_print_line(hunits x, vunits y, node *n, vunits, vunits);
658 void really_begin_page(int pageno, vunits page_length);
659 void outc(unsigned char c);
660 void outs(const char *s);
661 };
662
outc(unsigned char c)663 void ascii_output_file::outc(unsigned char c)
664 {
665 fputc(c, fp);
666 }
667
outs(const char * s)668 void ascii_output_file::outs(const char *s)
669 {
670 fputc('<', fp);
671 if (s)
672 fputs(s, fp);
673 fputc('>', fp);
674 }
675
676 struct hvpair;
677
678 class troff_output_file : public real_output_file {
679 units hpos;
680 units vpos;
681 units output_vpos;
682 units output_hpos;
683 int force_motion;
684 int current_size;
685 int current_slant;
686 int current_height;
687 tfont *current_tfont;
688 int current_font_number;
689 symbol *font_position;
690 int nfont_positions;
691 enum { TBUF_SIZE = 256 };
692 char tbuf[TBUF_SIZE];
693 int tbuf_len;
694 int tbuf_kern;
695 int begun_page;
696 void do_motion();
697 void put(char c);
698 void put(unsigned char c);
699 void put(int i);
700 void put(const char *s);
701 void set_font(tfont *tf);
702 void flush_tbuf();
703 public:
704 troff_output_file();
705 ~troff_output_file();
706 void trailer(vunits page_length);
707 void put_char(charinfo *ci, tfont *tf);
708 void put_char_width(charinfo *ci, tfont *tf, hunits w, hunits k);
709 void right(hunits);
710 void down(vunits);
711 void moveto(hunits, vunits);
712 void start_special();
713 void special_char(unsigned char c);
714 void end_special();
715 void word_marker();
716 void really_transparent_char(unsigned char c);
717 void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after);
718 void really_begin_page(int pageno, vunits page_length);
719 void really_copy_file(hunits x, vunits y, const char *filename);
720 void draw(char, hvpair *, int, font_size);
get_hpos()721 int get_hpos() { return hpos; }
get_vpos()722 int get_vpos() { return vpos; }
723 };
724
put_string(const char * s,FILE * fp)725 static void put_string(const char *s, FILE *fp)
726 {
727 for (; *s != '\0'; ++s)
728 putc(*s, fp);
729 }
730
put(char c)731 inline void troff_output_file::put(char c)
732 {
733 putc(c, fp);
734 }
735
put(unsigned char c)736 inline void troff_output_file::put(unsigned char c)
737 {
738 putc(c, fp);
739 }
740
put(const char * s)741 inline void troff_output_file::put(const char *s)
742 {
743 put_string(s, fp);
744 }
745
put(int i)746 inline void troff_output_file::put(int i)
747 {
748 put_string(itoa(i), fp);
749 }
750
start_special()751 void troff_output_file::start_special()
752 {
753 flush_tbuf();
754 do_motion();
755 put("x X ");
756 }
757
special_char(unsigned char c)758 void troff_output_file::special_char(unsigned char c)
759 {
760 put(c);
761 if (c == '\n')
762 put('+');
763 }
764
end_special()765 void troff_output_file::end_special()
766 {
767 put('\n');
768 }
769
moveto(hunits h,vunits v)770 inline void troff_output_file::moveto(hunits h, vunits v)
771 {
772 hpos = h.to_units();
773 vpos = v.to_units();
774 }
775
really_print_line(hunits x,vunits y,node * n,vunits before,vunits after)776 void troff_output_file::really_print_line(hunits x, vunits y, node *n,
777 vunits before, vunits after)
778 {
779 moveto(x, y);
780 while (n != 0) {
781 n->tprint(this);
782 n = n->next;
783 }
784 flush_tbuf();
785 // This ensures that transparent throughput will have a more predictable
786 // position.
787 do_motion();
788 force_motion = 1;
789 hpos = 0;
790 put('n');
791 put(before.to_units());
792 put(' ');
793 put(after.to_units());
794 put('\n');
795 }
796
word_marker()797 inline void troff_output_file::word_marker()
798 {
799 flush_tbuf();
800 put('w');
801 }
802
right(hunits n)803 inline void troff_output_file::right(hunits n)
804 {
805 hpos += n.to_units();
806 }
807
down(vunits n)808 inline void troff_output_file::down(vunits n)
809 {
810 vpos += n.to_units();
811 }
812
do_motion()813 void troff_output_file::do_motion()
814 {
815 if (force_motion) {
816 put('V');
817 put(vpos);
818 put('\n');
819 put('H');
820 put(hpos);
821 put('\n');
822 }
823 else {
824 if (hpos != output_hpos) {
825 units n = hpos - output_hpos;
826 if (n > 0 && n < hpos) {
827 put('h');
828 put(n);
829 }
830 else {
831 put('H');
832 put(hpos);
833 }
834 put('\n');
835 }
836 if (vpos != output_vpos) {
837 units n = vpos - output_vpos;
838 if (n > 0 && n < vpos) {
839 put('v');
840 put(n);
841 }
842 else {
843 put('V');
844 put(vpos);
845 }
846 put('\n');
847 }
848 }
849 output_vpos = vpos;
850 output_hpos = hpos;
851 force_motion = 0;
852 }
853
flush_tbuf()854 void troff_output_file::flush_tbuf()
855 {
856 if (tbuf_len == 0)
857 return;
858 if (tbuf_kern == 0)
859 put('t');
860 else {
861 put('u');
862 put(tbuf_kern);
863 put(' ');
864 }
865 for (int i = 0; i < tbuf_len; i++)
866 put(tbuf[i]);
867 put('\n');
868 tbuf_len = 0;
869 }
870
put_char_width(charinfo * ci,tfont * tf,hunits w,hunits k)871 void troff_output_file::put_char_width(charinfo *ci, tfont *tf, hunits w,
872 hunits k)
873 {
874 if (tf != current_tfont) {
875 flush_tbuf();
876 set_font(tf);
877 }
878 char c = ci->get_ascii_code();
879 int kk = k.to_units();
880 if (c == '\0') {
881 flush_tbuf();
882 do_motion();
883 if (ci->numbered()) {
884 put('N');
885 put(ci->get_number());
886 }
887 else {
888 put('C');
889 const char *s = ci->nm.contents();
890 if (s[1] == 0) {
891 put('\\');
892 put(s[0]);
893 }
894 else
895 put(s);
896 }
897 put('\n');
898 hpos += w.to_units() + kk;
899 }
900 else if (tcommand_flag) {
901 if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos
902 && kk == tbuf_kern
903 && tbuf_len < TBUF_SIZE) {
904 tbuf[tbuf_len++] = c;
905 output_hpos += w.to_units() + kk;
906 hpos = output_hpos;
907 return;
908 }
909 flush_tbuf();
910 do_motion();
911 tbuf[tbuf_len++] = c;
912 output_hpos += w.to_units() + kk;
913 tbuf_kern = kk;
914 hpos = output_hpos;
915 }
916 else {
917 // flush_tbuf();
918 int n = hpos - output_hpos;
919 if (vpos == output_vpos && n > 0 && n < 100 && !force_motion) {
920 put(char(n/10 + '0'));
921 put(char(n%10 + '0'));
922 put(c);
923 output_hpos = hpos;
924 }
925 else {
926 do_motion();
927 put('c');
928 put(c);
929 }
930 hpos += w.to_units() + kk;
931 }
932 }
933
put_char(charinfo * ci,tfont * tf)934 void troff_output_file::put_char(charinfo *ci, tfont *tf)
935 {
936 flush_tbuf();
937 if (tf != current_tfont)
938 set_font(tf);
939 char c = ci->get_ascii_code();
940 if (c == '\0') {
941 do_motion();
942 if (ci->numbered()) {
943 put('N');
944 put(ci->get_number());
945 }
946 else {
947 put('C');
948 const char *s = ci->nm.contents();
949 if (s[1] == 0) {
950 put('\\');
951 put(s[0]);
952 }
953 else
954 put(s);
955 }
956 put('\n');
957 }
958 else {
959 int n = hpos - output_hpos;
960 if (vpos == output_vpos && n > 0 && n < 100) {
961 put(char(n/10 + '0'));
962 put(char(n%10 + '0'));
963 put(c);
964 output_hpos = hpos;
965 }
966 else {
967 do_motion();
968 put('c');
969 put(c);
970 }
971 }
972 }
973
set_font(tfont * tf)974 void troff_output_file::set_font(tfont *tf)
975 {
976 if (current_tfont == tf)
977 return;
978 int n = tf->get_input_position();
979 symbol nm = tf->get_name();
980 if (n >= nfont_positions || font_position[n] != nm) {
981 put("x font ");
982 put(n);
983 put(' ');
984 put(nm.contents());
985 put('\n');
986 if (n >= nfont_positions) {
987 int old_nfont_positions = nfont_positions;
988 symbol *old_font_position = font_position;
989 nfont_positions *= 3;
990 nfont_positions /= 2;
991 if (nfont_positions <= n)
992 nfont_positions = n + 10;
993 font_position = new symbol[nfont_positions];
994 memcpy(font_position, old_font_position,
995 old_nfont_positions*sizeof(symbol));
996 a_delete old_font_position;
997 }
998 font_position[n] = nm;
999 }
1000 if (current_font_number != n) {
1001 put('f');
1002 put(n);
1003 put('\n');
1004 current_font_number = n;
1005 }
1006 int size = tf->get_size().to_scaled_points();
1007 if (current_size != size) {
1008 put('s');
1009 put(size);
1010 put('\n');
1011 current_size = size;
1012 }
1013 int slant = tf->get_slant();
1014 if (current_slant != slant) {
1015 put("x Slant ");
1016 put(slant);
1017 put('\n');
1018 current_slant = slant;
1019 }
1020 int height = tf->get_height();
1021 if (current_height != height) {
1022 put("x Height ");
1023 put(height == 0 ? current_size : height);
1024 put('\n');
1025 current_height = height;
1026 }
1027 current_tfont = tf;
1028 }
1029
draw(char code,hvpair * point,int npoints,font_size fsize)1030 void troff_output_file::draw(char code, hvpair *point, int npoints,
1031 font_size fsize)
1032 {
1033 flush_tbuf();
1034 do_motion();
1035 int size = fsize.to_scaled_points();
1036 if (current_size != size) {
1037 put('s');
1038 put(size);
1039 put('\n');
1040 current_size = size;
1041 current_tfont = 0;
1042 }
1043 put('D');
1044 put(code);
1045 int i;
1046 if (code == 'c') {
1047 put(' ');
1048 put(point[0].h.to_units());
1049 }
1050 else
1051 for (i = 0; i < npoints; i++) {
1052 put(' ');
1053 put(point[i].h.to_units());
1054 put(' ');
1055 put(point[i].v.to_units());
1056 }
1057 for (i = 0; i < npoints; i++)
1058 output_hpos += point[i].h.to_units();
1059 hpos = output_hpos;
1060 if (code != 'e') {
1061 for (i = 0; i < npoints; i++)
1062 output_vpos += point[i].v.to_units();
1063 vpos = output_vpos;
1064 }
1065 put('\n');
1066 }
1067
really_begin_page(int pageno,vunits page_length)1068 void troff_output_file::really_begin_page(int pageno, vunits page_length)
1069 {
1070 flush_tbuf();
1071 if (begun_page) {
1072 if (page_length > V0) {
1073 put('V');
1074 put(page_length.to_units());
1075 put('\n');
1076 }
1077 }
1078 else
1079 begun_page = 1;
1080 current_tfont = 0;
1081 current_font_number = -1;
1082 current_size = 0;
1083 // current_height = 0;
1084 // current_slant = 0;
1085 hpos = 0;
1086 vpos = 0;
1087 output_hpos = 0;
1088 output_vpos = 0;
1089 force_motion = 1;
1090 for (int i = 0; i < nfont_positions; i++)
1091 font_position[i] = NULL_SYMBOL;
1092 put('p');
1093 put(pageno);
1094 put('\n');
1095 }
1096
really_copy_file(hunits x,vunits y,const char * filename)1097 void troff_output_file::really_copy_file(hunits x, vunits y, const char *filename)
1098 {
1099 moveto(x, y);
1100 flush_tbuf();
1101 do_motion();
1102 errno = 0;
1103 FILE *ifp = fopen(filename, "r");
1104 if (ifp == 0)
1105 error("can't open `%1': %2", filename, strerror(errno));
1106 else {
1107 int c;
1108 while ((c = getc(ifp)) != EOF)
1109 put(char(c));
1110 fclose(ifp);
1111 }
1112 force_motion = 1;
1113 current_size = 0;
1114 current_tfont = 0;
1115 current_font_number = -1;
1116 for (int i = 0; i < nfont_positions; i++)
1117 font_position[i] = NULL_SYMBOL;
1118 }
1119
really_transparent_char(unsigned char c)1120 void troff_output_file::really_transparent_char(unsigned char c)
1121 {
1122 put(c);
1123 }
1124
~troff_output_file()1125 troff_output_file::~troff_output_file()
1126 {
1127 a_delete font_position;
1128 }
1129
trailer(vunits page_length)1130 void troff_output_file::trailer(vunits page_length)
1131 {
1132 flush_tbuf();
1133 if (page_length > V0) {
1134 put("x trailer\n");
1135 put('V');
1136 put(page_length.to_units());
1137 put('\n');
1138 }
1139 put("x stop\n");
1140 }
1141
troff_output_file()1142 troff_output_file::troff_output_file()
1143 : current_height(0), current_slant(0), tbuf_len(0), nfont_positions(10),
1144 begun_page(0)
1145 {
1146 font_position = new symbol[nfont_positions];
1147 put("x T ");
1148 put(device);
1149 put('\n');
1150 put("x res ");
1151 put(units_per_inch);
1152 put(' ');
1153 put(hresolution);
1154 put(' ');
1155 put(vresolution);
1156 put('\n');
1157 put("x init\n");
1158 }
1159
1160 /* output_file */
1161
1162 output_file *the_output = 0;
1163
output_file()1164 output_file::output_file()
1165 {
1166 }
1167
~output_file()1168 output_file::~output_file()
1169 {
1170 }
1171
trailer(vunits)1172 void output_file::trailer(vunits)
1173 {
1174 }
1175
real_output_file()1176 real_output_file::real_output_file()
1177 : printing(0)
1178 {
1179 if (pipe_command) {
1180 if ((fp = popen(pipe_command, "w")) != 0) {
1181 piped = 1;
1182 return;
1183 }
1184 error("pipe open failed: %1", strerror(errno));
1185 }
1186 piped = 0;
1187 fp = stdout;
1188 }
1189
~real_output_file()1190 real_output_file::~real_output_file()
1191 {
1192 if (!fp)
1193 return;
1194 // To avoid looping, set fp to 0 before calling fatal().
1195 if (ferror(fp) || fflush(fp) < 0) {
1196 fp = 0;
1197 fatal("error writing output file");
1198 }
1199 if (piped) {
1200 int result = pclose(fp);
1201 fp = 0;
1202 if (result < 0)
1203 fatal("pclose failed");
1204 if ((result & 0x7f) != 0)
1205 error("output process `%1' got fatal signal %2",
1206 pipe_command, result & 0x7f);
1207 else {
1208 int exit_status = (result >> 8) & 0xff;
1209 if (exit_status != 0)
1210 error("output process `%1' exited with status %2",
1211 pipe_command, exit_status);
1212 }
1213 }
1214 else if (fclose(fp) < 0) {
1215 fp = 0;
1216 fatal("error closing output file");
1217 }
1218 }
1219
flush()1220 void real_output_file::flush()
1221 {
1222 if (fflush(fp) < 0)
1223 fatal("error writing output file");
1224 }
1225
is_printing()1226 int real_output_file::is_printing()
1227 {
1228 return printing;
1229 }
1230
begin_page(int pageno,vunits page_length)1231 void real_output_file::begin_page(int pageno, vunits page_length)
1232 {
1233 printing = in_output_page_list(pageno);
1234 if (printing)
1235 really_begin_page(pageno, page_length);
1236 }
1237
copy_file(hunits x,vunits y,const char * filename)1238 void real_output_file::copy_file(hunits x, vunits y, const char *filename)
1239 {
1240 if (printing)
1241 really_copy_file(x, y, filename);
1242 }
1243
transparent_char(unsigned char c)1244 void real_output_file::transparent_char(unsigned char c)
1245 {
1246 if (printing)
1247 really_transparent_char(c);
1248 }
1249
print_line(hunits x,vunits y,node * n,vunits before,vunits after)1250 void real_output_file::print_line(hunits x, vunits y, node *n,
1251 vunits before, vunits after)
1252 {
1253 if (printing)
1254 really_print_line(x, y, n, before, after);
1255 delete_node_list(n);
1256 }
1257
really_copy_file(hunits,vunits,const char *)1258 void real_output_file::really_copy_file(hunits, vunits, const char *)
1259 {
1260 // do nothing
1261 }
1262
1263
1264 /* ascii_output_file */
1265
really_transparent_char(unsigned char c)1266 void ascii_output_file::really_transparent_char(unsigned char c)
1267 {
1268 putc(c, fp);
1269 }
1270
really_print_line(hunits,vunits,node * n,vunits,vunits)1271 void ascii_output_file::really_print_line(hunits, vunits, node *n, vunits, vunits)
1272 {
1273 while (n != 0) {
1274 n->ascii_print(this);
1275 n = n->next;
1276 }
1277 fputc('\n', fp);
1278 }
1279
really_begin_page(int,vunits)1280 void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/)
1281 {
1282 fputs("<beginning of page>\n", fp);
1283 }
1284
ascii_output_file()1285 ascii_output_file::ascii_output_file()
1286 {
1287 }
1288
1289 /* suppress_output_file */
1290
suppress_output_file()1291 suppress_output_file::suppress_output_file()
1292 {
1293 }
1294
really_print_line(hunits,vunits,node *,vunits,vunits)1295 void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits)
1296 {
1297 }
1298
really_begin_page(int,vunits)1299 void suppress_output_file::really_begin_page(int, vunits)
1300 {
1301 }
1302
really_transparent_char(unsigned char)1303 void suppress_output_file::really_transparent_char(unsigned char)
1304 {
1305 }
1306
1307 /* glyphs, ligatures, kerns, discretionary breaks */
1308
1309 class glyph_node : public node {
1310 static glyph_node *free_list;
1311 protected:
1312 charinfo *ci;
1313 tfont *tf;
1314 #ifdef STORE_WIDTH
1315 hunits wid;
1316 glyph_node(charinfo *, tfont *, hunits, node * = 0);
1317 #endif
1318 public:
1319 void *operator new(size_t);
1320 void operator delete(void *);
1321 glyph_node(charinfo *, tfont *, node * = 0);
~glyph_node()1322 ~glyph_node() {}
1323 node *copy();
1324 node *merge_glyph_node(glyph_node *);
1325 node *merge_self(node *);
1326 hunits width();
1327 node *last_char_node();
1328 units size();
1329 void vertical_extent(vunits *, vunits *);
1330 hunits subscript_correction();
1331 hunits italic_correction();
1332 hunits left_italic_correction();
1333 hunits skew();
1334 hyphenation_type get_hyphenation_type();
1335 tfont *get_tfont();
1336 void tprint(troff_output_file *);
1337 void zero_width_tprint(troff_output_file *);
1338 hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
1339 node *add_self(node *, hyphen_list **);
1340 int ends_sentence();
1341 int overlaps_vertically();
1342 int overlaps_horizontally();
1343 void ascii_print(ascii_output_file *);
1344 void asciify(macro *);
1345 int character_type();
1346 int same(node *);
1347 const char *type();
1348 };
1349
1350 glyph_node *glyph_node::free_list = 0;
1351
1352 class ligature_node : public glyph_node {
1353 node *n1;
1354 node *n2;
1355 #ifdef STORE_WIDTH
1356 ligature_node(charinfo *, tfont *, hunits, node *gn1, node *gn2, node *x = 0);
1357 #endif
1358 public:
1359 void *operator new(size_t);
1360 void operator delete(void *);
1361 ligature_node(charinfo *, tfont *, node *gn1, node *gn2, node *x = 0);
1362 ~ligature_node();
1363 node *copy();
1364 node *add_self(node *, hyphen_list **);
1365 hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
1366 void ascii_print(ascii_output_file *);
1367 void asciify(macro *);
1368 int same(node *);
1369 const char *type();
1370 };
1371
1372 class kern_pair_node : public node {
1373 hunits amount;
1374 node *n1;
1375 node *n2;
1376 public:
1377 kern_pair_node(hunits n, node *first, node *second, node *x = 0);
1378 ~kern_pair_node();
1379 node *copy();
1380 node *merge_glyph_node(glyph_node *);
1381 node *add_self(node *, hyphen_list **);
1382 hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
1383 node *add_discretionary_hyphen();
1384 hunits width();
1385 node *last_char_node();
1386 hunits italic_correction();
1387 hunits subscript_correction();
1388 void tprint(troff_output_file *);
1389 hyphenation_type get_hyphenation_type();
1390 int ends_sentence();
1391 void ascii_print(ascii_output_file *);
1392 void asciify(macro *);
1393 int same(node *);
1394 const char *type();
1395 };
1396
1397 class dbreak_node : public node {
1398 node *none;
1399 node *pre;
1400 node *post;
1401 public:
1402 dbreak_node(node *n, node *p, node *x = 0);
1403 ~dbreak_node();
1404 node *copy();
1405 node *merge_glyph_node(glyph_node *);
1406 node *add_discretionary_hyphen();
1407 hunits width();
1408 node *last_char_node();
1409 hunits italic_correction();
1410 hunits subscript_correction();
1411 void tprint(troff_output_file *);
1412 breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0,
1413 int is_inner = 0);
1414 int nbreaks();
1415 int ends_sentence();
1416 void split(int, node **, node **);
1417 hyphenation_type get_hyphenation_type();
1418 void ascii_print(ascii_output_file *);
1419 void asciify(macro *);
1420 int same(node *);
1421 const char *type();
1422 };
1423
operator new(size_t n)1424 void *glyph_node::operator new(size_t n)
1425 {
1426 assert(n == sizeof(glyph_node));
1427 if (!free_list) {
1428 const int BLOCK = 1024;
1429 free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK];
1430 for (int i = 0; i < BLOCK - 1; i++)
1431 free_list[i].next = free_list + i + 1;
1432 free_list[BLOCK-1].next = 0;
1433 }
1434 glyph_node *p = free_list;
1435 free_list = (glyph_node *)(free_list->next);
1436 p->next = 0;
1437 return p;
1438 }
1439
operator new(size_t n)1440 void *ligature_node::operator new(size_t n)
1441 {
1442 return new char[n];
1443 }
1444
operator delete(void * p)1445 void glyph_node::operator delete(void *p)
1446 {
1447 if (p) {
1448 ((glyph_node *)p)->next = free_list;
1449 free_list = (glyph_node *)p;
1450 }
1451 }
1452
operator delete(void * p)1453 void ligature_node::operator delete(void *p)
1454 {
1455 delete p;
1456 }
1457
glyph_node(charinfo * c,tfont * t,node * x)1458 glyph_node::glyph_node(charinfo *c, tfont *t, node *x)
1459 : ci(c), tf(t), node(x)
1460 {
1461 #ifdef STORE_WIDTH
1462 wid = tf->get_width(ci);
1463 #endif
1464 }
1465
1466 #ifdef STORE_WIDTH
glyph_node(charinfo * c,tfont * t,hunits w,node * x)1467 glyph_node::glyph_node(charinfo *c, tfont *t, hunits w, node *x)
1468 : ci(c), tf(t), wid(w), node(x)
1469 {
1470 }
1471 #endif
1472
copy()1473 node *glyph_node::copy()
1474 {
1475 #ifdef STORE_WIDTH
1476 return new glyph_node(ci, tf, wid);
1477 #else
1478 return new glyph_node(ci, tf);
1479 #endif
1480 }
1481
merge_self(node * nd)1482 node *glyph_node::merge_self(node *nd)
1483 {
1484 return nd->merge_glyph_node(this);
1485 }
1486
character_type()1487 int glyph_node::character_type()
1488 {
1489 return tf->get_character_type(ci);
1490 }
1491
add_self(node * n,hyphen_list ** p)1492 node *glyph_node::add_self(node *n, hyphen_list **p)
1493 {
1494 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
1495 next = 0;
1496 node *nn;
1497 if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) {
1498 next = n;
1499 nn = this;
1500 }
1501 if ((*p)->hyphen)
1502 nn = nn->add_discretionary_hyphen();
1503 hyphen_list *pp = *p;
1504 *p = (*p)->next;
1505 delete pp;
1506 return nn;
1507 }
1508
overlaps_horizontally()1509 int glyph_node::overlaps_horizontally()
1510 {
1511 return ci->overlaps_horizontally();
1512 }
1513
overlaps_vertically()1514 int glyph_node::overlaps_vertically()
1515 {
1516 return ci->overlaps_vertically();
1517 }
1518
size()1519 units glyph_node::size()
1520 {
1521 return tf->get_size().to_units();
1522 }
1523
get_hyphen_list(hyphen_list * tail)1524 hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail)
1525 {
1526 return new hyphen_list(ci->get_hyphenation_code(), tail);
1527 }
1528
1529
get_tfont()1530 tfont *node::get_tfont()
1531 {
1532 return 0;
1533 }
1534
get_tfont()1535 tfont *glyph_node::get_tfont()
1536 {
1537 return tf;
1538 }
1539
merge_glyph_node(glyph_node *)1540 node *node::merge_glyph_node(glyph_node * /*gn*/)
1541 {
1542 return 0;
1543 }
1544
merge_glyph_node(glyph_node * gn)1545 node *glyph_node::merge_glyph_node(glyph_node *gn)
1546 {
1547 if (tf == gn->tf) {
1548 charinfo *lig;
1549 if ((lig = tf->get_lig(ci, gn->ci)) != 0) {
1550 node *next1 = next;
1551 next = 0;
1552 return new ligature_node(lig, tf, this, gn, next1);
1553 }
1554 hunits kern;
1555 if (tf->get_kern(ci, gn->ci, &kern)) {
1556 node *next1 = next;
1557 next = 0;
1558 return new kern_pair_node(kern, this, gn, next1);
1559 }
1560 }
1561 return 0;
1562 }
1563
1564 #ifdef STORE_WIDTH
1565 inline
1566 #endif
width()1567 hunits glyph_node::width()
1568 {
1569 #ifdef STORE_WIDTH
1570 return wid;
1571 #else
1572 return tf->get_width(ci);
1573 #endif
1574 }
1575
last_char_node()1576 node *glyph_node::last_char_node()
1577 {
1578 return this;
1579 }
1580
vertical_extent(vunits * min,vunits * max)1581 void glyph_node::vertical_extent(vunits *min, vunits *max)
1582 {
1583 *min = -tf->get_char_height(ci);
1584 *max = tf->get_char_depth(ci);
1585 }
1586
skew()1587 hunits glyph_node::skew()
1588 {
1589 return tf->get_char_skew(ci);
1590 }
1591
subscript_correction()1592 hunits glyph_node::subscript_correction()
1593 {
1594 return tf->get_subscript_correction(ci);
1595 }
1596
italic_correction()1597 hunits glyph_node::italic_correction()
1598 {
1599 return tf->get_italic_correction(ci);
1600 }
1601
left_italic_correction()1602 hunits glyph_node::left_italic_correction()
1603 {
1604 return tf->get_left_italic_correction(ci);
1605 }
1606
get_hyphenation_type()1607 hyphenation_type glyph_node::get_hyphenation_type()
1608 {
1609 return HYPHEN_MIDDLE;
1610 }
1611
ends_sentence()1612 int glyph_node::ends_sentence()
1613 {
1614 if (ci->ends_sentence())
1615 return 1;
1616 else if (ci->transparent())
1617 return 2;
1618 else
1619 return 0;
1620 }
1621
ascii_print(ascii_output_file * ascii)1622 void glyph_node::ascii_print(ascii_output_file *ascii)
1623 {
1624 unsigned char c = ci->get_ascii_code();
1625 if (c != 0)
1626 ascii->outc(c);
1627 else
1628 ascii->outs(ci->nm.contents());
1629 }
1630
ligature_node(charinfo * c,tfont * t,node * gn1,node * gn2,node * x)1631 ligature_node::ligature_node(charinfo *c, tfont *t,
1632 node *gn1, node *gn2, node *x)
1633 : glyph_node(c, t, x), n1(gn1), n2(gn2)
1634 {
1635 }
1636
1637 #ifdef STORE_WIDTH
ligature_node(charinfo * c,tfont * t,hunits w,node * gn1,node * gn2,node * x)1638 ligature_node::ligature_node(charinfo *c, tfont *t, hunits w,
1639 node *gn1, node *gn2, node *x)
1640 : glyph_node(c, t, w, x), n1(gn1), n2(gn2)
1641 {
1642 }
1643 #endif
1644
~ligature_node()1645 ligature_node::~ligature_node()
1646 {
1647 delete n1;
1648 delete n2;
1649 }
1650
copy()1651 node *ligature_node::copy()
1652 {
1653 #ifdef STORE_WIDTH
1654 return new ligature_node(ci, tf, wid, n1->copy(), n2->copy());
1655 #else
1656 return new ligature_node(ci, tf, n1->copy(), n2->copy());
1657 #endif
1658 }
1659
ascii_print(ascii_output_file * ascii)1660 void ligature_node::ascii_print(ascii_output_file *ascii)
1661 {
1662 n1->ascii_print(ascii);
1663 n2->ascii_print(ascii);
1664 }
1665
get_hyphen_list(hyphen_list * tail)1666 hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail)
1667 {
1668 return n1->get_hyphen_list(n2->get_hyphen_list(tail));
1669 }
1670
add_self(node * n,hyphen_list ** p)1671 node *ligature_node::add_self(node *n, hyphen_list **p)
1672 {
1673 n = n1->add_self(n, p);
1674 n = n2->add_self(n, p);
1675 n1 = n2 = 0;
1676 delete this;
1677 return n;
1678 }
1679
kern_pair_node(hunits n,node * first,node * second,node * x)1680 kern_pair_node::kern_pair_node(hunits n, node *first, node *second, node *x)
1681 : node(x), n1(first), n2(second), amount(n)
1682 {
1683 }
1684
dbreak_node(node * n,node * p,node * x)1685 dbreak_node::dbreak_node(node *n, node *p, node *x)
1686 : node(x), none(n), pre(p), post(0)
1687 {
1688 }
1689
merge_glyph_node(glyph_node * gn)1690 node *dbreak_node::merge_glyph_node(glyph_node *gn)
1691 {
1692 glyph_node *gn2 = (glyph_node *)gn->copy();
1693 node *new_none = none ? none->merge_glyph_node(gn) : 0;
1694 node *new_post = post ? post->merge_glyph_node(gn2) : 0;
1695 if (new_none == 0 && new_post == 0) {
1696 delete gn2;
1697 return 0;
1698 }
1699 if (new_none != 0)
1700 none = new_none;
1701 else {
1702 gn->next = none;
1703 none = gn;
1704 }
1705 if (new_post != 0)
1706 post = new_post;
1707 else {
1708 gn2->next = post;
1709 post = gn2;
1710 }
1711 return this;
1712 }
1713
merge_glyph_node(glyph_node * gn)1714 node *kern_pair_node::merge_glyph_node(glyph_node *gn)
1715 {
1716 node *nd = n2->merge_glyph_node(gn);
1717 if (nd == 0)
1718 return 0;
1719 n2 = nd;
1720 nd = n2->merge_self(n1);
1721 if (nd) {
1722 nd->next = next;
1723 n1 = 0;
1724 n2 = 0;
1725 delete this;
1726 return nd;
1727 }
1728 return this;
1729 }
1730
1731
italic_correction()1732 hunits kern_pair_node::italic_correction()
1733 {
1734 return n2->italic_correction();
1735 }
1736
subscript_correction()1737 hunits kern_pair_node::subscript_correction()
1738 {
1739 return n2->subscript_correction();
1740 }
1741
add_discretionary_hyphen()1742 node *kern_pair_node::add_discretionary_hyphen()
1743 {
1744 tfont *tf = n2->get_tfont();
1745 if (tf) {
1746 if (tf->contains(soft_hyphen_char)) {
1747 node *next1 = next;
1748 next = 0;
1749 node *n = copy();
1750 glyph_node *gn = new glyph_node(soft_hyphen_char, tf);
1751 node *nn = n->merge_glyph_node(gn);
1752 if (nn == 0) {
1753 gn->next = n;
1754 nn = gn;
1755 }
1756 return new dbreak_node(this, nn, next1);
1757 }
1758 }
1759 return this;
1760 }
1761
1762
~kern_pair_node()1763 kern_pair_node::~kern_pair_node()
1764 {
1765 if (n1 != 0)
1766 delete n1;
1767 if (n2 != 0)
1768 delete n2;
1769 }
1770
~dbreak_node()1771 dbreak_node::~dbreak_node()
1772 {
1773 delete_node_list(pre);
1774 delete_node_list(post);
1775 delete_node_list(none);
1776 }
1777
copy()1778 node *kern_pair_node::copy()
1779 {
1780 return new kern_pair_node(amount, n1->copy(), n2->copy());
1781 }
1782
copy_node_list(node * n)1783 node *copy_node_list(node *n)
1784 {
1785 node *p = 0;
1786 while (n != 0) {
1787 node *nn = n->copy();
1788 nn->next = p;
1789 p = nn;
1790 n = n->next;
1791 }
1792 while (p != 0) {
1793 node *pp = p->next;
1794 p->next = n;
1795 n = p;
1796 p = pp;
1797 }
1798 return n;
1799 }
1800
delete_node_list(node * n)1801 void delete_node_list(node *n)
1802 {
1803 while (n != 0) {
1804 node *tem = n;
1805 n = n->next;
1806 delete tem;
1807 }
1808 }
1809
copy()1810 node *dbreak_node::copy()
1811 {
1812 dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre));
1813 p->post = copy_node_list(post);
1814 return p;
1815 }
1816
get_hyphen_list(hyphen_list * tail)1817 hyphen_list *node::get_hyphen_list(hyphen_list *tail)
1818 {
1819 return tail;
1820 }
1821
1822
get_hyphen_list(hyphen_list * tail)1823 hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail)
1824 {
1825 return n1->get_hyphen_list(n2->get_hyphen_list(tail));
1826 }
1827
1828 class hyphen_inhibitor_node : public node {
1829 public:
1830 hyphen_inhibitor_node(node *nd = 0);
1831 node *copy();
1832 int same(node *);
1833 const char *type();
1834 hyphenation_type get_hyphenation_type();
1835 };
1836
hyphen_inhibitor_node(node * nd)1837 hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd)
1838 {
1839 }
1840
copy()1841 node *hyphen_inhibitor_node::copy()
1842 {
1843 return new hyphen_inhibitor_node;
1844 }
1845
same(node *)1846 int hyphen_inhibitor_node::same(node *)
1847 {
1848 return 1;
1849 }
1850
type()1851 const char *hyphen_inhibitor_node::type()
1852 {
1853 return "hyphen_inhibitor_node";
1854 }
1855
get_hyphenation_type()1856 hyphenation_type hyphen_inhibitor_node::get_hyphenation_type()
1857 {
1858 return HYPHEN_INHIBIT;
1859 }
1860
1861 /* add_discretionary_hyphen methods */
1862
add_discretionary_hyphen()1863 node *dbreak_node::add_discretionary_hyphen()
1864 {
1865 if (post)
1866 post = post->add_discretionary_hyphen();
1867 if (none)
1868 none = none->add_discretionary_hyphen();
1869 return this;
1870 }
1871
1872
add_discretionary_hyphen()1873 node *node::add_discretionary_hyphen()
1874 {
1875 tfont *tf = get_tfont();
1876 if (!tf)
1877 return new hyphen_inhibitor_node(this);
1878 if (tf->contains(soft_hyphen_char)) {
1879 node *next1 = next;
1880 next = 0;
1881 node *n = copy();
1882 glyph_node *gn = new glyph_node(soft_hyphen_char, tf);
1883 node *n1 = n->merge_glyph_node(gn);
1884 if (n1 == 0) {
1885 gn->next = n;
1886 n1 = gn;
1887 }
1888 return new dbreak_node(this, n1, next1);
1889 }
1890 return this;
1891 }
1892
1893
merge_self(node *)1894 node *node::merge_self(node *)
1895 {
1896 return 0;
1897 }
1898
add_self(node * n,hyphen_list **)1899 node *node::add_self(node *n, hyphen_list ** /*p*/)
1900 {
1901 next = n;
1902 return this;
1903 }
1904
add_self(node * n,hyphen_list ** p)1905 node *kern_pair_node::add_self(node *n, hyphen_list **p)
1906 {
1907 n = n1->add_self(n, p);
1908 n = n2->add_self(n, p);
1909 n1 = n2 = 0;
1910 delete this;
1911 return n;
1912 }
1913
1914
width()1915 hunits node::width()
1916 {
1917 return H0;
1918 }
1919
last_char_node()1920 node *node::last_char_node()
1921 {
1922 return 0;
1923 }
1924
width()1925 hunits hmotion_node::width()
1926 {
1927 return n;
1928 }
1929
size()1930 units node::size()
1931 {
1932 return points_to_units(10);
1933 }
1934
width()1935 hunits kern_pair_node::width()
1936 {
1937 return n1->width() + n2->width() + amount;
1938 }
1939
last_char_node()1940 node *kern_pair_node::last_char_node()
1941 {
1942 node *nd = n2->last_char_node();
1943 if (nd)
1944 return nd;
1945 return n1->last_char_node();
1946 }
1947
width()1948 hunits dbreak_node::width()
1949 {
1950 hunits x = H0;
1951 for (node *n = none; n != 0; n = n->next)
1952 x += n->width();
1953 return x;
1954 }
1955
last_char_node()1956 node *dbreak_node::last_char_node()
1957 {
1958 for (node *n = none; n; n = n->next) {
1959 node *last = n->last_char_node();
1960 if (last)
1961 return last;
1962 }
1963 return 0;
1964 }
1965
italic_correction()1966 hunits dbreak_node::italic_correction()
1967 {
1968 return none ? none->italic_correction() : H0;
1969 }
1970
subscript_correction()1971 hunits dbreak_node::subscript_correction()
1972 {
1973 return none ? none->subscript_correction() : H0;
1974 }
1975
1976 class italic_corrected_node : public node {
1977 node *n;
1978 hunits x;
1979 public:
1980 italic_corrected_node(node *, hunits, node * = 0);
1981 ~italic_corrected_node();
1982 node *copy();
1983 void ascii_print(ascii_output_file *);
1984 void asciify(macro *m);
1985 hunits width();
1986 node *last_char_node();
1987 void vertical_extent(vunits *, vunits *);
1988 int ends_sentence();
1989 int overlaps_horizontally();
1990 int overlaps_vertically();
1991 int same(node *);
1992 hyphenation_type get_hyphenation_type();
1993 tfont *get_tfont();
1994 hyphen_list *get_hyphen_list(hyphen_list *ss = 0);
1995 int character_type();
1996 void tprint(troff_output_file *);
1997 hunits subscript_correction();
1998 hunits skew();
1999 node *add_self(node *, hyphen_list **);
2000 const char *type();
2001 };
2002
add_italic_correction(hunits * width)2003 node *node::add_italic_correction(hunits *width)
2004 {
2005 hunits ic = italic_correction();
2006 if (ic.is_zero())
2007 return this;
2008 else {
2009 node *next1 = next;
2010 next = 0;
2011 *width += ic;
2012 return new italic_corrected_node(this, ic, next1);
2013 }
2014 }
2015
italic_corrected_node(node * nn,hunits xx,node * p)2016 italic_corrected_node::italic_corrected_node(node *nn, hunits xx, node *p)
2017 : n(nn), x(xx), node(p)
2018 {
2019 assert(n != 0);
2020 }
2021
~italic_corrected_node()2022 italic_corrected_node::~italic_corrected_node()
2023 {
2024 delete n;
2025 }
2026
copy()2027 node *italic_corrected_node::copy()
2028 {
2029 return new italic_corrected_node(n->copy(), x);
2030 }
2031
width()2032 hunits italic_corrected_node::width()
2033 {
2034 return n->width() + x;
2035 }
2036
vertical_extent(vunits * min,vunits * max)2037 void italic_corrected_node::vertical_extent(vunits *min, vunits *max)
2038 {
2039 n->vertical_extent(min, max);
2040 }
2041
tprint(troff_output_file * out)2042 void italic_corrected_node::tprint(troff_output_file *out)
2043 {
2044 n->tprint(out);
2045 out->right(x);
2046 }
2047
skew()2048 hunits italic_corrected_node::skew()
2049 {
2050 return n->skew() - x/2;
2051 }
2052
subscript_correction()2053 hunits italic_corrected_node::subscript_correction()
2054 {
2055 return n->subscript_correction() - x;
2056 }
2057
ascii_print(ascii_output_file * out)2058 void italic_corrected_node::ascii_print(ascii_output_file *out)
2059 {
2060 n->ascii_print(out);
2061 }
2062
ends_sentence()2063 int italic_corrected_node::ends_sentence()
2064 {
2065 return n->ends_sentence();
2066 }
2067
overlaps_horizontally()2068 int italic_corrected_node::overlaps_horizontally()
2069 {
2070 return n->overlaps_horizontally();
2071 }
2072
overlaps_vertically()2073 int italic_corrected_node::overlaps_vertically()
2074 {
2075 return n->overlaps_vertically();
2076 }
2077
last_char_node()2078 node *italic_corrected_node::last_char_node()
2079 {
2080 return n->last_char_node();
2081 }
2082
get_tfont()2083 tfont *italic_corrected_node::get_tfont()
2084 {
2085 return n->get_tfont();
2086 }
2087
get_hyphenation_type()2088 hyphenation_type italic_corrected_node::get_hyphenation_type()
2089 {
2090 return n->get_hyphenation_type();
2091 }
2092
add_self(node * nd,hyphen_list ** p)2093 node *italic_corrected_node::add_self(node *nd, hyphen_list **p)
2094 {
2095 nd = n->add_self(nd, p);
2096 hunits not_interested;
2097 nd = nd->add_italic_correction(¬_interested);
2098 n = 0;
2099 delete this;
2100 return nd;
2101 }
2102
get_hyphen_list(hyphen_list * tail)2103 hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail)
2104 {
2105 return n->get_hyphen_list(tail);
2106 }
2107
character_type()2108 int italic_corrected_node::character_type()
2109 {
2110 return n->character_type();
2111 }
2112
2113 class break_char_node : public node {
2114 node *ch;
2115 char break_code;
2116 public:
2117 break_char_node(node *, int, node * = 0);
2118 ~break_char_node();
2119 node *copy();
2120 hunits width();
2121 vunits vertical_width();
2122 node *last_char_node();
2123 int character_type();
2124 int ends_sentence();
2125 node *add_self(node *, hyphen_list **);
2126 hyphen_list *get_hyphen_list(hyphen_list *s = 0);
2127 void tprint(troff_output_file *);
2128 void zero_width_tprint(troff_output_file *);
2129 void ascii_print(ascii_output_file *);
2130 void asciify(macro *m);
2131 hyphenation_type get_hyphenation_type();
2132 int overlaps_vertically();
2133 int overlaps_horizontally();
2134 units size();
2135 tfont *get_tfont();
2136 int same(node *);
2137 const char *type();
2138 };
2139
break_char_node(node * n,int c,node * x)2140 break_char_node::break_char_node(node *n, int c, node *x)
2141 : node(x), ch(n), break_code(c)
2142 {
2143 }
2144
~break_char_node()2145 break_char_node::~break_char_node()
2146 {
2147 delete ch;
2148 }
2149
copy()2150 node *break_char_node::copy()
2151 {
2152 return new break_char_node(ch->copy(), break_code);
2153 }
2154
width()2155 hunits break_char_node::width()
2156 {
2157 return ch->width();
2158 }
2159
vertical_width()2160 vunits break_char_node::vertical_width()
2161 {
2162 return ch->vertical_width();
2163 }
2164
last_char_node()2165 node *break_char_node::last_char_node()
2166 {
2167 return ch->last_char_node();
2168 }
2169
character_type()2170 int break_char_node::character_type()
2171 {
2172 return ch->character_type();
2173 }
2174
ends_sentence()2175 int break_char_node::ends_sentence()
2176 {
2177 return ch->ends_sentence();
2178 }
2179
add_self(node * n,hyphen_list ** p)2180 node *break_char_node::add_self(node *n, hyphen_list **p)
2181 {
2182 assert((*p)->hyphenation_code == 0);
2183 if ((*p)->breakable && (break_code & 1)) {
2184 n = new space_node(H0, n);
2185 n->freeze_space();
2186 }
2187 next = n;
2188 n = this;
2189 if ((*p)->breakable && (break_code & 2)) {
2190 n = new space_node(H0, n);
2191 n->freeze_space();
2192 }
2193 hyphen_list *pp = *p;
2194 *p = (*p)->next;
2195 delete pp;
2196 return n;
2197 }
2198
get_hyphen_list(hyphen_list * tail)2199 hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail)
2200 {
2201 return new hyphen_list(0, tail);
2202 }
2203
get_hyphenation_type()2204 hyphenation_type break_char_node::get_hyphenation_type()
2205 {
2206 return HYPHEN_MIDDLE;
2207 }
2208
ascii_print(ascii_output_file * ascii)2209 void break_char_node::ascii_print(ascii_output_file *ascii)
2210 {
2211 ch->ascii_print(ascii);
2212 }
2213
overlaps_vertically()2214 int break_char_node::overlaps_vertically()
2215 {
2216 return ch->overlaps_vertically();
2217 }
2218
overlaps_horizontally()2219 int break_char_node::overlaps_horizontally()
2220 {
2221 return ch->overlaps_horizontally();
2222 }
2223
size()2224 units break_char_node::size()
2225 {
2226 return ch->size();
2227 }
2228
get_tfont()2229 tfont *break_char_node::get_tfont()
2230 {
2231 return ch->get_tfont();
2232 }
2233
copy()2234 node *extra_size_node::copy()
2235 {
2236 return new extra_size_node(n);
2237 }
2238
copy()2239 node *vertical_size_node::copy()
2240 {
2241 return new vertical_size_node(n);
2242 }
2243
copy()2244 node *hmotion_node::copy()
2245 {
2246 return new hmotion_node(n);
2247 }
2248
copy()2249 node *space_char_hmotion_node::copy()
2250 {
2251 return new space_char_hmotion_node(n);
2252 }
2253
copy()2254 node *vmotion_node::copy()
2255 {
2256 return new vmotion_node(n);
2257 }
2258
copy()2259 node *dummy_node::copy()
2260 {
2261 return new dummy_node;
2262 }
2263
copy()2264 node *transparent_dummy_node::copy()
2265 {
2266 return new transparent_dummy_node;
2267 }
2268
~hline_node()2269 hline_node::~hline_node()
2270 {
2271 if (n)
2272 delete n;
2273 }
2274
copy()2275 node *hline_node::copy()
2276 {
2277 return new hline_node(x, n ? n->copy() : 0);
2278 }
2279
width()2280 hunits hline_node::width()
2281 {
2282 return x < H0 ? H0 : x;
2283 }
2284
2285
~vline_node()2286 vline_node::~vline_node()
2287 {
2288 if (n)
2289 delete n;
2290 }
2291
copy()2292 node *vline_node::copy()
2293 {
2294 return new vline_node(x, n ? n->copy() : 0);
2295 }
2296
width()2297 hunits vline_node::width()
2298 {
2299 return n == 0 ? H0 : n->width();
2300 }
2301
2302
zero_width_node(node * nd)2303 zero_width_node::zero_width_node(node *nd) : n(nd)
2304 {
2305 }
2306
~zero_width_node()2307 zero_width_node::~zero_width_node()
2308 {
2309 delete_node_list(n);
2310 }
2311
copy()2312 node *zero_width_node::copy()
2313 {
2314 return new zero_width_node(copy_node_list(n));
2315 }
2316
node_list_character_type(node * p)2317 int node_list_character_type(node *p)
2318 {
2319 int t = 0;
2320 for (; p; p = p->next)
2321 t |= p->character_type();
2322 return t;
2323 }
2324
character_type()2325 int zero_width_node::character_type()
2326 {
2327 return node_list_character_type(n);
2328 }
2329
node_list_vertical_extent(node * p,vunits * min,vunits * max)2330 void node_list_vertical_extent(node *p, vunits *min, vunits *max)
2331 {
2332 *min = V0;
2333 *max = V0;
2334 vunits cur_vpos = V0;
2335 vunits v1, v2;
2336 for (; p; p = p->next) {
2337 p->vertical_extent(&v1, &v2);
2338 v1 += cur_vpos;
2339 if (v1 < *min)
2340 *min = v1;
2341 v2 += cur_vpos;
2342 if (v2 > *max)
2343 *max = v2;
2344 cur_vpos += p->vertical_width();
2345 }
2346 }
2347
vertical_extent(vunits * min,vunits * max)2348 void zero_width_node::vertical_extent(vunits *min, vunits *max)
2349 {
2350 node_list_vertical_extent(n, min, max);
2351 }
2352
overstrike_node()2353 overstrike_node::overstrike_node() : max_width(H0), list(0)
2354 {
2355 }
2356
~overstrike_node()2357 overstrike_node::~overstrike_node()
2358 {
2359 delete_node_list(list);
2360 }
2361
copy()2362 node *overstrike_node::copy()
2363 {
2364 overstrike_node *on = new overstrike_node;
2365 for (node *tem = list; tem; tem = tem->next)
2366 on->overstrike(tem->copy());
2367 return on;
2368 }
2369
overstrike(node * n)2370 void overstrike_node::overstrike(node *n)
2371 {
2372 if (n == 0)
2373 return;
2374 hunits w = n->width();
2375 if (w > max_width)
2376 max_width = w;
2377 for (node **p = &list; *p; p = &(*p)->next)
2378 ;
2379 n->next = 0;
2380 *p = n;
2381 }
2382
width()2383 hunits overstrike_node::width()
2384 {
2385 return max_width;
2386 }
2387
bracket_node()2388 bracket_node::bracket_node() : max_width(H0), list(0)
2389 {
2390 }
2391
~bracket_node()2392 bracket_node::~bracket_node()
2393 {
2394 delete_node_list(list);
2395 }
2396
copy()2397 node *bracket_node::copy()
2398 {
2399 bracket_node *on = new bracket_node;
2400 for (node *tem = list; tem; tem = tem->next)
2401 on->bracket(tem->copy());
2402 return on;
2403 }
2404
2405
bracket(node * n)2406 void bracket_node::bracket(node *n)
2407 {
2408 if (n == 0)
2409 return;
2410 hunits w = n->width();
2411 if (w > max_width)
2412 max_width = w;
2413 n->next = list;
2414 list = n;
2415 }
2416
width()2417 hunits bracket_node::width()
2418 {
2419 return max_width;
2420 }
2421
nspaces()2422 int node::nspaces()
2423 {
2424 return 0;
2425 }
2426
merge_space(hunits)2427 int node::merge_space(hunits)
2428 {
2429 return 0;
2430 }
2431
2432 #if 0
2433 space_node *space_node::free_list = 0;
2434
2435 void *space_node::operator new(size_t n)
2436 {
2437 assert(n == sizeof(space_node));
2438 if (!free_list) {
2439 free_list = (space_node *)new char[sizeof(space_node)*BLOCK];
2440 for (int i = 0; i < BLOCK - 1; i++)
2441 free_list[i].next = free_list + i + 1;
2442 free_list[BLOCK-1].next = 0;
2443 }
2444 space_node *p = free_list;
2445 free_list = (space_node *)(free_list->next);
2446 p->next = 0;
2447 return p;
2448 }
2449
2450 inline void space_node::operator delete(void *p)
2451 {
2452 if (p) {
2453 ((space_node *)p)->next = free_list;
2454 free_list = (space_node *)p;
2455 }
2456 }
2457 #endif
2458
space_node(hunits nn,node * p)2459 space_node::space_node(hunits nn, node *p) : node(p), n(nn), set(0)
2460 {
2461 }
2462
space_node(hunits nn,int s,node * p)2463 space_node::space_node(hunits nn, int s, node *p) : node(p), n(nn), set(s)
2464 {
2465 }
2466
2467 #if 0
2468 space_node::~space_node()
2469 {
2470 }
2471 #endif
2472
copy()2473 node *space_node::copy()
2474 {
2475 return new space_node(n, set);
2476 }
2477
nspaces()2478 int space_node::nspaces()
2479 {
2480 return set ? 0 : 1;
2481 }
2482
merge_space(hunits h)2483 int space_node::merge_space(hunits h)
2484 {
2485 n += h;
2486 return 1;
2487 }
2488
width()2489 hunits space_node::width()
2490 {
2491 return n;
2492 }
2493
spread_space(int *,hunits *)2494 void node::spread_space(int*, hunits*)
2495 {
2496 }
2497
spread_space(int * nspaces,hunits * desired_space)2498 void space_node::spread_space(int *nspaces, hunits *desired_space)
2499 {
2500 if (!set) {
2501 assert(*nspaces > 0);
2502 if (*nspaces == 1) {
2503 n += *desired_space;
2504 *desired_space = H0;
2505 }
2506 else {
2507 hunits extra = *desired_space / *nspaces;
2508 *desired_space -= extra;
2509 n += extra;
2510 }
2511 *nspaces -= 1;
2512 set = 1;
2513 }
2514 }
2515
freeze_space()2516 void node::freeze_space()
2517 {
2518 }
2519
freeze_space()2520 void space_node::freeze_space()
2521 {
2522 set = 1;
2523 }
2524
diverted_space_node(vunits d,node * p)2525 diverted_space_node::diverted_space_node(vunits d, node *p)
2526 : node(p), n(d)
2527 {
2528 }
2529
copy()2530 node *diverted_space_node::copy()
2531 {
2532 return new diverted_space_node(n);
2533 }
2534
diverted_copy_file_node(symbol s,node * p)2535 diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p)
2536 : node(p), filename(s)
2537 {
2538 }
2539
copy()2540 node *diverted_copy_file_node::copy()
2541 {
2542 return new diverted_copy_file_node(filename);
2543 }
2544
ends_sentence()2545 int node::ends_sentence()
2546 {
2547 return 0;
2548 }
2549
ends_sentence()2550 int kern_pair_node::ends_sentence()
2551 {
2552 switch (n2->ends_sentence()) {
2553 case 0:
2554 return 0;
2555 case 1:
2556 return 1;
2557 case 2:
2558 break;
2559 default:
2560 assert(0);
2561 }
2562 return n1->ends_sentence();
2563 }
2564
node_list_ends_sentence(node * n)2565 int node_list_ends_sentence(node *n)
2566 {
2567 for (; n != 0; n = n->next)
2568 switch (n->ends_sentence()) {
2569 case 0:
2570 return 0;
2571 case 1:
2572 return 1;
2573 case 2:
2574 break;
2575 default:
2576 assert(0);
2577 }
2578 return 2;
2579 }
2580
2581
ends_sentence()2582 int dbreak_node::ends_sentence()
2583 {
2584 return node_list_ends_sentence(none);
2585 }
2586
2587
overlaps_horizontally()2588 int node::overlaps_horizontally()
2589 {
2590 return 0;
2591 }
2592
overlaps_vertically()2593 int node::overlaps_vertically()
2594 {
2595 return 0;
2596 }
2597
discardable()2598 int node::discardable()
2599 {
2600 return 0;
2601 }
2602
discardable()2603 int space_node::discardable()
2604 {
2605 return set ? 0 : 1;
2606 }
2607
2608
vertical_width()2609 vunits node::vertical_width()
2610 {
2611 return V0;
2612 }
2613
vertical_width()2614 vunits vline_node::vertical_width()
2615 {
2616 return x;
2617 }
2618
vertical_width()2619 vunits vmotion_node::vertical_width()
2620 {
2621 return n;
2622 }
2623
character_type()2624 int node::character_type()
2625 {
2626 return 0;
2627 }
2628
subscript_correction()2629 hunits node::subscript_correction()
2630 {
2631 return H0;
2632 }
2633
italic_correction()2634 hunits node::italic_correction()
2635 {
2636 return H0;
2637 }
2638
left_italic_correction()2639 hunits node::left_italic_correction()
2640 {
2641 return H0;
2642 }
2643
skew()2644 hunits node::skew()
2645 {
2646 return H0;
2647 }
2648
2649
2650 /* vertical_extent methods */
2651
vertical_extent(vunits * min,vunits * max)2652 void node::vertical_extent(vunits *min, vunits *max)
2653 {
2654 vunits v = vertical_width();
2655 if (v < V0) {
2656 *min = v;
2657 *max = V0;
2658 }
2659 else {
2660 *max = v;
2661 *min = V0;
2662 }
2663 }
2664
vertical_extent(vunits * min,vunits * max)2665 void vline_node::vertical_extent(vunits *min, vunits *max)
2666 {
2667 if (n == 0)
2668 node::vertical_extent(min, max);
2669 else {
2670 vunits cmin, cmax;
2671 n->vertical_extent(&cmin, &cmax);
2672 vunits h = n->size();
2673 if (x < V0) {
2674 if (-x < h) {
2675 *min = x;
2676 *max = V0;
2677 }
2678 else {
2679 // we print the first character and then move up, so
2680 *max = cmax;
2681 // we print the last character and then move up h
2682 *min = cmin + h;
2683 if (*min > V0)
2684 *min = V0;
2685 *min += x;
2686 }
2687 }
2688 else {
2689 if (x < h) {
2690 *max = x;
2691 *min = V0;
2692 }
2693 else {
2694 // we move down by h and then print the first character, so
2695 *min = cmin + h;
2696 if (*min > V0)
2697 *min = V0;
2698 *max = x + cmax;
2699 }
2700 }
2701 }
2702 }
2703
2704 /* ascii_print methods */
2705
2706
ascii_print_reverse_node_list(ascii_output_file * ascii,node * n)2707 static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n)
2708 {
2709 if (n == 0)
2710 return;
2711 ascii_print_reverse_node_list(ascii, n->next);
2712 n->ascii_print(ascii);
2713 }
2714
ascii_print(ascii_output_file * ascii)2715 void dbreak_node::ascii_print(ascii_output_file *ascii)
2716 {
2717 ascii_print_reverse_node_list(ascii, none);
2718 }
2719
ascii_print(ascii_output_file * ascii)2720 void kern_pair_node::ascii_print(ascii_output_file *ascii)
2721 {
2722 n1->ascii_print(ascii);
2723 n2->ascii_print(ascii);
2724 }
2725
2726
ascii_print(ascii_output_file *)2727 void node::ascii_print(ascii_output_file *)
2728 {
2729 }
2730
ascii_print(ascii_output_file * ascii)2731 void space_node::ascii_print(ascii_output_file *ascii)
2732 {
2733 if (!n.is_zero())
2734 ascii->outc(' ');
2735 }
2736
ascii_print(ascii_output_file * ascii)2737 void hmotion_node::ascii_print(ascii_output_file *ascii)
2738 {
2739 // this is pretty arbitrary
2740 if (n >= points_to_units(2))
2741 ascii->outc(' ');
2742 }
2743
ascii_print(ascii_output_file * ascii)2744 void space_char_hmotion_node::ascii_print(ascii_output_file *ascii)
2745 {
2746 ascii->outc(' ');
2747 }
2748
2749 /* asciify methods */
2750
asciify(macro * m)2751 void node::asciify(macro *m)
2752 {
2753 m->append(this);
2754 }
2755
asciify(macro * m)2756 void glyph_node::asciify(macro *m)
2757 {
2758 unsigned char c = ci->get_ascii_code();
2759 if (c != 0) {
2760 m->append(c);
2761 delete this;
2762 }
2763 else
2764 m->append(this);
2765 }
2766
asciify(macro * m)2767 void kern_pair_node::asciify(macro *m)
2768 {
2769 n1->asciify(m);
2770 n2->asciify(m);
2771 n1 = n2 = 0;
2772 delete this;
2773 }
2774
asciify_reverse_node_list(macro * m,node * n)2775 static void asciify_reverse_node_list(macro *m, node *n)
2776 {
2777 if (n == 0)
2778 return;
2779 asciify_reverse_node_list(m, n->next);
2780 n->asciify(m);
2781 }
2782
asciify(macro * m)2783 void dbreak_node::asciify(macro *m)
2784 {
2785 asciify_reverse_node_list(m, none);
2786 none = 0;
2787 delete this;
2788 }
2789
asciify(macro * m)2790 void ligature_node::asciify(macro *m)
2791 {
2792 n1->asciify(m);
2793 n2->asciify(m);
2794 n1 = n2 = 0;
2795 delete this;
2796 }
2797
asciify(macro * m)2798 void break_char_node::asciify(macro *m)
2799 {
2800 ch->asciify(m);
2801 ch = 0;
2802 delete this;
2803 }
2804
asciify(macro * m)2805 void italic_corrected_node::asciify(macro *m)
2806 {
2807 n->asciify(m);
2808 n = 0;
2809 delete this;
2810 }
2811
asciify(macro * m)2812 void left_italic_corrected_node::asciify(macro *m)
2813 {
2814 if (n) {
2815 n->asciify(m);
2816 n = 0;
2817 }
2818 delete this;
2819 }
2820
space_char_hmotion_node(hunits i,node * next)2821 space_char_hmotion_node::space_char_hmotion_node(hunits i, node *next)
2822 : hmotion_node(i, next)
2823 {
2824 }
2825
asciify(macro * m)2826 void space_char_hmotion_node::asciify(macro *m)
2827 {
2828 m->append(' ');
2829 delete this;
2830 }
2831
asciify(macro *)2832 void line_start_node::asciify(macro *)
2833 {
2834 delete this;
2835 }
2836
asciify(macro *)2837 void vertical_size_node::asciify(macro *)
2838 {
2839 delete this;
2840 }
2841
get_breakpoints(hunits,int,breakpoint * rest,int)2842 breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/,
2843 breakpoint *rest, int /*is_inner*/)
2844 {
2845 return rest;
2846 }
2847
nbreaks()2848 int node::nbreaks()
2849 {
2850 return 0;
2851 }
2852
get_breakpoints(hunits width,int ns,breakpoint * rest,int is_inner)2853 breakpoint *space_node::get_breakpoints(hunits width, int ns, breakpoint *rest,
2854 int is_inner)
2855 {
2856 if (next->discardable())
2857 return rest;
2858 breakpoint *bp = new breakpoint;
2859 bp->next = rest;
2860 bp->width = width;
2861 bp->nspaces = ns;
2862 bp->hyphenated = 0;
2863 if (is_inner) {
2864 assert(rest != 0);
2865 bp->index = rest->index + 1;
2866 bp->nd = rest->nd;
2867 }
2868 else {
2869 bp->nd = this;
2870 bp->index = 0;
2871 }
2872 return bp;
2873 }
2874
nbreaks()2875 int space_node::nbreaks()
2876 {
2877 if (next->discardable())
2878 return 0;
2879 else
2880 return 1;
2881 }
2882
node_list_get_breakpoints(node * p,hunits * widthp,int ns,breakpoint * rest)2883 static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp,
2884 int ns, breakpoint *rest)
2885 {
2886 if (p != 0) {
2887 rest = p->get_breakpoints(*widthp,
2888 ns,
2889 node_list_get_breakpoints(p->next, widthp, ns,
2890 rest),
2891 1);
2892 *widthp += p->width();
2893 }
2894 return rest;
2895 }
2896
2897
get_breakpoints(hunits width,int ns,breakpoint * rest,int is_inner)2898 breakpoint *dbreak_node::get_breakpoints(hunits width, int ns,
2899 breakpoint *rest, int is_inner)
2900 {
2901 breakpoint *bp = new breakpoint;
2902 bp->next = rest;
2903 bp->width = width;
2904 for (node *tem = pre; tem != 0; tem = tem->next)
2905 bp->width += tem->width();
2906 bp->nspaces = ns;
2907 bp->hyphenated = 1;
2908 if (is_inner) {
2909 assert(rest != 0);
2910 bp->index = rest->index + 1;
2911 bp->nd = rest->nd;
2912 }
2913 else {
2914 bp->nd = this;
2915 bp->index = 0;
2916 }
2917 return node_list_get_breakpoints(none, &width, ns, bp);
2918 }
2919
nbreaks()2920 int dbreak_node::nbreaks()
2921 {
2922 int i = 1;
2923 for (node *tem = none; tem != 0; tem = tem->next)
2924 i += tem->nbreaks();
2925 return i;
2926 }
2927
split(int,node **,node **)2928 void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/)
2929 {
2930 assert(0);
2931 }
2932
split(int where,node ** pre,node ** post)2933 void space_node::split(int where, node **pre, node **post)
2934 {
2935 assert(where == 0);
2936 *pre = next;
2937 *post = 0;
2938 delete this;
2939 }
2940
node_list_split(node * p,int * wherep,node ** prep,node ** postp)2941 static void node_list_split(node *p, int *wherep, node **prep, node **postp)
2942 {
2943 if (p == 0)
2944 return;
2945 int nb = p->nbreaks();
2946 node_list_split(p->next, wherep, prep, postp);
2947 if (*wherep < 0) {
2948 p->next = *postp;
2949 *postp = p;
2950 }
2951 else if (*wherep < nb) {
2952 p->next = *prep;
2953 p->split(*wherep, prep, postp);
2954 }
2955 else {
2956 p->next = *prep;
2957 *prep = p;
2958 }
2959 *wherep -= nb;
2960 }
2961
split(int where,node ** prep,node ** postp)2962 void dbreak_node::split(int where, node **prep, node **postp)
2963 {
2964 assert(where >= 0);
2965 if (where == 0) {
2966 *postp = post;
2967 post = 0;
2968 if (pre == 0)
2969 *prep = next;
2970 else {
2971 for (node *tem = pre; tem->next != 0; tem = tem->next)
2972 ;
2973 tem->next = next;
2974 *prep = pre;
2975 }
2976 pre = 0;
2977 delete this;
2978 }
2979 else {
2980 *prep = next;
2981 where -= 1;
2982 node_list_split(none, &where, prep, postp);
2983 none = 0;
2984 delete this;
2985 }
2986 }
2987
2988
get_hyphenation_type()2989 hyphenation_type node::get_hyphenation_type()
2990 {
2991 return HYPHEN_BOUNDARY;
2992 }
2993
2994
get_hyphenation_type()2995 hyphenation_type dbreak_node::get_hyphenation_type()
2996 {
2997 return HYPHEN_INHIBIT;
2998 }
2999
get_hyphenation_type()3000 hyphenation_type kern_pair_node::get_hyphenation_type()
3001 {
3002 return HYPHEN_MIDDLE;
3003 }
3004
get_hyphenation_type()3005 hyphenation_type dummy_node::get_hyphenation_type()
3006 {
3007 return HYPHEN_MIDDLE;
3008 }
3009
get_hyphenation_type()3010 hyphenation_type transparent_dummy_node::get_hyphenation_type()
3011 {
3012 return HYPHEN_MIDDLE;
3013 }
3014
interpret(macro *)3015 int node::interpret(macro *)
3016 {
3017 return 0;
3018 }
3019
special_node(const macro & m)3020 special_node::special_node(const macro &m)
3021 : mac(m)
3022 {
3023 }
3024
same(node * n)3025 int special_node::same(node *n)
3026 {
3027 return mac == ((special_node *)n)->mac;
3028 }
3029
type()3030 const char *special_node::type()
3031 {
3032 return "special_node";
3033 }
3034
copy()3035 node *special_node::copy()
3036 {
3037 return new special_node(mac);
3038 }
3039
tprint_start(troff_output_file * out)3040 void special_node::tprint_start(troff_output_file *out)
3041 {
3042 out->start_special();
3043 }
3044
tprint_char(troff_output_file * out,unsigned char c)3045 void special_node::tprint_char(troff_output_file *out, unsigned char c)
3046 {
3047 out->special_char(c);
3048 }
3049
tprint_end(troff_output_file * out)3050 void special_node::tprint_end(troff_output_file *out)
3051 {
3052 out->end_special();
3053 }
3054
3055 /* composite_node */
3056
3057 class composite_node : public node {
3058 charinfo *ci;
3059 node *n;
3060 tfont *tf;
3061 public:
3062 composite_node(node *, charinfo *, tfont *, node * = 0);
3063 ~composite_node();
3064 node *copy();
3065 hunits width();
3066 node *last_char_node();
3067 units size();
3068 void tprint(troff_output_file *);
3069 hyphenation_type get_hyphenation_type();
3070 int overlaps_horizontally();
3071 int overlaps_vertically();
3072 void ascii_print(ascii_output_file *);
3073 void asciify(macro *);
3074 hyphen_list *get_hyphen_list(hyphen_list *tail);
3075 node *add_self(node *, hyphen_list **);
3076 tfont *get_tfont();
3077 int same(node *);
3078 const char *type();
3079 void vertical_extent(vunits *, vunits *);
3080 vunits vertical_width();
3081 };
3082
composite_node(node * p,charinfo * c,tfont * t,node * x)3083 composite_node::composite_node(node *p, charinfo *c, tfont *t, node *x)
3084 : node(x), n(p), ci(c), tf(t)
3085 {
3086 }
3087
~composite_node()3088 composite_node::~composite_node()
3089 {
3090 delete_node_list(n);
3091 }
3092
copy()3093 node *composite_node::copy()
3094 {
3095 return new composite_node(copy_node_list(n), ci, tf);
3096 }
3097
width()3098 hunits composite_node::width()
3099 {
3100 hunits x;
3101 if (tf->get_constant_space(&x))
3102 return x;
3103 x = H0;
3104 for (node *tem = n; tem; tem = tem->next)
3105 x += tem->width();
3106 hunits offset;
3107 if (tf->get_bold(&offset))
3108 x += offset;
3109 x += tf->get_track_kern();
3110 return x;
3111 }
3112
last_char_node()3113 node *composite_node::last_char_node()
3114 {
3115 return this;
3116 }
3117
vertical_width()3118 vunits composite_node::vertical_width()
3119 {
3120 vunits v = V0;
3121 for (node *tem = n; tem; tem = tem->next)
3122 v += tem->vertical_width();
3123 return v;
3124 }
3125
size()3126 units composite_node::size()
3127 {
3128 return tf->get_size().to_units();
3129 }
3130
get_hyphenation_type()3131 hyphenation_type composite_node::get_hyphenation_type()
3132 {
3133 return HYPHEN_MIDDLE;
3134 }
3135
overlaps_horizontally()3136 int composite_node::overlaps_horizontally()
3137 {
3138 return ci->overlaps_horizontally();
3139 }
3140
overlaps_vertically()3141 int composite_node::overlaps_vertically()
3142 {
3143 return ci->overlaps_vertically();
3144 }
3145
asciify(macro * m)3146 void composite_node::asciify(macro *m)
3147 {
3148 unsigned char c = ci->get_ascii_code();
3149 if (c != 0) {
3150 m->append(c);
3151 delete this;
3152 }
3153 else
3154 m->append(this);
3155 }
3156
ascii_print(ascii_output_file * ascii)3157 void composite_node::ascii_print(ascii_output_file *ascii)
3158 {
3159 unsigned char c = ci->get_ascii_code();
3160 if (c != 0)
3161 ascii->outc(c);
3162 else
3163 ascii->outs(ci->nm.contents());
3164
3165 }
3166
get_hyphen_list(hyphen_list * tail)3167 hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail)
3168 {
3169 return new hyphen_list(ci->get_hyphenation_code(), tail);
3170
3171 }
3172
add_self(node * nn,hyphen_list ** p)3173 node *composite_node::add_self(node *nn, hyphen_list **p)
3174 {
3175 assert(ci->get_hyphenation_code() == (*p)->hyphenation_code);
3176 next = nn;
3177 nn = this;
3178 if ((*p)->hyphen)
3179 nn = nn->add_discretionary_hyphen();
3180 hyphen_list *pp = *p;
3181 *p = (*p)->next;
3182 delete pp;
3183 return nn;
3184 }
3185
get_tfont()3186 tfont *composite_node::get_tfont()
3187 {
3188 return tf;
3189 }
3190
reverse_node_list(node * n)3191 node *reverse_node_list(node *n)
3192 {
3193 node *r = 0;
3194 while (n) {
3195 node *tem = n;
3196 n = n->next;
3197 tem->next = r;
3198 r = tem;
3199 }
3200 return r;
3201 }
3202
vertical_extent(vunits * min,vunits * max)3203 void composite_node::vertical_extent(vunits *min, vunits *max)
3204 {
3205 n = reverse_node_list(n);
3206 node_list_vertical_extent(n, min, max);
3207 n = reverse_node_list(n);
3208 }
3209
word_space_node(hunits d,node * x)3210 word_space_node::word_space_node(hunits d, node *x) : space_node(d, x)
3211 {
3212 }
3213
word_space_node(hunits d,int s,node * x)3214 word_space_node::word_space_node(hunits d, int s, node *x)
3215 : space_node(d, s, x)
3216 {
3217 }
3218
copy()3219 node *word_space_node::copy()
3220 {
3221 return new word_space_node(n, set);
3222 }
3223
tprint(troff_output_file * out)3224 void word_space_node::tprint(troff_output_file *out)
3225 {
3226 out->word_marker();
3227 space_node::tprint(out);
3228 }
3229
unbreakable_space_node(hunits d,node * x)3230 unbreakable_space_node::unbreakable_space_node(hunits d, node *x)
3231 : word_space_node(d, x)
3232 {
3233 }
3234
unbreakable_space_node(hunits d,int s,node * x)3235 unbreakable_space_node::unbreakable_space_node(hunits d, int s, node *x)
3236 : word_space_node(d, s, x)
3237 {
3238 }
3239
copy()3240 node *unbreakable_space_node::copy()
3241 {
3242 return new unbreakable_space_node(n, set);
3243 }
3244
get_breakpoints(hunits,int,breakpoint * rest,int)3245 breakpoint *unbreakable_space_node::get_breakpoints(hunits, int,
3246 breakpoint *rest, int)
3247 {
3248 return rest;
3249 }
3250
nbreaks()3251 int unbreakable_space_node::nbreaks()
3252 {
3253 return 0;
3254 }
3255
split(int,node **,node **)3256 void unbreakable_space_node::split(int, node **, node **)
3257 {
3258 assert(0);
3259 }
3260
merge_space(hunits)3261 int unbreakable_space_node::merge_space(hunits)
3262 {
3263 return 0;
3264 }
3265
hvpair()3266 hvpair::hvpair()
3267 {
3268 }
3269
draw_node(char c,hvpair * p,int np,font_size s)3270 draw_node::draw_node(char c, hvpair *p, int np, font_size s)
3271 : code(c), npoints(np), sz(s)
3272 {
3273 point = new hvpair[npoints];
3274 for (int i = 0; i < npoints; i++)
3275 point[i] = p[i];
3276 }
3277
same(node * n)3278 int draw_node::same(node *n)
3279 {
3280 draw_node *nd = (draw_node *)n;
3281 if (code != nd->code || npoints != nd->npoints || sz != nd->sz)
3282 return 0;
3283 for (int i = 0; i < npoints; i++)
3284 if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v)
3285 return 0;
3286 return 1;
3287 }
3288
type()3289 const char *draw_node::type()
3290 {
3291 return "draw_node";
3292 }
3293
~draw_node()3294 draw_node::~draw_node()
3295 {
3296 if (point)
3297 a_delete point;
3298 }
3299
width()3300 hunits draw_node::width()
3301 {
3302 hunits x = H0;
3303 for (int i = 0; i < npoints; i++)
3304 x += point[i].h;
3305 return x;
3306 }
3307
vertical_width()3308 vunits draw_node::vertical_width()
3309 {
3310 if (code == 'e')
3311 return V0;
3312 vunits x = V0;
3313 for (int i = 0; i < npoints; i++)
3314 x += point[i].v;
3315 return x;
3316 }
3317
copy()3318 node *draw_node::copy()
3319 {
3320 return new draw_node(code, point, npoints, sz);
3321 }
3322
tprint(troff_output_file * out)3323 void draw_node::tprint(troff_output_file *out)
3324 {
3325 out->draw(code, point, npoints, sz);
3326 }
3327
3328 /* tprint methods */
3329
tprint(troff_output_file * out)3330 void glyph_node::tprint(troff_output_file *out)
3331 {
3332 tfont *ptf = tf->get_plain();
3333 if (ptf == tf)
3334 out->put_char_width(ci, ptf, width(), H0);
3335 else {
3336 hunits offset;
3337 int bold = tf->get_bold(&offset);
3338 hunits w = ptf->get_width(ci);
3339 hunits k = H0;
3340 hunits x;
3341 int cs = tf->get_constant_space(&x);
3342 if (cs) {
3343 x -= w;
3344 if (bold)
3345 x -= offset;
3346 hunits x2 = x/2;
3347 out->right(x2);
3348 k = x - x2;
3349 }
3350 else
3351 k = tf->get_track_kern();
3352 if (bold) {
3353 out->put_char(ci, ptf);
3354 out->right(offset);
3355 }
3356 out->put_char_width(ci, ptf, w, k);
3357 }
3358 }
3359
zero_width_tprint(troff_output_file * out)3360 void glyph_node::zero_width_tprint(troff_output_file *out)
3361 {
3362 tfont *ptf = tf->get_plain();
3363 hunits offset;
3364 int bold = tf->get_bold(&offset);
3365 hunits x;
3366 int cs = tf->get_constant_space(&x);
3367 if (cs) {
3368 x -= ptf->get_width(ci);
3369 if (bold)
3370 x -= offset;
3371 x = x/2;
3372 out->right(x);
3373 }
3374 out->put_char(ci, ptf);
3375 if (bold) {
3376 out->right(offset);
3377 out->put_char(ci, ptf);
3378 out->right(-offset);
3379 }
3380 if (cs)
3381 out->right(-x);
3382 }
3383
tprint(troff_output_file * t)3384 void break_char_node::tprint(troff_output_file *t)
3385 {
3386 ch->tprint(t);
3387 }
3388
zero_width_tprint(troff_output_file * t)3389 void break_char_node::zero_width_tprint(troff_output_file *t)
3390 {
3391 ch->zero_width_tprint(t);
3392 }
3393
tprint(troff_output_file * out)3394 void hline_node::tprint(troff_output_file *out)
3395 {
3396 if (x < H0) {
3397 out->right(x);
3398 x = -x;
3399 }
3400 if (n == 0) {
3401 out->right(x);
3402 return;
3403 }
3404 hunits w = n->width();
3405 if (w <= H0) {
3406 error("horizontal line drawing character must have positive width");
3407 out->right(x);
3408 return;
3409 }
3410 int i = int(x/w);
3411 if (i == 0) {
3412 hunits xx = x - w;
3413 hunits xx2 = xx/2;
3414 out->right(xx2);
3415 n->tprint(out);
3416 out->right(xx - xx2);
3417 }
3418 else {
3419 hunits rem = x - w*i;
3420 if (rem > H0)
3421 if (n->overlaps_horizontally()) {
3422 n->tprint(out);
3423 out->right(rem - w);
3424 }
3425 else
3426 out->right(rem);
3427 while (--i >= 0)
3428 n->tprint(out);
3429 }
3430 }
3431
tprint(troff_output_file * out)3432 void vline_node::tprint(troff_output_file *out)
3433 {
3434 if (n == 0) {
3435 out->down(x);
3436 return;
3437 }
3438 vunits h = n->size();
3439 int overlaps = n->overlaps_vertically();
3440 vunits y = x;
3441 if (y < V0) {
3442 y = -y;
3443 int i = y / h;
3444 vunits rem = y - i*h;
3445 if (i == 0) {
3446 out->right(n->width());
3447 out->down(-rem);
3448 }
3449 else {
3450 while (--i > 0) {
3451 n->zero_width_tprint(out);
3452 out->down(-h);
3453 }
3454 if (overlaps) {
3455 n->zero_width_tprint(out);
3456 out->down(-rem);
3457 n->tprint(out);
3458 out->down(-h);
3459 }
3460 else {
3461 n->tprint(out);
3462 out->down(-h - rem);
3463 }
3464 }
3465 }
3466 else {
3467 int i = y / h;
3468 vunits rem = y - i*h;
3469 if (i == 0) {
3470 out->down(rem);
3471 out->right(n->width());
3472 }
3473 else {
3474 out->down(h);
3475 if (overlaps)
3476 n->zero_width_tprint(out);
3477 out->down(rem);
3478 while (--i > 0) {
3479 n->zero_width_tprint(out);
3480 out->down(h);
3481 }
3482 n->tprint(out);
3483 }
3484 }
3485 }
3486
tprint(troff_output_file * out)3487 void zero_width_node::tprint(troff_output_file *out)
3488 {
3489 if (!n)
3490 return;
3491 if (!n->next) {
3492 n->zero_width_tprint(out);
3493 return;
3494 }
3495 int hpos = out->get_hpos();
3496 int vpos = out->get_vpos();
3497 node *tem = n;
3498 while (tem) {
3499 tem->tprint(out);
3500 tem = tem->next;
3501 }
3502 out->moveto(hpos, vpos);
3503 }
3504
tprint(troff_output_file * out)3505 void overstrike_node::tprint(troff_output_file *out)
3506 {
3507 hunits pos = H0;
3508 for (node *tem = list; tem; tem = tem->next) {
3509 hunits x = (max_width - tem->width())/2;
3510 out->right(x - pos);
3511 pos = x;
3512 tem->zero_width_tprint(out);
3513 }
3514 out->right(max_width - pos);
3515 }
3516
tprint(troff_output_file * out)3517 void bracket_node::tprint(troff_output_file *out)
3518 {
3519 if (list == 0)
3520 return;
3521 int npieces = 0;
3522 for (node *tem = list; tem; tem = tem->next)
3523 ++npieces;
3524 vunits h = list->size();
3525 vunits totalh = h*npieces;
3526 vunits y = (totalh - h)/2;
3527 out->down(y);
3528 for (tem = list; tem; tem = tem->next) {
3529 tem->zero_width_tprint(out);
3530 out->down(-h);
3531 }
3532 out->right(max_width);
3533 out->down(totalh - y);
3534 }
3535
tprint(troff_output_file *)3536 void node::tprint(troff_output_file *)
3537 {
3538 }
3539
zero_width_tprint(troff_output_file * out)3540 void node::zero_width_tprint(troff_output_file *out)
3541 {
3542 int hpos = out->get_hpos();
3543 int vpos = out->get_vpos();
3544 tprint(out);
3545 out->moveto(hpos, vpos);
3546 }
3547
tprint(troff_output_file * out)3548 void space_node::tprint(troff_output_file *out)
3549 {
3550 out->right(n);
3551 }
3552
tprint(troff_output_file * out)3553 void hmotion_node::tprint(troff_output_file *out)
3554 {
3555 out->right(n);
3556 }
3557
tprint(troff_output_file * out)3558 void vmotion_node::tprint(troff_output_file *out)
3559 {
3560 out->down(n);
3561 }
3562
tprint(troff_output_file * out)3563 void kern_pair_node::tprint(troff_output_file *out)
3564 {
3565 n1->tprint(out);
3566 out->right(amount);
3567 n2->tprint(out);
3568 }
3569
tprint_reverse_node_list(troff_output_file * out,node * n)3570 static void tprint_reverse_node_list(troff_output_file *out, node *n)
3571 {
3572 if (n == 0)
3573 return;
3574 tprint_reverse_node_list(out, n->next);
3575 n->tprint(out);
3576 }
3577
tprint(troff_output_file * out)3578 void dbreak_node::tprint(troff_output_file *out)
3579 {
3580 tprint_reverse_node_list(out, none);
3581 }
3582
tprint(troff_output_file * out)3583 void composite_node::tprint(troff_output_file *out)
3584 {
3585 hunits bold_offset;
3586 int is_bold = tf->get_bold(&bold_offset);
3587 hunits track_kern = tf->get_track_kern();
3588 hunits constant_space;
3589 int is_constant_spaced = tf->get_constant_space(&constant_space);
3590 hunits x = H0;
3591 if (is_constant_spaced) {
3592 x = constant_space;
3593 for (node *tem = n; tem; tem = tem->next)
3594 x -= tem->width();
3595 if (is_bold)
3596 x -= bold_offset;
3597 hunits x2 = x/2;
3598 out->right(x2);
3599 x -= x2;
3600 }
3601 if (is_bold) {
3602 int hpos = out->get_hpos();
3603 int vpos = out->get_vpos();
3604 tprint_reverse_node_list(out, n);
3605 out->moveto(hpos, vpos);
3606 out->right(bold_offset);
3607 }
3608 tprint_reverse_node_list(out, n);
3609 if (is_constant_spaced)
3610 out->right(x);
3611 else
3612 out->right(track_kern);
3613 }
3614
make_composite_node(charinfo * s,environment * env)3615 node *make_composite_node(charinfo *s, environment *env)
3616 {
3617 int fontno = env_definite_font(env);
3618 if (fontno < 0) {
3619 error("no current font");
3620 return 0;
3621 }
3622 assert(fontno < font_table_size && font_table[fontno] != 0);
3623 node *n = charinfo_to_node_list(s, env);
3624 font_size fs = env->get_font_size();
3625 int char_height = env->get_char_height();
3626 int char_slant = env->get_char_slant();
3627 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant,
3628 fontno);
3629 if (env->is_composite())
3630 tf = tf->get_plain();
3631 return new composite_node(n, s, tf);
3632 }
3633
make_glyph_node(charinfo * s,environment * env,int no_error_message=0)3634 node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0)
3635 {
3636 int fontno = env_definite_font(env);
3637 if (fontno < 0) {
3638 error("no current font");
3639 return 0;
3640 }
3641 assert(fontno < font_table_size && font_table[fontno] != 0);
3642 int fn = fontno;
3643 int found = font_table[fontno]->contains(s);
3644 if (!found) {
3645 if (s->numbered()) {
3646 if (!no_error_message)
3647 warning(WARN_CHAR, "can't find numbered character %1",
3648 s->get_number());
3649 return 0;
3650 }
3651 special_font_list *sf = font_table[fontno]->sf;
3652 while (sf != 0 && !found) {
3653 fn = sf->n;
3654 if (font_table[fn])
3655 found = font_table[fn]->contains(s);
3656 sf = sf->next;
3657 }
3658 if (!found) {
3659 sf = global_special_fonts;
3660 while (sf != 0 && !found) {
3661 fn = sf->n;
3662 if (font_table[fn])
3663 found = font_table[fn]->contains(s);
3664 sf = sf->next;
3665 }
3666 }
3667 if (!found
3668 #if 0
3669 && global_special_fonts == 0 && font_table[fontno]->sf == 0
3670 #endif
3671 ) {
3672 for (fn = 0; fn < font_table_size; fn++)
3673 if (font_table[fn]
3674 && font_table[fn]->is_special()
3675 && font_table[fn]->contains(s)) {
3676 found = 1;
3677 break;
3678 }
3679 }
3680 if (!found) {
3681 if (!no_error_message && s->first_time_not_found()) {
3682 unsigned char input_code = s->get_ascii_code();
3683 if (input_code != 0) {
3684 if (csgraph(input_code))
3685 warning(WARN_CHAR, "can't find character `%1'", input_code);
3686 else
3687 warning(WARN_CHAR, "can't find character with input code %1",
3688 int(input_code));
3689 }
3690 else
3691 warning(WARN_CHAR, "can't find special character `%1'",
3692 s->nm.contents());
3693 }
3694 return 0;
3695 }
3696 }
3697 font_size fs = env->get_font_size();
3698 int char_height = env->get_char_height();
3699 int char_slant = env->get_char_slant();
3700 tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn);
3701 if (env->is_composite())
3702 tf = tf->get_plain();
3703 return new glyph_node(s, tf);
3704 }
3705
make_node(charinfo * ci,environment * env)3706 node *make_node(charinfo *ci, environment *env)
3707 {
3708 switch (ci->get_special_translation()) {
3709 case charinfo::TRANSLATE_SPACE:
3710 return new space_char_hmotion_node(env->get_space_width());
3711 case charinfo::TRANSLATE_DUMMY:
3712 return new dummy_node;
3713 case charinfo::TRANSLATE_HYPHEN_INDICATOR:
3714 error("translation to \\% ignored in this context");
3715 break;
3716 }
3717 charinfo *tem = ci->get_translation();
3718 if (tem)
3719 ci = tem;
3720 macro *mac = ci->get_macro();
3721 if (mac)
3722 return make_composite_node(ci, env);
3723 else
3724 return make_glyph_node(ci, env);
3725 }
3726
character_exists(charinfo * ci,environment * env)3727 int character_exists(charinfo *ci, environment *env)
3728 {
3729 if (ci->get_special_translation() != charinfo::TRANSLATE_NONE)
3730 return 1;
3731 charinfo *tem = ci->get_translation();
3732 if (tem)
3733 ci = tem;
3734 if (ci->get_macro())
3735 return 1;
3736 node *nd = make_glyph_node(ci, env, 1);
3737 if (nd) {
3738 delete nd;
3739 return 1;
3740 }
3741 return 0;
3742 }
3743
add_char(charinfo * ci,environment * env,hunits * widthp)3744 node *node::add_char(charinfo *ci, environment *env, hunits *widthp)
3745 {
3746 node *res;
3747 switch (ci->get_special_translation()) {
3748 case charinfo::TRANSLATE_SPACE:
3749 res = new space_char_hmotion_node(env->get_space_width(), this);
3750 *widthp += res->width();
3751 return res;
3752 case charinfo::TRANSLATE_DUMMY:
3753 return new dummy_node(this);
3754 case charinfo::TRANSLATE_HYPHEN_INDICATOR:
3755 return add_discretionary_hyphen();
3756 }
3757 charinfo *tem = ci->get_translation();
3758 if (tem)
3759 ci = tem;
3760 macro *mac = ci->get_macro();
3761 if (mac) {
3762 res = make_composite_node(ci, env);
3763 if (res) {
3764 res->next = this;
3765 *widthp += res->width();
3766 }
3767 else
3768 return this;
3769 }
3770 else {
3771 node *gn = make_glyph_node(ci, env);
3772 if (gn == 0)
3773 return this;
3774 else {
3775 hunits old_width = width();
3776 node *p = gn->merge_self(this);
3777 if (p == 0) {
3778 *widthp += gn->width();
3779 gn->next = this;
3780 res = gn;
3781 }
3782 else {
3783 *widthp += p->width() - old_width;
3784 res = p;
3785 }
3786 }
3787 }
3788 int break_code = 0;
3789 if (ci->can_break_before())
3790 break_code = 1;
3791 if (ci->can_break_after())
3792 break_code |= 2;
3793 if (break_code) {
3794 node *next1 = res->next;
3795 res->next = 0;
3796 res = new break_char_node(res, break_code, next1);
3797 }
3798 return res;
3799 }
3800
3801
3802 #ifdef __GNUG__
3803 inline
3804 #endif
same_node(node * n1,node * n2)3805 int same_node(node *n1, node *n2)
3806 {
3807 if (n1 != 0) {
3808 if (n2 != 0)
3809 return n1->type() == n2->type() && n1->same(n2);
3810 else
3811 return 0;
3812 }
3813 else
3814 return n2 == 0;
3815 }
3816
same_node_list(node * n1,node * n2)3817 int same_node_list(node *n1, node *n2)
3818 {
3819 while (n1 && n2) {
3820 if (n1->type() != n2->type() || !n1->same(n2))
3821 return 0;
3822 n1 = n1->next;
3823 n2 = n2->next;
3824 }
3825 return !n1 && !n2;
3826 }
3827
same(node * nd)3828 int extra_size_node::same(node *nd)
3829 {
3830 return n == ((extra_size_node *)nd)->n;
3831 }
3832
type()3833 const char *extra_size_node::type()
3834 {
3835 return "extra_size_node";
3836 }
3837
same(node * nd)3838 int vertical_size_node::same(node *nd)
3839 {
3840 return n == ((vertical_size_node *)nd)->n;
3841 }
3842
type()3843 const char *vertical_size_node::type()
3844 {
3845 return "vertical_size_node";
3846 }
3847
same(node * nd)3848 int hmotion_node::same(node *nd)
3849 {
3850 return n == ((hmotion_node *)nd)->n;
3851 }
3852
type()3853 const char *hmotion_node::type()
3854 {
3855 return "hmotion_node";
3856 }
3857
same(node * nd)3858 int space_char_hmotion_node::same(node *nd)
3859 {
3860 return n == ((space_char_hmotion_node *)nd)->n;
3861 }
3862
type()3863 const char *space_char_hmotion_node::type()
3864 {
3865 return "space_char_hmotion_node";
3866 }
3867
same(node * nd)3868 int vmotion_node::same(node *nd)
3869 {
3870 return n == ((vmotion_node *)nd)->n;
3871 }
3872
type()3873 const char *vmotion_node::type()
3874 {
3875 return "vmotion_node";
3876 }
3877
same(node * nd)3878 int hline_node::same(node *nd)
3879 {
3880 return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n);
3881 }
3882
type()3883 const char *hline_node::type()
3884 {
3885 return "hline_node";
3886 }
3887
same(node * nd)3888 int vline_node::same(node *nd)
3889 {
3890 return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n);
3891 }
3892
type()3893 const char *vline_node::type()
3894 {
3895 return "vline_node";
3896 }
3897
same(node *)3898 int dummy_node::same(node * /*nd*/)
3899 {
3900 return 1;
3901 }
3902
type()3903 const char *dummy_node::type()
3904 {
3905 return "dummy_node";
3906 }
3907
same(node *)3908 int transparent_dummy_node::same(node * /*nd*/)
3909 {
3910 return 1;
3911 }
3912
type()3913 const char *transparent_dummy_node::type()
3914 {
3915 return "transparent_dummy_node";
3916 }
3917
ends_sentence()3918 int transparent_dummy_node::ends_sentence()
3919 {
3920 return 2;
3921 }
3922
same(node * nd)3923 int zero_width_node::same(node *nd)
3924 {
3925 return same_node_list(n, ((zero_width_node *)nd)->n);
3926 }
3927
type()3928 const char *zero_width_node::type()
3929 {
3930 return "zero_width_node";
3931 }
3932
same(node * nd)3933 int italic_corrected_node::same(node *nd)
3934 {
3935 return (x == ((italic_corrected_node *)nd)->x
3936 && same_node(n, ((italic_corrected_node *)nd)->n));
3937 }
3938
type()3939 const char *italic_corrected_node::type()
3940 {
3941 return "italic_corrected_node";
3942 }
3943
3944
left_italic_corrected_node(node * x)3945 left_italic_corrected_node::left_italic_corrected_node(node *x)
3946 : n(0), node(x)
3947 {
3948 }
3949
~left_italic_corrected_node()3950 left_italic_corrected_node::~left_italic_corrected_node()
3951 {
3952 delete n;
3953 }
3954
merge_glyph_node(glyph_node * gn)3955 node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn)
3956 {
3957 if (n == 0) {
3958 hunits lic = gn->left_italic_correction();
3959 if (!lic.is_zero()) {
3960 x = lic;
3961 n = gn;
3962 return this;
3963 }
3964 }
3965 else {
3966 node *nd = n->merge_glyph_node(gn);
3967 if (nd) {
3968 n = nd;
3969 x = n->left_italic_correction();
3970 return this;
3971 }
3972 }
3973 return 0;
3974 }
3975
copy()3976 node *left_italic_corrected_node::copy()
3977 {
3978 left_italic_corrected_node *nd = new left_italic_corrected_node;
3979 if (n) {
3980 nd->n = n->copy();
3981 nd->x = x;
3982 }
3983 return nd;
3984 }
3985
tprint(troff_output_file * out)3986 void left_italic_corrected_node::tprint(troff_output_file *out)
3987 {
3988 if (n) {
3989 out->right(x);
3990 n->tprint(out);
3991 }
3992 }
3993
type()3994 const char *left_italic_corrected_node::type()
3995 {
3996 return "left_italic_corrected_node";
3997 }
3998
same(node * nd)3999 int left_italic_corrected_node::same(node *nd)
4000 {
4001 return (x == ((left_italic_corrected_node *)nd)->x
4002 && same_node(n, ((left_italic_corrected_node *)nd)->n));
4003 }
4004
ascii_print(ascii_output_file * out)4005 void left_italic_corrected_node::ascii_print(ascii_output_file *out)
4006 {
4007 if (n)
4008 n->ascii_print(out);
4009 }
4010
width()4011 hunits left_italic_corrected_node::width()
4012 {
4013 return n ? n->width() + x : H0;
4014 }
4015
vertical_extent(vunits * min,vunits * max)4016 void left_italic_corrected_node::vertical_extent(vunits *min, vunits *max)
4017 {
4018 if (n)
4019 n->vertical_extent(min, max);
4020 else
4021 node::vertical_extent(min, max);
4022 }
4023
skew()4024 hunits left_italic_corrected_node::skew()
4025 {
4026 return n ? n->skew() + x/2 : H0;
4027 }
4028
subscript_correction()4029 hunits left_italic_corrected_node::subscript_correction()
4030 {
4031 return n ? n->subscript_correction() : H0;
4032 }
4033
italic_correction()4034 hunits left_italic_corrected_node::italic_correction()
4035 {
4036 return n ? n->italic_correction() : H0;
4037 }
4038
ends_sentence()4039 int left_italic_corrected_node::ends_sentence()
4040 {
4041 return n ? n->ends_sentence() : 0;
4042 }
4043
overlaps_horizontally()4044 int left_italic_corrected_node::overlaps_horizontally()
4045 {
4046 return n ? n->overlaps_horizontally() : 0;
4047 }
4048
overlaps_vertically()4049 int left_italic_corrected_node::overlaps_vertically()
4050 {
4051 return n ? n->overlaps_vertically() : 0;
4052 }
4053
last_char_node()4054 node *left_italic_corrected_node::last_char_node()
4055 {
4056 return n ? n->last_char_node() : 0;
4057 }
4058
get_tfont()4059 tfont *left_italic_corrected_node::get_tfont()
4060 {
4061 return n ? n->get_tfont() : 0;
4062 }
4063
get_hyphenation_type()4064 hyphenation_type left_italic_corrected_node::get_hyphenation_type()
4065 {
4066 if (n)
4067 return n->get_hyphenation_type();
4068 else
4069 return HYPHEN_MIDDLE;
4070 }
4071
get_hyphen_list(hyphen_list * tail)4072 hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail)
4073 {
4074 return n ? n->get_hyphen_list(tail) : tail;
4075 }
4076
add_self(node * nd,hyphen_list ** p)4077 node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p)
4078 {
4079 if (n) {
4080 nd = new left_italic_corrected_node(nd);
4081 nd = n->add_self(nd, p);
4082 n = 0;
4083 delete this;
4084 }
4085 return nd;
4086 }
4087
character_type()4088 int left_italic_corrected_node::character_type()
4089 {
4090 return n ? n->character_type() : 0;
4091 }
4092
same(node * nd)4093 int overstrike_node::same(node *nd)
4094 {
4095 return same_node_list(list, ((overstrike_node *)nd)->list);
4096 }
4097
type()4098 const char *overstrike_node::type()
4099 {
4100 return "overstrike_node";
4101 }
4102
same(node * nd)4103 int bracket_node::same(node *nd)
4104 {
4105 return same_node_list(list, ((bracket_node *)nd)->list);
4106 }
4107
type()4108 const char *bracket_node::type()
4109 {
4110 return "bracket_node";
4111 }
4112
same(node * nd)4113 int composite_node::same(node *nd)
4114 {
4115 return ci == ((composite_node *)nd)->ci
4116 && same_node_list(n, ((composite_node *)nd)->n);
4117 }
4118
type()4119 const char *composite_node::type()
4120 {
4121 return "composite_node";
4122 }
4123
same(node * nd)4124 int glyph_node::same(node *nd)
4125 {
4126 return ci == ((glyph_node *)nd)->ci && tf == ((glyph_node *)nd)->tf;
4127 }
4128
type()4129 const char *glyph_node::type()
4130 {
4131 return "glyph_node";
4132 }
4133
same(node * nd)4134 int ligature_node::same(node *nd)
4135 {
4136 return (same_node(n1, ((ligature_node *)nd)->n1)
4137 && same_node(n2, ((ligature_node *)nd)->n2)
4138 && glyph_node::same(nd));
4139 }
4140
type()4141 const char *ligature_node::type()
4142 {
4143 return "ligature_node";
4144 }
4145
same(node * nd)4146 int kern_pair_node::same(node *nd)
4147 {
4148 return (amount == ((kern_pair_node *)nd)->amount
4149 && same_node(n1, ((kern_pair_node *)nd)->n1)
4150 && same_node(n2, ((kern_pair_node *)nd)->n2));
4151 }
4152
type()4153 const char *kern_pair_node::type()
4154 {
4155 return "kern_pair_node";
4156 }
4157
same(node * nd)4158 int dbreak_node::same(node *nd)
4159 {
4160 return (same_node_list(none, ((dbreak_node *)nd)->none)
4161 && same_node_list(pre, ((dbreak_node *)nd)->pre)
4162 && same_node_list(post, ((dbreak_node *)nd)->post));
4163 }
4164
type()4165 const char *dbreak_node::type()
4166 {
4167 return "dbreak_node";
4168 }
4169
same(node * nd)4170 int break_char_node::same(node *nd)
4171 {
4172 return (break_code == ((break_char_node *)nd)->break_code
4173 && same_node(ch, ((break_char_node *)nd)->ch));
4174 }
4175
type()4176 const char *break_char_node::type()
4177 {
4178 return "break_char_node";
4179 }
4180
same(node *)4181 int line_start_node::same(node * /*nd*/)
4182 {
4183 return 1;
4184 }
4185
type()4186 const char *line_start_node::type()
4187 {
4188 return "line_start_node";
4189 }
4190
same(node * nd)4191 int space_node::same(node *nd)
4192 {
4193 return n == ((space_node *)nd)->n && set == ((space_node *)nd)->set;
4194 }
4195
type()4196 const char *space_node::type()
4197 {
4198 return "space_node";
4199 }
4200
same(node * nd)4201 int word_space_node::same(node *nd)
4202 {
4203 return (n == ((word_space_node *)nd)->n
4204 && set == ((word_space_node *)nd)->set);
4205 }
4206
type()4207 const char *word_space_node::type()
4208 {
4209 return "word_space_node";
4210 }
4211
same(node * nd)4212 int unbreakable_space_node::same(node *nd)
4213 {
4214 return (n == ((unbreakable_space_node *)nd)->n
4215 && set == ((unbreakable_space_node *)nd)->set);
4216 }
4217
type()4218 const char *unbreakable_space_node::type()
4219 {
4220 return "unbreakable_space_node";
4221 }
4222
same(node * nd)4223 int diverted_space_node::same(node *nd)
4224 {
4225 return n == ((diverted_space_node *)nd)->n;
4226 }
4227
type()4228 const char *diverted_space_node::type()
4229 {
4230 return "diverted_space_node";
4231 }
4232
same(node * nd)4233 int diverted_copy_file_node::same(node *nd)
4234 {
4235 return filename == ((diverted_copy_file_node *)nd)->filename;
4236 }
4237
type()4238 const char *diverted_copy_file_node::type()
4239 {
4240 return "diverted_copy_file_node";
4241 }
4242
4243 // Grow the font_table so that its size is > n.
4244
grow_font_table(int n)4245 static void grow_font_table(int n)
4246 {
4247 assert(n >= font_table_size);
4248 font_info **old_font_table = font_table;
4249 int old_font_table_size = font_table_size;
4250 font_table_size = font_table_size ? (font_table_size*3)/2 : 10;
4251 if (font_table_size <= n)
4252 font_table_size = n + 10;
4253 font_table = new font_info *[font_table_size];
4254 if (old_font_table_size)
4255 memcpy(font_table, old_font_table,
4256 old_font_table_size*sizeof(font_info *));
4257 a_delete old_font_table;
4258 for (int i = old_font_table_size; i < font_table_size; i++)
4259 font_table[i] = 0;
4260 }
4261
4262 dictionary font_translation_dictionary(17);
4263
get_font_translation(symbol nm)4264 static symbol get_font_translation(symbol nm)
4265 {
4266 void *p = font_translation_dictionary.lookup(nm);
4267 return p ? symbol((char *)p) : nm;
4268 }
4269
4270 dictionary font_dictionary(50);
4271
mount_font_no_translate(int n,symbol name,symbol external_name)4272 static int mount_font_no_translate(int n, symbol name, symbol external_name)
4273 {
4274 assert(n >= 0);
4275 // We store the address of this char in font_dictionary to indicate
4276 // that we've previously tried to mount the font and failed.
4277 static char a_char;
4278 font *fm = 0;
4279 void *p = font_dictionary.lookup(external_name);
4280 if (p == 0) {
4281 int not_found;
4282 fm = font::load_font(external_name.contents(), ¬_found);
4283 if (!fm) {
4284 if (not_found)
4285 warning(WARN_FONT, "can't find font `%1'", external_name.contents());
4286 font_dictionary.lookup(external_name, &a_char);
4287 return 0;
4288 }
4289 font_dictionary.lookup(name, fm);
4290 }
4291 else if (p == &a_char) {
4292 #if 0
4293 error("invalid font `%1'", external_name.contents());
4294 #endif
4295 return 0;
4296 }
4297 else
4298 fm = (font*)p;
4299 if (n >= font_table_size) {
4300 if (n - font_table_size > 1000) {
4301 error("font position too much larger than first unused position");
4302 return 0;
4303 }
4304 grow_font_table(n);
4305 }
4306 else if (font_table[n] != 0)
4307 delete font_table[n];
4308 font_table[n] = new font_info(name, n, external_name, fm);
4309 invalidate_fontno(n);
4310 return 1;
4311 }
4312
mount_font(int n,symbol name,symbol external_name)4313 int mount_font(int n, symbol name, symbol external_name)
4314 {
4315 assert(n >= 0);
4316 name = get_font_translation(name);
4317 if (external_name.is_null())
4318 external_name = name;
4319 else
4320 external_name = get_font_translation(external_name);
4321 return mount_font_no_translate(n, name, external_name);
4322 }
4323
mount_style(int n,symbol name)4324 void mount_style(int n, symbol name)
4325 {
4326 assert(n >= 0);
4327 if (n >= font_table_size) {
4328 if (n - font_table_size > 1000) {
4329 error("font position too much larger than first unused position");
4330 return;
4331 }
4332 grow_font_table(n);
4333 }
4334 else if (font_table[n] != 0)
4335 delete font_table[n];
4336 font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0);
4337 invalidate_fontno(n);
4338 }
4339
4340 /* global functions */
4341
font_translate()4342 void font_translate()
4343 {
4344 symbol from = get_name(1);
4345 if (!from.is_null()) {
4346 symbol to = get_name();
4347 if (to.is_null() || from == to)
4348 font_translation_dictionary.remove(from);
4349 else
4350 font_translation_dictionary.lookup(from, (void *)to.contents());
4351 }
4352 skip_line();
4353 }
4354
font_position()4355 void font_position()
4356 {
4357 int n;
4358 if (get_integer(&n)) {
4359 if (n < 0)
4360 error("negative font position");
4361 else {
4362 symbol internal_name = get_name(1);
4363 if (!internal_name.is_null()) {
4364 symbol external_name = get_long_name(0);
4365 mount_font(n, internal_name, external_name); // ignore error
4366 }
4367 }
4368 }
4369 skip_line();
4370 }
4371
font_family(symbol s)4372 font_family::font_family(symbol s)
4373 : nm(s), map_size(10)
4374 {
4375 map = new int[map_size];
4376 for (int i = 0; i < map_size; i++)
4377 map[i] = -1;
4378 }
4379
~font_family()4380 font_family::~font_family()
4381 {
4382 a_delete map;
4383 }
4384
make_definite(int i)4385 int font_family::make_definite(int i)
4386 {
4387 if (i >= 0) {
4388 if (i < map_size && map[i] >= 0)
4389 return map[i];
4390 else {
4391 if (i < font_table_size && font_table[i] != 0) {
4392 if (i >= map_size) {
4393 int old_map_size = map_size;
4394 int *old_map = map;
4395 map_size *= 3;
4396 map_size /= 2;
4397 if (i >= map_size)
4398 map_size = i + 10;
4399 map = new int[map_size];
4400 memcpy(map, old_map, old_map_size*sizeof(int));
4401 a_delete old_map;
4402 for (int j = old_map_size; j < map_size; j++)
4403 map[j] = -1;
4404 }
4405 if (font_table[i]->is_style()) {
4406 symbol sty = font_table[i]->get_name();
4407 symbol f = concat(nm, sty);
4408 int n;
4409 // don't use symbol_fontno, because that might return a style
4410 // and because we don't want to translate the name
4411 for (n = 0; n < font_table_size; n++)
4412 if (font_table[n] != 0 && font_table[n]->is_named(f)
4413 && !font_table[n]->is_style())
4414 break;
4415 if (n >= font_table_size) {
4416 n = next_available_font_position();
4417 if (!mount_font_no_translate(n, f, f))
4418 return -1;
4419 }
4420 return map[i] = n;
4421 }
4422 else
4423 return map[i] = i;
4424 }
4425 else
4426 return -1;
4427 }
4428 }
4429 else
4430 return -1;
4431 }
4432
4433 dictionary family_dictionary(5);
4434
lookup_family(symbol nm)4435 font_family *lookup_family(symbol nm)
4436 {
4437 font_family *f = (font_family *)family_dictionary.lookup(nm);
4438 if (!f) {
4439 f = new font_family(nm);
4440 (void)family_dictionary.lookup(nm, f);
4441 }
4442 return f;
4443 }
4444
invalidate_fontno(int n)4445 static void invalidate_fontno(int n)
4446 {
4447 assert(n >= 0 && n < font_table_size);
4448 dictionary_iterator iter(family_dictionary);
4449 symbol nm;
4450 font_family *fam;
4451 while (iter.get(&nm, (void **)&fam)) {
4452 int map_size = fam->map_size;
4453 if (n < map_size)
4454 fam->map[n] = -1;
4455 for (int i = 0; i < map_size; i++)
4456 if (fam->map[i] == n)
4457 fam->map[i] = -1;
4458 }
4459 }
4460
style()4461 void style()
4462 {
4463 int n;
4464 if (get_integer(&n)) {
4465 if (n < 0)
4466 error("negative font position");
4467 else {
4468 symbol internal_name = get_name(1);
4469 if (!internal_name.is_null())
4470 mount_style(n, internal_name);
4471 }
4472 }
4473 skip_line();
4474 }
4475
get_fontno()4476 static int get_fontno()
4477 {
4478 int n;
4479 tok.skip();
4480 if (tok.delimiter()) {
4481 symbol s = get_name(1);
4482 if (!s.is_null()) {
4483 n = symbol_fontno(s);
4484 if (n < 0) {
4485 n = next_available_font_position();
4486 if (!mount_font(n, s))
4487 return -1;
4488 }
4489 return curenv->get_family()->make_definite(n);
4490 }
4491 }
4492 else if (get_integer(&n)) {
4493 if (n < 0 || n >= font_table_size || font_table[n] == 0)
4494 error("bad font number");
4495 else
4496 return curenv->get_family()->make_definite(n);
4497 }
4498 return -1;
4499 }
4500
4501 static int underline_fontno = 2;
4502
underline_font()4503 void underline_font()
4504 {
4505 int n = get_fontno();
4506 if (n >= 0)
4507 underline_fontno = n;
4508 skip_line();
4509 }
4510
get_underline_fontno()4511 int get_underline_fontno()
4512 {
4513 return underline_fontno;
4514 }
4515
read_special_fonts(special_font_list ** sp)4516 static void read_special_fonts(special_font_list **sp)
4517 {
4518 special_font_list *s = *sp;
4519 *sp = 0;
4520 while (s != 0) {
4521 special_font_list *tem = s;
4522 s = s->next;
4523 delete tem;
4524 }
4525 special_font_list **p = sp;
4526 while (has_arg()) {
4527 int i = get_fontno();
4528 if (i >= 0) {
4529 special_font_list *tem = new special_font_list;
4530 tem->n = i;
4531 tem->next = 0;
4532 *p = tem;
4533 p = &(tem->next);
4534 }
4535 }
4536 }
4537
font_special_request()4538 void font_special_request()
4539 {
4540 int n = get_fontno();
4541 if (n >= 0)
4542 read_special_fonts(&font_table[n]->sf);
4543 skip_line();
4544 }
4545
4546
special_request()4547 void special_request()
4548 {
4549 read_special_fonts(&global_special_fonts);
4550 skip_line();
4551 }
4552
next_available_font_position()4553 int next_available_font_position()
4554 {
4555 for (int i = 1; i < font_table_size && font_table[i] != 0; i++)
4556 ;
4557 return i;
4558 }
4559
symbol_fontno(symbol s)4560 int symbol_fontno(symbol s)
4561 {
4562 s = get_font_translation(s);
4563 for (int i = 0; i < font_table_size; i++)
4564 if (font_table[i] != 0 && font_table[i]->is_named(s))
4565 return i;
4566 return -1;
4567 }
4568
is_good_fontno(int n)4569 int is_good_fontno(int n)
4570 {
4571 return n >= 0 && n < font_table_size && font_table[n] != NULL;
4572 }
4573
get_bold_fontno(int n)4574 int get_bold_fontno(int n)
4575 {
4576 if (n >= 0 && n < font_table_size && font_table[n] != 0) {
4577 hunits offset;
4578 if (font_table[n]->get_bold(&offset))
4579 return offset.to_units() + 1;
4580 else
4581 return 0;
4582 }
4583 else
4584 return 0;
4585 }
4586
env_digit_width(environment * env)4587 hunits env_digit_width(environment *env)
4588 {
4589 node *n = make_glyph_node(charset_table['0'], env);
4590 if (n) {
4591 hunits x = n->width();
4592 delete n;
4593 return x;
4594 }
4595 else
4596 return H0;
4597 }
4598
env_space_width(environment * env)4599 hunits env_space_width(environment *env)
4600 {
4601 int fn = env_definite_font(env);
4602 font_size fs = env->get_font_size();
4603 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
4604 return scale(fs.to_units()/3, env->get_space_size(), 12);
4605 else
4606 return font_table[fn]->get_space_width(fs, env->get_space_size());
4607 }
4608
env_sentence_space_width(environment * env)4609 hunits env_sentence_space_width(environment *env)
4610 {
4611 int fn = env_definite_font(env);
4612 font_size fs = env->get_font_size();
4613 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
4614 return scale(fs.to_units()/3, env->get_sentence_space_size(), 12);
4615 else
4616 return font_table[fn]->get_space_width(fs, env->get_sentence_space_size());
4617 }
4618
env_half_narrow_space_width(environment * env)4619 hunits env_half_narrow_space_width(environment *env)
4620 {
4621 int fn = env_definite_font(env);
4622 font_size fs = env->get_font_size();
4623 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
4624 return 0;
4625 else
4626 return font_table[fn]->get_half_narrow_space_width(fs);
4627 }
4628
env_narrow_space_width(environment * env)4629 hunits env_narrow_space_width(environment *env)
4630 {
4631 int fn = env_definite_font(env);
4632 font_size fs = env->get_font_size();
4633 if (fn < 0 || fn >= font_table_size || font_table[fn] == 0)
4634 return 0;
4635 else
4636 return font_table[fn]->get_narrow_space_width(fs);
4637 }
4638
bold_font()4639 void bold_font()
4640 {
4641 int n = get_fontno();
4642 if (n >= 0) {
4643 if (has_arg()) {
4644 if (tok.delimiter()) {
4645 int f = get_fontno();
4646 if (f >= 0) {
4647 units offset;
4648 if (has_arg() && get_number(&offset, 'u') && offset >= 1)
4649 font_table[f]->set_conditional_bold(n, hunits(offset - 1));
4650 else
4651 font_table[f]->conditional_unbold(n);
4652 }
4653 }
4654 else {
4655 units offset;
4656 if (get_number(&offset, 'u') && offset >= 1)
4657 font_table[n]->set_bold(hunits(offset - 1));
4658 else
4659 font_table[n]->unbold();
4660 }
4661 }
4662 else
4663 font_table[n]->unbold();
4664 }
4665 skip_line();
4666 }
4667
track_kerning_function()4668 track_kerning_function::track_kerning_function() : non_zero(0)
4669 {
4670 }
4671
track_kerning_function(int min_s,hunits min_a,int max_s,hunits max_a)4672 track_kerning_function::track_kerning_function(int min_s, hunits min_a,
4673 int max_s, hunits max_a)
4674 : non_zero(1),
4675 min_size(min_s), min_amount(min_a),
4676 max_size(max_s), max_amount(max_a)
4677 {
4678 }
4679
operator ==(const track_kerning_function & tk)4680 int track_kerning_function::operator==(const track_kerning_function &tk)
4681 {
4682 if (non_zero)
4683 return (tk.non_zero
4684 && min_size == tk.min_size
4685 && min_amount == tk.min_amount
4686 && max_size == tk.max_size
4687 && max_amount == tk.max_amount);
4688 else
4689 return !tk.non_zero;
4690 }
4691
operator !=(const track_kerning_function & tk)4692 int track_kerning_function::operator!=(const track_kerning_function &tk)
4693 {
4694 if (non_zero)
4695 return (!tk.non_zero
4696 || min_size != tk.min_size
4697 || min_amount != tk.min_amount
4698 || max_size != tk.max_size
4699 || max_amount != tk.max_amount);
4700 else
4701 return tk.non_zero;
4702 }
4703
compute(int size)4704 hunits track_kerning_function::compute(int size)
4705 {
4706 if (non_zero) {
4707 if (max_size <= min_size)
4708 return min_amount;
4709 else if (size <= min_size)
4710 return min_amount;
4711 else if (size >= max_size)
4712 return max_amount;
4713 else
4714 return (scale(max_amount, size - min_size, max_size - min_size)
4715 + scale(min_amount, max_size - size, max_size - min_size));
4716 }
4717 else
4718 return H0;
4719 }
4720
track_kern()4721 void track_kern()
4722 {
4723 int n = get_fontno();
4724 if (n >= 0) {
4725 int min_s, max_s;
4726 hunits min_a, max_a;
4727 if (has_arg()
4728 && get_number(&min_s, 'z')
4729 && get_hunits(&min_a, 'p')
4730 && get_number(&max_s, 'z')
4731 && get_hunits(&max_a, 'p')) {
4732 track_kerning_function tk(min_s, min_a, max_s, max_a);
4733 font_table[n]->set_track_kern(tk);
4734 }
4735 else {
4736 track_kerning_function tk;
4737 font_table[n]->set_track_kern(tk);
4738 }
4739 }
4740 skip_line();
4741 }
4742
constant_space()4743 void constant_space()
4744 {
4745 int n = get_fontno();
4746 if (n >= 0) {
4747 int x, y;
4748 if (!has_arg() || !get_integer(&x))
4749 font_table[n]->set_constant_space(CONSTANT_SPACE_NONE);
4750 else {
4751 if (!has_arg() || !get_number(&y, 'z'))
4752 font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x);
4753 else
4754 font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE,
4755 scale(y*x,
4756 units_per_inch,
4757 36*72*sizescale));
4758 }
4759 }
4760 skip_line();
4761 }
4762
ligature()4763 void ligature()
4764 {
4765 int lig;
4766 if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2)
4767 global_ligature_mode = lig;
4768 else
4769 global_ligature_mode = 1;
4770 skip_line();
4771 }
4772
kern_request()4773 void kern_request()
4774 {
4775 int k;
4776 if (has_arg() && get_integer(&k))
4777 global_kern_mode = k != 0;
4778 else
4779 global_kern_mode = 1;
4780 skip_line();
4781 }
4782
set_soft_hyphen_char()4783 void set_soft_hyphen_char()
4784 {
4785 soft_hyphen_char = get_optional_char();
4786 if (!soft_hyphen_char)
4787 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
4788 skip_line();
4789 }
4790
init_output()4791 void init_output()
4792 {
4793 if (suppress_output_flag)
4794 the_output = new suppress_output_file;
4795 else if (ascii_output_flag)
4796 the_output = new ascii_output_file;
4797 else
4798 the_output = new troff_output_file;
4799 }
4800
4801 class next_available_font_position_reg : public reg {
4802 public:
4803 const char *get_string();
4804 };
4805
get_string()4806 const char *next_available_font_position_reg::get_string()
4807 {
4808 return itoa(next_available_font_position());
4809 }
4810
4811 class printing_reg : public reg {
4812 public:
4813 const char *get_string();
4814 };
4815
get_string()4816 const char *printing_reg::get_string()
4817 {
4818 if (the_output)
4819 return the_output->is_printing() ? "1" : "0";
4820 else
4821 return "0";
4822 }
4823
init_node_requests()4824 void init_node_requests()
4825 {
4826 init_request("fp", font_position);
4827 init_request("sty", style);
4828 init_request("cs", constant_space);
4829 init_request("bd", bold_font);
4830 init_request("uf", underline_font);
4831 init_request("lg", ligature);
4832 init_request("kern", kern_request);
4833 init_request("tkf", track_kern);
4834 init_request("special", special_request);
4835 init_request("fspecial", font_special_request);
4836 init_request("ftr", font_translate);
4837 init_request("shc", set_soft_hyphen_char);
4838 number_reg_dictionary.define(".fp", new next_available_font_position_reg);
4839 number_reg_dictionary.define(".kern",
4840 new constant_int_reg(&global_kern_mode));
4841 number_reg_dictionary.define(".lg",
4842 new constant_int_reg(&global_ligature_mode));
4843 number_reg_dictionary.define(".P", new printing_reg);
4844 soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL);
4845 }
4846