Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / groff / src / preproc / eqn / script.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004, 2007, 2008, 2009
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 3 of the License, or
11 (at your option) any later 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
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20
21 #include "eqn.h"
22 #include "pbox.h"
23
24 class script_box : public pointer_box {
25 private:
26   box *sub;
27   box *sup;
28 public:
29   script_box(box *, box *, box *);
30   ~script_box();
31   int compute_metrics(int);
32   void output();
33   void debug_print();
34   int left_is_italic();
35   void hint(unsigned);
36   void check_tabs(int);
37 };
38
39 /* The idea is that the script should attach to the rightmost box
40 of a list. For example, given `2x sup 3', the superscript should
41 attach to `x' rather than `2x'. */
42
43 box *make_script_box(box *nuc, box *sub, box *sup)
44 {
45   list_box *b = nuc->to_list_box();
46   if (b != 0) {
47     b->list.p[b->list.len-1] = make_script_box(b->list.p[b->list.len - 1],
48                                                sub,
49                                                sup);
50     return b;
51   }
52   else
53     return new script_box(nuc, sub, sup);
54 }
55
56 script_box::script_box(box *pp, box *qq, box *rr)
57 : pointer_box(pp), sub(qq), sup(rr)
58 {
59 }
60
61 script_box::~script_box()
62 {
63   delete sub;
64   delete sup;
65 }
66
67 int script_box::left_is_italic()
68 {
69   return p->left_is_italic();
70 }
71
72 int script_box::compute_metrics(int style)
73 {
74   int res = p->compute_metrics(style);
75   p->compute_subscript_kern();
76   printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
77   if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
78     set_script_size();
79   printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
80   if (sub != 0)
81     sub->compute_metrics(cramped_style(script_style(style)));
82   if (sup != 0)
83     sup->compute_metrics(script_style(style));
84   // 18a
85   if (p->is_char()) {
86     printf(".nr " SUP_RAISE_FORMAT " 0\n", uid);
87     printf(".nr " SUB_LOWER_FORMAT " 0\n", uid);
88   }
89   else {
90     printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
91            uid, p->uid, sup_drop);
92     printf(".nr " SUB_LOWER_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
93            uid, p->uid, sub_drop);
94   }
95   printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
96   if (sup == 0) {
97     assert(sub != 0);
98     // 18b
99     printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM>?(\\n["
100            HEIGHT_FORMAT "]-(%dM*4/5))\n",
101            uid, uid, sub1, sub->uid, x_height);
102   }
103   else {
104     // sup != 0
105     // 18c
106     int pos;
107     if (style == DISPLAY_STYLE)
108       pos = sup1;
109     else if (style & 1)         // not cramped
110       pos = sup2;
111     else
112       pos = sup3;
113     printf(".nr " SUP_RAISE_FORMAT " \\n[" SUP_RAISE_FORMAT
114            "]>?%dM>?(\\n[" DEPTH_FORMAT "]+(%dM/4))\n",
115            uid, uid, pos, sup->uid, x_height);
116     // 18d
117     if (sub != 0) {
118       printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM\n",
119              uid, uid, sub2);
120       // 18e
121       printf(".nr " TEMP_REG " \\n[" DEPTH_FORMAT "]-\\n["
122              SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]-\\n["
123              SUB_LOWER_FORMAT "]+(4*%dM)\n",
124              sup->uid, uid, sub->uid, uid, default_rule_thickness);
125       printf(".if \\n[" TEMP_REG "] \\{");
126       printf(".nr " SUB_LOWER_FORMAT " +\\n[" TEMP_REG "]\n", uid);
127       printf(".nr " TEMP_REG " (%dM*4/5)-\\n[" SUP_RAISE_FORMAT
128              "]+\\n[" DEPTH_FORMAT "]>?0\n",
129              x_height, uid, sup->uid);
130       printf(".nr " SUP_RAISE_FORMAT " +\\n[" TEMP_REG "]\n", uid);
131       printf(".nr " SUB_LOWER_FORMAT " -\\n[" TEMP_REG "]\n", uid);
132       printf(".\\}\n");
133     }
134   }
135   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
136   if (sub != 0 && sup != 0)
137     printf("+((\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]>?\\n["
138            WIDTH_FORMAT "])+%dM)>?0\n",
139            sub->uid, p->uid, sup->uid, script_space);
140   else if (sub != 0)
141     printf("+(\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]+%dM)>?0\n",
142            sub->uid, p->uid, script_space);
143   else if (sup != 0)
144     printf("+(\\n[" WIDTH_FORMAT "]+%dM)>?0\n", sup->uid, script_space);
145   else
146     printf("\n");
147   printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]",
148          uid, p->uid);
149   if (sup != 0)
150     printf(">?(\\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
151            uid, sup->uid);
152   if (sub != 0)
153     printf(">?(-\\n[" SUB_LOWER_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
154            uid, sub->uid);
155   printf("\n");
156   printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]",
157          uid, p->uid);
158   if (sub != 0)
159     printf(">?(\\n[" SUB_LOWER_FORMAT "]+\\n[" DEPTH_FORMAT "])",
160            uid, sub->uid);
161   if (sup != 0)
162     printf(">?(-\\n[" SUP_RAISE_FORMAT "]+\\n[" DEPTH_FORMAT "])",
163            uid, sup->uid);
164   printf("\n");
165   return res;
166 }
167
168 void script_box::output()
169 {
170   if (output_format == troff) {
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   else if (output_format == mathml) {
193     if (sup != 0 && sub != 0) {
194       printf("<msubsup>");
195       p->output();
196       sub->output();
197       sup->output();
198       printf("</msubsup>");
199     }
200     else if (sup != 0) {
201       printf("<msup>");
202       p->output();
203       sup->output();
204       printf("</msup>");
205   }
206   else if (sub != 0) {
207       printf("<msub>");
208       p->output();
209       sub->output();
210       printf("</msub>");
211     }
212   }
213 }
214
215 void script_box::hint(unsigned flags)
216 {
217   p->hint(flags & ~HINT_NEXT_IS_ITALIC);
218 }
219
220 void script_box::debug_print()
221 {
222   fprintf(stderr, "{ ");
223   p->debug_print();
224   fprintf(stderr, " }");
225   if (sub) {
226     fprintf(stderr, " sub { ");
227     sub->debug_print();
228     fprintf(stderr, " }");
229   }
230   if (sup) {
231     fprintf(stderr, " sup { ");
232     sup->debug_print();
233     fprintf(stderr, " }");
234   }
235 }
236
237 void script_box::check_tabs(int level)
238 {
239   if (sup)
240     sup->check_tabs(level + 1);
241   if (sub)
242     sub->check_tabs(level + 1);
243   p->check_tabs(level);
244 }