+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
/* pdfdocument.h: Implementation of EvDocument for PDF
* Copyright (C) 2004, Red Hat, Inc.
*
#include "gpdf-g-switch.h"
#include "pdf-document.h"
+#include "ev-ps-exporter.h"
+#include "ev-document-find.h"
#include "gpdf-g-switch.h"
#include "GlobalParams.h"
#include "GDKSplashOutputDev.h"
#include "PDFDoc.h"
+#include "PSOutputDev.h"
typedef struct _PdfDocumentClass PdfDocumentClass;
GObject parent_instance;
int page;
- GdkRectangle page_rect;
+ int page_x_offset;
+ int page_y_offset;
+ double scale;
GdkDrawable *target;
GDKSplashOutputDev *out;
+ PSOutputDev *ps_out;
PDFDoc *doc;
-
+
+ gboolean page_valid;
};
-static void pdf_document_document_iface_init (EvDocumentIface *iface);
+static void pdf_document_document_iface_init (EvDocumentIface *iface);
+static void pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface);
+static void pdf_document_find_iface_init (EvDocumentFindIface *iface);
G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
- { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
- pdf_document_document_iface_init) });
+ {
+ G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT,
+ pdf_document_document_iface_init);
+ G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER,
+ pdf_document_ps_exporter_iface_init);
+ G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND,
+ pdf_document_find_iface_init);
+ });
+static gboolean
+document_validate_page (PdfDocument *pdf_document)
+{
+ if (!pdf_document->page_valid) {
+ pdf_document->doc->displayPage (pdf_document->out, pdf_document->page,
+ 72 * pdf_document->scale,
+ 72 * pdf_document->scale,
+ 0, gTrue, gTrue);
+
+ pdf_document->page_valid = TRUE;
+ }
+}
static gboolean
pdf_document_load (EvDocument *document,
if (!globalParams) {
globalParams = new GlobalParams("/etc/xpdfrc");
- globalParams->setupBaseFonts(NULL);
+ globalParams->setupBaseFontsFc(NULL);
}
filename = g_filename_from_uri (uri, NULL, error);
delete pdf_document->doc;
pdf_document->doc = newDoc;
- if (pdf_document->out) {
+ pdf_document->page = 1;
+
+ if (pdf_document->out)
pdf_document->out->startDoc(pdf_document->doc->getXRef());
- pdf_document->doc->displayPage (pdf_document->out, 1, 72, 72, 0, gTrue, gTrue);
- }
+
+ pdf_document->page_valid = FALSE;
return TRUE;
}
{
PdfDocument *pdf_document = PDF_DOCUMENT (document);
- pdf_document->page = page;
+ page = CLAMP (page, 1, ev_document_get_n_pages (document));
+
+ if (page != pdf_document->page) {
+ pdf_document->page = page;
+ pdf_document->page_valid = FALSE;
+ }
+
+}
+
+static int
+pdf_document_get_page (EvDocument *document)
+{
+ PdfDocument *pdf_document = PDF_DOCUMENT (document);
+
+ return pdf_document->page;
}
static void
if (pdf_document->target)
g_object_ref (pdf_document->target);
- if (pdf_document->out)
+ if (pdf_document->out) {
delete pdf_document->out;
+ pdf_document->out = NULL;
+ }
if (pdf_document->target) {
pdf_document->out = new GDKSplashOutputDev (gdk_drawable_get_screen (pdf_document->target),
redraw_callback, (void*) document);
- if (pdf_document->doc) {
+ if (pdf_document->doc)
pdf_document->out->startDoc(pdf_document->doc->getXRef());
- pdf_document->doc->displayPage (pdf_document->out, 1, 72, 72, 0, gTrue, gTrue);
- }
+
}
+
+ pdf_document->page_valid = FALSE;
+ }
+}
+
+static void
+pdf_document_set_scale (EvDocument *document,
+ double scale)
+{
+ PdfDocument *pdf_document = PDF_DOCUMENT (document);
+
+ if (pdf_document->scale != scale) {
+ pdf_document->scale = scale;
+ pdf_document->page_valid = FALSE;
}
}
static void
-pdf_document_set_page_rect (EvDocument *document,
- int x,
- int y,
- int width,
- int height)
+pdf_document_set_page_offset (EvDocument *document,
+ int x,
+ int y)
{
PdfDocument *pdf_document = PDF_DOCUMENT (document);
- pdf_document->page_rect.x = x;
- pdf_document->page_rect.y = y;
- pdf_document->page_rect.width = width;
- pdf_document->page_rect.height = height;
+ pdf_document->page_x_offset = x;
+ pdf_document->page_y_offset = y;
+}
+
+static void
+pdf_document_get_page_size (EvDocument *document,
+ int *width,
+ int *height)
+{
+ PdfDocument *pdf_document = PDF_DOCUMENT (document);
+
+ if (document_validate_page (pdf_document)) {
+ if (width)
+ *width = pdf_document->out->getBitmapWidth();
+ if (height)
+ *height = pdf_document->out->getBitmapHeight();
+ } else {
+ if (width)
+ *width = 1;
+ if (height)
+ *height = 1;
+ }
}
static void
GdkRectangle page;
GdkRectangle draw;
- if (!pdf_document->target)
+ if (!document_validate_page (pdf_document) || !pdf_document->target)
return;
- page.x = 0;
- page.y = 0;
+ page.x = pdf_document->page_x_offset;
+ page.y = pdf_document->page_y_offset;
page.width = pdf_document->out->getBitmapWidth();
page.height = pdf_document->out->getBitmapHeight();
draw.height = clip_height;
if (gdk_rectangle_intersect (&page, &draw, &draw))
- pdf_document->out->redraw (draw.x, draw.y,
+ pdf_document->out->redraw (draw.x - page.x, draw.y - page.y,
pdf_document->target,
draw.x, draw.y,
draw.width, draw.height);
}
+static void
+pdf_document_find_begin (EvDocumentFind *document,
+ const char *search_string,
+ gboolean case_sensitive)
+{
+ /* FIXME make this incremental (idle handler) and multi-page */
+ /* Right now it's fully synchronous plus only does the current page */
+
+ PdfDocument *pdf_document = PDF_DOCUMENT (document);
+ gunichar *ucs4;
+ glong ucs4_len;
+ int xMin, yMin, xMax, yMax;
+ GArray *results;
+ EvFindResult result;
+
+ /* FIXME case_sensitive (right now XPDF
+ * code is always case insensitive for ASCII
+ * and case sensitive for all other languaages)
+ */
+
+ g_assert (sizeof (gunichar) == sizeof (Unicode));
+ ucs4 = g_utf8_to_ucs4_fast (search_string, -1,
+ &ucs4_len);
+
+ results = g_array_new (FALSE,
+ FALSE,
+ sizeof (EvFindResult));
+
+ if (pdf_document->out->findText (ucs4, ucs4_len,
+ gTrue, gTrue, // startAtTop, stopAtBottom
+ gFalse, gFalse, // startAtLast, stopAtLast
+ &xMin, &yMin, &xMax, &yMax)) {
+
+ result.page_num = pdf_document->page;
+
+ result.highlight_area.x = xMin;
+ result.highlight_area.y = yMin;
+ result.highlight_area.width = xMax - xMin;
+ result.highlight_area.height = yMax - yMin;
+
+ g_array_append_val (results, result);
+
+ /* Now find further results */
+
+ while (pdf_document->out->findText (ucs4, ucs4_len,
+ gFalse, gTrue,
+ gTrue, gFalse,
+ &xMin, &yMin, &xMax, &yMax)) {
+
+ result.page_num = pdf_document->page;
+
+ result.highlight_area.x = xMin;
+ result.highlight_area.y = yMin;
+ result.highlight_area.width = xMax - xMin;
+ result.highlight_area.height = yMax - yMin;
+
+ g_array_append_val (results, result);
+ }
+ }
+
+ ev_document_find_found (document,
+ (EvFindResult*) results->data,
+ results->len,
+ 1.0);
+
+ g_array_free (results, TRUE);
+}
+
+static void
+pdf_document_find_cancel (EvDocumentFind *document)
+{
+ PdfDocument *pdf_document = PDF_DOCUMENT (document);
+
+ /* FIXME this will do something once begin_find queues
+ * an incremental find
+ */
+}
+
+static void
+pdf_document_ps_export_begin (EvPSExporter *exporter, const char *filename)
+{
+ PdfDocument *document = PDF_DOCUMENT (exporter);
+
+ if (document->ps_out)
+ delete document->ps_out;
+
+ document->ps_out = new PSOutputDev ((char *)filename, document->doc->getXRef(),
+ document->doc->getCatalog(), 1,
+ ev_document_get_n_pages (EV_DOCUMENT (document)),
+ psModePS);
+}
+
+static void
+pdf_document_ps_export_do_page (EvPSExporter *exporter, int page)
+{
+ PdfDocument *document = PDF_DOCUMENT (exporter);
+
+ document->doc->displayPage (document->ps_out, page,
+ 72.0, 72.0, 0, gTrue, gFalse);
+}
+
+static void
+pdf_document_ps_export_end (EvPSExporter *exporter)
+{
+ PdfDocument *document = PDF_DOCUMENT (exporter);
+
+ delete document->ps_out;
+ document->ps_out = NULL;
+}
+
static void
pdf_document_finalize (GObject *object)
{
if (pdf_document->out)
delete pdf_document->out;
+ if (pdf_document->ps_out)
+ delete pdf_document->ps_out;
if (pdf_document->doc)
delete pdf_document->doc;
iface->load = pdf_document_load;
iface->get_n_pages = pdf_document_get_n_pages;
iface->set_page = pdf_document_set_page;
+ iface->get_page = pdf_document_get_page;
+ iface->set_scale = pdf_document_set_scale;
iface->set_target = pdf_document_set_target;
- iface->set_page_rect = pdf_document_set_page_rect;
+ iface->set_page_offset = pdf_document_set_page_offset;
+ iface->get_page_size = pdf_document_get_page_size;
iface->render = pdf_document_render;
}
static void
-pdf_document_init (PdfDocument *document)
+pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface)
+{
+ iface->begin = pdf_document_ps_export_begin;
+ iface->do_page = pdf_document_ps_export_do_page;
+ iface->end = pdf_document_ps_export_end;
+}
+
+
+static void
+pdf_document_find_iface_init (EvDocumentFindIface *iface)
{
+ iface->begin = pdf_document_find_begin;
+ iface->cancel = pdf_document_find_cancel;
+}
+
+static void
+pdf_document_init (PdfDocument *pdf_document)
+{
+ pdf_document->page = 1;
+ pdf_document->page_x_offset = 0;
+ pdf_document->page_y_offset = 0;
+ pdf_document->scale = 1.;
+
+ pdf_document->page_valid = FALSE;
}