1 /**
2 * Yudit Unicode Editor Source File
3 *
4 * GNU Copyright (C) 1997-2006 Gaspar Sinai <gaspar@yudit.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2,
8 * dated June 1991. See file COPYYING for details.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include "swindow/SPostscript.h"
21 #include "stoolkit/STypes.h"
22 #include <time.h>
23
24 /**
25 * Bitmap font support
26 */
27 #ifndef USE_WINAPI
28 # if USE_X11
29 # include <X11/Xlib.h>
30 # include <X11/Xutil.h>
31 # include "swindow/SAwt.h"
32 # include "swindow/sx11/SX11Impl.h"
33 # endif
34 #endif
35
36 /**
37 * @author: Gaspar Sinai <gaspar@yudit.org>
38 * @version: 2000-04-23
39 * This is a postscript renderer for yudit.
40 */
SPostscript(const SWriter & wr,SMedia m,SOrientation o)41 SPostscript::SPostscript (const SWriter& wr, SMedia m, SOrientation o) : out (wr)
42 {
43 ticks = 0;
44 timer = 0;
45 isUgly = false;
46 cacheIDMapCount = 0;
47 media = m;
48 orientation = o;
49 unsigned int w;
50 unsigned int h;
51 switch (m)
52 {
53 case A3:
54 w = 842;
55 h = 1190;
56 widthMargin = 64;
57 heightMargin = 48;
58 break;
59 case A4:
60 w = 595;
61 h = 842;
62 widthMargin = 64;
63 heightMargin = 48;
64 break;
65 case A5:
66 w = 420;
67 h = 595;
68 widthMargin = 45;
69 heightMargin = 34;
70 break;
71 case B4:
72 w = 792;
73 h = 1032;
74 widthMargin = 64;
75 heightMargin = 48;
76 break;
77 case B5:
78 w = 516;
79 h = 729;
80 widthMargin = 45;
81 heightMargin = 34;
82 break;
83 case Executive:
84 w = 540;
85 h = 720;
86 widthMargin = 64;
87 heightMargin = 48;
88 break;
89 case Folio:
90 w = 612;
91 h = 936;
92 widthMargin = 64;
93 heightMargin = 48;
94 break;
95 case Ledger:
96 w = 980;
97 h = 792;
98 widthMargin = 64;
99 heightMargin = 48;
100 break;
101 case Legal:
102 w = 612;
103 h = 1008;
104 widthMargin = 64;
105 heightMargin = 48;
106 break;
107 case Letter:
108 w = 612;
109 h = 792;
110 widthMargin = 24;
111 heightMargin = 34;
112 break;
113 case Quarto:
114 w = 610;
115 h = 780;
116 widthMargin = 24;
117 heightMargin = 48;
118 break;
119 case Statement:
120 w = 396;
121 h = 612;
122 widthMargin = 24;
123 heightMargin = 48;
124 break;
125 case Tabloid:
126 w = 792;
127 h = 1028;
128 widthMargin = 24;
129 heightMargin = 48;
130 break;
131 default:
132 w = 595;
133 h = 842;
134 widthMargin = 64;
135 heightMargin = 48;
136 }
137 if (o==PORTRAIT)
138 {
139 width = w;
140 height = h;
141 }
142 else
143 {
144 width = h;
145 height = w;
146 }
147 status = true;
148
149 SS_Matrix2D mat;
150 matrix.append (mat);
151 }
152
~SPostscript()153 SPostscript::~SPostscript()
154 {
155 if (timer) delete timer;
156 }
157
158 /**
159 * return the margin-stripped width.
160 */
161 unsigned int
getWidth() const162 SPostscript::getWidth() const
163 {
164 return width - 2 * widthMargin;
165 }
166
167 /**
168 * return the margin-stripped height.
169 */
170 unsigned int
getHeight() const171 SPostscript::getHeight() const
172 {
173 return height - 2 * heightMargin;
174 }
175
176 /**
177 * return the margin stripped X corner.
178 */
179 int
getX() const180 SPostscript::getX() const
181 {
182 return (int) widthMargin;
183 }
184
185 /**
186 * return the margin stripped Y corner.
187 */
188 int
getY() const189 SPostscript::getY() const
190 {
191 return (int) heightMargin;
192 }
193
194 /**
195 * Print out the postscript prolog
196 */
197 bool
open(bool background)198 SPostscript::open (bool background)
199 {
200 isUgly = false;
201 status = true;
202 isCacheOn = true;
203
204 cache.clear();
205 cacheCurrent.clear();
206 cacheIDMapCount = 0;
207 cacheID.clear();
208 cacheIDMap.clear();
209
210 SStringVector head("%!PS-Adobe-3.0");
211 SString bb("%%BoundingBox: ");
212
213 switch (orientation)
214 {
215 case LANDSCAPE:
216
217 bb.print (heightMargin); bb.append (" ");
218 bb.print (widthMargin); bb.append (" ");
219 bb.print (height - heightMargin); bb.append (" ");
220 bb.print (width - widthMargin);
221 head.append (bb);
222
223 break;
224
225 case PORTRAIT:
226 default:
227
228 bb.print (widthMargin); bb.append (" ");
229 bb.print (heightMargin); bb.append (" ");
230 bb.print (width - widthMargin); bb.append (" ");
231 bb.print (height - heightMargin);
232 head.append (bb);
233
234 break;
235 }
236
237 head.append ("%%Title: Untitled");
238 SString creator ("%%Creator: yudit "); creator.append (SD_YUDIT_VERSION);
239 creator.append (" GNU (C) Gaspar Sinai");
240 head.append (creator);
241 time_t now;
242 struct tm* localTime;
243 time(&now);
244 localTime = localtime (&now);
245 char strt[64];
246 strftime (strt, sizeof (strt)-1, "%Y-%m-%d %H:%M:%S", localTime);
247 SString t("%%CreationDate: ");
248 creationDate = strt;
249 t.append (creationDate);
250 head.append (t);
251 switch (orientation)
252 {
253 case LANDSCAPE:
254 head.append ("%%Orientation: Landscape");
255 break;
256 case PORTRAIT:
257 default:
258 head.append ("%%Orientation: Portrait");
259 break;
260 }
261 SString m ("%%DocumentMedia: ");
262 switch (media)
263 {
264 case Legal:
265 m.append ("Legal "); break;
266 case Letter:
267 m.append ("Letter "); break;
268 case Tabloid:
269 m.append ("Tabloid "); break;
270 case Ledger:
271 m.append ("Ledger "); break;
272 case B4:
273 m.append ("B4 "); break;
274 case A3:
275 m.append ("A3 "); break;
276 case A4:
277 m.append ("A4 "); break;
278 case A5:
279 m.append ("A5 "); break;
280 case B5:
281 m.append ("B5 "); break;
282 default:
283 m.append ("A4 ");
284 }
285 if (orientation == LANDSCAPE)
286 {
287 m.print (height); m.append (" ");
288 m.print (width); m.append (" 0 () ()");
289 }
290 else
291 {
292 m.print (width); m.append (" ");
293 m.print (height); m.append (" 0 () ()");
294 }
295 head.append (m);
296 // windows gs goes crazy if I uncomment this.
297 //head.append ("");
298 /* caching should be here */
299 //head.append ("");
300 SString all = head.join("\n");
301 all.append ("\n");
302 writeString (all);
303 pages = 0;
304 currentPage = 0;
305 if (status && background)
306 {
307 timer = STimer::newTimer(1, this);
308 }
309 return status;
310 }
311
312
313 /**
314 * Print out the ending lines.
315 */
316 bool
close()317 SPostscript::close ()
318 {
319 if (timer) delete timer;
320 timer = 0;
321 /* go back */
322 isCacheOn = true;
323 cache.clear();
324 cacheCurrent.clear();
325 cacheIDMapCount = 0;
326 cacheID.clear();
327 cacheIDMap.clear();
328
329 if (currentPage!=0)
330 {
331 writeString ("\nshowpage restore\n");
332 }
333 SStringVector l("%%DocumentFonts: Times-Roman");
334 char a[64];
335 sprintf (a, "%%%%Pages: %u", pages);
336 l.append (a);
337 l.append ("%%Trailer");
338 l.append ("%%EOF");
339 SString all = l.join ("\n");
340 all.append ("\n");
341 writeString (all);
342 return status;
343 }
344
345 void
newPage()346 SPostscript::newPage()
347 {
348 if (isCacheOn)
349 {
350 pages++;
351 }
352 else
353 {
354 if (currentPage!=0)
355 {
356 writeString ("\nshowpage restore\n");
357 }
358 currentPage++;
359 char buff[128];
360
361 switch (orientation)
362 {
363 case LANDSCAPE:
364
365 sprintf (buff, "\n%%%%Page: %u %u\nsave\n90 rotate\n0 -%d.000 translate\n", pages, currentPage, height);
366
367 break;
368
369 case PORTRAIT:
370 default:
371
372 sprintf (buff, "\n%%%%Page: %u %u\nsave\n", pages, currentPage);
373
374 break;
375 }
376
377
378
379 writeString (buff);
380 }
381 }
382
383 #define SG(_ix)\
384 (((_ix) > -1000 && (_ix) < 0)? "-" : "")
385
386 #define SM(_ix)\
387 ((_ix < 0) ? ((-_ix) % 1000) : ((_ix) % 1000))
388 /**
389 * Try to do a fill from cache. return false on fail.
390 * INTERNAL FUNCTION. PRINTS ON SCREEN.
391 * @param id is the id to print.
392 */
393 bool
_beginImage(double _x,double _y,const SString & _id)394 SPostscript::_beginImage (double _x, double _y, const SString& _id)
395 {
396 if (!cacheIDMap.get (_id)) return false;
397 char ins[128];
398
399 /**
400 * if you noticed I negated all y coordinates, and now I add height to it
401 * it should nicely re-invert yudit screen coordinates.
402 * everything should be relative to this point
403 * SGC locale can screw things up (. -> , )- use decimals.
404 */
405 int ix = (int) (1000.0 * _x);
406 int iy = (int) (1000.0 * ((double)height-_y));
407 sprintf (ins, "gsave %s%d.%03d %s%d.%03d translate ",
408 SG(ix), ix/1000, SM (ix), SG(iy), iy/1000, SM(iy));
409
410 SString all;
411 all.append (ins);
412 all.append (cacheIDMap[_id]);
413 all.append (" grestore\n");
414 writeString (all);
415 return true;
416 }
417
418 /**
419 * Write out the cache, so that you can refer to it by the id
420 * mapped by cacheIDMap.
421 */
422 bool
cacheOn(bool on)423 SPostscript::cacheOn (bool on)
424 {
425 /* you can only turn it off */
426 if (on) return isCacheOn;
427
428 char p[64];
429 sprintf (p, "%u", pages);
430 SString cs;
431 cs.append ("%%Pages: ");
432 cs.append (p); cs.append ("\n");
433 cs.append ("%%PageOrder: Ascend\n");
434 cs.append ("%%EndComments\n");
435
436 cs.append ("\n");
437 cs.append ("%%BeginProlog\n");
438 cs.append ("%%BeginResource: cache\n");
439 cs.append ("\n");
440 writeString (cs);
441 cs = "";
442 //fprintf (stderr, "cache in flushed. size=%u\n", cache.size());
443 for (unsigned int i=0; i<cache.size(); i++)
444 {
445 if (status == false) break;
446 for (unsigned int j=0; j<cache.size(i); j++)
447 {
448 if (status == false) break;
449 const SString* s = cache.get (i, j);
450 if (s==0) continue;
451 const SString id = cache.key (i, j);
452 if (cacheIDMap.get (id)==0)
453 {
454 fprintf (stderr, "ID mismatch in SPostscript::cacheFlush\n");
455 continue;
456 }
457 cs.clear();
458 cs.append ("/");
459 cs.append (cacheIDMap[id]);
460 cs.append (" {\n");
461 cs.append (*s);
462 cs.append ("} bind def\n\n");
463 writeString (cs);
464 }
465 }
466 cs = "";
467 cs.append ("%%EndResource: cache\n");
468 cs.append ("%%EndProlog\n\n");
469 cs.append ("%%EndProlog\n\n");
470 writeString (cs);
471 return SCanvas::cacheOn(on);
472 }
473
474 /**
475 * start a new path. If cache is on and is is not ""
476 * @return true if no more draing is needed.
477 */
478 bool
beginImage(double _x,double _y,const SString & _id,const SColor & background)479 SPostscript::beginImage (double _x, double _y, const SString& _id, const SColor& background)
480 {
481 /* is it in the background ? */
482 if (timer)
483 {
484 if (((++ticks)%20)==0) SEventHandler::next();
485 }
486 cacheID = _id;
487 cacheCurrent.clear();
488 cacheOriginX = _x;
489 cacheOriginY = _y;
490
491 if (!isCacheOn)
492 {
493 /* This is a hack. now I requere you to cahce first. */
494 /* for some reason this one was inserting a newpath with no fill */
495 // FIXME
496 _beginImage (_x, _y, _id);
497 return true;
498 }
499 /* have to draw it anyway later. */
500 if (_id.size() == 0) return true;
501 return false;
502 }
503
504 void
newpath()505 SPostscript::newpath ()
506 {
507 /* put it in the cache */
508 if (!isCacheOn)
509 {
510 //fprintf (stderr, "failed %*.*s\n", SSARGS(_id));
511 // FIXME
512 #if 0
513 char arr[64];
514 int ix = (int) (1000.0 * _x);
515 int iy = (int) (1000.0 * ((double)height-_y));
516 sprintf (arr, "gsave %s%d.%03d %s%d.%03d translate newpath\n",
517 SG(ix), ix/1000, SM(ix), SG(iy), iy/1000, SM(iy));
518 // BUG-2011-08-04 Don't write. This happens between U+0000...U+001F
519 //writeString (arr);
520 #endif
521 return ;
522 }
523 cacheCurrent.append ("newpath\n");
524 }
525
526
527 /**
528 * have to call fill if newpath does fail.
529 * This routine should not be called if cache is off.
530 * and glyph is found. newpath returns treu for this case.
531 */
532 void
fill(const SPen & pen)533 SPostscript::fill (const SPen& pen)
534 {
535 fill();
536 }
537
538 void
endImage()539 SPostscript::endImage ()
540 {
541 if (isCacheOn)
542 {
543 if (cache.get (cacheID)) return;
544 cache.put (cacheID, cacheCurrent);
545 char buff[64];
546 sprintf (buff, "Glyph%u", cacheIDMapCount++);
547 cacheIDMap.put (cacheID, SString(buff));
548 cacheCurrent.clear();
549 cacheID.clear();
550 }
551 }
552
553 /**
554 * have to call fill if newpath does fail.
555 * This routine should not be called if cache is off.
556 * and glyph is found. newpath returns treu for this case.
557 */
558 void
fill()559 SPostscript::fill ()
560 {
561 if (isCacheOn)
562 {
563 if (cache.get (cacheID)) return;
564 cacheCurrent.append ("fill\n");
565 }
566 else
567 {
568 // BUG-2011-08-04 Don't write. This happens between U+0000...U+001F
569 // Originally only newpath was commented out.
570 // if (cache.get (cacheID) == 0) writeString ("fill grestore\n");
571 }
572 }
573
574 /**
575 * have to call fill if newpath does fail.
576 * This routine should not be called if cache is off.
577 * and glyph is found. newpath returns treu for this case.
578 */
579 void
stroke(const SPen & pen)580 SPostscript::stroke (const SPen& pen)
581 {
582 if (isCacheOn)
583 {
584 if (cache.get (cacheID)) return;
585 cacheCurrent.append ("stroke\n");
586 }
587 else
588 {
589 if (cache.get (cacheID) == 0) writeString ("stroke grestore\n");
590 }
591 }
592
593 void
moveto(double _x,double _y)594 SPostscript::moveto (double _x, double _y)
595 {
596 SS_Matrix2D m = matrix[matrix.size()-1];
597 double x = m.x0 * _x + m.y0 * _y + m.t0;
598 double y = m.x1 * _x + m.y1 * _y + m.t1;
599 char ins[128];
600 int ix = (int) (1000.0 * (x-cacheOriginX));
601 int iy = (int) (1000.0 * (cacheOriginY-y));
602 sprintf (ins, "%s%d.%03d %s%d.%03d moveto\n",
603 SG(ix), ix/1000, SM(ix), SG(iy), iy/1000, SM(iy));
604 if (isCacheOn)
605 {
606 cacheCurrent.append (ins);
607 }
608 else
609 {
610 writeString (ins);
611 }
612 }
613
614 void
lineto(double _x,double _y)615 SPostscript::lineto (double _x, double _y)
616 {
617 SS_Matrix2D m = matrix[matrix.size()-1];
618
619 double x = m.x0 * _x + m.y0 * _y + m.t0;
620 double y = m.x1 * _x + m.y1 * _y + m.t1;
621 char ins[128];
622 int ix = (int) (1000.0 * (x-cacheOriginX));
623 int iy = (int) (1000.0 * (cacheOriginY-y));
624 sprintf (ins, "%s%d.%03d %s%d.%03d lineto\n",
625 SG(ix), ix/1000, SM(ix), SG(iy), iy/1000, SM(iy));
626 if (isCacheOn)
627 {
628 cacheCurrent.append (ins);
629 }
630 else
631 {
632 writeString (ins);
633 }
634 }
635
636 void
curveto(double _x0,double _y0,double _x1,double _y1,double _x2,double _y2)637 SPostscript::curveto (double _x0, double _y0, double _x1, double _y1, double _x2, double _y2)
638 {
639 SS_Matrix2D m = matrix[matrix.size()-1];
640
641 double x0 = m.x0 * _x0 + m.y0 * _y0 + m.t0;
642 double y0 = m.x1 * _x0 + m.y1 * _y0 + m.t1;
643
644 double x1 = m.x0 * _x1 + m.y0 * _y1 + m.t0;
645 double y1 = m.x1 * _x1 + m.y1 * _y1 + m.t1;
646
647 double x2 = m.x0 * _x2 + m.y0 * _y2 + m.t0;
648 double y2 = m.x1 * _x2 + m.y1 * _y2 + m.t1;
649 char ins[128];
650 int ix0 = (int) (1000.0 * (x0-cacheOriginX));
651 int iy0 = (int) (1000.0 * (cacheOriginY-y0));
652 int ix1 = (int) (1000.0 * (x1-cacheOriginX));
653 int iy1 = (int) (1000.0 * (cacheOriginY-y1));
654 int ix2 = (int) (1000.0 * (x2-cacheOriginX));
655 int iy2 = (int) (1000.0 * (cacheOriginY-y2));
656 sprintf (ins, "%s%d.%03d %s%d.%03d %s%d.%03d %s%d.%03d %s%d.%03d %s%d.%03d curveto\n",
657 SG(ix0), ix0/1000, SM(ix0), SG(iy0), iy0/1000, SM(iy0),
658 SG(ix1), ix1/1000, SM(ix1), SG(iy1), iy1/1000, SM(iy1),
659 SG(ix2), ix2/1000, SM(ix2), SG(iy2), iy2/1000, SM(iy2));
660 if (isCacheOn)
661 {
662 cacheCurrent.append (ins);
663 }
664 else
665 {
666 writeString (ins);
667 }
668 }
669
670 void
closepath()671 SPostscript::closepath()
672 {
673 if (isCacheOn)
674 {
675 cacheCurrent.append ("closepath\n");
676 }
677 else
678 {
679 writeString ("closepath\n");
680 }
681 }
682
683 void
pushmatrix()684 SPostscript::pushmatrix()
685 {
686 SS_Matrix2D m = matrix[matrix.size()-1];
687 matrix.append (m);
688 }
689
690 void
popmatrix()691 SPostscript::popmatrix()
692 {
693 if (matrix.size())
694 {
695 matrix.truncate(matrix.size()-1);
696 }
697 }
698
699 void
scale(double x,double y)700 SPostscript::scale (double x, double y)
701 {
702 SS_Matrix2D m = matrix[matrix.size()-1];
703 m.scale (x, y);
704 popmatrix ();
705 matrix.append (m);
706 }
707
708 void
translate(double x,double y)709 SPostscript::translate (double x, double y)
710 {
711 SS_Matrix2D m = matrix[matrix.size()-1];
712 m.translate (x, y);
713 popmatrix ();
714 matrix.append (m);
715 }
716
717 void
rotate(double angle)718 SPostscript::rotate (double angle)
719 {
720 SS_Matrix2D m = matrix[matrix.size()-1];
721 m.rotate (angle);
722 popmatrix ();
723 matrix.append (m);
724 }
725
726 void
bitfont(const SPen & pen,double x,double y,void * native,char * data,unsigned int len)727 SPostscript::bitfont (const SPen& pen, double x, double y,
728 void* native, char* data, unsigned int len)
729 {
730 #ifndef USE_WINAPI
731 # if USE_X11
732 SX11Impl* impl=(SX11Impl*) SAwt::delegate;
733 if (impl == 0)
734 {
735 fprintf (stderr, "(impl) no luck in prining bitmap font.\n");
736 return;
737 }
738 Window aWindow = (Window) impl->getAnyWindow();
739 if (aWindow==None)
740 {
741 fprintf (stderr, "(window) no luck in prining bitmap font.\n");
742 return;
743 }
744
745 SString key("NF");
746 key.append (SString((long)native));
747 key.append (SString(data, len));
748 if (beginImage (x, y, key, pen.getBackground()))
749 {
750 endImage();
751 return;
752 }
753 newpath();
754 /* FIXME: draw font here */
755 int bits = DefaultDepth (impl->display, impl->screen);
756 int nchars = len/2;
757 int direction_return;
758 int font_ascent_return;
759 int font_descent_return;
760 XCharStruct overall_return;
761
762 XQueryTextExtents16 (
763 impl->display, ((Font)native), (XChar2b*) data, nchars,
764 &direction_return,
765 &font_ascent_return,
766 &font_descent_return,
767 &overall_return);
768
769 int wi = overall_return.width;
770 int ahe = (overall_return.ascent<0) ? -overall_return.ascent
771 : overall_return.ascent;
772 int he = ahe + ((overall_return.descent<0) ? -overall_return.descent
773 : overall_return.descent);
774
775 Pixmap pixmap = XCreatePixmap (impl->display, aWindow, wi+1, he+1, bits);
776 if (pixmap==None)
777 {
778 fill (pen);
779 endImage();
780 fprintf (stderr, "(Pixmap) no luck in prining bitmap font.\n");
781 return;
782 }
783 XGCValues gcv;
784 gcv.foreground = 1;
785 gcv.background = 0;
786 GC gc = XCreateGC (impl->display, pixmap, GCForeground | GCBackground, &gcv);
787 XSetForeground (impl->display, gc, 0);
788 XFillRectangle (impl->display, pixmap, gc, 0, 0, wi+1, he+1);
789 XSetForeground (impl->display, gc, 1);
790 XSetFont (impl->display, gc, (Font) native);
791 XDrawString16 (impl->display, pixmap, gc, 0, ahe, (XChar2b*) data, len/2);
792 //fprintf (stderr, "getting pixmap=%u %u 0x%lx\n", wi, he, (unsigned long) pixmap);
793 XImage* im = XGetImage (impl->display, pixmap, 0, 0, wi+1, he+1, AllPlanes, ZPixmap);
794 XFreePixmap (impl->display, pixmap);
795 XFreeGC (impl->display, gc);
796 if (im==0)
797 {
798 fprintf (stderr, "(Image) no luck in prining bitmap font.\n");
799 fill (pen);
800 endImage();
801 return;
802 }
803
804 /* draw here */
805 //fprintf (stderr, "BITMAP FONT\n");
806 for (int j=0; j<he; j++)
807 {
808 for (int i=0; i<wi; i++)
809 {
810 long l = XGetPixel (im, i, j);
811 if (l==1)
812 {
813 double squareX[4];
814 double squareY[4];
815 double delta = 1.0;
816
817 squareX[0] = (double)i+x;
818 squareY[0] = ((double)j+y - (double) ahe),
819
820 squareX[1] = squareX[0] + delta;
821 squareY[1] = squareY[0];
822
823 squareX[2] = squareX[0] + delta;
824 squareY[2] = squareY[0] + delta;
825
826 squareX[3] = squareX[0];
827 squareY[3] = squareY[0] + delta;
828
829 moveto (squareX[0], squareY[0]);
830 lineto (squareX[1], squareY[1]);
831 lineto (squareX[2], squareY[2]);
832 lineto (squareX[3], squareY[3]);
833 closepath();
834 //fprintf (stderr, "#");
835 }
836 else
837 {
838 //fprintf (stderr, ".");
839 }
840 }
841 //fprintf (stderr, "\n");
842 }
843 isUgly = true;
844 XDestroyImage (im);
845 fill (pen);
846 # endif
847 #endif
848 endImage();
849 }
850 bool
hasNative() const851 SPostscript::hasNative () const
852 {
853 return isUgly;
854 }
855
856
857 /**
858 * Fill a solid rectangle
859 * @param x is the upper left corner
860 * @param y is the upper top corner
861 * @param width is the width of the region to fill
862 * @param height is the height of the region to fill
863 */
864 void
bitfill(const SColor & bg,int x,int y,unsigned int width,unsigned int height)865 SPostscript::bitfill (const SColor& bg, int x, int y,
866 unsigned int width, unsigned int height)
867 {
868 }
869
870 /**
871 * Draw a solid line.
872 * @param x is the starting x point
873 * @param y is the starting y point
874 * @param x is the ending non-exclusive x point
875 * @param y is the ending non-exclusive y point
876 */
877 void
bitline(const SColor & fg,int x,int y,int tox,int toy)878 SPostscript::bitline (const SColor& fg, int x, int y, int tox, int toy)
879 {
880 }
881
882 /**
883 * Draw a solid line.
884 * @param x is the x point
885 * @param y is the y point
886 */
887 void
bitpoint(const SColor & fg,int x,int y)888 SPostscript::bitpoint (const SColor& fg, int x, int y)
889 {
890 SString key("BP");
891 key.append (SString((long)x));
892 key.append (SString((long)y));
893 if (beginImage (x, y, key, SColor ("white")))
894 {
895 endImage ();
896 return;
897 }
898 isUgly = true;
899 double squareX[4];
900 double squareY[4];
901 double delta = 1.0;
902
903 squareX[0] = (double)x;
904 squareY[0] = (double)y;
905
906 squareX[1] = squareX[0] + delta;
907 squareY[1] = squareY[0];
908
909 squareX[2] = squareX[0] + delta;
910 squareY[2] = squareY[0] + delta;
911
912 squareX[3] = squareX[0];
913 squareY[3] = squareY[0] + delta;
914
915 moveto (squareX[0], squareY[0]);
916 lineto (squareX[1], squareY[1]);
917 lineto (squareX[2], squareY[2]);
918 lineto (squareX[3], squareY[3]);
919 closepath();
920 fill ();
921 }
922
923 void
bitpoints(const SColor & fg,const int * x,const int * y,unsigned int _size)924 SPostscript::bitpoints (const SColor& fg, const int* x, const int* y,
925 unsigned int _size)
926 {
927 if (_size<=0) return;
928 SString key("BPS");
929 unsigned int i;
930 for (i=0; i<_size; i++)
931 {
932 key.append (SString(((char*) &x[i]), sizeof(int)));
933 key.append (SString(((char*) &y[i]), sizeof(int)));
934 }
935 if (beginImage (x[0], y[0], key, SColor ("white")))
936 {
937 endImage ();
938 return;
939 }
940 newpath();
941 for (i=0; i<_size; i++)
942 {
943 double squareX[4];
944 double squareY[4];
945 double delta = 1.0;
946
947 squareX[0] = (double)x[i];
948 squareY[0] = (double)y[i];
949
950 squareX[1] = squareX[0] + delta;
951 squareY[1] = squareY[0];
952
953 squareX[2] = squareX[0] + delta;
954 squareY[2] = squareY[0] + delta;
955
956 squareX[3] = squareX[0];
957 squareY[3] = squareY[0] + delta;
958
959 moveto (squareX[0], squareY[0]);
960 lineto (squareX[1], squareY[1]);
961 lineto (squareX[2], squareY[2]);
962 lineto (squareX[3], squareY[3]);
963 closepath();
964 }
965 fill ();
966 endImage ();
967 isUgly = true;
968 }
969
970 bool
writeString(const SString & str)971 SPostscript::writeString (const SString& str)
972 {
973 if (status == false) return false;
974 if (out.write (str) == false) status = false;
975 return status;
976 }
977
978 SString
getCreationDate() const979 SPostscript::getCreationDate() const
980 {
981 return SString(creationDate);
982 }
983 bool
timeout(const SEventSource * s)984 SPostscript::timeout (const SEventSource* s)
985 {
986 if (timer==0) return false;
987 return true;
988 }
989