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