groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / src / preproc / eqn / over.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002, 2007, 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 over_box : public box {
25 private:
26   int reduce_size;
27   box *num;
28   box *den;
29 public:
30   over_box(int small, box *, box *);
31   ~over_box();
32   void debug_print();
33   int compute_metrics(int);
34   void output();
35   void check_tabs(int);
36 };
37
38 box *make_over_box(box *pp, box *qq)
39 {
40   return new over_box(0, pp, qq);
41 }
42
43 box *make_small_over_box(box *pp, box *qq)
44 {
45   return new over_box(1, pp, qq);
46 }
47
48 over_box::over_box(int is_small, box *pp, box *qq)
49 : reduce_size(is_small), num(pp), den(qq)
50 {
51   spacing_type = INNER_TYPE;
52 }
53
54 over_box::~over_box()
55 {
56   delete num;
57   delete den;
58 }
59
60 int over_box::compute_metrics(int style)
61 {
62   if (reduce_size) {
63     style = script_style(style);
64     printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
65     set_script_size();
66     printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
67   }
68   int mark_uid = 0;
69   int res = num->compute_metrics(style);
70   if (res)
71     mark_uid = num->uid;
72   int r = den->compute_metrics(cramped_style(style));
73   if (r && res)
74     error("multiple marks and lineups");
75   else {
76     mark_uid = den->uid;
77     res = r;
78   }
79   if (reduce_size)
80     printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
81   printf(".nr " WIDTH_FORMAT " (\\n[" WIDTH_FORMAT "]>?\\n[" WIDTH_FORMAT "]", 
82          uid, num->uid, den->uid);
83   // allow for \(ru being wider than both the numerator and denominator
84   if (!draw_flag)
85     fputs(">?\\w" DELIMITER_CHAR "\\(ru" DELIMITER_CHAR, stdout);
86   printf(")+%dM\n", null_delimiter_space*2 + over_hang*2);
87   // 15b
88   printf(".nr " SUP_RAISE_FORMAT " %dM\n",
89          uid, (reduce_size ? num2 : num1));
90   printf(".nr " SUB_LOWER_FORMAT " %dM\n",
91          uid, (reduce_size ? denom2 : denom1));
92
93   // 15d
94   printf(".nr " SUP_RAISE_FORMAT " +(\\n[" DEPTH_FORMAT
95          "]-\\n[" SUP_RAISE_FORMAT "]+%dM+(%dM/2)+%dM)>?0\n",
96          uid, num->uid, uid, axis_height, default_rule_thickness,
97          default_rule_thickness*(reduce_size ? 1 : 3));
98   printf(".nr " SUB_LOWER_FORMAT " +(\\n[" HEIGHT_FORMAT
99          "]-\\n[" SUB_LOWER_FORMAT "]-%dM+(%dM/2)+%dM)>?0\n",
100          uid, den->uid, uid, axis_height, default_rule_thickness,
101          default_rule_thickness*(reduce_size ? 1 : 3));
102
103
104   printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
105          HEIGHT_FORMAT "]\n",
106          uid, uid, num->uid);
107   printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n["
108          DEPTH_FORMAT "]\n",
109          uid, uid, den->uid);
110   if (res)
111     printf(".nr " MARK_REG " +(\\n[" WIDTH_FORMAT "]-\\n["
112            WIDTH_FORMAT "]/2)\n", uid, mark_uid);
113   return res;
114 }
115
116 #define USE_Z
117
118 void over_box::output()
119 {
120   if (output_format == troff) {
121     if (reduce_size)
122       printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
123   #ifdef USE_Z
124     printf("\\Z" DELIMITER_CHAR);
125   #endif
126     // move up to the numerator baseline
127     printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
128     // move across so that it's centered
129     printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
130            uid, num->uid);
131
132     // print the numerator
133     num->output();
134
135   #ifdef USE_Z
136     printf(DELIMITER_CHAR);
137   #else
138     // back again
139     printf("\\h'-\\n[" WIDTH_FORMAT "]u'", num->uid);
140     printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'",
141            uid, num->uid);
142     // down again
143     printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
144   #endif
145   #ifdef USE_Z
146     printf("\\Z" DELIMITER_CHAR);
147   #endif
148     // move down to the denominator baseline
149     printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
150
151     // move across so that it's centered
152     printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
153            uid, den->uid);
154
155     // print the the denominator
156     den->output();
157
158   #ifdef USE_Z
159     printf(DELIMITER_CHAR);
160   #else
161     // back again
162     printf("\\h'-\\n[" WIDTH_FORMAT "]u'", den->uid);
163     printf("\\h'-(\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'",
164            uid, den->uid);
165     // up again
166     printf("\\v'-\\n[" SUB_LOWER_FORMAT "]u'", uid);
167   #endif
168     if (reduce_size)
169       printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
170     // draw the line
171     printf("\\h'%dM'", null_delimiter_space);
172     printf("\\v'-%dM'", axis_height);
173     fputs(draw_flag ? "\\D'l" : "\\l'", stdout);
174     printf("\\n[" WIDTH_FORMAT "]u-%dM",
175            uid, 2*null_delimiter_space);
176     fputs(draw_flag ? " 0'" : "\\&\\(ru'", stdout);
177     printf("\\v'%dM'", axis_height);
178     printf("\\h'%dM'", null_delimiter_space);
179   }
180   else if (output_format == mathml) {
181     // FIXME: passing a displaystyle attribute doesn't validate.
182     printf("<mfrac>");
183     num->output();
184     den->output();
185     printf("</mfrac>");
186   }
187 }
188
189 void over_box::debug_print()
190 {
191   fprintf(stderr, "{ ");
192   num->debug_print();
193   if (reduce_size)
194     fprintf(stderr, " } smallover { ");
195   else
196     fprintf(stderr, " } over { ");
197   den->debug_print();
198   fprintf(stderr, " }");
199 }
200
201 void over_box::check_tabs(int level)
202 {
203   num->check_tabs(level + 1);
204   den->check_tabs(level + 1);
205 }