1114402Sru// -*- C++ -*-
2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2002, 2004
3151497Sru   Free Software Foundation, Inc.
4114402Sru     Written by James Clark (jjc@jclark.com)
5114402Sru
6114402SruThis file is part of groff.
7114402Sru
8114402Srugroff is free software; you can redistribute it and/or modify it under
9114402Sruthe terms of the GNU General Public License as published by the Free
10114402SruSoftware Foundation; either version 2, or (at your option) any later
11114402Sruversion.
12114402Sru
13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
15114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16114402Srufor more details.
17114402Sru
18114402SruYou should have received a copy of the GNU General Public License along
19114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
21114402Sru
22114402Sru#include "eqn.h"
23114402Sru#include "pbox.h"
24114402Sru
25114402Sruclass script_box : public pointer_box {
26114402Sruprivate:
27114402Sru  box *sub;
28114402Sru  box *sup;
29114402Srupublic:
30114402Sru  script_box(box *, box *, box *);
31114402Sru  ~script_box();
32114402Sru  int compute_metrics(int);
33114402Sru  void output();
34114402Sru  void debug_print();
35114402Sru  int left_is_italic();
36114402Sru  void hint(unsigned);
37114402Sru  void check_tabs(int);
38114402Sru};
39114402Sru
40114402Sru/* The idea is that the script should attach to the rightmost box
41114402Sruof a list. For example, given `2x sup 3', the superscript should
42114402Sruattach to `x' rather than `2x'. */
43114402Sru
44114402Srubox *make_script_box(box *nuc, box *sub, box *sup)
45114402Sru{
46114402Sru  list_box *b = nuc->to_list_box();
47114402Sru  if (b != 0) {
48114402Sru    b->list.p[b->list.len-1] = make_script_box(b->list.p[b->list.len - 1],
49114402Sru					       sub,
50114402Sru					       sup);
51114402Sru    return b;
52114402Sru  }
53114402Sru  else
54114402Sru    return new script_box(nuc, sub, sup);
55114402Sru}
56114402Sru
57114402Sruscript_box::script_box(box *pp, box *qq, box *rr)
58114402Sru: pointer_box(pp), sub(qq), sup(rr)
59114402Sru{
60114402Sru}
61114402Sru
62114402Sruscript_box::~script_box()
63114402Sru{
64114402Sru  delete sub;
65114402Sru  delete sup;
66114402Sru}
67114402Sru
68114402Sruint script_box::left_is_italic()
69114402Sru{
70114402Sru  return p->left_is_italic();
71114402Sru}
72114402Sru
73114402Sruint script_box::compute_metrics(int style)
74114402Sru{
75114402Sru  int res = p->compute_metrics(style);
76114402Sru  p->compute_subscript_kern();
77114402Sru  printf(".nr " SIZE_FORMAT " \\n[.ps]\n", uid);
78114402Sru  if (!(style <= SCRIPT_STYLE && one_size_reduction_flag))
79114402Sru    set_script_size();
80114402Sru  printf(".nr " SMALL_SIZE_FORMAT " \\n[.ps]\n", uid);
81114402Sru  if (sub != 0)
82114402Sru    sub->compute_metrics(cramped_style(script_style(style)));
83114402Sru  if (sup != 0)
84114402Sru    sup->compute_metrics(script_style(style));
85114402Sru  // 18a
86114402Sru  if (p->is_char()) {
87114402Sru    printf(".nr " SUP_RAISE_FORMAT " 0\n", uid);
88114402Sru    printf(".nr " SUB_LOWER_FORMAT " 0\n", uid);
89114402Sru  }
90114402Sru  else {
91114402Sru    printf(".nr " SUP_RAISE_FORMAT " \\n[" HEIGHT_FORMAT "]-%dM>?0\n",
92114402Sru	   uid, p->uid, sup_drop);
93114402Sru    printf(".nr " SUB_LOWER_FORMAT " \\n[" DEPTH_FORMAT "]+%dM\n",
94114402Sru	   uid, p->uid, sub_drop);
95114402Sru  }
96114402Sru  printf(".ps \\n[" SIZE_FORMAT "]u\n", uid);
97114402Sru  if (sup == 0) {
98114402Sru    assert(sub != 0);
99114402Sru    // 18b
100114402Sru    printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM>?(\\n["
101114402Sru	   HEIGHT_FORMAT "]-(%dM*4/5))\n",
102114402Sru	   uid, uid, sub1, sub->uid, x_height);
103114402Sru  }
104114402Sru  else {
105114402Sru    // sup != 0
106114402Sru    // 18c
107151497Sru    int pos;
108114402Sru    if (style == DISPLAY_STYLE)
109151497Sru      pos = sup1;
110114402Sru    else if (style & 1)		// not cramped
111151497Sru      pos = sup2;
112114402Sru    else
113151497Sru      pos = sup3;
114114402Sru    printf(".nr " SUP_RAISE_FORMAT " \\n[" SUP_RAISE_FORMAT
115114402Sru	   "]>?%dM>?(\\n[" DEPTH_FORMAT "]+(%dM/4))\n",
116151497Sru	   uid, uid, pos, sup->uid, x_height);
117114402Sru    // 18d
118114402Sru    if (sub != 0) {
119114402Sru      printf(".nr " SUB_LOWER_FORMAT " \\n[" SUB_LOWER_FORMAT "]>?%dM\n",
120151497Sru	     uid, uid, sub2);
121114402Sru      // 18e
122114402Sru      printf(".nr " TEMP_REG " \\n[" DEPTH_FORMAT "]-\\n["
123114402Sru	     SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "]-\\n["
124114402Sru	     SUB_LOWER_FORMAT "]+(4*%dM)\n",
125114402Sru	     sup->uid, uid, sub->uid, uid, default_rule_thickness);
126114402Sru      printf(".if \\n[" TEMP_REG "] \\{");
127114402Sru      printf(".nr " SUB_LOWER_FORMAT " +\\n[" TEMP_REG "]\n", uid);
128114402Sru      printf(".nr " TEMP_REG " (%dM*4/5)-\\n[" SUP_RAISE_FORMAT
129114402Sru	     "]+\\n[" DEPTH_FORMAT "]>?0\n",
130114402Sru	     x_height, uid, sup->uid);
131114402Sru      printf(".nr " SUP_RAISE_FORMAT " +\\n[" TEMP_REG "]\n", uid);
132114402Sru      printf(".nr " SUB_LOWER_FORMAT " -\\n[" TEMP_REG "]\n", uid);
133114402Sru      printf(".\\}\n");
134114402Sru    }
135114402Sru  }
136114402Sru  printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]", uid, p->uid);
137114402Sru  if (sub != 0 && sup != 0)
138114402Sru    printf("+((\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]>?\\n["
139114402Sru	   WIDTH_FORMAT "])+%dM)>?0\n",
140114402Sru	   sub->uid, p->uid, sup->uid, script_space);
141114402Sru  else if (sub != 0)
142114402Sru    printf("+(\\n[" WIDTH_FORMAT "]-\\n[" SUB_KERN_FORMAT "]+%dM)>?0\n",
143114402Sru	   sub->uid, p->uid, script_space);
144114402Sru  else if (sup != 0)
145114402Sru    printf("+(\\n[" WIDTH_FORMAT "]+%dM)>?0\n", sup->uid, script_space);
146114402Sru  else
147114402Sru    printf("\n");
148114402Sru  printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]",
149114402Sru	 uid, p->uid);
150114402Sru  if (sup != 0)
151114402Sru    printf(">?(\\n[" SUP_RAISE_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
152114402Sru	   uid, sup->uid);
153114402Sru  if (sub != 0)
154114402Sru    printf(">?(-\\n[" SUB_LOWER_FORMAT "]+\\n[" HEIGHT_FORMAT "])",
155114402Sru	   uid, sub->uid);
156114402Sru  printf("\n");
157114402Sru  printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]",
158114402Sru	 uid, p->uid);
159114402Sru  if (sub != 0)
160114402Sru    printf(">?(\\n[" SUB_LOWER_FORMAT "]+\\n[" DEPTH_FORMAT "])",
161114402Sru	   uid, sub->uid);
162114402Sru  if (sup != 0)
163114402Sru    printf(">?(-\\n[" SUP_RAISE_FORMAT "]+\\n[" DEPTH_FORMAT "])",
164114402Sru	   uid, sup->uid);
165114402Sru  printf("\n");
166114402Sru  return res;
167114402Sru}
168114402Sru
169114402Sruvoid script_box::output()
170114402Sru{
171114402Sru  p->output();
172114402Sru  if (sup != 0) {
173114402Sru    printf("\\Z" DELIMITER_CHAR);
174114402Sru    printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid);
175114402Sru    printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
176114402Sru    sup->output();
177114402Sru    printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
178114402Sru    printf(DELIMITER_CHAR);
179114402Sru  }
180114402Sru  if (sub != 0) {
181114402Sru    printf("\\Z" DELIMITER_CHAR);
182114402Sru    printf("\\v'\\n[" SUB_LOWER_FORMAT "]u'", uid);
183114402Sru    printf("\\s[\\n[" SMALL_SIZE_FORMAT "]u]", uid);
184114402Sru    printf("\\h'-\\n[" SUB_KERN_FORMAT "]u'", p->uid);
185114402Sru    sub->output();
186114402Sru    printf("\\s[\\n[" SIZE_FORMAT "]u]", uid);
187114402Sru    printf(DELIMITER_CHAR);
188114402Sru  }
189114402Sru  printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'",
190114402Sru	 uid, p->uid);
191114402Sru}
192114402Sru
193114402Sruvoid script_box::hint(unsigned flags)
194114402Sru{
195114402Sru  p->hint(flags & ~HINT_NEXT_IS_ITALIC);
196114402Sru}
197114402Sru
198114402Sruvoid script_box::debug_print()
199114402Sru{
200114402Sru  fprintf(stderr, "{ ");
201114402Sru  p->debug_print();
202114402Sru  fprintf(stderr, " }");
203114402Sru  if (sub) {
204114402Sru    fprintf(stderr, " sub { ");
205114402Sru    sub->debug_print();
206114402Sru    fprintf(stderr, " }");
207114402Sru  }
208114402Sru  if (sup) {
209114402Sru    fprintf(stderr, " sup { ");
210114402Sru    sup->debug_print();
211114402Sru    fprintf(stderr, " }");
212114402Sru  }
213114402Sru}
214114402Sru
215114402Sruvoid script_box::check_tabs(int level)
216114402Sru{
217114402Sru  if (sup)
218114402Sru    sup->check_tabs(level + 1);
219114402Sru  if (sub)
220114402Sru    sub->check_tabs(level + 1);
221114402Sru  p->check_tabs(level);
222114402Sru}
223