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
)
609 if (!areawin
->redraw_ongoing
) {
610 areawin
->redraw_needed
= True
;
614 /* Draw first point */
615 if (thepath
->parts
) {
616 genpath
= thepath
->plist
;
617 switch(ELEMENTTYPE(*genpath
)) {
619 thepoly
= TOPOLY(genpath
);
620 cairo_move_to(areawin
->cr
, thepoly
->points
[0].x
,
621 thepoly
->points
[0].y
);
622 xp
= &thepoly
->points
[0];
625 thespline
= TOSPLINE(genpath
);
626 cairo_move_to(areawin
->cr
, thespline
->ctrl
[0].x
,
627 thespline
->ctrl
[0].y
);
628 xp
= &thespline
->ctrl
[0];
632 /* Draw all other points */
633 for (genpath
= thepath
->plist
; genpath
< thepath
->plist
+ thepath
->parts
;
637 switch(ELEMENTTYPE(*genpath
)) {
639 thepoly
= TOPOLY(genpath
);
640 for (i
= 1; i
< thepoly
->number
; i
++)
641 cairo_line_to(areawin
->cr
, thepoly
->points
[i
].x
,
642 thepoly
->points
[i
].y
);
643 xp
= &thepoly
->points
[thepoly
->number
- 1];
646 thespline
= TOSPLINE(genpath
);
648 /* If the curve 1st point is not the same as the last point
649 * drawn, then first draw a line to the first curve point.
652 if ((thespline
->ctrl
[0].x
!= xp
->x
) || (thespline
->ctrl
[0].y
!= xp
->y
))
653 cairo_line_to(areawin
->cr
, thespline
->ctrl
[0].x
,
654 thespline
->ctrl
[0].y
);
656 cairo_curve_to(areawin
->cr
, thespline
->ctrl
[1].x
,
657 thespline
->ctrl
[1].y
, thespline
->ctrl
[2].x
,
658 thespline
->ctrl
[2].y
, thespline
->ctrl
[3].x
,
659 thespline
->ctrl
[3].y
);
660 xp
= &thespline
->ctrl
[3];
664 xc_cairo_strokepath(thepath
->style
, thepath
->width
* passwidth
);
667 /*-------------------------------------------------------------------------*/
669 void UDrawSpline(splineptr thespline
, float passwidth
)
671 if (!areawin
->redraw_ongoing
) {
672 areawin
->redraw_needed
= True
;
676 cairo_move_to(areawin
->cr
, thespline
->ctrl
[0].x
, thespline
->ctrl
[0].y
);
677 cairo_curve_to(areawin
->cr
, thespline
->ctrl
[1].x
, thespline
->ctrl
[1].y
,
678 thespline
->ctrl
[2].x
, thespline
->ctrl
[2].y
,
679 thespline
->ctrl
[3].x
, thespline
->ctrl
[3].y
);
680 xc_cairo_strokepath(thespline
->style
, thespline
->width
* passwidth
);
683 /*-------------------------------------------------------------------------*/
685 void UDrawGraphic(graphicptr gp
)
689 if (!areawin
->redraw_ongoing
) {
690 areawin
->redraw_needed
= True
;
694 cairo_save(areawin
->cr
);
695 cairo_translate(areawin
->cr
,
698 cairo_rotate(areawin
->cr
, -gp
->rotation
* RADFAC
);
699 cairo_scale(areawin
->cr
, gp
->scale
, -gp
->scale
);
700 w
= cairo_image_surface_get_width(gp
->source
);
701 h
= cairo_image_surface_get_height(gp
->source
);
702 cairo_set_source_surface(areawin
->cr
, gp
->source
,
704 cairo_rectangle(areawin
->cr
, -w
/ 2, -h
/ 2, w
, h
);
705 cairo_clip(areawin
->cr
);
706 cairo_paint(areawin
->cr
);
707 cairo_restore(areawin
->cr
);
710 /*----------------------------*/
711 /* Draw the grids, axis, etc. */
712 /*----------------------------*/
714 void draw_grids(void)
716 double spc
, spc2
, spc3
;
717 cairo_matrix_t m
= {1., 0., 0., -1., 0., 0.};
718 m
.x0
= -areawin
->pcorner
.x
* areawin
->vscale
;
719 m
.y0
= areawin
->height
+ areawin
->pcorner
.y
* areawin
->vscale
;
721 if (!areawin
->redraw_ongoing
) {
722 areawin
->redraw_needed
= True
;
726 cairo_save(areawin
->cr
);
728 /* draw lines for grid */
729 spc
= xobjs
.pagelist
[areawin
->page
]->gridspace
* areawin
->vscale
;
730 if (areawin
->gridon
&& spc
> 8) {
733 /* find bottom-right point on the grid */
734 double xbegin
= areawin
->width
;
735 double ybegin
= areawin
->height
;
736 cairo_set_matrix(areawin
->cr
, &m
);
737 cairo_scale(areawin
->cr
, spc
, spc
);
738 cairo_device_to_user(areawin
->cr
, &xbegin
, &ybegin
);
739 xbegin
= floor(xbegin
);
740 ybegin
= ceil(ybegin
);
743 cairo_user_to_device(areawin
->cr
, &xbegin
, &ybegin
);
744 cairo_identity_matrix(areawin
->cr
);
746 xc_cairo_set_color(GRIDCOLOR
);
747 cairo_set_line_width(areawin
->cr
, 1.);
748 for (x
= xbegin
; x
>= 0.; x
-= spc
, ix
--) {
749 if (!ix
&& areawin
->axeson
) continue; /* do not draw main axis */
750 cairo_move_to(areawin
->cr
, floor(x
) + .5, .5);
751 cairo_line_to(areawin
->cr
, floor(x
) + .5, areawin
->height
+ .5);
753 for (y
= ybegin
; y
>= 0.; y
-= spc
, iy
++) {
754 if (!iy
&& areawin
->axeson
) continue; /* do not draw main axis */
755 cairo_move_to(areawin
->cr
, .5, floor(y
) + .5);
756 cairo_line_to(areawin
->cr
, areawin
->width
+ .5, floor(y
) + .5);
758 cairo_stroke(areawin
->cr
);
762 if (areawin
->axeson
) {
765 cairo_set_matrix(areawin
->cr
, &m
);
766 cairo_user_to_device(areawin
->cr
, &x
, &y
);
767 cairo_identity_matrix(areawin
->cr
);
769 xc_cairo_set_color(AXESCOLOR
);
770 cairo_set_line_width(areawin
->cr
, 1.);
771 cairo_move_to(areawin
->cr
, floor(x
) + .5, .5);
772 cairo_line_to(areawin
->cr
, floor(x
) + .5, areawin
->height
+ .5);
773 cairo_move_to(areawin
->cr
, .5, floor(y
) + .5);
774 cairo_line_to(areawin
->cr
, areawin
->width
+ .5, floor(y
) + .5);
775 cairo_stroke(areawin
->cr
);
778 /* bounding box goes beneath everything except grid/axis lines */
781 /* draw a little red dot at each snap-to point */
782 spc2
= xobjs
.pagelist
[areawin
->page
]->snapspace
* areawin
->vscale
;
783 if (areawin
->snapto
&& spc2
> 8) {
785 /* find bottom-right point on the grid */
786 double xbegin
= areawin
->width
;
787 double ybegin
= areawin
->height
;
788 cairo_set_matrix(areawin
->cr
, &m
);
789 cairo_scale(areawin
->cr
, spc2
, spc2
);
790 cairo_device_to_user(areawin
->cr
, &xbegin
, &ybegin
);
791 xbegin
= floor(xbegin
);
792 ybegin
= ceil(ybegin
);
793 cairo_user_to_device(areawin
->cr
, &xbegin
, &ybegin
);
794 cairo_identity_matrix(areawin
->cr
);
796 xc_cairo_set_color(SNAPCOLOR
);
797 cairo_set_line_width(areawin
->cr
, 1.);
798 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_ROUND
);
799 for (x
= xbegin
; x
>= 0.; x
-= spc2
) {
800 for (y
= ybegin
; y
>= 0.; y
-= spc2
) {
801 cairo_move_to(areawin
->cr
, floor(x
) + .5, floor(y
) + .5);
802 cairo_close_path(areawin
->cr
);
805 cairo_stroke(areawin
->cr
);
808 /* Draw major snap points */
812 /* find bottom-right point on the grid */
813 double xbegin
= areawin
->width
;
814 double ybegin
= areawin
->height
;
815 cairo_set_matrix(areawin
->cr
, &m
);
816 cairo_scale(areawin
->cr
, spc3
, spc3
);
817 cairo_device_to_user(areawin
->cr
, &xbegin
, &ybegin
);
818 xbegin
= floor(xbegin
);
819 ybegin
= ceil(ybegin
);
820 cairo_user_to_device(areawin
->cr
, &xbegin
, &ybegin
);
821 cairo_identity_matrix(areawin
->cr
);
823 xc_cairo_set_color(GRIDCOLOR
);
824 cairo_set_line_width(areawin
->cr
, 3.);
825 cairo_set_line_cap(areawin
->cr
, CAIRO_LINE_CAP_ROUND
);
826 for (x
= xbegin
; x
>= 0.; x
-= spc3
) {
827 for (y
= ybegin
; y
>= 0.; y
-= spc3
) {
828 cairo_move_to(areawin
->cr
, floor(x
) + .5, floor(y
) + .5);
829 cairo_close_path(areawin
->cr
);
832 cairo_stroke(areawin
->cr
);
834 cairo_restore(areawin
->cr
);
837 /*---------------------------------------------------------------------*/
838 /* Draw a string at position offset, starting at the start index and */
839 /* ending before the end index. The offset is updated on return. */
840 /*---------------------------------------------------------------------*/
842 void UDrawCharString(u_char
*text
, int start
, int end
, XfPoint
*offset
,
843 short styles
, short ffont
, int groupheight
, int passcolor
, float tmpscale
)
845 int idx
, nglyphs
= 0;
848 cairo_glyph_t
*glyphs
;
851 cairo_get_matrix(areawin
->cr
, &oldm
);
852 cairo_scale(areawin
->cr
, tmpscale
, fabs(tmpscale
));
854 /* under- and overlines */
856 y
= offset
->y
/ tmpscale
- 6.;
857 else if (styles
& 16)
858 y
= offset
->y
/ tmpscale
+ groupheight
+ 4;
860 /* under/overline thickness scales if bold */
861 float tmpthick
= ((fonts
[ffont
].flags
& 0x21) == 0x21) ? 4.0 : 2.0;
862 cairo_set_line_width(areawin
->cr
, tmpthick
);
864 x
= offset
->x
/ tmpscale
;
867 glyphs
= cairo_glyph_allocate(end
- start
);
868 for (idx
= start
; idx
< end
; idx
++)
871 glyphs
[nglyphs
].index
= fonts
[ffont
].glyph_index
[text
[idx
]];
872 glyphs
[nglyphs
].x
= offset
->x
/ tmpscale
;
873 glyphs
[nglyphs
].y
= offset
->y
/ fabs(tmpscale
);
875 /* Determine character width */
876 offset
->x
+= fonts
[ffont
].glyph_advance
[text
[idx
]] * tmpscale
;
879 cairo_show_glyphs(areawin
->cr
, glyphs
, nglyphs
);
880 cairo_new_path(areawin
->cr
);
882 cairo_glyph_free(glyphs
);
885 cairo_move_to(areawin
->cr
, x
, y
);
886 cairo_line_to(areawin
->cr
, offset
->x
/ tmpscale
, y
);
887 cairo_stroke(areawin
->cr
);
889 cairo_set_matrix(areawin
->cr
, &oldm
);
892 /*----------------------------------------------------------------------*/
893 /* A completely stripped down version of UDrawObject, used for stroke */
894 /* font drawing in xc_user_font_render */
895 /*----------------------------------------------------------------------*/
897 static void xc_draw_glyph_object(objinstptr inst
, float passwidth
)
901 objectptr obj
= inst
->thisobject
;
904 for (thispart
= 0; thispart
< obj
->parts
; thispart
++) {
905 areagen
= obj
->plist
+ thispart
;
906 switch(ELEMENTTYPE(*areagen
)) {
908 UDrawPolygon(TOPOLY(areagen
), passwidth
);
911 UDrawSpline(TOSPLINE(areagen
), passwidth
);
914 UDrawArc(TOARC(areagen
), passwidth
);
917 UDrawPath(TOPATH(areagen
), passwidth
);
920 ptr
= TOOBJINST(areagen
);
921 cairo_save(areawin
->cr
);
922 cairo_translate(areawin
->cr
, ptr
->position
.x
, ptr
->position
.y
);
923 cairo_rotate(areawin
->cr
, -ptr
->rotation
* RADFAC
);
924 cairo_scale(areawin
->cr
, ptr
->scale
, fabs(ptr
->scale
));
925 xc_draw_glyph_object(ptr
, passwidth
);
926 cairo_restore(areawin
->cr
);
932 /*----------------------------------------------------------------------*/
933 /* Rendering function for a cairo_user_font_face, to draw the stroke */
934 /* fonts of xcircuit */
935 /* TODO: always this factor 40 to match with cairo. Is it BASELINE? */
936 /*----------------------------------------------------------------------*/
938 static cairo_status_t
xc_user_font_render(cairo_scaled_font_t
*scaled_font
,
939 unsigned long glyph
, cairo_t
*cr
, cairo_text_extents_t
*extents
)
943 objinstptr theinstance
;
946 double llx
, lly
, trx
, try;
948 cairo_font_face_t
*ff
= cairo_scaled_font_get_font_face(scaled_font
);
949 size_t fontidx
= (size_t) cairo_font_face_get_user_data(ff
, &fontinfo_key
);
950 fontinfo
*fi
= &fonts
[fontidx
];
952 chr
= fi
->encoding
[glyph
];
953 theinstance
= &charinst
;
954 charinst
.thisobject
= chr
;
956 llx
= chr
->bbox
.lowerleft
.x
/ 40.;
957 lly
= chr
->bbox
.lowerleft
.y
/ 40.;
958 trx
= (chr
->bbox
.lowerleft
.x
+ chr
->bbox
.width
) / 40.;
959 try = (chr
->bbox
.lowerleft
.y
+ chr
->bbox
.height
) / 40.;
961 /* temporary override areawin->cr with the font context */
962 old_cr
= areawin
->cr
;
965 cairo_scale(cr
, 1. / 40., -1. / 40.);
966 cairo_set_line_width(cr
, 1);
968 /* if font is derived and italic, premultiply by slanting matrix */
969 if ((fi
->flags
& 0x22) == 0x22) {
970 cairo_matrix_t m
= {1., 0., .25, 1., 0., 0.};
971 cairo_transform(areawin
->cr
, &m
);
975 /* simple boldface technique for derived fonts */
976 passwidth
= ((fi
->flags
& 0x21) == 0x21) ? 4. : 2.;
978 /* Correct extentswith line width */
979 llx
-= passwidth
/ 40.;
980 lly
-= passwidth
/ 40.;
981 trx
+= passwidth
/ 40.;
982 try += passwidth
/ 40.;
984 xc_draw_glyph_object(theinstance
, passwidth
);
986 extents
->x_bearing
= llx
;
987 extents
->y_bearing
= -try;
988 extents
->width
= trx
- llx
;
989 extents
->height
= try - lly
;
990 extents
->x_advance
= (chr
->bbox
.lowerleft
.x
+ chr
->bbox
.width
) / 40.;
991 extents
->y_advance
= 0.;
993 areawin
->cr
= old_cr
;
994 return CAIRO_STATUS_SUCCESS
;
997 /*----------------------------------------------------------------------*/
998 /* Function to translate unicode into a glyph index for the stroke font */
999 /*----------------------------------------------------------------------*/
1001 static cairo_status_t
xc_user_font_glyph(cairo_scaled_font_t
*scaled_font
,
1002 unsigned long unicode
, unsigned long *glyph_index
)
1004 cairo_font_face_t
*ff
= cairo_scaled_font_get_font_face(scaled_font
);
1005 size_t fontidx
= (size_t) cairo_font_face_get_user_data(ff
, &fontinfo_key
);
1006 fontinfo
*fi
= &fonts
[fontidx
];
1009 /* search all glyphs in the utf8encoding. This is allowed to be slow, */
1010 /* as the glyph list will be buffered anyway */
1011 for (idx
= 1; idx
< 255; idx
++) {
1012 const char *s
= fi
->utf8encoding
[idx
];
1015 /* Convert utf-8 to unicode */
1016 unsigned long uc
= s
[0];
1018 unsigned long mask
= 0x3f;
1019 while ((s
[++cidx
] & 0xc0) == 0x80) {
1020 uc
= (uc
<< 6) | (s
[cidx
] & 0x3f);
1021 mask
= (mask
<< 5) | 0x1f;
1026 if (unicode
== uc
) {
1028 return CAIRO_STATUS_SUCCESS
;
1031 /* This should not happen: replace unknown glyph with question mark */
1033 return CAIRO_STATUS_SUCCESS
;
1036 /*---------------------------------------------------------------------*/
1037 /* find the corresponing cairo fontface for a given fontinfo structure */
1038 /*---------------------------------------------------------------------*/
1041 const char* postscript_name
;
1042 const char* replacement_name
;
1043 const char* foundry_name
;
1044 } xc_font_replacement
;
1046 static const xc_font_replacement replacement_fonts
[] =
1048 /* First try to see if 'real' postscript fonts have been installed */
1049 {"ITC Avant Garde Gothic", "ITC Avant Garde Gothic", "adobe"},
1050 {"ITC Bookman", "ITC Bookman", "adobe"},
1051 {"Courier", "Courier", "adobe"},
1052 {"Helvetica", "Helvetica", "adobe"},
1053 {"Helvetica Narrow", "Helvetica Narrow", "adobe"},
1054 {"New Century Schoolbook", "New Century Schoolbook", "adobe"},
1055 {"Palatino", "Palatino", "adobe"},
1056 {"Symbol", "Symbol", "adobe"},
1057 {"Times", "Times", "adobe"},
1058 {"Times-Roman", "Times-Roman", "adobe"},
1059 {"ITC ZapfChangery", "ITC ZapfChangery", "adobe"},
1060 {"ITC ZapfDingbats", "ITC ZapfDingbats", "adobe"},
1061 /* Next try the URW postscript fonts (guaranteed to have same extents) */
1062 {"ITC Avant Garde Gothic", "URW Gothic L", "urw"},
1063 {"ITC Bookman", "URW Bookman L", "urw"},
1064 {"Courier", "Nimbus Mono L", "urw"},
1065 {"Helvetica", "Nimbus Sans L", "urw"},
1066 {"Helvetica Narrow", "Nimbus Sans L Condensed", "urw"},
1067 {"New Century Schoolbook", "Century Schoolbook L", "urw"},
1068 {"Palatino", "URW Palladio L", "urw"},
1069 {"Symbol", "Standard Symbols L", "urw"},
1070 {"Times", "Nimbus Roman No9 L", "urw"},
1071 {"Times-Roman", "Nimbus Roman No9 L", "urw"},
1072 {"ITC ZapfChangery", "URW Changery L", "urw"},
1073 {"ITC ZapfDingbats", "Dingbats", "urw"},
1074 /* No success, use the 'old' stroke fonts */
1078 void xc_cairo_set_fontinfo(size_t fontidx
)
1080 /* TODO: memory leak. font_face is created here. It should also be */
1081 /* destroyed again somewhere */
1082 fontinfo
*fi
= &fonts
[fontidx
];
1083 const char *family
= fi
->family
;
1084 const xc_font_replacement
*replace
;
1087 #ifdef CAIRO_HAS_FC_FONT
1088 int weight
= FC_WEIGHT_NORMAL
;
1089 int slant
= FC_SLANT_ROMAN
;
1091 fi
->font_face
= NULL
;
1094 weight
= FC_WEIGHT_BOLD
;
1096 if (fi
->flags
& 2) {
1097 if (!strcmp(family
, "Helvetica"))
1098 slant
= FC_SLANT_OBLIQUE
;
1100 slant
= FC_SLANT_ITALIC
;
1102 /* Try to find a proper postscript font */
1103 for (replace
= replacement_fonts
; replace
->postscript_name
; replace
++) {
1104 if (!strcmp(replace
->postscript_name
, fi
->family
)) {
1106 FcChar8
*matched_family
, *matched_foundry
;
1108 FcPattern
*pattern
= FcPatternBuild(NULL
,
1109 FC_FAMILY
, FcTypeString
, replace
->replacement_name
,
1110 FC_WEIGHT
, FcTypeInteger
, weight
,
1111 FC_SLANT
, FcTypeInteger
, slant
,
1112 FC_FOUNDRY
, FcTypeString
, replace
->foundry_name
,
1114 FcConfigSubstitute(0, pattern
, FcMatchPattern
);
1115 FcDefaultSubstitute(pattern
);
1116 matched
= FcFontMatch(0, pattern
, &result
);
1117 /* Check if the matched font is actually the replacement font */
1118 FcPatternGetString(matched
, FC_FAMILY
, 0, &matched_family
);
1119 FcPatternGetString(matched
, FC_FOUNDRY
, 0, &matched_foundry
);
1120 if (!strcmp(matched_family
, replace
->replacement_name
)
1121 && !strcmp(matched_foundry
, replace
->foundry_name
))
1122 fi
->font_face
= cairo_ft_font_face_create_for_pattern(matched
);
1123 FcPatternDestroy(matched
);
1124 FcPatternDestroy(pattern
);
1129 #else /* CAIRO_HAS_FC_FONT */
1130 fi
->font_face
= NULL
;
1131 #endif /* CAIRO_HAS_FC_FONT */
1133 /* Cache the dimensions and all glyphs of the font */
1134 if (fi
->font_face
) {
1136 cairo_glyph_t
*glyphs
= NULL
;
1137 cairo_scaled_font_t
*scaled_font
;
1138 cairo_text_extents_t extents
;
1140 cairo_save(areawin
->cr
);
1141 cairo_identity_matrix(areawin
->cr
);
1142 cairo_set_font_face(areawin
->cr
, fi
->font_face
);
1143 cairo_set_font_size(areawin
->cr
, 100.);
1144 scaled_font
= cairo_get_scaled_font(areawin
->cr
);
1145 for (c
= 1; c
< 256; c
++) { /* skip encoding at index 0 */
1146 cairo_scaled_font_text_to_glyphs(scaled_font
, 0., 0.,
1147 fi
->utf8encoding
[c
], -1, &glyphs
, &num_glyphs
,
1149 fi
->glyph_index
[c
] = glyphs
[0].index
;
1150 cairo_scaled_font_glyph_extents(scaled_font
, glyphs
, 1, &extents
);
1151 fi
->glyph_top
[c
] = -extents
.y_bearing
* 40. / 100.;
1152 /* fi->glyph_bottom[c] = extents.height * 40. / 100. + fi->glyph_top[c]; */
1153 fi
->glyph_bottom
[c
] = fi
->glyph_top
[c
] - extents
.height
* 40. / 100.;
1154 fi
->glyph_advance
[c
] = extents
.x_advance
* 40. / 100.;
1156 cairo_glyph_free(glyphs
);
1157 cairo_restore(areawin
->cr
);
1160 /* No decent postscript font found. Backup using stroke fonts */
1161 fi
->font_face
= cairo_user_font_face_create();
1162 cairo_font_face_set_user_data(fi
->font_face
, &fontinfo_key
,
1163 (void*) fontidx
, (cairo_destroy_func_t
) cairo_font_face_destroy
);
1164 cairo_user_font_face_set_render_glyph_func(fi
->font_face
,
1165 xc_user_font_render
);
1166 cairo_user_font_face_set_unicode_to_glyph_func(fi
->font_face
,
1167 xc_user_font_glyph
);
1168 for (c
= 0; c
< 256; c
++) {
1169 objectptr chr
= fi
->encoding
[c
];
1170 fi
->glyph_index
[c
] = c
;
1171 fi
->glyph_top
[c
] = chr
->bbox
.lowerleft
.y
+ chr
->bbox
.height
;
1172 fi
->glyph_bottom
[c
] = chr
->bbox
.lowerleft
.y
;
1173 fi
->glyph_advance
[c
] = chr
->bbox
.lowerleft
.x
+ chr
->bbox
.width
;
1178 /*----------------------------------------------------------------------*/
1179 /* A light wrapper around cairo_surface_t, to a generalized xcImage */
1180 /*----------------------------------------------------------------------*/
1182 /* caching for cairo_surface_t */
1183 static xcImage
*xcImagePixel_oldimg
= NULL
;
1184 static uint32_t *xcImagePixel_data
;
1185 static int xcImagePixel_width
;
1186 static int xcImagePixel_height
;
1188 static inline void xcImageCheckCache(xcImage
*img
)
1190 if (img
!= xcImagePixel_oldimg
) {
1191 xcImagePixel_oldimg
= img
;
1192 xcImagePixel_data
= (uint32_t*) cairo_image_surface_get_data(img
);
1193 xcImagePixel_width
= cairo_image_surface_get_width(img
);
1194 xcImagePixel_height
= cairo_image_surface_get_height(img
);
1198 xcImage
*xcImageCreate(int width
, int height
)
1200 return cairo_image_surface_create(CAIRO_FORMAT_RGB24
, width
, height
);
1203 void xcImageDestroy(xcImage
*img
)
1205 cairo_surface_destroy(img
);
1208 int xcImageGetWidth(xcImage
*img
)
1210 xcImageCheckCache(img
);
1211 return xcImagePixel_width
;
1214 int xcImageGetHeight(xcImage
*img
)
1216 xcImageCheckCache(img
);
1217 return xcImagePixel_height
;
1220 void xcImagePutPixel(xcImage
*img
, int x
, int y
, u_char r
, u_char g
, u_char b
)
1222 xcImageCheckCache(img
);
1223 xcImagePixel_data
[y
* xcImagePixel_width
+ x
] = (r
<< 16) | (g
<< 8) | b
;
1226 void xcImageGetPixel(xcImage
*img
, int x
, int y
, u_char
*r
, u_char
*g
,
1230 xcImageCheckCache(img
);
1231 argb
= xcImagePixel_data
[y
* xcImagePixel_width
+ x
];
1238 /*------------------------------------------------------------------------*/
1239 /* Ghostscript rendering function. In contrast to X11, direct calls to */
1240 /* ghostscriptapi are made */
1241 /*------------------------------------------------------------------------*/
1243 /*------------------------------------------------------------------------*/
1244 /* gsapi I/O redirection functions */
1245 /*------------------------------------------------------------------------*/
1248 static int GSDLLCALL
gs_stdin_fn(void *caller_handle
, char *buf
, int len
)
1250 UNUSED(caller_handle
); UNUSED(buf
); UNUSED(len
);
1255 static int GSDLLCALL
gs_stdout_fn(void *caller_handle
, const char *str
, int len
)
1258 UNUSED(caller_handle
); UNUSED(str
);
1260 fwrite(str
, 1, len
, stdout
);
1266 static int GSDLLCALL
gs_stderr_fn(void *caller_handle
, const char *str
, int len
)
1269 UNUSED(caller_handle
); UNUSED(str
);
1271 fwrite(str
, 1, len
, stderr
);
1276 #endif /* HAVE_GS */
1278 /*------------------------------------------------------------------------*/
1279 /* gsapi displaycallback functions */
1280 /*------------------------------------------------------------------------*/
1283 static unsigned char *gs_pimage
;
1284 static int gs_width
, gs_height
, gs_raster
;
1286 static int gs_display_dummy(void)
1290 #endif /* HAVE_GS */
1293 static int gs_display_size(void *handle
, void *device
, int width
, int height
,
1294 int raster
, unsigned int format
, unsigned char *pimage
)
1296 UNUSED(handle
); UNUSED(device
); UNUSED(format
);
1304 #endif /* HAVE_GS */
1307 int gs_display_page(void *handle
, void *device
, int copies
, int flush
)
1309 cairo_surface_t
*tbuf
;
1311 UNUSED(handle
); UNUSED(device
); UNUSED(copies
); UNUSED(flush
);
1314 cairo_surface_destroy(bbuf
);
1315 /* Since cairo_image_surface_create_for_data assumes the buffer to be */
1316 /* valid until destruction, and ghostscript frees it immediately, */
1317 /* first use a temporary buffer. Then immediately copy the buffer */
1318 /* To the final location */
1319 tbuf
= cairo_image_surface_create_for_data(gs_pimage
, CAIRO_FORMAT_RGB24
,
1320 gs_width
, gs_height
, gs_raster
);
1321 bbuf
= cairo_image_surface_create(CAIRO_FORMAT_RGB24
, gs_width
, gs_height
);
1322 bbuf_cr
= cairo_create(bbuf
);
1323 cairo_set_source_surface(bbuf_cr
, tbuf
, 0., 0.);
1324 cairo_paint(bbuf_cr
);
1325 cairo_destroy(bbuf_cr
);
1326 cairo_surface_destroy(tbuf
);
1329 #endif /* HAVE_GS */
1332 display_callback gs_display
= {
1333 sizeof(display_callback
),
1334 DISPLAY_VERSION_MAJOR
,
1335 DISPLAY_VERSION_MINOR
,
1336 (int (*)(void*, void*)) gs_display_dummy
, /* display_open */
1337 (int (*)(void*, void*)) gs_display_dummy
, /* display_preclose */
1338 (int (*)(void*, void*)) gs_display_dummy
, /* display_close */
1339 (int (*)(void*, void*, int, int, int, unsigned int)) gs_display_dummy
,
1340 /* display_presize */
1342 (int (*)(void*, void*)) gs_display_dummy
, /* display_sync */
1344 NULL
, /* display_update */
1345 NULL
, /* display_memalloc */
1346 NULL
, /* display_memfree */
1347 NULL
/* display_separation */
1349 #endif /* HAVE_GS */
1351 /*------------------------------------------------------*/
1352 /* write scale and position to ghostscript */
1353 /* and tell ghostscript to run the requested file */
1354 /*------------------------------------------------------*/
1357 const char *gs_argv
[] = {
1358 "-dQUIET", /* Suppress startup messages */
1359 "-dNOPAUSE", /* Disable pause at end of page */
1360 "-dBATCH", /* Exit when all files done */
1362 "-sDisplayHandle=0",
1363 "-r75", /* Display resolution */
1364 "-dGraphicsAlphaBits=4", /* Graphics anti-aliasing */
1365 "-dTextAlphaBits=4" /* Text anti-aliasing */
1367 #endif /* HAVE_GS */
1369 void write_scale_position_and_run_gs(float norm
, float xpos
, float ypos
,
1373 UNUSED(norm
); UNUSED(xpos
); UNUSED(ypos
); UNUSED(bgfile
);
1376 int i
, code
, exit_code
;
1379 char display_format
[] = "-dDisplayFormat=........";
1380 char pixmap_size
[] = "-g........x........";
1381 int argc
= sizeof(gs_argv
) / sizeof(gs_argv
[0]);
1382 const char **argv
= (const char**) malloc((argc
+ 2) * sizeof(const char*));
1384 for (i
= 0; i
< argc
; i
++)
1385 argv
[i
] = gs_argv
[i
];
1386 argv
[argc
++] = display_format
;
1387 argv
[argc
++] = pixmap_size
;
1391 " /setpagedevice {pop} def"
1393 " %3.2f %3.2f translate"
1394 " %3.2f %3.2f scale"
1398 xpos
, ypos
, norm
, norm
, bgfile
);
1400 sprintf(display_format
, "-dDisplayFormat=%d", DISPLAY_COLORS_RGB
1401 | DISPLAY_UNUSED_LAST
| DISPLAY_DEPTH_8
| DISPLAY_LITTLEENDIAN
1402 | DISPLAY_TOPFIRST
| DISPLAY_ROW_ALIGN_DEFAULT
);
1403 sprintf(pixmap_size
, "-g%dx%d", areawin
->width
, areawin
->height
);
1405 XDefineCursor(dpy
, areawin
->window
, WAITFOR
);
1407 if ((code
= gsapi_new_instance(&instance
, NULL
)) == 0) {
1408 gsapi_set_stdio(instance
, gs_stdin_fn
, gs_stdout_fn
, gs_stderr_fn
);
1409 gsapi_set_display_callback(instance
, &gs_display
);
1410 if (!(code
= gsapi_init_with_args(instance
, argc
, (char**) argv
)))
1411 gsapi_run_string(instance
, gs_cmd
, 0, &exit_code
);
1412 gsapi_exit(instance
);
1413 gsapi_delete_instance(instance
);
1417 fprintf(stdout
, "Xcircuit: ghostscript done\n");
1420 XDefineCursor(dpy
, areawin
->window
, DEFAULTCURSOR
);
1421 areawin
->lastbackground
= xobjs
.pagelist
[areawin
->page
]->background
.name
;
1422 drawarea(areawin
->area
, NULL
, NULL
);
1423 #endif /* HAVE_GS */
1424 gs_state
= GS_READY
;
1427 #else /* HAVE_CAIRO */
1428 typedef int no_empty_translation_unit_warning
;
1429 #endif /* HAVE_CAIRO */