Line data Source code
1 : /* Copyright 1989-2024 Free Software Foundation, Inc. 2 : Written by James Clark (jjc@jclark.com) 3 : 4 : This file is part of groff, the GNU roff typesetting system. 5 : 6 : groff is free software; you can redistribute it and/or modify it under 7 : the terms of the GNU General Public License as published by the Free 8 : Software Foundation, either version 3 of the License, or 9 : (at your option) any later version. 10 : 11 : groff is distributed in the hope that it will be useful, but WITHOUT ANY 12 : WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 : for more details. 15 : 16 : You should have received a copy of the GNU General Public License 17 : along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 : 19 : #ifdef HAVE_CONFIG_H 20 : #include <config.h> 21 : #endif 22 : 23 : #include "eqn.h" 24 : #include "pbox.h" 25 : 26 1253 : list_box *box::to_list_box() 27 : { 28 1253 : return 0; 29 : } 30 : 31 531 : list_box *list_box::to_list_box() 32 : { 33 531 : return this; 34 : } 35 : 36 727 : void list_box::append(box *pp) 37 : { 38 727 : list_box *q = pp->to_list_box(); 39 727 : if (q == 0) 40 664 : list.append(pp); 41 : else { 42 210 : for (int i = 0; i < q->list.len; i++) { 43 147 : list.append(q->list.p[i]); 44 147 : q->list.p[i] = 0; 45 : } 46 63 : q->list.len = 0; 47 63 : delete q; 48 : } 49 727 : } 50 : 51 276 : list_box::list_box(box *pp) : list(pp), sty(-1) 52 : { 53 276 : list_box *q = pp->to_list_box(); 54 276 : if (q != 0) { 55 : // flatten it 56 0 : list.p[0] = q->list.p[0]; 57 0 : for (int i = 1; i < q->list.len; i++) { 58 0 : list.append(q->list.p[i]); 59 0 : q->list.p[i] = 0; 60 : } 61 0 : q->list.len = 0; 62 0 : delete q; 63 : } 64 276 : } 65 : 66 1454 : static int compute_spacing(int is_script, int left, int right) 67 : { 68 1454 : if (left == SUPPRESS_TYPE || right == SUPPRESS_TYPE) 69 326 : return 0; 70 1128 : if (left == PUNCTUATION_TYPE) 71 104 : return is_script ? 0 : get_param("thin_space"); 72 1024 : if (left == OPENING_TYPE || right == CLOSING_TYPE) 73 124 : return 0; 74 900 : if (right == BINARY_TYPE || left == BINARY_TYPE) 75 138 : return is_script ? 0 : get_param("medium_space"); 76 762 : if (right == RELATION_TYPE) { 77 102 : if (left == RELATION_TYPE) 78 0 : return 0; 79 : else 80 102 : return is_script ? 0 : get_param("thick_space"); 81 : } 82 660 : if (left == RELATION_TYPE) 83 102 : return is_script ? 0 : get_param("thick_space"); 84 558 : if (right == OPERATOR_TYPE) 85 18 : return get_param("thin_space"); 86 540 : if (left == INNER_TYPE || right == INNER_TYPE) 87 4 : return is_script ? 0 : get_param("thin_space"); 88 536 : if (left == OPERATOR_TYPE && right == ORDINARY_TYPE) 89 62 : return get_param("thin_space"); 90 474 : return 0; 91 : } 92 : 93 213 : int list_box::compute_metrics(int style) 94 : { 95 213 : sty = style; 96 : int i; 97 1153 : for (i = 0; i < list.len; i++) { 98 940 : int t = list.p[i]->spacing_type; 99 : // 5 100 940 : if (t == BINARY_TYPE) { 101 : int prevt; 102 58 : if (i == 0 103 35 : || (prevt = list.p[i-1]->spacing_type) == BINARY_TYPE 104 35 : || prevt == OPERATOR_TYPE 105 35 : || prevt == RELATION_TYPE 106 35 : || prevt == OPENING_TYPE 107 35 : || prevt == SUPPRESS_TYPE 108 93 : || prevt == PUNCTUATION_TYPE) 109 23 : list.p[i]->spacing_type = ORDINARY_TYPE; 110 : } 111 : // 7 112 882 : else if ((t == RELATION_TYPE || t == CLOSING_TYPE 113 796 : || t == PUNCTUATION_TYPE) 114 159 : && i > 0 && list.p[i-1]->spacing_type == BINARY_TYPE) 115 0 : list.p[i-1]->spacing_type = ORDINARY_TYPE; 116 : } 117 1153 : for (i = 0; i < list.len; i++) { 118 940 : unsigned flags = 0; 119 940 : if (i - 1 >= 0 && list.p[i - 1]->right_is_italic()) 120 247 : flags |= HINT_PREV_IS_ITALIC; 121 940 : if (i + 1 < list.len && list.p[i + 1]->left_is_italic()) 122 295 : flags |= HINT_NEXT_IS_ITALIC; 123 940 : if (flags) 124 495 : list.p[i]->hint(flags); 125 : } 126 213 : is_script = (style <= SCRIPT_STYLE); 127 213 : int total_spacing = 0; 128 940 : for (i = 1; i < list.len; i++) 129 727 : total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type, 130 727 : list.p[i]->spacing_type); 131 213 : int res = 0; 132 1153 : for (i = 0; i < list.len; i++) 133 940 : if (!list.p[i]->is_simple()) { 134 193 : int r = list.p[i]->compute_metrics(style); 135 193 : if (r) { 136 0 : if (res) 137 0 : error("multiple marks and lineups"); 138 : else { 139 0 : compute_sublist_width(i); 140 0 : printf(".nr " MARK_REG " +\\n[" TEMP_REG"]\n"); 141 0 : res = r; 142 : } 143 : } 144 : } 145 213 : printf(".nr " WIDTH_FORMAT " %dM", uid, total_spacing); 146 1153 : for (i = 0; i < list.len; i++) 147 940 : if (!list.p[i]->is_simple()) 148 193 : printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid); 149 213 : printf("\n"); 150 213 : printf(".nr " HEIGHT_FORMAT " 0", uid); 151 1153 : for (i = 0; i < list.len; i++) 152 940 : if (!list.p[i]->is_simple()) 153 193 : printf(">?\\n[" HEIGHT_FORMAT "]", list.p[i]->uid); 154 213 : printf("\n"); 155 213 : printf(".nr " DEPTH_FORMAT " 0", uid); 156 1153 : for (i = 0; i < list.len; i++) 157 940 : if (!list.p[i]->is_simple()) 158 193 : printf(">?\\n[" DEPTH_FORMAT "]", list.p[i]->uid); 159 213 : printf("\n"); 160 213 : int have_simple = 0; 161 465 : for (i = 0; i < list.len && !have_simple; i++) 162 252 : have_simple = list.p[i]->is_simple(); 163 213 : if (have_simple) { 164 207 : printf(".nr " WIDTH_FORMAT " +\\w" DELIMITER_CHAR, uid); 165 1135 : for (i = 0; i < list.len; i++) 166 928 : if (list.p[i]->is_simple()) 167 747 : list.p[i]->output(); 168 207 : printf(DELIMITER_CHAR "\n"); 169 207 : printf(".nr " HEIGHT_FORMAT " \\n[rst]>?\\n[" HEIGHT_FORMAT "]\n", 170 207 : uid, uid); 171 207 : printf(".nr " DEPTH_FORMAT " 0-\\n[rsb]>?\\n[" DEPTH_FORMAT "]\n", 172 207 : uid, uid); 173 : } 174 213 : return res; 175 : } 176 : 177 0 : void list_box::compute_sublist_width(int n) 178 : { 179 0 : int total_spacing = 0; 180 : int i; 181 0 : for (i = 1; i < n + 1 && i < list.len; i++) 182 0 : total_spacing += compute_spacing(is_script, list.p[i-1]->spacing_type, 183 0 : list.p[i]->spacing_type); 184 0 : printf(".nr " TEMP_REG " %dM", total_spacing); 185 0 : for (i = 0; i < n; i++) 186 0 : if (!list.p[i]->is_simple()) 187 0 : printf("+\\n[" WIDTH_FORMAT "]", list.p[i]->uid); 188 0 : int have_simple = 0; 189 0 : for (i = 0; i < n && !have_simple; i++) 190 0 : have_simple = list.p[i]->is_simple(); 191 0 : if (have_simple) { 192 0 : printf("+\\w" DELIMITER_CHAR); 193 0 : for (i = 0; i < n; i++) 194 0 : if (list.p[i]->is_simple()) 195 0 : list.p[i]->output(); 196 0 : printf(DELIMITER_CHAR); 197 : } 198 0 : printf("\n"); 199 0 : } 200 : 201 0 : void list_box::compute_subscript_kern() 202 : { 203 : // We can only call compute_subscript_kern if we have called 204 : // compute_metrics first. 205 0 : if (list.p[list.len-1]->is_simple()) 206 0 : list.p[list.len-1]->compute_metrics(sty); 207 0 : list.p[list.len-1]->compute_subscript_kern(); 208 0 : printf(".nr " SUB_KERN_FORMAT " \\n[" SUB_KERN_FORMAT "]\n", 209 0 : uid, list.p[list.len-1]->uid); 210 0 : } 211 : 212 213 : void list_box::output() 213 : { 214 213 : if (output_format == mathml) 215 0 : printf("<mrow>"); 216 1153 : for (int i = 0; i < list.len; i++) { 217 940 : if (output_format == troff && i > 0) { 218 1454 : int n = compute_spacing(is_script, 219 727 : list.p[i-1]->spacing_type, 220 727 : list.p[i]->spacing_type); 221 727 : if (n > 0) 222 229 : printf("\\h'%dM'", n); 223 : } 224 940 : list.p[i]->output(); 225 : } 226 213 : if (output_format == mathml) 227 0 : printf("</mrow>"); 228 213 : } 229 : 230 0 : void list_box::handle_char_type(int st, int ft) 231 : { 232 0 : for (int i = 0; i < list.len; i++) 233 0 : list.p[i]->handle_char_type(st, ft); 234 0 : } 235 : 236 0 : void list_box::debug_print() 237 : { 238 0 : list.list_debug_print(" "); 239 0 : } 240 : 241 213 : void list_box::diagnose_tab_stop_usage(int level) 242 : { 243 213 : list.list_diagnose_tab_stop_usage(level); 244 213 : } 245 : 246 : // Local Variables: 247 : // fill-column: 72 248 : // mode: C++ 249 : // End: 250 : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72: