]> www.fi.muni.cz Git - evince.git/blob - backend/dvi/cairo-device.c
New files, define a page transition effect, at the moment it maps
[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 <gdk/gdkcolor.h>
22 #ifdef HAVE_SPECTRE
23 #include <libspectre/spectre.h>
24 #endif
25
26 #include "cairo-device.h"
27
28 typedef struct {
29         cairo_t *cr;
30
31         gint xmargin;
32         gint ymargin;
33
34         gdouble scale;
35         
36         Ulong fg;
37         Ulong bg;
38
39 } DviCairoDevice;
40
41 static void
42 dvi_cairo_draw_glyph (DviContext  *dvi,
43                       DviFontChar *ch,
44                       int          x0,
45                       int          y0)
46 {
47         DviCairoDevice  *cairo_device;
48         int              x, y, w, h;
49         gboolean         isbox;
50         DviGlyph        *glyph;
51         cairo_surface_t *surface;
52
53         cairo_device = (DviCairoDevice *) dvi->device.device_data;
54
55         glyph = &ch->grey;
56
57         isbox = (glyph->data == NULL || (dvi->params.flags & MDVI_PARAM_CHARBOXES));
58
59         x = - glyph->x + x0 + cairo_device->xmargin;
60         y = - glyph->y + y0 + cairo_device->ymargin;
61         w = glyph->w;
62         h = glyph->h;
63
64         surface = cairo_get_target (cairo_device->cr);
65         if (x < 0 || y < 0
66             || x + w > cairo_image_surface_get_width (surface)
67             || y + h > cairo_image_surface_get_height (surface))
68                 return;
69
70         cairo_save (cairo_device->cr);
71         if (isbox) {
72                 cairo_rectangle (cairo_device->cr,
73                                  x - cairo_device->xmargin,
74                                  y - cairo_device->ymargin,
75                                  w, h);
76                 cairo_stroke (cairo_device->cr);
77         } else {
78                 cairo_translate (cairo_device->cr, x, y);
79                 cairo_set_source_surface (cairo_device->cr,
80                                           (cairo_surface_t *) glyph->data,
81                                           0, 0);
82                 cairo_paint (cairo_device->cr);
83         }
84
85         cairo_restore (cairo_device->cr);
86 }
87
88 static void
89 dvi_cairo_draw_rule (DviContext *dvi,
90                      int         x,
91                      int         y,
92                      Uint        width,
93                      Uint        height,
94                      int         fill)
95 {
96         DviCairoDevice *cairo_device;
97         Ulong           color;
98
99         cairo_device = (DviCairoDevice *) dvi->device.device_data;
100
101         color = cairo_device->fg;
102         
103         cairo_save (cairo_device->cr);
104
105         cairo_set_line_width (cairo_device->cr,
106                               cairo_get_line_width (cairo_device->cr) * cairo_device->scale);
107         cairo_set_source_rgb (cairo_device->cr,
108                               ((color >> 16) & 0xff) / 255.,
109                               ((color >> 8) & 0xff) / 255.,
110                               ((color >> 0) & 0xff) / 255.);
111
112         cairo_rectangle (cairo_device->cr,
113                          x + cairo_device->xmargin,
114                          y + cairo_device->ymargin,
115                          width, height);
116         if (fill == 0) {
117                 cairo_stroke (cairo_device->cr);
118         } else {
119                 cairo_fill (cairo_device->cr);
120         }
121
122         cairo_restore (cairo_device->cr);
123 }
124
125 #ifdef HAVE_SPECTRE
126 static void
127 dvi_cairo_draw_ps (DviContext *dvi,
128                    const char *filename,
129                    int         x,
130                    int         y,
131                    Uint        width,
132                    Uint        height)
133 {
134         DviCairoDevice       *cairo_device;
135         unsigned char        *data = NULL;
136         int                   row_length;
137         SpectreDocument      *psdoc;
138         SpectrePage          *page;
139         SpectreRenderContext *rc;
140         SpectreStatus         status;
141         cairo_surface_t      *image;
142
143         cairo_device = (DviCairoDevice *) dvi->device.device_data;
144
145         psdoc = spectre_document_new ();
146         spectre_document_load (psdoc, filename);
147         if (spectre_document_status (psdoc)) {
148                 spectre_document_free (psdoc);
149                 return;
150         }
151         
152         page = spectre_document_get_page (psdoc, 0);
153         if (!page) {
154                 spectre_document_free (psdoc);
155                 return;
156         }
157
158         rc = spectre_render_context_new ();
159         spectre_render_context_set_page_size (rc, width, height);
160         spectre_page_render (page, rc, &data, &row_length);
161         status = spectre_page_status (page);
162         spectre_render_context_free (rc);
163
164         spectre_page_free (page);
165         spectre_document_free (psdoc);
166
167         if (status) {
168                 free (data);
169                 return;
170         }
171
172         image = cairo_image_surface_create_for_data ((unsigned char *)data,
173                                                      CAIRO_FORMAT_RGB24,
174                                                      width, height,
175                                                      row_length);
176
177         cairo_save (cairo_device->cr);
178
179         cairo_translate (cairo_device->cr,
180                          x + cairo_device->xmargin,
181                          y + cairo_device->ymargin);
182         cairo_set_source_surface (cairo_device->cr, image, 0, 0); 
183         cairo_paint (cairo_device->cr);
184
185         cairo_restore (cairo_device->cr);
186
187         cairo_surface_destroy (image);
188         free (data);
189 }
190 #endif /* HAVE_SPECTRE */
191
192 static int
193 dvi_cairo_alloc_colors (void  *device_data,
194                         Ulong *pixels,
195                         int    npixels,
196                         Ulong  fg,
197                         Ulong  bg,
198                         double gamma,
199                         int    density)
200 {
201         double  frac;
202         GdkColor color, color_fg, color_bg;
203         int     i, n;
204
205         color_bg.red = (bg >> 16) & 0xff;
206         color_bg.green = (bg >> 8) & 0xff;
207         color_bg.blue = (bg >> 0) & 0xff;
208
209         color_fg.red = (fg >> 16) & 0xff;
210         color_fg.green = (fg >> 8) & 0xff;
211         color_fg.blue = (fg >> 0) & 0xff;
212
213         n = npixels - 1;
214         for (i = 0; i < npixels; i++) {
215                 frac = (gamma > 0) ?
216                         pow ((double)i / n, 1 / gamma) :
217                         1 - pow ((double)(n - i) / n, -gamma);
218                 
219                 color.red = frac * ((double)color_fg.red - color_bg.red) + color_bg.red;
220                 color.green = frac * ((double)color_fg.green - color_bg.green) + color_bg.green;
221                 color.blue = frac * ((double)color_fg.blue - color_bg.blue) + color_bg.blue;
222                 
223                 pixels[i] = (color.red << 16) + (color.green << 8) + color.blue + 0xff000000;
224         }
225
226         return npixels;
227 }
228
229 static void *
230 dvi_cairo_create_image (void *device_data,
231                         Uint  width,
232                         Uint  height,
233                         Uint  bpp)
234 {
235         return cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
236 }
237
238 static void
239 dvi_cairo_free_image (void *ptr)
240 {
241         cairo_surface_destroy ((cairo_surface_t *)ptr);
242 }
243
244 static void
245 dvi_cairo_put_pixel (void *image, int x, int y, Ulong color)
246 {
247         cairo_t         *cr;
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         gchar           *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 = (gchar *) 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 }