1114402Sru// -*- C++ -*-
2114402Sru/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3114402Sru     Written by James Clark (jjc@jclark.com)
4114402Sru
5114402SruThis file is part of groff.
6114402Sru
7114402Srugroff is free software; you can redistribute it and/or modify it under
8114402Sruthe terms of the GNU General Public License as published by the Free
9114402SruSoftware Foundation; either version 2, or (at your option) any later
10114402Sruversion.
11114402Sru
12114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
13114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
14114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15114402Srufor more details.
16114402Sru
17114402SruYou should have received a copy of the GNU General Public License along
18114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
19151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
20114402Sru
21114402Sru#include "eqn.h"
22114402Sru#include "pbox.h"
23114402Sru
24114402Srulist_box *box::to_list_box()
25114402Sru{
26114402Sru  return 0;
27114402Sru}
28114402Sru
29114402Srulist_box *list_box::to_list_box()
30114402Sru{
31114402Sru  return this;
32114402Sru}
33114402Sru
34114402Sruvoid list_box::append(box *pp)
35114402Sru{
36114402Sru  list_box *q = pp->to_list_box();
37114402Sru  if (q == 0)
38114402Sru    list.append(pp);
39114402Sru  else {
40114402Sru    for (int i = 0; i < q->list.len; i++) {
41114402Sru      list.append(q->list.p[i]);
42114402Sru      q->list.p[i] = 0;
43114402Sru    }
44114402Sru    q->list.len = 0;
45114402Sru    delete q;
46114402Sru  }
47114402Sru}
48114402Sru
49114402Srulist_box::list_box(box *pp) : list(pp), sty(-1)
50114402Sru{
51114402Sru  list_box *q = pp->to_list_box();
52114402Sru  if (q != 0) {
53114402Sru    // flatten it
54114402Sru    list.p[0] = q->list.p[0];
55114402Sru    for (int i = 1; i < q->list.len; i++) {
56114402Sru      list.append(q->list.p[i]);
57114402Sru      q->list.p[i] = 0;
58114402Sru    }
59114402Sru    q->list.len = 0;
60114402Sru    delete q;
61114402Sru  }
62114402Sru}
63114402Sru
64114402Srustatic int compute_spacing(int is_script, int left, int right)
65114402Sru{
66114402Sru  if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE)
67114402Sru    return 0;
68114402Sru  if (left == PUNCTUATION_TYPE)
69114402Sru    return is_script ? 0 : thin_space;
70114402Sru  if (left == OPENING_TYPE || right == CLOSING_TYPE)
71114402Sru    return 0;
72114402Sru  if (right == BINARY_TYPE || left == BINARY_TYPE)
73114402Sru    return is_script ? 0 : medium_space;
74114402Sru  if (right == RELATION_TYPE) {
75114402Sru    if (left == RELATION_TYPE)
76114402Sru      return 0;
77114402Sru    else
78114402Sru      return is_script ? 0 : thick_space;
79114402Sru  }
80114402Sru  if (left == RELATION_TYPE)
81114402Sru    return is_script ? 0 : thick_space;
82114402Sru  if (right == OPERATOR_TYPE)
83114402Sru    return thin_space;
84114402Sru  if (left == INNER_TYPE || right == INNER_TYPE)
85114402Sru    return is_script ? 0 : thin_space;
86114402Sru  if (left == OPERATOR_TYPE && right == ORDINARY_TYPE)
87114402Sru    return thin_space;
88114402Sru  return 0;
89114402Sru}
90114402Sru
91114402Sruint list_box::compute_metrics(int style)
92114402Sru{
93114402Sru  sty = style;
94114402Sru  int i;
95114402Sru  for (i = 0; i < list.len; i++) {
96114402Sru    int t = list.p[i]->spacing_type;
97114402Sru    // 5
98114402Sru    if (t == BINARY_TYPE) {
99114402Sru      int prevt;
100114402Sru      if (i == 0
101114402Sru	  || (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE
102114402Sru	  || prevt == OPERATOR_TYPE
103114402Sru	  || prevt == RELATION_TYPE
104114402Sru	  || prevt == OPENING_TYPE
105114402Sru	  || prevt == PUNCTUATION_TYPE)
106114402Sru	list.p[i]->spacing_type = ORDINARY_TYPE;
107114402Sru    }
108114402Sru    // 7
109114402Sru    else if ((t == RELATION_TYPE || t == CLOSING_TYPE
110114402Sru	      || t == PUNCTUATION_TYPE)
111114402Sru	     && i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE)
112114402Sru      list.p[i-1]->spacing_type = ORDINARY_TYPE;
113114402Sru  }
114114402Sru  for (i = 0; i < list.len; i++) {
115114402Sru    unsigned flags = 0;
116114402Sru    if (i - 1 >= 0 && list.p[i - 1]->right_is_italic())
117114402Sru      flags |= HINT_PREV_IS_ITALIC;
118114402Sru    if (i + 1 < list.len && list.p[i + 1]->left_is_italic())
119114402Sru      flags |= HINT_NEXT_IS_ITALIC;
120114402Sru    if (flags)
121114402Sru      list.p[i]->hint(flags);
122114402Sru  }
123114402Sru  is_script = (style <= SCRIPT_STYLE);
124114402Sru  int total_spacing = 0;
125114402Sru  for (i = 1; i < list.len; i++)
126114402Sru    total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
127114402Sru				     list.p[i]->spacing_type);
128114402Sru  int res = 0;
129114402Sru  for (i = 0; i < list.len; i++)
130114402Sru    if (!list.p[i]->is_simple()) {
131114402Sru      int r = list.p[i]->compute_metrics(style);
132114402Sru      if (r) {
133114402Sru	if (res)
134114402Sru	  error("multiple marks and lineups");
135114402Sru	else {
136114402Sru	  compute_sublist_width(i);
137114402Sru	  printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n");
138114402Sru	  res = r;
139114402Sru	}
140114402Sru      }
141114402Sru    }
142114402Sru  printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing);
143114402Sru  for (i = 0; i < list.len; i++)
144114402Sru    if (!list.p[i]->is_simple())
145114402Sru      printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
146114402Sru  printf("\n");
147114402Sru  printf(".nr " HEIGHT_FORMAT " 0", uid);
148114402Sru  for (i = 0; i < list.len; i++)
149114402Sru    if (!list.p[i]->is_simple())
150114402Sru      printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid);
151114402Sru  printf("\n");
152114402Sru  printf(".nr " DEPTH_FORMAT " 0", uid);
153114402Sru  for (i = 0; i < list.len; i++)
154114402Sru    if (!list.p[i]->is_simple())
155114402Sru      printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid);
156114402Sru  printf("\n");
157114402Sru  int have_simple = 0;
158114402Sru  for (i = 0; i < list.len && !have_simple; i++)
159114402Sru    have_simple = list.p[i]->is_simple();
160114402Sru  if (have_simple) {
161114402Sru    printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid);
162114402Sru    for (i = 0; i < list.len; i++)
163114402Sru      if (list.p[i]->is_simple())
164114402Sru	list.p[i]->output();
165114402Sru    printf(DELIMITER_CHAR "\n");
166114402Sru    printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n",
167114402Sru	   uid, uid);
168114402Sru    printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n",
169114402Sru	   uid, uid);
170114402Sru  }
171114402Sru  return res;
172114402Sru}
173114402Sru
174114402Sruvoid list_box::compute_sublist_width(int n)
175114402Sru{
176114402Sru  int total_spacing = 0;
177114402Sru  int i;
178114402Sru  for (i = 1; i < n + 1 && i < list.len; i++)
179114402Sru    total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type,
180114402Sru				     list.p[i]->spacing_type);
181114402Sru  printf(".nr " TEMP_REG " %dM", total_spacing);
182114402Sru  for (i = 0; i < n; i++)
183114402Sru    if (!list.p[i]->is_simple())
184114402Sru      printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid);
185114402Sru  int have_simple = 0;
186114402Sru  for (i = 0; i < n && !have_simple; i++)
187114402Sru    have_simple = list.p[i]->is_simple();
188114402Sru  if (have_simple) {
189114402Sru    printf("+\\w" DELIMITER_CHAR);
190114402Sru    for (i = 0; i < n; i++)
191114402Sru      if (list.p[i]->is_simple())
192114402Sru	list.p[i]->output();
193114402Sru    printf(DELIMITER_CHAR);
194114402Sru  }
195114402Sru  printf("\n");
196114402Sru}
197114402Sru
198114402Sruvoid list_box::compute_subscript_kern()
199114402Sru{
200114402Sru  // We can only call compute_subscript_kern if we have called
201114402Sru  // compute_metrics first.
202114402Sru  if (list.p[list.len-1]->is_simple())
203114402Sru    list.p[list.len-1]->compute_metrics(sty);
204114402Sru  list.p[list.len-1]->compute_subscript_kern();
205114402Sru  printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n",
206114402Sru	 uid, list.p[list.len-1]->uid);
207114402Sru}
208114402Sru
209114402Sruvoid list_box::output()
210114402Sru{
211114402Sru  for (int i = 0; i < list.len; i++) {
212114402Sru    if (i > 0) {
213114402Sru      int n = compute_spacing(is_script,
214114402Sru			      list.p[i-1]->spacing_type,
215114402Sru			      list.p[i]->spacing_type);
216114402Sru      if (n > 0)
217114402Sru	printf("\\h'%dM'", n);
218114402Sru    }
219114402Sru    list.p[i]->output();
220114402Sru  }
221114402Sru}
222114402Sru
223114402Sruvoid list_box::handle_char_type(int st, int ft)
224114402Sru{
225114402Sru  for (int i = 0; i < list.len; i++)
226114402Sru    list.p[i]->handle_char_type(st, ft);
227114402Sru}
228114402Sru
229114402Sruvoid list_box::debug_print()
230114402Sru{
231114402Sru  list.list_debug_print(" ");
232114402Sru}
233114402Sru
234114402Sruvoid list_box::check_tabs(int level)
235114402Sru{
236114402Sru  list.list_check_tabs(level);
237114402Sru}
238