[evince] djvu: enable selection highlighting



commit 32232115a832b3d4f0bd73d82894b75f1cc7e9aa
Author: Jonas Danielsson <jonas threetimestwo org>
Date:   Thu May 23 12:07:57 2013 +0200

    djvu: enable selection highlighting
    
    https://bugzilla.gnome.org/show_bug.cgi?id=448739

 backend/djvu/djvu-document.c  |  100 +++++++++++++++++++++++++++--
 backend/djvu/djvu-text-page.c |  141 ++++++++++++++++++++++++++++++-----------
 backend/djvu/djvu-text-page.h |   23 +++++---
 3 files changed, 212 insertions(+), 52 deletions(-)
---
diff --git a/backend/djvu/djvu-document.c b/backend/djvu/djvu-document.c
index 57af7dd..c4b50c4 100644
--- a/backend/djvu/djvu-document.c
+++ b/backend/djvu/djvu-document.c
@@ -537,6 +537,95 @@ djvu_text_copy (DjvuDocument *djvu_document,
        return text;
 }
 
+static void
+djvu_convert_to_doc_rect (EvRectangle *dest,
+                         EvRectangle *source,
+                         gdouble height,
+                         gdouble dpi)
+{
+       dest->x1 = source->x1 * dpi / 72;
+       dest->x2 = source->x2 * dpi / 72;
+       dest->y1 = (height - source->y2) * dpi / 72;
+       dest->y2 = (height - source->y1) * dpi / 72;
+}
+
+static GList *
+djvu_selection_get_selection_rects (DjvuDocument    *djvu_document,
+                                   gint             page,
+                                   EvRectangle     *points,
+                                   gdouble          height,
+                                   gdouble          dpi)
+{
+       miniexp_t   page_text;
+       EvRectangle rectangle;
+       GList      *rects = NULL;
+
+       djvu_convert_to_doc_rect (&rectangle, points, height, dpi);
+
+       while ((page_text = ddjvu_document_get_pagetext (djvu_document->d_document,
+                                                        page, "char")) == miniexp_dummy)
+               djvu_handle_events (djvu_document, TRUE, NULL);
+
+       if (page_text != miniexp_nil) {
+               DjvuTextPage *tpage = djvu_text_page_new (page_text);
+
+               rects = djvu_text_page_get_selection_region (tpage, &rectangle);
+               djvu_text_page_free (tpage);
+               ddjvu_miniexp_release (djvu_document->d_document, page_text);
+       }
+
+       return rects;
+}
+
+static cairo_region_t *
+djvu_get_selection_region (DjvuDocument *djvu_document,
+                           gint page,
+                           gdouble scale,
+                           EvRectangle *points)
+{
+       double          height, dpi;
+       GList          *rects = NULL, *l;
+       cairo_region_t *region;
+
+       document_get_page_size (djvu_document, page, NULL, &height, &dpi);
+       rects = djvu_selection_get_selection_rects (djvu_document, page, points,
+                                                   height, dpi);
+       region = cairo_region_create ();
+       for (l = rects; l && l->data; l = g_list_next (l)) {
+               cairo_rectangle_int_t rect;
+               EvRectangle          *r = (EvRectangle *)l->data;
+               gdouble               tmp;
+
+               tmp = r->y1;
+               r->x1 *= 72 / dpi;
+               r->x2 *= 72 / dpi;
+               r->y1 = height - r->y2 * 72 / dpi;
+               r->y2 = height - tmp * 72 / dpi;
+
+               rect.x = (gint) ((r->x1 * scale) + 0.5);
+               rect.y = (gint) ((r->y1 * scale) + 0.5);
+               rect.width = (gint) (((r->x2 - r->x1) * scale) + 0.5);
+               rect.height = (gint) (((r->y2 - r->y1) * scale) + 0.5);
+               cairo_region_union_rectangle (region, &rect);
+               ev_rectangle_free (r);
+       }
+       g_list_free (l);
+
+       return region;
+}
+
+static cairo_region_t *
+djvu_selection_get_selection_region (EvSelection    *selection,
+                                    EvRenderContext *rc,
+                                    EvSelectionStyle style,
+                                    EvRectangle     *points)
+{
+       DjvuDocument *djvu_document = DJVU_DOCUMENT (selection);
+
+       return djvu_get_selection_region (djvu_document, rc->page->index,
+                                         rc->scale, points);
+}
+
 static gchar *
 djvu_selection_get_selected_text (EvSelection     *selection,
                                  EvPage          *page,
@@ -544,16 +633,12 @@ djvu_selection_get_selected_text (EvSelection     *selection,
                                  EvRectangle     *points)
 {
        DjvuDocument *djvu_document = DJVU_DOCUMENT (selection);
-       double width, height, dpi;
+       double height, dpi;
        EvRectangle rectangle;
        gchar *text;
 
-        document_get_page_size (djvu_document, page->index, &width, &height, &dpi);
-        rectangle.x1 = points->x1 * dpi / 72.0;
-        rectangle.y1 = (height - points->y2) * dpi / 72.0;
-        rectangle.x2 = points->x2 * dpi / 72.0;
-        rectangle.y2 = (height - points->y1) * dpi / 72.0;
-               
+       document_get_page_size (djvu_document, page->index, NULL, &height, &dpi);
+       djvu_convert_to_doc_rect (&rectangle, points, height, dpi);
        text = djvu_text_copy (djvu_document, page->index, &rectangle);
       
        if (text == NULL)
@@ -566,6 +651,7 @@ static void
 djvu_selection_iface_init (EvSelectionInterface *iface)
 {
        iface->get_selected_text = djvu_selection_get_selected_text;
+       iface->get_selection_region = djvu_selection_get_selection_region;
 }
 
 /* EvFileExporterIface */
diff --git a/backend/djvu/djvu-text-page.c b/backend/djvu/djvu-text-page.c
index 3f171d1..6e04e94 100644
--- a/backend/djvu/djvu-text-page.c
+++ b/backend/djvu/djvu-text-page.c
@@ -25,7 +25,68 @@
 
 
 /**
- * djvu_text_page_selection_process:
+ * djvu_text_page_union:
+ * @target: first rectangle and result
+ * @source: second rectangle
+ *
+ * Calculates the bounding box of two rectangles and stores the result
+ * in the first.
+ */
+static void
+djvu_text_page_union (EvRectangle *target,
+                     EvRectangle *source)
+{
+       if (source->x1 < target->x1)
+               target->x1 = source->x1;
+       if (source->x2 > target->x2)
+               target->x2 = source->x2;
+       if (source->y1 < target->y1)
+               target->y1 = source->y1;
+       if (source->y2 > target->y2)
+               target->y2 = source->y2;
+}
+
+/**
+ * djvu_text_page_selection_process_box:
+ * @page: #DjvuTextPage instance
+ * @p: s-expression to append bounding box of
+ * @delimit: character/word/... delimiter
+ *
+ * Appends bounding box of the line containing miniexp_t to page->results
+ *
+ * Returns: whether the end was not reached in this s-expression
+ */
+static gboolean
+djvu_text_page_selection_process_box (DjvuTextPage *page,
+                                     miniexp_t     p,
+                                     int           delimit)
+{
+       if (page->results || p == page->start) {
+               EvRectangle box;
+
+               box.x1 = miniexp_to_int (miniexp_nth (1, p));
+               box.y1 = miniexp_to_int (miniexp_nth (2, p));
+               box.x2 = miniexp_to_int (miniexp_nth (3, p));
+               box.y2 = miniexp_to_int (miniexp_nth (4, p));
+
+               if (!(delimit & 2) && page->results != NULL) {
+                       EvRectangle *union_box = (EvRectangle *)page->results->data;
+
+                        /* If still on the same line, add box to union */
+                       djvu_text_page_union (union_box, &box);
+               } else {
+                       /* A new line, a new box */
+                       page->results = g_list_prepend (page->results, ev_rectangle_copy (&box));
+               }
+
+               if (p == page->end)
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+/**
+ * djvu_text_page_selection_process_text:
  * @page: #DjvuTextPage instance
  * @p: s-expression to append
  * @delimit: character/word/... delimiter
@@ -35,9 +96,9 @@
  * Returns: whether the end was not reached in this s-expression
  */
 static gboolean
-djvu_text_page_selection_process (DjvuTextPage *page, 
-                                  miniexp_t     p,
-                                  int           delimit)
+djvu_text_page_selection_process_text (DjvuTextPage *page,
+                                       miniexp_t     p,
+                                       int           delimit)
 {
        if (page->text || p == page->start) {
                char *token_text = (char *) miniexp_to_str (miniexp_nth (5, p));
@@ -63,16 +124,17 @@ djvu_text_page_selection_process (DjvuTextPage *page,
  * @p: tree to append
  * @delimit: character/word/... delimiter
  * 
- * Walks the tree in @p and appends the text with
- * djvu_text_page_selection_process() for all s-expressions 
+ * Walks the tree in @p and appends the text or bounding boxes with
+ * djvu_text_page_selection_process_{text|box}() for all s-expressions
  * between the start and end fields.
  * 
  * Returns: whether the end was not reached in this subtree
  */
 static gboolean
-djvu_text_page_selection (DjvuTextPage *page, 
-                         miniexp_t     p,
-                         int           delimit)
+djvu_text_page_selection (DjvuSelectionType type,
+                         DjvuTextPage *page,
+                         miniexp_t     p,
+                         int           delimit)
 {
        g_return_val_if_fail (miniexp_consp (p) && miniexp_symbolp
                              (miniexp_car (p)), FALSE);
@@ -84,12 +146,15 @@ djvu_text_page_selection (DjvuTextPage *page,
        while (deeper != miniexp_nil) {
                miniexp_t str = miniexp_car (deeper);
                if (miniexp_stringp (str)) {
-                       if (!djvu_text_page_selection_process
-                           (page, p, delimit))
-                               return FALSE;
+                       if (type == DJVU_SELECTION_TEXT) {
+                               if (!djvu_text_page_selection_process_text (page, p, delimit))
+                                       return FALSE;
+                       } else {
+                               if (!djvu_text_page_selection_process_box (page, p, delimit))
+                                       return FALSE;
+                       }
                } else {
-                       if (!djvu_text_page_selection
-                           (page, str, delimit))
+                       if (!djvu_text_page_selection (type, page, str, delimit))
                                return FALSE;
                }
                delimit = 0;
@@ -138,6 +203,29 @@ djvu_text_page_limits (DjvuTextPage *page,
        }
 }
 
+/**
+ * djvu_text_page_get_selection:
+ * @page: #DjvuTextPage instance
+ * @rectangle: #EvRectangle of the selection
+ *
+ * Returns: The bounding boxes of the selection
+ */
+GList *
+djvu_text_page_get_selection_region (DjvuTextPage *page,
+                                     EvRectangle  *rectangle)
+{
+       page->start = miniexp_nil;
+       page->end = miniexp_nil;
+
+       /* Get page->start and page->end filled from selection rectangle */
+       djvu_text_page_limits (page, page->text_structure, rectangle);
+       /* Fills page->results with the bouding boxes */
+       djvu_text_page_selection (DJVU_SELECTION_BOX,
+                                 page, page->text_structure, 0);
+
+       return g_list_reverse (page->results);
+}
+
 char *
 djvu_text_page_copy (DjvuTextPage *page, 
                     EvRectangle  *rectangle)
@@ -147,7 +235,8 @@ djvu_text_page_copy (DjvuTextPage *page,
        page->start = miniexp_nil;
        page->end = miniexp_nil;
        djvu_text_page_limits (page, page->text_structure, rectangle);
-       djvu_text_page_selection (page, page->text_structure, 0);
+       djvu_text_page_selection (DJVU_SELECTION_TEXT, page,
+                                 page->text_structure, 0);
        
        /* Do not free the string */      
        text = page->text;
@@ -194,28 +283,6 @@ djvu_text_page_position (DjvuTextPage *page,
 }
 
 /**
- * djvu_text_page_union:
- * @target: first rectangle and result
- * @source: second rectangle
- * 
- * Calculates the bounding box of two rectangles and stores the reuslt 
- * in the first.
- */
-static void
-djvu_text_page_union (EvRectangle *target, 
-                     EvRectangle *source)
-{
-       if (source->x1 < target->x1)
-               target->x1 = source->x1;
-       if (source->x2 > target->x2)
-               target->x2 = source->x2;
-       if (source->y1 < target->y1)
-               target->y1 = source->y1;
-       if (source->y2 > target->y2)
-               target->y2 = source->y2;
-}
-
-/**
  * djvu_text_page_sexpr_process:
  * @page: #DjvuTextPage instance
  * @p: s-expression to append
diff --git a/backend/djvu/djvu-text-page.h b/backend/djvu/djvu-text-page.h
index 6e16f25..4f1b1f8 100644
--- a/backend/djvu/djvu-text-page.h
+++ b/backend/djvu/djvu-text-page.h
@@ -46,14 +46,21 @@ struct _DjvuTextLink {
        miniexp_t pair;
 };
 
-char *                 djvu_text_page_copy             (DjvuTextPage *page, 
-                                                        EvRectangle  *rectangle);
-void                   djvu_text_page_prepare_search   (DjvuTextPage *page,
-                                                        gboolean      case_sensitive);
-void                   djvu_text_page_search           (DjvuTextPage *page, 
-                                                       const char    *text);
-DjvuTextPage*          djvu_text_page_new              (miniexp_t     text);
-void                   djvu_text_page_free             (DjvuTextPage *page);
+typedef enum {
+       DJVU_SELECTION_TEXT,
+       DJVU_SELECTION_BOX,
+} DjvuSelectionType;
+
+GList        *djvu_text_page_get_selection_region (DjvuTextPage *page,
+                                                   EvRectangle  *rectangle);
+char         *djvu_text_page_copy                 (DjvuTextPage *page,
+                                                   EvRectangle  *rectangle);
+void          djvu_text_page_prepare_search       (DjvuTextPage *page,
+                                                   gboolean      case_sensitive);
+void          djvu_text_page_search               (DjvuTextPage *page,
+                                                   const char   *text);
+DjvuTextPage *djvu_text_page_new                  (miniexp_t     text);
+void          djvu_text_page_free                 (DjvuTextPage *page);
 
 #endif /* __DJVU_TEXT_PAGE_H__ */
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]