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