7b5ae3a6118f885c75c522fe863eb12bae5e27cd
[platform/upstream/groff.git] / src / preproc / eqn / limit.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 limit_box : public box {
24 private:
25   box *p;
26   box *from;
27   box *to;
28 public:
29   limit_box(box *, box *, box *);
30   ~limit_box();
31   int compute_metrics(int);
32   void output();
33   void debug_print();
34   void check_tabs(int);
35 };
36
37 box *make_limit_box(box *pp, box *qq, box *rr)
38 {
39   return new limit_box(pp, qq, rr);
40 }
41
42 limit_box::limit_box(box *pp, box *qq, box *rr)
43 : p(pp), from(qq), to(rr)
44 {
45   spacing_type = p->spacing_type;
46 }
47
48 limit_box::~limit_box()
49 {
50   delete p;
51   delete from;
52   delete to;
53 }
54
55 int limit_box::compute_metrics(int style)
56 {
57   printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
58   if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
59     set_script_size();
60   printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
61   int res = 0;
62   int mark_uid = -1;
63   if (from != 0) {
64     res = from->compute_metrics(cramped_style(script_style(style)));
65     if (res)
66       mark_uid = from->uid;
67   }
68   if (to != 0) {
69     int r = to->compute_metrics(script_style(style));
70     if (res && r)
71       error("multiple marks and lineups");
72     else  {
73       mark_uid = to->uid;
74       res = r;
75     }
76   }
77   printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
78   int r = p->compute_metrics(style);
79   p->compute_subscript_kern();
80   if (res && r)
81     error("multiple marks and lineups");
82   else {
83     mark_uid = p->uid;
84     res = r;
85   }
86   printf(".nr " LEFT_WIDTH_FORMAT " "
87          "0\\n[" WIDTH_FORMAT "]",
88          uid, p->uid);
89   if (from != 0)
90     printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
91            p->uid, from->uid);
92   if (to != 0)
93     printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
94            p->uid, to->uid);
95   printf("/2\n");
96   printf(".nr " WIDTH_FORMAT " "
97          "0\\n[" WIDTH_FORMAT "]",
98          uid, p->uid);
99   if (from != 0)
100     printf(">?(-\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
101            p->uid, from->uid);
102   if (to != 0)
103     printf(">?(\\n[" SUB_KERN_FORMAT "]+\\n[" WIDTH_FORMAT "])",
104            p->uid, to->uid);
105   printf("/2+\\n[" LEFT_WIDTH_FORMAT "]\n", uid);
106   printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
107   if (to != 0)
108     printf(">?\\n[" WIDTH_FORMAT "]", to->uid);
109   if (from != 0)
110     printf(">?\\n[" WIDTH_FORMAT "]", from->uid);
111   printf("\n");
112   if (res)
113     printf(".nr " MARK_REG " +(\\n[" LEFT_WIDTH_FORMAT "]"
114            "-(\\n[" WIDTH_FORMAT "]/2))\n",
115            uid, mark_uid);
116   if (to != 0) {
117     printf(".nr " SUP_RAISE_FORMAT " %dM+\\n[" DEPTH_FORMAT
118            "]>?%dM+\\n[" HEIGHT_FORMAT "]\n",
119            uid, big_op_spacing1, to->uid, big_op_spacing3, p->uid);
120     printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
121            HEIGHT_FORMAT "]+%dM\n",
122            uid, uid, to->uid, big_op_spacing5);
123   }
124   else
125     printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
126   if (from != 0) {
127     printf(".nr " SUB_LOWER_FORMAT " %dM+\\n[" HEIGHT_FORMAT
128            "]>?%dM+\\n[" DEPTH_FORMAT "]\n",
129            uid, big_op_spacing2, from->uid, big_op_spacing4, p->uid);
130     printf(".nr " DEPTH_FORMAT " \\n[" SUB_LOWER_FORMAT "]+\\n["
131            DEPTH_FORMAT "]+%dM\n",
132            uid, uid, from->uid, big_op_spacing5);
133   }
134   else
135     printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
136   return res;
137 }
138
139 void limit_box::output()
140 {
141   if (output_format == troff) {
142     printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
143     if (to != 0) {
144       printf("\\Z" DELIMITER_CHAR);
145       printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
146       printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u"
147              "+(-\\n[" WIDTH_FORMAT "]u+\\n[" SUB_KERN_FORMAT "]u/2u)'",
148              uid, to->uid, p->uid);
149       to->output();
150       printf(DELIMITER_CHAR);
151     }
152     if (from != 0) {
153       printf("\\Z" DELIMITER_CHAR);
154       printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
155       printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u"
156              "+(-\\n[" SUB_KERN_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u)'",
157              uid, p->uid, from->uid);
158       from->output();
159       printf(DELIMITER_CHAR);
160     }
161     printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
162     printf("\\Z" DELIMITER_CHAR);
163     printf("\\h'\\n[" LEFT_WIDTH_FORMAT "]u"
164            "-(\\n[" WIDTH_FORMAT "]u/2u)'",
165            uid, p->uid);
166     p->output();
167     printf(DELIMITER_CHAR);
168     printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
169   }
170   else if (output_format == mathml) {
171     if (from != 0 && to != 0) {
172       printf("<munderover>");
173       p->output();
174       from->output();
175       to->output();
176       printf("</munderover>");
177     }
178     else if (from != 0) {
179       printf("<munder>");
180       p->output();
181       from->output();
182       printf("</munder>");
183     }
184     else if (to != 0) {
185       printf("<mover>");
186       p->output();
187       to->output();
188       printf("</mover>");
189     }
190   }
191 }
192
193 void limit_box::debug_print()
194 {
195   fprintf(stderr, "{ ");
196   p->debug_print();
197   fprintf(stderr, " }");
198   if (from) {
199     fprintf(stderr, " from { ");
200     from->debug_print();
201     fprintf(stderr, " }");
202   }
203   if (to) {
204     fprintf(stderr, " to { ");
205     to->debug_print();
206     fprintf(stderr, " }");
207   }
208 }
209
210 void limit_box::check_tabs(int level)
211 {
212   if (to)
213     to->check_tabs(level + 1);
214   if (from)
215     from->check_tabs(level + 1);
216   p->check_tabs(level + 1);
217 }