]> www.fi.muni.cz Git - evince.git/blob - backend/dvi/cairo-device.c
[dvi] Test glyph->data for MDVI_GLYPH_EMPTY
[evince.git] / backend / dvi / cairo-device.c
1 /*
2  * Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdlib.h>
22 #include <gdk/gdk.h>
23 #ifdef HAVE_SPECTRE
24 #include <libspectre/spectre.h>
25 #endif
26
27 #include "cairo-device.h"
28
29 typedef struct {
30         cairo_t *cr;
31
32         gint xmargin;
33         gint ymargin;
34
35         gdouble scale;
36         
37         Ulong fg;
38         Ulong bg;
39
40 } DviCairoDevice;
41
42 static void
43 dvi_cairo_draw_glyph (DviContext  *dvi,
44                       DviFontChar *ch,
45                       int          x0,
46                       int          y0)
47 {
48         DviCairoDevice  *cairo_device;
49         int              x, y, w, h;
50         gboolean         isbox;
51         DviGlyph        *glyph;
52         cairo_surface_t *surface;
53
54         cairo_device = (DviCairoDevice *) dvi->device.device_data;
55
56         glyph = &ch->grey;
57
58         isbox = (glyph->data == NULL ||
59                  (dvi->params.flags & MDVI_PARAM_CHARBOXES) ||
60                  MDVI_GLYPH_ISEMPTY (glyph->data));
61
62         x = - glyph->x + x0 + cairo_device->xmargin;
63         y = - glyph->y + y0 + cairo_device->ymargin;
64         w = glyph->w;
65         h = glyph->h;
66
67         surface = cairo_get_target (cairo_device->cr);
68         if (x < 0 || y < 0
69             || x + w > cairo_image_surface_get_width (surface)
70             || y + h > cairo_image_surface_get_height (surface))
71                 return;
72
73         cairo_save (cairo_device->cr);
74         if (isbox) {
75                 cairo_rectangle (cairo_device->cr,
76                                  x - cairo_device->xmargin,
77                                  y - cairo_device->ymargin,
78                                  w, h);
79                 cairo_stroke (cairo_device->cr);
80         } else {
81                 cairo_translate (cairo_device->cr, x, y);
82                 cairo_set_source_surface (cairo_device->cr,
83                                           (cairo_surface_t *) glyph->data,
84                                           0, 0);
85                 cairo_paint (cairo_device->cr);
86         }
87
88         cairo_restore (cairo_device->cr);
89 }
90
91 static void
92 dvi_cairo_draw_rule (DviContext *dvi,
93                      int         x,
94                      int         y,
95                      Uint        width,
96                      Uint        height,
97                      int         fill)
98 {
99         DviCairoDevice *cairo_device;
100         Ulong           color;
101
102         cairo_device = (DviCairoDevice *) dvi->device.device_data;
103
104         color = cairo_device->fg;
105         
106         cairo_save (cairo_device->cr);
107
108         cairo_set_line_width (cairo_device->cr,
109                               cairo_get_line_width (cairo_device->cr) * cairo_device->scale);
110         cairo_set_source_rgb (cairo_device->cr,
111                               ((color >> 16) & 0xff) / 255.,
112                               ((color >> 8) & 0xff) / 255.,
113                               ((color >> 0) & 0xff) / 255.);
114
115         cairo_rectangle (cairo_device->cr,
116                          x + cairo_device->xmargin,
117                          y + cairo_device->ymargin,
118                          width, height);
119         if (fill == 0) {
120                 cairo_stroke (cairo_device->cr);
121         } else {
122                 cairo_fill (cairo_device->cr);
123         }
124
125         cairo_restore (cairo_device->cr);
126 }
127
128 #ifdef HAVE_SPECTRE
129 static void
130 dvi_cairo_draw_ps (DviContext *dvi,
131                    const char *filename,
132                    int         x,
133                    int         y,
134                    Uint        width,
135                    Uint        height)
136 {
137         DviCairoDevice       *cairo_device;
138         unsigned char        *data = NULL;
139         int                   row_length;
140         SpectreDocument      *psdoc;
141         SpectreRenderContext *rc;
142         int                   w, h;
143         SpectreStatus         status;
144         cairo_surface_t      *image;
145
146         cairo_device = (DviCairoDevice *) dvi->device.device_data;
147
148         psdoc = spectre_document_new ();
149         spectre_document_load (psdoc, filename);
150         if (spectre_document_status (psdoc)) {
151                 spectre_document_free (psdoc);
152                 return;
153         }
154
155         spectre_document_get_page_size (psdoc, &w, &h);
156
157         rc = spectre_render_context_new ();
158         spectre_render_context_set_scale (rc,
159                                           (double)width / w,
160                                           (double)height / h);
161         spectre_document_render_full (psdoc, rc, &data, &row_length);   
162         status = spectre_document_status (psdoc);
163
164         spectre_render_context_free (rc);
165         spectre_document_free (psdoc);
166
167         if (status) {
168                 g_warning ("Error rendering PS document %s: %s\n",
169                            filename, spectre_status_to_string (status));
170                 free (data);
171                 
172                 return;
173         }
174
175         image = cairo_image_surface_create_for_data ((unsigned char *)data,
176                                                      CAIRO_FORMAT_RGB24,
177                                                      width, height,
178                                                      row_length);
179
180         cairo_save (cairo_device->cr);
181
182         cairo_translate (cairo_device->cr,
183                          x + cairo_device->xmargin,
184                          y + cairo_device->ymargin);
185         cairo_set_source_surface (cairo_device->cr, image, 0, 0); 
186         cairo_paint (cairo_device->cr);
187
188         cairo_restore (cairo_device->cr);
189
190         cairo_surface_destroy (image);
191         free (data);
192 }
193 #endif /* HAVE_SPECTRE */
194
195 static int
196 dvi_cairo_alloc_colors (void  *device_data,
197                         Ulong *pixels,
198                         int    npixels,
199                         Ulong  fg,
200                         Ulong  bg,
201                         double gamma,
202                         int    density)
203 {
204         double  frac;
205         GdkColor color, color_fg, color_bg;
206         int     i, n;
207
208         color_bg.red = (bg >> 16) & 0xff;
209         color_bg.green = (bg >> 8) & 0xff;
210         color_bg.blue = (bg >> 0) & 0xff;
211
212         color_fg.red = (fg >> 16) & 0xff;
213         color_fg.green = (fg >> 8) & 0xff;
214         color_fg.blue = (fg >> 0) & 0xff;
215
216         n = npixels - 1;
217         for (i = 0; i < npixels; i++) {
218                 frac = (gamma > 0) ?
219                         pow ((double)i / n, 1 / gamma) :
220                         1 - pow ((double)(n - i) / n, -gamma);
221                 
222                 color.red = frac * ((double)color_fg.red - color_bg.red) + color_bg.red;
223                 color.green = frac * ((double)color_fg.green - color_bg.green) + color_bg.green;
224                 color.blue = frac * ((double)color_fg.blue - color_bg.blue) + color_bg.blue;
225                 
226                 pixels[i] = (color.red << 16) + (color.green << 8) + color.blue + 0xff000000;
227         }
228
229         return npixels;
230 }
231
232 static void *
233 dvi_cairo_create_image (void *device_data,
234                         Uint  width,
235                         Uint  height,
236                         Uint  bpp)
237 {
238         return cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
239 }
240
241 static void
242 dvi_cairo_free_image (void *ptr)
243 {
244         cairo_surface_destroy ((cairo_surface_t *)ptr);
245 }
246
247 static void
248 dvi_cairo_put_pixel (void *image, int x, int y, Ulong color)
249 {
250         cairo_surface_t *surface;
251         gint             rowstride;
252         guint32         *p;
253
254         surface = (cairo_surface_t *) image;
255
256         rowstride = cairo_image_surface_get_stride (surface);
257         p = (guint32*) (cairo_image_surface_get_data (surface) + y * rowstride + x * 4);
258
259         *p = color;
260 }
261
262 static void
263 dvi_cairo_set_color (void *device_data, Ulong fg, Ulong bg)
264 {
265         DviCairoDevice *cairo_device = (DviCairoDevice *) device_data;
266
267         cairo_device->fg = fg;
268         cairo_device->bg = bg;
269 }
270
271 /* Public methods */
272 void
273 mdvi_cairo_device_init (DviDevice *device)
274 {
275         device->device_data = g_new0 (DviCairoDevice, 1);
276
277         device->draw_glyph = dvi_cairo_draw_glyph;
278         device->draw_rule = dvi_cairo_draw_rule;
279         device->alloc_colors = dvi_cairo_alloc_colors;
280         device->create_image = dvi_cairo_create_image;
281         device->free_image = dvi_cairo_free_image;
282         device->put_pixel = dvi_cairo_put_pixel;
283         device->set_color = dvi_cairo_set_color;
284 #ifdef HAVE_SPECTRE
285         device->draw_ps = dvi_cairo_draw_ps;
286 #else
287         device->draw_ps = NULL;
288 #endif
289         device->refresh = NULL;
290 }
291
292 void
293 mdvi_cairo_device_free (DviDevice *device)
294 {
295         DviCairoDevice *cairo_device;
296
297         cairo_device = (DviCairoDevice *) device->device_data;
298
299         if (cairo_device->cr)
300                 cairo_destroy (cairo_device->cr);
301
302         g_free (cairo_device);
303 }
304
305 cairo_surface_t *
306 mdvi_cairo_device_get_surface (DviDevice *device)
307 {
308         DviCairoDevice *cairo_device;
309
310         cairo_device = (DviCairoDevice *) device->device_data;
311
312         return cairo_surface_reference (cairo_get_target (cairo_device->cr));
313 }
314
315 void
316 mdvi_cairo_device_render (DviContext* dvi)
317 {
318         DviCairoDevice  *cairo_device;
319         gint             page_width;
320         gint             page_height;
321         cairo_surface_t *surface;
322         guchar          *pixels;
323         gint             rowstride;
324         static const cairo_user_data_key_t key;
325
326         cairo_device = (DviCairoDevice *) dvi->device.device_data;
327
328         if (cairo_device->cr)
329                 cairo_destroy (cairo_device->cr);
330
331         page_width = dvi->dvi_page_w * dvi->params.conv + 2 * cairo_device->xmargin;
332         page_height = dvi->dvi_page_h * dvi->params.vconv + 2 * cairo_device->ymargin;
333
334         rowstride = page_width * 4;
335         pixels = (guchar *) g_malloc (page_height * rowstride);
336         memset (pixels, 0xff, page_height * rowstride);
337
338         surface = cairo_image_surface_create_for_data (pixels,
339                                                        CAIRO_FORMAT_RGB24,
340                                                        page_width, page_height,
341                                                        rowstride);
342         cairo_surface_set_user_data (surface, &key,
343                                      pixels, (cairo_destroy_func_t)g_free);
344
345         cairo_device->cr = cairo_create (surface);
346         cairo_surface_destroy (surface);
347
348         mdvi_dopage (dvi, dvi->currpage);
349 }
350
351 void
352 mdvi_cairo_device_set_margins (DviDevice *device,
353                                gint       xmargin,
354                                gint       ymargin)
355 {
356         DviCairoDevice *cairo_device;
357
358         cairo_device = (DviCairoDevice *) device->device_data;
359
360         cairo_device->xmargin = xmargin;
361         cairo_device->ymargin = ymargin;
362 }
363
364 void
365 mdvi_cairo_device_set_scale (DviDevice *device,
366                              gdouble    scale)
367 {
368         DviCairoDevice *cairo_device;
369
370         cairo_device = (DviCairoDevice *) device->device_data;
371
372         cairo_device->scale = scale;
373 }