1// -*- C++ -*-
2/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3     Written by James Clark (jjc@jclark.com)
4
5This file is part of groff.
6
7groff is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12groff is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License along
18with groff; see the file COPYING.  If not, write to the Free Software
19Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
20
21#include "eqn.h"
22#include "pbox.h"
23
24list_box *box::to_list_box()
25{
26  return 0;
27}
28
29list_box *list_box::to_list_box()
30{
31  return this;
32}
33
34void list_box::append(box *pp)
35{
36  list_box *q = pp->to_list_box();
37  if (q == 0)
38    list.append(pp);
39  else {
40    for (int i = 0; i < q->list.len; i++) {
41      list.append(q->list.p[i]);
42      q->list.p[i] = 0;
43    }
44    q->list.len = 0;
45    delete q;
46  }
47}
48
49list_box::list_box(box *pp) : list(pp), sty(-1)
50{
51  list_box *q = pp->to_list_box();
52  if (q != 0) {
53    // flatten it
54    list.p[0] = q->list.p[0];
55    for (int i = 1; i < q->list.len; i++) {
56      list.append(q->list.p[i]);
57      q->list.p[i] = 0;
58    }
59    q->list.len = 0;
60    delete q;
61  }
62}
63
64static int compute_spacing(int is_script, int left, int right)
65{
66  if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE)
67    return 0;
68  if (left == PUNCTUATION_TYPE)
69    return is_script ? 0 : thin_space;
70  if (left == OPENING_TYPE || right == CLOSING_TYPE)
71    return 0;
72  if (right == BINARY_TYPE || left == BINARY_TYPE)
73    return is_script ? 0 : medium_space;
74  if (right == RELATION_TYPE) {
75    if (left == RELATION_TYPE)
76      return 0;
77    else
78      return is_script ? 0 : thick_space;
79  }
80  if (left == RELATION_TYPE)
81    return is_script ? 0 : thick_space;
82  if (right == OPERATOR_TYPE)
83    return thin_space;
84  if (left == INNER_TYPE || right == INNER_TYPE)
85    return is_script ? 0 : thin_space;
86  if (left == OPERATOR_TYPE && right == ORDINARY_TYPE)
87    return thin_space;
88  return 0;
89}
90
91int list_box::compute_metrics(int style)
92{
93  sty = style;
94  int i;
95  for (i = 0; i < list.len; i++) {
96    int t = list.p[i]->spacing_type;
97    // 5
98    if (t == BINARY_TYPE) {
99      int prevt;
100      if (i == 0
101	  || (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE
102	  || prevt == OPERATOR_TYPE
103	  || prevt == RELATION_TYPE
104	  || prevt == OPENING_TYPE
105	  || prevt == PUNCTUATION_TYPE)
106	list.p[i]->spacing_type = ORDINARY_TYPE;
107    }
108    // 7
109    else if ((t == RELATION_TYPE || t == CLOSING_TYPE
110	      || t == PUNCTUATION_TYPE)
111	     && i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE)
112      list.p[i-1]->spacing_type = ORDINARY_TYPE;
113  }
114  for (i = 0; i < list.len; i++) {
115    unsigned flags = 0;
116    if (i - 1 >= 0 && list.p[i - 1]->right_is_italic())
117      flags |= HINT_PREV_IS_ITALIC;
118    if (i + 1 < list.len && list.p[i + 1]->left_is_italic())
119      flags |= HINT_NEXT_IS_ITALIC;
120    if (flags)
121      list.p[i]->hint(flags);
122  }
123  is_script = (style <= SCRIPT_STYLE);
124  int total_spacing = 0;
125  for (i = 1; i < list.len; i++)
126    total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
127				     list.p[i]->spacing_type);
128  int res = 0;
129  for (i = 0; i < list.len; i++)
130    if (!list.p[i]->is_simple()) {
131      int r = list.p[i]->compute_metrics(style);
132      if (r) {
133	if (res)
134	  error("multiple marks and lineups");
135	else {
136	  compute_sublist_width(i);
137	  printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n");
138	  res = r;
139	}
140      }
141    }
142  printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing);
143  for (i = 0; i < list.len; i++)
144    if (!list.p[i]->is_simple())
145      printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
146  printf("\n");
147  printf(".nr " HEIGHT_FORMAT " 0", uid);
148  for (i = 0; i < list.len; i++)
149    if (!list.p[i]->is_simple())
150      printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid);
151  printf("\n");
152  printf(".nr " DEPTH_FORMAT " 0", uid);
153  for (i = 0; i < list.len; i++)
154    if (!list.p[i]->is_simple())
155      printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid);
156  printf("\n");
157  int have_simple = 0;
158  for (i = 0; i < list.len && !have_simple; i++)
159    have_simple = list.p[i]->is_simple();
160  if (have_simple) {
161    printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid);
162    for (i = 0; i < list.len; i++)
163      if (list.p[i]->is_simple())
164	list.p[i]->output();
165    printf(DELIMITER_CHAR "\n");
166    printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n",
167	   uid, uid);
168    printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n",
169	   uid, uid);
170  }
171  return res;
172}
173
174void list_box::compute_sublist_width(int n)
175{
176  int total_spacing = 0;
177  int i;
178  for (i = 1; i < n + 1 && i < list.len; i++)
179    total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
180				     list.p[i]->spacing_type);
181  printf(".nr " TEMP_REG " %dM", total_spacing);
182  for (i = 0; i < n; i++)
183    if (!list.p[i]->is_simple())
184      printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
185  int have_simple = 0;
186  for (i = 0; i < n && !have_simple; i++)
187    have_simple = list.p[i]->is_simple();
188  if (have_simple) {
189    printf("+\\w" DELIMITER_CHAR);
190    for (i = 0; i < n; i++)
191      if (list.p[i]->is_simple())
192	list.p[i]->output();
193    printf(DELIMITER_CHAR);
194  }
195  printf("\n");
196}
197
198void list_box::compute_subscript_kern()
199{
200  // We can only call compute_subscript_kern if we have called
201  // compute_metrics first.
202  if (list.p[list.len-1]->is_simple())
203    list.p[list.len-1]->compute_metrics(sty);
204  list.p[list.len-1]->compute_subscript_kern();
205  printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n",
206	 uid, list.p[list.len-1]->uid);
207}
208
209void list_box::output()
210{
211  for (int i = 0; i < list.len; i++) {
212    if (i > 0) {
213      int n = compute_spacing(is_script,
214			      list.p[i-1]->spacing_type,
215			      list.p[i]->spacing_type);
216      if (n > 0)
217	printf("\\h'%dM'", n);
218    }
219    list.p[i]->output();
220  }
221}
222
223void list_box::handle_char_type(int st, int ft)
224{
225  for (int i = 0; i < list.len; i++)
226    list.p[i]->handle_char_type(st, ft);
227}
228
229void list_box::debug_print()
230{
231  list.list_debug_print(" ");
232}
233
234void list_box::check_tabs(int level)
235{
236  list.list_check_tabs(level);
237}
238