1// -*- C++ -*-
2/* Copyright (C) 1989, 1990, 1991, 1992, 2002 Free Software Foundation, Inc.
3     Written by James Clark (jjc@jclark.com)
4
5This file is part of groff.
6
7groff is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12groff is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License along
18with groff; see the file COPYING.  If not, write to the Free Software
19Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
20
21#include "eqn.h"
22#include "pbox.h"
23
24class accent_box : public pointer_box {
25private:
26  box *ab;
27public:
28  accent_box(box *, box *);
29  ~accent_box();
30  int compute_metrics(int);
31  void output();
32  void debug_print();
33  void check_tabs(int);
34};
35
36box *make_accent_box(box *p, box *q)
37{
38  return new accent_box(p, q);
39}
40
41accent_box::accent_box(box *pp, box *qq) : pointer_box(pp), ab(qq)
42{
43}
44
45accent_box::~accent_box()
46{
47  delete ab;
48}
49
50#if 0
51int accent_box::compute_metrics(int style)
52{
53  int r = p->compute_metrics(style);
54  p->compute_skew();
55  ab->compute_metrics(style);
56  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
57  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
58  printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
59	 uid, p->uid, x_height);
60  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
61	 SUP_RAISE_FORMAT "]\n",
62	 uid, ab->uid, uid);
63  return r;
64}
65
66void accent_box::output()
67{
68  printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n["
69	 SKEW_FORMAT "]u'",
70	 p->uid, ab->uid, p->uid);
71  printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
72  ab->output();
73  printf("\\h'-\\n[" WIDTH_FORMAT "]u'", ab->uid);
74  printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
75  printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u+\\n["
76	 SKEW_FORMAT "]u)'",
77	 p->uid, ab->uid, p->uid);
78  p->output();
79}
80#endif
81
82/* This version copes with the possibility of an accent's being wider
83than its accentee.  LEFT_WIDTH_FORMAT gives the distance from the
84left edge of the resulting box to the middle of the accentee's box.*/
85
86int accent_box::compute_metrics(int style)
87{
88  int r = p->compute_metrics(style);
89  p->compute_skew();
90  ab->compute_metrics(style);
91  printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
92	 ">?(\\n[" WIDTH_FORMAT "]/2-\\n[" SKEW_FORMAT "])\n",
93	 uid, p->uid, ab->uid, p->uid);
94  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
95	 ">?(\\n[" WIDTH_FORMAT "]/2+\\n[" SKEW_FORMAT "])"
96	 "+\\n[" LEFT_WIDTH_FORMAT "]\n",
97	 uid, p->uid, ab->uid, p->uid, uid);
98  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
99  printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
100	 uid, p->uid, x_height);
101  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
102	 SUP_RAISE_FORMAT "]\n",
103	 uid, ab->uid, uid);
104  if (r)
105    printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]"
106	   "-(\\n[" WIDTH_FORMAT "]/2)'\n",
107	   uid, p->uid);
108  return r;
109}
110
111void accent_box::output()
112{
113  printf("\\Z" DELIMITER_CHAR);
114  printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u+\\n[" SKEW_FORMAT "]u"
115	 "-(\\n[" WIDTH_FORMAT "]u/2u)'",
116	 uid, p->uid, ab->uid);
117  printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
118  ab->output();
119  printf(DELIMITER_CHAR);
120  printf("\\Z" DELIMITER_CHAR);
121  printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
122	 uid, p->uid);
123  p->output();
124  printf(DELIMITER_CHAR);
125  printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
126}
127
128void accent_box::check_tabs(int level)
129{
130  ab->check_tabs(level + 1);
131  p->check_tabs(level + 1);
132}
133
134void accent_box::debug_print()
135{
136  fprintf(stderr, "{ ");
137  p->debug_print();
138  fprintf(stderr, " } accent { ");
139  ab->debug_print();
140  fprintf(stderr, " }");
141}
142
143class overline_char_box : public simple_box {
144public:
145  overline_char_box();
146  void output();
147  void debug_print();
148};
149
150overline_char_box::overline_char_box()
151{
152}
153
154void overline_char_box::output()
155{
156  printf("\\v'-%dM/2u-%dM'", 7*default_rule_thickness, x_height);
157  printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"),
158	 accent_width);
159  printf("\\v'%dM/2u+%dM'", 7*default_rule_thickness, x_height);
160}
161
162void overline_char_box::debug_print()
163{
164  fprintf(stderr, "<overline char>");
165}
166
167class overline_box : public pointer_box {
168public:
169  overline_box(box *);
170  int compute_metrics(int);
171  void output();
172  void debug_print();
173};
174
175box *make_overline_box(box *p)
176{
177  if (p->is_char())
178    return new accent_box(p, new overline_char_box);
179  else
180    return new overline_box(p);
181}
182
183overline_box::overline_box(box *pp) : pointer_box(pp)
184{
185}
186
187int overline_box::compute_metrics(int style)
188{
189  int r = p->compute_metrics(cramped_style(style));
190  // 9
191  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+%dM\n",
192	 uid, p->uid, default_rule_thickness*5);
193  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
194  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
195  return r;
196}
197
198void overline_box::output()
199{
200  // 9
201  printf("\\Z" DELIMITER_CHAR);
202  printf("\\v'-\\n[" HEIGHT_FORMAT "]u-(%dM/2u)'",
203	 p->uid, 7*default_rule_thickness);
204  if (draw_flag)
205    printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid);
206  else
207    printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid);
208  printf(DELIMITER_CHAR);
209  p->output();
210}
211
212void overline_box::debug_print()
213{
214  fprintf(stderr, "{ ");
215  p->debug_print();
216  fprintf(stderr, " } bar");
217}
218
219class uaccent_box : public pointer_box {
220  box *ab;
221public:
222  uaccent_box(box *, box *);
223  ~uaccent_box();
224  int compute_metrics(int);
225  void output();
226  void compute_subscript_kern();
227  void check_tabs(int);
228  void debug_print();
229};
230
231box *make_uaccent_box(box *p, box *q)
232{
233  return new uaccent_box(p, q);
234}
235
236uaccent_box::uaccent_box(box *pp, box *qq)
237: pointer_box(pp), ab(qq)
238{
239}
240
241uaccent_box::~uaccent_box()
242{
243  delete ab;
244}
245
246int uaccent_box::compute_metrics(int style)
247{
248  int r = p->compute_metrics(style);
249  ab->compute_metrics(style);
250  printf(".nr " LEFT_WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
251	 ">?(\\n[" WIDTH_FORMAT "]/2)\n",
252	 uid, p->uid, ab->uid);
253  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]/2"
254	 ">?(\\n[" WIDTH_FORMAT "]/2)"
255	 "+\\n[" LEFT_WIDTH_FORMAT "]\n",
256	 uid, p->uid, ab->uid, uid);
257  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
258  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]"
259	 "+\\n[" DEPTH_FORMAT "]\n",
260	 uid, p->uid, ab->uid);
261  if (r)
262    printf(".nr " MARK_REG " +\\n[" LEFT_WIDTH_FORMAT "]"
263	   "-(\\n[" WIDTH_FORMAT "]/2)'\n",
264	   uid, p->uid);
265  return r;
266}
267
268void uaccent_box::output()
269{
270  printf("\\Z" DELIMITER_CHAR);
271  printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
272	 uid, ab->uid);
273  printf("\\v'\\n[" DEPTH_FORMAT "]u'", p->uid);
274  ab->output();
275  printf(DELIMITER_CHAR);
276  printf("\\Z" DELIMITER_CHAR);
277  printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u-(\\n[" WIDTH_FORMAT "]u/2u)'",
278	 uid, p->uid);
279  p->output();
280  printf(DELIMITER_CHAR);
281  printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
282}
283
284void uaccent_box::check_tabs(int level)
285{
286  ab->check_tabs(level + 1);
287  p->check_tabs(level + 1);
288}
289
290void uaccent_box::compute_subscript_kern()
291{
292  box::compute_subscript_kern(); // want 0 subscript kern
293}
294
295void uaccent_box::debug_print()
296{
297  fprintf(stderr, "{ ");
298  p->debug_print();
299  fprintf(stderr, " } uaccent { ");
300  ab->debug_print();
301  fprintf(stderr, " }");
302}
303
304class underline_char_box : public simple_box {
305public:
306  underline_char_box();
307  void output();
308  void debug_print();
309};
310
311underline_char_box::underline_char_box()
312{
313}
314
315void underline_char_box::output()
316{
317  printf("\\v'%dM/2u'", 7*default_rule_thickness);
318  printf((draw_flag ? "\\D'l%dM 0'" : "\\l'%dM\\&\\(ru'"),
319	 accent_width);
320  printf("\\v'-%dM/2u'", 7*default_rule_thickness);
321}
322
323void underline_char_box::debug_print()
324{
325  fprintf(stderr, "<underline char>");
326}
327
328
329class underline_box : public pointer_box {
330public:
331  underline_box(box *);
332  int compute_metrics(int);
333  void output();
334  void compute_subscript_kern();
335  void debug_print();
336};
337
338box *make_underline_box(box *p)
339{
340  if (p->is_char())
341    return new uaccent_box(p, new underline_char_box);
342  else
343    return new underline_box(p);
344}
345
346underline_box::underline_box(box *pp) : pointer_box(pp)
347{
348}
349
350int underline_box::compute_metrics(int style)
351{
352  int r = p->compute_metrics(style);
353  // 10
354  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
355	 uid, p->uid, default_rule_thickness*5);
356  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
357  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
358  return r;
359}
360
361void underline_box::output()
362{
363  // 10
364  printf("\\Z" DELIMITER_CHAR);
365  printf("\\v'\\n[" DEPTH_FORMAT "]u+(%dM/2u)'",
366	 p->uid, 7*default_rule_thickness);
367  if (draw_flag)
368    printf("\\D'l\\n[" WIDTH_FORMAT "]u 0'", p->uid);
369  else
370    printf("\\l'\\n[" WIDTH_FORMAT "]u\\&\\(ru'", p->uid);
371  printf(DELIMITER_CHAR);
372  p->output();
373}
374
375// we want an underline box to have 0 subscript kern
376
377void underline_box::compute_subscript_kern()
378{
379  box::compute_subscript_kern();
380}
381
382void underline_box::debug_print()
383{
384  fprintf(stderr, "{ ");
385  p->debug_print();
386  fprintf(stderr, " } under");
387}
388
389size_box::size_box(char *s, box *pp) : pointer_box(pp), size(s)
390{
391}
392
393int size_box::compute_metrics(int style)
394{
395  printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
396  printf(".ps %s\n", size);
397  printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
398  int r = p->compute_metrics(style);
399  printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
400  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
401  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
402  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
403  return r;
404}
405
406void size_box::output()
407{
408  printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
409  p->output();
410  printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
411}
412
413size_box::~size_box()
414{
415  a_delete size;
416}
417
418void size_box::debug_print()
419{
420  fprintf(stderr, "size %s { ", size);
421  p->debug_print();
422  fprintf(stderr, " }");
423}
424
425
426font_box::font_box(char *s, box *pp) : pointer_box(pp), f(s)
427{
428}
429
430font_box::~font_box()
431{
432  a_delete f;
433}
434
435int font_box::compute_metrics(int style)
436{
437  const char *old_roman_font = current_roman_font;
438  current_roman_font = f;
439  printf(".nr " FONT_FORMAT " \\n[.f]\n", uid);
440  printf(".ft %s\n", f);
441  int r = p->compute_metrics(style);
442  current_roman_font = old_roman_font;
443  printf(".ft \\n[" FONT_FORMAT "]\n", uid);
444  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
445  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
446  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
447  return r;
448}
449
450void font_box::output()
451{
452  printf("\\f[%s]", f);
453  const char *old_roman_font = current_roman_font;
454  current_roman_font = f;
455  p->output();
456  current_roman_font = old_roman_font;
457  printf("\\f[\\n[" FONT_FORMAT "]]", uid);
458}
459
460void font_box::debug_print()
461{
462  fprintf(stderr, "font %s { ", f);
463  p->debug_print();
464  fprintf(stderr, " }");
465}
466
467fat_box::fat_box(box *pp) : pointer_box(pp)
468{
469}
470
471int fat_box::compute_metrics(int style)
472{
473  int r = p->compute_metrics(style);
474  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n",
475	 uid, p->uid, fat_offset);
476  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
477  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
478  return r;
479}
480
481void fat_box::output()
482{
483  p->output();
484  printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p->uid);
485  printf("\\h'%dM'", fat_offset);
486  p->output();
487}
488
489
490void fat_box::debug_print()
491{
492  fprintf(stderr, "fat { ");
493  p->debug_print();
494  fprintf(stderr, " }");
495}
496
497
498vmotion_box::vmotion_box(int i, box *pp) : pointer_box(pp), n(i)
499{
500}
501
502int vmotion_box::compute_metrics(int style)
503{
504  int r = p->compute_metrics(style);
505  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
506  if (n > 0) {
507    printf(".nr " HEIGHT_FORMAT " %dM+\\n[" HEIGHT_FORMAT "]\n",
508	   uid, n, p->uid);
509    printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
510  }
511  else {
512    printf(".nr " DEPTH_FORMAT " %dM+\\n[" DEPTH_FORMAT "]>?0\n",
513	   uid, -n, p->uid);
514    printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n",
515	   uid, p->uid);
516  }
517  return r;
518}
519
520void vmotion_box::output()
521{
522  printf("\\v'%dM'", -n);
523  p->output();
524  printf("\\v'%dM'", n);
525}
526
527void vmotion_box::debug_print()
528{
529  if (n >= 0)
530    fprintf(stderr, "up %d { ", n);
531  else
532    fprintf(stderr, "down %d { ", -n);
533  p->debug_print();
534  fprintf(stderr, " }");
535}
536
537hmotion_box::hmotion_box(int i, box *pp) : pointer_box(pp), n(i)
538{
539}
540
541int hmotion_box::compute_metrics(int style)
542{
543  int r = p->compute_metrics(style);
544  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]+%dM\n",
545	 uid, p->uid, n);
546  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
547  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
548  if (r)
549    printf(".nr " MARK_REG " +%dM\n", n);
550  return r;
551}
552
553void hmotion_box::output()
554{
555  printf("\\h'%dM'", n);
556  p->output();
557}
558
559void hmotion_box::debug_print()
560{
561  if (n >= 0)
562    fprintf(stderr, "fwd %d { ", n);
563  else
564    fprintf(stderr, "back %d { ", -n);
565  p->debug_print();
566  fprintf(stderr, " }");
567}
568
569vcenter_box::vcenter_box(box *pp) : pointer_box(pp)
570{
571}
572
573int vcenter_box::compute_metrics(int style)
574{
575  int r = p->compute_metrics(style);
576  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
577  printf(".nr " SUP_RAISE_FORMAT " \\n[" DEPTH_FORMAT "]-\\n["
578	 HEIGHT_FORMAT "]/2+%dM\n",
579	 uid, p->uid, p->uid, axis_height);
580  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]+\\n["
581	 SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid);
582  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]-\\n["
583	 SUP_RAISE_FORMAT "]>?0\n", uid, p->uid, uid);
584
585  return r;
586}
587
588void vcenter_box::output()
589{
590  printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
591  p->output();
592  printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
593}
594
595void vcenter_box::debug_print()
596{
597  fprintf(stderr, "vcenter { ");
598  p->debug_print();
599  fprintf(stderr, " }");
600}
601
602