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
make_script_box(box * nuc,box * sub,box * sup)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
script_box(box * pp,box * qq,box * rr)57 script_box::script_box(box *pp, box *qq, box *rr)
58 : pointer_box(pp), sub(qq), sup(rr)
59 {
60 }
61
~script_box()62 script_box::~script_box()
63 {
64 delete sub;
65 delete sup;
66 }
67
left_is_italic()68 int script_box::left_is_italic()
69 {
70 return p->left_is_italic();
71 }
72
compute_metrics(int style)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
output()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
hint(unsigned flags)193 void script_box::hint(unsigned flags)
194 {
195 p->hint(flags & ~HINT_NEXT_IS_ITALIC);
196 }
197
debug_print()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
check_tabs(int level)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 }
223