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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23 #include "htmlindicate.h"
26 const double RELATIVE_THICKNESS
= -1.0;
27 const double BAD_THICKNESS
= -2.0;
29 class simple_output
: public common_output
{
30 virtual void simple_line(const position
&, const position
&) = 0;
31 virtual void simple_spline(const position
&, const position
*, int n
) = 0;
32 virtual void simple_arc(const position
&, const position
&,
33 const position
&) = 0;
34 virtual void simple_circle(int, const position
&, double rad
) = 0;
35 virtual void simple_ellipse(int, const position
&, const distance
&) = 0;
36 virtual void simple_polygon(int, const position
*, int) = 0;
37 virtual void line_thickness(double) = 0;
38 virtual void set_fill(double) = 0;
39 void dot(const position
&, const line_type
&) = 0;
41 void start_picture(double sc
, const position
&ll
, const position
&ur
) = 0;
42 void finish_picture() = 0;
43 void text(const position
&, text_piece
*, int, double) = 0;
44 void line(const position
&, const position
*, int n
,
46 void polygon(const position
*, int n
,
47 const line_type
&, double);
48 void spline(const position
&, const position
*, int n
,
50 void arc(const position
&, const position
&, const position
&,
52 void circle(const position
&, double rad
, const line_type
&, double);
53 void ellipse(const position
&, const distance
&, const line_type
&, double);
54 int supports_filled_polygons();
57 int simple_output::supports_filled_polygons()
59 return driver_extension_flag
!= 0;
62 void simple_output::arc(const position
&start
, const position
¢
,
63 const position
&end
, const line_type
<
)
66 case line_type::solid
:
67 line_thickness(lt
.thickness
);
68 simple_arc(start
, cent
, end
);
70 case line_type::invisible
:
72 case line_type::dashed
:
73 dashed_arc(start
, cent
, end
, lt
);
75 case line_type::dotted
:
76 dotted_arc(start
, cent
, end
, lt
);
81 void simple_output::line(const position
&start
, const position
*v
, int n
,
85 line_thickness(lt
.thickness
);
86 for (int i
= 0; i
< n
; i
++) {
88 case line_type::solid
:
89 simple_line(pos
, v
[i
]);
91 case line_type::dotted
:
93 distance
vec(v
[i
] - pos
);
94 double dist
= hypot(vec
);
95 int ndots
= int(dist
/lt
.dash_width
+ .5);
100 for (int j
= 0; j
<= ndots
; j
++)
101 dot(pos
+ vec
*j
, lt
);
105 case line_type::dashed
:
107 distance
vec(v
[i
] - pos
);
108 double dist
= hypot(vec
);
109 if (dist
<= lt
.dash_width
*2.0)
110 simple_line(pos
, v
[i
]);
112 int ndashes
= int((dist
- lt
.dash_width
)/(lt
.dash_width
*2.0) + .5);
113 distance dash_vec
= vec
*(lt
.dash_width
/dist
);
114 double dash_gap
= (dist
- lt
.dash_width
)/ndashes
;
115 distance dash_gap_vec
= vec
*(dash_gap
/dist
);
116 for (int j
= 0; j
<= ndashes
; j
++) {
117 position
s(pos
+ dash_gap_vec
*j
);
118 simple_line(s
, s
+ dash_vec
);
123 case line_type::invisible
:
132 void simple_output::spline(const position
&start
, const position
*v
, int n
,
135 line_thickness(lt
.thickness
);
136 simple_spline(start
, v
, n
);
139 void simple_output::polygon(const position
*v
, int n
,
140 const line_type
<
, double fill
)
142 if (driver_extension_flag
) {
145 simple_polygon(1, v
, n
);
148 if (lt
.type
== line_type::solid
&& driver_extension_flag
) {
149 line_thickness(lt
.thickness
);
150 simple_polygon(0, v
, n
);
152 else if (lt
.type
!= line_type::invisible
) {
153 line_thickness(lt
.thickness
);
154 line(v
[n
- 1], v
, n
, lt
);
158 void simple_output::circle(const position
¢
, double rad
,
159 const line_type
<
, double fill
)
161 if (driver_extension_flag
&& fill
>= 0.0) {
163 simple_circle(1, cent
, rad
);
165 line_thickness(lt
.thickness
);
167 case line_type::invisible
:
169 case line_type::dashed
:
170 dashed_circle(cent
, rad
, lt
);
172 case line_type::dotted
:
173 dotted_circle(cent
, rad
, lt
);
175 case line_type::solid
:
176 simple_circle(0, cent
, rad
);
183 void simple_output::ellipse(const position
¢
, const distance
&dim
,
184 const line_type
<
, double fill
)
186 if (driver_extension_flag
&& fill
>= 0.0) {
188 simple_ellipse(1, cent
, dim
);
190 if (lt
.type
!= line_type::invisible
)
191 line_thickness(lt
.thickness
);
193 case line_type::invisible
:
195 case line_type::dotted
:
196 case line_type::dashed
:
197 case line_type::solid
:
198 simple_ellipse(0, cent
, dim
);
205 #define FILL_MAX 1000
207 class troff_output
: public simple_output
{
208 const char *last_filename
;
212 double last_line_thickness
;
217 void start_picture(double, const position
&ll
, const position
&ur
);
218 void finish_picture();
219 void text(const position
&, text_piece
*, int, double);
220 void dot(const position
&, const line_type
&);
221 void command(const char *, const char *, int);
222 void set_location(const char *, int);
223 void simple_line(const position
&, const position
&);
224 void simple_spline(const position
&, const position
*, int n
);
225 void simple_arc(const position
&, const position
&, const position
&);
226 void simple_circle(int, const position
&, double rad
);
227 void simple_ellipse(int, const position
&, const distance
&);
228 void simple_polygon(int, const position
*, int);
229 void line_thickness(double p
);
230 void set_fill(double);
231 position
transform(const position
&);
234 output
*make_troff_output()
236 return new troff_output
;
239 troff_output::troff_output()
240 : last_filename(0), last_line_thickness(BAD_THICKNESS
), last_fill(-1.0)
244 troff_output::~troff_output()
248 inline position
troff_output::transform(const position
&pos
)
250 return position((pos
.x
- upper_left
.x
)/scale
,
251 (upper_left
.y
- pos
.y
)/scale
);
254 #define FILL_REG "00"
256 // If this register > 0, then pic will generate \X'ps: ...' commands
257 // if the aligned attribute is used.
258 #define GROPS_REG "0p"
260 // If this register is defined, geqn won't produce `\x's.
261 #define EQN_NO_EXTRA_SPACE_REG "0x"
263 void troff_output::start_picture(double sc
,
264 const position
&ll
, const position
&ur
)
268 scale
= compute_scale(sc
, ll
, ur
);
269 height
= (ur
.y
- ll
.y
)/scale
;
270 double width
= (ur
.x
- ll
.x
)/scale
;
271 printf(".PS %.3fi %.3fi", height
, width
);
273 printf(" %s\n", args
);
277 printf(".\\\" %g %g %g %g\n", ll
.x
, ll
.y
, ur
.x
, ur
.y
);
278 printf(".\\\" %.3fi %.3fi %.3fi %.3fi\n", 0.0, height
, width
, 0.0);
279 printf(".nr " FILL_REG
" \\n(.u\n.nf\n");
280 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 1\n");
281 // This guarantees that if the picture is used in a diversion it will
282 // have the right width.
283 printf("\\h'%.3fi'\n.sp -1\n", width
);
286 void troff_output::finish_picture()
288 line_thickness(BAD_THICKNESS
);
289 last_fill
= -1.0; // force it to be reset for each picture
291 printf(".sp %.3fi+1\n", height
);
292 printf(".if \\n(" FILL_REG
" .fi\n");
294 printf(".nr " EQN_NO_EXTRA_SPACE_REG
" 0\n");
296 // this is a little gross
297 set_location(current_filename
, current_lineno
);
298 fputs(flyback_flag
? ".PF\n" : ".PE\n", stdout
);
301 void troff_output::command(const char *s
,
302 const char *filename
, int lineno
)
305 set_location(filename
, lineno
);
310 void troff_output::simple_circle(int filled
, const position
¢
, double rad
)
312 position c
= transform(cent
);
319 (filled
? 'C' : 'c'),
323 void troff_output::simple_ellipse(int filled
, const position
¢
,
326 position c
= transform(cent
);
331 c
.x
- dim
.x
/(2.0*scale
),
333 (filled
? 'E' : 'e'),
334 dim
.x
/scale
, dim
.y
/scale
);
337 void troff_output::simple_arc(const position
&start
, const distance
¢
,
340 position s
= transform(start
);
341 position c
= transform(cent
);
343 distance ev
= transform(end
) - c
;
346 "\\D'a%.3fi %.3fi %.3fi %.3fi'"
348 s
.x
, s
.y
, cv
.x
, cv
.y
, ev
.x
, ev
.y
);
351 void troff_output::simple_line(const position
&start
, const position
&end
)
353 position s
= transform(start
);
354 distance ev
= transform(end
) - s
;
359 s
.x
, s
.y
, ev
.x
, ev
.y
);
362 void troff_output::simple_spline(const position
&start
,
363 const position
*v
, int n
)
365 position pos
= transform(start
);
369 fputs("\\D'~", stdout
);
370 for (int i
= 0; i
< n
; i
++) {
371 position temp
= transform(v
[i
]);
372 distance d
= temp
- pos
;
376 printf("%.3fi %.3fi", d
.x
, d
.y
);
378 printf("'\n.sp -1\n");
383 void troff_output::simple_polygon(int filled
, const position
*v
, int n
)
385 position pos
= transform(v
[0]);
389 printf("\\D'%c", (filled
? 'P' : 'p'));
390 for (int i
= 1; i
< n
; i
++) {
391 position temp
= transform(v
[i
]);
392 distance d
= temp
- pos
;
396 printf("%.3fi %.3fi", d
.x
, d
.y
);
398 printf("'\n.sp -1\n");
401 const double TEXT_AXIS
= 0.22; // in ems
403 static const char *choose_delimiter(const char *text
)
405 if (strchr(text
, '\'') == 0)
411 void troff_output::text(const position
¢er
, text_piece
*v
, int n
,
414 line_thickness(BAD_THICKNESS
); // the text might use lines (eg in equations)
416 if (driver_extension_flag
&& ang
!= 0.0) {
418 position c
= transform(center
);
419 printf(".if \\n(" GROPS_REG
" \\{\\\n"
422 "\\X'ps: exec gsave currentpoint 2 copy translate %.4f rotate neg exch neg exch translate'"
425 c
.x
, c
.y
, -ang
*180.0/M_PI
);
427 for (int i
= 0; i
< n
; i
++)
428 if (v
[i
].text
!= 0 && *v
[i
].text
!= '\0') {
429 position c
= transform(center
);
430 if (v
[i
].filename
!= 0)
431 set_location(v
[i
].filename
, v
[i
].lineno
);
432 printf("\\h'%.3fi", c
.x
);
433 const char *delim
= choose_delimiter(v
[i
].text
);
434 if (v
[i
].adj
.h
== RIGHT_ADJUST
)
435 printf("-\\w%s%s%su", delim
, v
[i
].text
, delim
);
436 else if (v
[i
].adj
.h
!= LEFT_ADJUST
)
437 printf("-(\\w%s%s%su/2u)", delim
, v
[i
].text
, delim
);
439 printf("\\v'%.3fi-(%dv/2u)+%dv+%.2fm",
444 if (v
[i
].adj
.v
== ABOVE_ADJUST
)
446 else if (v
[i
].adj
.v
== BELOW_ADJUST
)
449 fputs(v
[i
].text
, stdout
);
450 fputs("\n.sp -1\n", stdout
);
453 printf(".if '\\*(.T'ps' \\{\\\n"
454 "\\X'ps: exec grestore'\n.sp -1\n"
458 void troff_output::line_thickness(double p
)
461 p
= RELATIVE_THICKNESS
;
462 if (driver_extension_flag
&& p
!= last_line_thickness
) {
463 printf("\\D't %.3fp'\\h'%.3fp'\n.sp -1\n", p
, -p
);
464 last_line_thickness
= p
;
468 void troff_output::set_fill(double f
)
470 if (driver_extension_flag
&& f
!= last_fill
) {
471 printf("\\D'f %du'\\h'%du'\n.sp -1\n", int(f
*FILL_MAX
), -int(f
*FILL_MAX
));
476 const double DOT_AXIS
= .044;
478 void troff_output::dot(const position
¢
, const line_type
<
)
480 if (driver_extension_flag
) {
481 line_thickness(lt
.thickness
);
482 simple_line(cent
, cent
);
485 position c
= transform(cent
);
486 printf("\\h'%.3fi-(\\w'.'u/2u)'"
495 void troff_output::set_location(const char *s
, int n
)
497 if (last_filename
!= 0 && strcmp(s
, last_filename
) == 0)
498 printf(".lf %d\n", n
);
500 printf(".lf %d %s\n", n
, s
);