| Commit | Line | Data |
|---|---|---|
| 92d0a6a6 | 1 | // -*- C++ -*- |
| 4d3e9548 JL |
2 | /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005, |
| 3 | 2006, 2008, 2009 | |
| 92d0a6a6 JR |
4 | Free Software Foundation, Inc. |
| 5 | Written by James Clark (jjc@jclark.com) | |
| 6 | ||
| 7 | This file is part of groff. | |
| 8 | ||
| 9 | groff is free software; you can redistribute it and/or modify it under | |
| 10 | the terms of the GNU General Public License as published by the Free | |
| 4d3e9548 JL |
11 | Software Foundation, either version 3 of the License, or |
| 12 | (at your option) any later version. | |
| 92d0a6a6 JR |
13 | |
| 14 | groff is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 16 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 17 | for more details. | |
| 18 | ||
| 4d3e9548 JL |
19 | You should have received a copy of the GNU General Public License |
| 20 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
| 465b256c JR |
21 | |
| 22 | extern int debug_state; | |
| 92d0a6a6 JR |
23 | |
| 24 | #include "troff.h" | |
| 25 | ||
| 26 | #ifdef HAVE_UNISTD_H | |
| 27 | #include <unistd.h> | |
| 28 | #endif | |
| 29 | ||
| 30 | #include "dictionary.h" | |
| 31 | #include "hvunits.h" | |
| 465b256c JR |
32 | #include "stringclass.h" |
| 33 | #include "mtsm.h" | |
| 92d0a6a6 JR |
34 | #include "env.h" |
| 35 | #include "request.h" | |
| 36 | #include "node.h" | |
| 37 | #include "token.h" | |
| 465b256c JR |
38 | #include "div.h" |
| 39 | #include "reg.h" | |
| 92d0a6a6 | 40 | #include "font.h" |
| 4d3e9548 | 41 | #include "charinfo.h" |
| 92d0a6a6 | 42 | #include "input.h" |
| 92d0a6a6 | 43 | #include "geometry.h" |
| 92d0a6a6 JR |
44 | |
| 45 | #include "nonposix.h" | |
| 46 | ||
| 47 | #ifdef _POSIX_VERSION | |
| 48 | ||
| 49 | #include <sys/wait.h> | |
| 50 | ||
| 51 | #else /* not _POSIX_VERSION */ | |
| 52 | ||
| 53 | /* traditional Unix */ | |
| 54 | ||
| 55 | #define WIFEXITED(s) (((s) & 0377) == 0) | |
| 56 | #define WEXITSTATUS(s) (((s) >> 8) & 0377) | |
| 57 | #define WTERMSIG(s) ((s) & 0177) | |
| 58 | #define WIFSTOPPED(s) (((s) & 0377) == 0177) | |
| 59 | #define WSTOPSIG(s) (((s) >> 8) & 0377) | |
| 60 | #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177)) | |
| 61 | ||
| 62 | #endif /* not _POSIX_VERSION */ | |
| 63 | ||
| 465b256c JR |
64 | // declarations to avoid friend name injections |
| 65 | class tfont; | |
| 66 | class tfont_spec; | |
| 67 | tfont *make_tfont(tfont_spec &); | |
| 68 | ||
| 69 | ||
| 92d0a6a6 JR |
70 | /* |
| 71 | * how many boundaries of images have been written? Useful for | |
| 72 | * debugging grohtml | |
| 73 | */ | |
| 74 | ||
| 75 | int image_no = 0; | |
| 76 | static int suppress_start_page = 0; | |
| 77 | ||
| 78 | #define STORE_WIDTH 1 | |
| 79 | ||
| 80 | symbol HYPHEN_SYMBOL("hy"); | |
| 81 | ||
| 82 | // Character used when a hyphen is inserted at a line break. | |
| 83 | static charinfo *soft_hyphen_char; | |
| 84 | ||
| 85 | enum constant_space_type { | |
| 86 | CONSTANT_SPACE_NONE, | |
| 87 | CONSTANT_SPACE_RELATIVE, | |
| 88 | CONSTANT_SPACE_ABSOLUTE | |
| 89 | }; | |
| 90 | ||
| 91 | struct special_font_list { | |
| 92 | int n; | |
| 93 | special_font_list *next; | |
| 94 | }; | |
| 95 | ||
| 96 | special_font_list *global_special_fonts; | |
| 97 | static int global_ligature_mode = 1; | |
| 98 | static int global_kern_mode = 1; | |
| 99 | ||
| 100 | class track_kerning_function { | |
| 101 | int non_zero; | |
| 102 | units min_size; | |
| 103 | hunits min_amount; | |
| 104 | units max_size; | |
| 105 | hunits max_amount; | |
| 106 | public: | |
| 107 | track_kerning_function(); | |
| 108 | track_kerning_function(units, hunits, units, hunits); | |
| 109 | int operator==(const track_kerning_function &); | |
| 110 | int operator!=(const track_kerning_function &); | |
| 111 | hunits compute(int point_size); | |
| 112 | }; | |
| 113 | ||
| 114 | // embolden fontno when this is the current font | |
| 115 | ||
| 116 | struct conditional_bold { | |
| 117 | conditional_bold *next; | |
| 118 | int fontno; | |
| 119 | hunits offset; | |
| 120 | conditional_bold(int, hunits, conditional_bold * = 0); | |
| 121 | }; | |
| 122 | ||
| 92d0a6a6 JR |
123 | class font_info { |
| 124 | tfont *last_tfont; | |
| 125 | int number; | |
| 126 | font_size last_size; | |
| 127 | int last_height; | |
| 128 | int last_slant; | |
| 129 | symbol internal_name; | |
| 130 | symbol external_name; | |
| 131 | font *fm; | |
| 132 | char is_bold; | |
| 133 | hunits bold_offset; | |
| 134 | track_kerning_function track_kern; | |
| 135 | constant_space_type is_constant_spaced; | |
| 136 | units constant_space; | |
| 137 | int last_ligature_mode; | |
| 138 | int last_kern_mode; | |
| 139 | conditional_bold *cond_bold_list; | |
| 140 | void flush(); | |
| 141 | public: | |
| 142 | special_font_list *sf; | |
| 465b256c | 143 | font_info(symbol, int, symbol, font *); |
| 92d0a6a6 JR |
144 | int contains(charinfo *); |
| 145 | void set_bold(hunits); | |
| 146 | void unbold(); | |
| 147 | void set_conditional_bold(int, hunits); | |
| 148 | void conditional_unbold(int); | |
| 149 | void set_track_kern(track_kerning_function &); | |
| 150 | void set_constant_space(constant_space_type, units = 0); | |
| 151 | int is_named(symbol); | |
| 152 | symbol get_name(); | |
| 153 | tfont *get_tfont(font_size, int, int, int); | |
| 154 | hunits get_space_width(font_size, int); | |
| 155 | hunits get_narrow_space_width(font_size); | |
| 156 | hunits get_half_narrow_space_width(font_size); | |
| 157 | int get_bold(hunits *); | |
| 158 | int is_special(); | |
| 159 | int is_style(); | |
| 4d3e9548 JL |
160 | void set_zoom(int); |
| 161 | int get_zoom(); | |
| 92d0a6a6 | 162 | friend symbol get_font_name(int, environment *); |
| 465b256c | 163 | friend symbol get_style_name(int); |
| 92d0a6a6 JR |
164 | }; |
| 165 | ||
| 166 | class tfont_spec { | |
| 167 | protected: | |
| 168 | symbol name; | |
| 169 | int input_position; | |
| 170 | font *fm; | |
| 171 | font_size size; | |
| 172 | char is_bold; | |
| 173 | char is_constant_spaced; | |
| 174 | int ligature_mode; | |
| 175 | int kern_mode; | |
| 176 | hunits bold_offset; | |
| 177 | hunits track_kern; // add this to the width | |
| 178 | hunits constant_space_width; | |
| 179 | int height; | |
| 180 | int slant; | |
| 181 | public: | |
| 465b256c | 182 | tfont_spec(symbol, int, font *, font_size, int, int); |
| 92d0a6a6 JR |
183 | tfont_spec(const tfont_spec &spec) { *this = spec; } |
| 184 | tfont_spec plain(); | |
| 185 | int operator==(const tfont_spec &); | |
| 186 | friend tfont *font_info::get_tfont(font_size fs, int, int, int); | |
| 187 | }; | |
| 188 | ||
| 189 | class tfont : public tfont_spec { | |
| 190 | static tfont *tfont_list; | |
| 191 | tfont *next; | |
| 192 | tfont *plain_version; | |
| 193 | public: | |
| 194 | tfont(tfont_spec &); | |
| 195 | int contains(charinfo *); | |
| 196 | hunits get_width(charinfo *c); | |
| 197 | int get_bold(hunits *); | |
| 198 | int get_constant_space(hunits *); | |
| 199 | hunits get_track_kern(); | |
| 200 | tfont *get_plain(); | |
| 201 | font_size get_size(); | |
| 4d3e9548 | 202 | int get_zoom(); |
| 92d0a6a6 JR |
203 | symbol get_name(); |
| 204 | charinfo *get_lig(charinfo *c1, charinfo *c2); | |
| 205 | int get_kern(charinfo *c1, charinfo *c2, hunits *res); | |
| 206 | int get_input_position(); | |
| 207 | int get_character_type(charinfo *); | |
| 208 | int get_height(); | |
| 209 | int get_slant(); | |
| 210 | vunits get_char_height(charinfo *); | |
| 211 | vunits get_char_depth(charinfo *); | |
| 212 | hunits get_char_skew(charinfo *); | |
| 213 | hunits get_italic_correction(charinfo *); | |
| 214 | hunits get_left_italic_correction(charinfo *); | |
| 215 | hunits get_subscript_correction(charinfo *); | |
| 216 | friend tfont *make_tfont(tfont_spec &); | |
| 217 | }; | |
| 218 | ||
| 219 | inline int env_definite_font(environment *env) | |
| 220 | { | |
| 221 | return env->get_family()->make_definite(env->get_font()); | |
| 222 | } | |
| 223 | ||
| 224 | /* font_info functions */ | |
| 225 | ||
| 226 | static font_info **font_table = 0; | |
| 227 | static int font_table_size = 0; | |
| 228 | ||
| 229 | font_info::font_info(symbol nm, int n, symbol enm, font *f) | |
| 230 | : last_tfont(0), number(n), last_size(0), | |
| 231 | internal_name(nm), external_name(enm), fm(f), | |
| 232 | is_bold(0), is_constant_spaced(CONSTANT_SPACE_NONE), last_ligature_mode(1), | |
| 233 | last_kern_mode(1), cond_bold_list(0), sf(0) | |
| 234 | { | |
| 235 | } | |
| 236 | ||
| 237 | inline int font_info::contains(charinfo *ci) | |
| 238 | { | |
| 4d3e9548 | 239 | return fm != 0 && fm->contains(ci->as_glyph()); |
| 92d0a6a6 JR |
240 | } |
| 241 | ||
| 242 | inline int font_info::is_special() | |
| 243 | { | |
| 244 | return fm != 0 && fm->is_special(); | |
| 245 | } | |
| 246 | ||
| 247 | inline int font_info::is_style() | |
| 248 | { | |
| 249 | return fm == 0; | |
| 250 | } | |
| 251 | ||
| 4d3e9548 JL |
252 | void font_info::set_zoom(int zoom) |
| 253 | { | |
| 254 | assert(fm != 0); | |
| 255 | fm->set_zoom(zoom); | |
| 256 | } | |
| 257 | ||
| 258 | inline int font_info::get_zoom() | |
| 259 | { | |
| 260 | if (is_style()) | |
| 261 | return 0; | |
| 262 | return fm->get_zoom(); | |
| 263 | } | |
| 264 | ||
| 92d0a6a6 JR |
265 | tfont *make_tfont(tfont_spec &spec) |
| 266 | { | |
| 267 | for (tfont *p = tfont::tfont_list; p; p = p->next) | |
| 268 | if (*p == spec) | |
| 269 | return p; | |
| 270 | return new tfont(spec); | |
| 271 | } | |
| 272 | ||
| 4d3e9548 JL |
273 | int env_get_zoom(environment *env) |
| 274 | { | |
| 275 | int fontno = env->get_family()->make_definite(env->get_font()); | |
| 276 | return font_table[fontno]->get_zoom(); | |
| 277 | } | |
| 278 | ||
| 92d0a6a6 JR |
279 | // this is the current_font, fontno is where we found the character, |
| 280 | // presumably a special font | |
| 281 | ||
| 282 | tfont *font_info::get_tfont(font_size fs, int height, int slant, int fontno) | |
| 283 | { | |
| 284 | if (last_tfont == 0 || fs != last_size | |
| 285 | || height != last_height || slant != last_slant | |
| 286 | || global_ligature_mode != last_ligature_mode | |
| 287 | || global_kern_mode != last_kern_mode | |
| 288 | || fontno != number) { | |
| 289 | font_info *f = font_table[fontno]; | |
| 290 | tfont_spec spec(f->external_name, f->number, f->fm, fs, height, slant); | |
| 291 | for (conditional_bold *p = cond_bold_list; p; p = p->next) | |
| 292 | if (p->fontno == fontno) { | |
| 293 | spec.is_bold = 1; | |
| 294 | spec.bold_offset = p->offset; | |
| 295 | break; | |
| 296 | } | |
| 297 | if (!spec.is_bold && is_bold) { | |
| 298 | spec.is_bold = 1; | |
| 299 | spec.bold_offset = bold_offset; | |
| 300 | } | |
| 301 | spec.track_kern = track_kern.compute(fs.to_scaled_points()); | |
| 302 | spec.ligature_mode = global_ligature_mode; | |
| 303 | spec.kern_mode = global_kern_mode; | |
| 304 | switch (is_constant_spaced) { | |
| 305 | case CONSTANT_SPACE_NONE: | |
| 306 | break; | |
| 307 | case CONSTANT_SPACE_ABSOLUTE: | |
| 308 | spec.is_constant_spaced = 1; | |
| 309 | spec.constant_space_width = constant_space; | |
| 310 | break; | |
| 311 | case CONSTANT_SPACE_RELATIVE: | |
| 312 | spec.is_constant_spaced = 1; | |
| 313 | spec.constant_space_width | |
| 314 | = scale(constant_space*fs.to_scaled_points(), | |
| 315 | units_per_inch, | |
| 316 | 36*72*sizescale); | |
| 317 | break; | |
| 318 | default: | |
| 319 | assert(0); | |
| 320 | } | |
| 321 | if (fontno != number) | |
| 322 | return make_tfont(spec); | |
| 4d3e9548 | 323 | // save font for comparison purposes |
| 92d0a6a6 | 324 | last_tfont = make_tfont(spec); |
| 4d3e9548 | 325 | // save font related values not contained in tfont |
| 92d0a6a6 JR |
326 | last_size = fs; |
| 327 | last_height = height; | |
| 328 | last_slant = slant; | |
| 329 | last_ligature_mode = global_ligature_mode; | |
| 330 | last_kern_mode = global_kern_mode; | |
| 331 | } | |
| 332 | return last_tfont; | |
| 333 | } | |
| 334 | ||
| 335 | int font_info::get_bold(hunits *res) | |
| 336 | { | |
| 337 | if (is_bold) { | |
| 338 | *res = bold_offset; | |
| 339 | return 1; | |
| 340 | } | |
| 341 | else | |
| 342 | return 0; | |
| 343 | } | |
| 344 | ||
| 345 | void font_info::unbold() | |
| 346 | { | |
| 347 | if (is_bold) { | |
| 348 | is_bold = 0; | |
| 349 | flush(); | |
| 350 | } | |
| 351 | } | |
| 352 | ||
| 353 | void font_info::set_bold(hunits offset) | |
| 354 | { | |
| 355 | if (!is_bold || offset != bold_offset) { | |
| 356 | is_bold = 1; | |
| 357 | bold_offset = offset; | |
| 358 | flush(); | |
| 359 | } | |
| 360 | } | |
| 361 | ||
| 362 | void font_info::set_conditional_bold(int fontno, hunits offset) | |
| 363 | { | |
| 364 | for (conditional_bold *p = cond_bold_list; p; p = p->next) | |
| 365 | if (p->fontno == fontno) { | |
| 366 | if (offset != p->offset) { | |
| 367 | p->offset = offset; | |
| 368 | flush(); | |
| 369 | } | |
| 370 | return; | |
| 371 | } | |
| 372 | cond_bold_list = new conditional_bold(fontno, offset, cond_bold_list); | |
| 373 | } | |
| 374 | ||
| 375 | conditional_bold::conditional_bold(int f, hunits h, conditional_bold *x) | |
| 376 | : next(x), fontno(f), offset(h) | |
| 377 | { | |
| 378 | } | |
| 379 | ||
| 380 | void font_info::conditional_unbold(int fontno) | |
| 381 | { | |
| 382 | for (conditional_bold **p = &cond_bold_list; *p; p = &(*p)->next) | |
| 383 | if ((*p)->fontno == fontno) { | |
| 384 | conditional_bold *tem = *p; | |
| 385 | *p = (*p)->next; | |
| 386 | delete tem; | |
| 387 | flush(); | |
| 388 | return; | |
| 389 | } | |
| 390 | } | |
| 391 | ||
| 392 | void font_info::set_constant_space(constant_space_type type, units x) | |
| 393 | { | |
| 394 | if (type != is_constant_spaced | |
| 395 | || (type != CONSTANT_SPACE_NONE && x != constant_space)) { | |
| 396 | flush(); | |
| 397 | is_constant_spaced = type; | |
| 398 | constant_space = x; | |
| 399 | } | |
| 400 | } | |
| 401 | ||
| 402 | void font_info::set_track_kern(track_kerning_function &tk) | |
| 403 | { | |
| 404 | if (track_kern != tk) { | |
| 405 | track_kern = tk; | |
| 406 | flush(); | |
| 407 | } | |
| 408 | } | |
| 409 | ||
| 410 | void font_info::flush() | |
| 411 | { | |
| 412 | last_tfont = 0; | |
| 413 | } | |
| 414 | ||
| 415 | int font_info::is_named(symbol s) | |
| 416 | { | |
| 417 | return internal_name == s; | |
| 418 | } | |
| 419 | ||
| 420 | symbol font_info::get_name() | |
| 421 | { | |
| 422 | return internal_name; | |
| 423 | } | |
| 424 | ||
| 425 | symbol get_font_name(int fontno, environment *env) | |
| 426 | { | |
| 427 | symbol f = font_table[fontno]->get_name(); | |
| 428 | if (font_table[fontno]->is_style()) { | |
| 429 | return concat(env->get_family()->nm, f); | |
| 430 | } | |
| 431 | return f; | |
| 432 | } | |
| 433 | ||
| 465b256c JR |
434 | symbol get_style_name(int fontno) |
| 435 | { | |
| 436 | if (font_table[fontno]->is_style()) | |
| 437 | return font_table[fontno]->get_name(); | |
| 438 | else | |
| 439 | return EMPTY_SYMBOL; | |
| 440 | } | |
| 441 | ||
| 92d0a6a6 JR |
442 | hunits font_info::get_space_width(font_size fs, int space_sz) |
| 443 | { | |
| 444 | if (is_constant_spaced == CONSTANT_SPACE_NONE) | |
| 445 | return scale(hunits(fm->get_space_width(fs.to_scaled_points())), | |
| 446 | space_sz, 12); | |
| 447 | else if (is_constant_spaced == CONSTANT_SPACE_ABSOLUTE) | |
| 448 | return constant_space; | |
| 449 | else | |
| 450 | return scale(constant_space*fs.to_scaled_points(), | |
| 451 | units_per_inch, 36*72*sizescale); | |
| 452 | } | |
| 453 | ||
| 454 | hunits font_info::get_narrow_space_width(font_size fs) | |
| 455 | { | |
| 456 | charinfo *ci = get_charinfo(symbol("|")); | |
| 4d3e9548 JL |
457 | if (fm->contains(ci->as_glyph())) |
| 458 | return hunits(fm->get_width(ci->as_glyph(), fs.to_scaled_points())); | |
| 92d0a6a6 JR |
459 | else |
| 460 | return hunits(fs.to_units()/6); | |
| 461 | } | |
| 462 | ||
| 463 | hunits font_info::get_half_narrow_space_width(font_size fs) | |
| 464 | { | |
| 465 | charinfo *ci = get_charinfo(symbol("^")); | |
| 4d3e9548 JL |
466 | if (fm->contains(ci->as_glyph())) |
| 467 | return hunits(fm->get_width(ci->as_glyph(), fs.to_scaled_points())); | |
| 92d0a6a6 JR |
468 | else |
| 469 | return hunits(fs.to_units()/12); | |
| 470 | } | |
| 471 | ||
| 472 | /* tfont */ | |
| 473 | ||
| 474 | tfont_spec::tfont_spec(symbol nm, int n, font *f, | |
| 475 | font_size s, int h, int sl) | |
| 476 | : name(nm), input_position(n), fm(f), size(s), | |
| 477 | is_bold(0), is_constant_spaced(0), ligature_mode(1), kern_mode(1), | |
| 478 | height(h), slant(sl) | |
| 479 | { | |
| 480 | if (height == size.to_scaled_points()) | |
| 481 | height = 0; | |
| 482 | } | |
| 483 | ||
| 484 | int tfont_spec::operator==(const tfont_spec &spec) | |
| 485 | { | |
| 486 | if (fm == spec.fm | |
| 487 | && size == spec.size | |
| 488 | && input_position == spec.input_position | |
| 489 | && name == spec.name | |
| 490 | && height == spec.height | |
| 491 | && slant == spec.slant | |
| 492 | && (is_bold | |
| 493 | ? (spec.is_bold && bold_offset == spec.bold_offset) | |
| 494 | : !spec.is_bold) | |
| 495 | && track_kern == spec.track_kern | |
| 496 | && (is_constant_spaced | |
| 497 | ? (spec.is_constant_spaced | |
| 498 | && constant_space_width == spec.constant_space_width) | |
| 499 | : !spec.is_constant_spaced) | |
| 500 | && ligature_mode == spec.ligature_mode | |
| 501 | && kern_mode == spec.kern_mode) | |
| 502 | return 1; | |
| 503 | else | |
| 504 | return 0; | |
| 505 | } | |
| 506 | ||
| 507 | tfont_spec tfont_spec::plain() | |
| 508 | { | |
| 509 | return tfont_spec(name, input_position, fm, size, height, slant); | |
| 510 | } | |
| 511 | ||
| 512 | hunits tfont::get_width(charinfo *c) | |
| 513 | { | |
| 514 | if (is_constant_spaced) | |
| 515 | return constant_space_width; | |
| 516 | else if (is_bold) | |
| 4d3e9548 | 517 | return (hunits(fm->get_width(c->as_glyph(), size.to_scaled_points())) |
| 92d0a6a6 JR |
518 | + track_kern + bold_offset); |
| 519 | else | |
| 4d3e9548 | 520 | return (hunits(fm->get_width(c->as_glyph(), size.to_scaled_points())) |
| 92d0a6a6 JR |
521 | + track_kern); |
| 522 | } | |
| 523 | ||
| 524 | vunits tfont::get_char_height(charinfo *c) | |
| 525 | { | |
| 4d3e9548 | 526 | vunits v = fm->get_height(c->as_glyph(), size.to_scaled_points()); |
| 92d0a6a6 JR |
527 | if (height != 0 && height != size.to_scaled_points()) |
| 528 | return scale(v, height, size.to_scaled_points()); | |
| 529 | else | |
| 530 | return v; | |
| 531 | } | |
| 532 | ||
| 533 | vunits tfont::get_char_depth(charinfo *c) | |
| 534 | { | |
| 4d3e9548 | 535 | vunits v = fm->get_depth(c->as_glyph(), size.to_scaled_points()); |
| 92d0a6a6 JR |
536 | if (height != 0 && height != size.to_scaled_points()) |
| 537 | return scale(v, height, size.to_scaled_points()); | |
| 538 | else | |
| 539 | return v; | |
| 540 | } | |
| 541 | ||
| 542 | hunits tfont::get_char_skew(charinfo *c) | |
| 543 | { | |
| 4d3e9548 | 544 | return hunits(fm->get_skew(c->as_glyph(), size.to_scaled_points(), slant)); |
| 92d0a6a6 JR |
545 | } |
| 546 | ||
| 547 | hunits tfont::get_italic_correction(charinfo *c) | |
| 548 | { | |
| 4d3e9548 | 549 | return hunits(fm->get_italic_correction(c->as_glyph(), size.to_scaled_points())); |
| 92d0a6a6 JR |
550 | } |
| 551 | ||
| 552 | hunits tfont::get_left_italic_correction(charinfo *c) | |
| 553 | { | |
| 4d3e9548 | 554 | return hunits(fm->get_left_italic_correction(c->as_glyph(), |
| 92d0a6a6 JR |
555 | size.to_scaled_points())); |
| 556 | } | |
| 557 | ||
| 558 | hunits tfont::get_subscript_correction(charinfo *c) | |
| 559 | { | |
| 4d3e9548 | 560 | return hunits(fm->get_subscript_correction(c->as_glyph(), |
| 92d0a6a6 JR |
561 | size.to_scaled_points())); |
| 562 | } | |
| 563 | ||
| 564 | inline int tfont::get_input_position() | |
| 565 | { | |
| 566 | return input_position; | |
| 567 | } | |
| 568 | ||
| 569 | inline int tfont::contains(charinfo *ci) | |
| 570 | { | |
| 4d3e9548 | 571 | return fm->contains(ci->as_glyph()); |
| 92d0a6a6 JR |
572 | } |
| 573 | ||
| 574 | inline int tfont::get_character_type(charinfo *ci) | |
| 575 | { | |
| 4d3e9548 | 576 | return fm->get_character_type(ci->as_glyph()); |
| 92d0a6a6 JR |
577 | } |
| 578 | ||
| 579 | inline int tfont::get_bold(hunits *res) | |
| 580 | { | |
| 581 | if (is_bold) { | |
| 582 | *res = bold_offset; | |
| 583 | return 1; | |
| 584 | } | |
| 585 | else | |
| 586 | return 0; | |
| 587 | } | |
| 588 | ||
| 589 | inline int tfont::get_constant_space(hunits *res) | |
| 590 | { | |
| 591 | if (is_constant_spaced) { | |
| 592 | *res = constant_space_width; | |
| 593 | return 1; | |
| 594 | } | |
| 595 | else | |
| 596 | return 0; | |
| 597 | } | |
| 598 | ||
| 599 | inline hunits tfont::get_track_kern() | |
| 600 | { | |
| 601 | return track_kern; | |
| 602 | } | |
| 603 | ||
| 604 | inline tfont *tfont::get_plain() | |
| 605 | { | |
| 606 | return plain_version; | |
| 607 | } | |
| 608 | ||
| 609 | inline font_size tfont::get_size() | |
| 610 | { | |
| 611 | return size; | |
| 612 | } | |
| 613 | ||
| 4d3e9548 JL |
614 | inline int tfont::get_zoom() |
| 615 | { | |
| 616 | return fm->get_zoom(); | |
| 617 | } | |
| 618 | ||
| 92d0a6a6 JR |
619 | inline symbol tfont::get_name() |
| 620 | { | |
| 621 | return name; | |
| 622 | } | |
| 623 | ||
| 624 | inline int tfont::get_height() | |
| 625 | { | |
| 626 | return height; | |
| 627 | } | |
| 628 | ||
| 629 | inline int tfont::get_slant() | |
| 630 | { | |
| 631 | return slant; | |
| 632 | } | |
| 633 | ||
| 634 | symbol SYMBOL_ff("ff"); | |
| 635 | symbol SYMBOL_fi("fi"); | |
| 636 | symbol SYMBOL_fl("fl"); | |
| 637 | symbol SYMBOL_Fi("Fi"); | |
| 638 | symbol SYMBOL_Fl("Fl"); | |
| 639 | ||
| 640 | charinfo *tfont::get_lig(charinfo *c1, charinfo *c2) | |
| 641 | { | |
| 642 | if (ligature_mode == 0) | |
| 643 | return 0; | |
| 644 | charinfo *ci = 0; | |
| 645 | if (c1->get_ascii_code() == 'f') { | |
| 646 | switch (c2->get_ascii_code()) { | |
| 647 | case 'f': | |
| 648 | if (fm->has_ligature(font::LIG_ff)) | |
| 649 | ci = get_charinfo(SYMBOL_ff); | |
| 650 | break; | |
| 651 | case 'i': | |
| 652 | if (fm->has_ligature(font::LIG_fi)) | |
| 653 | ci = get_charinfo(SYMBOL_fi); | |
| 654 | break; | |
| 655 | case 'l': | |
| 656 | if (fm->has_ligature(font::LIG_fl)) | |
| 657 | ci = get_charinfo(SYMBOL_fl); | |
| 658 | break; | |
| 659 | } | |
| 660 | } | |
| 661 | else if (ligature_mode != 2 && c1->nm == SYMBOL_ff) { | |
| 662 | switch (c2->get_ascii_code()) { | |
| 663 | case 'i': | |
| 664 | if (fm->has_ligature(font::LIG_ffi)) | |
| 665 | ci = get_charinfo(SYMBOL_Fi); | |
| 666 | break; | |
| 667 | case 'l': | |
| 668 | if (fm->has_ligature(font::LIG_ffl)) | |
| 669 | ci = get_charinfo(SYMBOL_Fl); | |
| 670 | break; | |
| 671 | } | |
| 672 | } | |
| 4d3e9548 | 673 | if (ci != 0 && fm->contains(ci->as_glyph())) |
| 92d0a6a6 JR |
674 | return ci; |
| 675 | return 0; | |
| 676 | } | |
| 677 | ||
| 678 | inline int tfont::get_kern(charinfo *c1, charinfo *c2, hunits *res) | |
| 679 | { | |
| 680 | if (kern_mode == 0) | |
| 681 | return 0; | |
| 682 | else { | |
| 4d3e9548 JL |
683 | int n = fm->get_kern(c1->as_glyph(), |
| 684 | c2->as_glyph(), | |
| 92d0a6a6 JR |
685 | size.to_scaled_points()); |
| 686 | if (n) { | |
| 687 | *res = hunits(n); | |
| 688 | return 1; | |
| 689 | } | |
| 690 | else | |
| 691 | return 0; | |
| 692 | } | |
| 693 | } | |
| 694 | ||
| 695 | tfont *tfont::tfont_list = 0; | |
| 696 | ||
| 697 | tfont::tfont(tfont_spec &spec) : tfont_spec(spec) | |
| 698 | { | |
| 699 | next = tfont_list; | |
| 700 | tfont_list = this; | |
| 701 | tfont_spec plain_spec = plain(); | |
| 702 | tfont *p; | |
| 703 | for (p = tfont_list; p; p = p->next) | |
| 704 | if (*p == plain_spec) { | |
| 705 | plain_version = p; | |
| 706 | break; | |
| 707 | } | |
| 708 | if (!p) | |
| 709 | plain_version = new tfont(plain_spec); | |
| 710 | } | |
| 711 | ||
| 712 | /* output_file */ | |
| 713 | ||
| 714 | class real_output_file : public output_file { | |
| 715 | #ifndef POPEN_MISSING | |
| 716 | int piped; | |
| 717 | #endif | |
| 4d3e9548 JL |
718 | int printing; // decision via optional page list |
| 719 | int output_on; // \O[0] or \O[1] escape calls | |
| 92d0a6a6 JR |
720 | virtual void really_transparent_char(unsigned char) = 0; |
| 721 | virtual void really_print_line(hunits x, vunits y, node *n, | |
| 722 | vunits before, vunits after, hunits width) = 0; | |
| 723 | virtual void really_begin_page(int pageno, vunits page_length) = 0; | |
| 724 | virtual void really_copy_file(hunits x, vunits y, const char *filename); | |
| 4d3e9548 | 725 | virtual void really_put_filename(const char *, int); |
| 92d0a6a6 JR |
726 | virtual void really_on(); |
| 727 | virtual void really_off(); | |
| 92d0a6a6 | 728 | public: |
| 465b256c | 729 | FILE *fp; |
| 92d0a6a6 JR |
730 | real_output_file(); |
| 731 | ~real_output_file(); | |
| 732 | void flush(); | |
| 733 | void transparent_char(unsigned char); | |
| 734 | void print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width); | |
| 735 | void begin_page(int pageno, vunits page_length); | |
| 4d3e9548 | 736 | void put_filename(const char *, int); |
| 92d0a6a6 JR |
737 | void on(); |
| 738 | void off(); | |
| 739 | int is_on(); | |
| 740 | int is_printing(); | |
| 741 | void copy_file(hunits x, vunits y, const char *filename); | |
| 742 | }; | |
| 743 | ||
| 744 | class suppress_output_file : public real_output_file { | |
| 745 | public: | |
| 746 | suppress_output_file(); | |
| 747 | void really_transparent_char(unsigned char); | |
| 748 | void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width); | |
| 749 | void really_begin_page(int pageno, vunits page_length); | |
| 750 | }; | |
| 751 | ||
| 752 | class ascii_output_file : public real_output_file { | |
| 753 | public: | |
| 754 | ascii_output_file(); | |
| 755 | void really_transparent_char(unsigned char); | |
| 756 | void really_print_line(hunits x, vunits y, node *n, vunits, vunits, hunits width); | |
| 757 | void really_begin_page(int pageno, vunits page_length); | |
| 758 | void outc(unsigned char c); | |
| 759 | void outs(const char *s); | |
| 760 | }; | |
| 761 | ||
| 762 | void ascii_output_file::outc(unsigned char c) | |
| 763 | { | |
| 764 | fputc(c, fp); | |
| 765 | } | |
| 766 | ||
| 767 | void ascii_output_file::outs(const char *s) | |
| 768 | { | |
| 769 | fputc('<', fp); | |
| 770 | if (s) | |
| 771 | fputs(s, fp); | |
| 772 | fputc('>', fp); | |
| 773 | } | |
| 774 | ||
| 775 | struct hvpair; | |
| 776 | ||
| 777 | class troff_output_file : public real_output_file { | |
| 778 | units hpos; | |
| 779 | units vpos; | |
| 780 | units output_vpos; | |
| 781 | units output_hpos; | |
| 782 | int force_motion; | |
| 783 | int current_size; | |
| 784 | int current_slant; | |
| 785 | int current_height; | |
| 786 | tfont *current_tfont; | |
| 787 | color *current_fill_color; | |
| 788 | color *current_glyph_color; | |
| 789 | int current_font_number; | |
| 790 | symbol *font_position; | |
| 791 | int nfont_positions; | |
| 792 | enum { TBUF_SIZE = 256 }; | |
| 793 | char tbuf[TBUF_SIZE]; | |
| 794 | int tbuf_len; | |
| 795 | int tbuf_kern; | |
| 796 | int begun_page; | |
| 465b256c JR |
797 | int cur_div_level; |
| 798 | string tag_list; | |
| 92d0a6a6 JR |
799 | void do_motion(); |
| 800 | void put(char c); | |
| 801 | void put(unsigned char c); | |
| 802 | void put(int i); | |
| 803 | void put(unsigned int i); | |
| 804 | void put(const char *s); | |
| 805 | void set_font(tfont *tf); | |
| 806 | void flush_tbuf(); | |
| 807 | public: | |
| 808 | troff_output_file(); | |
| 809 | ~troff_output_file(); | |
| 810 | void trailer(vunits page_length); | |
| 811 | void put_char(charinfo *, tfont *, color *, color *); | |
| 812 | void put_char_width(charinfo *, tfont *, color *, color *, hunits, hunits); | |
| 813 | void right(hunits); | |
| 814 | void down(vunits); | |
| 815 | void moveto(hunits, vunits); | |
| 816 | void start_special(tfont *, color *, color *, int = 0); | |
| 817 | void start_special(); | |
| 818 | void special_char(unsigned char c); | |
| 819 | void end_special(); | |
| 820 | void word_marker(); | |
| 821 | void really_transparent_char(unsigned char c); | |
| 822 | void really_print_line(hunits x, vunits y, node *n, vunits before, vunits after, hunits width); | |
| 823 | void really_begin_page(int pageno, vunits page_length); | |
| 824 | void really_copy_file(hunits x, vunits y, const char *filename); | |
| 4d3e9548 | 825 | void really_put_filename(const char *, int); |
| 92d0a6a6 JR |
826 | void really_on(); |
| 827 | void really_off(); | |
| 828 | void draw(char, hvpair *, int, font_size, color *, color *); | |
| 829 | void determine_line_limits (char code, hvpair *point, int npoints); | |
| 830 | void check_charinfo(tfont *tf, charinfo *ci); | |
| 831 | void glyph_color(color *c); | |
| 832 | void fill_color(color *c); | |
| 833 | int get_hpos() { return hpos; } | |
| 834 | int get_vpos() { return vpos; } | |
| 465b256c | 835 | void add_to_tag_list(string s); |
| 92d0a6a6 JR |
836 | friend void space_char_hmotion_node::tprint(troff_output_file *); |
| 837 | friend void unbreakable_space_node::tprint(troff_output_file *); | |
| 838 | }; | |
| 839 | ||
| 840 | static void put_string(const char *s, FILE *fp) | |
| 841 | { | |
| 842 | for (; *s != '\0'; ++s) | |
| 843 | putc(*s, fp); | |
| 844 | } | |
| 845 | ||
| 846 | inline void troff_output_file::put(char c) | |
| 847 | { | |
| 848 | putc(c, fp); | |
| 849 | } | |
| 850 | ||
| 851 | inline void troff_output_file::put(unsigned char c) | |
| 852 | { | |
| 853 | putc(c, fp); | |
| 854 | } | |
| 855 | ||
| 856 | inline void troff_output_file::put(const char *s) | |
| 857 | { | |
| 858 | put_string(s, fp); | |
| 859 | } | |
| 860 | ||
| 861 | inline void troff_output_file::put(int i) | |
| 862 | { | |
| 863 | put_string(i_to_a(i), fp); | |
| 864 | } | |
| 865 | ||
| 866 | inline void troff_output_file::put(unsigned int i) | |
| 867 | { | |
| 868 | put_string(ui_to_a(i), fp); | |
| 869 | } | |
| 870 | ||
| 871 | void troff_output_file::start_special(tfont *tf, color *gcol, color *fcol, | |
| 872 | int no_init_string) | |
| 873 | { | |
| 874 | set_font(tf); | |
| 875 | glyph_color(gcol); | |
| 876 | fill_color(fcol); | |
| 877 | flush_tbuf(); | |
| 878 | do_motion(); | |
| 879 | if (!no_init_string) | |
| 880 | put("x X "); | |
| 881 | } | |
| 882 | ||
| 883 | void troff_output_file::start_special() | |
| 884 | { | |
| 885 | flush_tbuf(); | |
| 886 | do_motion(); | |
| 887 | put("x X "); | |
| 888 | } | |
| 889 | ||
| 890 | void troff_output_file::special_char(unsigned char c) | |
| 891 | { | |
| 892 | put(c); | |
| 893 | if (c == '\n') | |
| 894 | put('+'); | |
| 895 | } | |
| 896 | ||
| 897 | void troff_output_file::end_special() | |
| 898 | { | |
| 899 | put('\n'); | |
| 900 | } | |
| 901 | ||
| 902 | inline void troff_output_file::moveto(hunits h, vunits v) | |
| 903 | { | |
| 904 | hpos = h.to_units(); | |
| 905 | vpos = v.to_units(); | |
| 906 | } | |
| 907 | ||
| 908 | void troff_output_file::really_print_line(hunits x, vunits y, node *n, | |
| 909 | vunits before, vunits after, hunits) | |
| 910 | { | |
| 911 | moveto(x, y); | |
| 912 | while (n != 0) { | |
| 465b256c JR |
913 | // Check whether we should push the current troff state and use |
| 914 | // the state at the start of the invocation of this diversion. | |
| 915 | if (n->div_nest_level > cur_div_level && n->push_state) { | |
| 916 | state.push_state(n->push_state); | |
| 917 | cur_div_level = n->div_nest_level; | |
| 918 | } | |
| 919 | // Has the current diversion level decreased? Then we must pop the | |
| 920 | // troff state. | |
| 921 | while (n->div_nest_level < cur_div_level) { | |
| 922 | state.pop_state(); | |
| 923 | cur_div_level = n->div_nest_level; | |
| 924 | } | |
| 925 | // Now check whether the state has changed. | |
| 926 | if ((is_on() || n->force_tprint()) | |
| 927 | && (state.changed(n->state) || n->is_tag() || n->is_special)) { | |
| 928 | flush_tbuf(); | |
| 929 | do_motion(); | |
| 930 | force_motion = 1; | |
| 931 | flush(); | |
| 932 | state.flush(fp, n->state, tag_list); | |
| 933 | tag_list = string(""); | |
| 934 | flush(); | |
| 935 | } | |
| 92d0a6a6 JR |
936 | n->tprint(this); |
| 937 | n = n->next; | |
| 938 | } | |
| 939 | flush_tbuf(); | |
| 940 | // This ensures that transparent throughput will have a more predictable | |
| 941 | // position. | |
| 942 | do_motion(); | |
| 943 | force_motion = 1; | |
| 944 | hpos = 0; | |
| 945 | put('n'); | |
| 946 | put(before.to_units()); | |
| 947 | put(' '); | |
| 948 | put(after.to_units()); | |
| 949 | put('\n'); | |
| 950 | } | |
| 951 | ||
| 952 | inline void troff_output_file::word_marker() | |
| 953 | { | |
| 954 | flush_tbuf(); | |
| 955 | if (is_on()) | |
| 956 | put('w'); | |
| 957 | } | |
| 958 | ||
| 959 | inline void troff_output_file::right(hunits n) | |
| 960 | { | |
| 961 | hpos += n.to_units(); | |
| 962 | } | |
| 963 | ||
| 964 | inline void troff_output_file::down(vunits n) | |
| 965 | { | |
| 966 | vpos += n.to_units(); | |
| 967 | } | |
| 968 | ||
| 969 | void troff_output_file::do_motion() | |
| 970 | { | |
| 971 | if (force_motion) { | |
| 972 | put('V'); | |
| 973 | put(vpos); | |
| 974 | put('\n'); | |
| 975 | put('H'); | |
| 976 | put(hpos); | |
| 977 | put('\n'); | |
| 978 | } | |
| 979 | else { | |
| 980 | if (hpos != output_hpos) { | |
| 981 | units n = hpos - output_hpos; | |
| 982 | if (n > 0 && n < hpos) { | |
| 983 | put('h'); | |
| 984 | put(n); | |
| 985 | } | |
| 986 | else { | |
| 987 | put('H'); | |
| 988 | put(hpos); | |
| 989 | } | |
| 990 | put('\n'); | |
| 991 | } | |
| 992 | if (vpos != output_vpos) { | |
| 993 | units n = vpos - output_vpos; | |
| 994 | if (n > 0 && n < vpos) { | |
| 995 | put('v'); | |
| 996 | put(n); | |
| 997 | } | |
| 998 | else { | |
| 999 | put('V'); | |
| 1000 | put(vpos); | |
| 1001 | } | |
| 1002 | put('\n'); | |
| 1003 | } | |
| 1004 | } | |
| 1005 | output_vpos = vpos; | |
| 1006 | output_hpos = hpos; | |
| 1007 | force_motion = 0; | |
| 1008 | } | |
| 1009 | ||
| 1010 | void troff_output_file::flush_tbuf() | |
| 1011 | { | |
| 1012 | if (!is_on()) { | |
| 1013 | tbuf_len = 0; | |
| 1014 | return; | |
| 1015 | } | |
| 1016 | ||
| 1017 | if (tbuf_len == 0) | |
| 1018 | return; | |
| 1019 | if (tbuf_kern == 0) | |
| 1020 | put('t'); | |
| 1021 | else { | |
| 1022 | put('u'); | |
| 1023 | put(tbuf_kern); | |
| 1024 | put(' '); | |
| 1025 | } | |
| 1026 | check_output_limits(hpos, vpos); | |
| 1027 | check_output_limits(hpos, vpos - current_size); | |
| 1028 | ||
| 1029 | for (int i = 0; i < tbuf_len; i++) | |
| 1030 | put(tbuf[i]); | |
| 1031 | put('\n'); | |
| 1032 | tbuf_len = 0; | |
| 1033 | } | |
| 1034 | ||
| 1035 | void troff_output_file::check_charinfo(tfont *tf, charinfo *ci) | |
| 1036 | { | |
| 1037 | if (!is_on()) | |
| 1038 | return; | |
| 1039 | ||
| 1040 | int height = tf->get_char_height(ci).to_units(); | |
| 1041 | int width = tf->get_width(ci).to_units() | |
| 1042 | + tf->get_italic_correction(ci).to_units(); | |
| 1043 | int depth = tf->get_char_depth(ci).to_units(); | |
| 1044 | check_output_limits(output_hpos, output_vpos - height); | |
| 1045 | check_output_limits(output_hpos + width, output_vpos + depth); | |
| 1046 | } | |
| 1047 | ||
| 1048 | void troff_output_file::put_char_width(charinfo *ci, tfont *tf, | |
| 1049 | color *gcol, color *fcol, | |
| 1050 | hunits w, hunits k) | |
| 1051 | { | |
| 1052 | int kk = k.to_units(); | |
| 1053 | if (!is_on()) { | |
| 1054 | flush_tbuf(); | |
| 1055 | hpos += w.to_units() + kk; | |
| 1056 | return; | |
| 1057 | } | |
| 1058 | set_font(tf); | |
| 1059 | unsigned char c = ci->get_ascii_code(); | |
| 1060 | if (c == '\0') { | |
| 1061 | glyph_color(gcol); | |
| 1062 | fill_color(fcol); | |
| 1063 | flush_tbuf(); | |
| 1064 | do_motion(); | |
| 1065 | check_charinfo(tf, ci); | |
| 1066 | if (ci->numbered()) { | |
| 1067 | put('N'); | |
| 1068 | put(ci->get_number()); | |
| 1069 | } | |
| 1070 | else { | |
| 1071 | put('C'); | |
| 1072 | const char *s = ci->nm.contents(); | |
| 1073 | if (s[1] == 0) { | |
| 1074 | put('\\'); | |
| 1075 | put(s[0]); | |
| 1076 | } | |
| 1077 | else | |
| 1078 | put(s); | |
| 1079 | } | |
| 1080 | put('\n'); | |
| 1081 | hpos += w.to_units() + kk; | |
| 1082 | } | |
| 1083 | else if (tcommand_flag) { | |
| 1084 | if (tbuf_len > 0 && hpos == output_hpos && vpos == output_vpos | |
| 1085 | && (!gcol || gcol == current_glyph_color) | |
| 1086 | && (!fcol || fcol == current_fill_color) | |
| 1087 | && kk == tbuf_kern | |
| 1088 | && tbuf_len < TBUF_SIZE) { | |
| 1089 | check_charinfo(tf, ci); | |
| 1090 | tbuf[tbuf_len++] = c; | |
| 1091 | output_hpos += w.to_units() + kk; | |
| 1092 | hpos = output_hpos; | |
| 1093 | return; | |
| 1094 | } | |
| 1095 | glyph_color(gcol); | |
| 1096 | fill_color(fcol); | |
| 1097 | flush_tbuf(); | |
| 1098 | do_motion(); | |
| 1099 | check_charinfo(tf, ci); | |
| 1100 | tbuf[tbuf_len++] = c; | |
| 1101 | output_hpos += w.to_units() + kk; | |
| 1102 | tbuf_kern = kk; | |
| 1103 | hpos = output_hpos; | |
| 1104 | } | |
| 1105 | else { | |
| 1106 | // flush_tbuf(); | |
| 1107 | int n = hpos - output_hpos; | |
| 1108 | check_charinfo(tf, ci); | |
| 1109 | // check_output_limits(output_hpos, output_vpos); | |
| 1110 | if (vpos == output_vpos | |
| 1111 | && (!gcol || gcol == current_glyph_color) | |
| 1112 | && (!fcol || fcol == current_fill_color) | |
| 1113 | && n > 0 && n < 100 && !force_motion) { | |
| 1114 | put(char(n/10 + '0')); | |
| 1115 | put(char(n%10 + '0')); | |
| 1116 | put(c); | |
| 1117 | output_hpos = hpos; | |
| 1118 | } | |
| 1119 | else { | |
| 1120 | glyph_color(gcol); | |
| 1121 | fill_color(fcol); | |
| 1122 | do_motion(); | |
| 1123 | put('c'); | |
| 1124 | put(c); | |
| 1125 | } | |
| 1126 | hpos += w.to_units() + kk; | |
| 1127 | } | |
| 1128 | } | |
| 1129 | ||
| 1130 | void troff_output_file::put_char(charinfo *ci, tfont *tf, | |
| 1131 | color *gcol, color *fcol) | |
| 1132 | { | |
| 1133 | flush_tbuf(); | |
| 1134 | if (!is_on()) | |
| 1135 | return; | |
| 1136 | set_font(tf); | |
| 1137 | unsigned char c = ci->get_ascii_code(); | |
| 1138 | if (c == '\0') { | |
| 1139 | glyph_color(gcol); | |
| 1140 | fill_color(fcol); | |
| 1141 | flush_tbuf(); | |
| 1142 | do_motion(); | |
| 1143 | if (ci->numbered()) { | |
| 1144 | put('N'); | |
| 1145 | put(ci->get_number()); | |
| 1146 | } | |
| 1147 | else { | |
| 1148 | put('C'); | |
| 1149 | const char *s = ci->nm.contents(); | |
| 1150 | if (s[1] == 0) { | |
| 1151 | put('\\'); | |
| 1152 | put(s[0]); | |
| 1153 | } | |
| 1154 | else | |
| 1155 | put(s); | |
| 1156 | } | |
| 1157 | put('\n'); | |
| 1158 | } | |
| 1159 | else { | |
| 1160 | int n = hpos - output_hpos; | |
| 1161 | if (vpos == output_vpos | |
| 1162 | && (!gcol || gcol == current_glyph_color) | |
| 1163 | && (!fcol || fcol == current_fill_color) | |
| 1164 | && n > 0 && n < 100) { | |
| 1165 | put(char(n/10 + '0')); | |
| 1166 | put(char(n%10 + '0')); | |
| 1167 | put(c); | |
| 1168 | output_hpos = hpos; | |
| 1169 | } | |
| 1170 | else { | |
| 1171 | glyph_color(gcol); | |
| 1172 | fill_color(fcol); | |
| 1173 | flush_tbuf(); | |
| 1174 | do_motion(); | |
| 1175 | put('c'); | |
| 1176 | put(c); | |
| 1177 | } | |
| 1178 | } | |
| 1179 | } | |
| 1180 | ||
| 1181 | // set_font calls `flush_tbuf' if necessary. | |
| 1182 | ||
| 1183 | void troff_output_file::set_font(tfont *tf) | |
| 1184 | { | |
| 1185 | if (current_tfont == tf) | |
| 1186 | return; | |
| 1187 | flush_tbuf(); | |
| 1188 | int n = tf->get_input_position(); | |
| 1189 | symbol nm = tf->get_name(); | |
| 1190 | if (n >= nfont_positions || font_position[n] != nm) { | |
| 1191 | put("x font "); | |
| 1192 | put(n); | |
| 1193 | put(' '); | |
| 1194 | put(nm.contents()); | |
| 1195 | put('\n'); | |
| 1196 | if (n >= nfont_positions) { | |
| 1197 | int old_nfont_positions = nfont_positions; | |
| 1198 | symbol *old_font_position = font_position; | |
| 1199 | nfont_positions *= 3; | |
| 1200 | nfont_positions /= 2; | |
| 1201 | if (nfont_positions <= n) | |
| 1202 | nfont_positions = n + 10; | |
| 1203 | font_position = new symbol[nfont_positions]; | |
| 1204 | memcpy(font_position, old_font_position, | |
| 1205 | old_nfont_positions*sizeof(symbol)); | |
| 1206 | a_delete old_font_position; | |
| 1207 | } | |
| 1208 | font_position[n] = nm; | |
| 1209 | } | |
| 1210 | if (current_font_number != n) { | |
| 1211 | put('f'); | |
| 1212 | put(n); | |
| 1213 | put('\n'); | |
| 1214 | current_font_number = n; | |
| 1215 | } | |
| 4d3e9548 JL |
1216 | int zoom = tf->get_zoom(); |
| 1217 | int size; | |
| 1218 | if (zoom) | |
| 1219 | size = scale(tf->get_size().to_scaled_points(), | |
| 1220 | zoom, 1000); | |
| 1221 | else | |
| 1222 | size = tf->get_size().to_scaled_points(); | |
| 92d0a6a6 JR |
1223 | if (current_size != size) { |
| 1224 | put('s'); | |
| 1225 | put(size); | |
| 1226 | put('\n'); | |
| 1227 | current_size = size; | |
| 1228 | } | |
| 1229 | int slant = tf->get_slant(); | |
| 1230 | if (current_slant != slant) { | |
| 1231 | put("x Slant "); | |
| 1232 | put(slant); | |
| 1233 | put('\n'); | |
| 1234 | current_slant = slant; | |
| 1235 | } | |
| 1236 | int height = tf->get_height(); | |
| 1237 | if (current_height != height) { | |
| 1238 | put("x Height "); | |
| 1239 | put(height == 0 ? current_size : height); | |
| 1240 | put('\n'); | |
| 1241 | current_height = height; | |
| 1242 | } | |
| 1243 | current_tfont = tf; | |
| 1244 | } | |
| 1245 | ||
| 1246 | // fill_color calls `flush_tbuf' and `do_motion' if necessary. | |
| 1247 | ||
| 1248 | void troff_output_file::fill_color(color *col) | |
| 1249 | { | |
| 1250 | if (!col || current_fill_color == col) | |
| 1251 | return; | |
| 1252 | current_fill_color = col; | |
| 1253 | if (!color_flag) | |
| 1254 | return; | |
| 1255 | flush_tbuf(); | |
| 1256 | do_motion(); | |
| 1257 | put("DF"); | |
| 1258 | unsigned int components[4]; | |
| 1259 | color_scheme cs; | |
| 1260 | cs = col->get_components(components); | |
| 1261 | switch (cs) { | |
| 1262 | case DEFAULT: | |
| 1263 | put('d'); | |
| 1264 | break; | |
| 1265 | case RGB: | |
| 1266 | put("r "); | |
| 1267 | put(Red); | |
| 1268 | put(' '); | |
| 1269 | put(Green); | |
| 1270 | put(' '); | |
| 1271 | put(Blue); | |
| 1272 | break; | |
| 1273 | case CMY: | |
| 1274 | put("c "); | |
| 1275 | put(Cyan); | |
| 1276 | put(' '); | |
| 1277 | put(Magenta); | |
| 1278 | put(' '); | |
| 1279 | put(Yellow); | |
| 1280 | break; | |
| 1281 | case CMYK: | |
| 1282 | put("k "); | |
| 1283 | put(Cyan); | |
| 1284 | put(' '); | |
| 1285 | put(Magenta); | |
| 1286 | put(' '); | |
| 1287 | put(Yellow); | |
| 1288 | put(' '); | |
| 1289 | put(Black); | |
| 1290 | break; | |
| 1291 | case GRAY: | |
| 1292 | put("g "); | |
| 1293 | put(Gray); | |
| 1294 | break; | |
| 1295 | } | |
| 1296 | put('\n'); | |
| 1297 | } | |
| 1298 | ||
| 1299 | // glyph_color calls `flush_tbuf' and `do_motion' if necessary. | |
| 1300 | ||
| 1301 | void troff_output_file::glyph_color(color *col) | |
| 1302 | { | |
| 1303 | if (!col || current_glyph_color == col) | |
| 1304 | return; | |
| 1305 | current_glyph_color = col; | |
| 1306 | if (!color_flag) | |
| 1307 | return; | |
| 1308 | flush_tbuf(); | |
| 1309 | // grotty doesn't like a color command if the vertical position is zero. | |
| 1310 | do_motion(); | |
| 1311 | put("m"); | |
| 1312 | unsigned int components[4]; | |
| 1313 | color_scheme cs; | |
| 1314 | cs = col->get_components(components); | |
| 1315 | switch (cs) { | |
| 1316 | case DEFAULT: | |
| 1317 | put('d'); | |
| 1318 | break; | |
| 1319 | case RGB: | |
| 1320 | put("r "); | |
| 1321 | put(Red); | |
| 1322 | put(' '); | |
| 1323 | put(Green); | |
| 1324 | put(' '); | |
| 1325 | put(Blue); | |
| 1326 | break; | |
| 1327 | case CMY: | |
| 1328 | put("c "); | |
| 1329 | put(Cyan); | |
| 1330 | put(' '); | |
| 1331 | put(Magenta); | |
| 1332 | put(' '); | |
| 1333 | put(Yellow); | |
| 1334 | break; | |
| 1335 | case CMYK: | |
| 1336 | put("k "); | |
| 1337 | put(Cyan); | |
| 1338 | put(' '); | |
| 1339 | put(Magenta); | |
| 1340 | put(' '); | |
| 1341 | put(Yellow); | |
| 1342 | put(' '); | |
| 1343 | put(Black); | |
| 1344 | break; | |
| 1345 | case GRAY: | |
| 1346 | put("g "); | |
| 1347 | put(Gray); | |
| 1348 | break; | |
| 1349 | } | |
| 1350 | put('\n'); | |
| 1351 | } | |
| 1352 | ||
| 465b256c JR |
1353 | void troff_output_file::add_to_tag_list(string s) |
| 1354 | { | |
| 1355 | if (tag_list == string("")) | |
| 1356 | tag_list = s; | |
| 1357 | else { | |
| 1358 | tag_list += string("\n"); | |
| 1359 | tag_list += s; | |
| 1360 | } | |
| 1361 | } | |
| 1362 | ||
| 92d0a6a6 JR |
1363 | // determine_line_limits - works out the smallest box which will contain |
| 1364 | // the entity, code, built from the point array. | |
| 1365 | void troff_output_file::determine_line_limits(char code, hvpair *point, | |
| 1366 | int npoints) | |
| 1367 | { | |
| 1368 | int i, x, y; | |
| 1369 | ||
| 1370 | if (!is_on()) | |
| 1371 | return; | |
| 1372 | ||
| 1373 | switch (code) { | |
| 1374 | case 'c': | |
| 1375 | case 'C': | |
| 1376 | // only the h field is used when defining a circle | |
| 1377 | check_output_limits(output_hpos, | |
| 1378 | output_vpos - point[0].h.to_units()/2); | |
| 1379 | check_output_limits(output_hpos + point[0].h.to_units(), | |
| 1380 | output_vpos + point[0].h.to_units()/2); | |
| 1381 | break; | |
| 1382 | case 'E': | |
| 1383 | case 'e': | |
| 1384 | check_output_limits(output_hpos, | |
| 1385 | output_vpos - point[0].v.to_units()/2); | |
| 1386 | check_output_limits(output_hpos + point[0].h.to_units(), | |
| 1387 | output_vpos + point[0].v.to_units()/2); | |
| 1388 | break; | |
| 1389 | case 'P': | |
| 1390 | case 'p': | |
| 1391 | x = output_hpos; | |
| 1392 | y = output_vpos; | |
| 1393 | check_output_limits(x, y); | |
| 1394 | for (i = 0; i < npoints; i++) { | |
| 1395 | x += point[i].h.to_units(); | |
| 1396 | y += point[i].v.to_units(); | |
| 1397 | check_output_limits(x, y); | |
| 1398 | } | |
| 1399 | break; | |
| 1400 | case 't': | |
| 1401 | x = output_hpos; | |
| 1402 | y = output_vpos; | |
| 1403 | for (i = 0; i < npoints; i++) { | |
| 1404 | x += point[i].h.to_units(); | |
| 1405 | y += point[i].v.to_units(); | |
| 1406 | check_output_limits(x, y); | |
| 1407 | } | |
| 1408 | break; | |
| 1409 | case 'a': | |
| 1410 | double c[2]; | |
| 1411 | int p[4]; | |
| 1412 | int minx, miny, maxx, maxy; | |
| 1413 | x = output_hpos; | |
| 1414 | y = output_vpos; | |
| 1415 | p[0] = point[0].h.to_units(); | |
| 1416 | p[1] = point[0].v.to_units(); | |
| 1417 | p[2] = point[1].h.to_units(); | |
| 1418 | p[3] = point[1].v.to_units(); | |
| 1419 | if (adjust_arc_center(p, c)) { | |
| 1420 | check_output_arc_limits(x, y, | |
| 1421 | p[0], p[1], p[2], p[3], | |
| 1422 | c[0], c[1], | |
| 1423 | &minx, &maxx, &miny, &maxy); | |
| 1424 | check_output_limits(minx, miny); | |
| 1425 | check_output_limits(maxx, maxy); | |
| 1426 | break; | |
| 1427 | } | |
| 1428 | // fall through | |
| 1429 | case 'l': | |
| 1430 | x = output_hpos; | |
| 1431 | y = output_vpos; | |
| 1432 | check_output_limits(x, y); | |
| 1433 | for (i = 0; i < npoints; i++) { | |
| 1434 | x += point[i].h.to_units(); | |
| 1435 | y += point[i].v.to_units(); | |
| 1436 | check_output_limits(x, y); | |
| 1437 | } | |
| 1438 | break; | |
| 1439 | default: | |
| 1440 | x = output_hpos; | |
| 1441 | y = output_vpos; | |
| 1442 | for (i = 0; i < npoints; i++) { | |
| 1443 | x += point[i].h.to_units(); | |
| 1444 | y += point[i].v.to_units(); | |
| 1445 | check_output_limits(x, y); | |
| 1446 | } | |
| 1447 | } | |
| 1448 | } | |
| 1449 | ||
| 1450 | void troff_output_file::draw(char code, hvpair *point, int npoints, | |
| 1451 | font_size fsize, color *gcol, color *fcol) | |
| 1452 | { | |
| 1453 | int i; | |
| 1454 | glyph_color(gcol); | |
| 1455 | fill_color(fcol); | |
| 1456 | flush_tbuf(); | |
| 1457 | do_motion(); | |
| 1458 | if (is_on()) { | |
| 1459 | int size = fsize.to_scaled_points(); | |
| 1460 | if (current_size != size) { | |
| 1461 | put('s'); | |
| 1462 | put(size); | |
| 1463 | put('\n'); | |
| 1464 | current_size = size; | |
| 1465 | current_tfont = 0; | |
| 1466 | } | |
| 1467 | put('D'); | |
| 1468 | put(code); | |
| 1469 | if (code == 'c') { | |
| 1470 | put(' '); | |
| 1471 | put(point[0].h.to_units()); | |
| 1472 | } | |
| 1473 | else | |
| 1474 | for (i = 0; i < npoints; i++) { | |
| 1475 | put(' '); | |
| 1476 | put(point[i].h.to_units()); | |
| 1477 | put(' '); | |
| 1478 | put(point[i].v.to_units()); | |
| 1479 | } | |
| 1480 | determine_line_limits(code, point, npoints); | |
| 1481 | } | |
| 1482 | ||
| 1483 | for (i = 0; i < npoints; i++) | |
| 1484 | output_hpos += point[i].h.to_units(); | |
| 1485 | hpos = output_hpos; | |
| 1486 | if (code != 'e') { | |
| 1487 | for (i = 0; i < npoints; i++) | |
| 1488 | output_vpos += point[i].v.to_units(); | |
| 1489 | vpos = output_vpos; | |
| 1490 | } | |
| 1491 | if (is_on()) | |
| 1492 | put('\n'); | |
| 1493 | } | |
| 1494 | ||
| 1495 | void troff_output_file::really_on() | |
| 1496 | { | |
| 1497 | flush_tbuf(); | |
| 1498 | force_motion = 1; | |
| 1499 | do_motion(); | |
| 1500 | } | |
| 1501 | ||
| 1502 | void troff_output_file::really_off() | |
| 1503 | { | |
| 1504 | flush_tbuf(); | |
| 1505 | } | |
| 1506 | ||
| 4d3e9548 | 1507 | void troff_output_file::really_put_filename(const char *filename, int po) |
| 92d0a6a6 JR |
1508 | { |
| 1509 | flush_tbuf(); | |
| 1510 | put("F "); | |
| 4d3e9548 JL |
1511 | if (po) |
| 1512 | put("<"); | |
| 92d0a6a6 | 1513 | put(filename); |
| 4d3e9548 JL |
1514 | if (po) |
| 1515 | put(">"); | |
| 92d0a6a6 JR |
1516 | put('\n'); |
| 1517 | } | |
| 1518 | ||
| 1519 | void troff_output_file::really_begin_page(int pageno, vunits page_length) | |
| 1520 | { | |
| 1521 | flush_tbuf(); | |
| 1522 | if (begun_page) { | |
| 1523 | if (page_length > V0) { | |
| 1524 | put('V'); | |
| 1525 | put(page_length.to_units()); | |
| 1526 | put('\n'); | |
| 1527 | } | |
| 1528 | } | |
| 1529 | else | |
| 1530 | begun_page = 1; | |
| 1531 | current_tfont = 0; | |
| 1532 | current_font_number = -1; | |
| 1533 | current_size = 0; | |
| 1534 | // current_height = 0; | |
| 1535 | // current_slant = 0; | |
| 1536 | hpos = 0; | |
| 1537 | vpos = 0; | |
| 1538 | output_hpos = 0; | |
| 1539 | output_vpos = 0; | |
| 1540 | force_motion = 1; | |
| 1541 | for (int i = 0; i < nfont_positions; i++) | |
| 1542 | font_position[i] = NULL_SYMBOL; | |
| 1543 | put('p'); | |
| 1544 | put(pageno); | |
| 1545 | put('\n'); | |
| 1546 | } | |
| 1547 | ||
| 1548 | void troff_output_file::really_copy_file(hunits x, vunits y, | |
| 1549 | const char *filename) | |
| 1550 | { | |
| 1551 | moveto(x, y); | |
| 1552 | flush_tbuf(); | |
| 1553 | do_motion(); | |
| 1554 | errno = 0; | |
| 1555 | FILE *ifp = include_search_path.open_file_cautious(filename); | |
| 1556 | if (ifp == 0) | |
| 1557 | error("can't open `%1': %2", filename, strerror(errno)); | |
| 1558 | else { | |
| 1559 | int c; | |
| 1560 | while ((c = getc(ifp)) != EOF) | |
| 1561 | put(char(c)); | |
| 1562 | fclose(ifp); | |
| 1563 | } | |
| 1564 | force_motion = 1; | |
| 1565 | current_size = 0; | |
| 1566 | current_tfont = 0; | |
| 1567 | current_font_number = -1; | |
| 1568 | for (int i = 0; i < nfont_positions; i++) | |
| 1569 | font_position[i] = NULL_SYMBOL; | |
| 1570 | } | |
| 1571 | ||
| 1572 | void troff_output_file::really_transparent_char(unsigned char c) | |
| 1573 | { | |
| 1574 | put(c); | |
| 1575 | } | |
| 1576 | ||
| 1577 | troff_output_file::~troff_output_file() | |
| 1578 | { | |
| 1579 | a_delete font_position; | |
| 1580 | } | |
| 1581 | ||
| 1582 | void troff_output_file::trailer(vunits page_length) | |
| 1583 | { | |
| 1584 | flush_tbuf(); | |
| 1585 | if (page_length > V0) { | |
| 1586 | put("x trailer\n"); | |
| 1587 | put('V'); | |
| 1588 | put(page_length.to_units()); | |
| 1589 | put('\n'); | |
| 1590 | } | |
| 1591 | put("x stop\n"); | |
| 1592 | } | |
| 1593 | ||
| 1594 | troff_output_file::troff_output_file() | |
| 1595 | : current_slant(0), current_height(0), current_fill_color(0), | |
| 465b256c JR |
1596 | current_glyph_color(0), nfont_positions(10), tbuf_len(0), begun_page(0), |
| 1597 | cur_div_level(0) | |
| 92d0a6a6 JR |
1598 | { |
| 1599 | font_position = new symbol[nfont_positions]; | |
| 1600 | put("x T "); | |
| 1601 | put(device); | |
| 1602 | put('\n'); | |
| 1603 | put("x res "); | |
| 1604 | put(units_per_inch); | |
| 1605 | put(' '); | |
| 1606 | put(hresolution); | |
| 1607 | put(' '); | |
| 1608 | put(vresolution); | |
| 1609 | put('\n'); | |
| 1610 | put("x init\n"); | |
| 1611 | } | |
| 1612 | ||
| 1613 | /* output_file */ | |
| 1614 | ||
| 1615 | output_file *the_output = 0; | |
| 1616 | ||
| 1617 | output_file::output_file() | |
| 1618 | { | |
| 1619 | } | |
| 1620 | ||
| 1621 | output_file::~output_file() | |
| 1622 | { | |
| 1623 | } | |
| 1624 | ||
| 1625 | void output_file::trailer(vunits) | |
| 1626 | { | |
| 1627 | } | |
| 1628 | ||
| 4d3e9548 | 1629 | void output_file::put_filename(const char *, int) |
| 92d0a6a6 JR |
1630 | { |
| 1631 | } | |
| 1632 | ||
| 1633 | void output_file::on() | |
| 1634 | { | |
| 1635 | } | |
| 1636 | ||
| 1637 | void output_file::off() | |
| 1638 | { | |
| 1639 | } | |
| 1640 | ||
| 1641 | real_output_file::real_output_file() | |
| 1642 | : printing(0), output_on(1) | |
| 1643 | { | |
| 1644 | #ifndef POPEN_MISSING | |
| 1645 | if (pipe_command) { | |
| 1646 | if ((fp = popen(pipe_command, POPEN_WT)) != 0) { | |
| 1647 | piped = 1; | |
| 1648 | return; | |
| 1649 | } | |
| 1650 | error("pipe open failed: %1", strerror(errno)); | |
| 1651 | } | |
| 1652 | piped = 0; | |
| 1653 | #endif /* not POPEN_MISSING */ | |
| 1654 | fp = stdout; | |
| 1655 | } | |
| 1656 | ||
| 1657 | real_output_file::~real_output_file() | |
| 1658 | { | |
| 1659 | if (!fp) | |
| 1660 | return; | |
| 1661 | // To avoid looping, set fp to 0 before calling fatal(). | |
| 1662 | if (ferror(fp) || fflush(fp) < 0) { | |
| 1663 | fp = 0; | |
| 1664 | fatal("error writing output file"); | |
| 1665 | } | |
| 1666 | #ifndef POPEN_MISSING | |
| 1667 | if (piped) { | |
| 1668 | int result = pclose(fp); | |
| 1669 | fp = 0; | |
| 1670 | if (result < 0) | |
| 1671 | fatal("pclose failed"); | |
| 1672 | if (!WIFEXITED(result)) | |
| 1673 | error("output process `%1' got fatal signal %2", | |
| 1674 | pipe_command, | |
| 1675 | WIFSIGNALED(result) ? WTERMSIG(result) : WSTOPSIG(result)); | |
| 1676 | else { | |
| 1677 | int exit_status = WEXITSTATUS(result); | |
| 1678 | if (exit_status != 0) | |
| 1679 | error("output process `%1' exited with status %2", | |
| 1680 | pipe_command, exit_status); | |
| 1681 | } | |
| 1682 | } | |
| 1683 | else | |
| 1684 | #endif /* not POPEN MISSING */ | |
| 1685 | if (fclose(fp) < 0) { | |
| 1686 | fp = 0; | |
| 1687 | fatal("error closing output file"); | |
| 1688 | } | |
| 1689 | } | |
| 1690 | ||
| 1691 | void real_output_file::flush() | |
| 1692 | { | |
| 1693 | if (fflush(fp) < 0) | |
| 1694 | fatal("error writing output file"); | |
| 1695 | } | |
| 1696 | ||
| 1697 | int real_output_file::is_printing() | |
| 1698 | { | |
| 1699 | return printing; | |
| 1700 | } | |
| 1701 | ||
| 1702 | void real_output_file::begin_page(int pageno, vunits page_length) | |
| 1703 | { | |
| 1704 | printing = in_output_page_list(pageno); | |
| 1705 | if (printing) | |
| 1706 | really_begin_page(pageno, page_length); | |
| 1707 | } | |
| 1708 | ||
| 1709 | void real_output_file::copy_file(hunits x, vunits y, const char *filename) | |
| 1710 | { | |
| 1711 | if (printing && output_on) | |
| 1712 | really_copy_file(x, y, filename); | |
| 1713 | check_output_limits(x.to_units(), y.to_units()); | |
| 1714 | } | |
| 1715 | ||
| 1716 | void real_output_file::transparent_char(unsigned char c) | |
| 1717 | { | |
| 1718 | if (printing && output_on) | |
| 1719 | really_transparent_char(c); | |
| 1720 | } | |
| 1721 | ||
| 1722 | void real_output_file::print_line(hunits x, vunits y, node *n, | |
| 1723 | vunits before, vunits after, hunits width) | |
| 1724 | { | |
| 1725 | if (printing) | |
| 1726 | really_print_line(x, y, n, before, after, width); | |
| 1727 | delete_node_list(n); | |
| 1728 | } | |
| 1729 | ||
| 1730 | void real_output_file::really_copy_file(hunits, vunits, const char *) | |
| 1731 | { | |
| 1732 | // do nothing | |
| 1733 | } | |
| 1734 | ||
| 4d3e9548 | 1735 | void real_output_file::put_filename(const char *filename, int po) |
| 92d0a6a6 | 1736 | { |
| 4d3e9548 | 1737 | really_put_filename(filename, po); |
| 92d0a6a6 JR |
1738 | } |
| 1739 | ||
| 4d3e9548 | 1740 | void real_output_file::really_put_filename(const char *, int) |
| 92d0a6a6 JR |
1741 | { |
| 1742 | } | |
| 1743 | ||
| 1744 | void real_output_file::on() | |
| 1745 | { | |
| 1746 | really_on(); | |
| 1747 | if (output_on == 0) | |
| 1748 | output_on = 1; | |
| 1749 | } | |
| 1750 | ||
| 1751 | void real_output_file::off() | |
| 1752 | { | |
| 1753 | really_off(); | |
| 1754 | output_on = 0; | |
| 1755 | } | |
| 1756 | ||
| 1757 | int real_output_file::is_on() | |
| 1758 | { | |
| 1759 | return output_on; | |
| 1760 | } | |
| 1761 | ||
| 1762 | void real_output_file::really_on() | |
| 1763 | { | |
| 1764 | } | |
| 1765 | ||
| 1766 | void real_output_file::really_off() | |
| 1767 | { | |
| 1768 | } | |
| 1769 | ||
| 1770 | /* ascii_output_file */ | |
| 1771 | ||
| 1772 | void ascii_output_file::really_transparent_char(unsigned char c) | |
| 1773 | { | |
| 1774 | putc(c, fp); | |
| 1775 | } | |
| 1776 | ||
| 1777 | void ascii_output_file::really_print_line(hunits, vunits, node *n, | |
| 1778 | vunits, vunits, hunits) | |
| 1779 | { | |
| 1780 | while (n != 0) { | |
| 1781 | n->ascii_print(this); | |
| 1782 | n = n->next; | |
| 1783 | } | |
| 1784 | fputc('\n', fp); | |
| 1785 | } | |
| 1786 | ||
| 1787 | void ascii_output_file::really_begin_page(int /*pageno*/, vunits /*page_length*/) | |
| 1788 | { | |
| 1789 | fputs("<beginning of page>\n", fp); | |
| 1790 | } | |
| 1791 | ||
| 1792 | ascii_output_file::ascii_output_file() | |
| 1793 | { | |
| 1794 | } | |
| 1795 | ||
| 1796 | /* suppress_output_file */ | |
| 1797 | ||
| 1798 | suppress_output_file::suppress_output_file() | |
| 1799 | { | |
| 1800 | } | |
| 1801 | ||
| 1802 | void suppress_output_file::really_print_line(hunits, vunits, node *, vunits, vunits, hunits) | |
| 1803 | { | |
| 1804 | } | |
| 1805 | ||
| 1806 | void suppress_output_file::really_begin_page(int, vunits) | |
| 1807 | { | |
| 1808 | } | |
| 1809 | ||
| 1810 | void suppress_output_file::really_transparent_char(unsigned char) | |
| 1811 | { | |
| 1812 | } | |
| 1813 | ||
| 1814 | /* glyphs, ligatures, kerns, discretionary breaks */ | |
| 1815 | ||
| 1816 | class charinfo_node : public node { | |
| 1817 | protected: | |
| 1818 | charinfo *ci; | |
| 1819 | public: | |
| 465b256c | 1820 | charinfo_node(charinfo *, statem *, int, node * = 0); |
| 92d0a6a6 JR |
1821 | int ends_sentence(); |
| 1822 | int overlaps_vertically(); | |
| 1823 | int overlaps_horizontally(); | |
| 1824 | }; | |
| 1825 | ||
| 465b256c JR |
1826 | charinfo_node::charinfo_node(charinfo *c, statem *s, int pop, node *x) |
| 1827 | : node(x, s, pop), ci(c) | |
| 92d0a6a6 JR |
1828 | { |
| 1829 | } | |
| 1830 | ||
| 1831 | int charinfo_node::ends_sentence() | |
| 1832 | { | |
| 1833 | if (ci->ends_sentence()) | |
| 1834 | return 1; | |
| 1835 | else if (ci->transparent()) | |
| 1836 | return 2; | |
| 1837 | else | |
| 1838 | return 0; | |
| 1839 | } | |
| 1840 | ||
| 1841 | int charinfo_node::overlaps_horizontally() | |
| 1842 | { | |
| 1843 | return ci->overlaps_horizontally(); | |
| 1844 | } | |
| 1845 | ||
| 1846 | int charinfo_node::overlaps_vertically() | |
| 1847 | { | |
| 1848 | return ci->overlaps_vertically(); | |
| 1849 | } | |
| 1850 | ||
| 1851 | class glyph_node : public charinfo_node { | |
| 1852 | static glyph_node *free_list; | |
| 1853 | protected: | |
| 1854 | tfont *tf; | |
| 1855 | color *gcol; | |
| 1856 | color *fcol; /* this is needed for grotty */ | |
| 1857 | #ifdef STORE_WIDTH | |
| 1858 | hunits wid; | |
| 465b256c JR |
1859 | glyph_node(charinfo *, tfont *, color *, color *, hunits, |
| 1860 | statem *, int, node * = 0); | |
| 92d0a6a6 JR |
1861 | #endif |
| 1862 | public: | |
| 1863 | void *operator new(size_t); | |
| 1864 | void operator delete(void *); | |
| 465b256c JR |
1865 | glyph_node(charinfo *, tfont *, color *, color *, |
| 1866 | statem *, int, node * = 0); | |
| 92d0a6a6 JR |
1867 | ~glyph_node() {} |
| 1868 | node *copy(); | |
| 1869 | node *merge_glyph_node(glyph_node *); | |
| 1870 | node *merge_self(node *); | |
| 1871 | hunits width(); | |
| 1872 | node *last_char_node(); | |
| 1873 | units size(); | |
| 1874 | void vertical_extent(vunits *, vunits *); | |
| 1875 | hunits subscript_correction(); | |
| 1876 | hunits italic_correction(); | |
| 1877 | hunits left_italic_correction(); | |
| 1878 | hunits skew(); | |
| 1879 | hyphenation_type get_hyphenation_type(); | |
| 1880 | tfont *get_tfont(); | |
| 1881 | color *get_glyph_color(); | |
| 1882 | color *get_fill_color(); | |
| 1883 | void tprint(troff_output_file *); | |
| 1884 | void zero_width_tprint(troff_output_file *); | |
| 1885 | hyphen_list *get_hyphen_list(hyphen_list *, int *); | |
| 1886 | node *add_self(node *, hyphen_list **); | |
| 1887 | void ascii_print(ascii_output_file *); | |
| 1888 | void asciify(macro *); | |
| 1889 | int character_type(); | |
| 1890 | int same(node *); | |
| 1891 | const char *type(); | |
| 1892 | int force_tprint(); | |
| 465b256c JR |
1893 | int is_tag(); |
| 1894 | void debug_node(); | |
| 92d0a6a6 JR |
1895 | }; |
| 1896 | ||
| 1897 | glyph_node *glyph_node::free_list = 0; | |
| 1898 | ||
| 1899 | class ligature_node : public glyph_node { | |
| 1900 | node *n1; | |
| 1901 | node *n2; | |
| 1902 | #ifdef STORE_WIDTH | |
| 1903 | ligature_node(charinfo *, tfont *, color *, color *, hunits, | |
| 465b256c | 1904 | node *, node *, statem *, int, node * = 0); |
| 92d0a6a6 JR |
1905 | #endif |
| 1906 | public: | |
| 1907 | void *operator new(size_t); | |
| 1908 | void operator delete(void *); | |
| 1909 | ligature_node(charinfo *, tfont *, color *, color *, | |
| 465b256c | 1910 | node *, node *, statem *, int, node * = 0); |
| 92d0a6a6 JR |
1911 | ~ligature_node(); |
| 1912 | node *copy(); | |
| 1913 | node *add_self(node *, hyphen_list **); | |
| 1914 | hyphen_list *get_hyphen_list(hyphen_list *, int *); | |
| 1915 | void ascii_print(ascii_output_file *); | |
| 1916 | void asciify(macro *); | |
| 1917 | int same(node *); | |
| 1918 | const char *type(); | |
| 1919 | int force_tprint(); | |
| 465b256c | 1920 | int is_tag(); |
| 92d0a6a6 JR |
1921 | }; |
| 1922 | ||
| 1923 | class kern_pair_node : public node { | |
| 1924 | hunits amount; | |
| 1925 | node *n1; | |
| 1926 | node *n2; | |
| 1927 | public: | |
| 465b256c | 1928 | kern_pair_node(hunits, node *, node *, statem *, int, node * = 0); |
| 92d0a6a6 JR |
1929 | ~kern_pair_node(); |
| 1930 | node *copy(); | |
| 1931 | node *merge_glyph_node(glyph_node *); | |
| 1932 | node *add_self(node *, hyphen_list **); | |
| 1933 | hyphen_list *get_hyphen_list(hyphen_list *, int *); | |
| 1934 | node *add_discretionary_hyphen(); | |
| 1935 | hunits width(); | |
| 1936 | node *last_char_node(); | |
| 1937 | hunits italic_correction(); | |
| 1938 | hunits subscript_correction(); | |
| 1939 | void tprint(troff_output_file *); | |
| 1940 | hyphenation_type get_hyphenation_type(); | |
| 1941 | int ends_sentence(); | |
| 1942 | void ascii_print(ascii_output_file *); | |
| 1943 | void asciify(macro *); | |
| 1944 | int same(node *); | |
| 1945 | const char *type(); | |
| 1946 | int force_tprint(); | |
| 465b256c | 1947 | int is_tag(); |
| 92d0a6a6 JR |
1948 | void vertical_extent(vunits *, vunits *); |
| 1949 | }; | |
| 1950 | ||
| 1951 | class dbreak_node : public node { | |
| 1952 | node *none; | |
| 1953 | node *pre; | |
| 1954 | node *post; | |
| 1955 | public: | |
| 465b256c | 1956 | dbreak_node(node *, node *, statem *, int, node * = 0); |
| 92d0a6a6 JR |
1957 | ~dbreak_node(); |
| 1958 | node *copy(); | |
| 1959 | node *merge_glyph_node(glyph_node *); | |
| 1960 | node *add_discretionary_hyphen(); | |
| 1961 | hunits width(); | |
| 1962 | node *last_char_node(); | |
| 1963 | hunits italic_correction(); | |
| 1964 | hunits subscript_correction(); | |
| 1965 | void tprint(troff_output_file *); | |
| 1966 | breakpoint *get_breakpoints(hunits width, int ns, breakpoint *rest = 0, | |
| 1967 | int is_inner = 0); | |
| 1968 | int nbreaks(); | |
| 1969 | int ends_sentence(); | |
| 1970 | void split(int, node **, node **); | |
| 1971 | hyphenation_type get_hyphenation_type(); | |
| 1972 | void ascii_print(ascii_output_file *); | |
| 1973 | void asciify(macro *); | |
| 1974 | int same(node *); | |
| 1975 | const char *type(); | |
| 1976 | int force_tprint(); | |
| 465b256c | 1977 | int is_tag(); |
| 92d0a6a6 JR |
1978 | }; |
| 1979 | ||
| 1980 | void *glyph_node::operator new(size_t n) | |
| 1981 | { | |
| 1982 | assert(n == sizeof(glyph_node)); | |
| 1983 | if (!free_list) { | |
| 1984 | const int BLOCK = 1024; | |
| 1985 | free_list = (glyph_node *)new char[sizeof(glyph_node)*BLOCK]; | |
| 1986 | for (int i = 0; i < BLOCK - 1; i++) | |
| 1987 | free_list[i].next = free_list + i + 1; | |
| 1988 | free_list[BLOCK-1].next = 0; | |
| 1989 | } | |
| 1990 | glyph_node *p = free_list; | |
| 1991 | free_list = (glyph_node *)(free_list->next); | |
| 1992 | p->next = 0; | |
| 1993 | return p; | |
| 1994 | } | |
| 1995 | ||
| 1996 | void *ligature_node::operator new(size_t n) | |
| 1997 | { | |
| 1998 | return new char[n]; | |
| 1999 | } | |
| 2000 | ||
| 2001 | void glyph_node::operator delete(void *p) | |
| 2002 | { | |
| 2003 | if (p) { | |
| 2004 | ((glyph_node *)p)->next = free_list; | |
| 2005 | free_list = (glyph_node *)p; | |
| 2006 | } | |
| 2007 | } | |
| 2008 | ||
| 2009 | void ligature_node::operator delete(void *p) | |
| 2010 | { | |
| 2011 | delete[] (char *)p; | |
| 2012 | } | |
| 2013 | ||
| 465b256c JR |
2014 | glyph_node::glyph_node(charinfo *c, tfont *t, color *gc, color *fc, |
| 2015 | statem *s, int pop, node *x) | |
| 2016 | : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc) | |
| 92d0a6a6 JR |
2017 | { |
| 2018 | #ifdef STORE_WIDTH | |
| 2019 | wid = tf->get_width(ci); | |
| 2020 | #endif | |
| 2021 | } | |
| 2022 | ||
| 2023 | #ifdef STORE_WIDTH | |
| 2024 | glyph_node::glyph_node(charinfo *c, tfont *t, | |
| 465b256c JR |
2025 | color *gc, color *fc, hunits w, |
| 2026 | statem *s, int pop, node *x) | |
| 2027 | : charinfo_node(c, s, pop, x), tf(t), gcol(gc), fcol(fc), wid(w) | |
| 92d0a6a6 JR |
2028 | { |
| 2029 | } | |
| 2030 | #endif | |
| 2031 | ||
| 2032 | node *glyph_node::copy() | |
| 2033 | { | |
| 2034 | #ifdef STORE_WIDTH | |
| 465b256c | 2035 | return new glyph_node(ci, tf, gcol, fcol, wid, state, div_nest_level); |
| 92d0a6a6 | 2036 | #else |
| 465b256c | 2037 | return new glyph_node(ci, tf, gcol, fcol, state, div_nest_level); |
| 92d0a6a6 JR |
2038 | #endif |
| 2039 | } | |
| 2040 | ||
| 2041 | node *glyph_node::merge_self(node *nd) | |
| 2042 | { | |
| 2043 | return nd->merge_glyph_node(this); | |
| 2044 | } | |
| 2045 | ||
| 2046 | int glyph_node::character_type() | |
| 2047 | { | |
| 2048 | return tf->get_character_type(ci); | |
| 2049 | } | |
| 2050 | ||
| 2051 | node *glyph_node::add_self(node *n, hyphen_list **p) | |
| 2052 | { | |
| 2053 | assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); | |
| 2054 | next = 0; | |
| 2055 | node *nn; | |
| 2056 | if (n == 0 || (nn = n->merge_glyph_node(this)) == 0) { | |
| 2057 | next = n; | |
| 2058 | nn = this; | |
| 2059 | } | |
| 2060 | if ((*p)->hyphen) | |
| 2061 | nn = nn->add_discretionary_hyphen(); | |
| 2062 | hyphen_list *pp = *p; | |
| 2063 | *p = (*p)->next; | |
| 2064 | delete pp; | |
| 2065 | return nn; | |
| 2066 | } | |
| 2067 | ||
| 2068 | units glyph_node::size() | |
| 2069 | { | |
| 2070 | return tf->get_size().to_units(); | |
| 2071 | } | |
| 2072 | ||
| 2073 | hyphen_list *glyph_node::get_hyphen_list(hyphen_list *tail, int *count) | |
| 2074 | { | |
| 2075 | (*count)++; | |
| 2076 | return new hyphen_list(ci->get_hyphenation_code(), tail); | |
| 2077 | } | |
| 2078 | ||
| 2079 | tfont *node::get_tfont() | |
| 2080 | { | |
| 2081 | return 0; | |
| 2082 | } | |
| 2083 | ||
| 2084 | tfont *glyph_node::get_tfont() | |
| 2085 | { | |
| 2086 | return tf; | |
| 2087 | } | |
| 2088 | ||
| 2089 | color *node::get_glyph_color() | |
| 2090 | { | |
| 2091 | return 0; | |
| 2092 | } | |
| 2093 | ||
| 2094 | color *glyph_node::get_glyph_color() | |
| 2095 | { | |
| 2096 | return gcol; | |
| 2097 | } | |
| 2098 | ||
| 2099 | color *node::get_fill_color() | |
| 2100 | { | |
| 2101 | return 0; | |
| 2102 | } | |
| 2103 | ||
| 2104 | color *glyph_node::get_fill_color() | |
| 2105 | { | |
| 2106 | return fcol; | |
| 2107 | } | |
| 2108 | ||
| 2109 | node *node::merge_glyph_node(glyph_node *) | |
| 2110 | { | |
| 2111 | return 0; | |
| 2112 | } | |
| 2113 | ||
| 2114 | node *glyph_node::merge_glyph_node(glyph_node *gn) | |
| 2115 | { | |
| 2116 | if (tf == gn->tf && gcol == gn->gcol && fcol == gn->fcol) { | |
| 2117 | charinfo *lig; | |
| 2118 | if ((lig = tf->get_lig(ci, gn->ci)) != 0) { | |
| 2119 | node *next1 = next; | |
| 2120 | next = 0; | |
| 465b256c JR |
2121 | return new ligature_node(lig, tf, gcol, fcol, this, gn, state, |
| 2122 | gn->div_nest_level, next1); | |
| 92d0a6a6 JR |
2123 | } |
| 2124 | hunits kern; | |
| 2125 | if (tf->get_kern(ci, gn->ci, &kern)) { | |
| 2126 | node *next1 = next; | |
| 2127 | next = 0; | |
| 465b256c JR |
2128 | return new kern_pair_node(kern, this, gn, state, |
| 2129 | gn->div_nest_level, next1); | |
| 92d0a6a6 JR |
2130 | } |
| 2131 | } | |
| 2132 | return 0; | |
| 2133 | } | |
| 2134 | ||
| 2135 | #ifdef STORE_WIDTH | |
| 2136 | inline | |
| 2137 | #endif | |
| 2138 | hunits glyph_node::width() | |
| 2139 | { | |
| 2140 | #ifdef STORE_WIDTH | |
| 2141 | return wid; | |
| 2142 | #else | |
| 2143 | return tf->get_width(ci); | |
| 2144 | #endif | |
| 2145 | } | |
| 2146 | ||
| 2147 | node *glyph_node::last_char_node() | |
| 2148 | { | |
| 2149 | return this; | |
| 2150 | } | |
| 2151 | ||
| 2152 | void glyph_node::vertical_extent(vunits *min, vunits *max) | |
| 2153 | { | |
| 2154 | *min = -tf->get_char_height(ci); | |
| 2155 | *max = tf->get_char_depth(ci); | |
| 2156 | } | |
| 2157 | ||
| 2158 | hunits glyph_node::skew() | |
| 2159 | { | |
| 2160 | return tf->get_char_skew(ci); | |
| 2161 | } | |
| 2162 | ||
| 2163 | hunits glyph_node::subscript_correction() | |
| 2164 | { | |
| 2165 | return tf->get_subscript_correction(ci); | |
| 2166 | } | |
| 2167 | ||
| 2168 | hunits glyph_node::italic_correction() | |
| 2169 | { | |
| 2170 | return tf->get_italic_correction(ci); | |
| 2171 | } | |
| 2172 | ||
| 2173 | hunits glyph_node::left_italic_correction() | |
| 2174 | { | |
| 2175 | return tf->get_left_italic_correction(ci); | |
| 2176 | } | |
| 2177 | ||
| 2178 | hyphenation_type glyph_node::get_hyphenation_type() | |
| 2179 | { | |
| 2180 | return HYPHEN_MIDDLE; | |
| 2181 | } | |
| 2182 | ||
| 2183 | void glyph_node::ascii_print(ascii_output_file *ascii) | |
| 2184 | { | |
| 2185 | unsigned char c = ci->get_ascii_code(); | |
| 2186 | if (c != 0) | |
| 2187 | ascii->outc(c); | |
| 2188 | else | |
| 2189 | ascii->outs(ci->nm.contents()); | |
| 2190 | } | |
| 2191 | ||
| 465b256c JR |
2192 | void glyph_node::debug_node() |
| 2193 | { | |
| 2194 | unsigned char c = ci->get_ascii_code(); | |
| 2195 | fprintf(stderr, "{ %s [", type()); | |
| 2196 | if (c) | |
| 2197 | fprintf(stderr, "%c", c); | |
| 2198 | else | |
| 2199 | fprintf(stderr, ci->nm.contents()); | |
| 2200 | if (push_state) | |
| 2201 | fprintf(stderr, " <push_state>"); | |
| 2202 | if (state) | |
| 2203 | state->display_state(); | |
| 2204 | fprintf(stderr, " nest level %d", div_nest_level); | |
| 2205 | fprintf(stderr, "]}\n"); | |
| 2206 | fflush(stderr); | |
| 2207 | } | |
| 2208 | ||
| 92d0a6a6 | 2209 | ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc, |
| 465b256c JR |
2210 | node *gn1, node *gn2, statem *s, |
| 2211 | int pop, node *x) | |
| 2212 | : glyph_node(c, t, gc, fc, s, pop, x), n1(gn1), n2(gn2) | |
| 92d0a6a6 JR |
2213 | { |
| 2214 | } | |
| 2215 | ||
| 2216 | #ifdef STORE_WIDTH | |
| 2217 | ligature_node::ligature_node(charinfo *c, tfont *t, color *gc, color *fc, | |
| 465b256c JR |
2218 | hunits w, node *gn1, node *gn2, statem *s, |
| 2219 | int pop, node *x) | |
| 2220 | : glyph_node(c, t, gc, fc, w, s, pop, x), n1(gn1), n2(gn2) | |
| 92d0a6a6 JR |
2221 | { |
| 2222 | } | |
| 2223 | #endif | |
| 2224 | ||
| 2225 | ligature_node::~ligature_node() | |
| 2226 | { | |
| 2227 | delete n1; | |
| 2228 | delete n2; | |
| 2229 | } | |
| 2230 | ||
| 2231 | node *ligature_node::copy() | |
| 2232 | { | |
| 2233 | #ifdef STORE_WIDTH | |
| 465b256c JR |
2234 | return new ligature_node(ci, tf, gcol, fcol, wid, n1->copy(), n2->copy(), |
| 2235 | state, div_nest_level); | |
| 92d0a6a6 | 2236 | #else |
| 465b256c JR |
2237 | return new ligature_node(ci, tf, gcol, fcol, n1->copy(), n2->copy(), |
| 2238 | state, div_nest_level); | |
| 92d0a6a6 JR |
2239 | #endif |
| 2240 | } | |
| 2241 | ||
| 2242 | void ligature_node::ascii_print(ascii_output_file *ascii) | |
| 2243 | { | |
| 2244 | n1->ascii_print(ascii); | |
| 2245 | n2->ascii_print(ascii); | |
| 2246 | } | |
| 2247 | ||
| 2248 | hyphen_list *ligature_node::get_hyphen_list(hyphen_list *tail, int *count) | |
| 2249 | { | |
| 2250 | hyphen_list *hl = n2->get_hyphen_list(tail, count); | |
| 2251 | return n1->get_hyphen_list(hl, count); | |
| 2252 | } | |
| 2253 | ||
| 2254 | node *ligature_node::add_self(node *n, hyphen_list **p) | |
| 2255 | { | |
| 2256 | n = n1->add_self(n, p); | |
| 2257 | n = n2->add_self(n, p); | |
| 2258 | n1 = n2 = 0; | |
| 2259 | delete this; | |
| 2260 | return n; | |
| 2261 | } | |
| 2262 | ||
| 465b256c JR |
2263 | kern_pair_node::kern_pair_node(hunits n, node *first, node *second, |
| 2264 | statem* s, int pop, node *x) | |
| 2265 | : node(x, s, pop), amount(n), n1(first), n2(second) | |
| 92d0a6a6 JR |
2266 | { |
| 2267 | } | |
| 2268 | ||
| 465b256c JR |
2269 | dbreak_node::dbreak_node(node *n, node *p, statem *s, int pop, node *x) |
| 2270 | : node(x, s, pop), none(n), pre(p), post(0) | |
| 92d0a6a6 JR |
2271 | { |
| 2272 | } | |
| 2273 | ||
| 2274 | node *dbreak_node::merge_glyph_node(glyph_node *gn) | |
| 2275 | { | |
| 2276 | glyph_node *gn2 = (glyph_node *)gn->copy(); | |
| 2277 | node *new_none = none ? none->merge_glyph_node(gn) : 0; | |
| 2278 | node *new_post = post ? post->merge_glyph_node(gn2) : 0; | |
| 2279 | if (new_none == 0 && new_post == 0) { | |
| 2280 | delete gn2; | |
| 2281 | return 0; | |
| 2282 | } | |
| 2283 | if (new_none != 0) | |
| 2284 | none = new_none; | |
| 2285 | else { | |
| 2286 | gn->next = none; | |
| 2287 | none = gn; | |
| 2288 | } | |
| 2289 | if (new_post != 0) | |
| 2290 | post = new_post; | |
| 2291 | else { | |
| 2292 | gn2->next = post; | |
| 2293 | post = gn2; | |
| 2294 | } | |
| 2295 | return this; | |
| 2296 | } | |
| 2297 | ||
| 2298 | node *kern_pair_node::merge_glyph_node(glyph_node *gn) | |
| 2299 | { | |
| 2300 | node *nd = n2->merge_glyph_node(gn); | |
| 2301 | if (nd == 0) | |
| 2302 | return 0; | |
| 2303 | n2 = nd; | |
| 2304 | nd = n2->merge_self(n1); | |
| 2305 | if (nd) { | |
| 2306 | nd->next = next; | |
| 2307 | n1 = 0; | |
| 2308 | n2 = 0; | |
| 2309 | delete this; | |
| 2310 | return nd; | |
| 2311 | } | |
| 2312 | return this; | |
| 2313 | } | |
| 2314 | ||
| 2315 | hunits kern_pair_node::italic_correction() | |
| 2316 | { | |
| 2317 | return n2->italic_correction(); | |
| 2318 | } | |
| 2319 | ||
| 2320 | hunits kern_pair_node::subscript_correction() | |
| 2321 | { | |
| 2322 | return n2->subscript_correction(); | |
| 2323 | } | |
| 2324 | ||
| 2325 | void kern_pair_node::vertical_extent(vunits *min, vunits *max) | |
| 2326 | { | |
| 2327 | n1->vertical_extent(min, max); | |
| 2328 | vunits min2, max2; | |
| 2329 | n2->vertical_extent(&min2, &max2); | |
| 2330 | if (min2 < *min) | |
| 2331 | *min = min2; | |
| 2332 | if (max2 > *max) | |
| 2333 | *max = max2; | |
| 2334 | } | |
| 2335 | ||
| 2336 | node *kern_pair_node::add_discretionary_hyphen() | |
| 2337 | { | |
| 2338 | tfont *tf = n2->get_tfont(); | |
| 2339 | if (tf) { | |
| 2340 | if (tf->contains(soft_hyphen_char)) { | |
| 2341 | color *gcol = n2->get_glyph_color(); | |
| 2342 | color *fcol = n2->get_fill_color(); | |
| 2343 | node *next1 = next; | |
| 2344 | next = 0; | |
| 2345 | node *n = copy(); | |
| 465b256c JR |
2346 | glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol, |
| 2347 | state, div_nest_level); | |
| 92d0a6a6 JR |
2348 | node *nn = n->merge_glyph_node(gn); |
| 2349 | if (nn == 0) { | |
| 2350 | gn->next = n; | |
| 2351 | nn = gn; | |
| 2352 | } | |
| 465b256c | 2353 | return new dbreak_node(this, nn, state, div_nest_level, next1); |
| 92d0a6a6 JR |
2354 | } |
| 2355 | } | |
| 2356 | return this; | |
| 2357 | } | |
| 2358 | ||
| 2359 | kern_pair_node::~kern_pair_node() | |
| 2360 | { | |
| 2361 | if (n1 != 0) | |
| 2362 | delete n1; | |
| 2363 | if (n2 != 0) | |
| 2364 | delete n2; | |
| 2365 | } | |
| 2366 | ||
| 2367 | dbreak_node::~dbreak_node() | |
| 2368 | { | |
| 2369 | delete_node_list(pre); | |
| 2370 | delete_node_list(post); | |
| 2371 | delete_node_list(none); | |
| 2372 | } | |
| 2373 | ||
| 2374 | node *kern_pair_node::copy() | |
| 2375 | { | |
| 465b256c JR |
2376 | return new kern_pair_node(amount, n1->copy(), n2->copy(), state, |
| 2377 | div_nest_level); | |
| 92d0a6a6 JR |
2378 | } |
| 2379 | ||
| 2380 | node *copy_node_list(node *n) | |
| 2381 | { | |
| 2382 | node *p = 0; | |
| 2383 | while (n != 0) { | |
| 2384 | node *nn = n->copy(); | |
| 2385 | nn->next = p; | |
| 2386 | p = nn; | |
| 2387 | n = n->next; | |
| 2388 | } | |
| 2389 | while (p != 0) { | |
| 2390 | node *pp = p->next; | |
| 2391 | p->next = n; | |
| 2392 | n = p; | |
| 2393 | p = pp; | |
| 2394 | } | |
| 2395 | return n; | |
| 2396 | } | |
| 2397 | ||
| 2398 | void delete_node_list(node *n) | |
| 2399 | { | |
| 2400 | while (n != 0) { | |
| 2401 | node *tem = n; | |
| 2402 | n = n->next; | |
| 2403 | delete tem; | |
| 2404 | } | |
| 2405 | } | |
| 2406 | ||
| 2407 | node *dbreak_node::copy() | |
| 2408 | { | |
| 465b256c JR |
2409 | dbreak_node *p = new dbreak_node(copy_node_list(none), copy_node_list(pre), |
| 2410 | state, div_nest_level); | |
| 92d0a6a6 JR |
2411 | p->post = copy_node_list(post); |
| 2412 | return p; | |
| 2413 | } | |
| 2414 | ||
| 2415 | hyphen_list *node::get_hyphen_list(hyphen_list *tail, int *) | |
| 2416 | { | |
| 2417 | return tail; | |
| 2418 | } | |
| 2419 | ||
| 2420 | hyphen_list *kern_pair_node::get_hyphen_list(hyphen_list *tail, int *count) | |
| 2421 | { | |
| 2422 | hyphen_list *hl = n2->get_hyphen_list(tail, count); | |
| 2423 | return n1->get_hyphen_list(hl, count); | |
| 2424 | } | |
| 2425 | ||
| 2426 | class hyphen_inhibitor_node : public node { | |
| 2427 | public: | |
| 465b256c | 2428 | hyphen_inhibitor_node(node * = 0); |
| 92d0a6a6 JR |
2429 | node *copy(); |
| 2430 | int same(node *); | |
| 2431 | const char *type(); | |
| 2432 | int force_tprint(); | |
| 465b256c | 2433 | int is_tag(); |
| 92d0a6a6 JR |
2434 | hyphenation_type get_hyphenation_type(); |
| 2435 | }; | |
| 2436 | ||
| 2437 | hyphen_inhibitor_node::hyphen_inhibitor_node(node *nd) : node(nd) | |
| 2438 | { | |
| 2439 | } | |
| 2440 | ||
| 2441 | node *hyphen_inhibitor_node::copy() | |
| 2442 | { | |
| 2443 | return new hyphen_inhibitor_node; | |
| 2444 | } | |
| 2445 | ||
| 2446 | int hyphen_inhibitor_node::same(node *) | |
| 2447 | { | |
| 2448 | return 1; | |
| 2449 | } | |
| 2450 | ||
| 2451 | const char *hyphen_inhibitor_node::type() | |
| 2452 | { | |
| 2453 | return "hyphen_inhibitor_node"; | |
| 2454 | } | |
| 2455 | ||
| 2456 | int hyphen_inhibitor_node::force_tprint() | |
| 2457 | { | |
| 2458 | return 0; | |
| 2459 | } | |
| 2460 | ||
| 465b256c JR |
2461 | int hyphen_inhibitor_node::is_tag() |
| 2462 | { | |
| 2463 | return 0; | |
| 2464 | } | |
| 2465 | ||
| 92d0a6a6 JR |
2466 | hyphenation_type hyphen_inhibitor_node::get_hyphenation_type() |
| 2467 | { | |
| 2468 | return HYPHEN_INHIBIT; | |
| 2469 | } | |
| 2470 | ||
| 2471 | /* add_discretionary_hyphen methods */ | |
| 2472 | ||
| 2473 | node *dbreak_node::add_discretionary_hyphen() | |
| 2474 | { | |
| 2475 | if (post) | |
| 2476 | post = post->add_discretionary_hyphen(); | |
| 2477 | if (none) | |
| 2478 | none = none->add_discretionary_hyphen(); | |
| 2479 | return this; | |
| 2480 | } | |
| 2481 | ||
| 2482 | node *node::add_discretionary_hyphen() | |
| 2483 | { | |
| 2484 | tfont *tf = get_tfont(); | |
| 2485 | if (!tf) | |
| 2486 | return new hyphen_inhibitor_node(this); | |
| 2487 | if (tf->contains(soft_hyphen_char)) { | |
| 2488 | color *gcol = get_glyph_color(); | |
| 2489 | color *fcol = get_fill_color(); | |
| 2490 | node *next1 = next; | |
| 2491 | next = 0; | |
| 2492 | node *n = copy(); | |
| 465b256c JR |
2493 | glyph_node *gn = new glyph_node(soft_hyphen_char, tf, gcol, fcol, |
| 2494 | state, div_nest_level); | |
| 92d0a6a6 JR |
2495 | node *n1 = n->merge_glyph_node(gn); |
| 2496 | if (n1 == 0) { | |
| 2497 | gn->next = n; | |
| 2498 | n1 = gn; | |
| 2499 | } | |
| 465b256c | 2500 | return new dbreak_node(this, n1, state, div_nest_level, next1); |
| 92d0a6a6 JR |
2501 | } |
| 2502 | return this; | |
| 2503 | } | |
| 2504 | ||
| 2505 | node *node::merge_self(node *) | |
| 2506 | { | |
| 2507 | return 0; | |
| 2508 | } | |
| 2509 | ||
| 2510 | node *node::add_self(node *n, hyphen_list ** /*p*/) | |
| 2511 | { | |
| 2512 | next = n; | |
| 2513 | return this; | |
| 2514 | } | |
| 2515 | ||
| 2516 | node *kern_pair_node::add_self(node *n, hyphen_list **p) | |
| 2517 | { | |
| 2518 | n = n1->add_self(n, p); | |
| 2519 | n = n2->add_self(n, p); | |
| 2520 | n1 = n2 = 0; | |
| 2521 | delete this; | |
| 2522 | return n; | |
| 2523 | } | |
| 2524 | ||
| 2525 | hunits node::width() | |
| 2526 | { | |
| 2527 | return H0; | |
| 2528 | } | |
| 2529 | ||
| 2530 | node *node::last_char_node() | |
| 2531 | { | |
| 2532 | return 0; | |
| 2533 | } | |
| 2534 | ||
| 2535 | int node::force_tprint() | |
| 2536 | { | |
| 2537 | return 0; | |
| 2538 | } | |
| 2539 | ||
| 465b256c JR |
2540 | int node::is_tag() |
| 2541 | { | |
| 2542 | return 0; | |
| 2543 | } | |
| 2544 | ||
| 92d0a6a6 JR |
2545 | hunits hmotion_node::width() |
| 2546 | { | |
| 2547 | return n; | |
| 2548 | } | |
| 2549 | ||
| 2550 | units node::size() | |
| 2551 | { | |
| 2552 | return points_to_units(10); | |
| 2553 | } | |
| 2554 | ||
| 465b256c JR |
2555 | void node::debug_node() |
| 2556 | { | |
| 2557 | fprintf(stderr, "{ %s ", type()); | |
| 2558 | if (push_state) | |
| 2559 | fprintf(stderr, " <push_state>"); | |
| 2560 | if (state) | |
| 2561 | fprintf(stderr, " <state>"); | |
| 2562 | fprintf(stderr, " nest level %d", div_nest_level); | |
| 2563 | fprintf(stderr, " }\n"); | |
| 2564 | fflush(stderr); | |
| 2565 | } | |
| 2566 | ||
| 2567 | void node::debug_node_list() | |
| 2568 | { | |
| 2569 | node *n = next; | |
| 2570 | ||
| 2571 | debug_node(); | |
| 2572 | while (n != 0) { | |
| 2573 | n->debug_node(); | |
| 2574 | n = n->next; | |
| 2575 | } | |
| 2576 | } | |
| 2577 | ||
| 92d0a6a6 JR |
2578 | hunits kern_pair_node::width() |
| 2579 | { | |
| 2580 | return n1->width() + n2->width() + amount; | |
| 2581 | } | |
| 2582 | ||
| 2583 | node *kern_pair_node::last_char_node() | |
| 2584 | { | |
| 2585 | node *nd = n2->last_char_node(); | |
| 2586 | if (nd) | |
| 2587 | return nd; | |
| 2588 | return n1->last_char_node(); | |
| 2589 | } | |
| 2590 | ||
| 2591 | hunits dbreak_node::width() | |
| 2592 | { | |
| 2593 | hunits x = H0; | |
| 2594 | for (node *n = none; n != 0; n = n->next) | |
| 2595 | x += n->width(); | |
| 2596 | return x; | |
| 2597 | } | |
| 2598 | ||
| 2599 | node *dbreak_node::last_char_node() | |
| 2600 | { | |
| 2601 | for (node *n = none; n; n = n->next) { | |
| 2602 | node *last_node = n->last_char_node(); | |
| 2603 | if (last_node) | |
| 2604 | return last_node; | |
| 2605 | } | |
| 2606 | return 0; | |
| 2607 | } | |
| 2608 | ||
| 2609 | hunits dbreak_node::italic_correction() | |
| 2610 | { | |
| 2611 | return none ? none->italic_correction() : H0; | |
| 2612 | } | |
| 2613 | ||
| 2614 | hunits dbreak_node::subscript_correction() | |
| 2615 | { | |
| 2616 | return none ? none->subscript_correction() : H0; | |
| 2617 | } | |
| 2618 | ||
| 2619 | class italic_corrected_node : public node { | |
| 2620 | node *n; | |
| 2621 | hunits x; | |
| 2622 | public: | |
| 465b256c | 2623 | italic_corrected_node(node *, hunits, statem *, int, node * = 0); |
| 92d0a6a6 JR |
2624 | ~italic_corrected_node(); |
| 2625 | node *copy(); | |
| 2626 | void ascii_print(ascii_output_file *); | |
| 2627 | void asciify(macro *); | |
| 2628 | hunits width(); | |
| 2629 | node *last_char_node(); | |
| 2630 | void vertical_extent(vunits *, vunits *); | |
| 2631 | int ends_sentence(); | |
| 2632 | int overlaps_horizontally(); | |
| 2633 | int overlaps_vertically(); | |
| 2634 | int same(node *); | |
| 2635 | hyphenation_type get_hyphenation_type(); | |
| 2636 | tfont *get_tfont(); | |
| 2637 | hyphen_list *get_hyphen_list(hyphen_list *, int *); | |
| 2638 | int character_type(); | |
| 2639 | void tprint(troff_output_file *); | |
| 2640 | hunits subscript_correction(); | |
| 2641 | hunits skew(); | |
| 2642 | node *add_self(node *, hyphen_list **); | |
| 2643 | const char *type(); | |
| 2644 | int force_tprint(); | |
| 465b256c | 2645 | int is_tag(); |
| 92d0a6a6 JR |
2646 | }; |
| 2647 | ||
| 2648 | node *node::add_italic_correction(hunits *wd) | |
| 2649 | { | |
| 2650 | hunits ic = italic_correction(); | |
| 2651 | if (ic.is_zero()) | |
| 2652 | return this; | |
| 2653 | else { | |
| 2654 | node *next1 = next; | |
| 2655 | next = 0; | |
| 2656 | *wd += ic; | |
| 465b256c | 2657 | return new italic_corrected_node(this, ic, state, div_nest_level, next1); |
| 92d0a6a6 JR |
2658 | } |
| 2659 | } | |
| 2660 | ||
| 465b256c JR |
2661 | italic_corrected_node::italic_corrected_node(node *nn, hunits xx, statem *s, |
| 2662 | int pop, node *p) | |
| 2663 | : node(p, s, pop), n(nn), x(xx) | |
| 92d0a6a6 JR |
2664 | { |
| 2665 | assert(n != 0); | |
| 2666 | } | |
| 2667 | ||
| 2668 | italic_corrected_node::~italic_corrected_node() | |
| 2669 | { | |
| 2670 | delete n; | |
| 2671 | } | |
| 2672 | ||
| 2673 | node *italic_corrected_node::copy() | |
| 2674 | { | |
| 465b256c | 2675 | return new italic_corrected_node(n->copy(), x, state, div_nest_level); |
| 92d0a6a6 JR |
2676 | } |
| 2677 | ||
| 2678 | hunits italic_corrected_node::width() | |
| 2679 | { | |
| 2680 | return n->width() + x; | |
| 2681 | } | |
| 2682 | ||
| 2683 | void italic_corrected_node::vertical_extent(vunits *min, vunits *max) | |
| 2684 | { | |
| 2685 | n->vertical_extent(min, max); | |
| 2686 | } | |
| 2687 | ||
| 2688 | void italic_corrected_node::tprint(troff_output_file *out) | |
| 2689 | { | |
| 2690 | n->tprint(out); | |
| 2691 | out->right(x); | |
| 2692 | } | |
| 2693 | ||
| 2694 | hunits italic_corrected_node::skew() | |
| 2695 | { | |
| 2696 | return n->skew() - x/2; | |
| 2697 | } | |
| 2698 | ||
| 2699 | hunits italic_corrected_node::subscript_correction() | |
| 2700 | { | |
| 2701 | return n->subscript_correction() - x; | |
| 2702 | } | |
| 2703 | ||
| 2704 | void italic_corrected_node::ascii_print(ascii_output_file *out) | |
| 2705 | { | |
| 2706 | n->ascii_print(out); | |
| 2707 | } | |
| 2708 | ||
| 2709 | int italic_corrected_node::ends_sentence() | |
| 2710 | { | |
| 2711 | return n->ends_sentence(); | |
| 2712 | } | |
| 2713 | ||
| 2714 | int italic_corrected_node::overlaps_horizontally() | |
| 2715 | { | |
| 2716 | return n->overlaps_horizontally(); | |
| 2717 | } | |
| 2718 | ||
| 2719 | int italic_corrected_node::overlaps_vertically() | |
| 2720 | { | |
| 2721 | return n->overlaps_vertically(); | |
| 2722 | } | |
| 2723 | ||
| 2724 | node *italic_corrected_node::last_char_node() | |
| 2725 | { | |
| 2726 | return n->last_char_node(); | |
| 2727 | } | |
| 2728 | ||
| 2729 | tfont *italic_corrected_node::get_tfont() | |
| 2730 | { | |
| 2731 | return n->get_tfont(); | |
| 2732 | } | |
| 2733 | ||
| 2734 | hyphenation_type italic_corrected_node::get_hyphenation_type() | |
| 2735 | { | |
| 2736 | return n->get_hyphenation_type(); | |
| 2737 | } | |
| 2738 | ||
| 2739 | node *italic_corrected_node::add_self(node *nd, hyphen_list **p) | |
| 2740 | { | |
| 2741 | nd = n->add_self(nd, p); | |
| 2742 | hunits not_interested; | |
| 2743 | nd = nd->add_italic_correction(¬_interested); | |
| 2744 | n = 0; | |
| 2745 | delete this; | |
| 2746 | return nd; | |
| 2747 | } | |
| 2748 | ||
| 2749 | hyphen_list *italic_corrected_node::get_hyphen_list(hyphen_list *tail, | |
| 2750 | int *count) | |
| 2751 | { | |
| 2752 | return n->get_hyphen_list(tail, count); | |
| 2753 | } | |
| 2754 | ||
| 2755 | int italic_corrected_node::character_type() | |
| 2756 | { | |
| 2757 | return n->character_type(); | |
| 2758 | } | |
| 2759 | ||
| 2760 | class break_char_node : public node { | |
| 2761 | node *ch; | |
| 2762 | char break_code; | |
| 2763 | color *col; | |
| 2764 | public: | |
| 2765 | break_char_node(node *, int, color *, node * = 0); | |
| 465b256c | 2766 | break_char_node(node *, int, color *, statem *, int, node * = 0); |
| 92d0a6a6 JR |
2767 | ~break_char_node(); |
| 2768 | node *copy(); | |
| 2769 | hunits width(); | |
| 2770 | vunits vertical_width(); | |
| 2771 | node *last_char_node(); | |
| 2772 | int character_type(); | |
| 2773 | int ends_sentence(); | |
| 2774 | node *add_self(node *, hyphen_list **); | |
| 2775 | hyphen_list *get_hyphen_list(hyphen_list *, int *); | |
| 2776 | void tprint(troff_output_file *); | |
| 2777 | void zero_width_tprint(troff_output_file *); | |
| 2778 | void ascii_print(ascii_output_file *); | |
| 2779 | void asciify(macro *); | |
| 2780 | hyphenation_type get_hyphenation_type(); | |
| 2781 | int overlaps_vertically(); | |
| 2782 | int overlaps_horizontally(); | |
| 2783 | units size(); | |
| 2784 | tfont *get_tfont(); | |
| 2785 | int same(node *); | |
| 2786 | const char *type(); | |
| 2787 | int force_tprint(); | |
| 465b256c | 2788 | int is_tag(); |
| 92d0a6a6 JR |
2789 | }; |
| 2790 | ||
| 2791 | break_char_node::break_char_node(node *n, int bc, color *c, node *x) | |
| 2792 | : node(x), ch(n), break_code(bc), col(c) | |
| 2793 | { | |
| 2794 | } | |
| 2795 | ||
| 465b256c JR |
2796 | break_char_node::break_char_node(node *n, int bc, color *c, statem *s, |
| 2797 | int pop, node *x) | |
| 2798 | : node(x, s, pop), ch(n), break_code(bc), col(c) | |
| 2799 | { | |
| 2800 | } | |
| 2801 | ||
| 92d0a6a6 JR |
2802 | break_char_node::~break_char_node() |
| 2803 | { | |
| 2804 | delete ch; | |
| 2805 | } | |
| 2806 | ||
| 2807 | node *break_char_node::copy() | |
| 2808 | { | |
| 465b256c JR |
2809 | return new break_char_node(ch->copy(), break_code, col, state, |
| 2810 | div_nest_level); | |
| 92d0a6a6 JR |
2811 | } |
| 2812 | ||
| 2813 | hunits break_char_node::width() | |
| 2814 | { | |
| 2815 | return ch->width(); | |
| 2816 | } | |
| 2817 | ||
| 2818 | vunits break_char_node::vertical_width() | |
| 2819 | { | |
| 2820 | return ch->vertical_width(); | |
| 2821 | } | |
| 2822 | ||
| 2823 | node *break_char_node::last_char_node() | |
| 2824 | { | |
| 2825 | return ch->last_char_node(); | |
| 2826 | } | |
| 2827 | ||
| 2828 | int break_char_node::character_type() | |
| 2829 | { | |
| 2830 | return ch->character_type(); | |
| 2831 | } | |
| 2832 | ||
| 2833 | int break_char_node::ends_sentence() | |
| 2834 | { | |
| 2835 | return ch->ends_sentence(); | |
| 2836 | } | |
| 2837 | ||
| 2838 | node *break_char_node::add_self(node *n, hyphen_list **p) | |
| 2839 | { | |
| 2840 | assert((*p)->hyphenation_code == 0); | |
| 4d3e9548 JL |
2841 | if (break_code & 1) { |
| 2842 | if ((*p)->breakable || break_code & 4) { | |
| 2843 | n = new space_node(H0, col, n); | |
| 2844 | n->freeze_space(); | |
| 2845 | } | |
| 92d0a6a6 JR |
2846 | } |
| 2847 | next = n; | |
| 2848 | n = this; | |
| 4d3e9548 JL |
2849 | if (break_code & 2) { |
| 2850 | if ((*p)->breakable || break_code & 4) { | |
| 2851 | n = new space_node(H0, col, n); | |
| 2852 | n->freeze_space(); | |
| 2853 | } | |
| 92d0a6a6 JR |
2854 | } |
| 2855 | hyphen_list *pp = *p; | |
| 2856 | *p = (*p)->next; | |
| 2857 | delete pp; | |
| 2858 | return n; | |
| 2859 | } | |
| 2860 | ||
| 2861 | hyphen_list *break_char_node::get_hyphen_list(hyphen_list *tail, int *) | |
| 2862 | { | |
| 2863 | return new hyphen_list(0, tail); | |
| 2864 | } | |
| 2865 | ||
| 2866 | hyphenation_type break_char_node::get_hyphenation_type() | |
| 2867 | { | |
| 2868 | return HYPHEN_MIDDLE; | |
| 2869 | } | |
| 2870 | ||
| 2871 | void break_char_node::ascii_print(ascii_output_file *ascii) | |
| 2872 | { | |
| 2873 | ch->ascii_print(ascii); | |
| 2874 | } | |
| 2875 | ||
| 2876 | int break_char_node::overlaps_vertically() | |
| 2877 | { | |
| 2878 | return ch->overlaps_vertically(); | |
| 2879 | } | |
| 2880 | ||
| 2881 | int break_char_node::overlaps_horizontally() | |
| 2882 | { | |
| 2883 | return ch->overlaps_horizontally(); | |
| 2884 | } | |
| 2885 | ||
| 2886 | units break_char_node::size() | |
| 2887 | { | |
| 2888 | return ch->size(); | |
| 2889 | } | |
| 2890 | ||
| 2891 | tfont *break_char_node::get_tfont() | |
| 2892 | { | |
| 2893 | return ch->get_tfont(); | |
| 2894 | } | |
| 2895 | ||
| 2896 | node *extra_size_node::copy() | |
| 2897 | { | |
| 465b256c JR |
2898 | return new extra_size_node(n, state, div_nest_level); |
| 2899 | } | |
| 2900 | ||
| 2901 | extra_size_node::extra_size_node(vunits i, statem *s, int pop) | |
| 2902 | : node(0, s, pop), n(i) | |
| 2903 | { | |
| 2904 | } | |
| 2905 | ||
| 2906 | extra_size_node::extra_size_node(vunits i) | |
| 2907 | : n(i) | |
| 2908 | { | |
| 92d0a6a6 JR |
2909 | } |
| 2910 | ||
| 2911 | node *vertical_size_node::copy() | |
| 2912 | { | |
| 465b256c JR |
2913 | return new vertical_size_node(n, state, div_nest_level); |
| 2914 | } | |
| 2915 | ||
| 2916 | vertical_size_node::vertical_size_node(vunits i, statem *s, int pop) | |
| 2917 | : node(0, s, pop), n(i) | |
| 2918 | { | |
| 2919 | } | |
| 2920 | ||
| 2921 | vertical_size_node::vertical_size_node(vunits i) | |
| 2922 | : n(i) | |
| 2923 | { | |
| 92d0a6a6 JR |
2924 | } |
| 2925 | ||
| 2926 | node *hmotion_node::copy() | |
| 2927 | { | |
| 465b256c | 2928 | return new hmotion_node(n, was_tab, unformat, col, state, div_nest_level); |
| 92d0a6a6 JR |
2929 | } |
| 2930 | ||
| 2931 | node *space_char_hmotion_node::copy() | |
| 2932 | { | |
| 465b256c JR |
2933 | return new space_char_hmotion_node(n, col, state, div_nest_level); |
| 2934 | } | |
| 2935 | ||
| 2936 | vmotion_node::vmotion_node(vunits i, color *c) | |
| 2937 | : n(i), col(c) | |
| 2938 | { | |
| 2939 | } | |
| 2940 | ||
| 2941 | vmotion_node::vmotion_node(vunits i, color *c, statem *s, int pop) | |
| 2942 | : node(0, s, pop), n(i), col(c) | |
| 2943 | { | |
| 92d0a6a6 JR |
2944 | } |
| 2945 | ||
| 2946 | node *vmotion_node::copy() | |
| 2947 | { | |
| 465b256c | 2948 | return new vmotion_node(n, col, state, div_nest_level); |
| 92d0a6a6 JR |
2949 | } |
| 2950 | ||
| 2951 | node *dummy_node::copy() | |
| 2952 | { | |
| 2953 | return new dummy_node; | |
| 2954 | } | |
| 2955 | ||
| 2956 | node *transparent_dummy_node::copy() | |
| 2957 | { | |
| 2958 | return new transparent_dummy_node; | |
| 2959 | } | |
| 2960 | ||
| 2961 | hline_node::~hline_node() | |
| 2962 | { | |
| 2963 | if (n) | |
| 2964 | delete n; | |
| 2965 | } | |
| 2966 | ||
| 465b256c JR |
2967 | hline_node::hline_node(hunits i, node *c, node *nxt) |
| 2968 | : node(nxt), x(i), n(c) | |
| 2969 | { | |
| 2970 | } | |
| 2971 | ||
| 2972 | hline_node::hline_node(hunits i, node *c, statem *s, int pop, node *nxt) | |
| 2973 | : node(nxt, s, pop), x(i), n(c) | |
| 2974 | { | |
| 2975 | } | |
| 2976 | ||
| 92d0a6a6 JR |
2977 | node *hline_node::copy() |
| 2978 | { | |
| 465b256c | 2979 | return new hline_node(x, n ? n->copy() : 0, state, div_nest_level); |
| 92d0a6a6 JR |
2980 | } |
| 2981 | ||
| 2982 | hunits hline_node::width() | |
| 2983 | { | |
| 2984 | return x < H0 ? H0 : x; | |
| 2985 | } | |
| 2986 | ||
| 465b256c JR |
2987 | vline_node::vline_node(vunits i, node *c, node *nxt) |
| 2988 | : node(nxt), x(i), n(c) | |
| 2989 | { | |
| 2990 | } | |
| 2991 | ||
| 2992 | vline_node::vline_node(vunits i, node *c, statem *s, int pop, node *nxt) | |
| 2993 | : node(nxt, s, pop), x(i), n(c) | |
| 2994 | { | |
| 2995 | } | |
| 2996 | ||
| 92d0a6a6 JR |
2997 | vline_node::~vline_node() |
| 2998 | { | |
| 2999 | if (n) | |
| 3000 | delete n; | |
| 3001 | } | |
| 3002 | ||
| 3003 | node *vline_node::copy() | |
| 3004 | { | |
| 465b256c | 3005 | return new vline_node(x, n ? n->copy() : 0, state, div_nest_level); |
| 92d0a6a6 JR |
3006 | } |
| 3007 | ||
| 3008 | hunits vline_node::width() | |
| 3009 | { | |
| 3010 | return n == 0 ? H0 : n->width(); | |
| 3011 | } | |
| 3012 | ||
| 465b256c JR |
3013 | zero_width_node::zero_width_node(node *nd, statem *s, int pop) |
| 3014 | : node(0, s, pop), n(nd) | |
| 3015 | { | |
| 3016 | } | |
| 3017 | ||
| 3018 | zero_width_node::zero_width_node(node *nd) | |
| 3019 | : n(nd) | |
| 92d0a6a6 JR |
3020 | { |
| 3021 | } | |
| 3022 | ||
| 3023 | zero_width_node::~zero_width_node() | |
| 3024 | { | |
| 3025 | delete_node_list(n); | |
| 3026 | } | |
| 3027 | ||
| 3028 | node *zero_width_node::copy() | |
| 3029 | { | |
| 465b256c | 3030 | return new zero_width_node(copy_node_list(n), state, div_nest_level); |
| 92d0a6a6 JR |
3031 | } |
| 3032 | ||
| 3033 | int node_list_character_type(node *p) | |
| 3034 | { | |
| 3035 | int t = 0; | |
| 3036 | for (; p; p = p->next) | |
| 3037 | t |= p->character_type(); | |
| 3038 | return t; | |
| 3039 | } | |
| 3040 | ||
| 3041 | int zero_width_node::character_type() | |
| 3042 | { | |
| 3043 | return node_list_character_type(n); | |
| 3044 | } | |
| 3045 | ||
| 3046 | void node_list_vertical_extent(node *p, vunits *min, vunits *max) | |
| 3047 | { | |
| 3048 | *min = V0; | |
| 3049 | *max = V0; | |
| 3050 | vunits cur_vpos = V0; | |
| 3051 | vunits v1, v2; | |
| 3052 | for (; p; p = p->next) { | |
| 3053 | p->vertical_extent(&v1, &v2); | |
| 3054 | v1 += cur_vpos; | |
| 3055 | if (v1 < *min) | |
| 3056 | *min = v1; | |
| 3057 | v2 += cur_vpos; | |
| 3058 | if (v2 > *max) | |
| 3059 | *max = v2; | |
| 3060 | cur_vpos += p->vertical_width(); | |
| 3061 | } | |
| 3062 | } | |
| 3063 | ||
| 3064 | void zero_width_node::vertical_extent(vunits *min, vunits *max) | |
| 3065 | { | |
| 3066 | node_list_vertical_extent(n, min, max); | |
| 3067 | } | |
| 3068 | ||
| 465b256c JR |
3069 | overstrike_node::overstrike_node() |
| 3070 | : list(0), max_width(H0) | |
| 3071 | { | |
| 3072 | } | |
| 3073 | ||
| 3074 | overstrike_node::overstrike_node(statem *s, int pop) | |
| 3075 | : node(0, s, pop), list(0), max_width(H0) | |
| 92d0a6a6 JR |
3076 | { |
| 3077 | } | |
| 3078 | ||
| 3079 | overstrike_node::~overstrike_node() | |
| 3080 | { | |
| 3081 | delete_node_list(list); | |
| 3082 | } | |
| 3083 | ||
| 3084 | node *overstrike_node::copy() | |
| 3085 | { | |
| 465b256c | 3086 | overstrike_node *on = new overstrike_node(state, div_nest_level); |
| 92d0a6a6 JR |
3087 | for (node *tem = list; tem; tem = tem->next) |
| 3088 | on->overstrike(tem->copy()); | |
| 3089 | return on; | |
| 3090 | } | |
| 3091 | ||
| 3092 | void overstrike_node::overstrike(node *n) | |
| 3093 | { | |
| 3094 | if (n == 0) | |
| 3095 | return; | |
| 3096 | hunits w = n->width(); | |
| 3097 | if (w > max_width) | |
| 3098 | max_width = w; | |
| 3099 | node **p; | |
| 3100 | for (p = &list; *p; p = &(*p)->next) | |
| 3101 | ; | |
| 3102 | n->next = 0; | |
| 3103 | *p = n; | |
| 3104 | } | |
| 3105 | ||
| 3106 | hunits overstrike_node::width() | |
| 3107 | { | |
| 3108 | return max_width; | |
| 3109 | } | |
| 3110 | ||
| 465b256c JR |
3111 | bracket_node::bracket_node() |
| 3112 | : list(0), max_width(H0) | |
| 3113 | { | |
| 3114 | } | |
| 3115 | ||
| 3116 | bracket_node::bracket_node(statem *s, int pop) | |
| 3117 | : node(0, s, pop), list(0), max_width(H0) | |
| 92d0a6a6 JR |
3118 | { |
| 3119 | } | |
| 3120 | ||
| 3121 | bracket_node::~bracket_node() | |
| 3122 | { | |
| 3123 | delete_node_list(list); | |
| 3124 | } | |
| 3125 | ||
| 3126 | node *bracket_node::copy() | |
| 3127 | { | |
| 465b256c | 3128 | bracket_node *on = new bracket_node(state, div_nest_level); |
| 92d0a6a6 JR |
3129 | node *last_node = 0; |
| 3130 | node *tem; | |
| 3131 | if (list) | |
| 3132 | list->last = 0; | |
| 3133 | for (tem = list; tem; tem = tem->next) { | |
| 3134 | if (tem->next) | |
| 3135 | tem->next->last = tem; | |
| 3136 | last_node = tem; | |
| 3137 | } | |
| 3138 | for (tem = last_node; tem; tem = tem->last) | |
| 3139 | on->bracket(tem->copy()); | |
| 3140 | return on; | |
| 3141 | } | |
| 3142 | ||
| 3143 | void bracket_node::bracket(node *n) | |
| 3144 | { | |
| 3145 | if (n == 0) | |
| 3146 | return; | |
| 3147 | hunits w = n->width(); | |
| 3148 | if (w > max_width) | |
| 3149 | max_width = w; | |
| 3150 | n->next = list; | |
| 3151 | list = n; | |
| 3152 | } | |
| 3153 | ||
| 3154 | hunits bracket_node::width() | |
| 3155 | { | |
| 3156 | return max_width; | |
| 3157 | } | |
| 3158 | ||
| 3159 | int node::nspaces() | |
| 3160 | { | |
| 3161 | return 0; | |
| 3162 | } | |
| 3163 | ||
| 3164 | int node::merge_space(hunits, hunits, hunits) | |
| 3165 | { | |
| 3166 | return 0; | |
| 3167 | } | |
| 3168 | ||
| 3169 | #if 0 | |
| 3170 | space_node *space_node::free_list = 0; | |
| 3171 | ||
| 3172 | void *space_node::operator new(size_t n) | |
| 3173 | { | |
| 3174 | assert(n == sizeof(space_node)); | |
| 3175 | if (!free_list) { | |
| 3176 | free_list = (space_node *)new char[sizeof(space_node)*BLOCK]; | |
| 3177 | for (int i = 0; i < BLOCK - 1; i++) | |
| 3178 | free_list[i].next = free_list + i + 1; | |
| 3179 | free_list[BLOCK-1].next = 0; | |
| 3180 | } | |
| 3181 | space_node *p = free_list; | |
| 3182 | free_list = (space_node *)(free_list->next); | |
| 3183 | p->next = 0; | |
| 3184 | return p; | |
| 3185 | } | |
| 3186 | ||
| 3187 | inline void space_node::operator delete(void *p) | |
| 3188 | { | |
| 3189 | if (p) { | |
| 3190 | ((space_node *)p)->next = free_list; | |
| 3191 | free_list = (space_node *)p; | |
| 3192 | } | |
| 3193 | } | |
| 3194 | #endif | |
| 3195 | ||
| 3196 | space_node::space_node(hunits nn, color *c, node *p) | |
| 465b256c | 3197 | : node(p, 0, 0), n(nn), set(0), was_escape_colon(0), col(c) |
| 92d0a6a6 JR |
3198 | { |
| 3199 | } | |
| 3200 | ||
| 465b256c JR |
3201 | space_node::space_node(hunits nn, color *c, statem *s, int pop, node *p) |
| 3202 | : node(p, s, pop), n(nn), set(0), was_escape_colon(0), col(c) | |
| 3203 | { | |
| 3204 | } | |
| 3205 | ||
| 3206 | space_node::space_node(hunits nn, int s, int flag, color *c, statem *st, | |
| 3207 | int pop, node *p) | |
| 3208 | : node(p, st, pop), n(nn), set(s), was_escape_colon(flag), col(c) | |
| 92d0a6a6 JR |
3209 | { |
| 3210 | } | |
| 3211 | ||
| 3212 | #if 0 | |
| 3213 | space_node::~space_node() | |
| 3214 | { | |
| 3215 | } | |
| 3216 | #endif | |
| 3217 | ||
| 3218 | node *space_node::copy() | |
| 3219 | { | |
| 465b256c | 3220 | return new space_node(n, set, was_escape_colon, col, state, div_nest_level); |
| 92d0a6a6 JR |
3221 | } |
| 3222 | ||
| 3223 | int space_node::force_tprint() | |
| 3224 | { | |
| 3225 | return 0; | |
| 3226 | } | |
| 3227 | ||
| 465b256c JR |
3228 | int space_node::is_tag() |
| 3229 | { | |
| 3230 | return 0; | |
| 3231 | } | |
| 3232 | ||
| 92d0a6a6 JR |
3233 | int space_node::nspaces() |
| 3234 | { | |
| 3235 | return set ? 0 : 1; | |
| 3236 | } | |
| 3237 | ||
| 3238 | int space_node::merge_space(hunits h, hunits, hunits) | |
| 3239 | { | |
| 3240 | n += h; | |
| 3241 | return 1; | |
| 3242 | } | |
| 3243 | ||
| 3244 | hunits space_node::width() | |
| 3245 | { | |
| 3246 | return n; | |
| 3247 | } | |
| 3248 | ||
| 3249 | void node::spread_space(int*, hunits*) | |
| 3250 | { | |
| 3251 | } | |
| 3252 | ||
| 3253 | void space_node::spread_space(int *n_spaces, hunits *desired_space) | |
| 3254 | { | |
| 3255 | if (!set) { | |
| 3256 | assert(*n_spaces > 0); | |
| 3257 | if (*n_spaces == 1) { | |
| 3258 | n += *desired_space; | |
| 3259 | *desired_space = H0; | |
| 3260 | } | |
| 3261 | else { | |
| 3262 | hunits extra = *desired_space / *n_spaces; | |
| 3263 | *desired_space -= extra; | |
| 3264 | n += extra; | |
| 3265 | } | |
| 3266 | *n_spaces -= 1; | |
| 3267 | set = 1; | |
| 3268 | } | |
| 3269 | } | |
| 3270 | ||
| 3271 | void node::freeze_space() | |
| 3272 | { | |
| 3273 | } | |
| 3274 | ||
| 3275 | void space_node::freeze_space() | |
| 3276 | { | |
| 3277 | set = 1; | |
| 3278 | } | |
| 3279 | ||
| 3280 | void node::is_escape_colon() | |
| 3281 | { | |
| 3282 | } | |
| 3283 | ||
| 3284 | void space_node::is_escape_colon() | |
| 3285 | { | |
| 3286 | was_escape_colon = 1; | |
| 3287 | } | |
| 3288 | ||
| 465b256c JR |
3289 | diverted_space_node::diverted_space_node(vunits d, statem *s, int pop, |
| 3290 | node *p) | |
| 3291 | : node(p, s, pop), n(d) | |
| 3292 | { | |
| 3293 | } | |
| 3294 | ||
| 92d0a6a6 JR |
3295 | diverted_space_node::diverted_space_node(vunits d, node *p) |
| 3296 | : node(p), n(d) | |
| 3297 | { | |
| 3298 | } | |
| 3299 | ||
| 3300 | node *diverted_space_node::copy() | |
| 3301 | { | |
| 465b256c JR |
3302 | return new diverted_space_node(n, state, div_nest_level); |
| 3303 | } | |
| 3304 | ||
| 3305 | diverted_copy_file_node::diverted_copy_file_node(symbol s, statem *st, | |
| 3306 | int pop, node *p) | |
| 3307 | : node(p, st, pop), filename(s) | |
| 3308 | { | |
| 92d0a6a6 JR |
3309 | } |
| 3310 | ||
| 3311 | diverted_copy_file_node::diverted_copy_file_node(symbol s, node *p) | |
| 3312 | : node(p), filename(s) | |
| 3313 | { | |
| 3314 | } | |
| 3315 | ||
| 3316 | node *diverted_copy_file_node::copy() | |
| 3317 | { | |
| 465b256c | 3318 | return new diverted_copy_file_node(filename, state, div_nest_level); |
| 92d0a6a6 JR |
3319 | } |
| 3320 | ||
| 3321 | int node::ends_sentence() | |
| 3322 | { | |
| 3323 | return 0; | |
| 3324 | } | |
| 3325 | ||
| 3326 | int kern_pair_node::ends_sentence() | |
| 3327 | { | |
| 3328 | switch (n2->ends_sentence()) { | |
| 3329 | case 0: | |
| 3330 | return 0; | |
| 3331 | case 1: | |
| 3332 | return 1; | |
| 3333 | case 2: | |
| 3334 | break; | |
| 3335 | default: | |
| 3336 | assert(0); | |
| 3337 | } | |
| 3338 | return n1->ends_sentence(); | |
| 3339 | } | |
| 3340 | ||
| 3341 | int node_list_ends_sentence(node *n) | |
| 3342 | { | |
| 3343 | for (; n != 0; n = n->next) | |
| 3344 | switch (n->ends_sentence()) { | |
| 3345 | case 0: | |
| 3346 | return 0; | |
| 3347 | case 1: | |
| 3348 | return 1; | |
| 3349 | case 2: | |
| 3350 | break; | |
| 3351 | default: | |
| 3352 | assert(0); | |
| 3353 | } | |
| 3354 | return 2; | |
| 3355 | } | |
| 3356 | ||
| 3357 | int dbreak_node::ends_sentence() | |
| 3358 | { | |
| 3359 | return node_list_ends_sentence(none); | |
| 3360 | } | |
| 3361 | ||
| 3362 | int node::overlaps_horizontally() | |
| 3363 | { | |
| 3364 | return 0; | |
| 3365 | } | |
| 3366 | ||
| 3367 | int node::overlaps_vertically() | |
| 3368 | { | |
| 3369 | return 0; | |
| 3370 | } | |
| 3371 | ||
| 3372 | int node::discardable() | |
| 3373 | { | |
| 3374 | return 0; | |
| 3375 | } | |
| 3376 | ||
| 3377 | int space_node::discardable() | |
| 3378 | { | |
| 3379 | return set ? 0 : 1; | |
| 3380 | } | |
| 3381 | ||
| 3382 | vunits node::vertical_width() | |
| 3383 | { | |
| 3384 | return V0; | |
| 3385 | } | |
| 3386 | ||
| 3387 | vunits vline_node::vertical_width() | |
| 3388 | { | |
| 3389 | return x; | |
| 3390 | } | |
| 3391 | ||
| 3392 | vunits vmotion_node::vertical_width() | |
| 3393 | { | |
| 3394 | return n; | |
| 3395 | } | |
| 3396 | ||
| 3397 | int node::set_unformat_flag() | |
| 3398 | { | |
| 3399 | return 1; | |
| 3400 | } | |
| 3401 | ||
| 3402 | int node::character_type() | |
| 3403 | { | |
| 3404 | return 0; | |
| 3405 | } | |
| 3406 | ||
| 3407 | hunits node::subscript_correction() | |
| 3408 | { | |
| 3409 | return H0; | |
| 3410 | } | |
| 3411 | ||
| 3412 | hunits node::italic_correction() | |
| 3413 | { | |
| 3414 | return H0; | |
| 3415 | } | |
| 3416 | ||
| 3417 | hunits node::left_italic_correction() | |
| 3418 | { | |
| 3419 | return H0; | |
| 3420 | } | |
| 3421 | ||
| 3422 | hunits node::skew() | |
| 3423 | { | |
| 3424 | return H0; | |
| 3425 | } | |
| 3426 | ||
| 3427 | /* vertical_extent methods */ | |
| 3428 | ||
| 3429 | void node::vertical_extent(vunits *min, vunits *max) | |
| 3430 | { | |
| 3431 | vunits v = vertical_width(); | |
| 3432 | if (v < V0) { | |
| 3433 | *min = v; | |
| 3434 | *max = V0; | |
| 3435 | } | |
| 3436 | else { | |
| 3437 | *max = v; | |
| 3438 | *min = V0; | |
| 3439 | } | |
| 3440 | } | |
| 3441 | ||
| 3442 | void vline_node::vertical_extent(vunits *min, vunits *max) | |
| 3443 | { | |
| 3444 | if (n == 0) | |
| 3445 | node::vertical_extent(min, max); | |
| 3446 | else { | |
| 3447 | vunits cmin, cmax; | |
| 3448 | n->vertical_extent(&cmin, &cmax); | |
| 3449 | vunits h = n->size(); | |
| 3450 | if (x < V0) { | |
| 3451 | if (-x < h) { | |
| 3452 | *min = x; | |
| 3453 | *max = V0; | |
| 3454 | } | |
| 3455 | else { | |
| 3456 | // we print the first character and then move up, so | |
| 3457 | *max = cmax; | |
| 3458 | // we print the last character and then move up h | |
| 3459 | *min = cmin + h; | |
| 3460 | if (*min > V0) | |
| 3461 | *min = V0; | |
| 3462 | *min += x; | |
| 3463 | } | |
| 3464 | } | |
| 3465 | else { | |
| 3466 | if (x < h) { | |
| 3467 | *max = x; | |
| 3468 | *min = V0; | |
| 3469 | } | |
| 3470 | else { | |
| 3471 | // we move down by h and then print the first character, so | |
| 3472 | *min = cmin + h; | |
| 3473 | if (*min > V0) | |
| 3474 | *min = V0; | |
| 3475 | *max = x + cmax; | |
| 3476 | } | |
| 3477 | } | |
| 3478 | } | |
| 3479 | } | |
| 3480 | ||
| 3481 | /* ascii_print methods */ | |
| 3482 | ||
| 3483 | static void ascii_print_reverse_node_list(ascii_output_file *ascii, node *n) | |
| 3484 | { | |
| 3485 | if (n == 0) | |
| 3486 | return; | |
| 3487 | ascii_print_reverse_node_list(ascii, n->next); | |
| 3488 | n->ascii_print(ascii); | |
| 3489 | } | |
| 3490 | ||
| 3491 | void dbreak_node::ascii_print(ascii_output_file *ascii) | |
| 3492 | { | |
| 3493 | ascii_print_reverse_node_list(ascii, none); | |
| 3494 | } | |
| 3495 | ||
| 3496 | void kern_pair_node::ascii_print(ascii_output_file *ascii) | |
| 3497 | { | |
| 3498 | n1->ascii_print(ascii); | |
| 3499 | n2->ascii_print(ascii); | |
| 3500 | } | |
| 3501 | ||
| 3502 | void node::ascii_print(ascii_output_file *) | |
| 3503 | { | |
| 3504 | } | |
| 3505 | ||
| 3506 | void space_node::ascii_print(ascii_output_file *ascii) | |
| 3507 | { | |
| 3508 | if (!n.is_zero()) | |
| 3509 | ascii->outc(' '); | |
| 3510 | } | |
| 3511 | ||
| 3512 | void hmotion_node::ascii_print(ascii_output_file *ascii) | |
| 3513 | { | |
| 3514 | // this is pretty arbitrary | |
| 3515 | if (n >= points_to_units(2)) | |
| 3516 | ascii->outc(' '); | |
| 3517 | } | |
| 3518 | ||
| 3519 | void space_char_hmotion_node::ascii_print(ascii_output_file *ascii) | |
| 3520 | { | |
| 3521 | ascii->outc(' '); | |
| 3522 | } | |
| 3523 | ||
| 3524 | /* asciify methods */ | |
| 3525 | ||
| 3526 | void node::asciify(macro *m) | |
| 3527 | { | |
| 3528 | m->append(this); | |
| 3529 | } | |
| 3530 | ||
| 3531 | void glyph_node::asciify(macro *m) | |
| 3532 | { | |
| 3533 | unsigned char c = ci->get_asciify_code(); | |
| 3534 | if (c == 0) | |
| 3535 | c = ci->get_ascii_code(); | |
| 3536 | if (c != 0) { | |
| 3537 | m->append(c); | |
| 3538 | delete this; | |
| 3539 | } | |
| 3540 | else | |
| 3541 | m->append(this); | |
| 3542 | } | |
| 3543 | ||
| 3544 | void kern_pair_node::asciify(macro *m) | |
| 3545 | { | |
| 3546 | n1->asciify(m); | |
| 3547 | n2->asciify(m); | |
| 3548 | n1 = n2 = 0; | |
| 3549 | delete this; | |
| 3550 | } | |
| 3551 | ||
| 3552 | static void asciify_reverse_node_list(macro *m, node *n) | |
| 3553 | { | |
| 3554 | if (n == 0) | |
| 3555 | return; | |
| 3556 | asciify_reverse_node_list(m, n->next); | |
| 3557 | n->asciify(m); | |
| 3558 | } | |
| 3559 | ||
| 3560 | void dbreak_node::asciify(macro *m) | |
| 3561 | { | |
| 3562 | asciify_reverse_node_list(m, none); | |
| 3563 | none = 0; | |
| 3564 | delete this; | |
| 3565 | } | |
| 3566 | ||
| 3567 | void ligature_node::asciify(macro *m) | |
| 3568 | { | |
| 3569 | n1->asciify(m); | |
| 3570 | n2->asciify(m); | |
| 3571 | n1 = n2 = 0; | |
| 3572 | delete this; | |
| 3573 | } | |
| 3574 | ||
| 3575 | void break_char_node::asciify(macro *m) | |
| 3576 | { | |
| 3577 | ch->asciify(m); | |
| 3578 | ch = 0; | |
| 3579 | delete this; | |
| 3580 | } | |
| 3581 | ||
| 3582 | void italic_corrected_node::asciify(macro *m) | |
| 3583 | { | |
| 3584 | n->asciify(m); | |
| 3585 | n = 0; | |
| 3586 | delete this; | |
| 3587 | } | |
| 3588 | ||
| 3589 | void left_italic_corrected_node::asciify(macro *m) | |
| 3590 | { | |
| 3591 | if (n) { | |
| 3592 | n->asciify(m); | |
| 3593 | n = 0; | |
| 3594 | } | |
| 3595 | delete this; | |
| 3596 | } | |
| 3597 | ||
| 3598 | void hmotion_node::asciify(macro *m) | |
| 3599 | { | |
| 3600 | if (was_tab) { | |
| 3601 | m->append('\t'); | |
| 3602 | delete this; | |
| 3603 | } | |
| 3604 | else | |
| 3605 | m->append(this); | |
| 3606 | } | |
| 3607 | ||
| 3608 | space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c, | |
| 465b256c | 3609 | statem *s, int pop, |
| 92d0a6a6 | 3610 | node *nxt) |
| 465b256c JR |
3611 | : hmotion_node(i, c, s, pop, nxt) |
| 3612 | { | |
| 3613 | } | |
| 3614 | ||
| 3615 | space_char_hmotion_node::space_char_hmotion_node(hunits i, color *c, | |
| 3616 | node *nxt) | |
| 3617 | : hmotion_node(i, c, 0, 0, nxt) | |
| 92d0a6a6 JR |
3618 | { |
| 3619 | } | |
| 3620 | ||
| 3621 | void space_char_hmotion_node::asciify(macro *m) | |
| 3622 | { | |
| 3623 | m->append(ESCAPE_SPACE); | |
| 3624 | delete this; | |
| 3625 | } | |
| 3626 | ||
| 3627 | void space_node::asciify(macro *m) | |
| 3628 | { | |
| 3629 | if (was_escape_colon) { | |
| 3630 | m->append(ESCAPE_COLON); | |
| 3631 | delete this; | |
| 3632 | } | |
| 3633 | else | |
| 3634 | m->append(this); | |
| 3635 | } | |
| 3636 | ||
| 3637 | void word_space_node::asciify(macro *m) | |
| 3638 | { | |
| 3639 | for (width_list *w = orig_width; w; w = w->next) | |
| 3640 | m->append(' '); | |
| 3641 | delete this; | |
| 3642 | } | |
| 3643 | ||
| 3644 | void unbreakable_space_node::asciify(macro *m) | |
| 3645 | { | |
| 3646 | m->append(ESCAPE_TILDE); | |
| 3647 | delete this; | |
| 3648 | } | |
| 3649 | ||
| 3650 | void line_start_node::asciify(macro *) | |
| 3651 | { | |
| 3652 | delete this; | |
| 3653 | } | |
| 3654 | ||
| 3655 | void vertical_size_node::asciify(macro *) | |
| 3656 | { | |
| 3657 | delete this; | |
| 3658 | } | |
| 3659 | ||
| 3660 | breakpoint *node::get_breakpoints(hunits /*width*/, int /*nspaces*/, | |
| 3661 | breakpoint *rest, int /*is_inner*/) | |
| 3662 | { | |
| 3663 | return rest; | |
| 3664 | } | |
| 3665 | ||
| 3666 | int node::nbreaks() | |
| 3667 | { | |
| 3668 | return 0; | |
| 3669 | } | |
| 3670 | ||
| 3671 | breakpoint *space_node::get_breakpoints(hunits wd, int ns, | |
| 3672 | breakpoint *rest, int is_inner) | |
| 3673 | { | |
| 3674 | if (next && next->discardable()) | |
| 3675 | return rest; | |
| 3676 | breakpoint *bp = new breakpoint; | |
| 3677 | bp->next = rest; | |
| 3678 | bp->width = wd; | |
| 3679 | bp->nspaces = ns; | |
| 3680 | bp->hyphenated = 0; | |
| 3681 | if (is_inner) { | |
| 3682 | assert(rest != 0); | |
| 3683 | bp->index = rest->index + 1; | |
| 3684 | bp->nd = rest->nd; | |
| 3685 | } | |
| 3686 | else { | |
| 3687 | bp->nd = this; | |
| 3688 | bp->index = 0; | |
| 3689 | } | |
| 3690 | return bp; | |
| 3691 | } | |
| 3692 | ||
| 3693 | int space_node::nbreaks() | |
| 3694 | { | |
| 3695 | if (next && next->discardable()) | |
| 3696 | return 0; | |
| 3697 | else | |
| 3698 | return 1; | |
| 3699 | } | |
| 3700 | ||
| 3701 | static breakpoint *node_list_get_breakpoints(node *p, hunits *widthp, | |
| 3702 | int ns, breakpoint *rest) | |
| 3703 | { | |
| 3704 | if (p != 0) { | |
| 3705 | rest = p->get_breakpoints(*widthp, | |
| 3706 | ns, | |
| 3707 | node_list_get_breakpoints(p->next, widthp, ns, | |
| 3708 | rest), | |
| 3709 | 1); | |
| 3710 | *widthp += p->width(); | |
| 3711 | } | |
| 3712 | return rest; | |
| 3713 | } | |
| 3714 | ||
| 3715 | breakpoint *dbreak_node::get_breakpoints(hunits wd, int ns, | |
| 3716 | breakpoint *rest, int is_inner) | |
| 3717 | { | |
| 3718 | breakpoint *bp = new breakpoint; | |
| 3719 | bp->next = rest; | |
| 3720 | bp->width = wd; | |
| 3721 | for (node *tem = pre; tem != 0; tem = tem->next) | |
| 3722 | bp->width += tem->width(); | |
| 3723 | bp->nspaces = ns; | |
| 3724 | bp->hyphenated = 1; | |
| 3725 | if (is_inner) { | |
| 3726 | assert(rest != 0); | |
| 3727 | bp->index = rest->index + 1; | |
| 3728 | bp->nd = rest->nd; | |
| 3729 | } | |
| 3730 | else { | |
| 3731 | bp->nd = this; | |
| 3732 | bp->index = 0; | |
| 3733 | } | |
| 3734 | return node_list_get_breakpoints(none, &wd, ns, bp); | |
| 3735 | } | |
| 3736 | ||
| 3737 | int dbreak_node::nbreaks() | |
| 3738 | { | |
| 3739 | int i = 1; | |
| 3740 | for (node *tem = none; tem != 0; tem = tem->next) | |
| 3741 | i += tem->nbreaks(); | |
| 3742 | return i; | |
| 3743 | } | |
| 3744 | ||
| 3745 | void node::split(int /*where*/, node ** /*prep*/, node ** /*postp*/) | |
| 3746 | { | |
| 3747 | assert(0); | |
| 3748 | } | |
| 3749 | ||
| 3750 | void space_node::split(int where, node **pre, node **post) | |
| 3751 | { | |
| 3752 | assert(where == 0); | |
| 3753 | *pre = next; | |
| 3754 | *post = 0; | |
| 3755 | delete this; | |
| 3756 | } | |
| 3757 | ||
| 3758 | static void node_list_split(node *p, int *wherep, node **prep, node **postp) | |
| 3759 | { | |
| 3760 | if (p == 0) | |
| 3761 | return; | |
| 3762 | int nb = p->nbreaks(); | |
| 3763 | node_list_split(p->next, wherep, prep, postp); | |
| 3764 | if (*wherep < 0) { | |
| 3765 | p->next = *postp; | |
| 3766 | *postp = p; | |
| 3767 | } | |
| 3768 | else if (*wherep < nb) { | |
| 3769 | p->next = *prep; | |
| 3770 | p->split(*wherep, prep, postp); | |
| 3771 | } | |
| 3772 | else { | |
| 3773 | p->next = *prep; | |
| 3774 | *prep = p; | |
| 3775 | } | |
| 3776 | *wherep -= nb; | |
| 3777 | } | |
| 3778 | ||
| 3779 | void dbreak_node::split(int where, node **prep, node **postp) | |
| 3780 | { | |
| 3781 | assert(where >= 0); | |
| 3782 | if (where == 0) { | |
| 3783 | *postp = post; | |
| 3784 | post = 0; | |
| 3785 | if (pre == 0) | |
| 3786 | *prep = next; | |
| 3787 | else { | |
| 3788 | node *tem; | |
| 3789 | for (tem = pre; tem->next != 0; tem = tem->next) | |
| 3790 | ; | |
| 3791 | tem->next = next; | |
| 3792 | *prep = pre; | |
| 3793 | } | |
| 3794 | pre = 0; | |
| 3795 | delete this; | |
| 3796 | } | |
| 3797 | else { | |
| 3798 | *prep = next; | |
| 3799 | where -= 1; | |
| 3800 | node_list_split(none, &where, prep, postp); | |
| 3801 | none = 0; | |
| 3802 | delete this; | |
| 3803 | } | |
| 3804 | } | |
| 3805 | ||
| 3806 | hyphenation_type node::get_hyphenation_type() | |
| 3807 | { | |
| 3808 | return HYPHEN_BOUNDARY; | |
| 3809 | } | |
| 3810 | ||
| 3811 | hyphenation_type dbreak_node::get_hyphenation_type() | |
| 3812 | { | |
| 3813 | return HYPHEN_INHIBIT; | |
| 3814 | } | |
| 3815 | ||
| 3816 | hyphenation_type kern_pair_node::get_hyphenation_type() | |
| 3817 | { | |
| 3818 | return HYPHEN_MIDDLE; | |
| 3819 | } | |
| 3820 | ||
| 3821 | hyphenation_type dummy_node::get_hyphenation_type() | |
| 3822 | { | |
| 3823 | return HYPHEN_MIDDLE; | |
| 3824 | } | |
| 3825 | ||
| 3826 | hyphenation_type transparent_dummy_node::get_hyphenation_type() | |
| 3827 | { | |
| 3828 | return HYPHEN_MIDDLE; | |
| 3829 | } | |
| 3830 | ||
| 3831 | hyphenation_type hmotion_node::get_hyphenation_type() | |
| 3832 | { | |
| 3833 | return HYPHEN_MIDDLE; | |
| 3834 | } | |
| 3835 | ||
| 3836 | hyphenation_type space_char_hmotion_node::get_hyphenation_type() | |
| 3837 | { | |
| 3838 | return HYPHEN_MIDDLE; | |
| 3839 | } | |
| 3840 | ||
| 3841 | hyphenation_type overstrike_node::get_hyphenation_type() | |
| 3842 | { | |
| 3843 | return HYPHEN_MIDDLE; | |
| 3844 | } | |
| 3845 | ||
| 3846 | hyphenation_type space_node::get_hyphenation_type() | |
| 3847 | { | |
| 3848 | if (was_escape_colon) | |
| 3849 | return HYPHEN_MIDDLE; | |
| 3850 | return HYPHEN_BOUNDARY; | |
| 3851 | } | |
| 3852 | ||
| 3853 | hyphenation_type unbreakable_space_node::get_hyphenation_type() | |
| 3854 | { | |
| 3855 | return HYPHEN_MIDDLE; | |
| 3856 | } | |
| 3857 | ||
| 3858 | int node::interpret(macro *) | |
| 3859 | { | |
| 3860 | return 0; | |
| 3861 | } | |
| 3862 | ||
| 3863 | special_node::special_node(const macro &m, int n) | |
| 3864 | : mac(m), no_init_string(n) | |
| 3865 | { | |
| 3866 | font_size fs = curenv->get_font_size(); | |
| 3867 | int char_height = curenv->get_char_height(); | |
| 3868 | int char_slant = curenv->get_char_slant(); | |
| 3869 | int fontno = env_definite_font(curenv); | |
| 3870 | tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fontno); | |
| 3871 | if (curenv->is_composite()) | |
| 3872 | tf = tf->get_plain(); | |
| 3873 | gcol = curenv->get_glyph_color(); | |
| 3874 | fcol = curenv->get_fill_color(); | |
| 465b256c | 3875 | is_special = 1; |
| 92d0a6a6 JR |
3876 | } |
| 3877 | ||
| 3878 | special_node::special_node(const macro &m, tfont *t, | |
| 465b256c JR |
3879 | color *gc, color *fc, |
| 3880 | statem *s, int pop, | |
| 3881 | int n) | |
| 3882 | : node(0, s, pop), mac(m), tf(t), gcol(gc), fcol(fc), no_init_string(n) | |
| 92d0a6a6 | 3883 | { |
| 465b256c | 3884 | is_special = 1; |
| 92d0a6a6 JR |
3885 | } |
| 3886 | ||
| 3887 | int special_node::same(node *n) | |
| 3888 | { | |
| 3889 | return mac == ((special_node *)n)->mac | |
| 3890 | && tf == ((special_node *)n)->tf | |
| 3891 | && gcol == ((special_node *)n)->gcol | |
| 3892 | && fcol == ((special_node *)n)->fcol | |
| 3893 | && no_init_string == ((special_node *)n)->no_init_string; | |
| 3894 | } | |
| 3895 | ||
| 3896 | const char *special_node::type() | |
| 3897 | { | |
| 3898 | return "special_node"; | |
| 3899 | } | |
| 3900 | ||
| 3901 | int special_node::ends_sentence() | |
| 3902 | { | |
| 3903 | return 2; | |
| 3904 | } | |
| 3905 | ||
| 3906 | int special_node::force_tprint() | |
| 3907 | { | |
| 3908 | return 0; | |
| 3909 | } | |
| 3910 | ||
| 465b256c JR |
3911 | int special_node::is_tag() |
| 3912 | { | |
| 3913 | return 0; | |
| 3914 | } | |
| 3915 | ||
| 92d0a6a6 JR |
3916 | node *special_node::copy() |
| 3917 | { | |
| 465b256c JR |
3918 | return new special_node(mac, tf, gcol, fcol, state, div_nest_level, |
| 3919 | no_init_string); | |
| 92d0a6a6 JR |
3920 | } |
| 3921 | ||
| 3922 | void special_node::tprint_start(troff_output_file *out) | |
| 3923 | { | |
| 3924 | out->start_special(tf, gcol, fcol, no_init_string); | |
| 3925 | } | |
| 3926 | ||
| 3927 | void special_node::tprint_char(troff_output_file *out, unsigned char c) | |
| 3928 | { | |
| 3929 | out->special_char(c); | |
| 3930 | } | |
| 3931 | ||
| 3932 | void special_node::tprint_end(troff_output_file *out) | |
| 3933 | { | |
| 3934 | out->end_special(); | |
| 3935 | } | |
| 3936 | ||
| 3937 | tfont *special_node::get_tfont() | |
| 3938 | { | |
| 3939 | return tf; | |
| 3940 | } | |
| 3941 | ||
| 3942 | /* suppress_node */ | |
| 3943 | ||
| 3944 | suppress_node::suppress_node(int on_or_off, int issue_limits) | |
| 465b256c JR |
3945 | : is_on(on_or_off), emit_limits(issue_limits), filename(0), position(0), |
| 3946 | image_id(0) | |
| 92d0a6a6 JR |
3947 | { |
| 3948 | } | |
| 3949 | ||
| 3950 | suppress_node::suppress_node(symbol f, char p, int id) | |
| 3951 | : is_on(2), emit_limits(0), filename(f), position(p), image_id(id) | |
| 3952 | { | |
| 465b256c | 3953 | is_special = 1; |
| 92d0a6a6 JR |
3954 | } |
| 3955 | ||
| 3956 | suppress_node::suppress_node(int issue_limits, int on_or_off, | |
| 465b256c JR |
3957 | symbol f, char p, int id, |
| 3958 | statem *s, int pop) | |
| 3959 | : node(0, s, pop), is_on(on_or_off), emit_limits(issue_limits), filename(f), | |
| 3960 | position(p), image_id(id) | |
| 92d0a6a6 JR |
3961 | { |
| 3962 | } | |
| 3963 | ||
| 3964 | int suppress_node::same(node *n) | |
| 3965 | { | |
| 3966 | return ((is_on == ((suppress_node *)n)->is_on) | |
| 3967 | && (emit_limits == ((suppress_node *)n)->emit_limits) | |
| 3968 | && (filename == ((suppress_node *)n)->filename) | |
| 3969 | && (position == ((suppress_node *)n)->position) | |
| 3970 | && (image_id == ((suppress_node *)n)->image_id)); | |
| 3971 | } | |
| 3972 | ||
| 3973 | const char *suppress_node::type() | |
| 3974 | { | |
| 3975 | return "suppress_node"; | |
| 3976 | } | |
| 3977 | ||
| 3978 | node *suppress_node::copy() | |
| 3979 | { | |
| 465b256c JR |
3980 | return new suppress_node(emit_limits, is_on, filename, position, image_id, |
| 3981 | state, div_nest_level); | |
| 3982 | } | |
| 3983 | ||
| 3984 | /* tag_node */ | |
| 3985 | ||
| 3986 | tag_node::tag_node() | |
| 3987 | : delayed(0) | |
| 3988 | { | |
| 3989 | is_special = 1; | |
| 3990 | } | |
| 3991 | ||
| 3992 | tag_node::tag_node(string s, int delay) | |
| 3993 | : tag_string(s), delayed(delay) | |
| 3994 | { | |
| 3995 | is_special = !delay; | |
| 3996 | } | |
| 3997 | ||
| 3998 | tag_node::tag_node(string s, statem *st, int pop, int delay) | |
| 3999 | : node(0, st, pop), tag_string(s), delayed(delay) | |
| 4000 | { | |
| 4001 | is_special = !delay; | |
| 4002 | } | |
| 4003 | ||
| 4004 | node *tag_node::copy() | |
| 4005 | { | |
| 4006 | return new tag_node(tag_string, state, div_nest_level, delayed); | |
| 4007 | } | |
| 4008 | ||
| 4009 | void tag_node::tprint(troff_output_file *out) | |
| 4010 | { | |
| 4011 | if (delayed) | |
| 4012 | out->add_to_tag_list(tag_string); | |
| 4013 | else | |
| 4014 | out->state.add_tag(out->fp, tag_string); | |
| 4015 | } | |
| 4016 | ||
| 4017 | int tag_node::same(node *nd) | |
| 4018 | { | |
| 4019 | return tag_string == ((tag_node *)nd)->tag_string | |
| 4020 | && delayed == ((tag_node *)nd)->delayed; | |
| 4021 | } | |
| 4022 | ||
| 4023 | const char *tag_node::type() | |
| 4024 | { | |
| 4025 | return "tag_node"; | |
| 4026 | } | |
| 4027 | ||
| 4028 | int tag_node::force_tprint() | |
| 4029 | { | |
| 4030 | return !delayed; | |
| 4031 | } | |
| 4032 | ||
| 4033 | int tag_node::is_tag() | |
| 4034 | { | |
| 4035 | return !delayed; | |
| 4036 | } | |
| 4037 | ||
| 4038 | int tag_node::ends_sentence() | |
| 4039 | { | |
| 4040 | return 2; | |
| 92d0a6a6 JR |
4041 | } |
| 4042 | ||
| 4043 | int get_reg_int(const char *p) | |
| 4044 | { | |
| 4045 | reg *r = (reg *)number_reg_dictionary.lookup(p); | |
| 4046 | units prev_value; | |
| 4047 | if (r && (r->get_value(&prev_value))) | |
| 4048 | return (int)prev_value; | |
| 4049 | else | |
| 4050 | warning(WARN_REG, "number register `%1' not defined", p); | |
| 4051 | return 0; | |
| 4052 | } | |
| 4053 | ||
| 4054 | const char *get_reg_str(const char *p) | |
| 4055 | { | |
| 4056 | reg *r = (reg *)number_reg_dictionary.lookup(p); | |
| 4057 | if (r) | |
| 4058 | return r->get_string(); | |
| 4059 | else | |
| 4060 | warning(WARN_REG, "register `%1' not defined", p); | |
| 4061 | return 0; | |
| 4062 | } | |
| 4063 | ||
| 4064 | void suppress_node::put(troff_output_file *out, const char *s) | |
| 4065 | { | |
| 4066 | int i = 0; | |
| 4067 | while (s[i] != (char)0) { | |
| 4068 | out->special_char(s[i]); | |
| 4069 | i++; | |
| 4070 | } | |
| 4071 | } | |
| 4072 | ||
| 4073 | /* | |
| 4074 | * We need to remember the start of the image and its name. | |
| 4075 | */ | |
| 4076 | ||
| 4077 | static char last_position = 0; | |
| 4078 | static const char *last_image_filename = 0; | |
| 4079 | static int last_image_id = 0; | |
| 4080 | ||
| 4081 | inline int min(int a, int b) | |
| 4082 | { | |
| 4083 | return a < b ? a : b; | |
| 4084 | } | |
| 4085 | ||
| 4086 | /* | |
| 4087 | * tprint - if (is_on == 2) | |
| 4088 | * remember current position (l, r, c, i) and filename | |
| 4089 | * else | |
| 4090 | * if (emit_limits) | |
| 4091 | * if (html) | |
| 4092 | * emit image tag | |
| 4093 | * else | |
| 4094 | * emit postscript bounds for image | |
| 4095 | * else | |
| 4096 | * if (suppress boolean differs from current state) | |
| 4097 | * alter state | |
| 4098 | * reset registers | |
| 4099 | * record current page | |
| 4100 | * set low water mark. | |
| 4101 | */ | |
| 4102 | ||
| 4103 | void suppress_node::tprint(troff_output_file *out) | |
| 4104 | { | |
| 4105 | int current_page = topdiv->get_page_number(); | |
| 4106 | // firstly check to see whether this suppress node contains | |
| 4107 | // an image filename & position. | |
| 4108 | if (is_on == 2) { | |
| 4109 | // remember position and filename | |
| 4110 | last_position = position; | |
| 4111 | char *tem = (char *)last_image_filename; | |
| 4112 | last_image_filename = strsave(filename.contents()); | |
| 4113 | if (tem) | |
| 4114 | a_delete tem; | |
| 4115 | last_image_id = image_id; | |
| 4116 | // printf("start of image and page = %d\n", current_page); | |
| 4117 | } | |
| 4118 | else { | |
| 4119 | // now check whether the suppress node requires us to issue limits. | |
| 4120 | if (emit_limits) { | |
| 4121 | char name[8192]; | |
| 4122 | // remember that the filename will contain a %d in which the | |
| 4123 | // last_image_id is placed | |
| 4124 | if (last_image_filename == (char *) 0) | |
| 4125 | *name = '\0'; | |
| 4126 | else | |
| 4127 | sprintf(name, last_image_filename, last_image_id); | |
| 4128 | if (is_html) { | |
| 4129 | switch (last_position) { | |
| 4130 | case 'c': | |
| 4131 | out->start_special(); | |
| 465b256c | 4132 | put(out, "devtag:.centered-image"); |
| 92d0a6a6 JR |
4133 | break; |
| 4134 | case 'r': | |
| 4135 | out->start_special(); | |
| 465b256c | 4136 | put(out, "devtag:.right-image"); |
| 92d0a6a6 JR |
4137 | break; |
| 4138 | case 'l': | |
| 4139 | out->start_special(); | |
| 465b256c | 4140 | put(out, "devtag:.left-image"); |
| 92d0a6a6 JR |
4141 | break; |
| 4142 | case 'i': | |
| 4143 | ; | |
| 4144 | default: | |
| 4145 | ; | |
| 4146 | } | |
| 4147 | out->end_special(); | |
| 4148 | out->start_special(); | |
| 465b256c | 4149 | put(out, "devtag:.auto-image "); |
| 92d0a6a6 JR |
4150 | put(out, name); |
| 4151 | out->end_special(); | |
| 4152 | } | |
| 4153 | else { | |
| 4154 | // postscript (or other device) | |
| 4155 | if (suppress_start_page > 0 && current_page != suppress_start_page) | |
| 4156 | error("suppression limit registers span more than one page;\n" | |
| 4d3e9548 | 4157 | "image description %1 will be wrong", image_no); |
| 92d0a6a6 JR |
4158 | // if (topdiv->get_page_number() != suppress_start_page) |
| 4159 | // fprintf(stderr, "end of image and topdiv page = %d and suppress_start_page = %d\n", | |
| 4160 | // topdiv->get_page_number(), suppress_start_page); | |
| 4161 | ||
| 4162 | // remember that the filename will contain a %d in which the | |
| 4163 | // image_no is placed | |
| 4164 | fprintf(stderr, | |
| 4165 | "grohtml-info:page %d %d %d %d %d %d %s %d %d %s\n", | |
| 4166 | topdiv->get_page_number(), | |
| 4167 | get_reg_int("opminx"), get_reg_int("opminy"), | |
| 4168 | get_reg_int("opmaxx"), get_reg_int("opmaxy"), | |
| 4169 | // page offset + line length | |
| 4170 | get_reg_int(".o") + get_reg_int(".l"), | |
| 4171 | name, hresolution, vresolution, get_reg_str(".F")); | |
| 4172 | fflush(stderr); | |
| 4173 | } | |
| 4174 | } | |
| 4175 | else { | |
| 4176 | if (is_on) { | |
| 4177 | out->on(); | |
| 4178 | // lastly we reset the output registers | |
| 4179 | reset_output_registers(); | |
| 4180 | } | |
| 4181 | else | |
| 4182 | out->off(); | |
| 4183 | suppress_start_page = current_page; | |
| 4184 | } | |
| 4185 | } | |
| 4186 | } | |
| 4187 | ||
| 4188 | int suppress_node::force_tprint() | |
| 4189 | { | |
| 4190 | return is_on; | |
| 4191 | } | |
| 4192 | ||
| 465b256c JR |
4193 | int suppress_node::is_tag() |
| 4194 | { | |
| 4195 | return is_on; | |
| 4196 | } | |
| 4197 | ||
| 92d0a6a6 JR |
4198 | hunits suppress_node::width() |
| 4199 | { | |
| 4200 | return H0; | |
| 4201 | } | |
| 4202 | ||
| 4203 | /* composite_node */ | |
| 4204 | ||
| 4205 | class composite_node : public charinfo_node { | |
| 4206 | node *n; | |
| 4207 | tfont *tf; | |
| 4208 | public: | |
| 465b256c | 4209 | composite_node(node *, charinfo *, tfont *, statem *, int, node * = 0); |
| 92d0a6a6 JR |
4210 | ~composite_node(); |
| 4211 | node *copy(); | |
| 4212 | hunits width(); | |
| 4213 | node *last_char_node(); | |
| 4214 | units size(); | |
| 4215 | void tprint(troff_output_file *); | |
| 4216 | hyphenation_type get_hyphenation_type(); | |
| 4217 | void ascii_print(ascii_output_file *); | |
| 4218 | void asciify(macro *); | |
| 4219 | hyphen_list *get_hyphen_list(hyphen_list *, int *); | |
| 4220 | node *add_self(node *, hyphen_list **); | |
| 4221 | tfont *get_tfont(); | |
| 4222 | int same(node *); | |
| 4223 | const char *type(); | |
| 4224 | int force_tprint(); | |
| 465b256c | 4225 | int is_tag(); |
| 92d0a6a6 JR |
4226 | void vertical_extent(vunits *, vunits *); |
| 4227 | vunits vertical_width(); | |
| 4228 | }; | |
| 4229 | ||
| 465b256c JR |
4230 | composite_node::composite_node(node *p, charinfo *c, tfont *t, statem *s, |
| 4231 | int pop, node *x) | |
| 4232 | : charinfo_node(c, s, pop, x), n(p), tf(t) | |
| 92d0a6a6 JR |
4233 | { |
| 4234 | } | |
| 4235 | ||
| 4236 | composite_node::~composite_node() | |
| 4237 | { | |
| 4238 | delete_node_list(n); | |
| 4239 | } | |
| 4240 | ||
| 4241 | node *composite_node::copy() | |
| 4242 | { | |
| 465b256c | 4243 | return new composite_node(copy_node_list(n), ci, tf, state, div_nest_level); |
| 92d0a6a6 JR |
4244 | } |
| 4245 | ||
| 4246 | hunits composite_node::width() | |
| 4247 | { | |
| 4248 | hunits x; | |
| 4249 | if (tf->get_constant_space(&x)) | |
| 4250 | return x; | |
| 4251 | x = H0; | |
| 4252 | for (node *tem = n; tem; tem = tem->next) | |
| 4253 | x += tem->width(); | |
| 4254 | hunits offset; | |
| 4255 | if (tf->get_bold(&offset)) | |
| 4256 | x += offset; | |
| 4257 | x += tf->get_track_kern(); | |
| 4258 | return x; | |
| 4259 | } | |
| 4260 | ||
| 4261 | node *composite_node::last_char_node() | |
| 4262 | { | |
| 4263 | return this; | |
| 4264 | } | |
| 4265 | ||
| 4266 | vunits composite_node::vertical_width() | |
| 4267 | { | |
| 4268 | vunits v = V0; | |
| 4269 | for (node *tem = n; tem; tem = tem->next) | |
| 4270 | v += tem->vertical_width(); | |
| 4271 | return v; | |
| 4272 | } | |
| 4273 | ||
| 4274 | units composite_node::size() | |
| 4275 | { | |
| 4276 | return tf->get_size().to_units(); | |
| 4277 | } | |
| 4278 | ||
| 4279 | hyphenation_type composite_node::get_hyphenation_type() | |
| 4280 | { | |
| 4281 | return HYPHEN_MIDDLE; | |
| 4282 | } | |
| 4283 | ||
| 4284 | void composite_node::asciify(macro *m) | |
| 4285 | { | |
| 4286 | unsigned char c = ci->get_asciify_code(); | |
| 4287 | if (c == 0) | |
| 4288 | c = ci->get_ascii_code(); | |
| 4289 | if (c != 0) { | |
| 4290 | m->append(c); | |
| 4291 | delete this; | |
| 4292 | } | |
| 4293 | else | |
| 4294 | m->append(this); | |
| 4295 | } | |
| 4296 | ||
| 4297 | void composite_node::ascii_print(ascii_output_file *ascii) | |
| 4298 | { | |
| 4299 | unsigned char c = ci->get_ascii_code(); | |
| 4300 | if (c != 0) | |
| 4301 | ascii->outc(c); | |
| 4302 | else | |
| 4303 | ascii->outs(ci->nm.contents()); | |
| 4304 | ||
| 4305 | } | |
| 4306 | ||
| 4307 | hyphen_list *composite_node::get_hyphen_list(hyphen_list *tail, int *count) | |
| 4308 | { | |
| 4309 | (*count)++; | |
| 4310 | return new hyphen_list(ci->get_hyphenation_code(), tail); | |
| 4311 | } | |
| 4312 | ||
| 4313 | node *composite_node::add_self(node *nn, hyphen_list **p) | |
| 4314 | { | |
| 4315 | assert(ci->get_hyphenation_code() == (*p)->hyphenation_code); | |
| 4316 | next = nn; | |
| 4317 | nn = this; | |
| 4318 | if ((*p)->hyphen) | |
| 4319 | nn = nn->add_discretionary_hyphen(); | |
| 4320 | hyphen_list *pp = *p; | |
| 4321 | *p = (*p)->next; | |
| 4322 | delete pp; | |
| 4323 | return nn; | |
| 4324 | } | |
| 4325 | ||
| 4326 | tfont *composite_node::get_tfont() | |
| 4327 | { | |
| 4328 | return tf; | |
| 4329 | } | |
| 4330 | ||
| 4331 | node *reverse_node_list(node *n) | |
| 4332 | { | |
| 4333 | node *r = 0; | |
| 4334 | while (n) { | |
| 4335 | node *tem = n; | |
| 4336 | n = n->next; | |
| 4337 | tem->next = r; | |
| 4338 | r = tem; | |
| 4339 | } | |
| 4340 | return r; | |
| 4341 | } | |
| 4342 | ||
| 4343 | void composite_node::vertical_extent(vunits *minimum, vunits *maximum) | |
| 4344 | { | |
| 4345 | n = reverse_node_list(n); | |
| 4346 | node_list_vertical_extent(n, minimum, maximum); | |
| 4347 | n = reverse_node_list(n); | |
| 4348 | } | |
| 4349 | ||
| 4350 | width_list::width_list(hunits w, hunits s) | |
| 4351 | : width(w), sentence_width(s), next(0) | |
| 4352 | { | |
| 4353 | } | |
| 4354 | ||
| 4355 | width_list::width_list(width_list *w) | |
| 4356 | : width(w->width), sentence_width(w->sentence_width), next(0) | |
| 4357 | { | |
| 4358 | } | |
| 4359 | ||
| 4360 | word_space_node::word_space_node(hunits d, color *c, width_list *w, node *x) | |
| 4361 | : space_node(d, c, x), orig_width(w), unformat(0) | |
| 4362 | { | |
| 4363 | } | |
| 4364 | ||
| 4365 | word_space_node::word_space_node(hunits d, int s, color *c, width_list *w, | |
| 465b256c JR |
4366 | int flag, statem *st, int pop, node *x) |
| 4367 | : space_node(d, s, 0, c, st, pop, x), orig_width(w), unformat(flag) | |
| 92d0a6a6 JR |
4368 | { |
| 4369 | } | |
| 4370 | ||
| 4371 | word_space_node::~word_space_node() | |
| 4372 | { | |
| 4373 | width_list *w = orig_width; | |
| 4374 | while (w != 0) { | |
| 4375 | width_list *tmp = w; | |
| 4376 | w = w->next; | |
| 4377 | delete tmp; | |
| 4378 | } | |
| 4379 | } | |
| 4380 | ||
| 4381 | node *word_space_node::copy() | |
| 4382 | { | |
| 4383 | assert(orig_width != 0); | |
| 4384 | width_list *w_old_curr = orig_width; | |
| 4385 | width_list *w_new_curr = new width_list(w_old_curr); | |
| 4386 | width_list *w_new = w_new_curr; | |
| 4387 | w_old_curr = w_old_curr->next; | |
| 4388 | while (w_old_curr != 0) { | |
| 4389 | w_new_curr->next = new width_list(w_old_curr); | |
| 4390 | w_new_curr = w_new_curr->next; | |
| 4391 | w_old_curr = w_old_curr->next; | |
| 4392 | } | |
| 465b256c JR |
4393 | return new word_space_node(n, set, col, w_new, unformat, state, |
| 4394 | div_nest_level); | |
| 92d0a6a6 JR |
4395 | } |
| 4396 | ||
| 4397 | int word_space_node::set_unformat_flag() | |
| 4398 | { | |
| 4399 | unformat = 1; | |
| 4400 | return 1; | |
| 4401 | } | |
| 4402 | ||
| 4403 | void word_space_node::tprint(troff_output_file *out) | |
| 4404 | { | |
| 4405 | out->fill_color(col); | |
| 4406 | out->word_marker(); | |
| 4407 | out->right(n); | |
| 4408 | } | |
| 4409 | ||
| 4410 | int word_space_node::merge_space(hunits h, hunits sw, hunits ssw) | |
| 4411 | { | |
| 4412 | n += h; | |
| 4413 | assert(orig_width != 0); | |
| 4414 | width_list *w = orig_width; | |
| 4415 | for (; w->next; w = w->next) | |
| 4416 | ; | |
| 4417 | w->next = new width_list(sw, ssw); | |
| 4418 | return 1; | |
| 4419 | } | |
| 4420 | ||
| 4421 | unbreakable_space_node::unbreakable_space_node(hunits d, color *c, node *x) | |
| 4422 | : word_space_node(d, c, 0, x) | |
| 4423 | { | |
| 4424 | } | |
| 4425 | ||
| 4426 | unbreakable_space_node::unbreakable_space_node(hunits d, int s, | |
| 465b256c JR |
4427 | color *c, statem *st, int pop, |
| 4428 | node *x) | |
| 4429 | : word_space_node(d, s, c, 0, 0, st, pop, x) | |
| 92d0a6a6 JR |
4430 | { |
| 4431 | } | |
| 4432 | ||
| 4433 | node *unbreakable_space_node::copy() | |
| 4434 | { | |
| 465b256c | 4435 | return new unbreakable_space_node(n, set, col, state, div_nest_level); |
| 92d0a6a6 JR |
4436 | } |
| 4437 | ||
| 4438 | int unbreakable_space_node::force_tprint() | |
| 4439 | { | |
| 4440 | return 0; | |
| 4441 | } | |
| 4442 | ||
| 465b256c JR |
4443 | int unbreakable_space_node::is_tag() |
| 4444 | { | |
| 4445 | return 0; | |
| 4446 | } | |
| 4447 | ||
| 92d0a6a6 JR |
4448 | breakpoint *unbreakable_space_node::get_breakpoints(hunits, int, |
| 4449 | breakpoint *rest, int) | |
| 4450 | { | |
| 4451 | return rest; | |
| 4452 | } | |
| 4453 | ||
| 4454 | int unbreakable_space_node::nbreaks() | |
| 4455 | { | |
| 4456 | return 0; | |
| 4457 | } | |
| 4458 | ||
| 4459 | void unbreakable_space_node::split(int, node **, node **) | |
| 4460 | { | |
| 4461 | assert(0); | |
| 4462 | } | |
| 4463 | ||
| 4464 | int unbreakable_space_node::merge_space(hunits, hunits, hunits) | |
| 4465 | { | |
| 4466 | return 0; | |
| 4467 | } | |
| 4468 | ||
| 4469 | hvpair::hvpair() | |
| 4470 | { | |
| 4471 | } | |
| 4472 | ||
| 4473 | draw_node::draw_node(char c, hvpair *p, int np, font_size s, | |
| 4474 | color *gc, color *fc) | |
| 4475 | : npoints(np), sz(s), gcol(gc), fcol(fc), code(c) | |
| 4476 | { | |
| 4477 | point = new hvpair[npoints]; | |
| 4478 | for (int i = 0; i < npoints; i++) | |
| 4479 | point[i] = p[i]; | |
| 4480 | } | |
| 4481 | ||
| 465b256c JR |
4482 | draw_node::draw_node(char c, hvpair *p, int np, font_size s, |
| 4483 | color *gc, color *fc, statem *st, int pop) | |
| 4484 | : node(0, st, pop), npoints(np), sz(s), gcol(gc), fcol(fc), code(c) | |
| 4485 | { | |
| 4486 | point = new hvpair[npoints]; | |
| 4487 | for (int i = 0; i < npoints; i++) | |
| 4488 | point[i] = p[i]; | |
| 4489 | } | |
| 4490 | ||
| 92d0a6a6 JR |
4491 | int draw_node::same(node *n) |
| 4492 | { | |
| 4493 | draw_node *nd = (draw_node *)n; | |
| 4494 | if (code != nd->code || npoints != nd->npoints || sz != nd->sz | |
| 4495 | || gcol != nd->gcol || fcol != nd->fcol) | |
| 4496 | return 0; | |
| 4497 | for (int i = 0; i < npoints; i++) | |
| 4498 | if (point[i].h != nd->point[i].h || point[i].v != nd->point[i].v) | |
| 4499 | return 0; | |
| 4500 | return 1; | |
| 4501 | } | |
| 4502 | ||
| 4503 | const char *draw_node::type() | |
| 4504 | { | |
| 4505 | return "draw_node"; | |
| 4506 | } | |
| 4507 | ||
| 4508 | int draw_node::force_tprint() | |
| 4509 | { | |
| 4510 | return 0; | |
| 4511 | } | |
| 4512 | ||
| 465b256c JR |
4513 | int draw_node::is_tag() |
| 4514 | { | |
| 4515 | return 0; | |
| 4516 | } | |
| 4517 | ||
| 92d0a6a6 JR |
4518 | draw_node::~draw_node() |
| 4519 | { | |
| 4520 | if (point) | |
| 4521 | a_delete point; | |
| 4522 | } | |
| 4523 | ||
| 4524 | hunits draw_node::width() | |
| 4525 | { | |
| 4526 | hunits x = H0; | |
| 4527 | for (int i = 0; i < npoints; i++) | |
| 4528 | x += point[i].h; | |
| 4529 | return x; | |
| 4530 | } | |
| 4531 | ||
| 4532 | vunits draw_node::vertical_width() | |
| 4533 | { | |
| 4534 | if (code == 'e') | |
| 4535 | return V0; | |
| 4536 | vunits x = V0; | |
| 4537 | for (int i = 0; i < npoints; i++) | |
| 4538 | x += point[i].v; | |
| 4539 | return x; | |
| 4540 | } | |
| 4541 | ||
| 4542 | node *draw_node::copy() | |
| 4543 | { | |
| 465b256c JR |
4544 | return new draw_node(code, point, npoints, sz, gcol, fcol, state, |
| 4545 | div_nest_level); | |
| 92d0a6a6 JR |
4546 | } |
| 4547 | ||
| 4548 | void draw_node::tprint(troff_output_file *out) | |
| 4549 | { | |
| 4550 | out->draw(code, point, npoints, sz, gcol, fcol); | |
| 4551 | } | |
| 4552 | ||
| 4553 | /* tprint methods */ | |
| 4554 | ||
| 4555 | void glyph_node::tprint(troff_output_file *out) | |
| 4556 | { | |
| 4557 | tfont *ptf = tf->get_plain(); | |
| 4558 | if (ptf == tf) | |
| 4559 | out->put_char_width(ci, ptf, gcol, fcol, width(), H0); | |
| 4560 | else { | |
| 4561 | hunits offset; | |
| 4562 | int bold = tf->get_bold(&offset); | |
| 4563 | hunits w = ptf->get_width(ci); | |
| 4564 | hunits k = H0; | |
| 4565 | hunits x; | |
| 4566 | int cs = tf->get_constant_space(&x); | |
| 4567 | if (cs) { | |
| 4568 | x -= w; | |
| 4569 | if (bold) | |
| 4570 | x -= offset; | |
| 4571 | hunits x2 = x/2; | |
| 4572 | out->right(x2); | |
| 4573 | k = x - x2; | |
| 4574 | } | |
| 4575 | else | |
| 4576 | k = tf->get_track_kern(); | |
| 4577 | if (bold) { | |
| 4578 | out->put_char(ci, ptf, gcol, fcol); | |
| 4579 | out->right(offset); | |
| 4580 | } | |
| 4581 | out->put_char_width(ci, ptf, gcol, fcol, w, k); | |
| 4582 | } | |
| 4583 | } | |
| 4584 | ||
| 4585 | void glyph_node::zero_width_tprint(troff_output_file *out) | |
| 4586 | { | |
| 4587 | tfont *ptf = tf->get_plain(); | |
| 4588 | hunits offset; | |
| 4589 | int bold = tf->get_bold(&offset); | |
| 4590 | hunits x; | |
| 4591 | int cs = tf->get_constant_space(&x); | |
| 4592 | if (cs) { | |
| 4593 | x -= ptf->get_width(ci); | |
| 4594 | if (bold) | |
| 4595 | x -= offset; | |
| 4596 | x = x/2; | |
| 4597 | out->right(x); | |
| 4598 | } | |
| 4599 | out->put_char(ci, ptf, gcol, fcol); | |
| 4600 | if (bold) { | |
| 4601 | out->right(offset); | |
| 4602 | out->put_char(ci, ptf, gcol, fcol); | |
| 4603 | out->right(-offset); | |
| 4604 | } | |
| 4605 | if (cs) | |
| 4606 | out->right(-x); | |
| 4607 | } | |
| 4608 | ||
| 4609 | void break_char_node::tprint(troff_output_file *t) | |
| 4610 | { | |
| 4611 | ch->tprint(t); | |
| 4612 | } | |
| 4613 | ||
| 4614 | void break_char_node::zero_width_tprint(troff_output_file *t) | |
| 4615 | { | |
| 4616 | ch->zero_width_tprint(t); | |
| 4617 | } | |
| 4618 | ||
| 4619 | void hline_node::tprint(troff_output_file *out) | |
| 4620 | { | |
| 4621 | if (x < H0) { | |
| 4622 | out->right(x); | |
| 4623 | x = -x; | |
| 4624 | } | |
| 4625 | if (n == 0) { | |
| 4626 | out->right(x); | |
| 4627 | return; | |
| 4628 | } | |
| 4629 | hunits w = n->width(); | |
| 4630 | if (w <= H0) { | |
| 4631 | error("horizontal line drawing character must have positive width"); | |
| 4632 | out->right(x); | |
| 4633 | return; | |
| 4634 | } | |
| 4635 | int i = int(x/w); | |
| 4636 | if (i == 0) { | |
| 4637 | hunits xx = x - w; | |
| 4638 | hunits xx2 = xx/2; | |
| 4639 | out->right(xx2); | |
| 4640 | if (out->is_on()) | |
| 4641 | n->tprint(out); | |
| 4642 | out->right(xx - xx2); | |
| 4643 | } | |
| 4644 | else { | |
| 4645 | hunits rem = x - w*i; | |
| 4646 | if (rem > H0) | |
| 4647 | if (n->overlaps_horizontally()) { | |
| 4648 | if (out->is_on()) | |
| 4649 | n->tprint(out); | |
| 4650 | out->right(rem - w); | |
| 4651 | } | |
| 4652 | else | |
| 4653 | out->right(rem); | |
| 4654 | while (--i >= 0) | |
| 4655 | if (out->is_on()) | |
| 4656 | n->tprint(out); | |
| 4657 | } | |
| 4658 | } | |
| 4659 | ||
| 4660 | void vline_node::tprint(troff_output_file *out) | |
| 4661 | { | |
| 4662 | if (n == 0) { | |
| 4663 | out->down(x); | |
| 4664 | return; | |
| 4665 | } | |
| 4666 | vunits h = n->size(); | |
| 4667 | int overlaps = n->overlaps_vertically(); | |
| 4668 | vunits y = x; | |
| 4669 | if (y < V0) { | |
| 4670 | y = -y; | |
| 4671 | int i = y / h; | |
| 4672 | vunits rem = y - i*h; | |
| 4673 | if (i == 0) { | |
| 4674 | out->right(n->width()); | |
| 4675 | out->down(-rem); | |
| 4676 | } | |
| 4677 | else { | |
| 4678 | while (--i > 0) { | |
| 4679 | n->zero_width_tprint(out); | |
| 4680 | out->down(-h); | |
| 4681 | } | |
| 4682 | if (overlaps) { | |
| 4683 | n->zero_width_tprint(out); | |
| 4684 | out->down(-rem); | |
| 4685 | if (out->is_on()) | |
| 4686 | n->tprint(out); | |
| 4687 | out->down(-h); | |
| 4688 | } | |
| 4689 | else { | |
| 4690 | if (out->is_on()) | |
| 4691 | n->tprint(out); | |
| 4692 | out->down(-h - rem); | |
| 4693 | } | |
| 4694 | } | |
| 4695 | } | |
| 4696 | else { | |
| 4697 | int i = y / h; | |
| 4698 | vunits rem = y - i*h; | |
| 4699 | if (i == 0) { | |
| 4700 | out->down(rem); | |
| 4701 | out->right(n->width()); | |
| 4702 | } | |
| 4703 | else { | |
| 4704 | out->down(h); | |
| 4705 | if (overlaps) | |
| 4706 | n->zero_width_tprint(out); | |
| 4707 | out->down(rem); | |
| 4708 | while (--i > 0) { | |
| 4709 | n->zero_width_tprint(out); | |
| 4710 | out->down(h); | |
| 4711 | } | |
| 4712 | if (out->is_on()) | |
| 4713 | n->tprint(out); | |
| 4714 | } | |
| 4715 | } | |
| 4716 | } | |
| 4717 | ||
| 4718 | void zero_width_node::tprint(troff_output_file *out) | |
| 4719 | { | |
| 4720 | if (!n) | |
| 4721 | return; | |
| 4722 | if (!n->next) { | |
| 4723 | n->zero_width_tprint(out); | |
| 4724 | return; | |
| 4725 | } | |
| 4726 | int hpos = out->get_hpos(); | |
| 4727 | int vpos = out->get_vpos(); | |
| 4728 | node *tem = n; | |
| 4729 | while (tem) { | |
| 4730 | tem->tprint(out); | |
| 4731 | tem = tem->next; | |
| 4732 | } | |
| 4733 | out->moveto(hpos, vpos); | |
| 4734 | } | |
| 4735 | ||
| 4736 | void overstrike_node::tprint(troff_output_file *out) | |
| 4737 | { | |
| 4738 | hunits pos = H0; | |
| 4739 | for (node *tem = list; tem; tem = tem->next) { | |
| 4740 | hunits x = (max_width - tem->width())/2; | |
| 4741 | out->right(x - pos); | |
| 4742 | pos = x; | |
| 4743 | tem->zero_width_tprint(out); | |
| 4744 | } | |
| 4745 | out->right(max_width - pos); | |
| 4746 | } | |
| 4747 | ||
| 4748 | void bracket_node::tprint(troff_output_file *out) | |
| 4749 | { | |
| 4750 | if (list == 0) | |
| 4751 | return; | |
| 4752 | int npieces = 0; | |
| 4753 | node *tem; | |
| 4754 | for (tem = list; tem; tem = tem->next) | |
| 4755 | ++npieces; | |
| 4756 | vunits h = list->size(); | |
| 4757 | vunits totalh = h*npieces; | |
| 4758 | vunits y = (totalh - h)/2; | |
| 4759 | out->down(y); | |
| 4760 | for (tem = list; tem; tem = tem->next) { | |
| 4761 | tem->zero_width_tprint(out); | |
| 4762 | out->down(-h); | |
| 4763 | } | |
| 4764 | out->right(max_width); | |
| 4765 | out->down(totalh - y); | |
| 4766 | } | |
| 4767 | ||
| 4768 | void node::tprint(troff_output_file *) | |
| 4769 | { | |
| 4770 | } | |
| 4771 | ||
| 4772 | void node::zero_width_tprint(troff_output_file *out) | |
| 4773 | { | |
| 4774 | int hpos = out->get_hpos(); | |
| 4775 | int vpos = out->get_vpos(); | |
| 4776 | tprint(out); | |
| 4777 | out->moveto(hpos, vpos); | |
| 4778 | } | |
| 4779 | ||
| 4780 | void space_node::tprint(troff_output_file *out) | |
| 4781 | { | |
| 4782 | out->fill_color(col); | |
| 4783 | out->right(n); | |
| 4784 | } | |
| 4785 | ||
| 4786 | void hmotion_node::tprint(troff_output_file *out) | |
| 4787 | { | |
| 4788 | out->fill_color(col); | |
| 4789 | out->right(n); | |
| 4790 | } | |
| 4791 | ||
| 4792 | void space_char_hmotion_node::tprint(troff_output_file *out) | |
| 4793 | { | |
| 4794 | out->fill_color(col); | |
| 4795 | if (is_html) { | |
| 4796 | // we emit the space width as a negative glyph index | |
| 4797 | out->flush_tbuf(); | |
| 4798 | out->do_motion(); | |
| 4799 | out->put('N'); | |
| 4800 | out->put(-n.to_units()); | |
| 4801 | out->put('\n'); | |
| 4802 | } | |
| 4803 | out->right(n); | |
| 4804 | } | |
| 4805 | ||
| 4806 | void vmotion_node::tprint(troff_output_file *out) | |
| 4807 | { | |
| 4808 | out->fill_color(col); | |
| 4809 | out->down(n); | |
| 4810 | } | |
| 4811 | ||
| 4812 | void kern_pair_node::tprint(troff_output_file *out) | |
| 4813 | { | |
| 4814 | n1->tprint(out); | |
| 4815 | out->right(amount); | |
| 4816 | n2->tprint(out); | |
| 4817 | } | |
| 4818 | ||
| 4819 | static void tprint_reverse_node_list(troff_output_file *out, node *n) | |
| 4820 | { | |
| 4821 | if (n == 0) | |
| 4822 | return; | |
| 4823 | tprint_reverse_node_list(out, n->next); | |
| 4824 | n->tprint(out); | |
| 4825 | } | |
| 4826 | ||
| 4827 | void dbreak_node::tprint(troff_output_file *out) | |
| 4828 | { | |
| 4829 | tprint_reverse_node_list(out, none); | |
| 4830 | } | |
| 4831 | ||
| 4832 | void composite_node::tprint(troff_output_file *out) | |
| 4833 | { | |
| 4834 | hunits bold_offset; | |
| 4835 | int is_bold = tf->get_bold(&bold_offset); | |
| 4836 | hunits track_kern = tf->get_track_kern(); | |
| 4837 | hunits constant_space; | |
| 4838 | int is_constant_spaced = tf->get_constant_space(&constant_space); | |
| 4839 | hunits x = H0; | |
| 4840 | if (is_constant_spaced) { | |
| 4841 | x = constant_space; | |
| 4842 | for (node *tem = n; tem; tem = tem->next) | |
| 4843 | x -= tem->width(); | |
| 4844 | if (is_bold) | |
| 4845 | x -= bold_offset; | |
| 4846 | hunits x2 = x/2; | |
| 4847 | out->right(x2); | |
| 4848 | x -= x2; | |
| 4849 | } | |
| 4850 | if (is_bold) { | |
| 4851 | int hpos = out->get_hpos(); | |
| 4852 | int vpos = out->get_vpos(); | |
| 4853 | tprint_reverse_node_list(out, n); | |
| 4854 | out->moveto(hpos, vpos); | |
| 4855 | out->right(bold_offset); | |
| 4856 | } | |
| 4857 | tprint_reverse_node_list(out, n); | |
| 4858 | if (is_constant_spaced) | |
| 4859 | out->right(x); | |
| 4860 | else | |
| 4861 | out->right(track_kern); | |
| 4862 | } | |
| 4863 | ||
| 4864 | node *make_composite_node(charinfo *s, environment *env) | |
| 4865 | { | |
| 4866 | int fontno = env_definite_font(env); | |
| 4867 | if (fontno < 0) { | |
| 4868 | error("no current font"); | |
| 4869 | return 0; | |
| 4870 | } | |
| 4871 | assert(fontno < font_table_size && font_table[fontno] != 0); | |
| 4872 | node *n = charinfo_to_node_list(s, env); | |
| 4873 | font_size fs = env->get_font_size(); | |
| 4874 | int char_height = env->get_char_height(); | |
| 4875 | int char_slant = env->get_char_slant(); | |
| 4876 | tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, | |
| 4877 | fontno); | |
| 4878 | if (env->is_composite()) | |
| 4879 | tf = tf->get_plain(); | |
| 465b256c | 4880 | return new composite_node(n, s, tf, 0, 0, 0); |
| 92d0a6a6 JR |
4881 | } |
| 4882 | ||
| 4883 | node *make_glyph_node(charinfo *s, environment *env, int no_error_message = 0) | |
| 4884 | { | |
| 4885 | int fontno = env_definite_font(env); | |
| 4886 | if (fontno < 0) { | |
| 4887 | error("no current font"); | |
| 4888 | return 0; | |
| 4889 | } | |
| 4890 | assert(fontno < font_table_size && font_table[fontno] != 0); | |
| 4891 | int fn = fontno; | |
| 4892 | int found = font_table[fontno]->contains(s); | |
| 4893 | if (!found) { | |
| 4894 | macro *mac = s->get_macro(); | |
| 4895 | if (mac && s->is_fallback()) | |
| 4896 | return make_composite_node(s, env); | |
| 4897 | if (s->numbered()) { | |
| 4898 | if (!no_error_message) | |
| 4899 | warning(WARN_CHAR, "can't find numbered character %1", | |
| 4900 | s->get_number()); | |
| 4901 | return 0; | |
| 4902 | } | |
| 4903 | special_font_list *sf = font_table[fontno]->sf; | |
| 4904 | while (sf != 0 && !found) { | |
| 4905 | fn = sf->n; | |
| 4906 | if (font_table[fn]) | |
| 4907 | found = font_table[fn]->contains(s); | |
| 4908 | sf = sf->next; | |
| 4909 | } | |
| 4910 | if (!found) { | |
| 4911 | symbol f = font_table[fontno]->get_name(); | |
| 4912 | string gl(f.contents()); | |
| 4913 | gl += ' '; | |
| 4914 | gl += s->nm.contents(); | |
| 4915 | gl += '\0'; | |
| 4916 | charinfo *ci = get_charinfo(symbol(gl.contents())); | |
| 4917 | if (ci && ci->get_macro()) | |
| 4918 | return make_composite_node(ci, env); | |
| 4919 | } | |
| 4920 | if (!found) { | |
| 4921 | sf = global_special_fonts; | |
| 4922 | while (sf != 0 && !found) { | |
| 4923 | fn = sf->n; | |
| 4924 | if (font_table[fn]) | |
| 4925 | found = font_table[fn]->contains(s); | |
| 4926 | sf = sf->next; | |
| 4927 | } | |
| 4928 | } | |
| 4929 | if (!found) | |
| 4930 | if (mac && s->is_special()) | |
| 4931 | return make_composite_node(s, env); | |
| 4932 | if (!found) { | |
| 4933 | for (fn = 0; fn < font_table_size; fn++) | |
| 4934 | if (font_table[fn] | |
| 4935 | && font_table[fn]->is_special() | |
| 4936 | && font_table[fn]->contains(s)) { | |
| 4937 | found = 1; | |
| 4938 | break; | |
| 4939 | } | |
| 4940 | } | |
| 4941 | if (!found) { | |
| 4942 | if (!no_error_message && s->first_time_not_found()) { | |
| 4943 | unsigned char input_code = s->get_ascii_code(); | |
| 4944 | if (input_code != 0) { | |
| 4945 | if (csgraph(input_code)) | |
| 4946 | warning(WARN_CHAR, "can't find character `%1'", input_code); | |
| 4947 | else | |
| 4948 | warning(WARN_CHAR, "can't find character with input code %1", | |
| 4949 | int(input_code)); | |
| 4950 | } | |
| 4d3e9548 JL |
4951 | else if (s->nm.contents()) { |
| 4952 | const char *nm = s->nm.contents(); | |
| 4953 | const char *backslash = (nm[1] == 0) ? "\\" : ""; | |
| 4954 | warning(WARN_CHAR, "can't find special character `%1%2'", | |
| 4955 | backslash, nm); | |
| 4956 | } | |
| 92d0a6a6 JR |
4957 | } |
| 4958 | return 0; | |
| 4959 | } | |
| 4960 | } | |
| 4961 | font_size fs = env->get_font_size(); | |
| 4962 | int char_height = env->get_char_height(); | |
| 4963 | int char_slant = env->get_char_slant(); | |
| 4964 | tfont *tf = font_table[fontno]->get_tfont(fs, char_height, char_slant, fn); | |
| 4965 | if (env->is_composite()) | |
| 4966 | tf = tf->get_plain(); | |
| 4967 | color *gcol = env->get_glyph_color(); | |
| 4968 | color *fcol = env->get_fill_color(); | |
| 465b256c | 4969 | return new glyph_node(s, tf, gcol, fcol, 0, 0); |
| 92d0a6a6 JR |
4970 | } |
| 4971 | ||
| 4972 | node *make_node(charinfo *ci, environment *env) | |
| 4973 | { | |
| 4974 | switch (ci->get_special_translation()) { | |
| 4975 | case charinfo::TRANSLATE_SPACE: | |
| 4976 | return new space_char_hmotion_node(env->get_space_width(), | |
| 4977 | env->get_fill_color()); | |
| 4978 | case charinfo::TRANSLATE_STRETCHABLE_SPACE: | |
| 4979 | return new unbreakable_space_node(env->get_space_width(), | |
| 4980 | env->get_fill_color()); | |
| 4981 | case charinfo::TRANSLATE_DUMMY: | |
| 4982 | return new dummy_node; | |
| 4983 | case charinfo::TRANSLATE_HYPHEN_INDICATOR: | |
| 4984 | error("translation to \\% ignored in this context"); | |
| 4985 | break; | |
| 4986 | } | |
| 4987 | charinfo *tem = ci->get_translation(); | |
| 4988 | if (tem) | |
| 4989 | ci = tem; | |
| 4990 | macro *mac = ci->get_macro(); | |
| 4991 | if (mac && ci->is_normal()) | |
| 4992 | return make_composite_node(ci, env); | |
| 4993 | else | |
| 4994 | return make_glyph_node(ci, env); | |
| 4995 | } | |
| 4996 | ||
| 4997 | int character_exists(charinfo *ci, environment *env) | |
| 4998 | { | |
| 4999 | if (ci->get_special_translation() != charinfo::TRANSLATE_NONE) | |
| 5000 | return 1; | |
| 5001 | charinfo *tem = ci->get_translation(); | |
| 5002 | if (tem) | |
| 5003 | ci = tem; | |
| 5004 | if (ci->get_macro()) | |
| 5005 | return 1; | |
| 5006 | node *nd = make_glyph_node(ci, env, 1); | |
| 5007 | if (nd) { | |
| 5008 | delete nd; | |
| 5009 | return 1; | |
| 5010 | } | |
| 5011 | return 0; | |
| 5012 | } | |
| 5013 | ||
| 5014 | node *node::add_char(charinfo *ci, environment *env, | |
| 465b256c | 5015 | hunits *widthp, int *spacep, node **glyph_comp_np) |
| 92d0a6a6 JR |
5016 | { |
| 5017 | node *res; | |
| 5018 | switch (ci->get_special_translation()) { | |
| 5019 | case charinfo::TRANSLATE_SPACE: | |
| 5020 | res = new space_char_hmotion_node(env->get_space_width(), | |
| 5021 | env->get_fill_color(), this); | |
| 5022 | *widthp += res->width(); | |
| 5023 | return res; | |
| 5024 | case charinfo::TRANSLATE_STRETCHABLE_SPACE: | |
| 5025 | res = new unbreakable_space_node(env->get_space_width(), | |
| 5026 | env->get_fill_color(), this); | |
| 5027 | res->freeze_space(); | |
| 5028 | *widthp += res->width(); | |
| 5029 | *spacep += res->nspaces(); | |
| 5030 | return res; | |
| 5031 | case charinfo::TRANSLATE_DUMMY: | |
| 5032 | return new dummy_node(this); | |
| 5033 | case charinfo::TRANSLATE_HYPHEN_INDICATOR: | |
| 5034 | return add_discretionary_hyphen(); | |
| 5035 | } | |
| 5036 | charinfo *tem = ci->get_translation(); | |
| 5037 | if (tem) | |
| 5038 | ci = tem; | |
| 5039 | macro *mac = ci->get_macro(); | |
| 5040 | if (mac && ci->is_normal()) { | |
| 5041 | res = make_composite_node(ci, env); | |
| 5042 | if (res) { | |
| 5043 | res->next = this; | |
| 5044 | *widthp += res->width(); | |
| 465b256c JR |
5045 | if (glyph_comp_np) |
| 5046 | *glyph_comp_np = res; | |
| 92d0a6a6 | 5047 | } |
| 465b256c JR |
5048 | else { |
| 5049 | if (glyph_comp_np) | |
| 5050 | *glyph_comp_np = res; | |
| 92d0a6a6 | 5051 | return this; |
| 465b256c | 5052 | } |
| 92d0a6a6 JR |
5053 | } |
| 5054 | else { | |
| 5055 | node *gn = make_glyph_node(ci, env); | |
| 5056 | if (gn == 0) | |
| 5057 | return this; | |
| 5058 | else { | |
| 5059 | hunits old_width = width(); | |
| 5060 | node *p = gn->merge_self(this); | |
| 5061 | if (p == 0) { | |
| 5062 | *widthp += gn->width(); | |
| 5063 | gn->next = this; | |
| 5064 | res = gn; | |
| 5065 | } | |
| 5066 | else { | |
| 5067 | *widthp += p->width() - old_width; | |
| 5068 | res = p; | |
| 5069 | } | |
| 465b256c JR |
5070 | if (glyph_comp_np) |
| 5071 | *glyph_comp_np = res; | |
| 92d0a6a6 JR |
5072 | } |
| 5073 | } | |
| 5074 | int break_code = 0; | |
| 5075 | if (ci->can_break_before()) | |
| 5076 | break_code = 1; | |
| 5077 | if (ci->can_break_after()) | |
| 5078 | break_code |= 2; | |
| 4d3e9548 JL |
5079 | if (ci->ignore_hcodes()) |
| 5080 | break_code |= 4; | |
| 92d0a6a6 JR |
5081 | if (break_code) { |
| 5082 | node *next1 = res->next; | |
| 5083 | res->next = 0; | |
| 5084 | res = new break_char_node(res, break_code, env->get_fill_color(), next1); | |
| 5085 | } | |
| 5086 | return res; | |
| 5087 | } | |
| 5088 | ||
| 5089 | #ifdef __GNUG__ | |
| 5090 | inline | |
| 5091 | #endif | |
| 5092 | int same_node(node *n1, node *n2) | |
| 5093 | { | |
| 5094 | if (n1 != 0) { | |
| 5095 | if (n2 != 0) | |
| 5096 | return n1->type() == n2->type() && n1->same(n2); | |
| 5097 | else | |
| 5098 | return 0; | |
| 5099 | } | |
| 5100 | else | |
| 5101 | return n2 == 0; | |
| 5102 | } | |
| 5103 | ||
| 5104 | int same_node_list(node *n1, node *n2) | |
| 5105 | { | |
| 5106 | while (n1 && n2) { | |
| 5107 | if (n1->type() != n2->type() || !n1->same(n2)) | |
| 5108 | return 0; | |
| 5109 | n1 = n1->next; | |
| 5110 | n2 = n2->next; | |
| 5111 | } | |
| 5112 | return !n1 && !n2; | |
| 5113 | } | |
| 5114 | ||
| 5115 | int extra_size_node::same(node *nd) | |
| 5116 | { | |
| 5117 | return n == ((extra_size_node *)nd)->n; | |
| 5118 | } | |
| 5119 | ||
| 5120 | const char *extra_size_node::type() | |
| 5121 | { | |
| 5122 | return "extra_size_node"; | |
| 5123 | } | |
| 5124 | ||
| 5125 | int extra_size_node::force_tprint() | |
| 5126 | { | |
| 5127 | return 0; | |
| 5128 | } | |
| 5129 | ||
| 465b256c JR |
5130 | int extra_size_node::is_tag() |
| 5131 | { | |
| 5132 | return 0; | |
| 5133 | } | |
| 5134 | ||
| 92d0a6a6 JR |
5135 | int vertical_size_node::same(node *nd) |
| 5136 | { | |
| 5137 | return n == ((vertical_size_node *)nd)->n; | |
| 5138 | } | |
| 5139 | ||
| 5140 | const char *vertical_size_node::type() | |
| 5141 | { | |
| 5142 | return "vertical_size_node"; | |
| 5143 | } | |
| 5144 | ||
| 5145 | int vertical_size_node::set_unformat_flag() | |
| 5146 | { | |
| 5147 | return 0; | |
| 5148 | } | |
| 5149 | ||
| 5150 | int vertical_size_node::force_tprint() | |
| 5151 | { | |
| 5152 | return 0; | |
| 5153 | } | |
| 5154 | ||
| 465b256c JR |
5155 | int vertical_size_node::is_tag() |
| 5156 | { | |
| 5157 | return 0; | |
| 5158 | } | |
| 5159 | ||
| 92d0a6a6 JR |
5160 | int hmotion_node::same(node *nd) |
| 5161 | { | |
| 5162 | return n == ((hmotion_node *)nd)->n | |
| 5163 | && col == ((hmotion_node *)nd)->col; | |
| 5164 | } | |
| 5165 | ||
| 5166 | const char *hmotion_node::type() | |
| 5167 | { | |
| 5168 | return "hmotion_node"; | |
| 5169 | } | |
| 5170 | ||
| 5171 | int hmotion_node::set_unformat_flag() | |
| 5172 | { | |
| 5173 | unformat = 1; | |
| 5174 | return 1; | |
| 5175 | } | |
| 5176 | ||
| 5177 | int hmotion_node::force_tprint() | |
| 5178 | { | |
| 5179 | return 0; | |
| 5180 | } | |
| 5181 | ||
| 465b256c JR |
5182 | int hmotion_node::is_tag() |
| 5183 | { | |
| 5184 | return 0; | |
| 5185 | } | |
| 5186 | ||
| 92d0a6a6 JR |
5187 | node *hmotion_node::add_self(node *nd, hyphen_list **p) |
| 5188 | { | |
| 5189 | next = nd; | |
| 5190 | hyphen_list *pp = *p; | |
| 5191 | *p = (*p)->next; | |
| 5192 | delete pp; | |
| 5193 | return this; | |
| 5194 | } | |
| 5195 | ||
| 5196 | hyphen_list *hmotion_node::get_hyphen_list(hyphen_list *tail, int *) | |
| 5197 | { | |
| 5198 | return new hyphen_list(0, tail); | |
| 5199 | } | |
| 5200 | ||
| 5201 | int space_char_hmotion_node::same(node *nd) | |
| 5202 | { | |
| 5203 | return n == ((space_char_hmotion_node *)nd)->n | |
| 5204 | && col == ((space_char_hmotion_node *)nd)->col; | |
| 5205 | } | |
| 5206 | ||
| 5207 | const char *space_char_hmotion_node::type() | |
| 5208 | { | |
| 5209 | return "space_char_hmotion_node"; | |
| 5210 | } | |
| 5211 | ||
| 5212 | int space_char_hmotion_node::force_tprint() | |
| 5213 | { | |
| 5214 | return 0; | |
| 5215 | } | |
| 5216 | ||
| 465b256c JR |
5217 | int space_char_hmotion_node::is_tag() |
| 5218 | { | |
| 5219 | return 0; | |
| 5220 | } | |
| 5221 | ||
| 92d0a6a6 JR |
5222 | node *space_char_hmotion_node::add_self(node *nd, hyphen_list **p) |
| 5223 | { | |
| 5224 | next = nd; | |
| 5225 | hyphen_list *pp = *p; | |
| 5226 | *p = (*p)->next; | |
| 5227 | delete pp; | |
| 5228 | return this; | |
| 5229 | } | |
| 5230 | ||
| 5231 | hyphen_list *space_char_hmotion_node::get_hyphen_list(hyphen_list *tail, | |
| 5232 | int *) | |
| 5233 | { | |
| 5234 | return new hyphen_list(0, tail); | |
| 5235 | } | |
| 5236 | ||
| 5237 | int vmotion_node::same(node *nd) | |
| 5238 | { | |
| 5239 | return n == ((vmotion_node *)nd)->n | |
| 5240 | && col == ((vmotion_node *)nd)->col; | |
| 5241 | } | |
| 5242 | ||
| 5243 | const char *vmotion_node::type() | |
| 5244 | { | |
| 5245 | return "vmotion_node"; | |
| 5246 | } | |
| 5247 | ||
| 5248 | int vmotion_node::force_tprint() | |
| 5249 | { | |
| 5250 | return 0; | |
| 5251 | } | |
| 5252 | ||
| 465b256c JR |
5253 | int vmotion_node::is_tag() |
| 5254 | { | |
| 5255 | return 0; | |
| 5256 | } | |
| 5257 | ||
| 92d0a6a6 JR |
5258 | int hline_node::same(node *nd) |
| 5259 | { | |
| 5260 | return x == ((hline_node *)nd)->x && same_node(n, ((hline_node *)nd)->n); | |
| 5261 | } | |
| 5262 | ||
| 5263 | const char *hline_node::type() | |
| 5264 | { | |
| 5265 | return "hline_node"; | |
| 5266 | } | |
| 5267 | ||
| 5268 | int hline_node::force_tprint() | |
| 5269 | { | |
| 5270 | return 0; | |
| 5271 | } | |
| 5272 | ||
| 465b256c JR |
5273 | int hline_node::is_tag() |
| 5274 | { | |
| 5275 | return 0; | |
| 5276 | } | |
| 5277 | ||
| 92d0a6a6 JR |
5278 | int vline_node::same(node *nd) |
| 5279 | { | |
| 5280 | return x == ((vline_node *)nd)->x && same_node(n, ((vline_node *)nd)->n); | |
| 5281 | } | |
| 5282 | ||
| 5283 | const char *vline_node::type() | |
| 5284 | { | |
| 5285 | return "vline_node"; | |
| 5286 | } | |
| 5287 | ||
| 5288 | int vline_node::force_tprint() | |
| 5289 | { | |
| 5290 | return 0; | |
| 5291 | } | |
| 5292 | ||
| 465b256c JR |
5293 | int vline_node::is_tag() |
| 5294 | { | |
| 5295 | return 0; | |
| 5296 | } | |
| 5297 | ||
| 92d0a6a6 JR |
5298 | int dummy_node::same(node * /*nd*/) |
| 5299 | { | |
| 5300 | return 1; | |
| 5301 | } | |
| 5302 | ||
| 5303 | const char *dummy_node::type() | |
| 5304 | { | |
| 5305 | return "dummy_node"; | |
| 5306 | } | |
| 5307 | ||
| 5308 | int dummy_node::force_tprint() | |
| 5309 | { | |
| 5310 | return 0; | |
| 5311 | } | |
| 5312 | ||
| 465b256c JR |
5313 | int dummy_node::is_tag() |
| 5314 | { | |
| 5315 | return 0; | |
| 5316 | } | |
| 5317 | ||
| 92d0a6a6 JR |
5318 | int transparent_dummy_node::same(node * /*nd*/) |
| 5319 | { | |
| 5320 | return 1; | |
| 5321 | } | |
| 5322 | ||
| 5323 | const char *transparent_dummy_node::type() | |
| 5324 | { | |
| 5325 | return "transparent_dummy_node"; | |
| 5326 | } | |
| 5327 | ||
| 5328 | int transparent_dummy_node::force_tprint() | |
| 5329 | { | |
| 5330 | return 0; | |
| 5331 | } | |
| 5332 | ||
| 465b256c JR |
5333 | int transparent_dummy_node::is_tag() |
| 5334 | { | |
| 5335 | return 0; | |
| 5336 | } | |
| 5337 | ||
| 92d0a6a6 JR |
5338 | int transparent_dummy_node::ends_sentence() |
| 5339 | { | |
| 5340 | return 2; | |
| 5341 | } | |
| 5342 | ||
| 5343 | int zero_width_node::same(node *nd) | |
| 5344 | { | |
| 5345 | return same_node_list(n, ((zero_width_node *)nd)->n); | |
| 5346 | } | |
| 5347 | ||
| 5348 | const char *zero_width_node::type() | |
| 5349 | { | |
| 5350 | return "zero_width_node"; | |
| 5351 | } | |
| 5352 | ||
| 5353 | int zero_width_node::force_tprint() | |
| 5354 | { | |
| 5355 | return 0; | |
| 5356 | } | |
| 5357 | ||
| 465b256c JR |
5358 | int zero_width_node::is_tag() |
| 5359 | { | |
| 5360 | return 0; | |
| 5361 | } | |
| 5362 | ||
| 92d0a6a6 JR |
5363 | int italic_corrected_node::same(node *nd) |
| 5364 | { | |
| 5365 | return (x == ((italic_corrected_node *)nd)->x | |
| 5366 | && same_node(n, ((italic_corrected_node *)nd)->n)); | |
| 5367 | } | |
| 5368 | ||
| 5369 | const char *italic_corrected_node::type() | |
| 5370 | { | |
| 5371 | return "italic_corrected_node"; | |
| 5372 | } | |
| 5373 | ||
| 5374 | int italic_corrected_node::force_tprint() | |
| 5375 | { | |
| 5376 | return 0; | |
| 5377 | } | |
| 5378 | ||
| 465b256c JR |
5379 | int italic_corrected_node::is_tag() |
| 5380 | { | |
| 5381 | return 0; | |
| 5382 | } | |
| 5383 | ||
| 92d0a6a6 JR |
5384 | left_italic_corrected_node::left_italic_corrected_node(node *xx) |
| 5385 | : node(xx), n(0) | |
| 5386 | { | |
| 5387 | } | |
| 5388 | ||
| 465b256c JR |
5389 | left_italic_corrected_node::left_italic_corrected_node(statem *s, int pop, |
| 5390 | node *xx) | |
| 5391 | : node(xx, s, pop), n(0) | |
| 5392 | { | |
| 5393 | } | |
| 5394 | ||
| 92d0a6a6 JR |
5395 | left_italic_corrected_node::~left_italic_corrected_node() |
| 5396 | { | |
| 5397 | delete n; | |
| 5398 | } | |
| 5399 | ||
| 5400 | node *left_italic_corrected_node::merge_glyph_node(glyph_node *gn) | |
| 5401 | { | |
| 5402 | if (n == 0) { | |
| 5403 | hunits lic = gn->left_italic_correction(); | |
| 5404 | if (!lic.is_zero()) { | |
| 5405 | x = lic; | |
| 5406 | n = gn; | |
| 5407 | return this; | |
| 5408 | } | |
| 5409 | } | |
| 5410 | else { | |
| 5411 | node *nd = n->merge_glyph_node(gn); | |
| 5412 | if (nd) { | |
| 5413 | n = nd; | |
| 5414 | x = n->left_italic_correction(); | |
| 5415 | return this; | |
| 5416 | } | |
| 5417 | } | |
| 5418 | return 0; | |
| 5419 | } | |
| 5420 | ||
| 5421 | node *left_italic_corrected_node::copy() | |
| 5422 | { | |
| 465b256c JR |
5423 | left_italic_corrected_node *nd = |
| 5424 | new left_italic_corrected_node(state, div_nest_level); | |
| 92d0a6a6 JR |
5425 | if (n) { |
| 5426 | nd->n = n->copy(); | |
| 5427 | nd->x = x; | |
| 5428 | } | |
| 5429 | return nd; | |
| 5430 | } | |
| 5431 | ||
| 5432 | void left_italic_corrected_node::tprint(troff_output_file *out) | |
| 5433 | { | |
| 5434 | if (n) { | |
| 5435 | out->right(x); | |
| 5436 | n->tprint(out); | |
| 5437 | } | |
| 5438 | } | |
| 5439 | ||
| 5440 | const char *left_italic_corrected_node::type() | |
| 5441 | { | |
| 5442 | return "left_italic_corrected_node"; | |
| 5443 | } | |
| 5444 | ||
| 5445 | int left_italic_corrected_node::force_tprint() | |
| 5446 | { | |
| 5447 | return 0; | |
| 5448 | } | |
| 5449 | ||
| 465b256c JR |
5450 | int left_italic_corrected_node::is_tag() |
| 5451 | { | |
| 5452 | return 0; | |
| 5453 | } | |
| 5454 | ||
| 92d0a6a6 JR |
5455 | int left_italic_corrected_node::same(node *nd) |
| 5456 | { | |
| 5457 | return (x == ((left_italic_corrected_node *)nd)->x | |
| 5458 | && same_node(n, ((left_italic_corrected_node *)nd)->n)); | |
| 5459 | } | |
| 5460 | ||
| 5461 | void left_italic_corrected_node::ascii_print(ascii_output_file *out) | |
| 5462 | { | |
| 5463 | if (n) | |
| 5464 | n->ascii_print(out); | |
| 5465 | } | |
| 5466 | ||
| 5467 | hunits left_italic_corrected_node::width() | |
| 5468 | { | |
| 5469 | return n ? n->width() + x : H0; | |
| 5470 | } | |
| 5471 | ||
| 5472 | void left_italic_corrected_node::vertical_extent(vunits *minimum, | |
| 5473 | vunits *maximum) | |
| 5474 | { | |
| 5475 | if (n) | |
| 5476 | n->vertical_extent(minimum, maximum); | |
| 5477 | else | |
| 5478 | node::vertical_extent(minimum, maximum); | |
| 5479 | } | |
| 5480 | ||
| 5481 | hunits left_italic_corrected_node::skew() | |
| 5482 | { | |
| 5483 | return n ? n->skew() + x/2 : H0; | |
| 5484 | } | |
| 5485 | ||
| 5486 | hunits left_italic_corrected_node::subscript_correction() | |
| 5487 | { | |
| 5488 | return n ? n->subscript_correction() : H0; | |
| 5489 | } | |
| 5490 | ||
| 5491 | hunits left_italic_corrected_node::italic_correction() | |
| 5492 | { | |
| 5493 | return n ? n->italic_correction() : H0; | |
| 5494 | } | |
| 5495 | ||
| 5496 | int left_italic_corrected_node::ends_sentence() | |
| 5497 | { | |
| 5498 | return n ? n->ends_sentence() : 0; | |
| 5499 | } | |
| 5500 | ||
| 5501 | int left_italic_corrected_node::overlaps_horizontally() | |
| 5502 | { | |
| 5503 | return n ? n->overlaps_horizontally() : 0; | |
| 5504 | } | |
| 5505 | ||
| 5506 | int left_italic_corrected_node::overlaps_vertically() | |
| 5507 | { | |
| 5508 | return n ? n->overlaps_vertically() : 0; | |
| 5509 | } | |
| 5510 | ||
| 5511 | node *left_italic_corrected_node::last_char_node() | |
| 5512 | { | |
| 5513 | return n ? n->last_char_node() : 0; | |
| 5514 | } | |
| 5515 | ||
| 5516 | tfont *left_italic_corrected_node::get_tfont() | |
| 5517 | { | |
| 5518 | return n ? n->get_tfont() : 0; | |
| 5519 | } | |
| 5520 | ||
| 5521 | hyphenation_type left_italic_corrected_node::get_hyphenation_type() | |
| 5522 | { | |
| 5523 | if (n) | |
| 5524 | return n->get_hyphenation_type(); | |
| 5525 | else | |
| 5526 | return HYPHEN_MIDDLE; | |
| 5527 | } | |
| 5528 | ||
| 5529 | hyphen_list *left_italic_corrected_node::get_hyphen_list(hyphen_list *tail, | |
| 5530 | int *count) | |
| 5531 | { | |
| 5532 | return n ? n->get_hyphen_list(tail, count) : tail; | |
| 5533 | } | |
| 5534 | ||
| 5535 | node *left_italic_corrected_node::add_self(node *nd, hyphen_list **p) | |
| 5536 | { | |
| 5537 | if (n) { | |
| 465b256c | 5538 | nd = new left_italic_corrected_node(state, div_nest_level, nd); |
| 92d0a6a6 JR |
5539 | nd = n->add_self(nd, p); |
| 5540 | n = 0; | |
| 5541 | delete this; | |
| 4d3e9548 JL |
5542 | return nd; |
| 5543 | } | |
| 5544 | else { | |
| 5545 | next = nd; | |
| 5546 | return this; | |
| 92d0a6a6 | 5547 | } |
| 92d0a6a6 JR |
5548 | } |
| 5549 | ||
| 5550 | int left_italic_corrected_node::character_type() | |
| 5551 | { | |
| 5552 | return n ? n->character_type() : 0; | |
| 5553 | } | |
| 5554 | ||
| 5555 | int overstrike_node::same(node *nd) | |
| 5556 | { | |
| 5557 | return same_node_list(list, ((overstrike_node *)nd)->list); | |
| 5558 | } | |
| 5559 | ||
| 5560 | const char *overstrike_node::type() | |
| 5561 | { | |
| 5562 | return "overstrike_node"; | |
| 5563 | } | |
| 5564 | ||
| 5565 | int overstrike_node::force_tprint() | |
| 5566 | { | |
| 5567 | return 0; | |
| 5568 | } | |
| 5569 | ||
| 465b256c JR |
5570 | int overstrike_node::is_tag() |
| 5571 | { | |
| 5572 | return 0; | |
| 5573 | } | |
| 5574 | ||
| 92d0a6a6 JR |
5575 | node *overstrike_node::add_self(node *n, hyphen_list **p) |
| 5576 | { | |
| 5577 | next = n; | |
| 5578 | hyphen_list *pp = *p; | |
| 5579 | *p = (*p)->next; | |
| 5580 | delete pp; | |
| 5581 | return this; | |
| 5582 | } | |
| 5583 | ||
| 5584 | hyphen_list *overstrike_node::get_hyphen_list(hyphen_list *tail, int *) | |
| 5585 | { | |
| 5586 | return new hyphen_list(0, tail); | |
| 5587 | } | |
| 5588 | ||
| 5589 | int bracket_node::same(node *nd) | |
| 5590 | { | |
| 5591 | return same_node_list(list, ((bracket_node *)nd)->list); | |
| 5592 | } | |
| 5593 | ||
| 5594 | const char *bracket_node::type() | |
| 5595 | { | |
| 5596 | return "bracket_node"; | |
| 5597 | } | |
| 5598 | ||
| 5599 | int bracket_node::force_tprint() | |
| 5600 | { | |
| 5601 | return 0; | |
| 5602 | } | |
| 5603 | ||
| 465b256c JR |
5604 | int bracket_node::is_tag() |
| 5605 | { | |
| 5606 | return 0; | |
| 5607 | } | |
| 5608 | ||
| 92d0a6a6 JR |
5609 | int composite_node::same(node *nd) |
| 5610 | { | |
| 5611 | return ci == ((composite_node *)nd)->ci | |
| 5612 | && same_node_list(n, ((composite_node *)nd)->n); | |
| 5613 | } | |
| 5614 | ||
| 5615 | const char *composite_node::type() | |
| 5616 | { | |
| 5617 | return "composite_node"; | |
| 5618 | } | |
| 5619 | ||
| 5620 | int composite_node::force_tprint() | |
| 5621 | { | |
| 5622 | return 0; | |
| 5623 | } | |
| 5624 | ||
| 465b256c JR |
5625 | int composite_node::is_tag() |
| 5626 | { | |
| 5627 | return 0; | |
| 5628 | } | |
| 5629 | ||
| 92d0a6a6 JR |
5630 | int glyph_node::same(node *nd) |
| 5631 | { | |
| 5632 | return ci == ((glyph_node *)nd)->ci | |
| 5633 | && tf == ((glyph_node *)nd)->tf | |
| 5634 | && gcol == ((glyph_node *)nd)->gcol | |
| 5635 | && fcol == ((glyph_node *)nd)->fcol; | |
| 5636 | } | |
| 5637 | ||
| 5638 | const char *glyph_node::type() | |
| 5639 | { | |
| 5640 | return "glyph_node"; | |
| 5641 | } | |
| 5642 | ||
| 5643 | int glyph_node::force_tprint() | |
| 5644 | { | |
| 5645 | return 0; | |
| 5646 | } | |
| 5647 | ||
| 465b256c JR |
5648 | int glyph_node::is_tag() |
| 5649 | { | |
| 5650 | return 0; | |
| 5651 | } | |
| 5652 | ||
| 92d0a6a6 JR |
5653 | int ligature_node::same(node *nd) |
| 5654 | { | |
| 5655 | return (same_node(n1, ((ligature_node *)nd)->n1) | |
| 5656 | && same_node(n2, ((ligature_node *)nd)->n2) | |
| 5657 | && glyph_node::same(nd)); | |
| 5658 | } | |
| 5659 | ||
| 5660 | const char *ligature_node::type() | |
| 5661 | { | |
| 5662 | return "ligature_node"; | |
| 5663 | } | |
| 5664 | ||
| 5665 | int ligature_node::force_tprint() | |
| 5666 | { | |
| 5667 | return 0; | |
| 5668 | } | |
| 5669 | ||
| 465b256c JR |
5670 | int ligature_node::is_tag() |
| 5671 | { | |
| 5672 | return 0; | |
| 5673 | } | |
| 5674 | ||
| 92d0a6a6 JR |
5675 | int kern_pair_node::same(node *nd) |
| 5676 | { | |
| 5677 | return (amount == ((kern_pair_node *)nd)->amount | |
| 5678 | && same_node(n1, ((kern_pair_node *)nd)->n1) | |
| 5679 | && same_node(n2, ((kern_pair_node *)nd)->n2)); | |
| 5680 | } | |
| 5681 | ||
| 5682 | const char *kern_pair_node::type() | |
| 5683 | { | |
| 5684 | return "kern_pair_node"; | |
| 5685 | } | |
| 5686 | ||
| 5687 | int kern_pair_node::force_tprint() | |
| 5688 | { | |
| 5689 | return 0; | |
| 5690 | } | |
| 5691 | ||
| 465b256c JR |
5692 | int kern_pair_node::is_tag() |
| 5693 | { | |
| 5694 | return 0; | |
| 5695 | } | |
| 5696 | ||
| 92d0a6a6 JR |
5697 | int dbreak_node::same(node *nd) |
| 5698 | { | |
| 5699 | return (same_node_list(none, ((dbreak_node *)nd)->none) | |
| 5700 | && same_node_list(pre, ((dbreak_node *)nd)->pre) | |
| 5701 | && same_node_list(post, ((dbreak_node *)nd)->post)); | |
| 5702 | } | |
| 5703 | ||
| 5704 | const char *dbreak_node::type() | |
| 5705 | { | |
| 5706 | return "dbreak_node"; | |
| 5707 | } | |
| 5708 | ||
| 5709 | int dbreak_node::force_tprint() | |
| 5710 | { | |
| 5711 | return 0; | |
| 5712 | } | |
| 5713 | ||
| 465b256c JR |
5714 | int dbreak_node::is_tag() |
| 5715 | { | |
| 5716 | return 0; | |
| 5717 | } | |
| 5718 | ||
| 92d0a6a6 JR |
5719 | int break_char_node::same(node *nd) |
| 5720 | { | |
| 5721 | return break_code == ((break_char_node *)nd)->break_code | |
| 5722 | && col == ((break_char_node *)nd)->col | |
| 5723 | && same_node(ch, ((break_char_node *)nd)->ch); | |
| 5724 | } | |
| 5725 | ||
| 5726 | const char *break_char_node::type() | |
| 5727 | { | |
| 5728 | return "break_char_node"; | |
| 5729 | } | |
| 5730 | ||
| 5731 | int break_char_node::force_tprint() | |
| 5732 | { | |
| 5733 | return 0; | |
| 5734 | } | |
| 5735 | ||
| 465b256c JR |
5736 | int break_char_node::is_tag() |
| 5737 | { | |
| 5738 | return 0; | |
| 5739 | } | |
| 5740 | ||
| 92d0a6a6 JR |
5741 | int line_start_node::same(node * /*nd*/) |
| 5742 | { | |
| 5743 | return 1; | |
| 5744 | } | |
| 5745 | ||
| 5746 | const char *line_start_node::type() | |
| 5747 | { | |
| 5748 | return "line_start_node"; | |
| 5749 | } | |
| 5750 | ||
| 5751 | int line_start_node::force_tprint() | |
| 5752 | { | |
| 5753 | return 0; | |
| 5754 | } | |
| 5755 | ||
| 465b256c JR |
5756 | int line_start_node::is_tag() |
| 5757 | { | |
| 5758 | return 0; | |
| 5759 | } | |
| 5760 | ||
| 92d0a6a6 JR |
5761 | int space_node::same(node *nd) |
| 5762 | { | |
| 5763 | return n == ((space_node *)nd)->n | |
| 5764 | && set == ((space_node *)nd)->set | |
| 5765 | && col == ((space_node *)nd)->col; | |
| 5766 | } | |
| 5767 | ||
| 5768 | const char *space_node::type() | |
| 5769 | { | |
| 5770 | return "space_node"; | |
| 5771 | } | |
| 5772 | ||
| 5773 | int word_space_node::same(node *nd) | |
| 5774 | { | |
| 5775 | return n == ((word_space_node *)nd)->n | |
| 5776 | && set == ((word_space_node *)nd)->set | |
| 5777 | && col == ((word_space_node *)nd)->col; | |
| 5778 | } | |
| 5779 | ||
| 5780 | const char *word_space_node::type() | |
| 5781 | { | |
| 5782 | return "word_space_node"; | |
| 5783 | } | |
| 5784 | ||
| 5785 | int word_space_node::force_tprint() | |
| 5786 | { | |
| 5787 | return 0; | |
| 5788 | } | |
| 5789 | ||
| 465b256c JR |
5790 | int word_space_node::is_tag() |
| 5791 | { | |
| 5792 | return 0; | |
| 5793 | } | |
| 5794 | ||
| 92d0a6a6 JR |
5795 | void unbreakable_space_node::tprint(troff_output_file *out) |
| 5796 | { | |
| 5797 | out->fill_color(col); | |
| 5798 | if (is_html) { | |
| 5799 | // we emit the space width as a negative glyph index | |
| 5800 | out->flush_tbuf(); | |
| 5801 | out->do_motion(); | |
| 5802 | out->put('N'); | |
| 5803 | out->put(-n.to_units()); | |
| 5804 | out->put('\n'); | |
| 5805 | } | |
| 5806 | out->right(n); | |
| 5807 | } | |
| 5808 | ||
| 5809 | int unbreakable_space_node::same(node *nd) | |
| 5810 | { | |
| 5811 | return n == ((unbreakable_space_node *)nd)->n | |
| 5812 | && set == ((unbreakable_space_node *)nd)->set | |
| 5813 | && col == ((unbreakable_space_node *)nd)->col; | |
| 5814 | } | |
| 5815 | ||
| 5816 | const char *unbreakable_space_node::type() | |
| 5817 | { | |
| 5818 | return "unbreakable_space_node"; | |
| 5819 | } | |
| 5820 | ||
| 5821 | node *unbreakable_space_node::add_self(node *nd, hyphen_list **p) | |
| 5822 | { | |
| 5823 | next = nd; | |
| 5824 | hyphen_list *pp = *p; | |
| 5825 | *p = (*p)->next; | |
| 5826 | delete pp; | |
| 5827 | return this; | |
| 5828 | } | |
| 5829 | ||
| 5830 | hyphen_list *unbreakable_space_node::get_hyphen_list(hyphen_list *tail, int *) | |
| 5831 | { | |
| 5832 | return new hyphen_list(0, tail); | |
| 5833 | } | |
| 5834 | ||
| 5835 | int diverted_space_node::same(node *nd) | |
| 5836 | { | |
| 5837 | return n == ((diverted_space_node *)nd)->n; | |
| 5838 | } | |
| 5839 | ||
| 5840 | const char *diverted_space_node::type() | |
| 5841 | { | |
| 5842 | return "diverted_space_node"; | |
| 5843 | } | |
| 5844 | ||
| 5845 | int diverted_space_node::force_tprint() | |
| 5846 | { | |
| 5847 | return 0; | |
| 5848 | } | |
| 5849 | ||
| 465b256c JR |
5850 | int diverted_space_node::is_tag() |
| 5851 | { | |
| 5852 | return 0; | |
| 5853 | } | |
| 5854 | ||
| 92d0a6a6 JR |
5855 | int diverted_copy_file_node::same(node *nd) |
| 5856 | { | |
| 5857 | return filename == ((diverted_copy_file_node *)nd)->filename; | |
| 5858 | } | |
| 5859 | ||
| 5860 | const char *diverted_copy_file_node::type() | |
| 5861 | { | |
| 5862 | return "diverted_copy_file_node"; | |
| 5863 | } | |
| 5864 | ||
| 5865 | int diverted_copy_file_node::force_tprint() | |
| 5866 | { | |
| 5867 | return 0; | |
| 5868 | } | |
| 5869 | ||
| 465b256c JR |
5870 | int diverted_copy_file_node::is_tag() |
| 5871 | { | |
| 5872 | return 0; | |
| 5873 | } | |
| 5874 | ||
| 92d0a6a6 JR |
5875 | // Grow the font_table so that its size is > n. |
| 5876 | ||
| 5877 | static void grow_font_table(int n) | |
| 5878 | { | |
| 5879 | assert(n >= font_table_size); | |
| 5880 | font_info **old_font_table = font_table; | |
| 5881 | int old_font_table_size = font_table_size; | |
| 5882 | font_table_size = font_table_size ? (font_table_size*3)/2 : 10; | |
| 5883 | if (font_table_size <= n) | |
| 5884 | font_table_size = n + 10; | |
| 5885 | font_table = new font_info *[font_table_size]; | |
| 5886 | if (old_font_table_size) | |
| 5887 | memcpy(font_table, old_font_table, | |
| 5888 | old_font_table_size*sizeof(font_info *)); | |
| 5889 | a_delete old_font_table; | |
| 5890 | for (int i = old_font_table_size; i < font_table_size; i++) | |
| 5891 | font_table[i] = 0; | |
| 5892 | } | |
| 5893 | ||
| 5894 | dictionary font_translation_dictionary(17); | |
| 5895 | ||
| 5896 | static symbol get_font_translation(symbol nm) | |
| 5897 | { | |
| 5898 | void *p = font_translation_dictionary.lookup(nm); | |
| 5899 | return p ? symbol((char *)p) : nm; | |
| 5900 | } | |
| 5901 | ||
| 5902 | dictionary font_dictionary(50); | |
| 5903 | ||
| 465b256c JR |
5904 | static int mount_font_no_translate(int n, symbol name, symbol external_name, |
| 5905 | int check_only = 0) | |
| 92d0a6a6 JR |
5906 | { |
| 5907 | assert(n >= 0); | |
| 5908 | // We store the address of this char in font_dictionary to indicate | |
| 5909 | // that we've previously tried to mount the font and failed. | |
| 5910 | static char a_char; | |
| 5911 | font *fm = 0; | |
| 5912 | void *p = font_dictionary.lookup(external_name); | |
| 5913 | if (p == 0) { | |
| 5914 | int not_found; | |
| 465b256c JR |
5915 | fm = font::load_font(external_name.contents(), ¬_found, check_only); |
| 5916 | if (check_only) | |
| 5917 | return fm != 0; | |
| 92d0a6a6 JR |
5918 | if (!fm) { |
| 5919 | if (not_found) | |
| 5920 | warning(WARN_FONT, "can't find font `%1'", external_name.contents()); | |
| 5921 | (void)font_dictionary.lookup(external_name, &a_char); | |
| 5922 | return 0; | |
| 5923 | } | |
| 5924 | (void)font_dictionary.lookup(name, fm); | |
| 5925 | } | |
| 5926 | else if (p == &a_char) { | |
| 5927 | #if 0 | |
| 5928 | error("invalid font `%1'", external_name.contents()); | |
| 5929 | #endif | |
| 5930 | return 0; | |
| 5931 | } | |
| 5932 | else | |
| 5933 | fm = (font*)p; | |
| 465b256c JR |
5934 | if (check_only) |
| 5935 | return 1; | |
| 92d0a6a6 JR |
5936 | if (n >= font_table_size) { |
| 5937 | if (n - font_table_size > 1000) { | |
| 5938 | error("font position too much larger than first unused position"); | |
| 5939 | return 0; | |
| 5940 | } | |
| 5941 | grow_font_table(n); | |
| 5942 | } | |
| 5943 | else if (font_table[n] != 0) | |
| 5944 | delete font_table[n]; | |
| 5945 | font_table[n] = new font_info(name, n, external_name, fm); | |
| 5946 | font_family::invalidate_fontno(n); | |
| 5947 | return 1; | |
| 5948 | } | |
| 5949 | ||
| 5950 | int mount_font(int n, symbol name, symbol external_name) | |
| 5951 | { | |
| 5952 | assert(n >= 0); | |
| 5953 | name = get_font_translation(name); | |
| 5954 | if (external_name.is_null()) | |
| 5955 | external_name = name; | |
| 5956 | else | |
| 5957 | external_name = get_font_translation(external_name); | |
| 5958 | return mount_font_no_translate(n, name, external_name); | |
| 5959 | } | |
| 5960 | ||
| 465b256c JR |
5961 | int check_font(symbol fam, symbol name) |
| 5962 | { | |
| 5963 | if (check_style(name)) | |
| 5964 | name = concat(fam, name); | |
| 5965 | return mount_font_no_translate(0, name, name, 1); | |
| 5966 | } | |
| 5967 | ||
| 5968 | int check_style(symbol s) | |
| 5969 | { | |
| 5970 | int i = symbol_fontno(s); | |
| 5971 | return i < 0 ? 0 : font_table[i]->is_style(); | |
| 5972 | } | |
| 5973 | ||
| 92d0a6a6 JR |
5974 | void mount_style(int n, symbol name) |
| 5975 | { | |
| 5976 | assert(n >= 0); | |
| 5977 | if (n >= font_table_size) { | |
| 5978 | if (n - font_table_size > 1000) { | |
| 5979 | error("font position too much larger than first unused position"); | |
| 5980 | return; | |
| 5981 | } | |
| 5982 | grow_font_table(n); | |
| 5983 | } | |
| 5984 | else if (font_table[n] != 0) | |
| 5985 | delete font_table[n]; | |
| 5986 | font_table[n] = new font_info(get_font_translation(name), n, NULL_SYMBOL, 0); | |
| 5987 | font_family::invalidate_fontno(n); | |
| 5988 | } | |
| 5989 | ||
| 5990 | /* global functions */ | |
| 5991 | ||
| 5992 | void font_translate() | |
| 5993 | { | |
| 5994 | symbol from = get_name(1); | |
| 5995 | if (!from.is_null()) { | |
| 5996 | symbol to = get_name(); | |
| 5997 | if (to.is_null() || from == to) | |
| 5998 | font_translation_dictionary.remove(from); | |
| 5999 | else | |
| 6000 | (void)font_translation_dictionary.lookup(from, (void *)to.contents()); | |
| 6001 | } | |
| 6002 | skip_line(); | |
| 6003 | } | |
| 6004 | ||
| 6005 | void font_position() | |
| 6006 | { | |
| 6007 | int n; | |
| 6008 | if (get_integer(&n)) { | |
| 6009 | if (n < 0) | |
| 6010 | error("negative font position"); | |
| 6011 | else { | |
| 6012 | symbol internal_name = get_name(1); | |
| 6013 | if (!internal_name.is_null()) { | |
| 6014 | symbol external_name = get_long_name(); | |
| 6015 | mount_font(n, internal_name, external_name); // ignore error | |
| 6016 | } | |
| 6017 | } | |
| 6018 | } | |
| 6019 | skip_line(); | |
| 6020 | } | |
| 6021 | ||
| 6022 | font_family::font_family(symbol s) | |
| 6023 | : map_size(10), nm(s) | |
| 6024 | { | |
| 6025 | map = new int[map_size]; | |
| 6026 | for (int i = 0; i < map_size; i++) | |
| 6027 | map[i] = -1; | |
| 6028 | } | |
| 6029 | ||
| 6030 | font_family::~font_family() | |
| 6031 | { | |
| 6032 | a_delete map; | |
| 6033 | } | |
| 6034 | ||
| 6035 | int font_family::make_definite(int i) | |
| 6036 | { | |
| 6037 | if (i >= 0) { | |
| 6038 | if (i < map_size && map[i] >= 0) | |
| 6039 | return map[i]; | |
| 6040 | else { | |
| 6041 | if (i < font_table_size && font_table[i] != 0) { | |
| 6042 | if (i >= map_size) { | |
| 6043 | int old_map_size = map_size; | |
| 6044 | int *old_map = map; | |
| 6045 | map_size *= 3; | |
| 6046 | map_size /= 2; | |
| 6047 | if (i >= map_size) | |
| 6048 | map_size = i + 10; | |
| 6049 | map = new int[map_size]; | |
| 6050 | memcpy(map, old_map, old_map_size*sizeof(int)); | |
| 6051 | a_delete old_map; | |
| 6052 | for (int j = old_map_size; j < map_size; j++) | |
| 6053 | map[j] = -1; | |
| 6054 | } | |
| 6055 | if (font_table[i]->is_style()) { | |
| 6056 | symbol sty = font_table[i]->get_name(); | |
| 6057 | symbol f = concat(nm, sty); | |
| 6058 | int n; | |
| 6059 | // don't use symbol_fontno, because that might return a style | |
| 6060 | // and because we don't want to translate the name | |
| 6061 | for (n = 0; n < font_table_size; n++) | |
| 6062 | if (font_table[n] != 0 && font_table[n]->is_named(f) | |
| 6063 | && !font_table[n]->is_style()) | |
| 6064 | break; | |
| 6065 | if (n >= font_table_size) { | |
| 6066 | n = next_available_font_position(); | |
| 6067 | if (!mount_font_no_translate(n, f, f)) | |
| 6068 | return -1; | |
| 6069 | } | |
| 6070 | return map[i] = n; | |
| 6071 | } | |
| 6072 | else | |
| 6073 | return map[i] = i; | |
| 6074 | } | |
| 6075 | else | |
| 6076 | return -1; | |
| 6077 | } | |
| 6078 | } | |
| 6079 | else | |
| 6080 | return -1; | |
| 6081 | } | |
| 6082 | ||
| 6083 | dictionary family_dictionary(5); | |
| 6084 | ||
| 6085 | font_family *lookup_family(symbol nm) | |
| 6086 | { | |
| 6087 | font_family *f = (font_family *)family_dictionary.lookup(nm); | |
| 6088 | if (!f) { | |
| 6089 | f = new font_family(nm); | |
| 6090 | (void)family_dictionary.lookup(nm, f); | |
| 6091 | } | |
| 6092 | return f; | |
| 6093 | } | |
| 6094 | ||
| 6095 | void font_family::invalidate_fontno(int n) | |
| 6096 | { | |
| 6097 | assert(n >= 0 && n < font_table_size); | |
| 6098 | dictionary_iterator iter(family_dictionary); | |
| 6099 | symbol nam; | |
| 6100 | font_family *fam; | |
| 6101 | while (iter.get(&nam, (void **)&fam)) { | |
| 6102 | int mapsize = fam->map_size; | |
| 6103 | if (n < mapsize) | |
| 6104 | fam->map[n] = -1; | |
| 6105 | for (int i = 0; i < mapsize; i++) | |
| 6106 | if (fam->map[i] == n) | |
| 6107 | fam->map[i] = -1; | |
| 6108 | } | |
| 6109 | } | |
| 6110 | ||
| 6111 | void style() | |
| 6112 | { | |
| 6113 | int n; | |
| 6114 | if (get_integer(&n)) { | |
| 6115 | if (n < 0) | |
| 6116 | error("negative font position"); | |
| 6117 | else { | |
| 6118 | symbol internal_name = get_name(1); | |
| 6119 | if (!internal_name.is_null()) | |
| 6120 | mount_style(n, internal_name); | |
| 6121 | } | |
| 6122 | } | |
| 6123 | skip_line(); | |
| 6124 | } | |
| 6125 | ||
| 6126 | static int get_fontno() | |
| 6127 | { | |
| 6128 | int n; | |
| 6129 | tok.skip(); | |
| 6130 | if (tok.delimiter()) { | |
| 6131 | symbol s = get_name(1); | |
| 6132 | if (!s.is_null()) { | |
| 6133 | n = symbol_fontno(s); | |
| 6134 | if (n < 0) { | |
| 6135 | n = next_available_font_position(); | |
| 6136 | if (!mount_font(n, s)) | |
| 6137 | return -1; | |
| 6138 | } | |
| 6139 | return curenv->get_family()->make_definite(n); | |
| 6140 | } | |
| 6141 | } | |
| 6142 | else if (get_integer(&n)) { | |
| 6143 | if (n < 0 || n >= font_table_size || font_table[n] == 0) | |
| 6144 | error("bad font number"); | |
| 6145 | else | |
| 6146 | return curenv->get_family()->make_definite(n); | |
| 6147 | } | |
| 6148 | return -1; | |
| 6149 | } | |
| 6150 | ||
| 6151 | static int underline_fontno = 2; | |
| 6152 | ||
| 6153 | void underline_font() | |
| 6154 | { | |
| 6155 | int n = get_fontno(); | |
| 6156 | if (n >= 0) | |
| 6157 | underline_fontno = n; | |
| 6158 | skip_line(); | |
| 6159 | } | |
| 6160 | ||
| 6161 | int get_underline_fontno() | |
| 6162 | { | |
| 6163 | return underline_fontno; | |
| 6164 | } | |
| 6165 | ||
| 6166 | void define_font_special_character() | |
| 6167 | { | |
| 6168 | int n = get_fontno(); | |
| 6169 | if (n < 0) { | |
| 6170 | skip_line(); | |
| 6171 | return; | |
| 6172 | } | |
| 6173 | symbol f = font_table[n]->get_name(); | |
| 6174 | do_define_character(CHAR_FONT_SPECIAL, f.contents()); | |
| 6175 | } | |
| 6176 | ||
| 6177 | void remove_font_special_character() | |
| 6178 | { | |
| 6179 | int n = get_fontno(); | |
| 6180 | if (n < 0) { | |
| 6181 | skip_line(); | |
| 6182 | return; | |
| 6183 | } | |
| 6184 | symbol f = font_table[n]->get_name(); | |
| 6185 | while (!tok.newline() && !tok.eof()) { | |
| 6186 | if (!tok.space() && !tok.tab()) { | |
| 6187 | charinfo *s = tok.get_char(1); | |
| 6188 | string gl(f.contents()); | |
| 6189 | gl += ' '; | |
| 6190 | gl += s->nm.contents(); | |
| 6191 | gl += '\0'; | |
| 6192 | charinfo *ci = get_charinfo(symbol(gl.contents())); | |
| 6193 | if (!ci) | |
| 6194 | break; | |
| 6195 | macro *m = ci->set_macro(0); | |
| 6196 | if (m) | |
| 6197 | delete m; | |
| 6198 | } | |
| 6199 | tok.next(); | |
| 6200 | } | |
| 6201 | skip_line(); | |
| 6202 | } | |
| 6203 | ||
| 6204 | static void read_special_fonts(special_font_list **sp) | |
| 6205 | { | |
| 6206 | special_font_list *s = *sp; | |
| 6207 | *sp = 0; | |
| 6208 | while (s != 0) { | |
| 6209 | special_font_list *tem = s; | |
| 6210 | s = s->next; | |
| 6211 | delete tem; | |
| 6212 | } | |
| 6213 | special_font_list **p = sp; | |
| 6214 | while (has_arg()) { | |
| 6215 | int i = get_fontno(); | |
| 6216 | if (i >= 0) { | |
| 6217 | special_font_list *tem = new special_font_list; | |
| 6218 | tem->n = i; | |
| 6219 | tem->next = 0; | |
| 6220 | *p = tem; | |
| 6221 | p = &(tem->next); | |
| 6222 | } | |
| 6223 | } | |
| 6224 | } | |
| 6225 | ||
| 6226 | void font_special_request() | |
| 6227 | { | |
| 6228 | int n = get_fontno(); | |
| 6229 | if (n >= 0) | |
| 6230 | read_special_fonts(&font_table[n]->sf); | |
| 6231 | skip_line(); | |
| 6232 | } | |
| 6233 | ||
| 6234 | void special_request() | |
| 6235 | { | |
| 6236 | read_special_fonts(&global_special_fonts); | |
| 6237 | skip_line(); | |
| 6238 | } | |
| 6239 | ||
| 4d3e9548 JL |
6240 | void font_zoom_request() |
| 6241 | { | |
| 6242 | int n = get_fontno(); | |
| 6243 | if (n >= 0) { | |
| 6244 | if (font_table[n]->is_style()) | |
| 6245 | warning(WARN_FONT, "can't set zoom factor for a style"); | |
| 6246 | else { | |
| 6247 | int zoom; | |
| 6248 | if (has_arg() && get_integer(&zoom)) { | |
| 6249 | if (zoom < 0) | |
| 6250 | warning(WARN_FONT, "can't use negative zoom factor"); | |
| 6251 | else | |
| 6252 | font_table[n]->set_zoom(zoom); | |
| 6253 | } | |
| 6254 | else | |
| 6255 | font_table[n]->set_zoom(0); | |
| 6256 | } | |
| 6257 | } | |
| 6258 | skip_line(); | |
| 6259 | } | |
| 6260 | ||
| 92d0a6a6 JR |
6261 | int next_available_font_position() |
| 6262 | { | |
| 6263 | int i; | |
| 6264 | for (i = 1; i < font_table_size && font_table[i] != 0; i++) | |
| 6265 | ; | |
| 6266 | return i; | |
| 6267 | } | |
| 6268 | ||
| 6269 | int symbol_fontno(symbol s) | |
| 6270 | { | |
| 6271 | s = get_font_translation(s); | |
| 6272 | for (int i = 0; i < font_table_size; i++) | |
| 6273 | if (font_table[i] != 0 && font_table[i]->is_named(s)) | |
| 6274 | return i; | |
| 6275 | return -1; | |
| 6276 | } | |
| 6277 | ||
| 6278 | int is_good_fontno(int n) | |
| 6279 | { | |
| 6280 | return n >= 0 && n < font_table_size && font_table[n] != 0; | |
| 6281 | } | |
| 6282 | ||
| 6283 | int get_bold_fontno(int n) | |
| 6284 | { | |
| 6285 | if (n >= 0 && n < font_table_size && font_table[n] != 0) { | |
| 6286 | hunits offset; | |
| 6287 | if (font_table[n]->get_bold(&offset)) | |
| 6288 | return offset.to_units() + 1; | |
| 6289 | else | |
| 6290 | return 0; | |
| 6291 | } | |
| 6292 | else | |
| 6293 | return 0; | |
| 6294 | } | |
| 6295 | ||
| 6296 | hunits env_digit_width(environment *env) | |
| 6297 | { | |
| 6298 | node *n = make_glyph_node(charset_table['0'], env); | |
| 6299 | if (n) { | |
| 6300 | hunits x = n->width(); | |
| 6301 | delete n; | |
| 6302 | return x; | |
| 6303 | } | |
| 6304 | else | |
| 6305 | return H0; | |
| 6306 | } | |
| 6307 | ||
| 6308 | hunits env_space_width(environment *env) | |
| 6309 | { | |
| 6310 | int fn = env_definite_font(env); | |
| 6311 | font_size fs = env->get_font_size(); | |
| 6312 | if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) | |
| 6313 | return scale(fs.to_units()/3, env->get_space_size(), 12); | |
| 6314 | else | |
| 6315 | return font_table[fn]->get_space_width(fs, env->get_space_size()); | |
| 6316 | } | |
| 6317 | ||
| 6318 | hunits env_sentence_space_width(environment *env) | |
| 6319 | { | |
| 6320 | int fn = env_definite_font(env); | |
| 6321 | font_size fs = env->get_font_size(); | |
| 6322 | if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) | |
| 6323 | return scale(fs.to_units()/3, env->get_sentence_space_size(), 12); | |
| 6324 | else | |
| 6325 | return font_table[fn]->get_space_width(fs, env->get_sentence_space_size()); | |
| 6326 | } | |
| 6327 | ||
| 6328 | hunits env_half_narrow_space_width(environment *env) | |
| 6329 | { | |
| 6330 | int fn = env_definite_font(env); | |
| 6331 | font_size fs = env->get_font_size(); | |
| 6332 | if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) | |
| 6333 | return 0; | |
| 6334 | else | |
| 6335 | return font_table[fn]->get_half_narrow_space_width(fs); | |
| 6336 | } | |
| 6337 | ||
| 6338 | hunits env_narrow_space_width(environment *env) | |
| 6339 | { | |
| 6340 | int fn = env_definite_font(env); | |
| 6341 | font_size fs = env->get_font_size(); | |
| 6342 | if (fn < 0 || fn >= font_table_size || font_table[fn] == 0) | |
| 6343 | return 0; | |
| 6344 | else | |
| 6345 | return font_table[fn]->get_narrow_space_width(fs); | |
| 6346 | } | |
| 6347 | ||
| 6348 | void bold_font() | |
| 6349 | { | |
| 6350 | int n = get_fontno(); | |
| 6351 | if (n >= 0) { | |
| 6352 | if (has_arg()) { | |
| 6353 | if (tok.delimiter()) { | |
| 6354 | int f = get_fontno(); | |
| 6355 | if (f >= 0) { | |
| 6356 | units offset; | |
| 6357 | if (has_arg() && get_number(&offset, 'u') && offset >= 1) | |
| 6358 | font_table[f]->set_conditional_bold(n, hunits(offset - 1)); | |
| 6359 | else | |
| 6360 | font_table[f]->conditional_unbold(n); | |
| 6361 | } | |
| 6362 | } | |
| 6363 | else { | |
| 6364 | units offset; | |
| 6365 | if (get_number(&offset, 'u') && offset >= 1) | |
| 6366 | font_table[n]->set_bold(hunits(offset - 1)); | |
| 6367 | else | |
| 6368 | font_table[n]->unbold(); | |
| 6369 | } | |
| 6370 | } | |
| 6371 | else | |
| 6372 | font_table[n]->unbold(); | |
| 6373 | } | |
| 6374 | skip_line(); | |
| 6375 | } | |
| 6376 | ||
| 6377 | track_kerning_function::track_kerning_function() : non_zero(0) | |
| 6378 | { | |
| 6379 | } | |
| 6380 | ||
| 6381 | track_kerning_function::track_kerning_function(int min_s, hunits min_a, | |
| 6382 | int max_s, hunits max_a) | |
| 6383 | : non_zero(1), min_size(min_s), min_amount(min_a), max_size(max_s), | |
| 6384 | max_amount(max_a) | |
| 6385 | { | |
| 6386 | } | |
| 6387 | ||
| 6388 | int track_kerning_function::operator==(const track_kerning_function &tk) | |
| 6389 | { | |
| 6390 | if (non_zero) | |
| 6391 | return (tk.non_zero | |
| 6392 | && min_size == tk.min_size | |
| 6393 | && min_amount == tk.min_amount | |
| 6394 | && max_size == tk.max_size | |
| 6395 | && max_amount == tk.max_amount); | |
| 6396 | else | |
| 6397 | return !tk.non_zero; | |
| 6398 | } | |
| 6399 | ||
| 6400 | int track_kerning_function::operator!=(const track_kerning_function &tk) | |
| 6401 | { | |
| 6402 | if (non_zero) | |
| 6403 | return (!tk.non_zero | |
| 6404 | || min_size != tk.min_size | |
| 6405 | || min_amount != tk.min_amount | |
| 6406 | || max_size != tk.max_size | |
| 6407 | || max_amount != tk.max_amount); | |
| 6408 | else | |
| 6409 | return tk.non_zero; | |
| 6410 | } | |
| 6411 | ||
| 6412 | hunits track_kerning_function::compute(int size) | |
| 6413 | { | |
| 6414 | if (non_zero) { | |
| 6415 | if (max_size <= min_size) | |
| 6416 | return min_amount; | |
| 6417 | else if (size <= min_size) | |
| 6418 | return min_amount; | |
| 6419 | else if (size >= max_size) | |
| 6420 | return max_amount; | |
| 6421 | else | |
| 6422 | return (scale(max_amount, size - min_size, max_size - min_size) | |
| 6423 | + scale(min_amount, max_size - size, max_size - min_size)); | |
| 6424 | } | |
| 6425 | else | |
| 6426 | return H0; | |
| 6427 | } | |
| 6428 | ||
| 6429 | void track_kern() | |
| 6430 | { | |
| 6431 | int n = get_fontno(); | |
| 6432 | if (n >= 0) { | |
| 6433 | int min_s, max_s; | |
| 6434 | hunits min_a, max_a; | |
| 6435 | if (has_arg() | |
| 6436 | && get_number(&min_s, 'z') | |
| 6437 | && get_hunits(&min_a, 'p') | |
| 6438 | && get_number(&max_s, 'z') | |
| 6439 | && get_hunits(&max_a, 'p')) { | |
| 6440 | track_kerning_function tk(min_s, min_a, max_s, max_a); | |
| 6441 | font_table[n]->set_track_kern(tk); | |
| 6442 | } | |
| 6443 | else { | |
| 6444 | track_kerning_function tk; | |
| 6445 | font_table[n]->set_track_kern(tk); | |
| 6446 | } | |
| 6447 | } | |
| 6448 | skip_line(); | |
| 6449 | } | |
| 6450 | ||
| 6451 | void constant_space() | |
| 6452 | { | |
| 6453 | int n = get_fontno(); | |
| 6454 | if (n >= 0) { | |
| 6455 | int x, y; | |
| 6456 | if (!has_arg() || !get_integer(&x)) | |
| 6457 | font_table[n]->set_constant_space(CONSTANT_SPACE_NONE); | |
| 6458 | else { | |
| 6459 | if (!has_arg() || !get_number(&y, 'z')) | |
| 6460 | font_table[n]->set_constant_space(CONSTANT_SPACE_RELATIVE, x); | |
| 6461 | else | |
| 6462 | font_table[n]->set_constant_space(CONSTANT_SPACE_ABSOLUTE, | |
| 6463 | scale(y*x, | |
| 6464 | units_per_inch, | |
| 6465 | 36*72*sizescale)); | |
| 6466 | } | |
| 6467 | } | |
| 6468 | skip_line(); | |
| 6469 | } | |
| 6470 | ||
| 6471 | void ligature() | |
| 6472 | { | |
| 6473 | int lig; | |
| 6474 | if (has_arg() && get_integer(&lig) && lig >= 0 && lig <= 2) | |
| 6475 | global_ligature_mode = lig; | |
| 6476 | else | |
| 6477 | global_ligature_mode = 1; | |
| 6478 | skip_line(); | |
| 6479 | } | |
| 6480 | ||
| 6481 | void kern_request() | |
| 6482 | { | |
| 6483 | int k; | |
| 6484 | if (has_arg() && get_integer(&k)) | |
| 6485 | global_kern_mode = k != 0; | |
| 6486 | else | |
| 6487 | global_kern_mode = 1; | |
| 6488 | skip_line(); | |
| 6489 | } | |
| 6490 | ||
| 6491 | void set_soft_hyphen_char() | |
| 6492 | { | |
| 6493 | soft_hyphen_char = get_optional_char(); | |
| 6494 | if (!soft_hyphen_char) | |
| 6495 | soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); | |
| 6496 | skip_line(); | |
| 6497 | } | |
| 6498 | ||
| 6499 | void init_output() | |
| 6500 | { | |
| 6501 | if (suppress_output_flag) | |
| 6502 | the_output = new suppress_output_file; | |
| 6503 | else if (ascii_output_flag) | |
| 6504 | the_output = new ascii_output_file; | |
| 6505 | else | |
| 6506 | the_output = new troff_output_file; | |
| 6507 | } | |
| 6508 | ||
| 6509 | class next_available_font_position_reg : public reg { | |
| 6510 | public: | |
| 6511 | const char *get_string(); | |
| 6512 | }; | |
| 6513 | ||
| 6514 | const char *next_available_font_position_reg::get_string() | |
| 6515 | { | |
| 6516 | return i_to_a(next_available_font_position()); | |
| 6517 | } | |
| 6518 | ||
| 6519 | class printing_reg : public reg { | |
| 6520 | public: | |
| 6521 | const char *get_string(); | |
| 6522 | }; | |
| 6523 | ||
| 6524 | const char *printing_reg::get_string() | |
| 6525 | { | |
| 6526 | if (the_output) | |
| 6527 | return the_output->is_printing() ? "1" : "0"; | |
| 6528 | else | |
| 6529 | return "0"; | |
| 6530 | } | |
| 6531 | ||
| 6532 | void init_node_requests() | |
| 6533 | { | |
| 6534 | init_request("bd", bold_font); | |
| 6535 | init_request("cs", constant_space); | |
| 6536 | init_request("fp", font_position); | |
| 6537 | init_request("fschar", define_font_special_character); | |
| 6538 | init_request("fspecial", font_special_request); | |
| 4d3e9548 | 6539 | init_request("fzoom", font_zoom_request); |
| 92d0a6a6 JR |
6540 | init_request("ftr", font_translate); |
| 6541 | init_request("kern", kern_request); | |
| 6542 | init_request("lg", ligature); | |
| 6543 | init_request("rfschar", remove_font_special_character); | |
| 6544 | init_request("shc", set_soft_hyphen_char); | |
| 6545 | init_request("special", special_request); | |
| 6546 | init_request("sty", style); | |
| 6547 | init_request("tkf", track_kern); | |
| 6548 | init_request("uf", underline_font); | |
| 6549 | number_reg_dictionary.define(".fp", new next_available_font_position_reg); | |
| 6550 | number_reg_dictionary.define(".kern", | |
| 6551 | new constant_int_reg(&global_kern_mode)); | |
| 6552 | number_reg_dictionary.define(".lg", | |
| 6553 | new constant_int_reg(&global_ligature_mode)); | |
| 6554 | number_reg_dictionary.define(".P", new printing_reg); | |
| 6555 | soft_hyphen_char = get_charinfo(HYPHEN_SYMBOL); | |
| 6556 | } |