f325b2
From 2b35ac76de22c9aa23c2245e49fc9e0c823b739c Mon Sep 17 00:00:00 2001
f325b2
From: Pranav Kant <pranavk@gnome.org>
f325b2
Date: Thu, 4 Jun 2015 00:06:46 +0530
f325b2
Subject: [PATCH 012/398] Add tile buffering support
f325b2
f325b2
The TileBuffer class now manages all the tiles. The tile rendering calls
f325b2
to LO core is also managed by this class.
f325b2
f325b2
Change-Id: Ic667a93dcf1c097e0601c0496e8a083c4742e8cb
f325b2
(cherry picked from commit 42dc4f3ed8b7b41597dd9851c31dee4d0e352f46)
f325b2
---
f325b2
 libreofficekit/Library_libreofficekitgtk.mk |  1 +
f325b2
 libreofficekit/source/gtk/lokdocview.cxx    | 76 ++++++++++++------------
f325b2
 libreofficekit/source/gtk/tilebuffer.cxx    | 90 +++++++++++++++++++++++++++++
f325b2
 libreofficekit/source/gtk/tilebuffer.hxx    | 78 +++++++++++++++++++++++++
f325b2
 4 files changed, 209 insertions(+), 36 deletions(-)
f325b2
 create mode 100644 libreofficekit/source/gtk/tilebuffer.cxx
f325b2
 create mode 100644 libreofficekit/source/gtk/tilebuffer.hxx
f325b2
f325b2
diff --git a/libreofficekit/Library_libreofficekitgtk.mk b/libreofficekit/Library_libreofficekitgtk.mk
f325b2
index ff800d0f1d96..92409537f4e8 100644
f325b2
--- a/libreofficekit/Library_libreofficekitgtk.mk
f325b2
+++ b/libreofficekit/Library_libreofficekitgtk.mk
f325b2
@@ -17,6 +17,7 @@ $(eval $(call gb_Library_use_externals,libreofficekitgtk,\
f325b2
 
f325b2
 $(eval $(call gb_Library_add_exception_objects,libreofficekitgtk,\
f325b2
     libreofficekit/source/gtk/lokdocview \
f325b2
+    libreofficekit/source/gtk/tilebuffer \
f325b2
 ))
f325b2
 
f325b2
 ifeq ($(OS),LINUX)
f325b2
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
f325b2
index c487ac8dd906..413054cf873c 100644
f325b2
--- a/libreofficekit/source/gtk/lokdocview.cxx
f325b2
+++ b/libreofficekit/source/gtk/lokdocview.cxx
f325b2
@@ -22,6 +22,8 @@
f325b2
 #include <LibreOfficeKit/LibreOfficeKitGtk.h>
f325b2
 #include <rsc/rsc-vcl-shared-types.hxx>
f325b2
 
f325b2
+#include "tilebuffer.hxx"
f325b2
+
f325b2
 #if !GLIB_CHECK_VERSION(2,32,0)
f325b2
 #define G_SOURCE_REMOVE FALSE
f325b2
 #define G_SOURCE_CONTINUE TRUE
f325b2
@@ -37,6 +39,8 @@
f325b2
 
f325b2
 // We know that VirtualDevices use a DPI of 96.
f325b2
 static const int DPI = 96;
f325b2
+// Lets use a square of side 256 pixels.
f325b2
+static const int nTileSizePixels = 256;
f325b2
 
f325b2
 namespace {
f325b2
 
f325b2
@@ -62,12 +66,8 @@ void payloadToSize(const char* pPayload, long& rWidth, long& rHeight)
f325b2
 struct LOKDocView_Impl
f325b2
 {
f325b2
     LOKDocView* m_pDocView;
f325b2
-    GtkWidget* m_pEventBox;
f325b2
-    GtkWidget* m_pTable;
f325b2
-    GtkWidget** m_pCanvas;
f325b2
-    GtkWidget *darea;
f325b2
-
f325b2
-    TileBuffer *mTileBuffer;
f325b2
+    GtkWidget *m_pDrawingArea;
f325b2
+    TileBuffer *m_pTileBuffer;
f325b2
 
f325b2
     float m_fZoom;
f325b2
 
f325b2
@@ -262,10 +262,7 @@ LOKDocView_Impl::CallbackData::CallbackData(int nType, const std::string& rPaylo
f325b2
 
f325b2
 LOKDocView_Impl::LOKDocView_Impl(LOKDocView* pDocView)
f325b2
     : m_pDocView(pDocView),
f325b2
-    m_pEventBox(gtk_event_box_new()),
f325b2
-    darea(gtk_drawing_area_new()),
f325b2
-    m_pTable(0),
f325b2
-    m_pCanvas(0),
f325b2
+    m_pDrawingArea(gtk_drawing_area_new()),
f325b2
     m_fZoom(1),
f325b2
     m_pOffice(0),
f325b2
     m_pDocument(0),
f325b2
@@ -313,7 +310,7 @@ void LOKDocView_Impl::destroy(LOKDocView* pDocView, gpointer /*pData*/)
f325b2
     delete pDocView->m_pImpl;
f325b2
 }
f325b2
 
f325b2
-void LOKDocView_Impl::on_exposed(GtkWidget *widget, GdkEvent *event, gpointer userdata)
f325b2
+void LOKDocView_Impl::on_exposed(GtkWidget* /*widget*/, GdkEvent* /*event*/, gpointer userdata)
f325b2
 {
f325b2
     LOKDocView *pDocView = LOK_DOCVIEW (userdata);
f325b2
     pDocView->m_pImpl->renderDocument(0);
f325b2
@@ -773,7 +770,7 @@ gboolean LOKDocView_Impl::handleTimeoutImpl()
f325b2
             m_bCursorOverlayVisible = false;
f325b2
         else
f325b2
             m_bCursorOverlayVisible = true;
f325b2
-        gtk_widget_queue_draw(GTK_WIDGET(m_pEventBox));
f325b2
+        gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea));
f325b2
     }
f325b2
 
f325b2
     return G_SOURCE_CONTINUE;
f325b2
@@ -781,8 +778,6 @@ gboolean LOKDocView_Impl::handleTimeoutImpl()
f325b2
 
f325b2
 void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
f325b2
 {
f325b2
-    const int nTileSizePixels = 256;
f325b2
-
f325b2
     GdkRectangle visibleArea;
f325b2
     lok_docview_get_visarea (m_pDocView, &visibleArea);
f325b2
 
f325b2
@@ -792,8 +787,8 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
f325b2
     guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
f325b2
     guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
f325b2
 
f325b2
-    gtk_widget_set_size_request(darea, nDocumentWidthPixels, nDocumentHeightPixels);
f325b2
-    cairo_t *pcairo = gdk_cairo_create(darea->window);
f325b2
+    gtk_widget_set_size_request(m_pDrawingArea, nDocumentWidthPixels, nDocumentHeightPixels);
f325b2
+    cairo_t *pcairo = gdk_cairo_create(m_pDrawingArea->window);
f325b2
 
f325b2
     // Render the tiles.
f325b2
     for (guint nRow = 0; nRow < nRows; ++nRow)
f325b2
@@ -826,20 +821,10 @@ void LOKDocView_Impl::renderDocument(GdkRectangle* pPartial)
f325b2
 
f325b2
             if (bPaint)
f325b2
             {
f325b2
-                // Index of the current tile.
f325b2
-                guint nTile = nRow * nColumns + nColumn;
f325b2
-
f325b2
-                GdkPixbuf* pPixBuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, aTileRectanglePixels.width, aTileRectanglePixels.height);
f325b2
-                unsigned char* pBuffer = gdk_pixbuf_get_pixels(pPixBuf);
f325b2
-                g_info("renderDocument: paintTile(%d, %d)", nRow, nColumn);
f325b2
-                m_pDocument->pClass->paintTile(m_pDocument,
f325b2
-                                               // Buffer and its size, depends on the position only.
f325b2
-                                               pBuffer,
f325b2
-                                               aTileRectanglePixels.width, aTileRectanglePixels.height,
f325b2
-                                               // Position of the tile.
f325b2
-                                               aTileRectangleTwips.x, aTileRectangleTwips.y,
f325b2
-                                               // Size of the tile, depends on the zoom factor and the tile position only.
f325b2
-                                               aTileRectangleTwips.width, aTileRectangleTwips.height);
f325b2
+                g_info("gettile: (%d %d)", nRow, nColumn);
f325b2
+
f325b2
+                Tile& currentTile = m_pTileBuffer->tile_buffer_get_tile(nRow, nColumn);
f325b2
+                GdkPixbuf* pPixBuf = currentTile.tile_get_buffer();
f325b2
 
f325b2
                 gdk_cairo_set_source_pixbuf (pcairo, pPixBuf, twipToPixel(aTileRectangleTwips.x), twipToPixel(aTileRectangleTwips.y));
f325b2
                 cairo_paint(pcairo);
f325b2
@@ -959,7 +944,7 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
f325b2
     {
f325b2
         m_aVisibleCursor = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
f325b2
         m_bCursorOverlayVisible = true;
f325b2
-        gtk_widget_queue_draw(GTK_WIDGET(m_pEventBox));
f325b2
+        gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea));
f325b2
     }
f325b2
     break;
f325b2
     case LOK_CALLBACK_TEXT_SELECTION:
f325b2
@@ -976,7 +961,7 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
f325b2
         }
f325b2
         else
f325b2
             memset(&m_aHandleMiddleRect, 0, sizeof(m_aHandleMiddleRect));
f325b2
-        gtk_widget_queue_draw(GTK_WIDGET(m_pEventBox));
f325b2
+        gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea));
f325b2
     }
f325b2
     break;
f325b2
     case LOK_CALLBACK_TEXT_SELECTION_START:
f325b2
@@ -1000,7 +985,7 @@ gboolean LOKDocView_Impl::callbackImpl(CallbackData* pCallback)
f325b2
             m_aGraphicSelection = LOKDocView_Impl::payloadToRectangle(pCallback->m_aPayload.c_str());
f325b2
         else
f325b2
             memset(&m_aGraphicSelection, 0, sizeof(m_aGraphicSelection));
f325b2
-        gtk_widget_queue_draw(GTK_WIDGET(m_pEventBox));
f325b2
+        gtk_widget_queue_draw(GTK_WIDGET(m_pDrawingArea));
f325b2
     }
f325b2
     break;
f325b2
     case LOK_CALLBACK_HYPERLINK_CLICKED:
f325b2
@@ -1154,9 +1139,9 @@ static void lok_docview_init( GTypeInstance* pInstance, gpointer )
f325b2
 
f325b2
     pDocView->m_pImpl = new LOKDocView_Impl(pDocView);
f325b2
     gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(pDocView),
f325b2
-                                           pDocView->m_pImpl->darea );
f325b2
+                                           pDocView->m_pImpl->m_pDrawingArea );
f325b2
 
f325b2
-    g_signal_connect(GTK_OBJECT(pDocView->m_pImpl->darea),
f325b2
+    g_signal_connect(GTK_OBJECT(pDocView->m_pImpl->m_pDrawingArea),
f325b2
                      "expose-event",
f325b2
                      GTK_SIGNAL_FUNC(LOKDocView_Impl::on_exposed), pDocView);
f325b2
 
f325b2
@@ -1218,6 +1203,18 @@ SAL_DLLPUBLIC_EXPORT gboolean lok_docview_open_document( LOKDocView* pDocView, c
f325b2
         pDocView->m_pImpl->m_pDocument->pClass->registerCallback(pDocView->m_pImpl->m_pDocument, &LOKDocView_Impl::callbackWorker, pDocView);
f325b2
         pDocView->m_pImpl->m_pDocument->pClass->getDocumentSize(pDocView->m_pImpl->m_pDocument, &pDocView->m_pImpl->m_nDocumentWidthTwips, &pDocView->m_pImpl->m_nDocumentHeightTwips);
f325b2
         g_timeout_add(600, &LOKDocView_Impl::handleTimeout, pDocView);
f325b2
+
f325b2
+        long nDocumentWidthTwips = pDocView->m_pImpl->m_nDocumentWidthTwips;
f325b2
+        long nDocumentHeightTwips = pDocView->m_pImpl->m_nDocumentHeightTwips;
f325b2
+        long nDocumentWidthPixels = pDocView->m_pImpl->twipToPixel(nDocumentWidthTwips);
f325b2
+        long nDocumentHeightPixels = pDocView->m_pImpl->twipToPixel(nDocumentHeightTwips);
f325b2
+        // Total number of rows / columns in this document.
f325b2
+        guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
f325b2
+        guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
f325b2
+        pDocView->m_pImpl->m_pTileBuffer = new TileBuffer(pDocView->m_pImpl->m_pDocument,
f325b2
+                                                          nTileSizePixels,
f325b2
+                                                          nRows,
f325b2
+                                                          nColumns);
f325b2
         pDocView->m_pImpl->renderDocument(0);
f325b2
     }
f325b2
 
f325b2
@@ -1232,6 +1229,13 @@ SAL_DLLPUBLIC_EXPORT LibreOfficeKitDocument* lok_docview_get_document(LOKDocView
f325b2
 SAL_DLLPUBLIC_EXPORT void lok_docview_set_zoom ( LOKDocView* pDocView, float fZoom )
f325b2
 {
f325b2
     pDocView->m_pImpl->m_fZoom = fZoom;
f325b2
+    long nDocumentWidthPixels = pDocView->m_pImpl->twipToPixel(pDocView->m_pImpl->m_nDocumentWidthTwips);
f325b2
+    long nDocumentHeightPixels = pDocView->m_pImpl->twipToPixel(pDocView->m_pImpl->m_nDocumentHeightTwips);
f325b2
+    // Total number of rows / columns in this document.
f325b2
+    guint nRows = ceil((double)nDocumentHeightPixels / nTileSizePixels);
f325b2
+    guint nColumns = ceil((double)nDocumentWidthPixels / nTileSizePixels);
f325b2
+
f325b2
+    pDocView->m_pImpl->m_pTileBuffer->tile_buffer_set_zoom(fZoom, nRows, nColumns);
f325b2
 
f325b2
     if ( pDocView->m_pImpl->m_pDocument )
f325b2
         pDocView->m_pImpl->renderDocument(0);
f325b2
@@ -1283,7 +1287,7 @@ SAL_DLLPUBLIC_EXPORT void lok_docview_set_edit( LOKDocView* pDocView,
f325b2
     }
f325b2
     pDocView->m_pImpl->m_bEdit = bEdit;
f325b2
     g_signal_emit(pDocView, docview_signals[EDIT_CHANGED], 0, bWasEdit);
f325b2
-    gtk_widget_queue_draw(GTK_WIDGET(pDocView->m_pImpl->m_pEventBox));
f325b2
+    gtk_widget_queue_draw(GTK_WIDGET(pDocView->m_pImpl->m_pDrawingArea));
f325b2
 }
f325b2
 
f325b2
 SAL_DLLPUBLIC_EXPORT gboolean lok_docview_get_edit(LOKDocView* pDocView)
f325b2
diff --git a/libreofficekit/source/gtk/tilebuffer.cxx b/libreofficekit/source/gtk/tilebuffer.cxx
f325b2
new file mode 100644
f325b2
index 000000000000..ca66ae904f71
f325b2
--- /dev/null
f325b2
+++ b/libreofficekit/source/gtk/tilebuffer.cxx
f325b2
@@ -0,0 +1,90 @@
f325b2
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
f325b2
+/*
f325b2
+ * This file is part of the LibreOffice project.
f325b2
+ *
f325b2
+ * This Source Code Form is subject to the terms of the Mozilla Public
f325b2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
f325b2
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
f325b2
+ */
f325b2
+
f325b2
+#include "tilebuffer.hxx"
f325b2
+
f325b2
+static const int DPI = 96;
f325b2
+
f325b2
+static float pixelToTwip(float fInput, float zoom)
f325b2
+{
f325b2
+    return (fInput / DPI / zoom) * 1440.0f;
f325b2
+}
f325b2
+
f325b2
+static float twipToPixel(float fInput, float zoom)
f325b2
+{
f325b2
+    return fInput / 1440.0f * DPI * zoom;
f325b2
+}
f325b2
+
f325b2
+GdkPixbuf* Tile::tile_get_buffer()
f325b2
+{
f325b2
+  return m_pBuffer;
f325b2
+}
f325b2
+
f325b2
+void Tile::tile_release()
f325b2
+{
f325b2
+  gdk_pixbuf_unref(m_pBuffer);
f325b2
+  m_pBuffer = NULL;
f325b2
+}
f325b2
+
f325b2
+void TileBuffer::tile_buffer_set_zoom(float newZoomFactor, int rows, int columns)
f325b2
+{
f325b2
+  m_fZoomFactor = newZoomFactor;
f325b2
+
f325b2
+  tile_buffer_reset_all_tiles();
f325b2
+
f325b2
+  // set new buffer width and height
f325b2
+  m_nWidth = columns;
f325b2
+  m_nHeight = rows;
f325b2
+  m_aTiles.resize(m_nWidth * m_nHeight);
f325b2
+}
f325b2
+
f325b2
+void TileBuffer::tile_buffer_reset_all_tiles()
f325b2
+{
f325b2
+  for (size_t i = 0; i < m_aTiles.size(); i++)
f325b2
+    {
f325b2
+      m_aTiles[i].tile_release();
f325b2
+    }
f325b2
+  m_aTiles.clear();
f325b2
+}
f325b2
+
f325b2
+Tile& TileBuffer::tile_buffer_get_tile(int x, int y)
f325b2
+{
f325b2
+  int index = x * m_nWidth + y;
f325b2
+  if(!m_aTiles[index].valid)
f325b2
+    {
f325b2
+      GdkPixbuf* pPixBuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, m_nTileSize, m_nTileSize);
f325b2
+      if (!pPixBuf){
f325b2
+        g_info ("error allocating memory to pixbuf");
f325b2
+      }
f325b2
+      unsigned char* pBuffer = gdk_pixbuf_get_pixels(pPixBuf);
f325b2
+      GdkRectangle aTileRectangle;
f325b2
+      aTileRectangle.x = pixelToTwip(m_nTileSize, m_fZoomFactor) * y;
f325b2
+      aTileRectangle.y = pixelToTwip(m_nTileSize, m_fZoomFactor) * x;
f325b2
+
f325b2
+      g_info ("rendering (%d %d)", x, y);
f325b2
+      m_pLOKDocument->pClass->paintTile(m_pLOKDocument,
f325b2
+                                        // Buffer and its size, depends on the position only.
f325b2
+                                        pBuffer,
f325b2
+                                        m_nTileSize, m_nTileSize,
f325b2
+                                        // Position of the tile.
f325b2
+                                        aTileRectangle.x, aTileRectangle.y,
f325b2
+                                        // Size of the tile, depends on the zoom factor and the tile position only.
f325b2
+                                        pixelToTwip(m_nTileSize, m_fZoomFactor), pixelToTwip(m_nTileSize, m_fZoomFactor));
f325b2
+
f325b2
+      m_aTiles[index].tile_set_pixbuf(pPixBuf);
f325b2
+      m_aTiles[index].valid = 1;
f325b2
+    }
f325b2
+
f325b2
+  return m_aTiles[index];
f325b2
+}
f325b2
+
f325b2
+void Tile::tile_set_pixbuf(GdkPixbuf *buffer)
f325b2
+{
f325b2
+  m_pBuffer = buffer;
f325b2
+}
f325b2
diff --git a/libreofficekit/source/gtk/tilebuffer.hxx b/libreofficekit/source/gtk/tilebuffer.hxx
f325b2
new file mode 100644
f325b2
index 000000000000..a5ed0dc8ec61
f325b2
--- /dev/null
f325b2
+++ b/libreofficekit/source/gtk/tilebuffer.hxx
f325b2
@@ -0,0 +1,78 @@
f325b2
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
f325b2
+/*
f325b2
+ * This file is part of the LibreOffice project.
f325b2
+ *
f325b2
+ * This Source Code Form is subject to the terms of the Mozilla Public
f325b2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
f325b2
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
f325b2
+ */
f325b2
+
f325b2
+#ifndef INCLUDED_TILEBUFFER_HXX
f325b2
+#define INCLUDED_TILEBUFFER_HXX
f325b2
+
f325b2
+#include <gdk/gdkkeysyms.h>
f325b2
+#include <gdk-pixbuf/gdk-pixbuf.h>
f325b2
+#include <vector>
f325b2
+
f325b2
+#define LOK_USE_UNSTABLE_API
f325b2
+#include <LibreOfficeKit/LibreOfficeKit.h>
f325b2
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
f325b2
+#include <LibreOfficeKit/LibreOfficeKitGtk.h>
f325b2
+
f325b2
+/*
f325b2
+  This class represents a single tile in the tile buffer.
f325b2
+  TODO: Extend it to support features like double buffering
f325b2
+*/
f325b2
+class Tile
f325b2
+{
f325b2
+public:
f325b2
+  Tile() : valid(0) {}
f325b2
+  ~Tile() {
f325b2
+    tile_release();
f325b2
+  }
f325b2
+
f325b2
+  GdkPixbuf* tile_get_buffer();
f325b2
+  void tile_release();
f325b2
+  void tile_set_pixbuf(GdkPixbuf*);
f325b2
+  bool valid;
f325b2
+private:
f325b2
+  GdkPixbuf *m_pBuffer;
f325b2
+};
f325b2
+
f325b2
+/*
f325b2
+  TileBuffer is the buffer caching all the recently rendered tiles.
f325b2
+  The buffer is set to invalid when zoom factor changes.
f325b2
+*/
f325b2
+class TileBuffer
f325b2
+{
f325b2
+public:
f325b2
+  TileBuffer(LibreOfficeKitDocument *document,
f325b2
+             int tileSize,
f325b2
+             int rows,
f325b2
+             int columns)
f325b2
+    : m_pLOKDocument(document)
f325b2
+    , m_nTileSize(tileSize)
f325b2
+    , m_fZoomFactor(1)
f325b2
+    , m_nWidth(columns)
f325b2
+    , m_nHeight(rows)
f325b2
+  {
f325b2
+    m_aTiles.resize(rows * columns);
f325b2
+  }
f325b2
+
f325b2
+  ~TileBuffer() {}
f325b2
+
f325b2
+  void tile_buffer_set_zoom(float zoomFactor, int rows, int columns);
f325b2
+  Tile& tile_buffer_get_tile(int x, int y);
f325b2
+  void tile_buffer_update();
f325b2
+  void tile_buffer_reset_all_tiles();
f325b2
+private:
f325b2
+  LibreOfficeKitDocument *m_pLOKDocument;
f325b2
+  int m_nTileSize;
f325b2
+  float m_fZoomFactor;
f325b2
+  std::vector<Tile> m_aTiles;
f325b2
+  //TODO: Also set width and height when document size changes
f325b2
+  int m_nWidth;
f325b2
+  int m_nHeight;
f325b2
+};
f325b2
+
f325b2
+#endif // INCLUDED_TILEBUFFER_HXX
f325b2
-- 
f325b2
2.12.0
f325b2