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