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