]> www.fi.muni.cz Git - evince.git/blob - backend/dvi/cairo-device.c
Use capabilities to know which options should be offered by the print
[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 <gdk/gdkcolor.h>
20 #include "cairo-device.h"
21
22 typedef struct {
23         cairo_t *cr;
24
25         gint xmargin;
26         gint ymargin;
27
28         gdouble scale;
29         
30         Ulong fg;
31         Ulong bg;
32
33 } DviCairoDevice;
34
35 static void
36 dvi_cairo_draw_glyph (DviContext  *dvi,
37                       DviFontChar *ch,
38                       int          x0,
39                       int          y0)
40 {
41         DviCairoDevice  *cairo_device;
42         int              x, y, w, h;
43         gboolean         isbox;
44         DviGlyph        *glyph;
45         cairo_surface_t *surface;
46
47         cairo_device = (DviCairoDevice *) dvi->device.device_data;
48
49         glyph = &ch->grey;
50
51         isbox = (glyph->data == NULL || (dvi->params.flags & MDVI_PARAM_CHARBOXES));
52
53         x = - glyph->x + x0 + cairo_device->xmargin;
54         y = - glyph->y + y0 + cairo_device->ymargin;
55         w = glyph->w;
56         h = glyph->h;
57
58         surface = cairo_get_target (cairo_device->cr);
59         if (x < 0 || y < 0
60             || x + w > cairo_image_surface_get_width (surface)
61             || y + h > cairo_image_surface_get_height (surface))
62                 return;
63
64         cairo_save (cairo_device->cr);
65         if (isbox) {
66                 cairo_rectangle (cairo_device->cr,
67                                  x - cairo_device->xmargin,
68                                  y - cairo_device->ymargin,
69                                  w, h);
70                 cairo_stroke (cairo_device->cr);
71         } else {
72                 cairo_translate (cairo_device->cr, x, y);
73                 cairo_set_source_surface (cairo_device->cr,
74                                           (cairo_surface_t *) glyph->data,
75                                           0, 0);
76                 cairo_paint (cairo_device->cr);
77         }
78
79         cairo_restore (cairo_device->cr);
80 }
81
82 static void
83 dvi_cairo_draw_rule (DviContext *dvi,
84                      int         x,
85                      int         y,
86                      Uint        width,
87                      Uint        height,
88                      int         fill)
89 {
90         DviCairoDevice *cairo_device;
91         Ulong           color;
92
93         cairo_device = (DviCairoDevice *) dvi->device.device_data;
94
95         color = cairo_device->fg;
96         
97         cairo_save (cairo_device->cr);
98
99         cairo_set_line_width (cairo_device->cr,
100                               cairo_get_line_width (cairo_device->cr) * cairo_device->scale);
101         cairo_set_source_rgb (cairo_device->cr,
102                               ((color >> 16) & 0xff) / 255.,
103                               ((color >> 8) & 0xff) / 255.,
104                               ((color >> 0) & 0xff) / 255.);
105
106         cairo_rectangle (cairo_device->cr,
107                          x + cairo_device->xmargin,
108                          y + cairo_device->ymargin,
109                          width, height);
110         if (fill == 0) {
111                 cairo_stroke (cairo_device->cr);
112         } else {
113                 cairo_fill (cairo_device->cr);
114         }
115
116         cairo_restore (cairo_device->cr);
117 }
118
119 static int
120 dvi_cairo_alloc_colors (void  *device_data,
121                         Ulong *pixels,
122                         int    npixels,
123                         Ulong  fg,
124                         Ulong  bg,
125                         double gamma,
126                         int    density)
127 {
128         double  frac;
129         GdkColor color, color_fg, color_bg;
130         int     i, n;
131
132         color_bg.red = (bg >> 16) & 0xff;
133         color_bg.green = (bg >> 8) & 0xff;
134         color_bg.blue = (bg >> 0) & 0xff;
135
136         color_fg.red = (fg >> 16) & 0xff;
137         color_fg.green = (fg >> 8) & 0xff;
138         color_fg.blue = (fg >> 0) & 0xff;
139
140         n = npixels - 1;
141         for (i = 0; i < npixels; i++) {
142                 frac = (gamma > 0) ?
143                         pow ((double)i / n, 1 / gamma) :
144                         1 - pow ((double)(n - i) / n, -gamma);
145                 
146                 color.red = frac * ((double)color_fg.red - color_bg.red) + color_bg.red;
147                 color.green = frac * ((double)color_fg.green - color_bg.green) + color_bg.green;
148                 color.blue = frac * ((double)color_fg.blue - color_bg.blue) + color_bg.blue;
149                 
150                 pixels[i] = (color.red << 16) + (color.green << 8) + color.blue + 0xff000000;
151         }
152
153         return npixels;
154 }
155
156 static void *
157 dvi_cairo_create_image (void *device_data,
158                         Uint  width,
159                         Uint  height,
160                         Uint  bpp)
161 {
162         return cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
163 }
164
165 static void
166 dvi_cairo_free_image (void *ptr)
167 {
168         cairo_surface_destroy ((cairo_surface_t *)ptr);
169 }
170
171 static void
172 dvi_cairo_put_pixel (void *image, int x, int y, Ulong color)
173 {
174         cairo_t         *cr;
175         cairo_surface_t *surface;
176         gint             rowstride;
177         guchar          *p;
178
179         surface = (cairo_surface_t *) image;
180
181         rowstride = cairo_image_surface_get_stride (surface);
182         p = cairo_image_surface_get_data (surface) + y * rowstride + x * 4;
183
184         p[2] = (color >> 16) & 0xff;
185         p[1] = (color >> 8) & 0xff;
186         p[0] = (color >> 0) & 0xff;
187 }
188
189 static void
190 dvi_cairo_set_color (void *device_data, Ulong fg, Ulong bg)
191 {
192         DviCairoDevice *cairo_device = (DviCairoDevice *) device_data;
193
194         cairo_device->fg = fg;
195         cairo_device->bg = bg;
196 }
197
198 /* Public methods */
199 void
200 mdvi_cairo_device_init (DviDevice *device)
201 {
202         device->device_data = g_new0 (DviCairoDevice, 1);
203
204         device->draw_glyph = dvi_cairo_draw_glyph;
205         device->draw_rule = dvi_cairo_draw_rule;
206         device->alloc_colors = dvi_cairo_alloc_colors;
207         device->create_image = dvi_cairo_create_image;
208         device->free_image = dvi_cairo_free_image;
209         device->put_pixel = dvi_cairo_put_pixel;
210         device->set_color = dvi_cairo_set_color;
211         device->refresh = NULL;
212 }
213
214 void
215 mdvi_cairo_device_free (DviDevice *device)
216 {
217         DviCairoDevice *cairo_device;
218
219         cairo_device = (DviCairoDevice *) device->device_data;
220
221         if (cairo_device->cr)
222                 cairo_destroy (cairo_device->cr);
223
224         g_free (cairo_device);
225 }
226
227 cairo_surface_t *
228 mdvi_cairo_device_get_surface (DviDevice *device)
229 {
230         DviCairoDevice *cairo_device;
231
232         cairo_device = (DviCairoDevice *) device->device_data;
233
234         return cairo_surface_reference (cairo_get_target (cairo_device->cr));
235 }
236
237 void
238 mdvi_cairo_device_render (DviContext* dvi)
239 {
240         DviCairoDevice  *cairo_device;
241         gint             page_width;
242         gint             page_height;
243         cairo_surface_t *surface;
244         gchar           *pixels;
245         gint             rowstride;
246         static const cairo_user_data_key_t key;
247
248         cairo_device = (DviCairoDevice *) dvi->device.device_data;
249
250         if (cairo_device->cr)
251                 cairo_destroy (cairo_device->cr);
252
253         page_width = dvi->dvi_page_w * dvi->params.conv + 2 * cairo_device->xmargin;
254         page_height = dvi->dvi_page_h * dvi->params.vconv + 2 * cairo_device->ymargin;
255
256         rowstride = page_width * 4;
257         pixels = (gchar *) g_malloc (page_height * rowstride);
258         memset (pixels, 0xff, page_height * rowstride);
259
260         surface = cairo_image_surface_create_for_data (pixels,
261                                                        CAIRO_FORMAT_RGB24,
262                                                        page_width, page_height,
263                                                        rowstride);
264         cairo_surface_set_user_data (surface, &key,
265                                      pixels, (cairo_destroy_func_t)g_free);
266
267         cairo_device->cr = cairo_create (surface);
268         cairo_surface_destroy (surface);
269
270         mdvi_dopage (dvi, dvi->currpage);
271 }
272
273 void
274 mdvi_cairo_device_set_margins (DviDevice *device,
275                                gint       xmargin,
276                                gint       ymargin)
277 {
278         DviCairoDevice *cairo_device;
279
280         cairo_device = (DviCairoDevice *) device->device_data;
281
282         cairo_device->xmargin = xmargin;
283         cairo_device->ymargin = ymargin;
284 }
285
286 void
287 mdvi_cairo_device_set_scale (DviDevice *device,
288                              gdouble    scale)
289 {
290         DviCairoDevice *cairo_device;
291
292         cairo_device = (DviCairoDevice *) device->device_data;
293
294         cairo_device->scale = scale;
295 }