]> www.fi.muni.cz Git - evince.git/blob - backend/dvi/cairo-device.c
Bug 558064 – build with single includes
[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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 || (dvi->params.flags & MDVI_PARAM_CHARBOXES));
59
60         x = - glyph->x + x0 + cairo_device->xmargin;
61         y = - glyph->y + y0 + cairo_device->ymargin;
62         w = glyph->w;
63         h = glyph->h;
64
65         surface = cairo_get_target (cairo_device->cr);
66         if (x < 0 || y < 0
67             || x + w > cairo_image_surface_get_width (surface)
68             || y + h > cairo_image_surface_get_height (surface))
69                 return;
70
71         cairo_save (cairo_device->cr);
72         if (isbox) {
73                 cairo_rectangle (cairo_device->cr,
74                                  x - cairo_device->xmargin,
75                                  y - cairo_device->ymargin,
76                                  w, h);
77                 cairo_stroke (cairo_device->cr);
78         } else {
79                 cairo_translate (cairo_device->cr, x, y);
80                 cairo_set_source_surface (cairo_device->cr,
81                                           (cairo_surface_t *) glyph->data,
82                                           0, 0);
83                 cairo_paint (cairo_device->cr);
84         }
85
86         cairo_restore (cairo_device->cr);
87 }
88
89 static void
90 dvi_cairo_draw_rule (DviContext *dvi,
91                      int         x,
92                      int         y,
93                      Uint        width,
94                      Uint        height,
95                      int         fill)
96 {
97         DviCairoDevice *cairo_device;
98         Ulong           color;
99
100         cairo_device = (DviCairoDevice *) dvi->device.device_data;
101
102         color = cairo_device->fg;
103         
104         cairo_save (cairo_device->cr);
105
106         cairo_set_line_width (cairo_device->cr,
107                               cairo_get_line_width (cairo_device->cr) * cairo_device->scale);
108         cairo_set_source_rgb (cairo_device->cr,
109                               ((color >> 16) & 0xff) / 255.,
110                               ((color >> 8) & 0xff) / 255.,
111                               ((color >> 0) & 0xff) / 255.);
112
113         cairo_rectangle (cairo_device->cr,
114                          x + cairo_device->xmargin,
115                          y + cairo_device->ymargin,
116                          width, height);
117         if (fill == 0) {
118                 cairo_stroke (cairo_device->cr);
119         } else {
120                 cairo_fill (cairo_device->cr);
121         }
122
123         cairo_restore (cairo_device->cr);
124 }
125
126 #ifdef HAVE_SPECTRE
127 static void
128 dvi_cairo_draw_ps (DviContext *dvi,
129                    const char *filename,
130                    int         x,
131                    int         y,
132                    Uint        width,
133                    Uint        height)
134 {
135         DviCairoDevice       *cairo_device;
136         unsigned char        *data = NULL;
137         int                   row_length;
138         SpectreDocument      *psdoc;
139         SpectreRenderContext *rc;
140         int                   w, h;
141         SpectreStatus         status;
142         cairo_surface_t      *image;
143
144         cairo_device = (DviCairoDevice *) dvi->device.device_data;
145
146         psdoc = spectre_document_new ();
147         spectre_document_load (psdoc, filename);
148         if (spectre_document_status (psdoc)) {
149                 spectre_document_free (psdoc);
150                 return;
151         }
152
153         spectre_document_get_page_size (psdoc, &w, &h);
154
155         rc = spectre_render_context_new ();
156         spectre_render_context_set_scale (rc,
157                                           (double)width / w,
158                                           (double)height / h);
159         spectre_document_render_full (psdoc, rc, &data, &row_length);   
160         status = spectre_document_status (psdoc);
161
162         spectre_render_context_free (rc);
163         spectre_document_free (psdoc);
164
165         if (status) {
166                 g_warning ("Error rendering PS document %s: %s\n",
167                            filename, spectre_status_to_string (status));
168                 free (data);
169                 
170                 return;
171         }
172
173         image = cairo_image_surface_create_for_data ((unsigned char *)data,
174                                                      CAIRO_FORMAT_RGB24,
175                                                      width, height,
176                                                      row_length);
177
178         cairo_save (cairo_device->cr);
179
180         cairo_translate (cairo_device->cr,
181                          x + cairo_device->xmargin,
182                          y + cairo_device->ymargin);
183         cairo_set_source_surface (cairo_device->cr, image, 0, 0); 
184         cairo_paint (cairo_device->cr);
185
186         cairo_restore (cairo_device->cr);
187
188         cairo_surface_destroy (image);
189         free (data);
190 }
191 #endif /* HAVE_SPECTRE */
192
193 static int
194 dvi_cairo_alloc_colors (void  *device_data,
195                         Ulong *pixels,
196                         int    npixels,
197                         Ulong  fg,
198                         Ulong  bg,
199                         double gamma,
200                         int    density)
201 {
202         double  frac;
203         GdkColor color, color_fg, color_bg;
204         int     i, n;
205
206         color_bg.red = (bg >> 16) & 0xff;
207         color_bg.green = (bg >> 8) & 0xff;
208         color_bg.blue = (bg >> 0) & 0xff;
209
210         color_fg.red = (fg >> 16) & 0xff;
211         color_fg.green = (fg >> 8) & 0xff;
212         color_fg.blue = (fg >> 0) & 0xff;
213
214         n = npixels - 1;
215         for (i = 0; i < npixels; i++) {
216                 frac = (gamma > 0) ?
217                         pow ((double)i / n, 1 / gamma) :
218                         1 - pow ((double)(n - i) / n, -gamma);
219                 
220                 color.red = frac * ((double)color_fg.red - color_bg.red) + color_bg.red;
221                 color.green = frac * ((double)color_fg.green - color_bg.green) + color_bg.green;
222                 color.blue = frac * ((double)color_fg.blue - color_bg.blue) + color_bg.blue;
223                 
224                 pixels[i] = (color.red << 16) + (color.green << 8) + color.blue + 0xff000000;
225         }
226
227         return npixels;
228 }
229
230 static void *
231 dvi_cairo_create_image (void *device_data,
232                         Uint  width,
233                         Uint  height,
234                         Uint  bpp)
235 {
236         return cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
237 }
238
239 static void
240 dvi_cairo_free_image (void *ptr)
241 {
242         cairo_surface_destroy ((cairo_surface_t *)ptr);
243 }
244
245 static void
246 dvi_cairo_put_pixel (void *image, int x, int y, Ulong color)
247 {
248         cairo_surface_t *surface;
249         gint             rowstride;
250         guchar          *p;
251
252         surface = (cairo_surface_t *) image;
253
254         rowstride = cairo_image_surface_get_stride (surface);
255         p = cairo_image_surface_get_data (surface) + y * rowstride + x * 4;
256
257         p[2] = (color >> 16) & 0xff;
258         p[1] = (color >> 8) & 0xff;
259         p[0] = (color >> 0) & 0xff;
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 }