Update to groff 1.19.2.
[dragonfly.git] / contrib / groff-1.19 / src / preproc / eqn / over.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989, 1990, 1991, 1992, 2001, 2002
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 over_box : public box {
26 private:
27   int reduce_size;
28   box *num;
29   box *den;
30 public:
31   over_box(int small, box *, box *);
32   ~over_box();
33   void debug_print();
34   int compute_metrics(int);
35   void output();
36   void check_tabs(int);
37 };
38
39 box *make_over_box(box *pp, box *qq)
40 {
41   return new over_box(0, pp, qq);
42 }
43
44 box *make_small_over_box(box *pp, box *qq)
45 {
46   return new over_box(1, pp, qq);
47 }
48
49 over_box::over_box(int is_small, box *pp, box *qq)
50 : reduce_size(is_small), num(pp), den(qq)
51 {
52   spacing_type = INNER_TYPE;
53 }
54
55 over_box::~over_box()
56 {
57   delete num;
58   delete den;
59 }
60
61 int over_box::compute_metrics(int style)
62 {
63   if (reduce_size) {
64     style = script_style(style);
65     printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
66     set_script_size();
67     printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
68   }
69   int mark_uid = 0;
70   int res = num->compute_metrics(style);
71   if (res)
72     mark_uid = num->uid;
73   int r = den->compute_metrics(cramped_style(style));
74   if (r && res)
75     error("multiple marks and lineups");
76   else {
77     mark_uid = den->uid;
78     res = r;
79   }
80   if (reduce_size)
81     printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
82   printf(".nr " WIDTH_FORMAT " (\\n[" WIDTH_FORMAT "]>?\\n[" WIDTH_FORMAT "]", 
83          uid, num->uid, den->uid);
84   // allow for \(ru being wider than both the numerator and denominator
85   if (!draw_flag)
86     fputs(">?\\w" DELIMITER_CHAR "\\(ru" DELIMITER_CHAR, stdout);
87   printf(")+%dM\n", null_delimiter_space*2 + over_hang*2);
88   // 15b
89   printf(".nr " SUP_RAISE_FORMAT " %dM\n",
90          uid, (reduce_size ? num2 : num1));
91   printf(".nr " SUB_LOWER_FORMAT " %dM\n",
92          uid, (reduce_size ? denom2 : denom1));
93
94   // 15d
95   printf(".nr " SUP_RAISE_FORMAT " +(\\n[" DEPTH_FORMAT
96          "]-\\n[" SUP_RAISE_FORMAT "]+%dM+(%dM/2)+%dM)>?0\n",
97          uid, num->uid, uid, axis_height, default_rule_thickness,
98          default_rule_thickness*(reduce_size ? 1 : 3));
99   printf(".nr " SUB_LOWER_FORMAT " +(\\n[" HEIGHT_FORMAT
100          "]-\\n[" SUB_LOWER_FORMAT "]-%dM+(%dM/2)+%dM)>?0\n",
101          uid, den->uid, uid, axis_height, default_rule_thickness,
102          default_rule_thickness*(reduce_size ? 1 : 3));
103
104
105   printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
106          HEIGHT_FORMAT "]\n",
107          uid, uid, num->uid);
108   printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n["
109          DEPTH_FORMAT "]\n",
110          uid, uid, den->uid);
111   if (res)
112     printf(".nr " MARK_REG " +(\\n[" WIDTH_FORMAT "]-\\n["
113            WIDTH_FORMAT "]/2)\n", uid, mark_uid);
114   return res;
115 }
116
117 #define USE_Z
118
119 void over_box::output()
120 {
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
181 void over_box::debug_print()
182 {
183   fprintf(stderr, "{ ");
184   num->debug_print();
185   if (reduce_size)
186     fprintf(stderr, " } smallover { ");
187   else
188     fprintf(stderr, " } over { ");
189   den->debug_print();
190   fprintf(stderr, " }");
191 }
192
193 void over_box::check_tabs(int level)
194 {
195   num->check_tabs(level + 1);
196   den->check_tabs(level + 1);
197 }