1 /*-------------------------------------------------------------------------*/
2 /* cairo.c --- mainly cairo versions of the UDraw... stuff in functions.c */
3 /* Copyright (c) 2002 Tim Edwards, Johns Hopkins University */
4 /*-------------------------------------------------------------------------*/
5 /*-------------------------------------------------------------------------*/
6 /* originally written by Tim Edwards, 8/13/93 */
7 /* All cairo graphics library modifications by Erik van der Wal, May 2014 */
8 /*-------------------------------------------------------------------------*/
20 #include <X11/Intrinsic.h>
25 #endif /* TCL_WRAPPER */
28 #include "colordefs.h"
29 #include "prototypes.h"
31 #ifdef CAIRO_HAS_FC_FONT
32 #include <cairo/cairo-ft.h>
33 #endif /* CAIRO_HAS_FC_FONT */
36 #include <ghostscript/ierrors.h>
37 #include <ghostscript/iapi.h>
38 #include <ghostscript/gdevdsp.h>
41 extern XCWindowData
*areawin
;
42 extern Globaldata xobjs
;
43 extern int number_colors
;
44 extern colorindex
*colorlist
;
45 extern short fontcount
;
46 extern fontinfo
*fonts
;
47 extern Cursor appcursors
[NUM_CURSORS
];
49 extern gs_state_t gs_state
;
50 extern cairo_surface_t
*bbuf
;
52 static cairo_user_data_key_t fontinfo_key
;
54 static void xc_cairo_strokepath(short style
, float width
);
56 /*----------------------------------------------------------------------------*/
58 void xc_cairo_set_matrix(const Matrix
*xcm
)
61 m
.xx
= xcm
->a
; m
.xy
= xcm
->b
; m
.x0
= xcm
->c
;
62 m
.yx
= xcm
->d
; m
.yy
= xcm
->e
; m
.y0
= xcm
->f
;
63 cairo_set_matrix(areawin
->cr
, &m
);
66 /*----------------------------------------------------------------------*/
67 /* Set the color, based on the given color index */
68 /*----------------------------------------------------------------------*/
70 void xc_cairo_set_color(int coloridx
)
74 if (coloridx
>= number_colors
) return;
76 xcc
= &colorlist
[coloridx
];
77 cairo_set_source_rgb(areawin
->cr
,
78 (double)xcc
->color
.red
/ 65535.,
79 (double)xcc
->color
.green
/ 65535.,
80 (double)xcc
->color
.blue
/ 65535.);
83 /*----------------------------------------------------------------------------*/
85 void UDrawLine(XPoint
*pt1
, XPoint
*pt2
)
87 if (!areawin
->redraw_ongoing
) {
88 areawin
->redraw_needed
= True
;
92 cairo_save(areawin
->cr
);
94 cairo_set_line_width(areawin
->cr
, xobjs
.pagelist
[areawin
->page
]->wirewidth
);
95 cairo_set_dash(areawin
->cr
, NULL
, 0, 0.);
96 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_ROUND
);
97 cairo_set_line_join(areawin
->cr
, CAIRO_LINE_JOIN_BEVEL
);
99 cairo_move_to(areawin
->cr
, pt1
->x
, pt1
->y
);
100 cairo_line_to(areawin
->cr
, pt2
->x
, pt2
->y
);
101 cairo_stroke(areawin
->cr
);
103 cairo_restore(areawin
->cr
);
106 /*----------------------------------------------------------------------*/
107 /* Add circle at given point to indicate that the point is a parameter. */
108 /* The circle is divided into quarters. For parameterized y-coordinate */
109 /* the top and bottom quarters are drawn. For parameterized x- */
110 /* coordinate, the left and right quarters are drawn. A full circle */
111 /* indicates either both x- and y-coordinates are parameterized, or */
112 /* else any other kind of parameterization (presently, not used). */
114 /* (note that the two angles in XDrawArc() are 1) the start angle, */
115 /* measured in absolute 64th degrees from 0 (3 o'clock), and 2) the */
116 /* path length, in relative 64th degrees (positive = counterclockwise, */
117 /* negative = clockwise)). */
118 /*----------------------------------------------------------------------*/
120 void UDrawCircle(XPoint
*upt
, u_char which
)
124 if (!areawin
->redraw_ongoing
) {
125 areawin
->redraw_needed
= True
;
129 cairo_save(areawin
->cr
);
130 cairo_identity_matrix(areawin
->cr
);
132 user_to_window(*upt
, &wpt
);
133 cairo_set_line_width(areawin
->cr
, .75);
134 cairo_set_dash(areawin
->cr
, NULL
, 0, 0.);
135 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_BUTT
);
136 cairo_set_line_join(areawin
->cr
, CAIRO_LINE_JOIN_MITER
);
138 /* TODO: angles might be mirrored or turning the wrong way */
141 cairo_arc(areawin
->cr
, wpt
.x
, wpt
.y
, 4., M_PI
* -.25, M_PI
* .25);
142 cairo_arc(areawin
->cr
, wpt
.x
, wpt
.y
, 4., M_PI
* .75, M_PI
* 1.25);
145 cairo_arc(areawin
->cr
, wpt
.x
, wpt
.y
, 4., M_PI
* .25, M_PI
* .75);
146 cairo_arc(areawin
->cr
, wpt
.x
, wpt
.y
, 4., M_PI
* 1.25, M_PI
* 1.75);
149 cairo_arc(areawin
->cr
, wpt
.x
, wpt
.y
, 4., 0., M_PI
* 2.);
153 cairo_restore(areawin
->cr
);
156 /*----------------------------------------------------------------------*/
157 /* Add "X" at string origin */
158 /*----------------------------------------------------------------------*/
160 void UDrawXAt(XPoint
*wpt
)
162 if (!areawin
->redraw_ongoing
) {
163 areawin
->redraw_needed
= True
;
167 cairo_save(areawin
->cr
);
168 cairo_identity_matrix(areawin
->cr
);
170 cairo_set_dash(areawin
->cr
, NULL
, 0, 0.);
171 cairo_set_line_width(areawin
->cr
, .75);
173 cairo_move_to(areawin
->cr
, wpt
->x
- 3., wpt
->y
- 3.);
174 cairo_line_to(areawin
->cr
, wpt
->x
+ 3., wpt
->y
+ 3.);
175 cairo_move_to(areawin
->cr
, wpt
->x
+ 3., wpt
->y
- 3.);
176 cairo_line_to(areawin
->cr
, wpt
->x
- 3., wpt
->y
+ 3.);
177 cairo_stroke(areawin
->cr
);
179 cairo_restore(areawin
->cr
);
182 void UDrawXLine(XPoint opt
, XPoint cpt
)
185 double dashes
[] = {4., 4.};
187 if (!areawin
->redraw_ongoing
) {
188 areawin
->redraw_needed
= True
;
192 cairo_save(areawin
->cr
);
193 cairo_identity_matrix(areawin
->cr
);
195 xc_cairo_set_color(AUXCOLOR
);
196 cairo_set_dash(areawin
->cr
, dashes
, sizeof(dashes
) / sizeof(double), 0.);
197 cairo_set_line_width(areawin
->cr
, .75);
199 user_to_window(cpt
, &upt
);
200 user_to_window(opt
, &vpt
);
201 cairo_move_to(areawin
->cr
, vpt
.x
, vpt
.y
);
202 cairo_line_to(areawin
->cr
, upt
.x
, upt
.y
);
203 cairo_stroke(areawin
->cr
);
205 cairo_set_dash(areawin
->cr
, NULL
, 0, 0.);
206 cairo_move_to(areawin
->cr
, upt
.x
- 3., upt
.y
- 3.);
207 cairo_line_to(areawin
->cr
, upt
.x
+ 3., upt
.y
+ 3.);
208 cairo_move_to(areawin
->cr
, upt
.x
+ 3., upt
.y
- 3.);
209 cairo_line_to(areawin
->cr
, upt
.x
- 3., upt
.y
+ 3.);
210 cairo_stroke(areawin
->cr
);
212 cairo_restore(areawin
->cr
);
215 /*-------------------------------------------------------------------------*/
217 void UDrawBox(XPoint origin
, XPoint corner
)
222 if (!areawin
->redraw_ongoing
) {
223 areawin
->redraw_needed
= True
;
227 user_to_window(origin
, &worig
);
228 user_to_window(corner
, &wcorn
);
230 cairo_save(areawin
->cr
);
231 cairo_identity_matrix(areawin
->cr
);
233 cairo_set_line_width(areawin
->cr
, 1.0);
234 cairo_set_dash(areawin
->cr
, NULL
, 0, 0.);
235 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_SQUARE
);
236 cairo_set_line_join(areawin
->cr
, CAIRO_LINE_JOIN_MITER
);
238 cairo_move_to(areawin
->cr
, worig
.x
+ .5, worig
.y
+ .5);
239 cairo_line_to(areawin
->cr
, worig
.x
+ .5, wcorn
.y
+ .5);
240 cairo_line_to(areawin
->cr
, wcorn
.x
+ .5, wcorn
.y
+ .5);
241 cairo_line_to(areawin
->cr
, wcorn
.x
+ .5, worig
.y
+ .5);
242 cairo_close_path(areawin
->cr
);
244 xc_cairo_set_color(AUXCOLOR
);
245 cairo_pattern_get_rgba(cairo_get_source(areawin
->cr
), &r
, &g
, &b
, &a
);
246 cairo_set_source_rgba(areawin
->cr
, r
, g
, b
, .1 * a
);
247 cairo_fill_preserve(areawin
->cr
);
248 cairo_set_source_rgba(areawin
->cr
, r
, g
, b
, a
);
249 cairo_stroke(areawin
->cr
);
251 cairo_restore(areawin
->cr
);
254 /*----------------------------------------------------------------------*/
255 /* Draw a box indicating the dimensions of the edit element that most */
256 /* closely reach the position "corner". */
257 /*----------------------------------------------------------------------*/
259 void UDrawRescaleBox(XPoint
*corner
)
263 if (!areawin
->redraw_ongoing
) {
264 areawin
->redraw_needed
= True
;
265 /* No return here, since the return value might be needed? */
268 if (areawin
->selects
== 0)
271 if (areawin
->redraw_ongoing
) {
273 UGetRescaleBox(corner
, newpoints
);
275 cairo_save(areawin
->cr
);
276 xc_cairo_set_color(AUXCOLOR
);
277 cairo_set_dash(areawin
->cr
, NULL
, 0, 0.);
278 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_ROUND
);
279 cairo_set_line_join(areawin
->cr
, CAIRO_LINE_JOIN_BEVEL
);
280 cairo_move_to(areawin
->cr
, newpoints
[0].x
, newpoints
[0].y
);
281 for (i
= 1; i
< 4; i
++)
282 cairo_line_to(areawin
->cr
, newpoints
[i
].x
, newpoints
[i
].y
);
283 xc_cairo_strokepath(0, 1);
284 cairo_restore(areawin
->cr
);
288 /*-------------------------------------------------------------------------*/
293 XPoint worig
, wcorn
, corner
;
294 objinstptr bbinst
= areawin
->topinstance
;
296 if (!areawin
->redraw_ongoing
) {
297 areawin
->redraw_needed
= True
;
301 if ((!areawin
->bboxon
) || (checkforbbox(topobject
) != NULL
)) return;
303 origin
= bbinst
->bbox
.lowerleft
;
304 corner
.x
= origin
.x
+ bbinst
->bbox
.width
;
305 corner
.y
= origin
.y
+ bbinst
->bbox
.height
;
307 /* Include any schematic labels in the bounding box. */
308 extendschembbox(bbinst
, &origin
, &corner
);
310 user_to_window(origin
, &worig
);
311 user_to_window(corner
, &wcorn
);
313 cairo_save(areawin
->cr
);
314 cairo_identity_matrix(areawin
->cr
);
316 xc_cairo_set_color(BBOXCOLOR
);
317 cairo_set_line_width(areawin
->cr
, 1.0);
318 cairo_set_dash(areawin
->cr
, NULL
, 0, 0.);
319 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_SQUARE
);
320 cairo_set_line_join(areawin
->cr
, CAIRO_LINE_JOIN_MITER
);
322 cairo_move_to(areawin
->cr
, worig
.x
+ .5, worig
.y
+ .5);
323 cairo_line_to(areawin
->cr
, worig
.x
+ .5, wcorn
.y
+ .5);
324 cairo_line_to(areawin
->cr
, wcorn
.x
+ .5, wcorn
.y
+ .5);
325 cairo_line_to(areawin
->cr
, wcorn
.x
+ .5, worig
.y
+ .5);
326 cairo_close_path(areawin
->cr
);
327 cairo_stroke(areawin
->cr
);
329 cairo_restore(areawin
->cr
);
332 /*----------------------------------------------------------------------*/
333 /* Main recursive object instance drawing routine. */
334 /* context is the instance information passed down from above */
335 /* theinstance is the object instance to be drawn */
336 /* level is the level of recursion */
337 /* passcolor is the inherited color value passed to object */
338 /* passwidth is the inherited linewidth value passed to the object */
339 /* stack contains graphics context information */
340 /*----------------------------------------------------------------------*/
342 void UDrawObject(objinstptr theinstance
, short level
, int passcolor
,
343 float passwidth
, pushlistptr
*stack
)
347 int defaultcolor
= passcolor
;
348 int curcolor
= passcolor
;
351 XPoint bboxin
[2], bboxout
[2];
353 objectptr theobject
= theinstance
->thisobject
;
355 if (!areawin
->redraw_ongoing
) {
356 areawin
->redraw_needed
= True
;
360 /* Save the number of selections and set it to zero while we do the */
361 /* object drawing. */
363 savesel
= areawin
->selects
;
364 areawin
->selects
= 0;
366 /* All parts are given in the coordinate system of the object, unless */
367 /* this is the top-level object, in which they will be interpreted as */
368 /* relative to the screen. */
372 /* Stack is not used by cairo but *is* used by expression evaluators */
373 if (stack
) push_stack((pushlistptr
*)stack
, theinstance
, (char *)NULL
);
376 UPreMultCTM(DCTM
, theinstance
->position
, theinstance
->scale
,
377 theinstance
->rotation
);
379 if (theinstance
->style
& LINE_INVARIANT
)
380 passwidth
/= fabs(theinstance
->scale
);
382 /* do a quick test for intersection with the display window */
384 bboxin
[0].x
= theobject
->bbox
.lowerleft
.x
;
385 bboxin
[0].y
= theobject
->bbox
.lowerleft
.y
;
386 bboxin
[1].x
= theobject
->bbox
.lowerleft
.x
+ theobject
->bbox
.width
;
387 bboxin
[1].y
= theobject
->bbox
.lowerleft
.y
+ theobject
->bbox
.height
;
389 extendschembbox(theinstance
, &(bboxin
[0]), &(bboxin
[1]));
390 UTransformbyCTM(DCTM
, bboxin
, bboxout
, 2);
392 xm
= (bboxout
[0].x
< bboxout
[1].x
) ? 0 : 1;
393 ym
= (bboxout
[0].y
< bboxout
[1].y
) ? 0 : 1;
395 if (bboxout
[xm
].x
< areawin
->width
&& bboxout
[ym
].y
< areawin
->height
&&
396 bboxout
[1 - xm
].x
> 0 && bboxout
[1 - ym
].y
> 0) {
398 /* make parameter substitutions */
399 psubstitute(theinstance
);
401 /* draw all of the elements */
403 tmpwidth
= UTopTransScale(passwidth
);
404 cairo_set_line_width(areawin
->cr
, tmpwidth
);
405 cairo_set_dash(areawin
->cr
, NULL
, 0, 0.);
406 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_ROUND
);
407 cairo_set_line_join(areawin
->cr
, CAIRO_LINE_JOIN_BEVEL
);
409 /* guard against plist being regenerated during a redraw by the */
410 /* expression parameter mechanism (should that be prohibited?) */
412 for (thispart
= 0; thispart
< theobject
->parts
; thispart
++) {
413 areagen
= theobject
->plist
+ thispart
;
414 if ((*areagen
)->type
& DRAW_HIDE
) continue;
416 if (defaultcolor
!= DOFORALL
) {
417 if ((*areagen
)->color
!= curcolor
) {
418 if ((*areagen
)->color
== DEFAULTCOLOR
)
419 curcolor
= defaultcolor
;
421 curcolor
= (*areagen
)->color
;
423 XcTopSetForeground(curcolor
);
427 switch(ELEMENTTYPE(*areagen
)) {
429 if (level
== 0 || !((TOPOLY(areagen
))->style
& BBOX
))
430 UDrawPolygon(TOPOLY(areagen
), passwidth
);
434 UDrawSpline(TOSPLINE(areagen
), passwidth
);
438 UDrawArc(TOARC(areagen
), passwidth
);
442 UDrawPath(TOPATH(areagen
), passwidth
);
446 UDrawGraphic(TOGRAPHIC(areagen
));
450 UDrawObject(TOOBJINST(areagen
), level
+ 1, curcolor
, passwidth
, stack
);
454 if (level
== 0 || TOLABEL(areagen
)->pin
== False
)
455 UDrawString(TOLABEL(areagen
), curcolor
, theinstance
);
456 else if ((TOLABEL(areagen
)->anchor
& PINVISIBLE
) && areawin
->pinpointon
)
457 UDrawString(TOLABEL(areagen
), curcolor
, theinstance
);
458 else if (TOLABEL(areagen
)->anchor
& PINVISIBLE
)
459 UDrawStringNoX(TOLABEL(areagen
), curcolor
, theinstance
);
460 else if (level
== 1 && TOLABEL(areagen
)->pin
&&
461 TOLABEL(areagen
)->pin
!= INFO
&& areawin
->pinpointon
)
462 UDrawXDown(TOLABEL(areagen
));
467 /* restore the color passed to the object, if different from current color */
469 if ((defaultcolor
!= DOFORALL
) && (passcolor
!= curcolor
)) {
470 XTopSetForeground(passcolor
);
474 /* restore the selection list (if any) */
475 areawin
->selects
= savesel
;
478 /* Stack is not used by cairo but *is* used by expression evaluators */
479 if (stack
) pop_stack(stack
);
482 /*-------------------------------------------------------------------------*/
484 static void xc_cairo_strokepath(short style
, float width
)
486 if (!(style
& CLIPMASK
) || (areawin
->showclipmasks
== TRUE
)) {
487 if (style
& FILLED
|| (!(style
& FILLED
) && style
& OPAQUE
)) {
488 if ((style
& FILLSOLID
) == FILLSOLID
)
489 cairo_fill_preserve(areawin
->cr
);
491 double red
, green
, blue
, alpha
;
492 cairo_pattern_get_rgba(cairo_get_source(areawin
->cr
),
493 &red
, &green
, &blue
, &alpha
);
494 if (!(style
& FILLED
))
495 cairo_set_source_rgba(areawin
->cr
, 1., 1., 1., alpha
);
497 double m
= (1 + ((style
& FILLSOLID
) >> 5)) / 8.;
498 if (style
& OPAQUE
) {
500 cairo_set_source_rgba(areawin
->cr
, m
* red
+ n
,
501 m
* green
+ n
, m
* blue
+ n
, alpha
);
504 cairo_set_source_rgba(areawin
->cr
, red
, green
, blue
,
507 cairo_fill_preserve(areawin
->cr
);
508 cairo_set_source_rgba(areawin
->cr
, red
, green
, blue
, alpha
);
511 if (!(style
& NOBORDER
)) {
512 cairo_set_line_width(areawin
->cr
, width
);
513 cairo_set_line_join(areawin
->cr
, (style
& SQUARECAP
) ?
514 CAIRO_LINE_JOIN_MITER
: CAIRO_LINE_JOIN_BEVEL
);
515 if (style
& (DASHED
| DOTTED
)) {
517 dashes
[0] = dashes
[1] = 4.0 * width
;
520 cairo_set_dash(areawin
->cr
, dashes
, 2, 0.0);
521 cairo_set_line_width(areawin
->cr
, width
);
522 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_BUTT
);
525 cairo_set_dash(areawin
->cr
, NULL
, 0, 0.0);
526 cairo_set_line_cap(areawin
->cr
, (style
& SQUARECAP
) ?
527 CAIRO_LINE_CAP_SQUARE
: CAIRO_LINE_CAP_ROUND
);
530 /* draw the spline and close off if so specified */
531 if (!(style
& UNCLOSED
))
532 cairo_close_path(areawin
->cr
);
533 cairo_stroke_preserve(areawin
->cr
);
536 if (style
& CLIPMASK
)
537 cairo_clip_preserve(areawin
->cr
);
538 cairo_new_path(areawin
->cr
); /* clear preserved paths */
541 /*-------------------------------------------------------------------------*/
543 void UDrawPolygon(polyptr thepoly
, float passwidth
)
547 if (!areawin
->redraw_ongoing
) {
548 areawin
->redraw_needed
= True
;
552 if (thepoly
->number
) {
553 cairo_move_to(areawin
->cr
, thepoly
->points
[0].x
, thepoly
->points
[0].y
);
554 for (i
= 1; i
< thepoly
->number
; i
++)
555 cairo_line_to(areawin
->cr
, thepoly
->points
[i
].x
, thepoly
->points
[i
].y
);
556 xc_cairo_strokepath(thepoly
->style
, thepoly
->width
* passwidth
);
560 /*-------------------------------------------------------------------------*/
562 void UDrawArc(arcptr thearc
, float passwidth
)
564 if (!areawin
->redraw_ongoing
) {
565 areawin
->redraw_needed
= True
;
569 if (abs(thearc
->radius
) == thearc
->yaxis
)
570 cairo_arc(areawin
->cr
, thearc
->position
.x
, thearc
->position
.y
,
571 abs(thearc
->radius
), thearc
->angle1
* M_PI
/ 180.0,
572 thearc
->angle2
* M_PI
/ 180.0);
573 else if (thearc
->yaxis
) {
574 /* perform elliptical arc, as described in cairo manual */
575 cairo_save(areawin
->cr
);
576 cairo_translate(areawin
->cr
, thearc
->position
.x
, thearc
->position
.y
);
577 cairo_scale(areawin
->cr
, abs(thearc
->radius
), thearc
->yaxis
);
578 cairo_arc(areawin
->cr
, 0.0, 0.0, 1.0, thearc
->angle1
* M_PI
/ 180.0,
579 thearc
->angle2
* M_PI
/ 180.0);
580 cairo_restore(areawin
->cr
);
582 else { /* no y-axis dimension: draw a line */
583 /* can we do this in a more elegant manner? */
585 double theta_start
= thearc
->angle1
* RADFAC
;
586 double theta_stop
= thearc
->angle2
* RADFAC
;
587 cairo_move_to(areawin
->cr
, thearc
->position
.x
+ fabs(thearc
->radius
)
588 * cos(theta_start
), thearc
->position
.y
);
589 for (theta
= -M_PI
; theta
< theta_stop
; theta
+= M_PI
) {
590 if (theta
<= theta_start
) continue;
591 cairo_line_to(areawin
->cr
, thearc
->position
.x
592 + fabs(thearc
->radius
) * cos(theta
), thearc
->position
.y
);
594 cairo_line_to(areawin
->cr
, thearc
->position
.x
+ fabs(thearc
->radius
)
595 * cos(theta_stop
), thearc
->position
.y
);
597 xc_cairo_strokepath(thearc
->style
, thearc
->width
* passwidth
);
600 /*-------------------------------------------------------------------------*/
602 void UDrawPath(pathptr thepath
, float passwidth
)
608 if (!areawin
->redraw_ongoing
) {
609 areawin
->redraw_needed
= True
;
613 /* Draw first point */
614 if (thepath
->parts
) {
615 genpath
= thepath
->plist
;
616 switch(ELEMENTTYPE(*genpath
)) {
618 thepoly
= TOPOLY(genpath
);
619 cairo_move_to(areawin
->cr
, thepoly
->points
[0].x
,
620 thepoly
->points
[0].y
);
623 thespline
= TOSPLINE(genpath
);
624 cairo_move_to(areawin
->cr
, thespline
->ctrl
[0].x
,
625 thespline
->ctrl
[0].y
);
629 /* Draw all other points */
630 for (genpath
= thepath
->plist
; genpath
< thepath
->plist
+ thepath
->parts
;
633 switch(ELEMENTTYPE(*genpath
)) {
635 thepoly
= TOPOLY(genpath
);
636 for (i
= 1; i
< thepoly
->number
; i
++)
637 cairo_line_to(areawin
->cr
, thepoly
->points
[i
].x
,
638 thepoly
->points
[i
].y
);
641 thespline
= TOSPLINE(genpath
);
642 cairo_curve_to(areawin
->cr
, thespline
->ctrl
[1].x
,
643 thespline
->ctrl
[1].y
, thespline
->ctrl
[2].x
,
644 thespline
->ctrl
[2].y
, thespline
->ctrl
[3].x
,
645 thespline
->ctrl
[3].y
);
649 xc_cairo_strokepath(thepath
->style
, thepath
->width
* passwidth
);
652 /*-------------------------------------------------------------------------*/
654 void UDrawSpline(splineptr thespline
, float passwidth
)
656 if (!areawin
->redraw_ongoing
) {
657 areawin
->redraw_needed
= True
;
661 cairo_move_to(areawin
->cr
, thespline
->ctrl
[0].x
, thespline
->ctrl
[0].y
);
662 cairo_curve_to(areawin
->cr
, thespline
->ctrl
[1].x
, thespline
->ctrl
[1].y
,
663 thespline
->ctrl
[2].x
, thespline
->ctrl
[2].y
,
664 thespline
->ctrl
[3].x
, thespline
->ctrl
[3].y
);
665 xc_cairo_strokepath(thespline
->style
, thespline
->width
* passwidth
);
668 /*-------------------------------------------------------------------------*/
670 void UDrawGraphic(graphicptr gp
)
674 if (!areawin
->redraw_ongoing
) {
675 areawin
->redraw_needed
= True
;
679 cairo_save(areawin
->cr
);
680 cairo_translate(areawin
->cr
,
683 cairo_rotate(areawin
->cr
, -gp
->rotation
* RADFAC
);
684 cairo_scale(areawin
->cr
, gp
->scale
, -gp
->scale
);
685 w
= cairo_image_surface_get_width(gp
->source
);
686 h
= cairo_image_surface_get_height(gp
->source
);
687 cairo_set_source_surface(areawin
->cr
, gp
->source
,
689 cairo_rectangle(areawin
->cr
, -w
/ 2, -h
/ 2, w
, h
);
690 cairo_clip(areawin
->cr
);
691 cairo_paint(areawin
->cr
);
692 cairo_restore(areawin
->cr
);
695 /*----------------------------*/
696 /* Draw the grids, axis, etc. */
697 /*----------------------------*/
699 void draw_grids(void)
701 double spc
, spc2
, spc3
;
702 cairo_matrix_t m
= {1., 0., 0., -1., 0., 0.};
703 m
.x0
= -areawin
->pcorner
.x
* areawin
->vscale
;
704 m
.y0
= areawin
->height
+ areawin
->pcorner
.y
* areawin
->vscale
;
706 if (!areawin
->redraw_ongoing
) {
707 areawin
->redraw_needed
= True
;
711 cairo_save(areawin
->cr
);
713 /* draw lines for grid */
714 spc
= xobjs
.pagelist
[areawin
->page
]->gridspace
* areawin
->vscale
;
715 if (areawin
->gridon
&& spc
> 8) {
718 /* find bottom-right point on the grid */
719 double xbegin
= areawin
->width
;
720 double ybegin
= areawin
->height
;
721 cairo_set_matrix(areawin
->cr
, &m
);
722 cairo_scale(areawin
->cr
, spc
, spc
);
723 cairo_device_to_user(areawin
->cr
, &xbegin
, &ybegin
);
724 xbegin
= floor(xbegin
);
725 ybegin
= ceil(ybegin
);
728 cairo_user_to_device(areawin
->cr
, &xbegin
, &ybegin
);
729 cairo_identity_matrix(areawin
->cr
);
731 xc_cairo_set_color(GRIDCOLOR
);
732 cairo_set_line_width(areawin
->cr
, 1.);
733 for (x
= xbegin
; x
>= 0.; x
-= spc
, ix
--) {
734 if (!ix
&& areawin
->axeson
) continue; /* do not draw main axis */
735 cairo_move_to(areawin
->cr
, floor(x
) + .5, .5);
736 cairo_line_to(areawin
->cr
, floor(x
) + .5, areawin
->height
+ .5);
738 for (y
= ybegin
; y
>= 0.; y
-= spc
, iy
++) {
739 if (!iy
&& areawin
->axeson
) continue; /* do not draw main axis */
740 cairo_move_to(areawin
->cr
, .5, floor(y
) + .5);
741 cairo_line_to(areawin
->cr
, areawin
->width
+ .5, floor(y
) + .5);
743 cairo_stroke(areawin
->cr
);
747 if (areawin
->axeson
) {
750 cairo_set_matrix(areawin
->cr
, &m
);
751 cairo_user_to_device(areawin
->cr
, &x
, &y
);
752 cairo_identity_matrix(areawin
->cr
);
754 xc_cairo_set_color(AXESCOLOR
);
755 cairo_set_line_width(areawin
->cr
, 1.);
756 cairo_move_to(areawin
->cr
, floor(x
) + .5, .5);
757 cairo_line_to(areawin
->cr
, floor(x
) + .5, areawin
->height
+ .5);
758 cairo_move_to(areawin
->cr
, .5, floor(y
) + .5);
759 cairo_line_to(areawin
->cr
, areawin
->width
+ .5, floor(y
) + .5);
760 cairo_stroke(areawin
->cr
);
763 /* bounding box goes beneath everything except grid/axis lines */
766 /* draw a little red dot at each snap-to point */
767 spc2
= xobjs
.pagelist
[areawin
->page
]->snapspace
* areawin
->vscale
;
768 if (areawin
->snapto
&& spc2
> 8) {
770 /* find bottom-right point on the grid */
771 double xbegin
= areawin
->width
;
772 double ybegin
= areawin
->height
;
773 cairo_set_matrix(areawin
->cr
, &m
);
774 cairo_scale(areawin
->cr
, spc2
, spc2
);
775 cairo_device_to_user(areawin
->cr
, &xbegin
, &ybegin
);
776 xbegin
= floor(xbegin
);
777 ybegin
= ceil(ybegin
);
778 cairo_user_to_device(areawin
->cr
, &xbegin
, &ybegin
);
779 cairo_identity_matrix(areawin
->cr
);
781 xc_cairo_set_color(SNAPCOLOR
);
782 cairo_set_line_width(areawin
->cr
, 1.);
783 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_ROUND
);
784 for (x
= xbegin
; x
>= 0.; x
-= spc2
) {
785 for (y
= ybegin
; y
>= 0.; y
-= spc2
) {
786 cairo_move_to(areawin
->cr
, floor(x
) + .5, floor(y
) + .5);
787 cairo_close_path(areawin
->cr
);
790 cairo_stroke(areawin
->cr
);
793 /* Draw major snap points */
797 /* find bottom-right point on the grid */
798 double xbegin
= areawin
->width
;
799 double ybegin
= areawin
->height
;
800 cairo_set_matrix(areawin
->cr
, &m
);
801 cairo_scale(areawin
->cr
, spc3
, spc3
);
802 cairo_device_to_user(areawin
->cr
, &xbegin
, &ybegin
);
803 xbegin
= floor(xbegin
);
804 ybegin
= ceil(ybegin
);
805 cairo_user_to_device(areawin
->cr
, &xbegin
, &ybegin
);
806 cairo_identity_matrix(areawin
->cr
);
808 xc_cairo_set_color(GRIDCOLOR
);
809 cairo_set_line_width(areawin
->cr
, 3.);
810 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_ROUND
);
811 for (x
= xbegin
; x
>= 0.; x
-= spc3
) {
812 for (y
= ybegin
; y
>= 0.; y
-= spc3
) {
813 cairo_move_to(areawin
->cr
, floor(x
) + .5, floor(y
) + .5);
814 cairo_close_path(areawin
->cr
);
817 cairo_stroke(areawin
->cr
);
819 cairo_restore(areawin
->cr
);
822 /*---------------------------------------------------------------------*/
823 /* Draw a string at position offset, starting at the start index and */
824 /* ending before the end index. The offset is updated on return. */
825 /*---------------------------------------------------------------------*/
827 void UDrawCharString(u_char
*text
, int start
, int end
, XfPoint
*offset
,
828 short styles
, short ffont
, int groupheight
, int passcolor
, float tmpscale
)
830 int idx
, nglyphs
= 0;
833 cairo_glyph_t
*glyphs
;
836 cairo_get_matrix(areawin
->cr
, &oldm
);
837 cairo_scale(areawin
->cr
, tmpscale
, fabs(tmpscale
));
839 /* under- and overlines */
841 y
= offset
->y
/ tmpscale
- 6.;
842 else if (styles
& 16)
843 y
= offset
->y
/ tmpscale
+ groupheight
+ 4;
845 /* under/overline thickness scales if bold */
846 float tmpthick
= ((fonts
[ffont
].flags
& 0x21) == 0x21) ? 4.0 : 2.0;
847 cairo_set_line_width(areawin
->cr
, tmpthick
);
849 x
= offset
->x
/ tmpscale
;
852 glyphs
= cairo_glyph_allocate(end
- start
);
853 for (idx
= start
; idx
< end
; idx
++)
856 glyphs
[nglyphs
].index
= fonts
[ffont
].glyph_index
[text
[idx
]];
857 glyphs
[nglyphs
].x
= offset
->x
/ tmpscale
;
858 glyphs
[nglyphs
].y
= offset
->y
/ fabs(tmpscale
);
860 /* Determine character width */
861 offset
->x
+= fonts
[ffont
].glyph_advance
[text
[idx
]] * tmpscale
;
864 cairo_show_glyphs(areawin
->cr
, glyphs
, nglyphs
);
865 cairo_new_path(areawin
->cr
);
867 cairo_glyph_free(glyphs
);
870 cairo_move_to(areawin
->cr
, x
, y
);
871 cairo_line_to(areawin
->cr
, offset
->x
/ tmpscale
, y
);
872 cairo_stroke(areawin
->cr
);
874 cairo_set_matrix(areawin
->cr
, &oldm
);
877 /*----------------------------------------------------------------------*/
878 /* A completely stripped down version of UDrawObject, used for stroke */
879 /* font drawing in xc_user_font_render */
880 /*----------------------------------------------------------------------*/
882 static void xc_draw_glyph_object(objinstptr inst
, float passwidth
)
886 objectptr obj
= inst
->thisobject
;
889 for (thispart
= 0; thispart
< obj
->parts
; thispart
++) {
890 areagen
= obj
->plist
+ thispart
;
891 switch(ELEMENTTYPE(*areagen
)) {
893 UDrawPolygon(TOPOLY(areagen
), passwidth
);
896 UDrawSpline(TOSPLINE(areagen
), passwidth
);
899 UDrawArc(TOARC(areagen
), passwidth
);
902 UDrawPath(TOPATH(areagen
), passwidth
);
905 ptr
= TOOBJINST(areagen
);
906 cairo_save(areawin
->cr
);
907 cairo_translate(areawin
->cr
, ptr
->position
.x
, ptr
->position
.y
);
908 cairo_rotate(areawin
->cr
, -ptr
->rotation
* RADFAC
);
909 cairo_scale(areawin
->cr
, ptr
->scale
, fabs(ptr
->scale
));
910 xc_draw_glyph_object(ptr
, passwidth
);
911 cairo_restore(areawin
->cr
);
917 /*----------------------------------------------------------------------*/
918 /* Rendering function for a cairo_user_font_face, to draw the stroke */
919 /* fonts of xcircuit */
920 /* TODO: always this factor 40 to match with cairo. Is it BASELINE? */
921 /*----------------------------------------------------------------------*/
923 static cairo_status_t
xc_user_font_render(cairo_scaled_font_t
*scaled_font
,
924 unsigned long glyph
, cairo_t
*cr
, cairo_text_extents_t
*extents
)
928 objinstptr theinstance
;
931 double llx
, lly
, trx
, try;
933 cairo_font_face_t
*ff
= cairo_scaled_font_get_font_face(scaled_font
);
934 size_t fontidx
= (size_t) cairo_font_face_get_user_data(ff
, &fontinfo_key
);
935 fontinfo
*fi
= &fonts
[fontidx
];
937 chr
= fi
->encoding
[glyph
];
938 theinstance
= &charinst
;
939 charinst
.thisobject
= chr
;
941 llx
= chr
->bbox
.lowerleft
.x
/ 40.;
942 lly
= chr
->bbox
.lowerleft
.y
/ 40.;
943 trx
= (chr
->bbox
.lowerleft
.x
+ chr
->bbox
.width
) / 40.;
944 try = (chr
->bbox
.lowerleft
.y
+ chr
->bbox
.height
) / 40.;
946 /* temporary override areawin->cr with the font context */
947 old_cr
= areawin
->cr
;
950 cairo_scale(cr
, 1. / 40., -1. / 40.);
951 cairo_set_line_width(cr
, 1);
953 /* if font is derived and italic, premultiply by slanting matrix */
954 if ((fi
->flags
& 0x22) == 0x22) {
955 cairo_matrix_t m
= {1., 0., .25, 1., 0., 0.};
956 cairo_transform(areawin
->cr
, &m
);
960 /* simple boldface technique for derived fonts */
961 passwidth
= ((fi
->flags
& 0x21) == 0x21) ? 4. : 2.;
963 /* Correct extentswith line width */
964 llx
-= passwidth
/ 40.;
965 lly
-= passwidth
/ 40.;
966 trx
+= passwidth
/ 40.;
967 try += passwidth
/ 40.;
969 xc_draw_glyph_object(theinstance
, passwidth
);
971 extents
->x_bearing
= llx
;
972 extents
->y_bearing
= -try;
973 extents
->width
= trx
- llx
;
974 extents
->height
= try - lly
;
975 extents
->x_advance
= (chr
->bbox
.lowerleft
.x
+ chr
->bbox
.width
) / 40.;
976 extents
->y_advance
= 0.;
978 areawin
->cr
= old_cr
;
979 return CAIRO_STATUS_SUCCESS
;
982 /*----------------------------------------------------------------------*/
983 /* Function to translate unicode into a glyph index for the stroke font */
984 /*----------------------------------------------------------------------*/
986 static cairo_status_t
xc_user_font_glyph(cairo_scaled_font_t
*scaled_font
,
987 unsigned long unicode
, unsigned long *glyph_index
)
989 cairo_font_face_t
*ff
= cairo_scaled_font_get_font_face(scaled_font
);
990 size_t fontidx
= (size_t) cairo_font_face_get_user_data(ff
, &fontinfo_key
);
991 fontinfo
*fi
= &fonts
[fontidx
];
994 /* search all glyphs in the utf8encoding. This is allowed to be slow, */
995 /* as the glyph list will be buffered anyway */
996 for (idx
= 1; idx
< 255; idx
++) {
997 const char *s
= fi
->utf8encoding
[idx
];
1000 /* Convert utf-8 to unicode */
1001 unsigned long uc
= s
[0];
1003 unsigned long mask
= 0x3f;
1004 while ((s
[++cidx
] & 0xc0) == 0x80) {
1005 uc
= (uc
<< 6) | (s
[cidx
] & 0x3f);
1006 mask
= (mask
<< 5) | 0x1f;
1011 if (unicode
== uc
) {
1013 return CAIRO_STATUS_SUCCESS
;
1016 /* This should not happen: replace unknown glyph with question mark */
1018 return CAIRO_STATUS_SUCCESS
;
1021 /*---------------------------------------------------------------------*/
1022 /* find the corresponing cairo fontface for a given fontinfo structure */
1023 /*---------------------------------------------------------------------*/
1026 const char* postscript_name
;
1027 const char* replacement_name
;
1028 const char* foundry_name
;
1029 } xc_font_replacement
;
1031 static const xc_font_replacement replacement_fonts
[] =
1033 /* First try to see if 'real' postscript fonts have been installed */
1034 {"ITC Avant Garde Gothic", "ITC Avant Garde Gothic", "adobe"},
1035 {"ITC Bookman", "ITC Bookman", "adobe"},
1036 {"Courier", "Courier", "adobe"},
1037 {"Helvetica", "Helvetica", "adobe"},
1038 {"Helvetica Narrow", "Helvetica Narrow", "adobe"},
1039 {"New Century Schoolbook", "New Century Schoolbook", "adobe"},
1040 {"Palatino", "Palatino", "adobe"},
1041 {"Symbol", "Symbol", "adobe"},
1042 {"Times", "Times", "adobe"},
1043 {"Times-Roman", "Times-Roman", "adobe"},
1044 {"ITC ZapfChangery", "ITC ZapfChangery", "adobe"},
1045 {"ITC ZapfDingbats", "ITC ZapfDingbats", "adobe"},
1046 /* Next try the URW postscript fonts (guaranteed to have same extents) */
1047 {"ITC Avant Garde Gothic", "URW Gothic L", "urw"},
1048 {"ITC Bookman", "URW Bookman L", "urw"},
1049 {"Courier", "Nimbus Mono L", "urw"},
1050 {"Helvetica", "Nimbus Sans L", "urw"},
1051 {"Helvetica Narrow", "Nimbus Sans L Condensed", "urw"},
1052 {"New Century Schoolbook", "Century Schoolbook L", "urw"},
1053 {"Palatino", "URW Palladio L", "urw"},
1054 {"Symbol", "Standard Symbols L", "urw"},
1055 {"Times", "Nimbus Roman No9 L", "urw"},
1056 {"Times-Roman", "Nimbus Roman No9 L", "urw"},
1057 {"ITC ZapfChangery", "URW Changery L", "urw"},
1058 {"ITC ZapfDingbats", "Dingbats", "urw"},
1059 /* No success, use the 'old' stroke fonts */
1063 void xc_cairo_set_fontinfo(size_t fontidx
)
1065 /* TODO: memory leak. font_face is created here. It should also be */
1066 /* destroyed again somewhere */
1067 fontinfo
*fi
= &fonts
[fontidx
];
1068 const char *family
= fi
->family
;
1069 const xc_font_replacement
*replace
;
1072 #ifdef CAIRO_HAS_FC_FONT
1073 int weight
= FC_WEIGHT_NORMAL
;
1074 int slant
= FC_SLANT_ROMAN
;
1076 fi
->font_face
= NULL
;
1079 weight
= FC_WEIGHT_BOLD
;
1081 if (fi
->flags
& 2) {
1082 if (!strcmp(family
, "Helvetica"))
1083 slant
= FC_SLANT_OBLIQUE
;
1085 slant
= FC_SLANT_ITALIC
;
1087 /* Try to find a proper postscript font */
1088 for (replace
= replacement_fonts
; replace
->postscript_name
; replace
++) {
1089 if (!strcmp(replace
->postscript_name
, fi
->family
)) {
1091 FcChar8
*matched_family
, *matched_foundry
;
1093 FcPattern
*pattern
= FcPatternBuild(NULL
,
1094 FC_FAMILY
, FcTypeString
, replace
->replacement_name
,
1095 FC_WEIGHT
, FcTypeInteger
, weight
,
1096 FC_SLANT
, FcTypeInteger
, slant
,
1097 FC_FOUNDRY
, FcTypeString
, replace
->foundry_name
,
1099 FcConfigSubstitute(0, pattern
, FcMatchPattern
);
1100 FcDefaultSubstitute(pattern
);
1101 matched
= FcFontMatch(0, pattern
, &result
);
1102 /* Check if the matched font is actually the replacement font */
1103 FcPatternGetString(matched
, FC_FAMILY
, 0, &matched_family
);
1104 FcPatternGetString(matched
, FC_FOUNDRY
, 0, &matched_foundry
);
1105 if (!strcmp(matched_family
, replace
->replacement_name
)
1106 && !strcmp(matched_foundry
, replace
->foundry_name
))
1107 fi
->font_face
= cairo_ft_font_face_create_for_pattern(matched
);
1108 FcPatternDestroy(matched
);
1109 FcPatternDestroy(pattern
);
1114 #else /* CAIRO_HAS_FC_FONT */
1115 fi
->font_face
= NULL
;
1116 #endif /* CAIRO_HAS_FC_FONT */
1118 /* Cache the dimensions and all glyphs of the font */
1119 if (fi
->font_face
) {
1121 cairo_glyph_t
*glyphs
= NULL
;
1122 cairo_scaled_font_t
*scaled_font
;
1123 cairo_text_extents_t extents
;
1125 cairo_save(areawin
->cr
);
1126 cairo_identity_matrix(areawin
->cr
);
1127 cairo_set_font_face(areawin
->cr
, fi
->font_face
);
1128 cairo_set_font_size(areawin
->cr
, 100.);
1129 scaled_font
= cairo_get_scaled_font(areawin
->cr
);
1130 for (c
= 1; c
< 256; c
++) { /* skip encoding at index 0 */
1131 cairo_scaled_font_text_to_glyphs(scaled_font
, 0., 0.,
1132 fi
->utf8encoding
[c
], -1, &glyphs
, &num_glyphs
,
1134 fi
->glyph_index
[c
] = glyphs
[0].index
;
1135 cairo_scaled_font_glyph_extents(scaled_font
, glyphs
, 1, &extents
);
1136 fi
->glyph_top
[c
] = -extents
.y_bearing
* 40. / 100.;
1137 /* fi->glyph_bottom[c] = extents.height * 40. / 100. + fi->glyph_top[c]; */
1138 fi
->glyph_bottom
[c
] = fi
->glyph_top
[c
] - extents
.height
* 40. / 100.;
1139 fi
->glyph_advance
[c
] = extents
.x_advance
* 40. / 100.;
1141 cairo_glyph_free(glyphs
);
1142 cairo_restore(areawin
->cr
);
1145 /* No decent postscript font found. Backup using stroke fonts */
1146 fi
->font_face
= cairo_user_font_face_create();
1147 cairo_font_face_set_user_data(fi
->font_face
, &fontinfo_key
,
1148 (void*) fontidx
, (cairo_destroy_func_t
) cairo_font_face_destroy
);
1149 cairo_user_font_face_set_render_glyph_func(fi
->font_face
,
1150 xc_user_font_render
);
1151 cairo_user_font_face_set_unicode_to_glyph_func(fi
->font_face
,
1152 xc_user_font_glyph
);
1153 for (c
= 0; c
< 256; c
++) {
1154 objectptr chr
= fi
->encoding
[c
];
1155 fi
->glyph_index
[c
] = c
;
1156 fi
->glyph_top
[c
] = chr
->bbox
.lowerleft
.y
+ chr
->bbox
.height
;
1157 fi
->glyph_bottom
[c
] = chr
->bbox
.lowerleft
.y
;
1158 fi
->glyph_advance
[c
] = chr
->bbox
.lowerleft
.x
+ chr
->bbox
.width
;
1163 /*----------------------------------------------------------------------*/
1164 /* A light wrapper around cairo_surface_t, to a generalized xcImage */
1165 /*----------------------------------------------------------------------*/
1167 /* caching for cairo_surface_t */
1168 static xcImage
*xcImagePixel_oldimg
= NULL
;
1169 static uint32_t *xcImagePixel_data
;
1170 static int xcImagePixel_width
;
1171 static int xcImagePixel_height
;
1173 static inline void xcImageCheckCache(xcImage
*img
)
1175 if (img
!= xcImagePixel_oldimg
) {
1176 xcImagePixel_oldimg
= img
;
1177 xcImagePixel_data
= (uint32_t*) cairo_image_surface_get_data(img
);
1178 xcImagePixel_width
= cairo_image_surface_get_width(img
);
1179 xcImagePixel_height
= cairo_image_surface_get_height(img
);
1183 xcImage
*xcImageCreate(int width
, int height
)
1185 return cairo_image_surface_create(CAIRO_FORMAT_RGB24
, width
, height
);
1188 void xcImageDestroy(xcImage
*img
)
1190 cairo_surface_destroy(img
);
1193 int xcImageGetWidth(xcImage
*img
)
1195 xcImageCheckCache(img
);
1196 return xcImagePixel_width
;
1199 int xcImageGetHeight(xcImage
*img
)
1201 xcImageCheckCache(img
);
1202 return xcImagePixel_height
;
1205 void xcImagePutPixel(xcImage
*img
, int x
, int y
, u_char r
, u_char g
, u_char b
)
1207 xcImageCheckCache(img
);
1208 xcImagePixel_data
[y
* xcImagePixel_width
+ x
] = (r
<< 16) | (g
<< 8) | b
;
1211 void xcImageGetPixel(xcImage
*img
, int x
, int y
, u_char
*r
, u_char
*g
,
1215 xcImageCheckCache(img
);
1216 argb
= xcImagePixel_data
[y
* xcImagePixel_width
+ x
];
1223 /*------------------------------------------------------------------------*/
1224 /* Ghostscript rendering function. In contrast to X11, direct calls to */
1225 /* ghostscriptapi are made */
1226 /*------------------------------------------------------------------------*/
1228 /*------------------------------------------------------------------------*/
1229 /* gsapi I/O redirection functions */
1230 /*------------------------------------------------------------------------*/
1233 static int GSDLLCALL
gs_stdin_fn(void *caller_handle
, char *buf
, int len
)
1235 UNUSED(caller_handle
); UNUSED(buf
); UNUSED(len
);
1240 static int GSDLLCALL
gs_stdout_fn(void *caller_handle
, const char *str
, int len
)
1243 UNUSED(caller_handle
); UNUSED(str
);
1245 fwrite(str
, 1, len
, stdout
);
1251 static int GSDLLCALL
gs_stderr_fn(void *caller_handle
, const char *str
, int len
)
1254 UNUSED(caller_handle
); UNUSED(str
);
1256 fwrite(str
, 1, len
, stderr
);
1261 #endif /* HAVE_GS */
1263 /*------------------------------------------------------------------------*/
1264 /* gsapi displaycallback functions */
1265 /*------------------------------------------------------------------------*/
1268 static unsigned char *gs_pimage
;
1269 static int gs_width
, gs_height
, gs_raster
;
1271 static int gs_display_dummy(void)
1275 #endif /* HAVE_GS */
1278 static int gs_display_size(void *handle
, void *device
, int width
, int height
,
1279 int raster
, unsigned int format
, unsigned char *pimage
)
1281 UNUSED(handle
); UNUSED(device
); UNUSED(format
);
1289 #endif /* HAVE_GS */
1292 int gs_display_page(void *handle
, void *device
, int copies
, int flush
)
1294 cairo_surface_t
*tbuf
;
1296 UNUSED(handle
); UNUSED(device
); UNUSED(copies
); UNUSED(flush
);
1299 cairo_surface_destroy(bbuf
);
1300 /* Since cairo_image_surface_create_for_data assumes the buffer to be */
1301 /* valid until destruction, and ghostscript frees it immediately, */
1302 /* first use a temporary buffer. Then immediately copy the buffer */
1303 /* To the final location */
1304 tbuf
= cairo_image_surface_create_for_data(gs_pimage
, CAIRO_FORMAT_RGB24
,
1305 gs_width
, gs_height
, gs_raster
);
1306 bbuf
= cairo_image_surface_create(CAIRO_FORMAT_RGB24
, gs_width
, gs_height
);
1307 bbuf_cr
= cairo_create(bbuf
);
1308 cairo_set_source_surface(bbuf_cr
, tbuf
, 0., 0.);
1309 cairo_paint(bbuf_cr
);
1310 cairo_destroy(bbuf_cr
);
1311 cairo_surface_destroy(tbuf
);
1314 #endif /* HAVE_GS */
1317 display_callback gs_display
= {
1318 sizeof(display_callback
),
1319 DISPLAY_VERSION_MAJOR
,
1320 DISPLAY_VERSION_MINOR
,
1321 (int (*)(void*, void*)) gs_display_dummy
, /* display_open */
1322 (int (*)(void*, void*)) gs_display_dummy
, /* display_preclose */
1323 (int (*)(void*, void*)) gs_display_dummy
, /* display_close */
1324 (int (*)(void*, void*, int, int, int, unsigned int)) gs_display_dummy
,
1325 /* display_presize */
1327 (int (*)(void*, void*)) gs_display_dummy
, /* display_sync */
1329 NULL
, /* display_update */
1330 NULL
, /* display_memalloc */
1331 NULL
, /* display_memfree */
1332 NULL
/* display_separation */
1334 #endif /* HAVE_GS */
1336 /*------------------------------------------------------*/
1337 /* write scale and position to ghostscript */
1338 /* and tell ghostscript to run the requested file */
1339 /*------------------------------------------------------*/
1342 const char *gs_argv
[] = {
1343 "-dQUIET", /* Suppress startup messages */
1344 "-dNOPAUSE", /* Disable pause at end of page */
1345 "-dBATCH", /* Exit when all files done */
1347 "-sDisplayHandle=0",
1348 "-r75", /* Display resolution */
1349 "-dGraphicsAlphaBits=4", /* Graphics anti-aliasing */
1350 "-dTextAlphaBits=4" /* Text anti-aliasing */
1352 #endif /* HAVE_GS */
1354 void write_scale_position_and_run_gs(float norm
, float xpos
, float ypos
,
1358 UNUSED(norm
); UNUSED(xpos
); UNUSED(ypos
); UNUSED(bgfile
);
1361 int i
, code
, exit_code
;
1364 char display_format
[] = "-dDisplayFormat=........";
1365 char pixmap_size
[] = "-g........x........";
1366 int argc
= sizeof(gs_argv
) / sizeof(gs_argv
[0]);
1367 const char **argv
= (const char**) malloc((argc
+ 2) * sizeof(const char*));
1369 for (i
= 0; i
< argc
; i
++)
1370 argv
[i
] = gs_argv
[i
];
1371 argv
[argc
++] = display_format
;
1372 argv
[argc
++] = pixmap_size
;
1376 " /setpagedevice {pop} def"
1378 " %3.2f %3.2f translate"
1379 " %3.2f %3.2f scale"
1383 xpos
, ypos
, norm
, norm
, bgfile
);
1385 sprintf(display_format
, "-dDisplayFormat=%d", DISPLAY_COLORS_RGB
1386 | DISPLAY_UNUSED_LAST
| DISPLAY_DEPTH_8
| DISPLAY_LITTLEENDIAN
1387 | DISPLAY_TOPFIRST
| DISPLAY_ROW_ALIGN_DEFAULT
);
1388 sprintf(pixmap_size
, "-g%dx%d", areawin
->width
, areawin
->height
);
1390 XDefineCursor(dpy
, areawin
->window
, WAITFOR
);
1392 if ((code
= gsapi_new_instance(&instance
, NULL
)) == 0) {
1393 gsapi_set_stdio(instance
, gs_stdin_fn
, gs_stdout_fn
, gs_stderr_fn
);
1394 gsapi_set_display_callback(instance
, &gs_display
);
1395 if (!(code
= gsapi_init_with_args(instance
, argc
, (char**) argv
)))
1396 gsapi_run_string(instance
, gs_cmd
, 0, &exit_code
);
1397 gsapi_exit(instance
);
1398 gsapi_delete_instance(instance
);
1402 fprintf(stdout
, "Xcircuit: ghostscript done\n");
1405 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
1406 areawin
->lastbackground
= xobjs
.pagelist
[areawin
->page
]->background
.name
;
1407 drawarea(areawin
->area
, NULL
, NULL
);
1408 #endif /* HAVE_GS */
1409 gs_state
= GS_READY
;
1412 #else /* HAVE_CAIRO */
1413 typedef int no_empty_translation_unit_warning
;
1414 #endif /* HAVE_CAIRO */