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