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
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
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.
24 #include "eqn-config.h"
29 const char *current_roman_font
;
36 int script_size_reduction
= -1; // negative means reduce by a percentage
38 int positive_space
= -1;
39 int negative_space
= -1;
48 int accent_width
= 31;
49 int delimiter_factor
= 900;
50 int delimiter_shortfall
= 50;
52 int null_delimiter_space
= 12;
55 int medium_space
= 22;
60 // we don't use num3, because we don't have \atop
63 int axis_height
= 26; // in 100ths of an em
67 int default_rule_thickness
= 4;
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?
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
},
104 { "denom1", &denom1
},
105 { "denom2", &denom2
},
106 { "axis_height", &axis_height
},
110 { "default_rule_thickness", &default_rule_thickness
},
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
},
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
;
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
)
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
;
168 long n
= strtol(p
, &end
, 10);
169 if (n
<= 0 || *end
!= '\0' || n
> INT_MAX
)
175 if (gsize
> INT_MAX
- n
)
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
)
216 void set_grfont(const char *s
)
222 void set_gbfont(const char *s
)
230 if (output_format
== troff
) {
231 printf(".nr " COMPATIBLE_REG
" \\n(.C\n");
233 printf(".ds " LINE_STRING
"\n");
239 if (output_format
== troff
)
240 printf("\\*(" LINE_STRING
"\n");
241 else if (output_format
== mathml
&& !xhtml
)
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
) {
255 printf(".as " LINE_STRING
" \"%s\n", s
);
258 else if (output_format
== mathml
) {
260 if (xhtml
&& strlen(s
) > 0)
265 void set_minimum_size(int n
)
270 void set_script_size()
272 if (minimum_size
< 0)
274 if (script_size_reduction
>= 0)
275 printf(".ps \\n[.s]-%d>?%d\n", script_size_reduction
, minimum_size
);
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
++)
290 void box::top_level()
293 if (output_format
== troff
) {
295 // putc('\n', stderr);
296 printf(".nr " SAVED_FONT_REG
" \\n[.f]\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");
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).
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");
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]'"
327 "\\R'" SAVED_INLINE_PREV_FONT_REG
" \\En[.f]'"
328 "\\R'" SAVED_INLINE_SIZE_REG
" \\En[.ps]'"
330 "\\R'" SAVED_INLINE_PREV_SIZE_REG
" \\En[.ps]'"
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'"
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();
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",
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
) {
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;
380 printf(".if !\\n[" EQN_NO_EXTRA_SPACE_REG
"] "
381 ".if \\n[" HEIGHT_FORMAT
"]>%dM .as1 " LINE_STRING
382 " \\x'-(\\n[" HEIGHT_FORMAT
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
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
);
415 void box::check_tabs(int)
424 int box::left_is_italic()
429 int box::right_is_italic()
434 void box::hint(unsigned)
438 void box::handle_char_type(int, int)
442 box_list::box_list(box
*pp
)
445 for (int i
= 0; i
< 10; i
++)
452 void box_list::append(box
*pp
)
454 if (len
+ 1 > maxlen
) {
457 p
= new box
*[maxlen
];
458 memcpy(p
, oldp
, sizeof(box
*)*len
);
464 box_list::~box_list()
466 for (int i
= 0; i
< len
; i
++)
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()
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
);
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()
505 printf(".nr " SKEW_FORMAT
" 0\\n[" SKEW_FORMAT
"]\n",
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
);
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
541 int simple_box::is_simple()
546 quoted_text_box::quoted_text_box(char *s
) : text(s
)
550 quoted_text_box::~quoted_text_box()
555 void quoted_text_box::output()
558 if (output_format
== troff
)
560 else if (output_format
== mathml
) {
561 fputs("<mtext>", 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()
580 void tab_box::check_tabs(int level
)
583 error("tabs allowed only at outermost level");
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 //    doesn't display right under Firefox 1.5.
599 printf("<mtext> </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> </mtext>");
615 void box_list::list_debug_print(const char *sep
)
618 for (int i
= 1; i
< len
; i
++) {
619 fprintf(stderr
, "%s", sep
);
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>");