2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #define DEFAULT_LINEWIDTH 40
24 static int linewidth
= DEFAULT_LINEWIDTH
;
26 static int draw_flag
= 1;
28 /* These values were chosen because:
30 (MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27)
32 and 57816 is an exact multiple of both 72.27*SIZESCALE and 72.
34 The width in the groff font file is the product of MULTIPLIER and the
35 width in the tfm file. */
38 #define RES_7227 (RES/7227)
39 #define UNITWIDTH 131072
45 class dvi_font
: public font
{
46 dvi_font(const char *);
51 void handle_unknown_font_command(const char *command
, const char *arg
,
52 const char *filename
, int lineno
);
53 static dvi_font
*load_dvi_font(const char *);
56 dvi_font
*dvi_font::load_dvi_font(const char *s
)
58 dvi_font
*f
= new dvi_font(s
);
66 dvi_font::dvi_font(const char *nm
)
67 : font(nm
), checksum(0), design_size(0)
75 void dvi_font::handle_unknown_font_command(const char *command
,
77 const char *filename
, int lineno
)
80 if (strcmp(command
, "checksum") == 0) {
82 fatal_with_file_and_line(filename
, lineno
,
83 "`checksum' command requires an argument");
84 checksum
= int(strtol(arg
, &ptr
, 10));
85 if (checksum
== 0 && ptr
== arg
) {
86 fatal_with_file_and_line(filename
, lineno
, "bad checksum");
89 else if (strcmp(command
, "designsize") == 0) {
91 fatal_with_file_and_line(filename
, lineno
,
92 "`designsize' command requires an argument");
93 design_size
= int(strtol(arg
, &ptr
, 10));
94 if (design_size
== 0 && ptr
== arg
) {
95 fatal_with_file_and_line(filename
, lineno
, "bad design size");
100 #define FONTS_MAX 256
105 output_font() : f(0) { }
108 class dvi_printer
: public printer
{
119 output_font output_font_table
[FONTS_MAX
];
128 void define_font(int);
130 void possibly_begin_line();
158 void moveto(int, int);
159 void out_string(const char *);
160 void out_signed(unsigned char, int);
161 void out_unsigned(unsigned char, int);
162 void do_special(const char *);
166 font
*make_font(const char *);
167 void begin_page(int);
169 void set_char(int, font
*, const environment
*, int w
);
170 void special(char *arg
, const environment
*env
);
172 void draw(int code
, int *p
, int np
, const environment
*env
);
176 class draw_dvi_printer
: public dvi_printer
{
179 void set_line_thickness(const environment
*);
184 void draw(int code
, int *p
, int np
, const environment
*env
);
188 dvi_printer::dvi_printer()
189 : byte_count(0), last_bop(-1), page_count(0), cur_font(0), fp(stdout
),
190 max_h(0), max_v(0), pushed(0), line_thickness(-1), cur_point_size(-1)
192 if (font::res
!= RES
)
193 fatal("resolution must be %1", RES
);
194 if (font::unitwidth
!= UNITWIDTH
)
195 fatal("unitwidth must be %1", UNITWIDTH
);
197 fatal("hor must be equal to 1");
199 fatal("vert must be equal to 1");
200 if (font::sizescale
!= SIZESCALE
)
201 fatal("sizescale must be equal to %1", SIZESCALE
);
202 max_drift
= font::res
/1000; // this is fairly arbitrary
206 dvi_printer::~dvi_printer()
212 draw_dvi_printer::draw_dvi_printer()
213 : output_pen_size(-1), fill(FILL_MAX
)
217 draw_dvi_printer::~draw_dvi_printer()
222 void dvi_printer::out1(int n
)
228 void dvi_printer::out2(int n
)
231 putc((n
>> 8) & 0xff, fp
);
235 void dvi_printer::out3(int n
)
238 putc((n
>> 16) & 0xff, fp
);
239 putc((n
>> 8) & 0xff, fp
);
243 void dvi_printer::out4(int n
)
246 putc((n
>> 24) & 0xff, fp
);
247 putc((n
>> 16) & 0xff, fp
);
248 putc((n
>> 8) & 0xff, fp
);
252 void dvi_printer::out_string(const char *s
)
260 void dvi_printer::end_of_line()
270 void dvi_printer::possibly_begin_line()
273 have_pushed
= pushed
= 1;
280 int scale(int x
, int z
)
285 alpha
= 16*z
; beta
= 16;
286 while (z
>= 040000000L) {
293 sw
= (((((d
* z
) / 0400) + (c
* z
)) / 0400) + (b
* z
)) / beta
;
302 void dvi_printer::set_char(int index
, font
*f
, const environment
*env
, int w
)
304 int code
= f
->get_code(index
);
305 if (env
->size
!= cur_point_size
|| f
!= cur_font
) {
307 cur_point_size
= env
->size
;
308 for (int i
= 0;; i
++) {
309 if (i
>= FONTS_MAX
) {
310 fatal("too many output fonts required");
312 if (output_font_table
[i
].f
== 0) {
313 output_font_table
[i
].f
= (dvi_font
*)cur_font
;
314 output_font_table
[i
].point_size
= cur_point_size
;
317 if (output_font_table
[i
].f
== cur_font
318 && output_font_table
[i
].point_size
== cur_point_size
)
323 int distance
= env
->hpos
- cur_h
;
324 if (env
->hpos
!= end_h
&& distance
!= 0) {
325 out_signed(right1
, distance
);
328 else if (distance
> max_drift
) {
329 out_signed(right1
, distance
- max_drift
);
330 cur_h
= env
->hpos
- max_drift
;
332 else if (distance
< -max_drift
) {
333 out_signed(right1
, distance
+ max_drift
);
334 cur_h
= env
->hpos
+ max_drift
;
336 if (env
->vpos
!= cur_v
) {
337 out_signed(down1
, env
->vpos
- cur_v
);
340 possibly_begin_line();
341 end_h
= env
->hpos
+ w
;
342 cur_h
+= scale(f
->get_width(index
, UNITWIDTH
)/MULTIPLIER
,
343 cur_point_size
*RES_7227
);
348 if (code
>= 0 && code
<= 127)
351 out_unsigned(set1
, code
);
354 void dvi_printer::define_font(int i
)
356 out_unsigned(fnt_def1
, i
);
357 dvi_font
*f
= output_font_table
[i
].f
;
359 out4(output_font_table
[i
].point_size
*RES_7227
);
360 out4(int((double(f
->design_size
)/(1<<20))*RES_7227
*100 + .5));
361 const char *nm
= f
->get_internal_name();
366 void dvi_printer::set_font(int i
)
368 if (i
>= 0 && i
<= 63)
371 out_unsigned(fnt1
, i
);
374 void dvi_printer::out_signed(unsigned char base
, int param
)
376 if (-128 <= param
&& param
< 128) {
380 else if (-32768 <= param
&& param
< 32768) {
384 else if (-(1 << 23) <= param
&& param
< (1 << 23)) {
394 void dvi_printer::out_unsigned(unsigned char base
, int param
)
401 else if (param
< 65536) {
405 else if (param
< (1 << 24)) {
420 void dvi_printer::preamble()
430 void dvi_printer::postamble()
432 int tem
= byte_count
;
440 out2(have_pushed
); // stack depth
443 for (i
= 0; i
< FONTS_MAX
&& output_font_table
[i
].f
!= 0; i
++)
448 for (i
= 0; i
< 4 || byte_count
% 4 != 0; i
++)
452 void dvi_printer::begin_page(int i
)
455 int tem
= byte_count
;
458 for (int j
= 1; j
< 10; j
++)
462 // By convention position (0,0) in a dvi file is placed at (1in, 1in).
468 void dvi_printer::end_page()
476 void draw_dvi_printer::end_page()
478 dvi_printer::end_page();
479 output_pen_size
= -1;
482 void dvi_printer::do_special(const char *s
)
487 possibly_begin_line();
488 out_unsigned(xxx1
, len
);
493 void dvi_printer::special(char *arg
, const environment
*env
)
495 moveto(env
->hpos
, env
->vpos
);
499 void dvi_printer::moveto(int h
, int v
)
502 out_signed(right1
, h
- cur_h
);
508 out_signed(down1
, v
- cur_v
);
516 void dvi_printer::draw(int code
, int *p
, int np
, const environment
*env
)
520 int height
= 0, width
;
522 if (line_thickness
< 0)
523 thickness
= env
->size
*RES_7227
*linewidth
/1000;
524 else if (line_thickness
> 0)
525 thickness
= line_thickness
;
529 error("2 arguments required for line");
531 else if (p
[0] == 0) {
534 x
= env
->hpos
- thickness
/2;
535 y
= env
->vpos
+ p
[1] + thickness
/2;
536 height
= p
[1] + thickness
;
540 x
= env
->hpos
- thickness
/2;
541 y
= env
->vpos
+ thickness
/2;
542 height
= thickness
- p
[1];
546 else if (p
[1] == 0) {
548 x
= env
->hpos
- thickness
/2;
549 y
= env
->vpos
+ thickness
/2;
551 width
= p
[0] + thickness
;
554 x
= env
->hpos
- p
[0] - thickness
/2;
555 y
= env
->vpos
+ thickness
/2;
557 width
= thickness
- p
[0];
567 else if (code
== 't') {
572 // troff gratuitously adds an extra 0
573 if (np
!= 1 && np
!= 2)
574 error("0 or 1 argument required for thickness");
576 line_thickness
= p
[0];
579 else if (code
== 'R') {
581 error("2 arguments required for rule");
582 else if (p
[0] != 0 || p
[1] != 0) {
603 // XXX Will this overflow?
605 inline int milliinches(int n
)
607 return (n
*1000 + font::res
/2)/font::res
;
610 void draw_dvi_printer::set_line_thickness(const environment
*env
)
613 = milliinches(line_thickness
< 0
614 // Will this overflow?
615 ? env
->size
*RES_7227
*linewidth
/1000
617 if (desired_pen_size
!= output_pen_size
) {
619 sprintf(buf
, "pn %d", desired_pen_size
);
621 output_pen_size
= desired_pen_size
;
625 void draw_dvi_printer::fill_next()
628 sprintf(buf
, "sh %.3f", double(fill
)/FILL_MAX
);
632 void draw_dvi_printer::draw(int code
, int *p
, int np
, const environment
*env
)
641 // troff adds an extra argument to C
642 if (np
!= 1 && !(code
== 'C' && np
== 2)) {
643 error("1 argument required for circle");
646 moveto(env
->hpos
+p
[0]/2, env
->vpos
);
650 set_line_thickness(env
);
652 rad
= milliinches(p
[0]/2);
653 sprintf(buf
, "%s 0 0 %d %d 0 6.28319",
654 (fill_flag
? "ia" : "ar"),
661 error("2 arguments required for line");
664 moveto(env
->hpos
, env
->vpos
);
665 set_line_thickness(env
);
666 do_special("pa 0 0");
667 sprintf(buf
, "pa %d %d", milliinches(p
[0]), milliinches(p
[1]));
676 error("2 arguments required for ellipse");
679 moveto(env
->hpos
+p
[0]/2, env
->vpos
);
682 sprintf(buf
, "%s 0 0 %d %d 0 6.28319",
683 (fill_flag
? "ia" : "ar"),
685 milliinches(p
[1]/2));
694 error("even number of arguments required for polygon");
698 error("no arguments for polygon");
701 moveto(env
->hpos
, env
->vpos
);
705 set_line_thickness(env
);
706 do_special("pa 0 0");
708 for (int i
= 0; i
< np
; i
+= 2) {
711 sprintf(buf
, "pa %d %d", milliinches(h
), milliinches(v
));
714 do_special("pa 0 0");
715 do_special(fill_flag
? "ip" : "fp");
721 error("even number of arguments required for spline");
725 error("no arguments for spline");
728 moveto(env
->hpos
, env
->vpos
);
729 set_line_thickness(env
);
730 do_special("pa 0 0");
732 for (int i
= 0; i
< np
; i
+= 2) {
735 sprintf(buf
, "pa %d %d", milliinches(h
), milliinches(v
));
744 error("4 arguments required for arc");
747 set_line_thickness(env
);
750 int eh
= p
[0] + p
[2];
751 int ev
= p
[1] + p
[3];
752 double n
= (double(ch
)*eh
) + (double(cv
)*ev
);
754 moveto(env
->hpos
, env
->vpos
);
755 do_special("pa 0 0");
756 sprintf(buf
, "pa %d %d", milliinches(eh
), milliinches(ev
));
761 double k
= (double(eh
)*eh
+ double(ev
)*ev
)/(2.0*n
);
764 double start_angle
= atan2(-v
, -h
);
765 double end_angle
= atan2(ev
- v
, eh
- h
);
766 int rad
= milliinches(int(sqrt(h
*h
+ v
*v
) + .5));
767 moveto(env
->hpos
+ int(h
), env
->vpos
+ int(v
));
768 sprintf(buf
, "ar 0 0 %d %d %f %f",
783 // troff gratuitously adds an extra 0
784 if (np
!= 1 && np
!= 2) {
785 error("0 or 1 argument required for thickness");
788 line_thickness
= p
[0];
794 if (np
!= 1 && np
!= 2) {
795 error("1 argument required for fill");
799 if (fill
< 0 || fill
> FILL_MAX
)
806 error("2 arguments required for rule");
832 error("unrecognised drawing command `%1'", char(code
));
837 font
*dvi_printer::make_font(const char *nm
)
839 return dvi_font::load_dvi_font(nm
);
842 printer
*make_printer()
845 return new draw_dvi_printer
;
847 return new dvi_printer
;
852 int main(int argc
, char **argv
)
854 program_name
= argv
[0];
855 static char stderr_buf
[BUFSIZ
];
856 setbuf(stderr
, stderr_buf
);
858 while ((c
= getopt(argc
, argv
, "F:vw:d")) != EOF
)
862 extern const char *version_string
;
863 fprintf(stderr
, "grodvi version %s\n", version_string
);
868 if (sscanf(optarg
, "%d", &linewidth
) != 1
869 || linewidth
< 0 || linewidth
> 1000) {
870 error("bad line width");
871 linewidth
= DEFAULT_LINEWIDTH
;
878 font::command_line_font_dir(optarg
);
889 for (int i
= optind
; i
< argc
; i
++)
898 fprintf(stderr
, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n",