1 /* gtkplotpc - gtkplot print context - a renderer for printing functions
2  * Copyright 1999-2001  Adrian E. Feiguin <feiguin@ifir.edu.ar>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /**
21  * SECTION: gtkplotgdk
22  * @short_description: GDK drawing backend (mapped to Cairo)
23  *
24  * This Subclass of #GtkPlotPC has been rewritten to use Cairo
25  * drawing routines.
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32 #include <ctype.h>
33 #include <time.h>
34 #include <gtk/gtk.h>
35 #include <gdk/gdk.h>
36 
37 #include "gtkplotpc.h"
38 #include "gtkplotgdk.h"
39 #include "gtkplot.h"
40 #include "gtkpsfont.h"
41 #include "gtkplotcanvas.h"
42 #include <pango/pango.h>
43 
44 static void gtk_plot_gdk_init                       (GtkPlotGdk *pc);
45 static void gtk_plot_gdk_class_init                 (GtkPlotGdkClass *klass);
46 static void gtk_plot_gdk_finalize                   (GObject *object);
47 static void gtk_plot_gdk_real_set_drawable          (GtkPlotGdk *gdk,
48 						     GdkDrawable *drawable);
49 static gboolean gtk_plot_gdk_real_init              (GtkPlotPC *pc);
50 static void gtk_plot_gdk_set_viewport               (GtkPlotPC *pc,
51 						     gdouble w, gdouble h);
52 static void gtk_plot_gdk_leave                      (GtkPlotPC *pc);
53 static void gtk_plot_gdk_gsave                      (GtkPlotPC *pc);
54 static void gtk_plot_gdk_grestore                   (GtkPlotPC *pc);
55 static void gtk_plot_gdk_clip                       (GtkPlotPC *pc,
56                                                      const GdkRectangle *area);
57 static void gtk_plot_gdk_clip_mask                  (GtkPlotPC *pc,
58 						     gdouble x,
59 						     gdouble y,
60                                                      const GdkBitmap *mask);
61 static void gtk_plot_gdk_set_color                   (GtkPlotPC *pc,
62                                                      const GdkColor *color);
63 static void gtk_plot_gdk_set_lineattr           (GtkPlotPC *pc,
64                                                  gfloat line_width,
65                                                  GdkLineStyle line_style,
66                                                  GdkCapStyle cap_style,
67                                                  GdkJoinStyle join_style);
68 static void gtk_plot_gdk_set_dash                    (GtkPlotPC *pc,
69                                                      gdouble offset_,
70                                                      gdouble *values,
71                                                      gint num_values);
72 static void gtk_plot_gdk_draw_point                  (GtkPlotPC *pc,
73                                                      gdouble x, gdouble y);
74 static void gtk_plot_gdk_draw_line                   (GtkPlotPC *pc,
75                                                      gdouble x1, gdouble y1,
76                                                      gdouble x2, gdouble y2);
77 static void gtk_plot_gdk_draw_lines                  (GtkPlotPC *pc,
78                                                      GtkPlotPoint *points,
79                                                      gint numpoints);
80 static void gtk_plot_gdk_draw_rectangle              (GtkPlotPC *pc,
81                                                      gint filled,
82                                                      gdouble x, gdouble y,
83                                                      gdouble width,
84                                                      gdouble height);
85 static void gtk_plot_gdk_draw_polygon                (GtkPlotPC *pc,
86                                                      gint filled,
87                                                      GtkPlotPoint *points,
88                                                      gint numpoints);
89 static void gtk_plot_gdk_draw_circle                 (GtkPlotPC *pc,
90                                                      gint filled,
91                                                      gdouble x, gdouble y,
92                                                      gdouble size);
93 static void gtk_plot_gdk_draw_ellipse                (GtkPlotPC *pc,
94                                                      gint filled,
95                                                      gdouble x, gdouble y,
96                                                      gdouble width,
97                                                      gdouble height);
98 static void gtk_plot_gdk_set_font                    (GtkPlotPC *pc,
99 						     GtkPSFont *psfont,
100                                                      gint height);
101 static void gtk_plot_gdk_draw_string                (GtkPlotPC *pc,
102                                                      gint x, gint y,
103                                                      gint angle,
104                                                      const GdkColor *fg,
105                                                      const GdkColor *bg,
106                                                      gboolean transparent,
107                                                      gint border,
108                                                      gint border_space,
109                                                      gint border_width,
110                                                      gint shadow_width,
111                                                      const gchar *font,
112                                                      gint height,
113                                                      GtkJustification just,
114                                                      const gchar *text);
115 static void gtk_plot_gdk_draw_pixmap                (GtkPlotPC *pc,
116                                                      GdkPixmap *pixmap,
117                                                      GdkBitmap *mask,
118                                                      gint xsrc, gint ysrc,
119                                                      gint xdest, gint ydest,
120                                                      gint width, gint height,
121                                                      gdouble scale_x,
122                                                      gdouble scale_y);
123 
124 static GdkPixmap * scale_pixmap 		    (GdkWindow *window,
125 						     GdkPixmap *pixmap,
126 						     gdouble scale_x,
127 						     gdouble scale_y);
128 static GdkBitmap * scale_bitmap 		    (GdkWindow *window,
129 						     GdkBitmap *bitmap,
130 						     gdouble scale_x,
131 						     gdouble scale_y);
132 
133 extern gint roundint                         (gdouble x);
134 
135 static GtkPlotPCClass *parent_class = NULL;
136 
137 GType
gtk_plot_gdk_get_type(void)138 gtk_plot_gdk_get_type (void)
139 {
140   static GType pc_type = 0;
141 
142   if (!pc_type)
143     {
144       pc_type = g_type_register_static_simple (
145 		GTK_TYPE_PLOT_PC,
146 		"GtkPlotGdk",
147 		sizeof (GtkPlotGdkClass),
148 		(GClassInitFunc) gtk_plot_gdk_class_init,
149 		sizeof (GtkPlotGdk),
150 		(GInstanceInitFunc) gtk_plot_gdk_init,
151 		0);
152     }
153   return pc_type;
154 }
155 
156 static void
gtk_plot_gdk_init(GtkPlotGdk * pc)157 gtk_plot_gdk_init (GtkPlotGdk *pc)
158 {
159 /*
160   GdkWindowAttr attributes;
161   gint attributes_mask;
162   GdkScreen *screen;
163 
164   attributes.window_type = GDK_WINDOW_CHILD;
165   attributes.title = NULL;
166   attributes.wclass = GDK_INPUT_OUTPUT;
167   attributes.visual = gdk_visual_get_system ();
168   attributes.colormap = gdk_colormap_get_system ();
169   attributes.event_mask = 0;
170   attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
171 */
172   pc->gc = NULL;
173   pc->drawable = NULL;
174   pc->ref_count = 0;
175   pc->text_direction = GTK_TEXT_DIR_LTR;
176 
177 /*
178   pc->window = gdk_window_new (NULL, &attributes, attributes_mask);
179 
180   screen = gdk_screen_get_default ();
181   pc->context = gdk_pango_context_get ();
182 */
183 /*
184   pango_context_set_base_dir (pc->context,
185                               pc->text_direction == GTK_TEXT_DIR_LTR ?
186                               PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL);
187 */
188 /*
189   pango_context_set_language (pc->context, gtk_get_default_language ());
190 
191   pc->layout = pango_layout_new(pc->context);
192 */
193 }
194 
195 
196 static void
gtk_plot_gdk_class_init(GtkPlotGdkClass * klass)197 gtk_plot_gdk_class_init (GtkPlotGdkClass *klass)
198 {
199   GtkObjectClass *object_class;
200   GObjectClass *gobject_class;
201   GtkPlotPCClass *pc_class;
202   GtkPlotGdkClass *gdk_class;
203 
204   parent_class = g_type_class_ref (gtk_plot_pc_get_type ());
205 
206   object_class = (GtkObjectClass *) klass;
207   gobject_class = (GObjectClass *) klass;
208 
209   pc_class = (GtkPlotPCClass *) klass;
210   gdk_class = (GtkPlotGdkClass *) klass;
211 
212   gobject_class->finalize = gtk_plot_gdk_finalize;
213 
214   gdk_class->set_drawable = gtk_plot_gdk_real_set_drawable;
215 
216   pc_class->init = gtk_plot_gdk_real_init;
217   pc_class->leave = gtk_plot_gdk_leave;
218   pc_class->set_viewport = gtk_plot_gdk_set_viewport;
219   pc_class->gsave = gtk_plot_gdk_gsave;
220   pc_class->grestore = gtk_plot_gdk_grestore;
221   pc_class->clip = gtk_plot_gdk_clip;
222   pc_class->clip_mask = gtk_plot_gdk_clip_mask;
223   pc_class->set_color = gtk_plot_gdk_set_color;
224   pc_class->set_dash = gtk_plot_gdk_set_dash;
225   pc_class->set_lineattr = gtk_plot_gdk_set_lineattr;
226   pc_class->draw_point = gtk_plot_gdk_draw_point;
227   pc_class->draw_line = gtk_plot_gdk_draw_line;
228   pc_class->draw_lines = gtk_plot_gdk_draw_lines;
229   pc_class->draw_rectangle = gtk_plot_gdk_draw_rectangle;
230   pc_class->draw_polygon = gtk_plot_gdk_draw_polygon;
231   pc_class->draw_circle = gtk_plot_gdk_draw_circle;
232   pc_class->draw_ellipse = gtk_plot_gdk_draw_ellipse;
233   pc_class->set_font = gtk_plot_gdk_set_font;
234   pc_class->draw_string = gtk_plot_gdk_draw_string;
235   pc_class->draw_pixmap = gtk_plot_gdk_draw_pixmap;
236 }
237 
238 
239 /**
240  * gtk_plot_gdk_new:
241  * @widget:
242  *
243  *
244  *
245  * Return value:
246  */
247 GtkObject *
gtk_plot_gdk_new(GtkWidget * widget)248 gtk_plot_gdk_new                                (GtkWidget *widget)
249 {
250   GtkObject *object;
251 
252   object = g_object_new(gtk_plot_gdk_get_type(), NULL);
253 
254   gtk_plot_gdk_construct(GTK_PLOT_GDK(object), widget);
255 
256   return (object);
257 }
258 
259 /**
260  * gtk_plot_gdk_construct:
261  * @pc:
262  * @widget:
263  *
264  *
265  */
266 void
gtk_plot_gdk_construct(GtkPlotGdk * pc,GtkWidget * widget)267 gtk_plot_gdk_construct(GtkPlotGdk *pc, GtkWidget *widget)
268 {
269   pc->window = gtk_widget_get_window(widget);
270   pc->context = gtk_widget_get_pango_context (widget);
271   g_object_ref(G_OBJECT(pc->context));
272   pc->layout = pango_layout_new(pc->context);
273 }
274 
275 
276 static void
gtk_plot_gdk_finalize(GObject * object)277 gtk_plot_gdk_finalize (GObject *object)
278 {
279   GtkPlotGdk *pc = GTK_PLOT_GDK(object);
280 
281   GTK_PLOT_GDK(object)->window = NULL;
282 
283   if(GTK_PLOT_GDK(object)->ref_count > 0 && GTK_PLOT_GDK(object)->gc){
284           gdk_gc_destroy(GTK_PLOT_GDK(object)->gc);
285           GTK_PLOT_GDK(object)->gc = NULL;
286   }
287 
288   if(pc->layout)
289     g_object_unref(G_OBJECT(pc->layout));
290   pc->layout = NULL;
291 
292   if(pc->context)
293     g_object_unref(G_OBJECT(pc->context));
294   pc->context = NULL;
295 }
296 
297 static void
gtk_plot_gdk_real_set_drawable(GtkPlotGdk * pc,GdkDrawable * drawable)298 gtk_plot_gdk_real_set_drawable(GtkPlotGdk *pc, GdkDrawable *drawable)
299 {
300   pc->drawable = drawable;
301 }
302 
303 static gboolean
gtk_plot_gdk_real_init(GtkPlotPC * pc)304 gtk_plot_gdk_real_init (GtkPlotPC *pc)
305 {
306   return TRUE;
307 }
308 
309 static void
gtk_plot_gdk_leave(GtkPlotPC * pc)310 gtk_plot_gdk_leave (GtkPlotPC *pc)
311 {
312 }
313 
314 /**
315  * gtk_plot_gdk_set_drawable:
316  * @gdk:
317  * @drawable:
318  *
319  *
320  */
321 void
gtk_plot_gdk_set_drawable(GtkPlotGdk * gdk,GdkDrawable * drawable)322 gtk_plot_gdk_set_drawable               (GtkPlotGdk *gdk, GdkDrawable *drawable)
323 {
324   GTK_PLOT_GDK_CLASS(GTK_OBJECT_GET_CLASS(GTK_OBJECT(gdk)))->set_drawable(gdk, drawable);
325 }
326 
327 static void
gtk_plot_gdk_set_viewport(GtkPlotPC * pc,gdouble w,gdouble h)328 gtk_plot_gdk_set_viewport               (GtkPlotPC *pc, gdouble w, gdouble h)
329 {
330 }
331 
332 static void
gtk_plot_gdk_gsave(GtkPlotPC * pc)333 gtk_plot_gdk_gsave                                  (GtkPlotPC *pc)
334 {
335   if(GTK_PLOT_GDK(pc)->gc)
336     gdk_gc_ref(GTK_PLOT_GDK(pc)->gc);
337   else{
338     if(GTK_PLOT_GDK(pc)->drawable) GTK_PLOT_GDK(pc)->gc = gdk_gc_new(GTK_PLOT_GDK(pc)->drawable);
339   }
340 
341   GTK_PLOT_GDK(pc)->ref_count++;
342 }
343 
344 static void
gtk_plot_gdk_grestore(GtkPlotPC * pc)345 gtk_plot_gdk_grestore                                  (GtkPlotPC *pc)
346 {
347   if(GTK_PLOT_GDK(pc)->gc) gdk_gc_unref(GTK_PLOT_GDK(pc)->gc);
348 
349   GTK_PLOT_GDK(pc)->ref_count--;
350   if(GTK_PLOT_GDK(pc)->ref_count == 0) GTK_PLOT_GDK(pc)->gc = NULL;
351 }
352 
353 static void
gtk_plot_gdk_clip(GtkPlotPC * pc,const GdkRectangle * area)354 gtk_plot_gdk_clip                                   (GtkPlotPC *pc,
355                                                      const GdkRectangle *area)
356 {
357   if(!GTK_PLOT_GDK(pc)->gc) return;
358 
359   /* discard GdkRectangle* const:
360    * gdk_gc_set_clip_rectangle should have a const arg.
361    * I've checked the code and it doesn't change it or keep it. murrayc.
362    */
363 
364   gdk_gc_set_clip_rectangle(GTK_PLOT_GDK(pc)->gc, (GdkRectangle*)area);
365 }
366 
367 static void
gtk_plot_gdk_clip_mask(GtkPlotPC * pc,gdouble x,gdouble y,const GdkBitmap * mask)368 gtk_plot_gdk_clip_mask                              (GtkPlotPC *pc,
369 						     gdouble x,
370 						     gdouble y,
371                                                      const GdkBitmap *mask)
372 {
373   if(!GTK_PLOT_GDK(pc)->gc) return;
374 
375   if(x >= 0 && y >= 0)
376     gdk_gc_set_clip_origin(GTK_PLOT_GDK(pc)->gc, x, y);
377 
378   gdk_gc_set_clip_mask(GTK_PLOT_GDK(pc)->gc, (GdkBitmap*)mask);
379 }
380 
381 static void
gtk_plot_gdk_set_color(GtkPlotPC * pc,const GdkColor * color)382 gtk_plot_gdk_set_color                               (GtkPlotPC *pc,
383                                                      const GdkColor *color)
384 {
385   GdkColor new_color;
386 
387   if(!GTK_PLOT_GDK(pc)->gc) return;
388 
389   new_color = *color;
390   gdk_color_alloc(gdk_colormap_get_system(), &new_color);
391   gdk_gc_set_foreground(GTK_PLOT_GDK(pc)->gc, &new_color);
392 }
393 
394 static void
gtk_plot_gdk_set_dash(GtkPlotPC * pc,gdouble offset,gdouble * values,gint num_values)395 gtk_plot_gdk_set_dash                               (GtkPlotPC *pc,
396                                                     gdouble offset,
397                                                     gdouble *values,
398                                                     gint num_values)
399 {
400   gint list[] = {0, 1, 2, 3, 4, 5, 6, 7};
401   gint8 dash[1000];
402   gint i;
403 
404   if(!GTK_PLOT_GDK(pc)->gc) return;
405 
406   if(num_values == 0){
407     return;
408   }
409 
410   for(i = 0; i < num_values; i++){
411      gint value;
412      value = values[i];
413      dash[i] = list[value];
414   }
415 
416   gdk_gc_set_dashes(GTK_PLOT_GDK(pc)->gc, 0, dash, num_values);
417 }
418 
gtk_plot_gdk_set_lineattr(GtkPlotPC * pc,gfloat line_width,GdkLineStyle line_style,GdkCapStyle cap_style,GdkJoinStyle join_style)419 static void gtk_plot_gdk_set_lineattr           (GtkPlotPC *pc,
420                                                  gfloat line_width,
421                                                  GdkLineStyle line_style,
422                                                  GdkCapStyle cap_style,
423                                                  GdkJoinStyle join_style)
424 {
425   if(!GTK_PLOT_GDK(pc)->gc) return;
426 
427   gdk_gc_set_line_attributes(GTK_PLOT_GDK(pc)->gc,
428                              roundint(line_width),
429                              line_style,
430                              cap_style,
431                              join_style);
432 }
433 
434 static void
gtk_plot_gdk_draw_point(GtkPlotPC * pc,gdouble x,gdouble y)435 gtk_plot_gdk_draw_point                              (GtkPlotPC *pc,
436                                                      gdouble x, gdouble y)
437 {
438   if(!GTK_PLOT_GDK(pc)->gc) return;
439   if(!GTK_PLOT_GDK(pc)->drawable) return;
440 
441   gdk_draw_point(GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
442                  roundint(x), roundint(y));
443 }
444 
445 static void
gtk_plot_gdk_draw_line(GtkPlotPC * pc,gdouble x1,gdouble y1,gdouble x2,gdouble y2)446 gtk_plot_gdk_draw_line                               (GtkPlotPC *pc,
447                                                      gdouble x1, gdouble y1,
448                                                      gdouble x2, gdouble y2)
449 {
450   if(!GTK_PLOT_GDK(pc)->gc) return;
451   if(!GTK_PLOT_GDK(pc)->drawable) return;
452 
453   gdk_draw_line(GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
454                 roundint(x1), roundint(y1), roundint(x2), roundint(y2));
455 }
456 
457 static void
gtk_plot_gdk_draw_lines(GtkPlotPC * pc,GtkPlotPoint * points,gint numpoints)458 gtk_plot_gdk_draw_lines                              (GtkPlotPC *pc,
459                                                      GtkPlotPoint *points,
460                                                      gint numpoints)
461 {
462   GdkPoint *p = NULL;
463   gint i;
464 
465   if(!GTK_PLOT_GDK(pc)->gc) return;
466   if(!GTK_PLOT_GDK(pc)->drawable) return;
467 
468   p = (GdkPoint *)g_malloc(numpoints * sizeof(GdkPoint));
469   for(i = 0; i < numpoints; i++){
470     p[i].x = roundint(points[i].x);
471     p[i].y = roundint(points[i].y);
472   }
473 
474   gdk_draw_lines(GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc, p, numpoints);
475 
476   g_free(p);
477 }
478 
479 static void
gtk_plot_gdk_draw_rectangle(GtkPlotPC * pc,gint filled,gdouble x,gdouble y,gdouble width,gdouble height)480 gtk_plot_gdk_draw_rectangle                          (GtkPlotPC *pc,
481                                                      gint filled,
482                                                      gdouble x, gdouble y,
483                                                      gdouble width, gdouble height)
484 {
485   if(!GTK_PLOT_GDK(pc)->gc) return;
486   if(!GTK_PLOT_GDK(pc)->drawable) return;
487 
488   gdk_draw_rectangle (GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
489                       filled,
490                       roundint(x), roundint(y),
491                       roundint(width), roundint(height));
492 
493 }
494 
495 static void
gtk_plot_gdk_draw_polygon(GtkPlotPC * pc,gint filled,GtkPlotPoint * points,gint numpoints)496 gtk_plot_gdk_draw_polygon                            (GtkPlotPC *pc,
497                                                      gint filled,
498                                                      GtkPlotPoint *points,
499                                                      gint numpoints)
500 {
501   GdkPoint *p = NULL;
502   gint i;
503 
504   if(!GTK_PLOT_GDK(pc)->gc) return;
505   if(!GTK_PLOT_GDK(pc)->drawable) return;
506 
507   p = (GdkPoint *)g_malloc(numpoints * sizeof(GdkPoint));
508   for(i = 0; i < numpoints; i++){
509     p[i].x = roundint(points[i].x);
510     p[i].y = roundint(points[i].y);
511   }
512 
513   gdk_draw_polygon(GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
514                    filled, p, numpoints);
515 
516   g_free(p);
517 }
518 
519 static void
gtk_plot_gdk_draw_circle(GtkPlotPC * pc,gint filled,gdouble x,gdouble y,gdouble size)520 gtk_plot_gdk_draw_circle                             (GtkPlotPC *pc,
521                                                      gint filled,
522                                                      gdouble x, gdouble y,
523                                                      gdouble size)
524 {
525   if(!GTK_PLOT_GDK(pc)->gc) return;
526   if(!GTK_PLOT_GDK(pc)->drawable) return;
527 
528   gdk_draw_arc (GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
529                 filled,
530                 roundint(x-size/2.0), roundint(y-size/2.0),
531                 roundint(size), roundint(size), 0, 25000);
532 
533 }
534 
535 static void
gtk_plot_gdk_draw_ellipse(GtkPlotPC * pc,gint filled,gdouble x,gdouble y,gdouble width,gdouble height)536 gtk_plot_gdk_draw_ellipse                            (GtkPlotPC *pc,
537                                                      gint filled,
538                                                      gdouble x, gdouble y,
539                                                      gdouble width, gdouble height)
540 {
541   if(!GTK_PLOT_GDK(pc)->gc) return;
542   if(!GTK_PLOT_GDK(pc)->drawable) return;
543 
544   gdk_draw_arc (GTK_PLOT_GDK(pc)->drawable, GTK_PLOT_GDK(pc)->gc,
545                 filled,
546                 roundint(x), roundint(y),
547                 roundint(width), roundint(height), 0, 25000);
548 }
549 
550 static void
gtk_plot_gdk_set_font(GtkPlotPC * pc,GtkPSFont * psfont,gint height)551 gtk_plot_gdk_set_font                                (GtkPlotPC *pc,
552 						     GtkPSFont *psfont,
553                                                      gint height)
554 {
555 
556 }
557 
558 /* subfunction of gtk_plot_gdk_draw_string(). */
559 static gint
drawstring(GtkPlotPC * pc,GdkDrawable * drawable,GdkGC * gc,gint angle,gint dx,gint dy,GtkPSFont * psfont,gint height,const gchar * text)560 drawstring(GtkPlotPC *pc,
561 	   GdkDrawable *drawable,
562 	   GdkGC *gc,
563            gint angle,
564 	   gint dx, gint dy,
565 	   GtkPSFont *psfont, gint height,
566 	   const gchar *text)
567 {
568   PangoFontDescription *font;
569   PangoRectangle rect;
570   gint ret_value;
571 
572   if(!text || strlen(text) == 0) return 0;
573   font = gtk_psfont_get_font_description(psfont, height);
574   pango_layout_set_font_description(GTK_PLOT_GDK(pc)->layout, font);
575 
576   pango_layout_set_text(GTK_PLOT_GDK(pc)->layout, text, strlen(text));
577   pango_layout_get_extents(GTK_PLOT_GDK(pc)->layout, NULL, &rect);
578 
579   if (psfont->i18n_latinfamily && psfont->vertical) {
580     /* vertical-writing CJK postscript fonts. */
581     return rect.height;
582   }
583   else
584   {
585     /* horizontal writing */
586     if(angle == 90)
587       gdk_draw_layout (drawable, gc, dx, dy-PANGO_PIXELS(rect.width), GTK_PLOT_GDK(pc)->layout);
588     else if(angle == 180)
589       gdk_draw_layout (drawable, gc, dx-PANGO_PIXELS(rect.width), dy, GTK_PLOT_GDK(pc)->layout);
590     else
591       gdk_draw_layout (drawable, gc, dx, dy, GTK_PLOT_GDK(pc)->layout);
592 
593 /*
594     gdk_draw_layout (GTK_PLOT_GDK(pc)->drawable, gc, dx, dy, GTK_PLOT_GDK(pc)->layout);
595 */
596 
597   }
598   if (font) pango_font_description_free(font);
599   ret_value = (angle == 0 || angle == 180) ? rect.width : rect.height;
600   return PANGO_PIXELS(rect.width);
601 }
602 
603 static void
gtk_plot_gdk_draw_string(GtkPlotPC * pc,gint tx,gint ty,gint angle,const GdkColor * fg,const GdkColor * bg,gboolean transparent,gint border,gint border_space,gint border_width,gint shadow_width,const gchar * font_name,gint font_height,GtkJustification just,const gchar * text)604 gtk_plot_gdk_draw_string                        (GtkPlotPC *pc,
605                                                 gint tx, gint ty,
606                                                 gint angle,
607                                                 const GdkColor *fg,
608                                                 const GdkColor *bg,
609                                                 gboolean transparent,
610                                                 gint border,
611                                                 gint border_space,
612                                                 gint border_width,
613                                                 gint shadow_width,
614                                                 const gchar *font_name,
615                                                 gint font_height,
616                                                 GtkJustification just,
617                                                 const gchar *text)
618 {
619   GdkGC *gc;
620   GList *family = NULL;
621   gint x0, y0;
622   gint old_width, old_height;
623   gboolean bold, italic;
624   gint fontsize;
625   gint ascent, descent;
626   gint numf;
627   gint width, height;
628   gint x, y;
629   gint i;
630   PangoFontDescription *font = NULL, *latin_font = NULL;
631   GtkPSFont *psfont, *base_psfont, *latin_psfont;
632   gchar subs[2], insert_char;
633   const gchar *aux = text;
634   const gchar *lastchar = text;
635   const gchar *wtext = text;
636   const gchar *xaux = text;
637   gchar *new_text; /* Support Tiny C compiler : Original : gchar new_text[strlen(text)+1];*/
638   gchar num[4];
639   PangoRectangle rect;
640   PangoFontMetrics *metrics = NULL;
641   PangoLayout *layout = NULL;
642   gint real_x, real_y, real_width, real_height;
643   GdkColor real_fg = *fg;
644   GdkColor real_bg = *bg;
645   PangoMatrix matrix = PANGO_MATRIX_INIT;
646   PangoContext *context = GTK_PLOT_GDK(pc)->context;
647   GdkDrawable *drawable = GTK_PLOT_GDK(pc)->drawable;
648   gint sign_x = 1, sign_y = 0;
649   gint old_tx = tx, old_ty = ty;
650 
651   if(!GTK_PLOT_GDK(pc)->drawable) return;
652   if(!GTK_PLOT_GDK(pc)->gc) return;
653   if(!text || strlen(text) == 0) return;
654 
655   gc = GTK_PLOT_GDK(pc)->gc;
656   layout = GTK_PLOT_GDK(pc)->layout;
657 
658   if(!gc) return;
659 
660   gtk_plot_text_get_size(text, angle, font_name, font_height, &width, &height, &ascent, &descent);
661 
662   if(height == 0 || width == 0) return;
663 
664   old_width = width;
665   old_height = height;
666   if(angle == 90 || angle == 270)
667     {
668       old_width = height;
669       old_height = width;
670     }
671   switch(angle){
672     case 90:
673       sign_x = 0;
674       sign_y = -1;
675       break;
676     case 180:
677       sign_x = -1;
678       sign_y = 0;
679       break;
680     case 270:
681       sign_x = 0;
682       sign_y = 1;
683       break;
684     case 0:
685     default:
686       sign_x = 1;
687       sign_y = 0;
688       break;
689   }
690 
691   switch(just){
692     case GTK_JUSTIFY_LEFT:
693       switch(angle){
694         case 0:
695             ty -= ascent;
696             break;
697         case 90:
698             ty -= height;
699             tx -= ascent;
700             break;
701         case 180:
702             tx -= width;
703             ty -= descent;
704             break;
705         case 270:
706             tx -= descent;
707             break;
708       }
709       old_tx = tx;
710       old_ty = ty;
711       break;
712     case GTK_JUSTIFY_RIGHT:
713       switch(angle){
714         case 0:
715             tx -= width;
716             ty -= ascent;
717             old_tx -= width;
718             old_ty -= ascent;
719             break;
720         case 90:
721             tx -= ascent;
722             ty += height;
723             old_tx -= ascent;
724             break;
725         case 180:
726             tx += width;
727             ty -= descent;
728             old_ty -= descent;
729             break;
730         case 270:
731             tx -= descent;
732             old_tx -= descent;
733             old_ty -= height;
734             break;
735       }
736       break;
737     case GTK_JUSTIFY_CENTER:
738     default:
739       switch(angle){
740         case 0:
741             tx -= width / 2.;
742             ty -= ascent;
743             old_tx -= width / 2.;
744             old_ty -= ascent;
745             break;
746         case 90:
747             tx -= ascent;
748             ty += height / 2.;
749             old_tx -= ascent;
750             old_ty -= height / 2.;
751             break;
752         case 180:
753             tx += width / 2.;
754             ty -= descent;
755             old_tx -= width / 2.;
756             old_ty -= descent;
757             break;
758         case 270:
759             tx -= descent;
760             ty -= height / 2.;
761             old_tx -= descent;
762             old_ty -= height / 2.;
763             break;
764       }
765   }
766 
767   real_x = tx;
768   real_y = ty;
769   real_width = width;
770   real_height = height;
771 
772   pango_matrix_rotate (&matrix, angle);
773   pango_context_set_matrix (context, &matrix);
774   pango_layout_context_changed (layout);
775 
776   if(!transparent){
777     gdk_gc_set_foreground(gc, &real_bg);
778     gdk_draw_rectangle(drawable, gc, TRUE, old_tx, old_ty, old_width, old_height);
779   }
780 
781 /* TEST */
782 /*
783   gdk_draw_rectangle(text_pixmap, gc, FALSE, 0, 0, old_width-1, old_height-1);
784 */
785 
786   gtk_psfont_get_families(&family, &numf);
787   base_psfont = psfont = gtk_psfont_get_by_name(font_name);
788   font = gtk_psfont_get_font_description(psfont, font_height);
789   italic = psfont->italic;
790   bold = psfont->bold;
791   fontsize = font_height;
792   x0 = x = 0;
793   y0 = y = 0;
794 
795   if (psfont->i18n_latinfamily) {
796     latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily, italic,
797                                              bold);
798     if(latin_font) pango_font_description_free(latin_font);
799     latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
800   } else {
801     latin_psfont = NULL;
802     latin_font = NULL;
803   }
804 
805   gdk_gc_set_foreground(gc, &real_fg);
806   aux = text;
807   while(aux && *aux != '\0' && *aux != '\n'){
808    if(*aux == '\\'){
809      aux = g_utf8_next_char(aux);
810      switch(*aux){
811        case '0': case '1': case '2': case '3':
812        case '4': case '5': case '6': case '7': case '9':
813            psfont = gtk_psfont_get_by_family((gchar *)g_list_nth_data(family, *aux-'0'), italic, bold);
814            pango_font_description_free(font);
815            font = gtk_psfont_get_font_description(psfont, fontsize);
816            aux = g_utf8_next_char(aux);
817            break;
818        case '8': case 'g':
819            psfont = gtk_psfont_get_by_family("Symbol", italic, bold);
820            pango_font_description_free(font);
821            font = gtk_psfont_get_font_description(psfont, fontsize);
822            aux = g_utf8_next_char(aux);
823            break;
824        case 'B':
825            bold = TRUE;
826            psfont = gtk_psfont_get_by_family(psfont->family, italic, bold);
827            pango_font_description_free(font);
828            font = gtk_psfont_get_font_description(psfont, fontsize);
829            if(latin_font){
830              latin_font = NULL;
831            }
832            if (psfont->i18n_latinfamily) {
833              latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily,
834                                                       italic, bold);
835              if(latin_font) pango_font_description_free(latin_font);
836              latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
837            }
838            aux = g_utf8_next_char(aux);
839            break;
840        case 'x':
841            xaux = aux + 1;
842            for (i=0; i<3; i++){
843             if (xaux[i] >= '0' && xaux[i] <= '9')
844               num[i] = xaux[i];
845             else
846               break;
847            }
848            if (i < 3){
849               aux = g_utf8_next_char(aux);
850               break;
851            }
852            num[3] = '\0';
853            insert_char = (gchar)atoi(num);
854            subs[0] = insert_char;
855            subs[1] = '\0';
856            pango_layout_set_font_description(layout, font);
857            pango_layout_set_text(layout, subs, 1);
858            pango_layout_get_extents(layout, NULL, &rect);
859            x += sign_x*PANGO_PIXELS(rect.width);
860            y += sign_y*PANGO_PIXELS(rect.width);
861            aux += 4;
862            lastchar = aux - 1;
863            break;
864        case 'i':
865            italic = TRUE;
866            psfont = gtk_psfont_get_by_family(psfont->family, italic, bold);
867            pango_font_description_free(font);
868            font = gtk_psfont_get_font_description(psfont, fontsize);
869            if (psfont->i18n_latinfamily) {
870              latin_psfont = gtk_psfont_get_by_family(psfont->i18n_latinfamily,
871                                                       italic, bold);
872              if(latin_font) pango_font_description_free(latin_font);
873              latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
874            }
875            aux = g_utf8_next_char(aux);
876            break;
877        case 'S': case '^':
878            fontsize = (int)((gdouble)fontsize * 0.6 + 0.5);
879            pango_font_description_free(font);
880            font = gtk_psfont_get_font_description(psfont, fontsize);
881            if(metrics) pango_font_metrics_unref(metrics);
882            metrics = pango_context_get_metrics(pango_layout_get_context(layout), font, pango_context_get_language(pango_layout_get_context(layout)));
883            if (psfont->i18n_latinfamily) {
884              latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
885            }
886            if(angle == 180)
887              y = y0 + fontsize;
888            else if(angle == 270)
889              x = x0 + sign_y*fontsize;
890            aux = g_utf8_next_char(aux);
891            break;
892        case 's': case '_':
893            fontsize = (int)((gdouble)fontsize * 0.6 + 0.5);
894            pango_font_description_free(font);
895            font = gtk_psfont_get_font_description(psfont, fontsize);
896            if(metrics) pango_font_metrics_unref(metrics);
897            metrics = pango_context_get_metrics(pango_layout_get_context(layout), font, pango_context_get_language(pango_layout_get_context(layout)));
898            if(angle == 0)
899              y = y0 + fontsize;
900            else if(angle == 90)
901              x = x0 - sign_y*fontsize;
902            if (psfont->i18n_latinfamily) {
903              latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
904            }
905            aux = g_utf8_next_char(aux);
906            break;
907        case '+':
908            fontsize += 3;
909            y -= sign_x*3;
910            x += sign_y*3;
911            pango_font_description_free(font);
912            font = gtk_psfont_get_font_description(psfont, fontsize);
913            if (psfont->i18n_latinfamily) {
914              latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
915            }
916            aux = g_utf8_next_char(aux);
917            break;
918        case '-':
919            fontsize -= 3;
920            y += sign_x*3;
921            x -= sign_y*3;
922            pango_font_description_free(font);
923            font = gtk_psfont_get_font_description(psfont, fontsize);
924            if (psfont->i18n_latinfamily) {
925              latin_font = gtk_psfont_get_font_description(latin_psfont, fontsize);
926            }
927            aux = g_utf8_next_char(aux);
928            break;
929        case 'N':
930 	   psfont = base_psfont;
931            fontsize = font_height;
932            pango_font_description_free(font);
933            font = gtk_psfont_get_font_description(psfont, fontsize);
934            if(angle == 0 || angle == 180)
935              y = y0;
936            else
937              x = x0;
938            italic = psfont->italic;
939            bold = psfont->bold;
940            aux = g_utf8_next_char(aux);
941            break;
942        case 'b':
943 	   if (lastchar) {
944              const gchar *aux2 = lastchar;
945              gint i = g_utf8_prev_char(lastchar) != --aux2 ? 2 : 1;
946              pango_layout_set_text(layout, lastchar, i);
947              pango_layout_get_extents(layout, NULL, &rect);
948 	     x -= sign_x*PANGO_PIXELS(rect.width);
949 	     y -= sign_y*PANGO_PIXELS(rect.width);
950 
951 	     if (lastchar == wtext)
952 	       lastchar = NULL;
953 	     else
954 	       lastchar = g_utf8_prev_char(lastchar);
955 	   } else {
956              pango_layout_set_text(layout, "X", 1);
957              pango_layout_get_extents(layout, NULL, &rect);
958 	     x -= sign_x*PANGO_PIXELS(rect.width);
959 	     y -= sign_y*PANGO_PIXELS(rect.width);
960 	   }
961            aux = g_utf8_next_char(aux);
962            break;
963        default:
964            if(aux && *aux != '\0' && *aux !='\n'){
965              gint new_width = 0;
966 	     new_width = drawstring(pc, drawable, gc, angle, tx+x, ty+y,
967 			     psfont, fontsize, aux);
968              x += sign_x * new_width;
969              y += sign_y * new_width;
970 	     lastchar = aux;
971 	     aux = g_utf8_next_char(aux);
972 	   }
973 	   break;
974      }
975    } else {
976      gint new_len = 0;
977      gint new_width = 0;
978      lastchar = aux;
979      while(aux && *aux != '\0' && *aux !='\n' && *aux != '\\'){
980        xaux = aux;
981        new_len += g_utf8_next_char(aux) != ++xaux ? 2 : 1;
982        aux = g_utf8_next_char(aux);
983      }
984      xaux = lastchar;
985 
986      new_text = (gchar *) g_new0(gchar , strlen(text)+1); /* Tiny C Compiler support */
987      for(i = 0; i < new_len; i++) new_text[i] = *xaux++;
988      new_text[new_len] = '\0';
989      new_width = drawstring(pc, drawable, gc, angle, tx+x, ty+y,
990 	         psfont, fontsize, new_text);
991      x += sign_x * new_width;
992      y += sign_y * new_width;
993      lastchar = aux;
994 
995      g_free (new_text);
996    }
997   }
998 
999   pango_matrix_rotate (&matrix, 0);
1000   pango_context_set_matrix (context, &matrix);
1001   pango_font_description_free(font);
1002   if(latin_font) pango_font_description_free(latin_font);
1003   if(metrics) pango_font_metrics_unref(metrics);
1004 
1005 /* border */
1006 
1007   gdk_gc_set_foreground(gc, &real_fg);
1008   gtk_plot_pc_set_dash(pc, 0, NULL, 0);
1009   gtk_plot_pc_set_lineattr(pc, border_width, 0, 0, 0);
1010   switch(border){
1011     case GTK_PLOT_BORDER_SHADOW:
1012       gtk_plot_pc_draw_rectangle(pc,
1013    		         TRUE,
1014                          old_tx - border_space + shadow_width,
1015                          old_ty + height + border_space,
1016                          width + 2 * border_space, shadow_width);
1017       gtk_plot_pc_draw_rectangle(pc,
1018    		         TRUE,
1019                          old_tx + width + border_space,
1020                          old_ty - border_space + shadow_width,
1021                          shadow_width, height + 2 * border_space);
1022     case GTK_PLOT_BORDER_LINE:
1023       gtk_plot_pc_draw_rectangle(pc,
1024    		         FALSE,
1025                          old_tx - border_space, old_ty - border_space,
1026                          width + 2*border_space, height + 2*border_space);
1027     case GTK_PLOT_BORDER_NONE:
1028     default:
1029 	break;
1030   }
1031 
1032   return;
1033 }
1034 
gtk_plot_gdk_draw_pixmap(GtkPlotPC * pc,GdkPixmap * pixmap,GdkBitmap * mask,gint xsrc,gint ysrc,gint xdest,gint ydest,gint width,gint height,gdouble scale_x,gdouble scale_y)1035 static void gtk_plot_gdk_draw_pixmap                (GtkPlotPC *pc,
1036                                                      GdkPixmap *pixmap,
1037                                                      GdkBitmap *mask,
1038                                                      gint xsrc, gint ysrc,
1039                                                      gint xdest, gint ydest,
1040                                                      gint width,
1041                                                      gint height,
1042                                                      gdouble scale_x,
1043                                                      gdouble scale_y)
1044 {
1045   GdkGC *gc;
1046   GdkPixmap *new_pixmap;
1047   GdkBitmap *new_mask = NULL;
1048 
1049   if(!GTK_PLOT_GDK(pc)->drawable) return;
1050   if(!GTK_PLOT_GDK(pc)->gc) return;
1051 
1052   gc = GTK_PLOT_GDK(pc)->gc;
1053 
1054   if(!gc) return;
1055 
1056   new_pixmap = scale_pixmap(GTK_PLOT_GDK(pc)->drawable, pixmap, scale_x, scale_y);
1057 
1058   if(mask)
1059      new_mask = scale_bitmap(GTK_PLOT_GDK(pc)->drawable, mask, scale_x, scale_y);
1060 
1061 /* TEST
1062   new_pixmap = pixmap; gdk_pixmap_ref(pixmap);
1063   if(mask) new_mask = mask; gdk_bitmap_ref(mask);
1064 */
1065 
1066   gtk_plot_pc_clip_mask(pc, xdest, ydest, new_mask);
1067   gdk_draw_pixmap(GTK_PLOT_GDK(pc)->drawable, gc, new_pixmap,
1068                   xsrc, ysrc, xdest, ydest, width*scale_x, height*scale_y);
1069   gtk_plot_pc_clip_mask(pc, xdest, ydest, NULL);
1070 
1071   if(new_mask) gdk_bitmap_unref(new_mask);
1072   gdk_pixmap_unref(new_pixmap);
1073 }
1074 
1075 static GdkPixmap *
scale_pixmap(GdkWindow * window,GdkPixmap * pixmap,gdouble scale_x,gdouble scale_y)1076 scale_pixmap (GdkWindow *window, GdkPixmap *pixmap, gdouble scale_x, gdouble scale_y)
1077 {
1078   GdkGC *gc = NULL;
1079   GdkPixmap *new_pixmap;
1080   gint width, height, new_width, new_height;
1081   GdkPixbuf *pixbuf = NULL;
1082   GdkPixbuf *aux_pixbuf = NULL;
1083 
1084   if(!pixmap) return NULL;
1085   if(!window) return NULL;
1086 
1087   gdk_window_get_size(pixmap, &width, &height);
1088 
1089   gc = gdk_gc_new(window);
1090 
1091   if(scale_x == 1.0 && scale_y == 1.0){
1092     new_pixmap = gdk_pixmap_new(window, width, height, -1);
1093     gdk_draw_pixmap(new_pixmap,
1094                     gc,
1095                     pixmap,
1096                     0, 0,
1097                     0, 0,
1098                     width, height);
1099     return new_pixmap;
1100   }
1101 
1102   new_width = roundint(width * scale_x);
1103   new_height = roundint(height * scale_y);
1104 
1105   pixbuf = gdk_pixbuf_get_from_drawable(NULL, pixmap, gdk_drawable_get_colormap(window), 0, 0, 0, 0, width, height);
1106   aux_pixbuf = gdk_pixbuf_scale_simple(pixbuf, new_width, new_height, GDK_INTERP_BILINEAR);
1107   new_pixmap = gdk_pixmap_new(pixmap, new_width, new_height, -1);
1108   gdk_draw_pixbuf(new_pixmap, gc, aux_pixbuf, 0, 0, 0, 0, new_width, new_height, GDK_RGB_DITHER_MAX, 0, 0);
1109 
1110   gdk_pixbuf_unref(pixbuf);
1111   gdk_pixbuf_unref(aux_pixbuf);
1112 
1113   gdk_gc_unref(gc);
1114 
1115   return new_pixmap;
1116 }
1117 
1118 static GdkBitmap *
scale_bitmap(GdkWindow * window,GdkBitmap * bitmap,gdouble scale_x,gdouble scale_y)1119 scale_bitmap (GdkWindow *window, GdkBitmap *bitmap, gdouble scale_x, gdouble scale_y)
1120 {
1121   GdkGC *gc;
1122   GdkVisual *visual = NULL;
1123   GdkImage *image = NULL, *new_image = NULL;
1124   GdkBitmap *new_bitmap = NULL;
1125   gint x, y, width, height, new_width, new_height;
1126   GdkColor color;
1127 
1128   if(!bitmap) return NULL;
1129   if(!window) return NULL;
1130 
1131   gc = gdk_gc_new(bitmap);
1132 
1133   gdk_window_get_size(bitmap, &width, &height);
1134 
1135   if(scale_x == 1.0 && scale_y == 1.0){
1136     new_bitmap = gdk_pixmap_new(window, width, height, 1);
1137     color.pixel = 0;
1138     gdk_gc_set_foreground(gc, &color);
1139     gdk_draw_rectangle(new_bitmap, gc, TRUE, 0, 0, width, height);
1140     color.pixel = 1;
1141     gdk_gc_set_foreground(gc, &color);
1142 
1143     gdk_draw_pixmap(new_bitmap,
1144                     gc,
1145                     bitmap,
1146                     0, 0,
1147                     0, 0,
1148                     width, height);
1149     return new_bitmap;
1150   }
1151 
1152   new_width = roundint(width * scale_x);
1153   new_height = roundint(height * scale_y);
1154 
1155   /* make a client side image of the bitmap, and
1156    * scale the data into a another client side image */
1157   visual = gdk_window_get_visual (bitmap);
1158   if(!visual) return NULL;
1159   new_image = gdk_image_new(GDK_IMAGE_FASTEST,visual,new_width,new_height);
1160   if(!new_image) return NULL;
1161   new_bitmap = gdk_pixmap_new(window, new_width, new_height, 1);
1162 
1163   image = gdk_drawable_get_image(bitmap,
1164                         0, 0,
1165                         width, height);
1166 
1167   color.pixel = 0;
1168   gdk_gc_set_foreground(gc, &color);
1169   gdk_draw_rectangle(new_bitmap, gc, TRUE, 0, 0, width, height);
1170   color.pixel = 1;
1171   gdk_gc_set_foreground(gc, &color);
1172 
1173   for(x = 0; x < new_width; x++){
1174     for(y = 0; y < new_height; y++){
1175       gint px, py;
1176       gulong pixel;
1177 
1178       px = MIN(roundint(x / scale_x), width - 1);
1179       py = MIN(roundint(y / scale_y), height - 1);
1180 
1181       pixel = gdk_image_get_pixel(image, px, py);
1182       gdk_image_put_pixel(new_image, x, y, pixel);
1183     }
1184   }
1185 
1186   /* draw the image into a new pixmap */
1187   gdk_draw_image(new_bitmap,gc,new_image,0,0,0,0,new_width,new_height);
1188 
1189   gdk_image_destroy(image);
1190   gdk_image_destroy(new_image);
1191 
1192   return new_bitmap;
1193 }
1194 
1195