Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
cairo-device.c
Go to the documentation of this file.
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 xscale;
36  gdouble yscale;
37 
40 
42 
43 static void
45  DviFontChar *ch,
46  int x0,
47  int y0)
48 {
49  DviCairoDevice *cairo_device;
50  int x, y, w, h;
51  gboolean isbox;
52  DviGlyph *glyph;
53  cairo_surface_t *surface;
54 
55  cairo_device = (DviCairoDevice *) dvi->device.device_data;
56 
57  glyph = &ch->grey;
58 
59  isbox = (glyph->data == NULL ||
61  MDVI_GLYPH_ISEMPTY (glyph->data));
62 
63  x = - glyph->x + x0 + cairo_device->xmargin;
64  y = - glyph->y + y0 + cairo_device->ymargin;
65  w = glyph->w;
66  h = glyph->h;
67 
68  surface = cairo_get_target (cairo_device->cr);
69  if (x < 0 || y < 0
70  || x + w > cairo_image_surface_get_width (surface)
71  || y + h > cairo_image_surface_get_height (surface))
72  return;
73 
74  cairo_save (cairo_device->cr);
75  if (isbox) {
76  cairo_rectangle (cairo_device->cr,
77  x - cairo_device->xmargin,
78  y - cairo_device->ymargin,
79  w, h);
80  cairo_stroke (cairo_device->cr);
81  } else {
82  cairo_translate (cairo_device->cr, x, y);
83  cairo_set_source_surface (cairo_device->cr,
84  (cairo_surface_t *) glyph->data,
85  0, 0);
86  cairo_paint (cairo_device->cr);
87  }
88 
89  cairo_restore (cairo_device->cr);
90 }
91 
92 static void
94  int x,
95  int y,
96  Uint width,
97  Uint height,
98  int fill)
99 {
100  DviCairoDevice *cairo_device;
101  Ulong color;
102 
103  cairo_device = (DviCairoDevice *) dvi->device.device_data;
104 
105  color = cairo_device->fg;
106 
107  cairo_save (cairo_device->cr);
108  cairo_scale (cairo_device->cr, cairo_device->xscale, cairo_device->yscale);
109 
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) / cairo_device->xscale,
117  (y + cairo_device->ymargin) / cairo_device->yscale,
118  width / cairo_device->xscale, height / cairo_device->yscale);
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;
206  int i, n;
207  unsigned int alpha;
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 * color_fg.red;
220  color.green = frac * color_fg.green;
221  color.blue = frac * color_fg.blue;
222  alpha = frac * 0xFF;
223 
224  pixels[i] = (alpha << 24) + (color.red << 16) + (color.green << 8) + color.blue;
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_ARGB32, width, height);
237 }
238 
239 static void
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  guint32 *p;
251 
252  surface = (cairo_surface_t *) image;
253 
254  rowstride = cairo_image_surface_get_stride (surface);
255  p = (guint32*) (cairo_image_surface_get_data (surface) + y * rowstride + x * 4);
256 
257  /* per cairo docs, must flush before modifying outside of cairo */
258  cairo_surface_flush(surface);
259  *p = color;
260 }
261 
262 static void
264 {
265  cairo_surface_mark_dirty((cairo_surface_t *)ptr);
266 }
267 
268 static void
269 dvi_cairo_set_color (void *device_data, Ulong fg, Ulong bg)
270 {
271  DviCairoDevice *cairo_device = (DviCairoDevice *) device_data;
272 
273  cairo_device->fg = fg;
274  cairo_device->bg = bg;
275 }
276 
277 /* Public methods */
278 void
280 {
281  device->device_data = g_new0 (DviCairoDevice, 1);
282 
284  device->draw_rule = dvi_cairo_draw_rule;
288  device->put_pixel = dvi_cairo_put_pixel;
290  device->set_color = dvi_cairo_set_color;
291 #ifdef HAVE_SPECTRE
292  device->draw_ps = dvi_cairo_draw_ps;
293 #else
294  device->draw_ps = NULL;
295 #endif
296  device->refresh = NULL;
297 }
298 
299 void
301 {
302  DviCairoDevice *cairo_device;
303 
304  cairo_device = (DviCairoDevice *) device->device_data;
305 
306  if (cairo_device->cr)
307  cairo_destroy (cairo_device->cr);
308 
309  g_free (cairo_device);
310 }
311 
312 cairo_surface_t *
314 {
315  DviCairoDevice *cairo_device;
316 
317  cairo_device = (DviCairoDevice *) device->device_data;
318 
319  return cairo_surface_reference (cairo_get_target (cairo_device->cr));
320 }
321 
322 void
324 {
325  DviCairoDevice *cairo_device;
326  gint page_width;
327  gint page_height;
328  cairo_surface_t *surface;
329 
330  cairo_device = (DviCairoDevice *) dvi->device.device_data;
331 
332  if (cairo_device->cr)
333  cairo_destroy (cairo_device->cr);
334 
335  page_width = dvi->dvi_page_w * dvi->params.conv + 2 * cairo_device->xmargin;
336  page_height = dvi->dvi_page_h * dvi->params.vconv + 2 * cairo_device->ymargin;
337 
338  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
339  page_width, page_height);
340 
341  cairo_device->cr = cairo_create (surface);
342  cairo_surface_destroy (surface);
343 
344  cairo_set_source_rgb (cairo_device->cr, 1., 1., 1.);
345  cairo_paint (cairo_device->cr);
346 
347  mdvi_dopage (dvi, dvi->currpage);
348 }
349 
350 void
352  gint xmargin,
353  gint ymargin)
354 {
355  DviCairoDevice *cairo_device;
356 
357  cairo_device = (DviCairoDevice *) device->device_data;
358 
359  cairo_device->xmargin = xmargin;
360  cairo_device->ymargin = ymargin;
361 }
362 
363 void
365  gdouble xscale,
366  gdouble yscale)
367 {
368  DviCairoDevice *cairo_device;
369 
370  cairo_device = (DviCairoDevice *) device->device_data;
371 
372  cairo_device->xscale = xscale;
373  cairo_device->yscale = yscale;
374 }