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