| Commit | Line | Data |
|---|---|---|
| 92d0a6a6 | 1 | // -*- C++ -*- |
| 4d3e9548 JL |
2 | /* Copyright (C) 1989, 1990, 1991, 1992, 2004, 2007, 2009 |
| 3 | Free Software Foundation, Inc. | |
| 92d0a6a6 JR |
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 | // piles and matrices |
| 21 | ||
| 22 | #include "eqn.h" | |
| 23 | #include "pbox.h" | |
| 24 | ||
| 25 | // SUP_RAISE_FORMAT gives the first baseline | |
| 26 | // BASELINE_SEP_FORMAT gives the separation between baselines | |
| 27 | ||
| 28 | int pile_box::compute_metrics(int style) | |
| 29 | { | |
| 30 | int i; | |
| 31 | for (i = 0; i < col.len; i++) | |
| 32 | col.p[i]->compute_metrics(style); | |
| 33 | printf(".nr " WIDTH_FORMAT " 0", uid); | |
| 34 | for (i = 0; i < col.len; i++) | |
| 35 | printf(">?\\n[" WIDTH_FORMAT "]", col.p[i]->uid); | |
| 36 | printf("\n"); | |
| 37 | printf(".nr " BASELINE_SEP_FORMAT " %dM", | |
| 38 | uid, baseline_sep+col.space); | |
| 39 | for (i = 1; i < col.len; i++) | |
| 40 | printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)", | |
| 41 | col.p[i-1]->uid, col.p[i]->uid, default_rule_thickness*5); | |
| 42 | // round it so that it's a multiple of the vertical resolution | |
| 43 | printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n"); | |
| 44 | ||
| 45 | printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2" | |
| 46 | "+%dM\n", | |
| 47 | uid, uid, col.len-1, axis_height - shift_down); | |
| 48 | printf(".nr " HEIGHT_FORMAT " \\n[" SUP_RAISE_FORMAT "]+\\n[" | |
| 49 | HEIGHT_FORMAT "]\n", | |
| 50 | uid, uid, col.p[0]->uid); | |
| 51 | printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d+\\n[" | |
| 52 | DEPTH_FORMAT "]-\\n[" SUP_RAISE_FORMAT "]\n", | |
| 53 | uid, uid, col.len-1, col.p[col.len-1]->uid, uid); | |
| 54 | return FOUND_NOTHING; | |
| 55 | } | |
| 56 | ||
| 57 | void pile_box::output() | |
| 58 | { | |
| 4d3e9548 JL |
59 | if (output_format == troff) { |
| 60 | int i; | |
| 61 | printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); | |
| 62 | for (i = 0; i < col.len; i++) { | |
| 63 | switch (col.align) { | |
| 64 | case LEFT_ALIGN: | |
| 65 | break; | |
| 66 | case CENTER_ALIGN: | |
| 67 | printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", | |
| 68 | uid, col.p[i]->uid); | |
| 69 | break; | |
| 70 | case RIGHT_ALIGN: | |
| 71 | printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", | |
| 72 | uid, col.p[i]->uid); | |
| 73 | break; | |
| 74 | default: | |
| 75 | assert(0); | |
| 76 | } | |
| 77 | col.p[i]->output(); | |
| 78 | printf("\\h'-\\n[" WIDTH_FORMAT "]u'", col.p[i]->uid); | |
| 79 | switch (col.align) { | |
| 80 | case LEFT_ALIGN: | |
| 81 | break; | |
| 82 | case CENTER_ALIGN: | |
| 83 | printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", | |
| 84 | col.p[i]->uid, uid); | |
| 85 | break; | |
| 86 | case RIGHT_ALIGN: | |
| 87 | printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", | |
| 88 | col.p[i]->uid, uid); | |
| 89 | break; | |
| 90 | default: | |
| 91 | assert(0); | |
| 92 | } | |
| 93 | if (i != col.len - 1) | |
| 94 | printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid); | |
| 95 | } | |
| 96 | printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); | |
| 97 | printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", col.len - 1, uid); | |
| 98 | printf("\\h'\\n[" WIDTH_FORMAT "]u'", uid); | |
| 99 | } | |
| 100 | else if (output_format == mathml) { | |
| 101 | const char *av; | |
| 92d0a6a6 JR |
102 | switch (col.align) { |
| 103 | case LEFT_ALIGN: | |
| 4d3e9548 | 104 | av = "left"; |
| 92d0a6a6 JR |
105 | break; |
| 106 | case RIGHT_ALIGN: | |
| 4d3e9548 | 107 | av = "right"; |
| 92d0a6a6 JR |
108 | break; |
| 109 | case CENTER_ALIGN: | |
| 4d3e9548 | 110 | av = "center"; |
| 92d0a6a6 JR |
111 | break; |
| 112 | default: | |
| 113 | assert(0); | |
| 114 | } | |
| 4d3e9548 JL |
115 | printf("<mtable columnalign='%s'>", av); |
| 116 | for (int i = 0; i < col.len; i++) { | |
| 117 | printf("<mtr><mtd>"); | |
| 118 | col.p[i]->output(); | |
| 119 | printf("</mtd></mtr>"); | |
| 120 | } | |
| 121 | printf("</mtable>"); | |
| 92d0a6a6 | 122 | } |
| 92d0a6a6 JR |
123 | } |
| 124 | ||
| 125 | pile_box::pile_box(box *pp) : col(pp) | |
| 126 | { | |
| 127 | } | |
| 128 | ||
| 129 | void pile_box::check_tabs(int level) | |
| 130 | { | |
| 131 | col.list_check_tabs(level); | |
| 132 | } | |
| 133 | ||
| 134 | void pile_box::debug_print() | |
| 135 | { | |
| 136 | col.debug_print("pile"); | |
| 137 | } | |
| 138 | ||
| 139 | int matrix_box::compute_metrics(int style) | |
| 140 | { | |
| 141 | int i, j; | |
| 142 | int max_len = 0; | |
| 143 | int space = 0; | |
| 144 | for (i = 0; i < len; i++) { | |
| 145 | for (j = 0; j < p[i]->len; j++) | |
| 146 | p[i]->p[j]->compute_metrics(style); | |
| 147 | if (p[i]->len > max_len) | |
| 148 | max_len = p[i]->len; | |
| 149 | if (p[i]->space > space) | |
| 150 | space = p[i]->space; | |
| 151 | } | |
| 152 | for (i = 0; i < len; i++) { | |
| 153 | printf(".nr " COLUMN_WIDTH_FORMAT " 0", uid, i); | |
| 154 | for (j = 0; j < p[i]->len; j++) | |
| 155 | printf(">?\\n[" WIDTH_FORMAT "]", p[i]->p[j]->uid); | |
| 156 | printf("\n"); | |
| 157 | } | |
| 158 | printf(".nr " WIDTH_FORMAT " %dM", | |
| 159 | uid, column_sep*(len-1)+2*matrix_side_sep); | |
| 160 | for (i = 0; i < len; i++) | |
| 161 | printf("+\\n[" COLUMN_WIDTH_FORMAT "]", uid, i); | |
| 162 | printf("\n"); | |
| 163 | printf(".nr " BASELINE_SEP_FORMAT " %dM", | |
| 164 | uid, baseline_sep+space); | |
| 165 | for (i = 0; i < len; i++) | |
| 166 | for (j = 1; j < p[i]->len; j++) | |
| 167 | printf(">?(\\n[" DEPTH_FORMAT "]+\\n[" HEIGHT_FORMAT "]+%dM)", | |
| 168 | p[i]->p[j-1]->uid, p[i]->p[j]->uid, default_rule_thickness*5); | |
| 169 | // round it so that it's a multiple of the vertical resolution | |
| 170 | printf("/\\n(.V+(\\n(.V/2)*\\n(.V\n"); | |
| 171 | printf(".nr " SUP_RAISE_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d/2" | |
| 172 | "+%dM\n", | |
| 173 | uid, uid, max_len-1, axis_height - shift_down); | |
| 174 | printf(".nr " HEIGHT_FORMAT " 0\\n[" SUP_RAISE_FORMAT "]+(0", | |
| 175 | uid, uid); | |
| 176 | for (i = 0; i < len; i++) | |
| 177 | printf(">?\\n[" HEIGHT_FORMAT "]", p[i]->p[0]->uid); | |
| 178 | printf(")>?0\n"); | |
| 179 | printf(".nr " DEPTH_FORMAT " \\n[" BASELINE_SEP_FORMAT "]*%d-\\n[" | |
| 180 | SUP_RAISE_FORMAT "]+(0", | |
| 181 | uid, uid, max_len-1, uid); | |
| 182 | for (i = 0; i < len; i++) | |
| 183 | if (p[i]->len == max_len) | |
| 184 | printf(">?\\n[" DEPTH_FORMAT "]", p[i]->p[max_len-1]->uid); | |
| 185 | printf(")>?0\n"); | |
| 186 | return FOUND_NOTHING; | |
| 187 | } | |
| 188 | ||
| 189 | void matrix_box::output() | |
| 190 | { | |
| 4d3e9548 JL |
191 | if (output_format == troff) { |
| 192 | printf("\\h'%dM'", matrix_side_sep); | |
| 193 | for (int i = 0; i < len; i++) { | |
| 194 | int j; | |
| 195 | printf("\\v'-\\n[" SUP_RAISE_FORMAT "]u'", uid); | |
| 196 | for (j = 0; j < p[i]->len; j++) { | |
| 197 | switch (p[i]->align) { | |
| 198 | case LEFT_ALIGN: | |
| 199 | break; | |
| 200 | case CENTER_ALIGN: | |
| 201 | printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u/2u'", | |
| 202 | uid, i, p[i]->p[j]->uid); | |
| 203 | break; | |
| 204 | case RIGHT_ALIGN: | |
| 205 | printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u-\\n[" WIDTH_FORMAT "]u'", | |
| 206 | uid, i, p[i]->p[j]->uid); | |
| 207 | break; | |
| 208 | default: | |
| 209 | assert(0); | |
| 210 | } | |
| 211 | p[i]->p[j]->output(); | |
| 212 | printf("\\h'-\\n[" WIDTH_FORMAT "]u'", p[i]->p[j]->uid); | |
| 213 | switch (p[i]->align) { | |
| 214 | case LEFT_ALIGN: | |
| 215 | break; | |
| 216 | case CENTER_ALIGN: | |
| 217 | printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u/2u'", | |
| 218 | p[i]->p[j]->uid, uid, i); | |
| 219 | break; | |
| 220 | case RIGHT_ALIGN: | |
| 221 | printf("\\h'\\n[" WIDTH_FORMAT "]u-\\n[" COLUMN_WIDTH_FORMAT "]u'", | |
| 222 | p[i]->p[j]->uid, uid, i); | |
| 223 | break; | |
| 224 | default: | |
| 225 | assert(0); | |
| 226 | } | |
| 227 | if (j != p[i]->len - 1) | |
| 228 | printf("\\v'\\n[" BASELINE_SEP_FORMAT "]u'", uid); | |
| 92d0a6a6 | 229 | } |
| 4d3e9548 JL |
230 | printf("\\v'\\n[" SUP_RAISE_FORMAT "]u'", uid); |
| 231 | printf("\\v'-(%du*\\n[" BASELINE_SEP_FORMAT "]u)'", p[i]->len - 1, uid); | |
| 232 | printf("\\h'\\n[" COLUMN_WIDTH_FORMAT "]u'", uid, i); | |
| 233 | if (i != len - 1) | |
| 234 | printf("\\h'%dM'", column_sep); | |
| 235 | } | |
| 236 | printf("\\h'%dM'", matrix_side_sep); | |
| 237 | } | |
| 238 | else if (output_format == mathml) { | |
| 239 | int n = p[0]->len; // Each column must have the same number of rows in it | |
| 240 | printf("<mtable>"); | |
| 241 | for (int i = 0; i < n; i++) { | |
| 242 | printf("<mtr>"); | |
| 243 | for (int j = 0; j < len; j++) { | |
| 244 | const char *av; | |
| 245 | switch (p[j]->align) { | |
| 246 | case LEFT_ALIGN: | |
| 247 | av = "left"; | |
| 248 | break; | |
| 249 | case RIGHT_ALIGN: | |
| 250 | av = "right"; | |
| 251 | break; | |
| 252 | case CENTER_ALIGN: | |
| 253 | av = "center"; | |
| 254 | break; | |
| 255 | default: | |
| 256 | assert(0); | |
| 257 | } | |
| 258 | printf("<mtd columnalign='%s'>", av); | |
| 259 | p[j]->p[i]->output(); | |
| 260 | printf("</mtd>"); | |
| 92d0a6a6 | 261 | } |
| 4d3e9548 | 262 | printf("</mtr>"); |
| 92d0a6a6 | 263 | } |
| 4d3e9548 | 264 | printf("</mtable>"); |
| 92d0a6a6 | 265 | } |
| 92d0a6a6 JR |
266 | } |
| 267 | ||
| 268 | matrix_box::matrix_box(column *pp) | |
| 269 | { | |
| 270 | p = new column*[10]; | |
| 271 | for (int i = 0; i < 10; i++) | |
| 272 | p[i] = 0; | |
| 273 | maxlen = 10; | |
| 274 | len = 1; | |
| 275 | p[0] = pp; | |
| 276 | } | |
| 277 | ||
| 278 | matrix_box::~matrix_box() | |
| 279 | { | |
| 280 | for (int i = 0; i < len; i++) | |
| 281 | delete p[i]; | |
| 282 | a_delete p; | |
| 283 | } | |
| 284 | ||
| 285 | void matrix_box::append(column *pp) | |
| 286 | { | |
| 287 | if (len + 1 > maxlen) { | |
| 288 | column **oldp = p; | |
| 289 | maxlen *= 2; | |
| 290 | p = new column*[maxlen]; | |
| 291 | memcpy(p, oldp, sizeof(column*)*len); | |
| 292 | a_delete oldp; | |
| 293 | } | |
| 294 | p[len++] = pp; | |
| 295 | } | |
| 296 | ||
| 297 | void matrix_box::check_tabs(int level) | |
| 298 | { | |
| 299 | for (int i = 0; i < len; i++) | |
| 300 | p[i]->list_check_tabs(level); | |
| 301 | } | |
| 302 | ||
| 303 | void matrix_box::debug_print() | |
| 304 | { | |
| 305 | fprintf(stderr, "matrix { "); | |
| 306 | p[0]->debug_print("col"); | |
| 307 | for (int i = 1; i < len; i++) { | |
| 308 | fprintf(stderr, " "); | |
| 309 | p[i]->debug_print("col"); | |
| 310 | } | |
| 311 | fprintf(stderr, " }"); | |
| 312 | } | |
| 313 | ||
| 314 | column::column(box *pp) : box_list(pp), align(CENTER_ALIGN), space(0) | |
| 315 | { | |
| 316 | } | |
| 317 | ||
| 318 | void column::set_alignment(alignment a) | |
| 319 | { | |
| 320 | align = a; | |
| 321 | } | |
| 322 | ||
| 323 | void column::set_space(int n) | |
| 324 | { | |
| 325 | space = n; | |
| 326 | } | |
| 327 | ||
| 328 | void column::debug_print(const char *s) | |
| 329 | { | |
| 330 | char c = '\0'; // shut up -Wall | |
| 331 | switch (align) { | |
| 332 | case LEFT_ALIGN: | |
| 333 | c = 'l'; | |
| 334 | break; | |
| 335 | case RIGHT_ALIGN: | |
| 336 | c = 'r'; | |
| 337 | break; | |
| 338 | case CENTER_ALIGN: | |
| 339 | c = 'c'; | |
| 340 | break; | |
| 341 | default: | |
| 342 | assert(0); | |
| 343 | } | |
| 344 | fprintf(stderr, "%c%s %d { ", c, s, space); | |
| 345 | list_debug_print(" above "); | |
| 346 | fprintf(stderr, " }"); | |
| 347 | } | |
| 348 |