Commit e93b3a26 authored by Jonathan Blandford's avatar Jonathan Blandford Committed by Jonathan Blandford

Massive changes. We now support text selection of pdfs, and not just

Thu Jun 30 01:43:00 2005  Jonathan Blandford  <jrb@redhat.com>

        * shell/*:
        * backend/ev-render-context.[ch]:
        * backend/ev-selection.[ch]:

        Massive changes.  We now support text selection of pdfs, and not
        just rectangular selection.  This is pretty broken still, but I
        want to get something into CVS.
parent a50ca052
Thu Jun 30 01:43:00 2005 Jonathan Blandford <jrb@redhat.com>
* shell/*:
* backend/ev-render-context.[ch]:
* backend/ev-selection.[ch]:
Massive changes. We now support text selection of pdfs, and not
just rectangular selection. This is pretty broken still, but I
want to get something into CVS.
2005-06-28 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
* pdf/ev-poppler.cc:
......
......@@ -25,6 +25,29 @@ Thoughts on threading:
* The primary thing we are trying to do is minimize switching pages, as
doing so is slow for backends. Additionally, some operations on the
backend are slow, leaving poor interactivity. This
backend are slow, leaving poor interactivity.
--
Thoughts on selection:
* On button_press, we record selection_start, and set in_selection.
* selection_list must be ordered!!!
* On motion_notify, we update selection_end and call compute_selection,
that keeps an ordered list of the selections.
* If any of the selection changes, we notify the pixbuf_cache right
away.
* On button_release, we unset in_selection, and trim all the current
pixbufs.
* If a resize (somehow) occurs, during a selection, we clear
in_selection and abort.
* I'd like to support shift-click to handle extending the selection,
but for that to survive resizing, I might need to store the points as
doubles, etc. It should be possible to reconstruct it from the
existing EvViewSelection structs, so maybe I don't need it.
......@@ -30,6 +30,10 @@ libevbackend_la_SOURCES= \
ev-document-info.h \
ev-ps-exporter.c \
ev-ps-exporter.h \
ev-render-context.h \
ev-render-context.c \
ev-selection.h \
ev-selection.c \
ev-document-misc.h \
ev-document-misc.c \
$(NULL)
......
......@@ -203,9 +203,8 @@ ev_document_get_links (EvDocument *document,
GdkPixbuf *
ev_document_render_pixbuf (EvDocument *document,
int page,
double scale)
ev_document_render_pixbuf (EvDocument *document,
EvRenderContext *rc)
{
EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document);
GdkPixbuf *retval;
......@@ -213,7 +212,7 @@ ev_document_render_pixbuf (EvDocument *document,
LOG ("ev_document_render_pixbuf");
g_assert (iface->render_pixbuf);
retval = iface->render_pixbuf (document, page, scale);
retval = iface->render_pixbuf (document, rc);
return retval;
}
......@@ -250,3 +249,22 @@ ev_document_info_free (EvDocumentInfo *info)
g_free (info);
}
/* Compares two rects. returns 0 if they're equal */
#define EPSILON 0.0000001
gint
ev_rect_cmp (EvRectangle *a,
EvRectangle *b)
{
if (a == b)
return 0;
if (a == NULL || b == NULL)
return 1;
return ! ((ABS (a->x1 - b->x1) < EPSILON) &&
(ABS (a->y1 - b->y1) < EPSILON) &&
(ABS (a->x2 - b->x2) < EPSILON) &&
(ABS (a->y2 - b->y2) < EPSILON));
}
......@@ -28,6 +28,7 @@
#include "ev-link.h"
#include "ev-document-info.h"
#include "ev-render-context.h"
G_BEGIN_DECLS
......@@ -55,14 +56,6 @@ typedef enum
EV_DOCUMENT_ERROR_ENCRYPTED
} EvDocumentError;
typedef enum
{
EV_ORIENTATION_PORTRAIT,
EV_ORIENTATION_LANDSCAPE,
EV_ORIENTATION_UPSIDEDOWN,
EV_ORIENTATION_SEASCAPE
} EvOrientation;
typedef struct {
double x1;
double y1;
......@@ -94,9 +87,8 @@ struct _EvDocumentIface
EvRectangle *rect);
GList * (* get_links) (EvDocument *document,
int page);
GdkPixbuf * (* render_pixbuf) (EvDocument *document,
int page,
double scale);
GdkPixbuf * (* render_pixbuf) (EvDocument *document,
EvRenderContext *rc);
EvOrientation (* get_orientation) (EvDocument *document);
void (* set_orientation) (EvDocument *document,
EvOrientation orientation);
......@@ -130,12 +122,16 @@ char *ev_document_get_text (EvDocument *document,
GList *ev_document_get_links (EvDocument *document,
int page);
GdkPixbuf *ev_document_render_pixbuf (EvDocument *document,
int page,
double scale);
EvRenderContext *rc);
EvOrientation ev_document_get_orientation (EvDocument *document);
void ev_document_set_orientation (EvDocument *document,
EvOrientation orientation);
gint ev_rect_cmp (EvRectangle *a,
EvRectangle *b);
G_END_DECLS
#endif
#include "ev-render-context.h"
static void ev_render_context_init (EvRenderContext *rc);
static void ev_render_context_class_init (EvRenderContextClass *class);
G_DEFINE_TYPE (EvRenderContext, ev_render_context, G_TYPE_OBJECT);
static void ev_render_context_init (EvRenderContext *rc) { /* Do Nothing */ }
static void
ev_render_context_dispose (GObject *object)
{
EvRenderContext *rc;
rc = (EvRenderContext *) object;
if (rc->destroy) {
(*rc->destroy) (rc->data);
rc->destroy = NULL;
}
(* G_OBJECT_CLASS (ev_render_context_parent_class)->dispose) (object);
}
static void
ev_render_context_class_init (EvRenderContextClass *class)
{
GObjectClass *oclass;
oclass = G_OBJECT_CLASS (class);
oclass->dispose = ev_render_context_dispose;
}
EvRenderContext *
ev_render_context_new (EvOrientation orientation,
gint page,
gdouble scale)
{
EvRenderContext *rc;
rc = (EvRenderContext *) g_object_new (EV_TYPE_RENDER_CONTEXT, NULL);
rc->orientation = orientation;
rc->page = page;
rc->scale = scale;
return rc;
}
void
ev_render_context_set_page (EvRenderContext *rc,
gint page)
{
g_return_if_fail (rc != NULL);
rc->page = page;
}
void
ev_render_context_set_orientation (EvRenderContext *rc,
EvOrientation orientation)
{
g_return_if_fail (rc != NULL);
rc->orientation = orientation;
}
void
ev_render_context_set_scale (EvRenderContext *rc,
gdouble scale)
{
g_return_if_fail (rc != NULL);
rc->scale = scale;
}
/* this file is part of evince, a gnome document viewer
*
* Copyright (C) 2005 Jonathan Blandford <jrb@gnome.org>
*
* Evince is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Evince is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef EV_RENDER_CONTEXT_H
#define EV_RENDER_CONTEXT_H
#include <glib-object.h>
G_BEGIN_DECLS
typedef struct _EvRenderContext EvRenderContext;
typedef struct _EvRenderContextClass EvRenderContextClass;
#define EV_TYPE_RENDER_CONTEXT (ev_render_context_get_type())
#define EV_RENDER_CONTEXT(context) ((EvRenderContext *) (context))
#define EV_RENDER_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_RENDER_CONTEXT, EvRenderContext))
#define EV_IS_RENDER_CONTEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_RENDER_CONTEXT))
typedef enum
{
EV_ORIENTATION_PORTRAIT,
EV_ORIENTATION_LANDSCAPE,
EV_ORIENTATION_UPSIDEDOWN,
EV_ORIENTATION_SEASCAPE
} EvOrientation;
struct _EvRenderContextClass
{
GObjectClass klass;
};
struct _EvRenderContext
{
GObject parent;
EvOrientation orientation;
gint page;
gdouble scale;
gpointer data;
GDestroyNotify destroy;
};
GType ev_render_context_get_type (void) G_GNUC_CONST;
EvRenderContext *ev_render_context_new (EvOrientation orientation,
gint page,
gdouble scale);
void ev_render_context_set_page (EvRenderContext *rc,
gint page);
void ev_render_context_set_orientation (EvRenderContext *rc,
EvOrientation orientation);
void ev_render_context_set_scale (EvRenderContext *rc,
gdouble scale);
G_END_DECLS
#endif /* !EV_RENDER_CONTEXT */
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
/*
* Copyright (C) 2005 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include "config.h"
#include "ev-selection.h"
static void ev_selection_base_init (gpointer g_class);
GType
ev_selection_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0))
{
static const GTypeInfo our_info =
{
sizeof (EvSelectionIface),
ev_selection_base_init,
NULL,
};
type = g_type_register_static (G_TYPE_INTERFACE,
"EvSelection",
&our_info, (GTypeFlags)0);
}
return type;
}
static void
ev_selection_base_init (gpointer g_class)
{
static gboolean initialized = FALSE;
if (!initialized) {
}
}
void
ev_selection_render_selection (EvSelection *selection,
EvRenderContext *rc,
GdkPixbuf **pixbuf,
EvRectangle *points,
EvRectangle *old_points)
{
EvSelectionIface *iface = EV_SELECTION_GET_IFACE (selection);
iface->render_selection (selection, rc,
pixbuf,
points, old_points);
}
GdkRegion *ev_selection_get_selection_region (EvSelection *selection,
EvRenderContext *rc,
EvRectangle *points)
{
EvSelectionIface *iface = EV_SELECTION_GET_IFACE (selection);
return iface->get_selection_region (selection, rc, points);
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
/*
* Copyright (C) 2000-2003 Marco Pesenti Gritti
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#ifndef EV_SELECTION_H
#define EV_SELECTION_H
#include <glib-object.h>
#include <glib.h>
#include <gdk/gdkpixbuf.h>
#include <gdk/gdk.h>
#include "ev-document.h"
G_BEGIN_DECLS
#define EV_TYPE_SELECTION (ev_selection_get_type ())
#define EV_SELECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_SELECTION, EvSelection))
#define EV_SELECTION_IFACE(k) (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_SELECTION, EvSelectionIface))
#define EV_IS_SELECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EV_TYPE_SELECTION))
#define EV_IS_SELECTION_IFACE(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_SELECTION))
#define EV_SELECTION_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EV_TYPE_SELECTION, EvSelectionIface))
typedef struct _EvSelection EvSelection;
typedef struct _EvSelectionIface EvSelectionIface;
struct _EvSelectionIface
{
GTypeInterface base_iface;
void (* render_selection) (EvSelection *selection,
EvRenderContext *rc,
GdkPixbuf **pixbuf,
EvRectangle *points,
EvRectangle *old_points);
GdkRegion * (* get_selection_region) (EvSelection *selection,
EvRenderContext *rc,
EvRectangle *points);
};
GType ev_selection_get_type (void);
void ev_selection_render_selection (EvSelection *selection,
EvRenderContext *rc,
GdkPixbuf **pixbuf,
EvRectangle *points,
EvRectangle *old_points);
GdkRegion *ev_selection_get_selection_region (EvSelection *selection,
EvRenderContext *rc,
EvRectangle *points);
G_END_DECLS
#endif
......@@ -33,6 +33,7 @@
#include "ev-document-fonts.h"
#include "ev-document-security.h"
#include "ev-document-thumbnails.h"
#include "ev-selection.h"
typedef struct {
PdfDocument *document;
......@@ -73,6 +74,7 @@ static void pdf_document_document_links_iface_init (EvDocumentLinksIface
static void pdf_document_document_fonts_iface_init (EvDocumentFontsIface *iface);
static void pdf_document_find_iface_init (EvDocumentFindIface *iface);
static void pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface);
static void pdf_selection_iface_init (EvSelectionIface *iface);
static void pdf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
gint page,
gint size,
......@@ -97,6 +99,8 @@ G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT,
pdf_document_find_iface_init);
G_IMPLEMENT_INTERFACE (EV_TYPE_PS_EXPORTER,
pdf_document_ps_exporter_iface_init);
G_IMPLEMENT_INTERFACE (EV_TYPE_SELECTION,
pdf_selection_iface_init);
});
static void
......@@ -308,8 +312,7 @@ pdf_document_get_links (EvDocument *document,
static GdkPixbuf *
pdf_document_render_pixbuf (EvDocument *document,
int page,
double scale)
EvRenderContext *rc)
{
PdfDocument *pdf_document;
PopplerPage *poppler_page;
......@@ -319,12 +322,12 @@ pdf_document_render_pixbuf (EvDocument *document,
pdf_document = PDF_DOCUMENT (document);
poppler_page = poppler_document_get_page (pdf_document->document,
page);
rc->page);
set_page_orientation (pdf_document, poppler_page);
poppler_page_get_size (poppler_page, &width_points, &height_points);
width = (int) ((width_points * scale) + 0.5);
height = (int) ((height_points * scale) + 0.5);
width = (int) ((width_points * rc->scale) + 0.5);
height = (int) ((height_points * rc->scale) + 0.5);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
FALSE, 8,
......@@ -333,7 +336,7 @@ pdf_document_render_pixbuf (EvDocument *document,
poppler_page_render_to_pixbuf (poppler_page,
0, 0,
width, height,
scale,
rc->scale,
pixbuf,
0, 0);
......@@ -543,18 +546,20 @@ pdf_document_get_orientation (EvDocument *document)
}
switch (pdf_document->orientation) {
case POPPLER_ORIENTATION_PORTRAIT:
result = EV_ORIENTATION_PORTRAIT;
break;
case POPPLER_ORIENTATION_LANDSCAPE:
result = EV_ORIENTATION_LANDSCAPE;
break;
case POPPLER_ORIENTATION_UPSIDEDOWN:
result = EV_ORIENTATION_UPSIDEDOWN;
break;
case POPPLER_ORIENTATION_SEASCAPE:
result = EV_ORIENTATION_SEASCAPE;
break;
case POPPLER_ORIENTATION_PORTRAIT:
result = EV_ORIENTATION_PORTRAIT;
break;
case POPPLER_ORIENTATION_LANDSCAPE:
result = EV_ORIENTATION_LANDSCAPE;
break;
case POPPLER_ORIENTATION_UPSIDEDOWN:
result = EV_ORIENTATION_UPSIDEDOWN;
break;
case POPPLER_ORIENTATION_SEASCAPE:
result = EV_ORIENTATION_SEASCAPE;
break;
default:
g_assert_not_reached ();
}
return result;
......@@ -567,18 +572,20 @@ pdf_document_set_orientation (EvDocument *document, EvOrientation orientation)
PopplerOrientation poppler_orientation;
switch (orientation) {
case EV_ORIENTATION_PORTRAIT:
poppler_orientation = POPPLER_ORIENTATION_PORTRAIT;
break;
case EV_ORIENTATION_LANDSCAPE:
poppler_orientation = POPPLER_ORIENTATION_LANDSCAPE;
break;
case EV_ORIENTATION_UPSIDEDOWN:
poppler_orientation = POPPLER_ORIENTATION_UPSIDEDOWN;
break;
case EV_ORIENTATION_SEASCAPE:
poppler_orientation = POPPLER_ORIENTATION_SEASCAPE;
break;
case EV_ORIENTATION_PORTRAIT:
poppler_orientation = POPPLER_ORIENTATION_PORTRAIT;
break;
case EV_ORIENTATION_LANDSCAPE:
poppler_orientation = POPPLER_ORIENTATION_LANDSCAPE;
break;
case EV_ORIENTATION_UPSIDEDOWN:
poppler_orientation = POPPLER_ORIENTATION_UPSIDEDOWN;
break;
case EV_ORIENTATION_SEASCAPE:
poppler_orientation = POPPLER_ORIENTATION_SEASCAPE;
break;
default:
g_assert_not_reached ();
}
pdf_document->orientation = poppler_orientation;
......@@ -662,7 +669,6 @@ pdf_document_fonts_fill_model (EvDocumentFonts *document_fonts,
if (iter) {
do {
GtkTreeIter list_iter;
PopplerIndexIter *child;
const char *name;
name = poppler_fonts_iter_get_name (iter);
......@@ -1170,6 +1176,70 @@ pdf_document_ps_exporter_iface_init (EvPSExporterIface *iface)
iface->end = pdf_document_ps_exporter_end;
}
void
pdf_selection_render_selection (EvSelection *selection,
EvRenderContext *rc,
GdkPixbuf **pixbuf,
EvRectangle *points,
EvRectangle *old_points)
{
PdfDocument *pdf_document;
PopplerPage *poppler_page;
double width_points, height_points;
gint width, height;
pdf_document = PDF_DOCUMENT (selection);
poppler_page = poppler_document_get_page (pdf_document->document,
rc->page);
set_page_orientation (pdf_document, poppler_page);
poppler_page_get_size (poppler_page, &width_points, &height_points);
width = (int) ((width_points * rc->scale) + 0.5);
height = (int) ((height_points * rc->scale) + 0.5);
if (*pixbuf == NULL) {
* pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
TRUE, 8,
width, height);
}
poppler_page_render_selection (poppler_page,
rc->scale, *pixbuf,
(PopplerRectangle *)points,
(PopplerRectangle *)old_points);
g_object_unref (poppler_page);
}
GdkRegion *
pdf_selection_get_selection_region (EvSelection *selection,
EvRenderContext *rc,
EvRectangle *points)
{
PdfDocument *pdf_document;
PopplerPage *poppler_page;
GdkRegion *retval;
pdf_document = PDF_DOCUMENT (selection);
poppler_page = poppler_document_get_page (pdf_document->document,
rc->page);
set_page_orientation (pdf_document, poppler_page);
retval = poppler_page_get_selection_region (poppler_page, rc->scale, (PopplerRectangle *) points);
g_object_unref (poppler_page);
return retval;
}
static void
pdf_selection_iface_init (EvSelectionIface *iface)
{
iface->render_selection = pdf_selection_render_selection;
iface->get_selection_region = pdf_selection_get_selection_region;
}
PdfDocument *
pdf_document_new (void)
{
......
......@@ -139,14 +139,15 @@ pixbuf_document_get_page_size (EvDocument *document,
}
static GdkPixbuf*
pixbuf_document_render_pixbuf (EvDocument *document, int page, double scale)
pixbuf_document_render_pixbuf (EvDocument *document,
EvRenderContext *rc)
{
PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (document);
GdkPixbuf *scaled_pixbuf, *rotated_pixbuf;
scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf_document->pixbuf,
gdk_pixbuf_get_width (pixbuf_document->pixbuf) * scale,
gdk_pixbuf_get_height (pixbuf_document->pixbuf) * scale,
gdk_pixbuf_get_width (pixbuf_document->pixbuf) * rc->scale,
gdk_pixbuf_get_height (pixbuf_document->pixbuf) * rc->scale,
GDK_INTERP_BILINEAR);
rotated_pixbuf = rotate_pixbuf (document, scaled_pixbuf);
......
......@@ -3,6 +3,7 @@
#include "ev-document-thumbnails.h"
#include "ev-document-links.h"
#include "ev-document-fonts.h"
#include "ev-selection.h"
#include "ev-async-renderer.h"
static void ev_job_init (EvJob *job);
......@@ -110,6 +111,11 @@ ev_job_render_dispose (GObject *object)
job->pixbuf = NULL;
}
if (job->rc) {
g_object_unref (job->rc);
job->rc = NULL;
}
(* G_OBJECT_CLASS (ev_job_render_parent_class)->dispose) (object);
}
......@@ -215,23 +221,31 @@ ev_job_links_run (EvJobLinks *job)
EvJob *
ev_job_render_new (EvDocument *document,
gint page,
double scale,
gint width,
gint height,
gboolean include_links)
ev_job_render_new (EvDocument *document,
EvRenderContext *rc,
gint width,
gint height,
EvRectangle *selection_points,
gboolean include_links,
gboolean include_selection)
{
EvJobRender *job;
g_return_val_if_fail (EV_IS_RENDER_CONTEXT (rc), NULL);
if (include_selection)
g_return_val_if_fail (selection_points != NULL, NULL);
job = g_object_new (EV_TYPE_JOB_RENDER, NULL);
EV_JOB (job)->document = g_object_ref (document);
job->page = page;
job->scale = scale;
job->rc = g_object_ref (rc);
job->target_width = width;
job->target_height = height;
job->include_links = include_links;
job->include_selection = include_selection;
if (include_selection)
job->selection_points = *selection_points;
if (EV_IS_ASYNC_RENDERER (document)) {
EV_JOB (job)->async = TRUE;
......@@ -260,15 +274,19 @@ ev_job_render_run (EvJobRender *job)
if (EV_JOB (job)->async) {
EvAsyncRenderer *renderer = EV_ASYNC_RENDERER (EV_JOB (job)->document);
ev_async_renderer_render_pixbuf (renderer, job->page, job->scale);
ev_async_renderer_render_pixbuf (renderer, job->rc->page, job->rc->scale);
g_signal_connect (EV_JOB (job)->document, "render_finished",
G_CALLBACK (render_finished_cb), job);
} else {
job->pixbuf = ev_document_render_pixbuf (EV_JOB (job)->document,
job->page,
job->scale);
job->pixbuf = ev_document_render_pixbuf (EV_JOB (job)->document, job->rc);
if (job->include_links)