1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* pdfdocument.h: Implementation of EvDocument for PDF
3 * Copyright (C) 2004, Red Hat, Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "gpdf-g-switch.h"
21 #include "pdf-document.h"
22 #include "gpdf-g-switch.h"
24 #include "GlobalParams.h"
25 #include "GDKSplashOutputDev.h"
28 typedef struct _PdfDocumentClass PdfDocumentClass;
30 #define PDF_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PDF_TYPE_DOCUMENT, PdfDocumentClass))
31 #define PDF_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PDF_TYPE_DOCUMENT))
32 #define PDF_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PDF_TYPE_DOCUMENT, PdfDocumentClass))
34 struct _PdfDocumentClass
36 GObjectClass parent_class;
41 GObject parent_instance;
49 GDKSplashOutputDev *out;
55 static void pdf_document_document_iface_init (EvDocumentIface *iface);
57 G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
58 { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
59 pdf_document_document_iface_init) });
62 document_validate_page (PdfDocument *pdf_document)
64 if (!pdf_document->page_valid) {
65 pdf_document->doc->displayPage (pdf_document->out, pdf_document->page,
66 72 * pdf_document->scale,
67 72 * pdf_document->scale,
70 pdf_document->page_valid = TRUE;
75 pdf_document_load (EvDocument *document,
79 PdfDocument *pdf_document = PDF_DOCUMENT (document);
86 globalParams = new GlobalParams("/etc/xpdfrc");
87 globalParams->setupBaseFonts(NULL);
90 filename = g_filename_from_uri (uri, NULL, error);
94 filename_g = new GString (filename);
97 // open the PDF file, assumes ownership of filename_g
98 newDoc = new PDFDoc(filename_g, 0, 0);
100 if (!newDoc->isOk()) {
101 err = newDoc->getErrorCode();
104 /* FIXME: Add a real error enum to EvDocument */
105 g_set_error (error, G_FILE_ERROR,
107 "Failed to load document (error %d) '%s'\n",
114 if (pdf_document->doc)
115 delete pdf_document->doc;
116 pdf_document->doc = newDoc;
118 pdf_document->page = 1;
120 if (pdf_document->out)
121 pdf_document->out->startDoc(pdf_document->doc->getXRef());
123 pdf_document->page_valid = FALSE;
129 pdf_document_get_n_pages (EvDocument *document)
131 PdfDocument *pdf_document = PDF_DOCUMENT (document);
133 if (pdf_document->doc)
134 return pdf_document->doc->getNumPages();
140 pdf_document_set_page (EvDocument *document,
143 PdfDocument *pdf_document = PDF_DOCUMENT (document);
145 page = CLAMP (page, 1, ev_document_get_n_pages (document));
147 if (page != pdf_document->page) {
148 pdf_document->page = page;
149 pdf_document->page_valid = FALSE;
155 pdf_document_get_page (EvDocument *document)
157 PdfDocument *pdf_document = PDF_DOCUMENT (document);
159 return pdf_document->page;
163 redraw_callback (void *data)
165 /* Need to hook up through a EvDocument callback? */
169 pdf_document_set_target (EvDocument *document,
172 PdfDocument *pdf_document = PDF_DOCUMENT (document);
174 if (pdf_document->target != target) {
175 if (pdf_document->target)
176 g_object_unref (pdf_document->target);
178 pdf_document->target = target;
180 if (pdf_document->target)
181 g_object_ref (pdf_document->target);
183 if (pdf_document->out) {
184 delete pdf_document->out;
185 pdf_document->out = NULL;
188 if (pdf_document->target) {
189 pdf_document->out = new GDKSplashOutputDev (gdk_drawable_get_screen (pdf_document->target),
190 redraw_callback, (void*) document);
192 if (pdf_document->doc)
193 pdf_document->out->startDoc(pdf_document->doc->getXRef());
197 pdf_document->page_valid = FALSE;
202 pdf_document_set_scale (EvDocument *document,
205 PdfDocument *pdf_document = PDF_DOCUMENT (document);
207 if (pdf_document->scale != scale) {
208 pdf_document->scale = scale;
209 pdf_document->page_valid = FALSE;
214 pdf_document_set_page_offset (EvDocument *document,
218 PdfDocument *pdf_document = PDF_DOCUMENT (document);
220 pdf_document->page_x_offset = x;
221 pdf_document->page_y_offset = y;
225 pdf_document_get_page_size (EvDocument *document,
229 PdfDocument *pdf_document = PDF_DOCUMENT (document);
231 if (document_validate_page (pdf_document)) {
233 *width = pdf_document->out->getBitmapWidth();
235 *height = pdf_document->out->getBitmapHeight();
245 pdf_document_render (EvDocument *document,
251 PdfDocument *pdf_document = PDF_DOCUMENT (document);
255 if (!document_validate_page (pdf_document) || !pdf_document->target)
258 page.x = pdf_document->page_x_offset;
259 page.y = pdf_document->page_y_offset;
260 page.width = pdf_document->out->getBitmapWidth();
261 page.height = pdf_document->out->getBitmapHeight();
265 draw.width = clip_width;
266 draw.height = clip_height;
268 if (gdk_rectangle_intersect (&page, &draw, &draw))
269 pdf_document->out->redraw (draw.x - page.x, draw.y - page.y,
270 pdf_document->target,
272 draw.width, draw.height);
276 pdf_document_begin_find (EvDocument *document,
277 const char *search_string,
278 gboolean case_sensitive)
280 /* FIXME make this incremental (idle handler) and multi-page */
281 /* Right now it's fully synchronous plus only does the current page */
283 PdfDocument *pdf_document = PDF_DOCUMENT (document);
286 int xMin, yMin, xMax, yMax;
290 /* FIXME case_sensitive (right now XPDF
291 * code is always case insensitive for ASCII
292 * and case sensitive for all other languaages)
295 g_assert (sizeof (gunichar) == sizeof (Unicode));
296 ucs4 = g_utf8_to_ucs4_fast (search_string, -1,
299 results = g_array_new (FALSE,
301 sizeof (EvFindResult));
303 if (pdf_document->out->findText (ucs4, ucs4_len,
304 gTrue, gTrue, // startAtTop, stopAtBottom
305 gFalse, gFalse, // startAtLast, stopAtLast
306 &xMin, &yMin, &xMax, &yMax)) {
308 result.page_num = pdf_document->page;
310 result.highlight_area.x = xMin;
311 result.highlight_area.y = yMin;
312 result.highlight_area.width = xMax - xMin;
313 result.highlight_area.height = yMax - yMin;
315 g_array_append_val (results, result);
317 /* Now find further results */
319 while (pdf_document->out->findText (ucs4, ucs4_len,
322 &xMin, &yMin, &xMax, &yMax)) {
324 result.page_num = pdf_document->page;
326 result.highlight_area.x = xMin;
327 result.highlight_area.y = yMin;
328 result.highlight_area.width = xMax - xMin;
329 result.highlight_area.height = yMax - yMin;
331 g_array_append_val (results, result);
335 ev_document_found (document,
336 (EvFindResult*) results->data,
340 g_array_free (results, TRUE);
344 pdf_document_end_find (EvDocument *document)
346 PdfDocument *pdf_document = PDF_DOCUMENT (document);
348 /* FIXME this will do something once begin_find queues
349 * an incremental find
352 // this should probably be shared among EvDocument
353 // implementations somehow?
354 ev_document_found (document, NULL, 0, 1.0);
358 pdf_document_finalize (GObject *object)
360 PdfDocument *pdf_document = PDF_DOCUMENT (object);
362 if (pdf_document->target)
363 g_object_unref (pdf_document->target);
365 if (pdf_document->out)
366 delete pdf_document->out;
367 if (pdf_document->doc)
368 delete pdf_document->doc;
373 pdf_document_class_init (PdfDocumentClass *klass)
375 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
377 gobject_class->finalize = pdf_document_finalize;
381 pdf_document_document_iface_init (EvDocumentIface *iface)
383 iface->load = pdf_document_load;
384 iface->get_n_pages = pdf_document_get_n_pages;
385 iface->set_page = pdf_document_set_page;
386 iface->get_page = pdf_document_get_page;
387 iface->set_scale = pdf_document_set_scale;
388 iface->set_target = pdf_document_set_target;
389 iface->set_page_offset = pdf_document_set_page_offset;
390 iface->get_page_size = pdf_document_get_page_size;
391 iface->render = pdf_document_render;
392 iface->begin_find = pdf_document_begin_find;
393 iface->end_find = pdf_document_end_find;
397 pdf_document_init (PdfDocument *pdf_document)
399 pdf_document->page = 1;
400 pdf_document->page_x_offset = 0;
401 pdf_document->page_y_offset = 0;
402 pdf_document->scale = 1.;
404 pdf_document->page_valid = FALSE;