Imported Upstream version 1.22.4
[platform/upstream/groff.git] / src / preproc / eqn / pile.cpp
1 // -*- C++ -*-
2 /* Copyright (C) 1989-2018 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 // piles and matrices
20
21 #include "eqn.h"
22 #include "pbox.h"
23
24 // SUP_RAISE_FORMAT gives the first baseline
25 // BASELINE_SEP_FORMAT gives the separation between baselines
26
27 int pile_box::compute_metrics(int style)
28 {
29   int i;
30   for (i = 0; i < col.len; i++)
31     col.p[i]->compute_metrics(style);
32   printf(".nr " WIDTH_FORMAT " 0", uid);
33   for (i = 0; i < col.len; i++)
34     printf(">?\\n[" WIDTH_FORMAT "]", col.p[i]->uid);
35   printf("\n");
36   printf(".nr " BASELINE_SEP_FORMAT " %dM",
37          uid, baseline_sep+col.space);
38   for (i = 1; i < col.len; i++)
39     printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)",
40            col.p[i-1]->uid, col.p[i]->uid, default_rule_thickness*5);
41   // round it so that it's a multiple of the vertical resolution
42   printf("+(\\n(.V/2)/\\n(.V*\\n(.V\n");
43
44   printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2"
45          "+%dM\n",
46          uid, uid, col.len-1, axis_height - shift_down);
47   printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n["
48          HEIGHT_FORMAT "]\n",
49          uid, uid, col.p[0]->uid);
50   printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d+\\n["
51          DEPTH_FORMAT "]-\\n[" SUP_RAISE_FORMAT "]\n",
52          uid, uid, col.len-1, col.p[col.len-1]->uid, uid);
53   return FOUND_NOTHING;
54 }
55
56 void pile_box::output()
57 {
58   if (output_format == troff) {
59     int i;
60     printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
61     for (i = 0; i < col.len; i++) {
62       switch (col.align) {
63       case LEFT_ALIGN:
64         break;
65       case CENTER_ALIGN:
66         printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
67                uid, col.p[i]->uid);
68         break;
69       case RIGHT_ALIGN:
70         printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
71                uid, col.p[i]->uid);
72         break;
73       default:
74         assert(0);
75       }
76       col.p[i]->output();
77       printf("\\h'-\\n[" WIDTH_FORMAT "]u'", col.p[i]->uid);
78       switch (col.align) {
79       case LEFT_ALIGN:
80         break;
81       case CENTER_ALIGN:
82         printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
83                col.p[i]->uid, uid);
84         break;
85       case RIGHT_ALIGN:
86         printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
87                col.p[i]->uid, uid);
88         break;
89       default:
90         assert(0);
91       }
92       if (i != col.len - 1)
93         printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid);
94     }
95     printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
96     printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", col.len - 1, uid);
97     printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid);
98   }
99   else if (output_format == mathml) {
100     const char *av;
101     switch (col.align) {
102     case LEFT_ALIGN:
103       av = "left";
104       break;
105     case RIGHT_ALIGN:
106       av = "right";
107       break;
108     case CENTER_ALIGN:
109       av = "center";
110       break;
111     default:
112       assert(0);
113     }
114     printf("<mtable columnalign='%s'>", av);
115     for (int i = 0; i < col.len; i++) {
116       printf("<mtr><mtd>");
117       col.p[i]->output();
118       printf("</mtd></mtr>");
119     }
120     printf("</mtable>");
121   }
122 }
123
124 pile_box::pile_box(box *pp) : col(pp)
125 {
126 }
127
128 void pile_box::check_tabs(int level)
129 {
130   col.list_check_tabs(level);
131 }
132
133 void pile_box::debug_print()
134 {
135   col.debug_print("pile");
136 }
137
138 int matrix_box::compute_metrics(int style)
139 {
140   int i, j;
141   int max_len = 0;
142   int space = 0;
143   for (i = 0; i < len; i++) {
144     for (j = 0; j < p[i]->len; j++)
145       p[i]->p[j]->compute_metrics(style);
146     if (p[i]->len > max_len)
147       max_len = p[i]->len;
148     if (p[i]->space > space)
149       space = p[i]->space;
150   }
151   for (i = 0; i < len; i++) {
152     printf(".nr " COLUMN_WIDTH_FORMAT " 0", uid, i);
153     for (j = 0; j < p[i]->len; j++)
154       printf(">?\\n[" WIDTH_FORMAT "]", p[i]->p[j]->uid);
155     printf("\n");
156   }
157   printf(".nr " WIDTH_FORMAT " %dM",
158          uid, column_sep*(len-1)+2*matrix_side_sep);
159   for (i = 0; i < len; i++)
160     printf("+\\n[" COLUMN_WIDTH_FORMAT "]", uid, i);
161   printf("\n");
162   printf(".nr " BASELINE_SEP_FORMAT " %dM",
163          uid, baseline_sep+space);
164   for (i = 0; i < len; i++)
165     for (j = 1; j < p[i]->len; j++)
166       printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)",
167            p[i]->p[j-1]->uid, p[i]->p[j]->uid, default_rule_thickness*5);
168   // round it so that it's a multiple of the vertical resolution
169   printf("+(\\n(.V/2)/\\n(.V*\\n(.V\n");
170   printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2"
171          "+%dM\n",
172          uid, uid, max_len-1, axis_height - shift_down);
173   printf(".nr " HEIGHT_FORMAT " 0\\n[" SUP_RAISE_FORMAT "]+(0",
174          uid, uid);
175   for (i = 0; i < len; i++)
176     printf(">?\\n[" HEIGHT_FORMAT "]", p[i]->p[0]->uid);
177   printf(")>?0\n");
178   printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d-\\n["
179          SUP_RAISE_FORMAT "]+(0",
180          uid, uid, max_len-1, uid);
181   for (i = 0; i < len; i++)
182     if (p[i]->len == max_len)
183       printf(">?\\n[" DEPTH_FORMAT "]", p[i]->p[max_len-1]->uid);
184   printf(")>?0\n");
185   return FOUND_NOTHING;
186 }
187
188 void matrix_box::output()
189 {
190   if (output_format == troff) {
191     printf("\\h'%dM'", matrix_side_sep);
192     for (int i = 0; i < len; i++) {
193       int j;
194       printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
195       for (j = 0; j < p[i]->len; j++) {
196         switch (p[i]->align) {
197         case LEFT_ALIGN:
198           break;
199         case CENTER_ALIGN:
200           printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'",
201                  uid, i, p[i]->p[j]->uid);
202           break;
203         case RIGHT_ALIGN:
204           printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
205                  uid, i, p[i]->p[j]->uid);
206           break;
207         default:
208           assert(0);
209         }
210         p[i]->p[j]->output();
211         printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p[i]->p[j]->uid);
212         switch (p[i]->align) {
213         case LEFT_ALIGN:
214           break;
215         case CENTER_ALIGN:
216           printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u/2u'",
217                  p[i]->p[j]->uid, uid, i);
218           break;
219         case RIGHT_ALIGN:
220           printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u'",
221                  p[i]->p[j]->uid, uid, i);
222           break;
223         default:
224           assert(0);
225         }
226         if (j != p[i]->len - 1)
227           printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid);
228       }
229       printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid);
230       printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", p[i]->len - 1, uid);
231       printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u'", uid, i);
232       if (i != len - 1)
233         printf("\\h'%dM'", column_sep);
234     }
235     printf("\\h'%dM'", matrix_side_sep);
236   }
237   else if (output_format == mathml) {
238     int n = p[0]->len;  // Each column must have the same number of rows in it
239     printf("<mtable>");
240     for (int i = 0; i < n; i++) {
241       printf("<mtr>");
242       for (int j = 0; j < len; j++) {
243         const char *av;
244         switch (p[j]->align) {
245         case LEFT_ALIGN:
246           av = "left";
247           break;
248         case RIGHT_ALIGN:
249           av = "right";
250           break;
251         case CENTER_ALIGN:
252           av = "center";
253           break;
254         default:
255           assert(0);
256         }
257         printf("<mtd columnalign='%s'>", av);
258         p[j]->p[i]->output();
259         printf("</mtd>");
260       }
261       printf("</mtr>");
262     }
263     printf("</mtable>");
264   }
265 }
266
267 matrix_box::matrix_box(column *pp)
268 {
269   p = new column*[10];
270   for (int i = 0; i < 10; i++)
271     p[i] = 0;
272   maxlen = 10;
273   len = 1;
274   p[0] = pp;
275 }
276
277 matrix_box::~matrix_box()
278 {
279   for (int i = 0; i < len; i++)
280     delete p[i];
281   a_delete p;
282 }
283
284 void matrix_box::append(column *pp)
285 {
286   if (len + 1 > maxlen) {
287     column **oldp = p;
288     maxlen *= 2;
289     p = new column*[maxlen];
290     memcpy(p, oldp, sizeof(column*)*len);
291     a_delete oldp;
292   }
293   p[len++] = pp;
294 }
295
296 void matrix_box::check_tabs(int level)
297 {
298   for (int i = 0; i < len; i++)
299     p[i]->list_check_tabs(level);
300 }
301
302 void matrix_box::debug_print()
303 {
304   fprintf(stderr, "matrix { ");
305   p[0]->debug_print("col");
306   for (int i = 1; i < len; i++) {
307     fprintf(stderr, " ");
308     p[i]->debug_print("col");
309   }
310   fprintf(stderr, " }");
311 }
312
313 column::column(box *pp) : box_list(pp), align(CENTER_ALIGN), space(0)
314 {
315 }
316
317 void column::set_alignment(alignment a)
318 {
319   align = a;
320 }
321
322 void column::set_space(int n)
323 {
324   space = n;
325 }
326
327 void column::debug_print(const char *s)
328 {
329   char c = '\0';                // shut up -Wall
330   switch (align) {
331   case LEFT_ALIGN:
332     c = 'l';
333     break;
334   case RIGHT_ALIGN:
335     c = 'r';
336     break;
337   case CENTER_ALIGN:
338     c = 'c';
339     break;
340   default:
341     assert(0);
342   }
343   fprintf(stderr, "%c%s %d { ", c, s, space);
344   list_debug_print(" above ");
345   fprintf(stderr, " }");
346 }
347