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 "ev-ps-exporter.h"
23 #include "gpdf-g-switch.h"
25 #include "GlobalParams.h"
26 #include "GDKSplashOutputDev.h"
28 #include "PSOutputDev.h"
30 typedef struct _PdfDocumentClass PdfDocumentClass;
32 #define PDF_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PDF_TYPE_DOCUMENT, PdfDocumentClass))
33 #define PDF_IS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PDF_TYPE_DOCUMENT))
34 #define PDF_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PDF_TYPE_DOCUMENT, PdfDocumentClass))
36 struct _PdfDocumentClass
38 GObjectClass parent_class;
43 GObject parent_instance;
51 GDKSplashOutputDev *out;
58 static void pdf_document_document_iface_init (EvDocumentIface *iface);
59 static void pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface);
61 G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
63 G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
64 pdf_document_document_iface_init);
65 G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER,
66 pdf_document_ps_exporter_iface_init);
70 document_validate_page (PdfDocument *pdf_document)
72 if (!pdf_document->page_valid) {
73 pdf_document->doc->displayPage (pdf_document->out, pdf_document->page,
74 72 * pdf_document->scale,
75 72 * pdf_document->scale,
78 pdf_document->page_valid = TRUE;
83 pdf_document_load (EvDocument *document,
87 PdfDocument *pdf_document = PDF_DOCUMENT (document);
94 globalParams = new GlobalParams("/etc/xpdfrc");
95 globalParams->setupBaseFontsFc(NULL);
98 filename = g_filename_from_uri (uri, NULL, error);
102 filename_g = new GString (filename);
105 // open the PDF file, assumes ownership of filename_g
106 newDoc = new PDFDoc(filename_g, 0, 0);
108 if (!newDoc->isOk()) {
109 err = newDoc->getErrorCode();
112 /* FIXME: Add a real error enum to EvDocument */
113 g_set_error (error, G_FILE_ERROR,
115 "Failed to load document (error %d) '%s'\n",
122 if (pdf_document->doc)
123 delete pdf_document->doc;
124 pdf_document->doc = newDoc;
126 pdf_document->page = 1;
128 if (pdf_document->out)
129 pdf_document->out->startDoc(pdf_document->doc->getXRef());
131 pdf_document->page_valid = FALSE;
137 pdf_document_get_n_pages (EvDocument *document)
139 PdfDocument *pdf_document = PDF_DOCUMENT (document);
141 if (pdf_document->doc)
142 return pdf_document->doc->getNumPages();
148 pdf_document_set_page (EvDocument *document,
151 PdfDocument *pdf_document = PDF_DOCUMENT (document);
153 page = CLAMP (page, 1, ev_document_get_n_pages (document));
155 if (page != pdf_document->page) {
156 pdf_document->page = page;
157 pdf_document->page_valid = FALSE;
163 pdf_document_get_page (EvDocument *document)
165 PdfDocument *pdf_document = PDF_DOCUMENT (document);
167 return pdf_document->page;
171 redraw_callback (void *data)
173 /* Need to hook up through a EvDocument callback? */
177 pdf_document_set_target (EvDocument *document,
180 PdfDocument *pdf_document = PDF_DOCUMENT (document);
182 if (pdf_document->target != target) {
183 if (pdf_document->target)
184 g_object_unref (pdf_document->target);
186 pdf_document->target = target;
188 if (pdf_document->target)
189 g_object_ref (pdf_document->target);
191 if (pdf_document->out) {
192 delete pdf_document->out;
193 pdf_document->out = NULL;
196 if (pdf_document->target) {
197 pdf_document->out = new GDKSplashOutputDev (gdk_drawable_get_screen (pdf_document->target),
198 redraw_callback, (void*) document);
200 if (pdf_document->doc)
201 pdf_document->out->startDoc(pdf_document->doc->getXRef());
205 pdf_document->page_valid = FALSE;
210 pdf_document_set_scale (EvDocument *document,
213 PdfDocument *pdf_document = PDF_DOCUMENT (document);
215 if (pdf_document->scale != scale) {
216 pdf_document->scale = scale;
217 pdf_document->page_valid = FALSE;
222 pdf_document_set_page_offset (EvDocument *document,
226 PdfDocument *pdf_document = PDF_DOCUMENT (document);
228 pdf_document->page_x_offset = x;
229 pdf_document->page_y_offset = y;
233 pdf_document_get_page_size (EvDocument *document,
237 PdfDocument *pdf_document = PDF_DOCUMENT (document);
239 if (document_validate_page (pdf_document)) {
241 *width = pdf_document->out->getBitmapWidth();
243 *height = pdf_document->out->getBitmapHeight();
253 pdf_document_render (EvDocument *document,
259 PdfDocument *pdf_document = PDF_DOCUMENT (document);
263 if (!document_validate_page (pdf_document) || !pdf_document->target)
266 page.x = pdf_document->page_x_offset;
267 page.y = pdf_document->page_y_offset;
268 page.width = pdf_document->out->getBitmapWidth();
269 page.height = pdf_document->out->getBitmapHeight();
273 draw.width = clip_width;
274 draw.height = clip_height;
276 if (gdk_rectangle_intersect (&page, &draw, &draw))
277 pdf_document->out->redraw (draw.x - page.x, draw.y - page.y,
278 pdf_document->target,
280 draw.width, draw.height);
284 pdf_document_begin_find (EvDocument *document,
285 const char *search_string,
286 gboolean case_sensitive)
288 /* FIXME make this incremental (idle handler) and multi-page */
289 /* Right now it's fully synchronous plus only does the current page */
291 PdfDocument *pdf_document = PDF_DOCUMENT (document);
294 int xMin, yMin, xMax, yMax;
298 /* FIXME case_sensitive (right now XPDF
299 * code is always case insensitive for ASCII
300 * and case sensitive for all other languaages)
303 g_assert (sizeof (gunichar) == sizeof (Unicode));
304 ucs4 = g_utf8_to_ucs4_fast (search_string, -1,
307 results = g_array_new (FALSE,
309 sizeof (EvFindResult));
311 if (pdf_document->out->findText (ucs4, ucs4_len,
312 gTrue, gTrue, // startAtTop, stopAtBottom
313 gFalse, gFalse, // startAtLast, stopAtLast
314 &xMin, &yMin, &xMax, &yMax)) {
316 result.page_num = pdf_document->page;
318 result.highlight_area.x = xMin;
319 result.highlight_area.y = yMin;
320 result.highlight_area.width = xMax - xMin;
321 result.highlight_area.height = yMax - yMin;
323 g_array_append_val (results, result);
325 /* Now find further results */
327 while (pdf_document->out->findText (ucs4, ucs4_len,
330 &xMin, &yMin, &xMax, &yMax)) {
332 result.page_num = pdf_document->page;
334 result.highlight_area.x = xMin;
335 result.highlight_area.y = yMin;
336 result.highlight_area.width = xMax - xMin;
337 result.highlight_area.height = yMax - yMin;
339 g_array_append_val (results, result);
343 ev_document_found (document,
344 (EvFindResult*) results->data,
348 g_array_free (results, TRUE);
352 pdf_document_end_find (EvDocument *document)
354 PdfDocument *pdf_document = PDF_DOCUMENT (document);
356 /* FIXME this will do something once begin_find queues
357 * an incremental find
360 // this should probably be shared among EvDocument
361 // implementations somehow?
362 ev_document_found (document, NULL, 0, 1.0);
366 pdf_document_ps_export_begin (EvPSExporter *exporter, const char *filename)
368 PdfDocument *document = PDF_DOCUMENT (exporter);
370 if (document->ps_out)
371 delete document->ps_out;
373 document->ps_out = new PSOutputDev ((char *)filename, document->doc->getXRef(),
374 document->doc->getCatalog(), 1,
375 ev_document_get_n_pages (EV_DOCUMENT (document)),
380 pdf_document_ps_export_do_page (EvPSExporter *exporter, int page)
382 PdfDocument *document = PDF_DOCUMENT (exporter);
384 document->doc->displayPage (document->ps_out, page,
385 72.0, 72.0, 0, gTrue, gFalse);
389 pdf_document_ps_export_end (EvPSExporter *exporter)
391 PdfDocument *document = PDF_DOCUMENT (exporter);
393 delete document->ps_out;
394 document->ps_out = NULL;
398 pdf_document_finalize (GObject *object)
400 PdfDocument *pdf_document = PDF_DOCUMENT (object);
402 if (pdf_document->target)
403 g_object_unref (pdf_document->target);
405 if (pdf_document->out)
406 delete pdf_document->out;
407 if (pdf_document->ps_out)
408 delete pdf_document->ps_out;
409 if (pdf_document->doc)
410 delete pdf_document->doc;
415 pdf_document_class_init (PdfDocumentClass *klass)
417 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
419 gobject_class->finalize = pdf_document_finalize;
423 pdf_document_document_iface_init (EvDocumentIface *iface)
425 iface->load = pdf_document_load;
426 iface->get_n_pages = pdf_document_get_n_pages;
427 iface->set_page = pdf_document_set_page;
428 iface->get_page = pdf_document_get_page;
429 iface->set_scale = pdf_document_set_scale;
430 iface->set_target = pdf_document_set_target;
431 iface->set_page_offset = pdf_document_set_page_offset;
432 iface->get_page_size = pdf_document_get_page_size;
433 iface->render = pdf_document_render;
434 iface->begin_find = pdf_document_begin_find;
435 iface->end_find = pdf_document_end_find;
439 pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface)
441 iface->begin = pdf_document_ps_export_begin;
442 iface->do_page = pdf_document_ps_export_do_page;
443 iface->end = pdf_document_ps_export_end;
447 pdf_document_init (PdfDocument *pdf_document)
449 pdf_document->page = 1;
450 pdf_document->page_x_offset = 0;
451 pdf_document->page_y_offset = 0;
452 pdf_document->scale = 1.;
454 pdf_document->page_valid = FALSE;