Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / preproc / eqn / script.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004
3    Free Software Foundation, Inc.
4      Written by James Clark (jjc@jclark.com)
5
6 This file is part of groff.
7
8 groff is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 groff is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with groff; see the file COPYING.  If not, write to the Free Software
20 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21
22 #include "eqn.h"
23 #include "pbox.h"
24
25 class script_box : public pointer_box {
26 private:
27   box *sub;
28   box *sup;
29 public:
30   script_box(box *, box *, box *);
31   ~script_box();
32   int compute_metrics(int);
33   void output();
34   void debug_print();
35   int left_is_italic();
36   void hint(unsigned);
37   void check_tabs(int);
38 };
39
40 /* The idea is that the script should attach to the rightmost box
41 of a list. For example, given `2x sup 3', the superscript should
42 attach to `x' rather than `2x'. */
43
44 box *make_script_box(box *nuc, box *sub, box *sup)
45 {
46   list_box *b = nuc->to_list_box();
47   if (b != 0) {
48     b->list.p[b->list.len-1] = make_script_box(b->list.p[b->list.len - 1],
49                                                sub,
50                                                sup);
51     return b;
52   }
53   else
54     return new script_box(nuc, sub, sup);
55 }
56
57 script_box::script_box(box *pp, box *qq, box *rr)
58 : pointer_box(pp), sub(qq), sup(rr)
59 {
60 }
61
62 script_box::~script_box()
63 {
64   delete sub;
65   delete sup;
66 }
67
68 int script_box::left_is_italic()
69 {
70   return p->left_is_italic();
71 }
72
73 int script_box::compute_metrics(int style)
74 {
75   int res = p->compute_metrics(style);
76   p->compute_subscript_kern();
77   printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
78   if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
79     set_script_size();
80   printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
81   if (sub != 0)
82     sub->compute_metrics(cramped_style(script_style(style)));
83   if (sup != 0)
84     sup->compute_metrics(script_style(style));
85   // 18a
86   if (p->is_char()) {
87     printf(".nr " SUP_RAISE_FORMAT " 0\n", uid);
88     printf(".nr " SUB_LOWER_FORMAT " 0\n", uid);
89   }
90   else {
91     printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
92            uid, p->uid, sup_drop);
93     printf(".nr " SUB_LOWER_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
94            uid, p->uid, sub_drop);
95   }
96   printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
97   if (sup == 0) {
98     assert(sub != 0);
99     // 18b
100     printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM>?(\\n["
101            HEIGHT_FORMAT "]-(%dM*4/5))\n",
102            uid, uid, sub1, sub->uid, x_height);
103   }
104   else {
105     // sup != 0
106     // 18c
107     int pos;
108     if (style == DISPLAY_STYLE)
109       pos = sup1;
110     else if (style & 1)         // not cramped
111       pos = sup2;
112     else
113       pos = sup3;
114     printf(".nr " SUP_RAISE_FORMAT " \\n[" SUP_RAISE_FORMAT
115            "]>?%dM>?(\\n[" DEPTH_FORMAT "]+(%dM/4))\n",
116            uid, uid, pos, sup->uid, x_height);
117     // 18d
118     if (sub != 0) {
119       printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM\n",
120              uid, uid, sub2);
121       // 18e
122       printf(".nr " TEMP_REG " \\n[" DEPTH_FORMAT "]-\\n["
123              SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]-\\n["
124              SUB_LOWER_FORMAT "]+(4*%dM)\n",
125              sup->uid, uid, sub->uid, uid, default_rule_thickness);
126       printf(".if \\n[" TEMP_REG "] \\{");
127       printf(".nr " SUB_LOWER_FORMAT " +\\n[" TEMP_REG "]\n", uid);
128       printf(".nr " TEMP_REG " (%dM*4/5)-\\n[" SUP_RAISE_FORMAT
129              "]+\\n[" DEPTH_FORMAT "]>?0\n",
130              x_height, uid, sup->uid);
131       printf(".nr " SUP_RAISE_FORMAT " +\\n[" TEMP_REG "]\n", uid);
132       printf(".nr " SUB_LOWER_FORMAT " -\\n[" TEMP_REG "]\n", uid);
133       printf(".\\}\n");
134     }
135   }
136   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
137   if (sub != 0 && sup != 0)
138     printf("+((\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]>?\\n["
139            WIDTH_FORMAT "])+%dM)>?0\n",
140            sub->uid, p->uid, sup->uid, script_space);
141   else if (sub != 0)
142     printf("+(\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]+%dM)>?0\n",
143            sub->uid, p->uid, script_space);
144   else if (sup != 0)
145     printf("+(\\n[" WIDTH_FORMAT "]+%dM)>?0\n", sup->uid, script_space);
146   else
147     printf("\n");
148   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]",
149          uid, p->uid);
150   if (sup != 0)
151     printf(">?(\\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
152            uid, sup->uid);
153   if (sub != 0)
154     printf(">?(-\\n[" SUB_LOWER_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
155            uid, sub->uid);
156   printf("\n");
157   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]",
158          uid, p->uid);
159   if (sub != 0)
160     printf(">?(\\n[" SUB_LOWER_FORMAT "]+\\n[" DEPTH_FORMAT "])",
161            uid, sub->uid);
162   if (sup != 0)
163     printf(">?(-\\n[" SUP_RAISE_FORMAT "]+\\n[" DEPTH_FORMAT "])",
164            uid, sup->uid);
165   printf("\n");
166   return res;
167 }
168
169 void script_box::output()
170 {
171   p->output();
172   if (sup != 0) {
173     printf("\\Z" DELIMITER_CHAR);
174     printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
175     printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
176     sup->output();
177     printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
178     printf(DELIMITER_CHAR);
179   }
180   if (sub != 0) {
181     printf("\\Z" DELIMITER_CHAR);
182     printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
183     printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
184     printf("\\h'-\\n[" SUB_KERN_FORMAT "]u'", p->uid);
185     sub->output();
186     printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
187     printf(DELIMITER_CHAR);
188   }
189   printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
190          uid, p->uid);
191 }
192
193 void script_box::hint(unsigned flags)
194 {
195   p->hint(flags & ~HINT_NEXT_IS_ITALIC);
196 }
197
198 void script_box::debug_print()
199 {
200   fprintf(stderr, "{ ");
201   p->debug_print();
202   fprintf(stderr, " }");
203   if (sub) {
204     fprintf(stderr, " sub { ");
205     sub->debug_print();
206     fprintf(stderr, " }");
207   }
208   if (sup) {
209     fprintf(stderr, " sup { ");
210     sup->debug_print();
211     fprintf(stderr, " }");
212   }
213 }
214
215 void script_box::check_tabs(int level)
216 {
217   if (sup)
218     sup->check_tabs(level + 1);
219   if (sub)
220     sub->check_tabs(level + 1);
221   p->check_tabs(level);
222 }