PageRenderTime 81ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/groff/src/roff/troff/node.cpp

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