1/*	$NetBSD$	*/
2
3// -*- C++ -*-
4/* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004
5   Free Software Foundation, Inc.
6     Written by James Clark (jjc@jclark.com)
7
8This file is part of groff.
9
10groff is free software; you can redistribute it and/or modify it under
11the terms of the GNU General Public License as published by the Free
12Software Foundation; either version 2, or (at your option) any later
13version.
14
15groff is distributed in the hope that it will be useful, but WITHOUT ANY
16WARRANTY; without even the implied warranty of MERCHANTABILITY or
17FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18for more details.
19
20You should have received a copy of the GNU General Public License along
21with groff; see the file COPYING.  If not, write to the Free Software
22Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
23
24#include "eqn.h"
25#include "pbox.h"
26
27class script_box : public pointer_box {
28private:
29  box *sub;
30  box *sup;
31public:
32  script_box(box *, box *, box *);
33  ~script_box();
34  int compute_metrics(int);
35  void output();
36  void debug_print();
37  int left_is_italic();
38  void hint(unsigned);
39  void check_tabs(int);
40};
41
42/* The idea is that the script should attach to the rightmost box
43of a list. For example, given `2x sup 3', the superscript should
44attach to `x' rather than `2x'. */
45
46box *make_script_box(box *nuc, box *sub, box *sup)
47{
48  list_box *b = nuc->to_list_box();
49  if (b != 0) {
50    b->list.p[b->list.len-1] = make_script_box(b->list.p[b->list.len - 1],
51					       sub,
52					       sup);
53    return b;
54  }
55  else
56    return new script_box(nuc, sub, sup);
57}
58
59script_box::script_box(box *pp, box *qq, box *rr)
60: pointer_box(pp), sub(qq), sup(rr)
61{
62}
63
64script_box::~script_box()
65{
66  delete sub;
67  delete sup;
68}
69
70int script_box::left_is_italic()
71{
72  return p->left_is_italic();
73}
74
75int script_box::compute_metrics(int style)
76{
77  int res = p->compute_metrics(style);
78  p->compute_subscript_kern();
79  printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
80  if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
81    set_script_size();
82  printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
83  if (sub != 0)
84    sub->compute_metrics(cramped_style(script_style(style)));
85  if (sup != 0)
86    sup->compute_metrics(script_style(style));
87  // 18a
88  if (p->is_char()) {
89    printf(".nr " SUP_RAISE_FORMAT " 0\n", uid);
90    printf(".nr " SUB_LOWER_FORMAT " 0\n", uid);
91  }
92  else {
93    printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
94	   uid, p->uid, sup_drop);
95    printf(".nr " SUB_LOWER_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
96	   uid, p->uid, sub_drop);
97  }
98  printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
99  if (sup == 0) {
100    assert(sub != 0);
101    // 18b
102    printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM>?(\\n["
103	   HEIGHT_FORMAT "]-(%dM*4/5))\n",
104	   uid, uid, sub1, sub->uid, x_height);
105  }
106  else {
107    // sup != 0
108    // 18c
109    int pos;
110    if (style == DISPLAY_STYLE)
111      pos = sup1;
112    else if (style & 1)		// not cramped
113      pos = sup2;
114    else
115      pos = sup3;
116    printf(".nr " SUP_RAISE_FORMAT " \\n[" SUP_RAISE_FORMAT
117	   "]>?%dM>?(\\n[" DEPTH_FORMAT "]+(%dM/4))\n",
118	   uid, uid, pos, sup->uid, x_height);
119    // 18d
120    if (sub != 0) {
121      printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM\n",
122	     uid, uid, sub2);
123      // 18e
124      printf(".nr " TEMP_REG " \\n[" DEPTH_FORMAT "]-\\n["
125	     SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]-\\n["
126	     SUB_LOWER_FORMAT "]+(4*%dM)\n",
127	     sup->uid, uid, sub->uid, uid, default_rule_thickness);
128      printf(".if \\n[" TEMP_REG "] \\{");
129      printf(".nr " SUB_LOWER_FORMAT " +\\n[" TEMP_REG "]\n", uid);
130      printf(".nr " TEMP_REG " (%dM*4/5)-\\n[" SUP_RAISE_FORMAT
131	     "]+\\n[" DEPTH_FORMAT "]>?0\n",
132	     x_height, uid, sup->uid);
133      printf(".nr " SUP_RAISE_FORMAT " +\\n[" TEMP_REG "]\n", uid);
134      printf(".nr " SUB_LOWER_FORMAT " -\\n[" TEMP_REG "]\n", uid);
135      printf(".\\}\n");
136    }
137  }
138  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
139  if (sub != 0 && sup != 0)
140    printf("+((\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]>?\\n["
141	   WIDTH_FORMAT "])+%dM)>?0\n",
142	   sub->uid, p->uid, sup->uid, script_space);
143  else if (sub != 0)
144    printf("+(\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]+%dM)>?0\n",
145	   sub->uid, p->uid, script_space);
146  else if (sup != 0)
147    printf("+(\\n[" WIDTH_FORMAT "]+%dM)>?0\n", sup->uid, script_space);
148  else
149    printf("\n");
150  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]",
151	 uid, p->uid);
152  if (sup != 0)
153    printf(">?(\\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
154	   uid, sup->uid);
155  if (sub != 0)
156    printf(">?(-\\n[" SUB_LOWER_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
157	   uid, sub->uid);
158  printf("\n");
159  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]",
160	 uid, p->uid);
161  if (sub != 0)
162    printf(">?(\\n[" SUB_LOWER_FORMAT "]+\\n[" DEPTH_FORMAT "])",
163	   uid, sub->uid);
164  if (sup != 0)
165    printf(">?(-\\n[" SUP_RAISE_FORMAT "]+\\n[" DEPTH_FORMAT "])",
166	   uid, sup->uid);
167  printf("\n");
168  return res;
169}
170
171void script_box::output()
172{
173  p->output();
174  if (sup != 0) {
175    printf("\\Z" DELIMITER_CHAR);
176    printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
177    printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
178    sup->output();
179    printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
180    printf(DELIMITER_CHAR);
181  }
182  if (sub != 0) {
183    printf("\\Z" DELIMITER_CHAR);
184    printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
185    printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
186    printf("\\h'-\\n[" SUB_KERN_FORMAT "]u'", p->uid);
187    sub->output();
188    printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
189    printf(DELIMITER_CHAR);
190  }
191  printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
192	 uid, p->uid);
193}
194
195void script_box::hint(unsigned flags)
196{
197  p->hint(flags & ~HINT_NEXT_IS_ITALIC);
198}
199
200void script_box::debug_print()
201{
202  fprintf(stderr, "{ ");
203  p->debug_print();
204  fprintf(stderr, " }");
205  if (sub) {
206    fprintf(stderr, " sub { ");
207    sub->debug_print();
208    fprintf(stderr, " }");
209  }
210  if (sup) {
211    fprintf(stderr, " sup { ");
212    sup->debug_print();
213    fprintf(stderr, " }");
214  }
215}
216
217void script_box::check_tabs(int level)
218{
219  if (sup)
220    sup->check_tabs(level + 1);
221  if (sub)
222    sub->check_tabs(level + 1);
223  p->check_tabs(level);
224}
225