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