]> www.fi.muni.cz Git - evince.git/commitdiff
Massive changes. We now support text selection of pdfs, and not just
authorJonathan Blandford <jrb@redhat.com>
Thu, 30 Jun 2005 05:44:28 +0000 (05:44 +0000)
committerJonathan Blandford <jrb@src.gnome.org>
Thu, 30 Jun 2005 05:44:28 +0000 (05:44 +0000)
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.

18 files changed:
ChangeLog
NOTES
backend/Makefile.am
backend/ev-document.c
backend/ev-document.h
backend/ev-render-context.c [new file with mode: 0644]
backend/ev-render-context.h [new file with mode: 0644]
backend/ev-selection.c [new file with mode: 0644]
backend/ev-selection.h [new file with mode: 0644]
pdf/ev-poppler.cc
pixbuf/pixbuf-document.c
shell/ev-jobs.c
shell/ev-jobs.h
shell/ev-pixbuf-cache.c
shell/ev-pixbuf-cache.h
shell/ev-view.c
shell/ev-view.h
tiff/tiff-document.c

index f90335244ae77e7c9f81e7908b4f045fb791117f..5ef20ffb9bf22c0c614b0ed7d208b9bb99184b70 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+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:
diff --git a/NOTES b/NOTES
index 19b52b3e5e1bdb7b51d934faf61d097df89c6d9e..d709444f4862494af5677f0ced51da477f739e81 100644 (file)
--- a/NOTES
+++ b/NOTES
@@ -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.
index b000dc4e38107b9b36334d7651271bbed70179d2..8ce117d52d1c8b396642090d7e7c21c34b1cfa0b 100644 (file)
@@ -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)
index 9bccc4cab7ee2d09ed99e5024ac3144a6cea4456..3395bf7c4ac40173364190840fb53483db9fbeab 100644 (file)
@@ -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));
+}
index 044014f370cb8798782d9cd7fca4bea3b7ca7a6f..e95ce96f277c080ddc8191a37392ead2fe25a05d 100644 (file)
@@ -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
diff --git a/backend/ev-render-context.c b/backend/ev-render-context.c
new file mode 100644 (file)
index 0000000..2d09d44
--- /dev/null
@@ -0,0 +1,79 @@
+#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;
+}
+
diff --git a/backend/ev-render-context.h b/backend/ev-render-context.h
new file mode 100644 (file)
index 0000000..7bd73d6
--- /dev/null
@@ -0,0 +1,75 @@
+/* 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 */
diff --git a/backend/ev-selection.c b/backend/ev-selection.c
new file mode 100644 (file)
index 0000000..fc8caa6
--- /dev/null
@@ -0,0 +1,80 @@
+/* -*- 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);
+}
diff --git a/backend/ev-selection.h b/backend/ev-selection.h
new file mode 100644 (file)
index 0000000..a07d639
--- /dev/null
@@ -0,0 +1,68 @@
+/* -*- 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
index 9ebc614f8571c5491a64056b6f3d45067a80796d..528ecfd436621f696498691feabfc96e9cb13560 100644 (file)
@@ -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)
 {
index 97f5271883ad516759a0bd1fa45d810f0e185c04..d4a8c9afb1f41984dab2ff03b5be1ce0a15649a7 100644 (file)
@@ -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);
index 20ebf856c33285a4b12f76f676ff9fbf8ee3addf..3bc2fa883ccd260684a4a8ec201b29a7a81060dd 100644 (file)
@@ -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)
-                       job->link_mapping = ev_document_get_links (EV_JOB (job)->document, job->page);
+                       job->link_mapping = ev_document_get_links (EV_JOB (job)->document, job->rc->page);
+               if (job->include_selection && EV_IS_SELECTION (EV_JOB (job)->document))
+                       ev_selection_render_selection (EV_SELECTION (EV_JOB (job)->document),
+                                                      job->rc,
+                                                      &(job->selection),
+                                                      &(job->selection_points),
+                                                      NULL);
 
                EV_JOB (job)->finished = TRUE;
        }
index 900d040566cf398efec8094a3795dd6843153145..9e4690939349bb4fa84eaec419673eaa8af5c312 100644 (file)
@@ -45,32 +45,32 @@ typedef struct _EvJobFontsClass EvJobFontsClass;
 
 #define EV_TYPE_JOB                         (ev_job_get_type())
 #define EV_JOB(object)                      (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB, EvJob))
-#define EV_JOB_CLASS(klass)                 (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB, EvJobClass))
+#define EV_JOB_CLASS(klass)                 (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB, EvJobClass))
 #define EV_IS_JOB(object)                   (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB))
 
 #define EV_TYPE_JOB_LINKS                   (ev_job_links_get_type())
 #define EV_JOB_LINKS(object)                (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_LINKS, EvJobLinks))
-#define EV_JOB_LINKS_CLASS(klass)           (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_LINKS, EvJobLinksClass))
+#define EV_JOB_LINKS_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_LINKS, EvJobLinksClass))
 #define EV_IS_JOB_LINKS(object)                     (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_LINKS))
 
 #define EV_TYPE_JOB_RENDER                  (ev_job_render_get_type())
 #define EV_JOB_RENDER(object)               (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_RENDER, EvJobRender))
-#define EV_JOB_RENDER_CLASS(klass)          (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_RENDER, EvJobRenderClass))
+#define EV_JOB_RENDER_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_RENDER, EvJobRenderClass))
 #define EV_IS_JOB_RENDER(object)            (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_RENDER))
 
 #define EV_TYPE_JOB_THUMBNAIL               (ev_job_thumbnail_get_type())
 #define EV_JOB_THUMBNAIL(object)            (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_THUMBNAIL, EvJobThumbnail))
-#define EV_JOB_THUMBNAIL_CLASS(klass)       (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_THUMBNAIL, EvJobThumbnailClass))
+#define EV_JOB_THUMBNAIL_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_THUMBNAIL, EvJobThumbnailClass))
 #define EV_IS_JOB_THUMBNAIL(object)         (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_THUMBNAIL))
 
 #define EV_TYPE_JOB_LOAD                    (ev_job_load_get_type())
 #define EV_JOB_LOAD(object)                 (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_LOAD, EvJobLoad))
-#define EV_JOB_LOAD_CLASS(klass)            (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_LOAD, EvJobLoadClass))
+#define EV_JOB_LOAD_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_LOAD, EvJobLoadClass))
 #define EV_IS_JOB_LOAD(object)              (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_LOAD))
 
 #define EV_TYPE_JOB_FONTS                   (ev_job_fonts_get_type())
 #define EV_JOB_FONTS(object)                (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_JOB_FONTS, EvJobFonts))
-#define EV_JOB_FONTS_CLASS(klass)           (G_TYPE_CHACK_CLASS_CAST((klass), EV_TYPE_JOB_FONTS, EvJobFontsClass))
+#define EV_JOB_FONTS_CLASS(klass)           (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_JOB_FONTS, EvJobFontsClass))
 #define EV_IS_JOB_FONTS(object)                     (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_JOB_FONTS))
 
 typedef enum {
@@ -109,13 +109,18 @@ struct _EvJobRender
 {
        EvJob parent;
 
-       gint page;
-       double scale;
+       EvRenderContext *rc;
        gint target_width;
        gint target_height;
        GdkPixbuf *pixbuf;
+
        GList *link_mapping;
-       gboolean include_links;
+
+       GdkPixbuf *selection;
+       EvRectangle selection_points;
+
+       gint include_links : 1;
+       gint include_selection : 1;
 };
 
 struct _EvJobRenderClass
@@ -171,13 +176,14 @@ void            ev_job_links_run          (EvJobLinks     *thumbnail);
 
 /* EvJobRender */
 GType           ev_job_render_get_type    (void);
-EvJob          *ev_job_render_new         (EvDocument     *document,
-                                          gint            page,
-                                          double          scale,
-                                          gint            width,
-                                          gint            height,
-                                          gboolean        include_links);
-void            ev_job_render_run         (EvJobRender    *thumbnail);
+EvJob          *ev_job_render_new         (EvDocument      *document,
+                                          EvRenderContext *rc,
+                                          gint             width,
+                                          gint             height,
+                                          EvRectangle     *selection_points,
+                                          gboolean         include_links,
+                                          gboolean         include_selection);
+void            ev_job_render_run         (EvJobRender     *thumbnail);
 
 /* EvJobThumbnail */
 GType           ev_job_thumbnail_get_type (void);
index 0601de053422665b3e0266872cd1c8e166649d3a..6c5618da3daae4f24fca456eff70b2f24bda016a 100644 (file)
@@ -1,13 +1,21 @@
 #include "ev-pixbuf-cache.h"
 #include "ev-job-queue.h"
 #include "ev-page-cache.h"
-
+#include "ev-selection.h"
 
 typedef struct _CacheJobInfo
 {
        EvJob *job;
        GdkPixbuf *pixbuf;
+       EvRenderContext *rc;
        GList *link_mapping;
+
+       /* Selection info.  If the *_points structs are unset, we put -1 in x1.
+        * selection_points are the coordinates encapsulated in selection.
+        * new_points is the target selection size. */
+       EvRectangle selection_points;
+       GdkPixbuf *selection;
+       EvRectangle new_points;
 } CacheJobInfo;
 
 struct _EvPixbufCache
@@ -55,6 +63,10 @@ static CacheJobInfo *find_job_cache             (EvPixbufCache      *pixbuf_cach
 static void          copy_job_to_job_info       (EvJobRender        *job_render,
                                                 CacheJobInfo       *job_info,
                                                 EvPixbufCache      *pixbuf_cache);
+static gboolean      new_selection_pixbuf_needed(EvPixbufCache *pixbuf_cache,
+                                                CacheJobInfo  *job_info,
+                                                gint           page,
+                                                gfloat         scale);
 
 
 /* These are used for iterating through the prev and next arrays */
@@ -132,6 +144,13 @@ dispose_cache_job_info (CacheJobInfo *job_info,
                ev_link_mapping_free (job_info->link_mapping);
                job_info->link_mapping = NULL;
        }
+       if (job_info->selection) {
+               g_object_unref (G_OBJECT (job_info->selection));
+               job_info->selection = NULL;
+       }
+
+       job_info->selection_points.x1 = -1;
+       job_info->new_points.x1 = -1;
 }
 
 static void
@@ -173,13 +192,13 @@ job_finished_cb (EvJob         *job,
        GdkPixbuf *pixbuf;
 
        /* If the job is outside of our interest, we silently discard it */
-       if ((job_render->page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)) ||
-           (job_render->page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))) {
+       if ((job_render->rc->page < (pixbuf_cache->start_page - pixbuf_cache->preload_cache_size)) ||
+           (job_render->rc->page > (pixbuf_cache->end_page + pixbuf_cache->preload_cache_size))) {
                g_object_unref (job);
                return;
        }
        
-       job_info = find_job_cache (pixbuf_cache, job_render->page);
+       job_info = find_job_cache (pixbuf_cache, job_render->rc->page);
 
        pixbuf = g_object_ref (job_render->pixbuf);
        if (job_info->pixbuf)
@@ -191,6 +210,13 @@ job_finished_cb (EvJob         *job,
                        ev_link_mapping_free (job_info->link_mapping);
                job_info->link_mapping = job_render->link_mapping;
        }
+       if (job_render->include_selection) {
+               if (job_info->selection)
+                       g_object_unref (job_info->selection);
+               job_info->selection_points = job_render->selection_points;
+               job_info->selection = job_render->selection;
+               g_assert (job_info->selection_points.x1 >= 0);
+       }
        
        if (job_info->job == job)
                job_info->job = NULL;
@@ -216,7 +242,7 @@ check_job_size_and_unref (CacheJobInfo *job_info,
                return;
 
        ev_page_cache_get_size (page_cache,
-                               EV_JOB_RENDER (job_info->job)->page,
+                               EV_JOB_RENDER (job_info->job)->rc->page,
                                scale,
                                &width, &height);
                                
@@ -336,7 +362,7 @@ ev_pixbuf_cache_update_range (EvPixbufCache *pixbuf_cache,
                              pixbuf_cache, page,
                              new_job_list, new_prev_job, new_next_job,
                              start_page, end_page, EV_JOB_PRIORITY_HIGH);
-               page++;
+               page ++;
        }
 
        for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
@@ -441,6 +467,8 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
                   gfloat         scale,
                   EvJobPriority  priority)
 {
+       gboolean include_links = FALSE;
+       gboolean include_selection = FALSE;
        int width, height;
 
        if (job_info->job)
@@ -456,10 +484,27 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache,
                return;
 
        /* make a new job now */
+       if (job_info->rc == NULL) {
+               job_info->rc = ev_render_context_new (EV_ORIENTATION_PORTRAIT,
+                                                     page, scale);
+       } else {
+               ev_render_context_set_page (job_info->rc, page);
+               ev_render_context_set_scale (job_info->rc, scale);
+       }
+
+       /* Figure out what else we need for this job */
+       if (job_info->link_mapping == NULL)
+               include_links = TRUE;
+       if (new_selection_pixbuf_needed (pixbuf_cache, job_info, page, scale)) {
+               include_selection = TRUE;
+       }
+
        job_info->job = ev_job_render_new (pixbuf_cache->document,
-                                          page, scale,
+                                          job_info->rc,
                                           width, height,
-                                          (job_info->link_mapping == NULL)?TRUE:FALSE);
+                                          &(job_info->new_points),
+                                          include_links,
+                                          include_selection);
        ev_job_queue_add_job (job_info->job, priority);
        g_signal_connect (job_info->job, "finished", G_CALLBACK (job_finished_cb), pixbuf_cache);
 }
@@ -509,7 +554,8 @@ void
 ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
                                gint           start_page,
                                gint           end_page,
-                               gfloat         scale)
+                               gfloat         scale,
+                               GList          *selection_list)
 {
        EvPageCache *page_cache;
 
@@ -529,6 +575,9 @@ ev_pixbuf_cache_set_page_range (EvPixbufCache *pixbuf_cache,
         * size, we remove them if we need to. */
        ev_pixbuf_cache_clear_job_sizes (pixbuf_cache, scale);
 
+       /* Next, we update the target selection for our pages */
+       ev_pixbuf_cache_set_selection_list (pixbuf_cache, selection_list);
+
        /* Finally, we add the new jobs for all the sizes that don't have a
         * pixbuf */
        ev_pixbuf_cache_add_jobs_if_needed (pixbuf_cache, scale);
@@ -571,3 +620,212 @@ ev_pixbuf_cache_get_link_mapping (EvPixbufCache *pixbuf_cache,
        
        return job_info->link_mapping;
 }
+
+/* Selection */
+static gboolean
+new_selection_pixbuf_needed (EvPixbufCache *pixbuf_cache,
+                            CacheJobInfo  *job_info,
+                            gint           page,
+                            gfloat         scale)
+{
+       EvPageCache *page_cache;
+       gint width, height;
+
+       if (job_info->selection) {
+               page_cache = ev_page_cache_get (pixbuf_cache->document);
+               ev_page_cache_get_size (page_cache, page, scale,
+                                       &width, &height);
+               
+               if (width != gdk_pixbuf_get_width (job_info->selection) ||
+                   height != gdk_pixbuf_get_height (job_info->selection))
+                       return TRUE;
+       } else {
+               if (job_info->new_points.x1 >= 0)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+static void
+clear_selection_if_needed (EvPixbufCache *pixbuf_cache,
+                          CacheJobInfo  *job_info,
+                          gint           page,
+                          gfloat         scale)
+{
+       if (new_selection_pixbuf_needed (pixbuf_cache, job_info, page, scale)) {
+               g_object_unref (job_info->selection);
+               job_info->selection = NULL;
+               job_info->selection_points.x1 = -1;
+       }
+}
+
+GList *
+ev_pixbuf_cach_get_text_mapping      (EvPixbufCache *pixbuf_cache,
+                                     gint           page)
+{
+       return NULL;
+}
+
+GdkPixbuf *
+ev_pixbuf_cache_get_selection_pixbuf (EvPixbufCache *pixbuf_cache,
+                                     gint           page,
+                                     gfloat         scale)
+{
+       CacheJobInfo *job_info;
+
+       job_info = find_job_cache (pixbuf_cache, page);
+       if (job_info == NULL)
+               return NULL;
+
+       /* No selection on this page */
+       if (job_info->new_points.x1 < 0)
+               return NULL;
+
+       /* If we have a running job, we just return what we have under the
+        * assumption that it'll be updated later and we can scale it as need
+        * be */
+       if (job_info->job && EV_JOB_RENDER (job_info->job)->include_selection)
+               return job_info->selection;
+
+       /* Now, lets see if we need to resize the image.  If we do, we clear the
+        * old one. */
+       clear_selection_if_needed (pixbuf_cache, job_info, page, scale);
+
+       /* Finally, we see if the two scales are the same, and get a new pixbuf
+        * if needed.  We do this synchronously for now.  At some point, we
+        * _should_ be able to get rid of the doc_mutex, so the synchronicity
+        * doesn't kill us.  Rendering a few glyphs should really be fast.
+        */
+       if (ev_rect_cmp (&(job_info->new_points), &(job_info->selection_points))) {
+               EvRenderContext *rc;
+
+               rc = ev_render_context_new (EV_ORIENTATION_PORTRAIT,
+                                           page,
+                                           scale);
+
+               /* we need to get a new selection pixbuf */
+               ev_document_doc_mutex_lock ();
+               if (job_info->selection_points.x1 < 0) {
+                       g_assert (job_info->selection == NULL);
+                       ev_selection_render_selection (EV_SELECTION (pixbuf_cache->document),
+                                                      rc, &(job_info->selection),
+                                                      &(job_info->new_points),
+                                                      NULL);
+               } else {
+                       g_assert (job_info->selection != NULL);
+                       ev_selection_render_selection (EV_SELECTION (pixbuf_cache->document),
+                                                      rc, &(job_info->selection),
+                                                      &(job_info->new_points),
+                                                      &(job_info->selection_points));
+               }
+               job_info->selection_points = job_info->new_points;
+               ev_document_doc_mutex_unlock ();
+
+       }
+       return job_info->selection;
+}
+
+
+static void
+update_job_selection (CacheJobInfo    *job_info,
+                     EvViewSelection *selection)
+{
+       if (job_info->selection == NULL)
+               job_info->selection_points.x1 = -1;
+       job_info->new_points = selection->rect;
+}
+
+static void
+clear_job_selection (CacheJobInfo *job_info)
+{
+       job_info->selection_points.x1 = -1;
+       job_info->new_points.x1 = -1;
+
+       if (job_info->selection) {
+               g_object_unref (job_info->selection);
+               job_info->selection = NULL;
+       }
+}
+
+/* This function will reset the selection on pages that no longer have them, and
+ * will update the target_selection on those that need it.
+ */
+void
+ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache,
+                                   GList         *selection_list)
+{
+       EvPageCache *page_cache;
+       EvViewSelection *selection;
+       GList *list = selection_list;
+       int page;
+       int i;
+
+       g_return_if_fail (EV_IS_PIXBUF_CACHE (pixbuf_cache));
+
+       page_cache = ev_page_cache_get (pixbuf_cache->document);
+
+       /* We check each area to see what needs updating, and what needs freeing; */
+       page = pixbuf_cache->start_page - pixbuf_cache->preload_cache_size;
+       for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
+               if (page < 0) {
+                       page ++;
+                       continue;
+               }
+
+               selection = NULL;
+               while (list) {
+                       if (((EvViewSelection *)list->data)->page == page) {
+                               selection = list->data;
+                               break;
+                       } else if (((EvViewSelection *)list->data)->page > page) 
+                               break;
+                       list = list->next;
+               }
+
+               if (selection)
+                       update_job_selection (pixbuf_cache->prev_job + i, selection);
+               else
+                       clear_job_selection (pixbuf_cache->prev_job + i);
+               page ++;
+       }
+
+       page = pixbuf_cache->start_page;
+       for (i = 0; i < PAGE_CACHE_LEN (pixbuf_cache); i++) {
+               selection = NULL;
+               while (list) {
+                       if (((EvViewSelection *)list->data)->page == page) {
+                               selection = list->data;
+                               break;
+                       } else if (((EvViewSelection *)list->data)->page > page) 
+                               break;
+                       list = list->next;
+               }
+
+               if (selection)
+                       update_job_selection (pixbuf_cache->job_list + i, selection);
+               else
+                       clear_job_selection (pixbuf_cache->job_list + i);
+               page ++;
+       }
+
+       for (i = 0; i < pixbuf_cache->preload_cache_size; i++) {
+               if (page >= ev_page_cache_get_n_pages (page_cache))
+                       break;
+               
+               selection = NULL;
+               while (list) {
+                       if (((EvViewSelection *)list->data)->page == page) {
+                               selection = list->data;
+                               break;
+                       } else if (((EvViewSelection *)list->data)->page > page) 
+                               break;
+                       list = list->next;
+               }
+
+               if (selection)
+                       update_job_selection (pixbuf_cache->next_job + i, selection);
+               else
+                       clear_job_selection (pixbuf_cache->next_job + i);
+               page ++;
+       }
+}
index 0bd1cbc771080bb3bb31e84bec4e588c1b7f1ed7..19d0311f55bf2c2ede126efe50460891657dc141 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  */
 
+/* This File is basically an extention of EvView, and is out here just to keep
+ * ev-view.c from exploding.
+ */
+
 #ifndef __EV_PIXBUF_CACHE_H__
 #define __EV_PIXBUF_CACHE_H__
 
@@ -30,24 +34,38 @@ G_BEGIN_DECLS
 #define EV_PIXBUF_CACHE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), EV_TYPE_PIXBUF_CACHE, EvPixbufCache))
 #define EV_IS_PIXBUF_CACHE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EV_TYPE_PIXBUF_CACHE))
 
-/* This is basically an extention of ev-view.c, and is out here just to keep
- * ev-view.c from exploding.
+
+
+/* The coordinates in the rect here are at scale == 1.0, so that we can ignore
+ * resizings.  There is one per page, maximum.
  */
+typedef struct {
+       int page;
+       EvRectangle rect;
+} EvViewSelection;
 
 typedef struct _EvPixbufCache       EvPixbufCache;
 typedef struct _EvPixbufCacheClass  EvPixbufCacheClass;
 
 GType          ev_pixbuf_cache_get_type         (void) G_GNUC_CONST;
-EvPixbufCache *ev_pixbuf_cache_new              (EvDocument    *document);
-void           ev_pixbuf_cache_set_page_range   (EvPixbufCache *pixbuf_cache,
-                                                gint           start_page,
-                                                gint           end_page,
-                                                gfloat         scale);
-GdkPixbuf     *ev_pixbuf_cache_get_pixbuf       (EvPixbufCache *pixbuf_cache,
-                                                gint           page);
-GList         *ev_pixbuf_cache_get_link_mapping (EvPixbufCache *pixbuf_cache,
-                                                gint           page);
-
+EvPixbufCache *ev_pixbuf_cache_new                  (EvDocument    *document);
+void           ev_pixbuf_cache_set_page_range       (EvPixbufCache *pixbuf_cache,
+                                                    gint           start_page,
+                                                    gint           end_page,
+                                                    gfloat         scale,
+                                                    GList          *selection_list);
+GdkPixbuf     *ev_pixbuf_cache_get_pixbuf           (EvPixbufCache *pixbuf_cache,
+                                                    gint           page);
+GList         *ev_pixbuf_cache_get_link_mapping     (EvPixbufCache *pixbuf_cache,
+                                                    gint           page);
+/* Selection */
+GList         *ev_pixbuf_cach_get_text_mapping      (EvPixbufCache *pixbuf_cache,
+                                                    gint           page);
+GdkPixbuf     *ev_pixbuf_cache_get_selection_pixbuf (EvPixbufCache *pixbuf_cache,
+                                                    gint           page,
+                                                    gfloat         scale);
+void           ev_pixbuf_cache_set_selection_list   (EvPixbufCache *pixbuf_cache,
+                                                    GList         *selection_list);
 
 G_END_DECLS
 
index 9ff59dbbe6c22b7ec7b0889b10bc4ac3bad39b95..29c87a2914ffd108285436c5203b7496d71b54bd 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "ev-marshal.h"
 #include "ev-view.h"
+#include "ev-selection.h"
 #include "ev-document-find.h"
 #include "ev-document-misc.h"
 #include "ev-debug.h"
@@ -89,18 +90,21 @@ typedef enum {
 #define MIN_SCALE 0.05409
 #define MAX_SCALE 4.0
 
+/* Information for middle clicking and moving around the doc */
 typedef struct {
-       EvRectangle rect;
-       int page;
-} EvViewSelection;
-
-typedef struct {
-        gboolean dragging;
+        gboolean in_drag;
        GdkPoint start;
        gdouble hadj;
        gdouble vadj;
 } DragInfo;
 
+/* Information for handling selection */
+typedef struct {
+       gboolean in_selection;
+       GdkPoint start;
+       GList *selections;
+} SelectionInfo;
+
 typedef enum {
        SCROLL_TO_KEEP_POSITION,
        SCROLL_TO_CURRENT_PAGE,
@@ -118,10 +122,14 @@ struct _EvView {
        gint scroll_x;
        gint scroll_y;
 
+       /* Information for middle clicking and dragging around. */
        DragInfo drag_info;
+
+       /* Selection */
+       EvViewSelectionMode selection_mode;
+       SelectionInfo selection_info;
+
        gboolean pressed_button;
-       GdkPoint selection_start;
-       GList *selections;
        EvViewCursor cursor;
 
        GtkAdjustment *hadjustment;
@@ -147,7 +155,7 @@ struct _EvView {
        gboolean fullscreen;
        gboolean presentation;
        EvSizingMode sizing_mode;
-       
+
        PendingScroll pending_scroll;
        gboolean pending_resize;
 };
@@ -165,7 +173,7 @@ struct _EvViewClass {
 };
 
 /*** Scrolling ***/
-static void       scroll_to_current_page                    (EvView *view, 
+static void       scroll_to_current_page                    (EvView *view,
                                                              GtkOrientation orientation);
 static void       ev_view_set_scroll_adjustments             (EvView             *view,
                                                              GtkAdjustment      *hadjustment,
@@ -353,7 +361,7 @@ static void       ev_view_primary_clear_cb                   (GtkClipboard
                                                              gpointer            data);
 static void       ev_view_update_primary_selection           (EvView             *ev_view);
 
-                                               
+
 G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET)
 
 static void
@@ -364,7 +372,7 @@ scroll_to_current_page (EvView *view, GtkOrientation orientation)
 
        get_page_extents (view, view->current_page, &page_area, &border);
 
-       if (orientation == GTK_ORIENTATION_VERTICAL) {  
+       if (orientation == GTK_ORIENTATION_VERTICAL) {
                if (view->continuous) {
                        gtk_adjustment_clamp_page (view->vadjustment,
                                                   page_area.y - view->spacing,
@@ -376,13 +384,13 @@ scroll_to_current_page (EvView *view, GtkOrientation orientation)
        } else {
                if (view->dual_page) {
                        gtk_adjustment_clamp_page (view->hadjustment,
-                                                  page_area.x, 
+                                                  page_area.x,
                                                   page_area.x + view->hadjustment->page_size);
                } else {
                        gtk_adjustment_set_value (view->hadjustment,
-                                                 CLAMP (view->hadjustment->value, 
+                                                 CLAMP (view->hadjustment->value,
                                                  view->hadjustment->lower,
-                                                 view->hadjustment->upper - 
+                                                 view->hadjustment->upper -
                                                  view->hadjustment->page_size));
                }
        }
@@ -412,15 +420,15 @@ view_set_adjustment_values (EvView         *view,
 
        if (!adjustment)
                return;
-       
+
        factor = 1.0;
        switch (view->pending_scroll) {
-               case SCROLL_TO_KEEP_POSITION: 
+               case SCROLL_TO_KEEP_POSITION:
                        factor = (adjustment->value) / adjustment->upper;
                        break;
-               case SCROLL_TO_CURRENT_PAGE: 
+               case SCROLL_TO_CURRENT_PAGE:
                        break;
-               case SCROLL_TO_CENTER: 
+               case SCROLL_TO_CENTER:
                        factor = (adjustment->value + adjustment->page_size * 0.5) / adjustment->upper;
                        break;
        }
@@ -431,18 +439,18 @@ view_set_adjustment_values (EvView         *view,
        adjustment->lower = 0;
        adjustment->upper = MAX (allocation, requisition);
 
-       /* 
+       /*
         * We add 0.5 to the values before to average out our rounding errors.
         */
        switch (view->pending_scroll) {
-               case SCROLL_TO_KEEP_POSITION: 
+               case SCROLL_TO_KEEP_POSITION:
                        new_value = CLAMP (adjustment->upper * factor + 0.5, 0, adjustment->upper - adjustment->page_size);
                        gtk_adjustment_set_value (adjustment, (int)new_value);
                        break;
-               case SCROLL_TO_CURRENT_PAGE: 
+               case SCROLL_TO_CURRENT_PAGE:
                        scroll_to_current_page (view, orientation);
                        break;
-               case SCROLL_TO_CENTER: 
+               case SCROLL_TO_CENTER:
                        new_value = CLAMP (adjustment->upper * factor - adjustment->page_size * 0.5 + 0.5,
                                           0, adjustment->upper - adjustment->page_size);
                        gtk_adjustment_set_value (adjustment, (int)new_value);
@@ -465,10 +473,10 @@ view_update_range_and_current_page (EvView *view)
                gint current_page;
                gboolean found = FALSE;
                int i;
-               
+
                if (!(view->vadjustment && view->hadjustment))
                        return;
-               
+
                current_area.x = view->hadjustment->value;
                current_area.width = view->hadjustment->upper;
                current_area.y = view->vadjustment->value;
@@ -477,25 +485,25 @@ view_update_range_and_current_page (EvView *view)
                for (i = 0; i < ev_page_cache_get_n_pages (view->page_cache); i++) {
 
                        get_page_extents (view, i, &page_area, &border);
-                       
+
                        if (gdk_rectangle_intersect (&current_area, &page_area, &unused)) {
                                if (! found) {
                                        view->start_page = i;
                                        found = TRUE;
-                                       
+
                                }
                                view->end_page = i;
                        } else if (found) {
                                break;
                        }
                }
-               
+
                current_page = ev_page_cache_get_current_page (view->page_cache);
 
                if (current_page < view->start_page || current_page > view->end_page) {
                        view->current_page = view->start_page;
                        ev_page_cache_set_current_page (view->page_cache, view->start_page);
-               }                       
+               }
        } else {
                if (view->dual_page) {
                        if (view->current_page % 2 == 0) {
@@ -515,7 +523,8 @@ view_update_range_and_current_page (EvView *view)
        ev_pixbuf_cache_set_page_range (view->pixbuf_cache,
                                        view->start_page,
                                        view->end_page,
-                                       view->scale);   
+                                       view->scale,
+                                       view->selection_info.selections);
 }
 
 static void
@@ -639,7 +648,7 @@ ev_view_binding_activated (EvView *view,
 {
        GtkAdjustment *adjustment;
        double value;
-       
+
        if (view->presentation) {
                switch (scroll) {
                        case GTK_SCROLL_STEP_BACKWARD:
@@ -735,13 +744,13 @@ static void       get_page_y_offset                          (EvView *view,
 {
        int max_width, offset;
        GtkBorder border;
-       
+
        g_return_if_fail (y_offset != NULL);
-               
+
        ev_page_cache_get_max_width (view->page_cache, zoom, &max_width);
 
        compute_border (view, max_width, max_width, &border);
-       
+
        if (view->dual_page) {
                ev_page_cache_get_height_to_page (view->page_cache, page, zoom, NULL, &offset);
                offset += (page / 2 + 1) * view->spacing + (page / 2) * (border.top + border.bottom);
@@ -749,7 +758,7 @@ static void       get_page_y_offset                          (EvView *view,
                ev_page_cache_get_height_to_page (view->page_cache, page, zoom, &offset, NULL);
                offset += (page + 1) * view->spacing + page * (border.top + border.bottom);
        }
-       
+
        *y_offset = offset;
        return;
 }
@@ -1150,15 +1159,15 @@ ev_view_size_allocate (GtkWidget      *widget,
                       GtkAllocation  *allocation)
 {
        EvView *view = EV_VIEW (widget);
-       
+
        if (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
                  view->sizing_mode == EV_SIZING_BEST_FIT) {
 
                g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0);
-               
+
                ev_view_size_request (widget, &widget->requisition);
        }
-       
+
        view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
        view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
 
@@ -1166,7 +1175,7 @@ ev_view_size_allocate (GtkWidget      *widget,
        view->pending_resize = FALSE;
 
        if (view->document)
-               view_update_range_and_current_page (view);              
+               view_update_range_and_current_page (view);
 
        GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
 }
@@ -1220,13 +1229,13 @@ ev_view_unrealize (GtkWidget *widget)
 static gboolean
 ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
 {
-       EvView *view = EV_VIEW (widget); 
+       EvView *view = EV_VIEW (widget);
 
-       if ((event->state & GDK_CONTROL_MASK) != 0) {   
+       if ((event->state & GDK_CONTROL_MASK) != 0) {
 
-                ev_view_set_sizing_mode (view, EV_SIZING_FREE);         
+                ev_view_set_sizing_mode (view, EV_SIZING_FREE);
 
-                if (event->direction == GDK_SCROLL_UP || 
+                if (event->direction == GDK_SCROLL_UP ||
                        event->direction == GDK_SCROLL_LEFT) {
                            if (ev_view_can_zoom_in (view)) {
                                    ev_view_zoom_in (view);
@@ -1234,12 +1243,12 @@ ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
                 } else {
                            if (ev_view_can_zoom_out (view)) {
                                    ev_view_zoom_out (view);
-                           }   
+                           }
                 }
                 return TRUE;
        }
-       
-       if ((event->state & GDK_SHIFT_MASK) != 0) {     
+
+       if ((event->state & GDK_SHIFT_MASK) != 0) {
                if (event->direction == GDK_SCROLL_UP)
                        event->direction = GDK_SCROLL_LEFT;
                if (event->direction == GDK_SCROLL_DOWN)
@@ -1249,13 +1258,29 @@ ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event)
        return FALSE;
 }
 
+static EvViewSelection *
+find_selection_for_page (EvView *view,
+                        gint    page)
+{
+       GList *list;
+
+       for (list = view->selection_info.selections; list != NULL; list = list->next) {
+               EvViewSelection *selection;
+
+               selection = (EvViewSelection *) list->data;
+
+               if (selection->page == page)
+                       return selection;
+       }
+
+       return NULL;
+}
+
 static gboolean
 ev_view_expose_event (GtkWidget      *widget,
                      GdkEventExpose *event)
 {
        EvView *view = EV_VIEW (widget);
-       GdkRectangle rubberband;
-       GList *l;
        int i;
 
        if (view->document == NULL)
@@ -1267,26 +1292,14 @@ ev_view_expose_event (GtkWidget      *widget,
 
                if (!get_page_extents (view, i, &page_area, &border))
                        continue;
-                   
+
                page_area.x -= view->scroll_x;
                page_area.y -= view->scroll_y;
-                   
+
                draw_one_page (view, i, &page_area, &border, &(event->area));
 
-               if (EV_IS_DOCUMENT_FIND (view->document)) {
+               if (EV_IS_DOCUMENT_FIND (view->document))
                        highlight_find_results (view, i);
-               }
-       }
-
-       for (l = view->selections; l != NULL; l = l->next) {
-               EvViewSelection *selection = (EvViewSelection *)l->data;
-
-               doc_rect_to_view_rect (view, selection->page,
-                                      &selection->rect, &rubberband);
-               if (rubberband.width > 0 && rubberband.height > 0) {
-                       draw_rubberband (GTK_WIDGET (view), GTK_WIDGET(view)->window,
-                                        &rubberband, 0x40);
-               }
        }
 
        return FALSE;
@@ -1306,13 +1319,13 @@ ev_view_button_press_event (GtkWidget      *widget,
 
        switch (event->button) {
                case 1:
-                       if (view->selections) {
+                       if (view->selection_info.selections) {
                                clear_selection (view);
                                gtk_widget_queue_draw (widget);
                        }
 
-                       view->selection_start.x = event->x;
-                       view->selection_start.y = event->y;
+                       view->selection_info.start.x = event->x;
+                       view->selection_info.start.y = event->y;
                        return TRUE;
                case 2:
                        /* use root coordinates as reference point because
@@ -1341,19 +1354,18 @@ ev_view_motion_notify_event (GtkWidget      *widget,
 
        if (view->pressed_button == 1) {
                GdkRectangle selection;
+               view->selection_info.in_selection = TRUE;
 
-               selection.x = MIN (view->selection_start.x, event->x) + view->scroll_x;
-               selection.y = MIN (view->selection_start.y, event->y) + view->scroll_y;
-               selection.width = ABS (view->selection_start.x - event->x) + 1;
-               selection.height = ABS (view->selection_start.y - event->y) + 1;
+               selection.x = MIN (view->selection_info.start.x, event->x) + view->scroll_x;
+               selection.y = MIN (view->selection_info.start.y, event->y) + view->scroll_y;
+               selection.width = ABS (view->selection_info.start.x - event->x) + 1;
+               selection.height = ABS (view->selection_info.start.y - event->y) + 1;
 
                compute_selections (view, &selection);
 
-               gtk_widget_queue_draw (widget);
-
                return TRUE;
        } else if (view->pressed_button == 2) {
-               if (!view->drag_info.dragging) {
+               if (!view->drag_info.in_drag) {
                        gboolean start;
 
                        start = gtk_drag_check_threshold (widget,
@@ -1361,10 +1373,10 @@ ev_view_motion_notify_event (GtkWidget      *widget,
                                                          view->drag_info.start.y,
                                                          event->x_root,
                                                          event->y_root);
-                       view->drag_info.dragging = start;
+                       view->drag_info.in_drag = start;
                }
 
-               if (view->drag_info.dragging) {
+               if (view->drag_info.in_drag) {
                        int dx, dy;
                        gdouble dhadj_value, dvadj_value;
 
@@ -1422,9 +1434,9 @@ ev_view_button_release_event (GtkWidget      *widget,
        }
 
        view->pressed_button = -1;
-       view->drag_info.dragging = FALSE;
+       view->drag_info.in_drag = FALSE;
 
-       if (view->selections) {
+       if (view->selection_info.selections) {
                ev_view_update_primary_selection (view);
        } else if (view->document) {
                EvLink *link;
@@ -1458,7 +1470,7 @@ draw_rubberband (GtkWidget *widget, GdkWindow *window,
        GdkPixbuf *pixbuf;
        GdkColor *fill_color_gdk;
        guint fill_color;
-       
+
        fill_color_gdk = gdk_color_copy (&GTK_WIDGET (widget)->style->base[GTK_STATE_SELECTED]);
        fill_color = ev_gdk_color_to_rgb (fill_color_gdk) << 8 | alpha;
 
@@ -1519,22 +1531,23 @@ highlight_find_results (EvView *view, int page)
 }
 
 static void
-draw_one_page (EvView       *view,
-              gint          page,
-              GdkRectangle *page_area,
-              GtkBorder    *border,
-              GdkRectangle *expose_area)
+draw_one_page (EvView          *view,
+              gint             page,
+              GdkRectangle    *page_area,
+              GtkBorder       *border,
+              GdkRectangle    *expose_area)
 {
        gint width, height;
-       GdkPixbuf *scaled_image;
        GdkPixbuf *current_pixbuf;
        GdkRectangle overlap;
        GdkRectangle real_page_area;
+       EvViewSelection *selection;
 
        g_assert (view->document);
        if (! gdk_rectangle_intersect (page_area, expose_area, &overlap))
                return;
 
+       selection = find_selection_for_page (view, page);
        ev_page_cache_get_size (view->page_cache,
                                page, view->scale,
                                &width, &height);
@@ -1551,8 +1564,18 @@ draw_one_page (EvView       *view,
                                         page_area, border);
 
        if (gdk_rectangle_intersect (&real_page_area, expose_area, &overlap)) {
+               GdkPixbuf *selection_pixbuf = NULL;
+               GdkPixbuf *scaled_image;
+               GdkPixbuf *scaled_selection;
+
                current_pixbuf = ev_pixbuf_cache_get_pixbuf (view->pixbuf_cache, page);
 
+               /* Get the selection pixbuf iff we have something to draw */
+               if (current_pixbuf && view->selection_mode == EV_VIEW_SELECTION_TEXT && selection)
+                       selection_pixbuf = ev_pixbuf_cache_get_selection_pixbuf (view->pixbuf_cache,
+                                                                                page,
+                                                                                view->scale);
+
                if (current_pixbuf == NULL)
                        scaled_image = NULL;
                else if (width == gdk_pixbuf_get_width (current_pixbuf) &&
@@ -1565,6 +1588,18 @@ draw_one_page (EvView       *view,
                                                                width, height,
                                                                GDK_INTERP_NEAREST);
 
+               if (selection_pixbuf == NULL)
+                       scaled_selection = NULL;
+               else if (width == gdk_pixbuf_get_width (selection_pixbuf) &&
+                        height == gdk_pixbuf_get_height (selection_pixbuf))
+                       scaled_selection = g_object_ref (selection_pixbuf);
+               else
+                       /* FIXME: We don't want to scale the whole area, just the right
+                        * area of it */
+                       scaled_selection = gdk_pixbuf_scale_simple (selection_pixbuf,
+                                                                   width, height,
+                                                                   GDK_INTERP_NEAREST);
+
                if (scaled_image) {
                        gdk_draw_pixbuf (GTK_WIDGET(view)->window,
                                         GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL],
@@ -1577,6 +1612,19 @@ draw_one_page (EvView       *view,
                                         0, 0);
                        g_object_unref (scaled_image);
                }
+
+               if (scaled_selection) {
+                       gdk_draw_pixbuf (GTK_WIDGET(view)->window,
+                                        GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL],
+                                        scaled_selection,
+                                        overlap.x - real_page_area.x,
+                                        overlap.y - real_page_area.y,
+                                        overlap.x, overlap.y,
+                                        overlap.width, overlap.height,
+                                        GDK_RGB_DITHER_NORMAL,
+                                        0, 0);
+                       g_object_unref (scaled_selection);
+               }
        }
 }
 
@@ -1713,7 +1761,7 @@ ev_view_class_init (EvViewClass *class)
        class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
        class->binding_activated = ev_view_binding_activated;
 
-       widget_class->set_scroll_adjustments_signal =  
+       widget_class->set_scroll_adjustments_signal =
            g_signal_new ("set-scroll-adjustments",
                          G_OBJECT_CLASS_TYPE (object_class),
                          G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
@@ -1802,7 +1850,7 @@ ev_view_class_init (EvViewClass *class)
                                         g_param_spec_double ("zoom",
                                                              "Zoom factor",
                                                               "Zoom factor",
-                                                              MIN_SCALE, 
+                                                              MIN_SCALE,
                                                               MAX_SCALE,
                                                               1.0,
                                                               G_PARAM_READWRITE));
@@ -1825,8 +1873,10 @@ ev_view_init (EvView *view)
        view->current_page = 0;
        view->pressed_button = -1;
        view->cursor = EV_VIEW_CURSOR_NORMAL;
-       view->drag_info.dragging = FALSE;
+       view->drag_info.in_drag = FALSE;
+       view->selection_info.in_selection = FALSE;
 
+       view->selection_mode = EV_VIEW_SELECTION_TEXT;
        view->continuous = TRUE;
        view->dual_page = FALSE;
        view->presentation = FALSE;
@@ -1861,7 +1911,7 @@ page_changed_cb (EvPageCache *page_cache,
                 EvView      *view)
 {
        if (view->current_page != new_page) {
-               
+
                view->current_page = new_page;
                view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
                gtk_widget_queue_resize (GTK_WIDGET (view));
@@ -1895,9 +1945,9 @@ static void on_adjustment_value_changed (GtkAdjustment  *adjustment,
        } else {
                view->scroll_y = 0;
        }
-       
-       
-       if (view->pending_resize)       
+
+
+       if (view->pending_resize)
                gtk_widget_queue_draw (GTK_WIDGET (view));
        else
                gdk_window_scroll (GTK_WIDGET (view)->window, dx, dy);
@@ -1999,7 +2049,7 @@ ev_view_set_zoom (EvView   *view,
 
        view->scale = scale;
        view->pending_resize = TRUE;
-       
+
        gtk_widget_queue_resize (GTK_WIDGET (view));
 
        g_object_notify (G_OBJECT (view), "zoom");
@@ -2038,7 +2088,7 @@ ev_view_set_dual_page (EvView   *view,
 
        if (view->dual_page == dual_page)
                return;
-    
+
        view->pending_scroll = SCROLL_TO_CURRENT_PAGE;
        view->dual_page = dual_page;
        /* FIXME: if we're keeping the pixbuf cache around, we should extend the
@@ -2118,7 +2168,7 @@ ev_view_set_sizing_mode (EvView       *view,
 
        view->sizing_mode = sizing_mode;
        gtk_widget_queue_resize (GTK_WIDGET (view));
-       
+
        g_object_notify (G_OBJECT (view), "sizing-mode");
 }
 
@@ -2146,7 +2196,7 @@ void
 ev_view_zoom_in (EvView *view)
 {
        g_return_if_fail (view->sizing_mode == EV_SIZING_FREE);
-       
+
        view->pending_scroll = SCROLL_TO_CENTER;
        ev_view_set_zoom (view, ZOOM_IN_FACTOR, TRUE);
 }
@@ -2421,7 +2471,7 @@ ev_view_set_zoom_for_size (EvView *view,
                           int     height,
                           int     vsb_width,
                           int     hsb_height)
-{      
+{
        g_return_if_fail (view->sizing_mode == EV_SIZING_FIT_WIDTH ||
                          view->sizing_mode == EV_SIZING_BEST_FIT);
        g_return_if_fail (width >= 0);
@@ -2643,14 +2693,20 @@ ev_view_find_previous (EvView *view)
 
 /*** Selections ***/
 
-static void
-compute_selections (EvView *view, GdkRectangle *view_rect)
+/* compute_new_selection_rect/text calculates the area currently selected by
+ * view_rect.  each handles a different mode;
+ */
+static GList *
+compute_new_selection_rect (EvView       *view,
+                           GdkRectangle *view_rect)
 {
        int n_pages, i;
+       GList *list = NULL;
 
-       clear_selection (view);
+       g_assert (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE);
 
        n_pages = ev_page_cache_get_n_pages (view->page_cache);
+
        for (i = 0; i < n_pages; i++) {
                GdkRectangle page_area;
                GtkBorder border;
@@ -2666,18 +2722,137 @@ compute_selections (EvView *view, GdkRectangle *view_rect)
                                view_rect_to_doc_rect (view, &overlap, &page_area,
                                                       &(selection->rect));
 
-                               view->selections = g_list_append
-                                               (view->selections, selection);
+                               list = g_list_append (list, selection);
+                       }
+               }
+       }
+
+       return list;
+}
+
+static GList *
+compute_new_selection_text (EvView       *view,
+                           GdkRectangle *view_rect)
+{
+       int n_pages, i;
+       GList *list = NULL;
+       EvViewSelection *first_selection = NULL;
+       EvViewSelection *last_selection = NULL;
+       gint width, height;
+
+       g_assert (view->selection_mode == EV_VIEW_SELECTION_TEXT);
+
+       n_pages = ev_page_cache_get_n_pages (view->page_cache);
+
+       /* We get the two edge pages */
+       for (i = 0; i < n_pages; i++) {
+               GdkRectangle page_area;
+               GtkBorder border;
+
+               if (get_page_extents (view, i, &page_area, &border)) {
+                       GdkRectangle overlap;
+
+                       if (gdk_rectangle_intersect (&page_area, view_rect, &overlap)) {
+                               EvViewSelection *selection;
+
+                               if (first_selection == NULL) {
+                                       first_selection = g_new0 (EvViewSelection, 1);
+                                       selection = first_selection;
+                               } else if (last_selection == NULL) {
+                                       last_selection = g_new0 (EvViewSelection, 1);
+                                       selection = last_selection;
+                               } else {
+                                       selection = last_selection;
+                               }
+
+                               selection->page = i;
+                               view_rect_to_doc_rect (view, &overlap, &page_area,
+                                                      &(selection->rect));
                        }
                }
        }
+
+       /* No overlap */
+       if (first_selection == NULL)
+               return NULL;
+
+       /* only one selection.  Return a page of it */
+       if (last_selection == NULL)
+               return g_list_append (NULL, first_selection);
+
+       /*clean up the selections;
+        */
+       ev_page_cache_get_size (view->page_cache, first_selection->page,
+                               1.0, &width, &height);
+       first_selection->rect.x2 = width;
+       first_selection->rect.y2 = height;
+       list = g_list_append (NULL, first_selection);
+
+       /* Add all the intervening pages */
+       for (i = first_selection->page + 1; i < last_selection->page; i++) {
+               EvViewSelection *selection;
+
+               selection = g_new0 (EvViewSelection, 1);
+               selection->page = i;
+               ev_page_cache_get_size (view->page_cache, i,
+                                       1.0, &width, &height);
+               selection->rect.x1 = selection->rect.y1 = 0;
+               selection->rect.x2 = width;
+               selection->rect.y2 = height;
+               g_list_append (list, selection);
+       }
+
+       /* Clean up the last page */
+       last_selection->rect.x1 = 0;
+       last_selection->rect.y1 = 0;
+       list = g_list_append (list, last_selection);
+
+       return list;
+}
+
+/* This function takes the newly calculated list, and figures out which regions
+ * have changed.  It then queues a redraw approporiately.
+ */
+static void
+merge_selection_region (EvView *view,
+                       GList  *list)
+{
+
+       /* FIXME: actually write... */
+       clear_selection (view);
+       gtk_widget_queue_draw (GTK_WIDGET (view));
+
+       view->selection_info.selections = list;
+       ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, list);
+}
+
+static void
+compute_selections (EvView       *view,
+                   GdkRectangle *view_rect)
+{
+       GList *list;
+
+       if (view->selection_mode == EV_VIEW_SELECTION_RECTANGLE)
+               list = compute_new_selection_rect (view, view_rect);
+       else
+               list = compute_new_selection_text (view, view_rect);
+       merge_selection_region (view, list);
+}
+
+/* Free's the selection.  It's up to the caller to queue redraws if needed.
+ */
+static void
+selection_free (EvViewSelection *selection)
+{
+       g_free (selection);
 }
 
 static void
 clear_selection (EvView *view)
 {
-       g_list_foreach (view->selections, (GFunc)g_free, NULL);
-       view->selections = NULL;
+       g_list_foreach (view->selection_info.selections, (GFunc)selection_free, NULL);
+       view->selection_info.selections = NULL;
+       view->selection_info.in_selection = FALSE;
 }
 
 
@@ -2702,9 +2877,10 @@ ev_view_select_all (EvView *view)
                selection->rect.x2 = width;
                selection->rect.y2 = height;
 
-               view->selections = g_list_append (view->selections, selection);
+               view->selection_info.selections = g_list_append (view->selection_info.selections, selection);
        }
 
+       ev_pixbuf_cache_set_selection_list (view->pixbuf_cache, view->selection_info.selections);
        gtk_widget_queue_draw (GTK_WIDGET (view));
 }
 
@@ -2718,7 +2894,7 @@ get_selected_text (EvView *ev_view)
 
        ev_document_doc_mutex_lock ();
 
-       for (l = ev_view->selections; l != NULL; l = l->next) {
+       for (l = ev_view->selection_info.selections; l != NULL; l = l->next) {
                EvViewSelection *selection = (EvViewSelection *)l->data;
                char *tmp;
 
@@ -2786,7 +2962,7 @@ ev_view_update_primary_selection (EvView *ev_view)
        clipboard = gtk_widget_get_clipboard (GTK_WIDGET (ev_view),
                                               GDK_SELECTION_PRIMARY);
 
-       if (ev_view->selections) {
+       if (ev_view->selection_info.selections) {
                if (!gtk_clipboard_set_with_owner (clipboard,
                                                   targets,
                                                   G_N_ELEMENTS (targets),
index 05b254292372d1113881444a01e80b07dcb47ad1..0c0ebaf65a23379cdc7d5049e0b8e721921db8eb 100644 (file)
@@ -42,6 +42,11 @@ typedef enum {
        EV_SIZING_FREE,
 } EvSizingMode;
 
+typedef enum {
+       EV_VIEW_SELECTION_TEXT,
+       EV_VIEW_SELECTION_RECTANGLE,
+} EvViewSelectionMode;
+
 typedef enum {
        EV_SCROLL_PAGE_FORWARD,
        EV_SCROLL_PAGE_BACKWARD
index a4c8638ab3042a4512f4e4a2841d216dff7a3077..f2ed498651d58e51232608a3b474025ead415e0e 100644 (file)
@@ -205,7 +205,8 @@ rotate_pixbuf (EvDocument *document, GdkPixbuf *pixbuf)
 }
 
 static GdkPixbuf *
-tiff_document_render_pixbuf (EvDocument  *document, int page, double scale)
+tiff_document_render_pixbuf (EvDocument      *document,
+                            EvRenderContext *rc)
 {
   TiffDocument *tiff_document = TIFF_DOCUMENT (document);
   int width, height;
@@ -219,7 +220,7 @@ tiff_document_render_pixbuf (EvDocument  *document, int page, double scale)
   g_return_val_if_fail (tiff_document->tiff != NULL, 0);
 
   push_handlers ();
-  if (TIFFSetDirectory (tiff_document->tiff, page) != 1)
+  if (TIFFSetDirectory (tiff_document->tiff, rc->page) != 1)
     {
       pop_handlers ();
       return NULL;
@@ -266,8 +267,8 @@ tiff_document_render_pixbuf (EvDocument  *document, int page, double scale)
   pop_handlers ();
 
   scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
-                                          width * scale,
-                                          height * scale,
+                                          width * rc->scale,
+                                          height * rc->scale,
                                           GDK_INTERP_BILINEAR);
   g_object_unref (pixbuf);
 
@@ -332,6 +333,7 @@ tiff_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
                                        gint                  size,
                                        gboolean              border)
 {
+  EvRenderContext *rc;
   GdkPixbuf *pixbuf;
   gdouble w, h;
 
@@ -339,9 +341,9 @@ tiff_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
                               page,
                               &w, &h);
 
-  pixbuf = tiff_document_render_pixbuf (EV_DOCUMENT (document),
-                                       page,
-                                       size/w);
+  rc = ev_render_context_new (EV_ORIENTATION_PORTRAIT, page, size/w);
+  pixbuf = tiff_document_render_pixbuf (EV_DOCUMENT (document), rc);
+  g_object_unref (G_OBJECT (rc));
 
   if (border)
     {