Merge branch 'master' into xcircuit-3.10
[xcircuit.git] / cairo.c
blob828e12243471649516c9fc0458ec861b83e592d4
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 /*-------------------------------------------------------------------------*/
10 #ifdef HAVE_CAIRO
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stdint.h>
15 #include <assert.h>
16 #include <math.h>
17 #include <limits.h>
19 #ifndef XC_WIN32
20 #include <X11/Intrinsic.h>
21 #endif
23 #ifdef TCL_WRAPPER
24 #include <tk.h>
25 #endif /* TCL_WRAPPER */
27 #include "xcircuit.h"
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 */
35 #ifdef HAVE_GS
36 #include <ghostscript/ierrors.h>
37 #include <ghostscript/iapi.h>
38 #include <ghostscript/gdevdsp.h>
39 #endif /* HAVE_GS */
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];
48 extern Display *dpy;
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)
60 cairo_matrix_t m;
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)
72 colorindex *xcc;
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;
89 return;
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). */
113 /* */
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)
122 XPoint wpt;
124 if (!areawin->redraw_ongoing) {
125 areawin->redraw_needed = True;
126 return;
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 */
139 switch(which) {
140 case P_POSITION_X:
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);
143 break;
144 case P_POSITION_Y:
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);
147 break;
148 default:
149 cairo_arc(areawin->cr, wpt.x, wpt.y, 4., 0., M_PI * 2.);
150 break;
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;
164 return;
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)
184 XPoint upt, vpt;
185 double dashes[] = {4., 4.};
187 if (!areawin->redraw_ongoing) {
188 areawin->redraw_needed = True;
189 return;
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)
219 XPoint worig, wcorn;
220 double r, g, b, a;
222 if (!areawin->redraw_ongoing) {
223 areawin->redraw_needed = True;
224 return;
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)
261 XPoint newpoints[5];
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)
269 return;
271 if (areawin->redraw_ongoing) {
272 int i;
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 /*-------------------------------------------------------------------------*/
290 void UDrawBBox()
292 XPoint origin;
293 XPoint worig, wcorn, corner;
294 objinstptr bbinst = areawin->topinstance;
296 if (!areawin->redraw_ongoing) {
297 areawin->redraw_needed = True;
298 return;
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)
345 genericptr *areagen;
346 float tmpwidth;
347 int defaultcolor = passcolor;
348 int curcolor = passcolor;
349 int thispart;
350 short savesel;
351 XPoint bboxin[2], bboxout[2];
352 u_char xm, ym;
353 objectptr theobject = theinstance->thisobject;
355 if (!areawin->redraw_ongoing) {
356 areawin->redraw_needed = True;
357 return;
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. */
370 UPushCTM();
372 /* Stack is not used by cairo but *is* used by expression evaluators */
373 if (stack) push_stack((pushlistptr *)stack, theinstance, (char *)NULL);
375 if (level != 0)
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;
388 if (level == 0)
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;
420 else
421 curcolor = (*areagen)->color;
423 XcTopSetForeground(curcolor);
427 switch(ELEMENTTYPE(*areagen)) {
428 case(POLYGON):
429 if (level == 0 || !((TOPOLY(areagen))->style & BBOX))
430 UDrawPolygon(TOPOLY(areagen), passwidth);
431 break;
433 case(SPLINE):
434 UDrawSpline(TOSPLINE(areagen), passwidth);
435 break;
437 case(ARC):
438 UDrawArc(TOARC(areagen), passwidth);
439 break;
441 case(PATH):
442 UDrawPath(TOPATH(areagen), passwidth);
443 break;
445 case(GRAPHIC):
446 UDrawGraphic(TOGRAPHIC(areagen));
447 break;
449 case(OBJINST):
450 UDrawObject(TOOBJINST(areagen), level + 1, curcolor, passwidth, stack);
451 break;
453 case(LABEL):
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));
463 break;
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;
476 UPopCTM();
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);
490 else {
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);
496 else {
497 double m = (1 + ((style & FILLSOLID) >> 5)) / 8.;
498 if (style & OPAQUE) {
499 double n = (1. - m);
500 cairo_set_source_rgba(areawin->cr, m * red + n,
501 m * green + n, m * blue + n, alpha);
503 else
504 cairo_set_source_rgba(areawin->cr, red, green, blue,
505 m * alpha);
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)) {
516 double dashes[2];
517 dashes[0] = dashes[1] = 4.0 * width;
518 if (style & DOTTED)
519 dashes[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);
524 else {
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)
545 int i;
547 if (!areawin->redraw_ongoing) {
548 areawin->redraw_needed = True;
549 return;
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;
566 return;
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? */
584 double theta;
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)
604 genericptr *genpath;
605 polyptr thepoly;
606 splineptr thespline;
608 if (!areawin->redraw_ongoing) {
609 areawin->redraw_needed = True;
610 return;
613 /* Draw first point */
614 if (thepath->parts) {
615 genpath = thepath->plist;
616 switch(ELEMENTTYPE(*genpath)) {
617 case POLYGON:
618 thepoly = TOPOLY(genpath);
619 cairo_move_to(areawin->cr, thepoly->points[0].x,
620 thepoly->points[0].y);
621 break;
622 case SPLINE:
623 thespline = TOSPLINE(genpath);
624 cairo_move_to(areawin->cr, thespline->ctrl[0].x,
625 thespline->ctrl[0].y);
626 break;
629 /* Draw all other points */
630 for (genpath = thepath->plist; genpath < thepath->plist + thepath->parts;
631 genpath++) {
632 int i;
633 switch(ELEMENTTYPE(*genpath)) {
634 case POLYGON:
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);
639 break;
640 case SPLINE:
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);
646 break;
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;
658 return;
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)
672 double w, h;
674 if (!areawin->redraw_ongoing) {
675 areawin->redraw_needed = True;
676 return;
679 cairo_save(areawin->cr);
680 cairo_translate(areawin->cr,
681 gp->position.x,
682 gp->position.y);
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,
688 -w / 2., -h / 2.);
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;
708 return;
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) {
716 double x, y;
717 int ix, iy;
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);
726 ix = xbegin;
727 iy = ybegin;
728 cairo_user_to_device(areawin->cr, &xbegin, &ybegin);
729 cairo_identity_matrix(areawin->cr);
730 /* draw the grid */
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) {
748 /* find main axis */
749 double x = 0, y = 0;
750 cairo_set_matrix(areawin->cr, &m);
751 cairo_user_to_device(areawin->cr, &x, &y);
752 cairo_identity_matrix(areawin->cr);
753 /* draw the grid */
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 */
764 UDrawBBox();
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) {
769 double x, y;
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);
780 /* draw the grid */
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 */
794 spc3 = spc * 20.;
795 if (spc > 4.) {
796 double x, y;
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);
807 /* draw the grid */
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;
831 cairo_matrix_t oldm;
832 double x, y;
833 cairo_glyph_t *glyphs;
834 UNUSED(passcolor);
836 cairo_get_matrix(areawin->cr, &oldm);
837 cairo_scale(areawin->cr, tmpscale, fabs(tmpscale));
839 /* under- and overlines */
840 if (styles & 8)
841 y = offset->y / tmpscale - 6.;
842 else if (styles & 16)
843 y = offset->y / tmpscale + groupheight + 4;
844 if (styles & 24) {
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++)
855 /* Add glyphs */
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);
859 nglyphs++;
860 /* Determine character width */
861 offset->x += fonts[ffont].glyph_advance[text[idx]] * tmpscale;
863 if (nglyphs) {
864 cairo_show_glyphs(areawin->cr, glyphs, nglyphs);
865 cairo_new_path(areawin->cr);
867 cairo_glyph_free(glyphs);
869 if (styles & 24) {
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)
884 int thispart;
885 genericptr *areagen;
886 objectptr obj = inst->thisobject;
887 objinstptr ptr;
889 for (thispart = 0; thispart < obj->parts; thispart++) {
890 areagen = obj->plist + thispart;
891 switch(ELEMENTTYPE(*areagen)) {
892 case(POLYGON):
893 UDrawPolygon(TOPOLY(areagen), passwidth);
894 break;
895 case(SPLINE):
896 UDrawSpline(TOSPLINE(areagen), passwidth);
897 break;
898 case(ARC):
899 UDrawArc(TOARC(areagen), passwidth);
900 break;
901 case(PATH):
902 UDrawPath(TOPATH(areagen), passwidth);
903 break;
904 case(OBJINST):
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);
912 break;
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)
926 objectptr chr;
927 objinst charinst;
928 objinstptr theinstance;
929 cairo_t *old_cr;
930 float passwidth;
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;
948 areawin->cr = 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);
957 llx += .25 * lly;
958 trx += .25 * try;
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];
992 unsigned long idx;
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];
998 int cidx = 0;
1000 /* Convert utf-8 to unicode */
1001 unsigned long uc = s[0];
1002 if (uc & 0x80) {
1003 unsigned long mask = 0x3f;
1004 while ((s[++cidx] & 0xc0) == 0x80) {
1005 uc = (uc << 6) | (s[cidx] & 0x3f);
1006 mask = (mask << 5) | 0x1f;
1008 uc &= mask;
1011 if (unicode == uc) {
1012 *glyph_index = idx;
1013 return CAIRO_STATUS_SUCCESS;
1016 /* This should not happen: replace unknown glyph with question mark */
1017 *glyph_index = '?';
1018 return CAIRO_STATUS_SUCCESS;
1021 /*---------------------------------------------------------------------*/
1022 /* find the corresponing cairo fontface for a given fontinfo structure */
1023 /*---------------------------------------------------------------------*/
1025 typedef struct {
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 */
1060 {NULL, NULL, NULL}
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;
1070 int c;
1072 #ifdef CAIRO_HAS_FC_FONT
1073 int weight = FC_WEIGHT_NORMAL;
1074 int slant = FC_SLANT_ROMAN;
1076 fi->font_face = NULL;
1078 if (fi->flags & 1)
1079 weight = FC_WEIGHT_BOLD;
1081 if (fi->flags & 2) {
1082 if (!strcmp(family, "Helvetica"))
1083 slant = FC_SLANT_OBLIQUE;
1084 else
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)) {
1090 FcPattern *matched;
1091 FcChar8 *matched_family, *matched_foundry;
1092 FcResult result;
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,
1098 NULL);
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);
1110 if (fi->font_face)
1111 break;
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) {
1120 int num_glyphs;
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,
1133 NULL, NULL, NULL);
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);
1144 else {
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,
1212 u_char *b)
1214 uint32_t argb;
1215 xcImageCheckCache(img);
1216 argb = xcImagePixel_data[y * xcImagePixel_width + x];
1217 *r = argb >> 16;
1218 *g = argb >> 8;
1219 *b = argb;
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 /*------------------------------------------------------------------------*/
1232 #ifdef HAVE_GS
1233 static int GSDLLCALL gs_stdin_fn(void *caller_handle, char *buf, int len)
1235 UNUSED(caller_handle); UNUSED(buf); UNUSED(len);
1237 return 0; /* EOF */
1240 static int GSDLLCALL gs_stdout_fn(void *caller_handle, const char *str, int len)
1242 #ifndef GS_DEBUG
1243 UNUSED(caller_handle); UNUSED(str);
1244 #else
1245 fwrite(str, 1, len, stdout);
1246 fflush(stdout);
1247 #endif
1248 return len;
1251 static int GSDLLCALL gs_stderr_fn(void *caller_handle, const char *str, int len)
1253 #ifndef GS_DEBUG
1254 UNUSED(caller_handle); UNUSED(str);
1255 #else
1256 fwrite(str, 1, len, stderr);
1257 fflush(stderr);
1258 #endif
1259 return len;
1261 #endif /* HAVE_GS */
1263 /*------------------------------------------------------------------------*/
1264 /* gsapi displaycallback functions */
1265 /*------------------------------------------------------------------------*/
1267 #ifdef HAVE_GS
1268 static unsigned char *gs_pimage;
1269 static int gs_width, gs_height, gs_raster;
1271 static int gs_display_dummy(void)
1273 return 0;
1275 #endif /* HAVE_GS */
1277 #ifdef 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);
1283 gs_pimage = pimage;
1284 gs_width = width;
1285 gs_height = height;
1286 gs_raster = raster;
1287 return 0;
1289 #endif /* HAVE_GS */
1291 #ifdef HAVE_GS
1292 int gs_display_page(void *handle, void *device, int copies, int flush)
1294 cairo_surface_t *tbuf;
1295 cairo_t *bbuf_cr;
1296 UNUSED(handle); UNUSED(device); UNUSED(copies); UNUSED(flush);
1298 if (bbuf)
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);
1312 return 0;
1314 #endif /* HAVE_GS */
1316 #ifdef 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 */
1326 gs_display_size,
1327 (int (*)(void*, void*)) gs_display_dummy, /* display_sync */
1328 gs_display_page,
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 /*------------------------------------------------------*/
1341 #ifdef HAVE_GS
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 */
1346 "-sDEVICE=display",
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,
1355 const char *bgfile)
1357 #ifndef HAVE_GS
1358 UNUSED(norm); UNUSED(xpos); UNUSED(ypos); UNUSED(bgfile);
1359 #endif
1360 #ifdef HAVE_GS
1361 int i, code, exit_code;
1362 void *instance;
1363 char gs_cmd[256];
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;
1374 sprintf(gs_cmd,
1375 " /GSobj save def"
1376 " /setpagedevice {pop} def"
1377 " gsave"
1378 " %3.2f %3.2f translate"
1379 " %3.2f %3.2f scale"
1380 " (%s) run"
1381 " GSobj restore"
1382 " grestore",
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);
1400 free(argv);
1401 #ifdef GS_DEBUG
1402 fprintf(stdout, "Xcircuit: ghostscript done\n");
1403 #endif
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 */