9e6e3591de0bbdba4e911c34fda79cebc78b7c35
[platform/upstream/groff.git] / src / preproc / eqn / list.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 list_box *box::to_list_box()
24 {
25   return 0;
26 }
27
28 list_box *list_box::to_list_box()
29 {
30   return this;
31 }
32
33 void list_box::append(box *pp)
34 {
35   list_box *q = pp->to_list_box();
36   if (q == 0)
37     list.append(pp);
38   else {
39     for (int i = 0; i < q->list.len; i++) {
40       list.append(q->list.p[i]);
41       q->list.p[i] = 0;
42     }
43     q->list.len = 0;
44     delete q;
45   }
46 }
47
48 list_box::list_box(box *pp) : list(pp), sty(-1)
49 {
50   list_box *q = pp->to_list_box();
51   if (q != 0) {
52     // flatten it
53     list.p[0] = q->list.p[0];
54     for (int i = 1; i < q->list.len; i++) {
55       list.append(q->list.p[i]);
56       q->list.p[i] = 0;
57     }
58     q->list.len = 0;
59     delete q;
60   }
61 }
62
63 static int compute_spacing(int is_script, int left, int right)
64 {
65   if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE)
66     return 0;
67   if (left == PUNCTUATION_TYPE)
68     return is_script ? 0 : thin_space;
69   if (left == OPENING_TYPE || right == CLOSING_TYPE)
70     return 0;
71   if (right == BINARY_TYPE || left == BINARY_TYPE)
72     return is_script ? 0 : medium_space;
73   if (right == RELATION_TYPE) {
74     if (left == RELATION_TYPE)
75       return 0;
76     else
77       return is_script ? 0 : thick_space;
78   }
79   if (left == RELATION_TYPE)
80     return is_script ? 0 : thick_space;
81   if (right == OPERATOR_TYPE)
82     return thin_space;
83   if (left == INNER_TYPE || right == INNER_TYPE)
84     return is_script ? 0 : thin_space;
85   if (left == OPERATOR_TYPE && right == ORDINARY_TYPE)
86     return thin_space;
87   return 0;
88 }
89
90 int list_box::compute_metrics(int style)
91 {
92   sty = style;
93   int i;
94   for (i = 0; i < list.len; i++) {
95     int t = list.p[i]->spacing_type; 
96     // 5
97     if (t == BINARY_TYPE) {
98       int prevt;
99       if (i == 0
100           || (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE
101           || prevt == OPERATOR_TYPE
102           || prevt == RELATION_TYPE
103           || prevt == OPENING_TYPE
104           || prevt == PUNCTUATION_TYPE)
105         list.p[i]->spacing_type = ORDINARY_TYPE;
106     }
107     // 7
108     else if ((t == RELATION_TYPE || t == CLOSING_TYPE 
109               || t == PUNCTUATION_TYPE)
110              && i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE)
111       list.p[i-1]->spacing_type = ORDINARY_TYPE;
112   }
113   for (i = 0; i < list.len; i++) {
114     unsigned flags = 0;
115     if (i - 1 >= 0 && list.p[i - 1]->right_is_italic())
116       flags |= HINT_PREV_IS_ITALIC;
117     if (i + 1 < list.len && list.p[i + 1]->left_is_italic())
118       flags |= HINT_NEXT_IS_ITALIC;
119     if (flags)
120       list.p[i]->hint(flags);
121   }
122   is_script = (style <= SCRIPT_STYLE);
123   int total_spacing = 0;
124   for (i = 1; i < list.len; i++)
125     total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
126                                      list.p[i]->spacing_type);
127   int res = 0;
128   for (i = 0; i < list.len; i++)
129     if (!list.p[i]->is_simple()) {
130       int r = list.p[i]->compute_metrics(style);
131       if (r) {
132         if (res)
133           error("multiple marks and lineups");
134         else {
135           compute_sublist_width(i);
136           printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n");
137           res = r;
138         }
139       }
140     }
141   printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing);
142   for (i = 0; i < list.len; i++)
143     if (!list.p[i]->is_simple())
144       printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
145   printf("\n");
146   printf(".nr " HEIGHT_FORMAT " 0", uid);
147   for (i = 0; i < list.len; i++)
148     if (!list.p[i]->is_simple())
149       printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid);
150   printf("\n");
151   printf(".nr " DEPTH_FORMAT " 0", uid);
152   for (i = 0; i < list.len; i++)
153     if (!list.p[i]->is_simple())
154       printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid);
155   printf("\n");
156   int have_simple = 0;
157   for (i = 0; i < list.len && !have_simple; i++)
158     have_simple = list.p[i]->is_simple();
159   if (have_simple) {
160     printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid);
161     for (i = 0; i < list.len; i++)
162       if (list.p[i]->is_simple())
163         list.p[i]->output();
164     printf(DELIMITER_CHAR "\n");
165     printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n",
166            uid, uid);
167     printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n",
168            uid, uid);
169   }
170   return res;
171 }
172
173 void list_box::compute_sublist_width(int n)
174 {
175   int total_spacing = 0;
176   int i;
177   for (i = 1; i < n + 1 && i < list.len; i++)
178     total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
179                                      list.p[i]->spacing_type);
180   printf(".nr " TEMP_REG " %dM", total_spacing);
181   for (i = 0; i < n; i++)
182     if (!list.p[i]->is_simple())
183       printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
184   int have_simple = 0;
185   for (i = 0; i < n && !have_simple; i++)
186     have_simple = list.p[i]->is_simple();
187   if (have_simple) {
188     printf("+\\w" DELIMITER_CHAR);
189     for (i = 0; i < n; i++)
190       if (list.p[i]->is_simple())
191         list.p[i]->output();
192     printf(DELIMITER_CHAR);
193   }
194   printf("\n");
195 }
196
197 void list_box::compute_subscript_kern()
198 {
199   // We can only call compute_subscript_kern if we have called
200   // compute_metrics first.
201   if (list.p[list.len-1]->is_simple())
202     list.p[list.len-1]->compute_metrics(sty);
203   list.p[list.len-1]->compute_subscript_kern();
204   printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n",
205          uid, list.p[list.len-1]->uid);
206 }
207
208 void list_box::output()
209 {
210   if (output_format == mathml)
211     printf("<mrow>");
212   for (int i = 0; i < list.len; i++) {
213     if (output_format == troff && i > 0) {
214       int n = compute_spacing(is_script,
215                               list.p[i-1]->spacing_type,
216                               list.p[i]->spacing_type);
217       if (n > 0)
218         printf("\\h'%dM'", n);
219     }
220     list.p[i]->output();
221   }
222   if (output_format == mathml)
223     printf("</mrow>");
224 }
225
226 void list_box::handle_char_type(int st, int ft)
227 {
228   for (int i = 0; i < list.len; i++)
229     list.p[i]->handle_char_type(st, ft);
230 }
231
232 void list_box::debug_print()
233 {
234   list.list_debug_print(" ");
235 }
236
237 void list_box::check_tabs(int level)
238 {
239   list.list_check_tabs(level);
240 }