Adapt src/pre-eqn (src/preproc/eqn)
[s-roff.git] / src / pre-eqn / box.cpp
blob417410d70f321984fb9412b478504b99474ae0be
1 /*@
2 * Copyright (c) 2014 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 1989 - 1992, 2002, 2004, 2007
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
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
10 * Software Foundation; either version 2, or (at your option) any later
11 * version.
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.
18 * You should have received a copy of the GNU General Public License along
19 * with groff; see the file COPYING. If not, write to the Free Software
20 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
23 #include "config.h"
24 #include "eqn-config.h"
26 #include "eqn.h"
27 #include "pbox.h"
29 const char *current_roman_font;
31 char *gfont = 0;
32 char *grfont = 0;
33 char *gbfont = 0;
34 int gsize = 0;
36 int script_size_reduction = -1; // negative means reduce by a percentage
38 int positive_space = -1;
39 int negative_space = -1;
41 int minimum_size = 5;
43 int fat_offset = 4;
44 int body_height = 85;
45 int body_depth = 35;
47 int over_hang = 0;
48 int accent_width = 31;
49 int delimiter_factor = 900;
50 int delimiter_shortfall = 50;
52 int null_delimiter_space = 12;
53 int script_space = 5;
54 int thin_space = 17;
55 int medium_space = 22;
56 int thick_space = 28;
58 int num1 = 70;
59 int num2 = 40;
60 // we don't use num3, because we don't have \atop
61 int denom1 = 70;
62 int denom2 = 36;
63 int axis_height = 26; // in 100ths of an em
64 int sup1 = 42;
65 int sup2 = 37;
66 int sup3 = 28;
67 int default_rule_thickness = 4;
68 int sub1 = 20;
69 int sub2 = 23;
70 int sup_drop = 38;
71 int sub_drop = 5;
72 int x_height = 45;
73 int big_op_spacing1 = 11;
74 int big_op_spacing2 = 17;
75 int big_op_spacing3 = 20;
76 int big_op_spacing4 = 60;
77 int big_op_spacing5 = 10;
79 // These are for piles and matrices.
81 int baseline_sep = 140; // = num1 + denom1
82 int shift_down = 26; // = axis_height
83 int column_sep = 100; // = em space
84 int matrix_side_sep = 17; // = thin space
86 int nroff = 0; // should we grok ndefine or tdefine?
88 struct S {
89 const char *name;
90 int *ptr;
91 } param_table[] = { // FIXME const
92 { "fat_offset", &fat_offset },
93 { "over_hang", &over_hang },
94 { "accent_width", &accent_width },
95 { "delimiter_factor", &delimiter_factor },
96 { "delimiter_shortfall", &delimiter_shortfall },
97 { "null_delimiter_space", &null_delimiter_space },
98 { "script_space", &script_space },
99 { "thin_space", &thin_space },
100 { "medium_space", &medium_space },
101 { "thick_space", &thick_space },
102 { "num1", &num1 },
103 { "num2", &num2 },
104 { "denom1", &denom1 },
105 { "denom2", &denom2 },
106 { "axis_height", &axis_height },
107 { "sup1", &sup1 },
108 { "sup2", &sup2 },
109 { "sup3", &sup3 },
110 { "default_rule_thickness", &default_rule_thickness },
111 { "sub1", &sub1 },
112 { "sub2", &sub2 },
113 { "sup_drop", &sup_drop },
114 { "sub_drop", &sub_drop },
115 { "x_height", &x_height },
116 { "big_op_spacing1", &big_op_spacing1 },
117 { "big_op_spacing2", &big_op_spacing2 },
118 { "big_op_spacing3", &big_op_spacing3 },
119 { "big_op_spacing4", &big_op_spacing4 },
120 { "big_op_spacing5", &big_op_spacing5 },
121 { "minimum_size", &minimum_size },
122 { "baseline_sep", &baseline_sep },
123 { "shift_down", &shift_down },
124 { "column_sep", &column_sep },
125 { "matrix_side_sep", &matrix_side_sep },
126 { "draw_lines", &draw_flag },
127 { "body_height", &body_height },
128 { "body_depth", &body_depth },
129 { "nroff", &nroff },
130 { 0, 0 }
133 void set_param(const char *name, int value)
135 for (int i = 0; param_table[i].name != 0; i++)
136 if (strcmp(param_table[i].name, name) == 0) {
137 *param_table[i].ptr = value;
138 return;
140 error("unrecognised parameter `%1'", name);
143 int script_style(int style)
145 return style > SCRIPT_STYLE ? style - 2 : style;
148 int cramped_style(int style)
150 return (style & 1) ? style - 1 : style;
153 void set_space(int n)
155 if (n < 0)
156 negative_space = -n;
157 else
158 positive_space = n;
161 // Return 0 if the specified size is bad.
162 // The caller is responsible for giving the error message.
164 int set_gsize(const char *s)
166 const char *p = (*s == '+' || *s == '-') ? s + 1 : s;
167 char *end;
168 long n = strtol(p, &end, 10);
169 if (n <= 0 || *end != '\0' || n > INT_MAX)
170 return 0;
171 if (p > s) {
172 if (!gsize)
173 gsize = 10;
174 if (*s == '+') {
175 if (gsize > INT_MAX - n)
176 return 0;
177 gsize += int(n);
179 else {
180 if (gsize - n <= 0)
181 return 0;
182 gsize -= int(n);
185 else
186 gsize = int(n);
187 return 1;
190 void set_script_reduction(int n)
192 script_size_reduction = n;
195 const char *get_gfont()
197 return gfont ? gfont : "I";
200 const char *get_grfont()
202 return grfont ? grfont : "R";
205 const char *get_gbfont()
207 return gbfont ? gbfont : "B";
210 void set_gfont(const char *s)
212 a_delete gfont;
213 gfont = strsave(s);
216 void set_grfont(const char *s)
218 a_delete grfont;
219 grfont = strsave(s);
222 void set_gbfont(const char *s)
224 a_delete gbfont;
225 gbfont = strsave(s);
228 void start_string()
230 if (output_format == troff) {
231 printf(".nr " COMPATIBLE_REG " \\n(.C\n");
232 printf(".cp 0\n");
233 printf(".ds " LINE_STRING "\n");
237 void output_string()
239 if (output_format == troff)
240 printf("\\*(" LINE_STRING "\n");
241 else if (output_format == mathml && !xhtml)
242 putchar('\n');
245 void restore_compatibility()
247 if (output_format == troff)
248 printf(".cp \\n(" COMPATIBLE_REG "\n");
251 void do_text(const char *s)
253 if (output_format == troff) {
254 printf(".eo\n");
255 printf(".as " LINE_STRING " \"%s\n", s);
256 printf(".ec\n");
258 else if (output_format == mathml) {
259 fputs(s, stdout);
260 if (xhtml && strlen(s) > 0)
261 printf("\n");
265 void set_minimum_size(int n)
267 minimum_size = n;
270 void set_script_size()
272 if (minimum_size < 0)
273 minimum_size = 0;
274 if (script_size_reduction >= 0)
275 printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction, minimum_size);
276 else
277 printf(".ps (u;\\n[.ps]*7+5/10>?%d)\n", minimum_size);
280 int box::next_uid = 0;
282 box::box() : spacing_type(ORDINARY_TYPE), uid(next_uid++)
286 box::~box()
290 void box::top_level()
292 box *b = this;
293 if (output_format == troff) {
294 // debug_print();
295 // putc('\n', stderr);
296 printf(".nr " SAVED_FONT_REG " \\n[.f]\n");
297 printf(".ft\n");
298 printf(".nr " SAVED_PREV_FONT_REG " \\n[.f]\n");
299 printf(".ft %s\n", get_gfont());
300 printf(".nr " SAVED_SIZE_REG " \\n[.ps]\n");
301 if (gsize > 0) {
302 char buf[INT_DIGITS + 1];
303 sprintf(buf, "%d", gsize);
304 b = new size_box(strsave(buf), b);
306 current_roman_font = get_grfont();
307 // This catches tabs used within \Z (which aren't allowed).
308 b->check_tabs(0);
309 int r = b->compute_metrics(DISPLAY_STYLE);
310 printf(".ft \\n[" SAVED_PREV_FONT_REG "]\n");
311 printf(".ft \\n[" SAVED_FONT_REG "]\n");
312 printf(".nr " MARK_OR_LINEUP_FLAG_REG " %d\n", r);
313 if (r == FOUND_MARK) {
314 printf(".nr " SAVED_MARK_REG " \\n[" MARK_REG "]\n");
315 printf(".nr " MARK_WIDTH_REG " 0\\n[" WIDTH_FORMAT "]\n", b->uid);
317 else if (r == FOUND_LINEUP)
318 printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
319 SAVED_MARK_REG "]u-\\n[" MARK_REG "]u'\n");
320 else
321 assert(r == FOUND_NOTHING);
322 // If we use \R directly, the space will prevent it working in a
323 // macro argument; so we hide it in a string instead.
324 printf(".ds " SAVE_FONT_STRING " "
325 "\\R'" SAVED_INLINE_FONT_REG " \\En[.f]'"
326 "\\fP"
327 "\\R'" SAVED_INLINE_PREV_FONT_REG " \\En[.f]'"
328 "\\R'" SAVED_INLINE_SIZE_REG " \\En[.ps]'"
329 "\\s0"
330 "\\R'" SAVED_INLINE_PREV_SIZE_REG " \\En[.ps]'"
331 "\n"
332 ".ds " RESTORE_FONT_STRING " "
333 "\\f[\\En[" SAVED_INLINE_PREV_FONT_REG "]]"
334 "\\f[\\En[" SAVED_INLINE_FONT_REG "]]"
335 "\\s'\\En[" SAVED_INLINE_PREV_SIZE_REG "]u'"
336 "\\s'\\En[" SAVED_INLINE_SIZE_REG "]u'"
337 "\n");
338 printf(".as1 " LINE_STRING " \\&\\E*[" SAVE_FONT_STRING "]");
339 printf("\\f[%s]", get_gfont());
340 printf("\\s'\\En[" SAVED_SIZE_REG "]u'");
341 current_roman_font = get_grfont();
342 b->output();
343 printf("\\E*[" RESTORE_FONT_STRING "]\n");
344 if (r == FOUND_LINEUP)
345 printf(".if r" SAVED_MARK_REG " .as1 " LINE_STRING " \\h'\\n["
346 MARK_WIDTH_REG "]u-\\n[" SAVED_MARK_REG "]u-(\\n["
347 WIDTH_FORMAT "]u-\\n[" MARK_REG "]u)'\n",
348 b->uid);
349 b->extra_space();
350 if (!inline_flag)
351 printf(".ne \\n[" HEIGHT_FORMAT "]u-%dM>?0+(\\n["
352 DEPTH_FORMAT "]u-%dM>?0)\n",
353 b->uid, body_height, b->uid, body_depth);
355 else if (output_format == mathml) {
356 if (xhtml)
357 printf(".MATHML ");
358 printf("<math>");
359 b->output();
360 printf("</math>");
362 delete b;
363 next_uid = 0;
366 void box::extra_space()
368 printf(".if !r" EQN_NO_EXTRA_SPACE_REG " "
369 ".nr " EQN_NO_EXTRA_SPACE_REG " 0\n");
370 if (positive_space >= 0 || negative_space >= 0) {
371 if (positive_space > 0)
372 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
373 ".as1 " LINE_STRING " \\x'-%dM'\n", positive_space);
374 if (negative_space > 0)
375 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
376 ".as1 " LINE_STRING " \\x'%dM'\n", negative_space);
377 positive_space = negative_space = -1;
379 else {
380 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
381 ".if \\n[" HEIGHT_FORMAT "]>%dM .as1 " LINE_STRING
382 " \\x'-(\\n[" HEIGHT_FORMAT
383 "]u-%dM)'\n",
384 uid, body_height, uid, body_height);
385 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG "] "
386 ".if \\n[" DEPTH_FORMAT "]>%dM .as1 " LINE_STRING
387 " \\x'\\n[" DEPTH_FORMAT
388 "]u-%dM'\n",
389 uid, body_depth, uid, body_depth);
393 int box::compute_metrics(int)
395 printf(".nr " WIDTH_FORMAT " 0\n", uid);
396 printf(".nr " HEIGHT_FORMAT " 0\n", uid);
397 printf(".nr " DEPTH_FORMAT " 0\n", uid);
398 return FOUND_NOTHING;
401 void box::compute_subscript_kern()
403 printf(".nr " SUB_KERN_FORMAT " 0\n", uid);
406 void box::compute_skew()
408 printf(".nr " SKEW_FORMAT " 0\n", uid);
411 void box::output()
415 void box::check_tabs(int)
419 int box::is_char()
421 return 0;
424 int box::left_is_italic()
426 return 0;
429 int box::right_is_italic()
431 return 0;
434 void box::hint(unsigned)
438 void box::handle_char_type(int, int)
442 box_list::box_list(box *pp)
444 p = new box*[10];
445 for (int i = 0; i < 10; i++)
446 p[i] = 0;
447 maxlen = 10;
448 len = 1;
449 p[0] = pp;
452 void box_list::append(box *pp)
454 if (len + 1 > maxlen) {
455 box **oldp = p;
456 maxlen *= 2;
457 p = new box*[maxlen];
458 memcpy(p, oldp, sizeof(box*)*len);
459 a_delete oldp;
461 p[len++] = pp;
464 box_list::~box_list()
466 for (int i = 0; i < len; i++)
467 delete p[i];
468 a_delete p;
471 void box_list::list_check_tabs(int level)
473 for (int i = 0; i < len; i++)
474 p[i]->check_tabs(level);
477 pointer_box::pointer_box(box *pp) : p(pp)
479 spacing_type = p->spacing_type;
482 pointer_box::~pointer_box()
484 delete p;
487 int pointer_box::compute_metrics(int style)
489 int r = p->compute_metrics(style);
490 printf(".nr " WIDTH_FORMAT " 0\\n[" WIDTH_FORMAT "]\n", uid, p->uid);
491 printf(".nr " HEIGHT_FORMAT " \\n[" HEIGHT_FORMAT "]\n", uid, p->uid);
492 printf(".nr " DEPTH_FORMAT " \\n[" DEPTH_FORMAT "]\n", uid, p->uid);
493 return r;
496 void pointer_box::compute_subscript_kern()
498 p->compute_subscript_kern();
499 printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", uid, p->uid);
502 void pointer_box::compute_skew()
504 p->compute_skew();
505 printf(".nr " SKEW_FORMAT " 0\\n[" SKEW_FORMAT "]\n",
506 uid, p->uid);
509 void pointer_box::check_tabs(int level)
511 p->check_tabs(level);
514 int simple_box::compute_metrics(int)
516 printf(".nr " WIDTH_FORMAT " 0\\w" DELIMITER_CHAR, uid);
517 output();
518 printf(DELIMITER_CHAR "\n");
519 printf(".nr " HEIGHT_FORMAT " 0>?\\n[rst]\n", uid);
520 printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?0\n", uid);
521 printf(".nr " SUB_KERN_FORMAT " 0-\\n[ssc]>?0\n", uid);
522 printf(".nr " SKEW_FORMAT " 0\\n[skw]\n", uid);
523 return FOUND_NOTHING;
526 void simple_box::compute_subscript_kern()
528 // do nothing, we already computed it in do_metrics
531 void simple_box::compute_skew()
533 // do nothing, we already computed it in do_metrics
536 int box::is_simple()
538 return 0;
541 int simple_box::is_simple()
543 return 1;
546 quoted_text_box::quoted_text_box(char *s) : text(s)
550 quoted_text_box::~quoted_text_box()
552 a_delete text;
555 void quoted_text_box::output()
557 if (text) {
558 if (output_format == troff)
559 fputs(text, stdout);
560 else if (output_format == mathml) {
561 fputs("<mtext>", stdout);
562 fputs(text, stdout);
563 fputs("</mtext>", stdout);
568 tab_box::tab_box() : disabled(0)
572 // We treat a tab_box as having width 0 for width computations.
574 void tab_box::output()
576 if (!disabled)
577 printf("\\t");
580 void tab_box::check_tabs(int level)
582 if (level > 0) {
583 error("tabs allowed only at outermost level");
584 disabled = 1;
588 space_box::space_box()
590 spacing_type = SUPPRESS_TYPE;
593 void space_box::output()
595 if (output_format == troff)
596 printf("\\h'%dM'", thick_space);
597 else if (output_format == mathml)
598 // &ThickSpace; doesn't display right under Firefox 1.5.
599 printf("<mtext>&ensp;</mtext>");
602 half_space_box::half_space_box()
604 spacing_type = SUPPRESS_TYPE;
607 void half_space_box::output()
609 if (output_format == troff)
610 printf("\\h'%dM'", thin_space);
611 else if (output_format == mathml)
612 printf("<mtext>&ThinSpace;</mtext>");
615 void box_list::list_debug_print(const char *sep)
617 p[0]->debug_print();
618 for (int i = 1; i < len; i++) {
619 fprintf(stderr, "%s", sep);
620 p[i]->debug_print();
624 void quoted_text_box::debug_print()
626 fprintf(stderr, "\"%s\"", (text ? text : ""));
629 void half_space_box::debug_print()
631 fprintf(stderr, "^");
634 void space_box::debug_print()
636 fprintf(stderr, "~");
639 void tab_box::debug_print()
641 fprintf(stderr, "<tab>");
644 // s-it2-mode