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